mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 12:09:03 +00:00
fix(i18n): complete Brazilian Portuguese locale
This commit is contained in:
1 parent
bb2596e296
commit
0a80dddb9c
2 files changed
+47
-2
No files matched your search
+12
-2
@@ -7,6 +7,7 @@ const resources = {
|
|||||||
translation: {
|
translation: {
|
||||||
locale: {
|
locale: {
|
||||||
en: 'English',
|
en: 'English',
|
||||||
|
'pt-BR': 'Brazilian Portuguese',
|
||||||
'zh-CN': 'Simplified Chinese',
|
'zh-CN': 'Simplified Chinese',
|
||||||
vi: 'Vietnamese',
|
vi: 'Vietnamese',
|
||||||
ja: 'Japanese',
|
ja: 'Japanese',
|
||||||
@@ -2791,7 +2792,7 @@ const resources = {
|
|||||||
configurationRequired: 'Configuração Necessária',
|
configurationRequired: 'Configuração Necessária',
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
dashboardTitle: 'Painel CCS',
|
dashboardTitle: 'Claude Codex Switch Dashboard',
|
||||||
protectedAccessLabel: 'Acesso protegido',
|
protectedAccessLabel: 'Acesso protegido',
|
||||||
remoteGuardLabel: 'Proteção de acesso remoto',
|
remoteGuardLabel: 'Proteção de acesso remoto',
|
||||||
loading: 'Verificando acesso ao painel…',
|
loading: 'Verificando acesso ao painel…',
|
||||||
@@ -2819,7 +2820,7 @@ const resources = {
|
|||||||
safetyNoteLocal:
|
safetyNoteLocal:
|
||||||
'Se você estiver na mesma máquina, a URL localhost continua sendo o caminho mais simples para entrar.',
|
'Se você estiver na mesma máquina, a URL localhost continua sendo o caminho mais simples para entrar.',
|
||||||
safetyNoteSession:
|
safetyNoteSession:
|
||||||
'Logins bem-sucedidos criam uma sessão somente HTTP que fica restrita a este host do painel.',
|
'Logins bem-sucedidos criam um cookie HttpOnly restrito a este host do painel.',
|
||||||
hostStepTitle: 'No host do CCS',
|
hostStepTitle: 'No host do CCS',
|
||||||
hostStepDescription:
|
hostStepDescription:
|
||||||
'Crie ou reative as credenciais do painel e, em seguida, reabra esta página a partir do dispositivo remoto.',
|
'Crie ou reative as credenciais do painel e, em seguida, reabra esta página a partir do dispositivo remoto.',
|
||||||
@@ -2975,6 +2976,9 @@ const resources = {
|
|||||||
'O modelo fixado não está sendo anunciado atualmente pelo proxy: {{model}}',
|
'O modelo fixado não está sendo anunciado atualmente pelo proxy: {{model}}',
|
||||||
codexReasoningVariants: 'Variantes de raciocínio',
|
codexReasoningVariants: 'Variantes de raciocínio',
|
||||||
codexFastVariants: 'Variantes rápidas',
|
codexFastVariants: 'Variantes rápidas',
|
||||||
|
effortLabel: 'Esforço de raciocínio',
|
||||||
|
effortAuto: 'Automático',
|
||||||
|
fastTier: 'Rápido',
|
||||||
},
|
},
|
||||||
createAuthProfileDialog: {
|
createAuthProfileDialog: {
|
||||||
title: 'Criar Nova Conta',
|
title: 'Criar Nova Conta',
|
||||||
@@ -4747,6 +4751,11 @@ const resources = {
|
|||||||
sessionRecognitionTitle: 'Reconhecimento de sessão',
|
sessionRecognitionTitle: 'Reconhecimento de sessão',
|
||||||
sessionRecognitionDescription:
|
sessionRecognitionDescription:
|
||||||
'O CCS não promete uma ordem de precedência universal aqui. Na prática, os back-ends upstream preferem IDs explícitos de sessão ou thread primeiro, depois recorrem a campos de metadados e, por fim, a um hash baseado no histórico do prompt inicial.',
|
'O CCS não promete uma ordem de precedência universal aqui. Na prática, os back-ends upstream preferem IDs explícitos de sessão ou thread primeiro, depois recorrem a campos de metadados e, por fim, a um hash baseado no histórico do prompt inicial.',
|
||||||
|
retryTitle: 'Nova tentativa automática',
|
||||||
|
retryHint: 'Tentativas / espera máxima (s)',
|
||||||
|
requestRetryLabel: 'Tentativas da solicitação',
|
||||||
|
maxRetryIntervalLabel: 'Intervalo máximo entre tentativas (segundos)',
|
||||||
|
retryRangeError: 'Deve ser um número inteiro igual ou maior que 0.',
|
||||||
},
|
},
|
||||||
extendedContext: {
|
extendedContext: {
|
||||||
extendedContext: 'Contexto Estendido',
|
extendedContext: 'Contexto Estendido',
|
||||||
@@ -5147,6 +5156,7 @@ const resources = {
|
|||||||
noProfilesToSync: 'Nenhum perfil para sincronizar',
|
noProfilesToSync: 'Nenhum perfil para sincronizar',
|
||||||
syncFailed: 'Falha na sincronização: {{error}}',
|
syncFailed: 'Falha na sincronização: {{error}}',
|
||||||
sessionAffinityUpdated: 'Afinidade de sessão {{state}}.',
|
sessionAffinityUpdated: 'Afinidade de sessão {{state}}.',
|
||||||
|
cliproxyRetryUpdated: 'Configurações de nova tentativa atualizadas.',
|
||||||
providerAuthSuccess: 'Autenticação do {{provider}} bem-sucedida',
|
providerAuthSuccess: 'Autenticação do {{provider}} bem-sucedida',
|
||||||
providerDeviceCodeInCallback: 'O provedor retornou o fluxo Device Code no modo callback',
|
providerDeviceCodeInCallback: 'O provedor retornou o fluxo Device Code no modo callback',
|
||||||
providerAuthTimeout: 'A autenticação expirou. Tente novamente.',
|
providerAuthTimeout: 'A autenticação expirou. Tente novamente.',
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { render, screen, userEvent, waitFor } from '@tests/setup/test-utils';
|
import { render, screen, userEvent, waitFor } from '@tests/setup/test-utils';
|
||||||
import i18n from '@/lib/i18n';
|
import i18n from '@/lib/i18n';
|
||||||
import { ContinuityOverview } from '@/components/account/continuity-overview';
|
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();
|
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', () => {
|
describe('Dashboard i18n', () => {
|
||||||
const storage = new Map<string, string>();
|
const storage = new Map<string, string>();
|
||||||
const localStorageMock = window.localStorage as unknown as {
|
const localStorageMock = window.localStorage as unknown as {
|
||||||
@@ -94,6 +106,7 @@ describe('Dashboard i18n', () => {
|
|||||||
}, 10000);
|
}, 10000);
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
|
{ locale: 'pt-BR', label: 'Brazilian Portuguese', browserLocale: 'pt-BR' },
|
||||||
{ locale: 'vi', label: 'Vietnamese', browserLocale: 'vi-VN' },
|
{ locale: 'vi', label: 'Vietnamese', browserLocale: 'vi-VN' },
|
||||||
{ locale: 'ja', label: 'Japanese', browserLocale: 'ja-JP' },
|
{ locale: 'ja', label: 'Japanese', browserLocale: 'ja-JP' },
|
||||||
{ locale: 'ko', label: 'Korean', browserLocale: 'ko-KR' },
|
{ 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', () => {
|
it('restores locale from persisted storage', () => {
|
||||||
persistLocale('ja');
|
persistLocale('ja');
|
||||||
expect(getInitialLocale()).toBe('ja');
|
expect(getInitialLocale()).toBe('ja');
|
||||||
|
|||||||
Reference in new issue
Block a user