mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 12:09:03 +00:00
Merge pull request #1673 from jeffersongoncalves/feat/i18n-pt-br
feat(i18n): add Brazilian Portuguese (pt-BR) locale
This commit is contained in:
4 files changed
+2855
-1
No files matched your search
@@ -10,6 +10,7 @@ Dashboard i18n currently covers UI text rendered by React components.
|
||||
|
||||
- Supported locales today:
|
||||
- `en` (English)
|
||||
- `pt-BR` (Brazilian Portuguese)
|
||||
- `zh-CN` (Simplified Chinese)
|
||||
- `vi` (Vietnamese)
|
||||
- `ja` (Japanese)
|
||||
@@ -36,6 +37,7 @@ Out of scope:
|
||||
- File: `ui/src/lib/i18n.ts`
|
||||
- Contains `resources` object with locale blocks:
|
||||
- `en.translation`
|
||||
- `pt-BR.translation`
|
||||
- `zh-CN.translation`
|
||||
- `vi.translation`
|
||||
- `ja.translation`
|
||||
|
||||
+2816
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
export const LOCALE_STORAGE_KEY = 'ccs-ui-locale';
|
||||
|
||||
export const SUPPORTED_LOCALES = ['en', 'zh-CN', 'vi', 'ja', 'ko'] as const;
|
||||
export const SUPPORTED_LOCALES = ['en', 'pt-BR', 'zh-CN', 'vi', 'ja', 'ko'] as const;
|
||||
|
||||
export type AppLocale = (typeof SUPPORTED_LOCALES)[number];
|
||||
|
||||
@@ -14,6 +14,7 @@ export function normalizeLocale(locale: string | null | undefined): AppLocale {
|
||||
if (locale.toLowerCase().startsWith('ja')) return 'ja';
|
||||
if (locale.toLowerCase().startsWith('zh')) return 'zh-CN';
|
||||
if (locale.toLowerCase().startsWith('vi')) return 'vi';
|
||||
if (locale.toLowerCase().startsWith('pt')) return 'pt-BR';
|
||||
return 'en';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { render, screen, userEvent, waitFor } from '@tests/setup/test-utils';
|
||||
import i18n from '@/lib/i18n';
|
||||
import { ContinuityOverview } from '@/components/account/continuity-overview';
|
||||
@@ -31,6 +32,17 @@ function collectPlaceholders(text: string): string[] {
|
||||
return Array.from(text.matchAll(/\{\{[^{}]+\}\}/g), (match) => match[0]).sort();
|
||||
}
|
||||
|
||||
function AuthCopyProbe() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>{t('auth.dashboardTitle')}</h1>
|
||||
<p>{t('auth.safetyNoteSession')}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
describe('Dashboard i18n', () => {
|
||||
const storage = new Map<string, string>();
|
||||
const localStorageMock = window.localStorage as unknown as {
|
||||
@@ -94,6 +106,7 @@ describe('Dashboard i18n', () => {
|
||||
}, 10000);
|
||||
|
||||
it.each([
|
||||
{ locale: 'pt-BR', label: 'Brazilian Portuguese', browserLocale: 'pt-BR' },
|
||||
{ locale: 'vi', label: 'Vietnamese', browserLocale: 'vi-VN' },
|
||||
{ locale: 'ja', label: 'Japanese', browserLocale: 'ja-JP' },
|
||||
{ locale: 'ko', label: 'Korean', browserLocale: 'ko-KR' },
|
||||
@@ -113,6 +126,28 @@ describe('Dashboard i18n', () => {
|
||||
}
|
||||
);
|
||||
|
||||
it.each([
|
||||
['pt-BR', 'pt-BR'],
|
||||
['pt-PT', 'pt-BR'],
|
||||
])('normalizes Portuguese locale %s to %s', (browserLocale, expectedLocale) => {
|
||||
expect(normalizeLocale(browserLocale)).toBe(expectedLocale);
|
||||
});
|
||||
|
||||
it('renders semantic Brazilian Portuguese auth copy when pt-BR is selected', async () => {
|
||||
await i18n.changeLanguage('pt-BR');
|
||||
|
||||
render(<AuthCopyProbe />);
|
||||
|
||||
expect(
|
||||
screen.getByRole('heading', { name: 'Claude Codex Switch Dashboard' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Logins bem-sucedidos criam um cookie HttpOnly restrito a este host do painel.'
|
||||
)
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('restores locale from persisted storage', () => {
|
||||
persistLocale('ja');
|
||||
expect(getInitialLocale()).toBe('ja');
|
||||
|
||||
Reference in new issue
Block a user