diff --git a/assets/i18n-pt-br/integrations-cursor.png b/assets/i18n-pt-br/integrations-cursor.png new file mode 100644 index 00000000000..3a40f69fc55 Binary files /dev/null and b/assets/i18n-pt-br/integrations-cursor.png differ diff --git a/assets/i18n-pt-br/providers.png b/assets/i18n-pt-br/providers.png new file mode 100644 index 00000000000..ee64697f9d2 Binary files /dev/null and b/assets/i18n-pt-br/providers.png differ diff --git a/gui/src/components/QuotaBars.tsx b/gui/src/components/QuotaBars.tsx index 7a9e848eb38..b470ce3a31b 100644 --- a/gui/src/components/QuotaBars.tsx +++ b/gui/src/components/QuotaBars.tsx @@ -180,6 +180,8 @@ function bcp47(locale: Locale): string { return "tr-TR"; case "vi": return "vi-VN"; + case "pt-BR": + return "pt-BR"; default: { const _exhaustive: never = locale; return _exhaustive; diff --git a/gui/src/components/provider-workspace/ProviderCapacityQuota.tsx b/gui/src/components/provider-workspace/ProviderCapacityQuota.tsx index dce977c5c63..4ba4b617113 100644 --- a/gui/src/components/provider-workspace/ProviderCapacityQuota.tsx +++ b/gui/src/components/provider-workspace/ProviderCapacityQuota.tsx @@ -27,6 +27,7 @@ function bcp47(locale: Locale): string { case "ja": return "ja-JP"; case "tr": return "tr-TR"; case "vi": return "vi-VN"; + case "pt-BR": return "pt-BR"; default: { const _exhaustive: never = locale; return _exhaustive; diff --git a/gui/src/i18n/catalogs.ts b/gui/src/i18n/catalogs.ts index dd5f41b78c4..bf5f6f59b30 100644 --- a/gui/src/i18n/catalogs.ts +++ b/gui/src/i18n/catalogs.ts @@ -8,6 +8,7 @@ import { ru } from "./ru"; import { ja } from "./ja"; import { tr } from "./tr"; import { vi } from "./vi"; +import { ptBR } from "./pt-BR"; import { LAB_CATALOG_OVERRIDES, type LabLocale } from "./lab-translations"; /** React-free locale catalog registry for formatters and other shared helpers. */ @@ -33,6 +34,7 @@ export const DICTS: Record> = { ja: withLabTranslations("ja", ja), tr: withLabTranslations("tr", tr), vi: withLabTranslations("vi", vi), + "pt-BR": withLabTranslations("pt-BR", ptBR), }; /** Native language names shown by the language picker, kept inside i18n rather than UI metadata. */ diff --git a/gui/src/i18n/lab-translations.ts b/gui/src/i18n/lab-translations.ts index 59d1639e80a..6d0a8583b55 100644 --- a/gui/src/i18n/lab-translations.ts +++ b/gui/src/i18n/lab-translations.ts @@ -1,6 +1,6 @@ import type { TKey } from "./en"; -export type LabLocale = "en" | "de" | "fr" | "ko" | "zh" | "zh-TW" | "ru" | "ja" | "tr" | "vi"; +export type LabLocale = "en" | "de" | "fr" | "ko" | "zh" | "zh-TW" | "ru" | "ja" | "tr" | "vi" | "pt-BR"; export type LabCatalogKey = Exclude, `lab.production.${string}`>; export type LabSupplementKey = | "subjectKindUnknown" @@ -514,6 +514,57 @@ const vi: Record = { "lab.layer.task_effectiveness": "Hiệu quả tác vụ", }; + +const ptBR: Record = { + "lab.title": "Laboratório de Compatibilidade", + "lab.subtitle": "Matriz de pareceres de compatibilidade somente leitura baseada em evidências de projeção do laboratório.", + "lab.loadFailed": "Não foi possível carregar os dados do laboratório de compatibilidade", + "lab.projectionUnavailable": "A projeção do laboratório não está disponível. Execute os testes de conformidade ou sondagens ativas primeiro.", + "lab.projectionIncompatible": "O esquema de projeção do laboratório é incompatível. Reconstrua a projeção.", + "lab.statusTitle": "Status da projeção", + "lab.matrixTitle": "Matriz de compatibilidade", + "lab.verdictsTitle": "Registros de pareceres", + "lab.filter.layer": "Camada de evidência", + "lab.filter.verdict": "Parecer", + "lab.filter.subject": "ID do sujeito", + "lab.filter.all": "Todos", + "lab.col.subject": "Sujeito", + "lab.col.layer": "Camada", + "lab.col.suite": "Suite", + "lab.col.verdict": "Parecer", + "lab.col.asOf": "Em", + "lab.col.protocol": "Conformidade de protocolo", + "lab.col.live": "Compatibilidade de rota ativa", + "lab.col.task": "Eficácia da tarefa", + "lab.empty": "Nenhum parecer de compatibilidade na projeção ainda.", + "lab.subjectKind": "Tipo", + "lab.observationCount": "Observações", + "lab.eventCount": "Eventos", + "lab.verdictCount": "Pareceres", + "lab.subjectCount": "Sujeitos", + "lab.builtAt": "Construído em", + "lab.loading": "Carregando evidências de compatibilidade…", + "lab.loadMore": "Carregar mais", + "lab.detailTitle": "Detalhes do parecer", + "lab.detailClose": "Fechar", + "lab.detailSubject": "Sujeito", + "lab.detailObservations": "Observações", + "lab.detailEvents": "Eventos de evidência", + "lab.detailArtifacts": "Metadados do artefato", + "lab.detailLoadFailed": "Não foi possível carregar os detalhes do parecer", + "lab.refresh": "Atualizar", + "lab.verdict.UNKNOWN": "Desconhecido", + "lab.verdict.CLAIMED": "Declarado", + "lab.verdict.PROBED": "Sondado", + "lab.verdict.VERIFIED": "Verificado", + "lab.verdict.DEGRADED": "Degradado", + "lab.verdict.BLOCKED": "Bloqueado", + "lab.verdict.UNSUPPORTED": "Não suportado", + "lab.layer.protocol_conformance": "Conformidade de protocolo", + "lab.layer.live_route_compatibility": "Compatibilidade de rota ativa", + "lab.layer.task_effectiveness": "Eficácia da tarefa", +}; + export const LAB_CATALOG_OVERRIDES: Record> = { en, de, @@ -525,6 +576,7 @@ export const LAB_CATALOG_OVERRIDES: Record> = { @@ -648,6 +700,18 @@ const supplements: Record> = { "community.activeRecords": "Bản ghi đang hoạt động", "community.revokedRecords": "Bản ghi đã thu hồi", }, + "pt-BR": { + subjectKindUnknown: "Desconhecido", + "artifact.present": "Presente", + "artifact.corrupt": "Corrompido", + "artifact.purged_unavailable": "Expurgado / indisponível", + selectVerdict: "Visualizar parecer para {subject}", + "community.title": "Evidência da comunidade", + "community.notLocalVerdict": "Contexto somente leitura não confiável. Não incluído neste parecer local.", + "community.bundles": "Pacotes de evidência", + "community.activeRecords": "Registros ativos", + "community.revokedRecords": "Registros revogados", + }, }; export function labSupplement( diff --git a/gui/src/i18n/log-guard-labels.ts b/gui/src/i18n/log-guard-labels.ts index 7c0d329fb9e..f7667b4a9ea 100644 --- a/gui/src/i18n/log-guard-labels.ts +++ b/gui/src/i18n/log-guard-labels.ts @@ -298,6 +298,33 @@ const LABELS: Record> = { "error.database_error": "Không thể cập nhật cơ sở dữ liệu nhật ký Codex.", "error.config_write_failed": "Cơ sở dữ liệu đã thay đổi nhưng OpenCodex không thể lưu cài đặt bảo vệ. Vui lòng sửa lỗi lưu trữ cấu hình, sau đó chạy Sửa chữa.", }, + "pt-BR": { + compact: "Compactar", + compactComplete: "Compactação concluída (lógica / espaço recuperado no disco)", + pagesUnit: "páginas", + compactPartial: "Compactação parcial (lógica / espaço recuperado no disco)", + confirmCompact: "Confirmar compactação", + cancel: "Cancelar", + inspectionOnly: "Apenas inspeção", + externalSqliteHome: "Armazenamento SQLite externo", + inspectionUnavailable: "A inspeção de logs de diagnóstico está indisponível.", + metricsSkippedLarge: "Métricas de linhas ignoradas: o banco de dados excede {threshold}, e a leitura bloquearia o proxy.", + protection: "Proteção", + compat: "Compatibilidade", + quiet: "Silencioso", + disable: "Desativar proteção", + repair: "Reparar proteção", + applying: "Aplicando proteção…", + "error.generic": "Não foi possível alterar a proteção de logs do Codex.", + "error.codex_running": "Feche o Codex antes de alterar a proteção de logs.", + "error.process_enumeration_failed": "Não foi possível verificar se o Codex está finalizado. A proteção não foi alterada.", + "error.busy": "O banco de dados de logs do Codex está ocupado. Feche o Codex e tente novamente.", + "error.unsupported_schema": "Este esquema de logs do Codex não é suportado para proteção.", + "error.trigger_collision": "Um nome de trigger reservado do Log Guard já está em uso. A proteção não foi alterada.", + "error.unsafe_path": "O caminho do banco de dados de logs do Codex falhou na verificação de segurança.", + "error.database_error": "Não foi possível atualizar o banco de dados de logs do Codex.", + "error.config_write_failed": "O banco de dados mudou, mas o OpenCodex não conseguiu salvar a configuração de proteção. Corrija o armazenamento de config e execute Reparar.", + }, }; export function logGuardLabel(locale: Locale, key: LogGuardLabelKey): string { diff --git a/gui/src/i18n/log-guard-operation-labels.ts b/gui/src/i18n/log-guard-operation-labels.ts index 8eded1eeddf..c6231111407 100644 --- a/gui/src/i18n/log-guard-operation-labels.ts +++ b/gui/src/i18n/log-guard-operation-labels.ts @@ -133,6 +133,18 @@ const LABELS: Record> = { "error.auto_vacuum_not_incremental": "Cơ sở dữ liệu nhật ký Codex này không được định cấu hình cho tính năng incremental vacuum, do đó không thể thu hồi dung lượng nếu không xây dựng lại hoàn toàn.", "error.integrity_check_failed": "Cơ sở dữ liệu nhật ký Codex không vượt qua được kiểm tra tính toàn vẹn. Không có dung lượng nào được thu hồi.", }, + "pt-BR": { + applying: "Aplicando alteração do Log Guard…", + "error.generic": "Não foi possível atualizar o armazenamento de logs do Codex.", + "error.codex_running": "Feche o Codex antes de alterar o armazenamento de logs do Codex.", + "error.process_enumeration_failed": "Não foi possível verificar se o Codex foi finalizado. A operação do Log Guard não foi iniciada.", + "error.busy": "O banco de dados de logs do Codex está ocupado. Feche o Codex e tente novamente.", + "error.unsupported_schema": "Este esquema de logs do Codex não é suportado para esta operação.", + "error.unsafe_path": "O caminho do banco de dados de logs do Codex falhou na verificação de segurança.", + "error.database_error": "Não foi possível atualizar o banco de dados de logs do Codex.", + "error.auto_vacuum_not_incremental": "Este banco de dados de logs do Codex não está configurado para vacuum incremental; o espaço não pode ser recuperado sem uma recriação completa.", + "error.integrity_check_failed": "O banco de dados de logs do Codex falhou na verificação de integridade. Nenhum espaço foi recuperado.", + }, }; export function logGuardOperationLabel(locale: Locale, key: LogGuardOperationLabelKey): string { diff --git a/gui/src/i18n/log-guard-state-labels.ts b/gui/src/i18n/log-guard-state-labels.ts index 32296ee0eb5..e52e8a2285f 100644 --- a/gui/src/i18n/log-guard-state-labels.ts +++ b/gui/src/i18n/log-guard-state-labels.ts @@ -61,6 +61,11 @@ const LABELS: Record = { protection: { off: "Tắt", active: "Đang hoạt động", drifted: "Cần sửa chữa", unsupported: "Không được hỗ trợ", unknown: "Không xác định" }, mode: { off: "Tắt", compat: "Tương thích", quiet: "Yên tĩnh", collision: "Không xác định" }, }, + "pt-BR": { + schema: { compatible: "Compatível", missing: "Banco de dados não encontrado", unreadable: "Banco de dados indisponível", unsupported: "Não suportado" }, + protection: { off: "Desativada", active: "Ativa", drifted: "Requer reparo", unsupported: "Não suportada", unknown: "Desconhecido" }, + mode: { off: "Desativado", compat: "Compatibilidade", quiet: "Silencioso", collision: "Desconhecido" }, + }, }; export function logGuardSchemaStateLabel(locale: Locale, state: LogGuardSchemaState): string { diff --git a/gui/src/i18n/native-main-copy.ts b/gui/src/i18n/native-main-copy.ts index 71091e37468..aca1473af94 100644 --- a/gui/src/i18n/native-main-copy.ts +++ b/gui/src/i18n/native-main-copy.ts @@ -3,7 +3,7 @@ import { NATIVE_MAIN_TRANSLATIONS, type NativeMainTKey } from "./native-main-tra export type NativeMainTFn = (key: NativeMainTKey, vars?: Record) => string; -/** Closed, nine-locale namespace like the adjacent Log Guard label modules. +/** Closed, eleven-locale namespace like the adjacent Log Guard label modules. * Keep these keys out of the global catalog contract used by existing screens. */ export function nativeMainTranslator(locale: Locale): NativeMainTFn { diff --git a/gui/src/i18n/native-main-translations.ts b/gui/src/i18n/native-main-translations.ts index a1f53768ae2..16994f368dc 100644 --- a/gui/src/i18n/native-main-translations.ts +++ b/gui/src/i18n/native-main-translations.ts @@ -382,4 +382,42 @@ export const NATIVE_MAIN_TRANSLATIONS = { "nativeMain.confirm": "Xác nhận thay đổi đăng nhập gốc", "nativeMain.unavailable": "Không thể thay đổi hồ sơ. Hãy kiểm tra mã chẩn đoán trước khi tiếp tục." }, -} satisfies Record<"en" | "de" | "fr" | "ko" | "zh" | "zh-TW" | "ru" | "ja" | "tr" | "vi", Record>; + "pt-BR": { + "nativeMain.title": "Login principal do Codex nativo", + "nativeMain.manage": "Gerenciar login principal", + "nativeMain.close": "Fechar gerenciador de login principal", + "nativeMain.separate": "Estes controles alteram o login nativo do Codex, não a conta selecionada para a próxima requisição do Pool.", + "nativeMain.home": "CODEX_HOME em vigor", + "nativeMain.current": "Perfil ativo registrado", + "nativeMain.unregistered": "Não registrado", + "nativeMain.physicalHint": "Este diretório home pertence ao servidor OpenCodex, que pode ser um computador diferente. O backend verifica o login físico antes de qualquer alternância.", + "nativeMain.busyOther": "Outra operação de login nativo já está em execução. Conclua ou cancele-a primeiro.", + "nativeMain.working": "Processando…", + "nativeMain.changed": "O diretório home, o perfil ativo ou o estado de recuperação mudou. Revise o estado atualizado e confirme novamente.", + "nativeMain.error": "Não foi possível confirmar a operação. Leia o estado atualizado antes de tentar novamente; uma resposta perdida não comprova a reversão. Use o comando de diagnóstico do servidor abaixo.", + "nativeMain.doctorHint": "Execute {cmd} no servidor para obter detalhes.", + "nativeMain.saved": "Login atual salvo como um perfil. O login físico não foi alterado.", + "nativeMain.restart": "Alteração de login concluída. Reinicie o Codex nativo usando o CODEX_HOME exibido antes de continuar.", + "nativeMain.done": "Operação concluída. O servidor não solicitou a reinicialização do Codex nativo.", + "nativeMain.refreshFailed": "Não foi possível atualizar todas as informações da conta. Uma alteração concluída não foi desfeita. Atualize antes de outra operação.", + "nativeMain.refresh": "Atualizar status", + "nativeMain.unsupported": "Este armazenamento de credenciais não é suportado. O gerenciamento de perfis nativos requer o armazenamento em arquivo.", + "nativeMain.recoveryHint": "Uma transação interrompida precisa de recuperação. Recuperar conclui a reconciliação; reverter desfaz a transação pendente. Nenhuma ação é executada até que você confirme.", + "nativeMain.recover": "Recuperar alteração interrompida", + "nativeMain.rollback": "Reverter transação pendente", + "nativeMain.empty": "Nenhum perfil nativo registrado ainda. Salve o login atual primeiro.", + "nativeMain.active": "Ativo", + "nativeMain.switchTo": "Alternar login nativo para {label}", + "nativeMain.switch": "Alternar", + "nativeMain.restore": "Retornar ao exibido anteriormente: {label}", + "nativeMain.restoreHint": "Este atalho seleciona o perfil exibido antes da sua última alternância, não um histórico de transações verificado pelo servidor. Ele é mantido apenas nesta página.", + "nativeMain.label": "Rótulo do perfil", + "nativeMain.save": "Salvar atual como perfil", + "nativeMain.saveHint": "Para um login ativo já registrado, salvar atualiza seu rótulo. Isso não adiciona um novo login.", + "nativeMain.confirmHint": "Isso altera apenas o login nativo no diretório home abaixo. Feche o Codex nativo naquele computador primeiro. A estratégia de Pool, membros, chaves de provedor e dados de tarefas/histórico não são editados por este painel.", + "nativeMain.stopped": "Eu parei o Codex nativo usando este CODEX_HOME e compreendo que uma reinicialização pode ser necessária.", + "nativeMain.cancel": "Cancelar", + "nativeMain.confirm": "Confirmar alteração de login nativo", + "nativeMain.unavailable": "Alterações de perfil indisponíveis. Verifique o código de diagnóstico antes de continuar." +}, +} satisfies Record<"en" | "de" | "fr" | "ko" | "zh" | "zh-TW" | "ru" | "ja" | "tr" | "vi" | "pt-BR", Record>; diff --git a/gui/src/i18n/pt-BR.ts b/gui/src/i18n/pt-BR.ts new file mode 100644 index 00000000000..3255b5bd502 --- /dev/null +++ b/gui/src/i18n/pt-BR.ts @@ -0,0 +1,3583 @@ +// Brazilian Portuguese translations +// Auto-generated structure matching en.ts key-for-key +export const ptBR: Record = { + "tray.updated": "Atualizado {time} · a cada 60 s", + "tray.today": "Hoje", + "tray.input": "Entrada", + "tray.output": "Saída", + "tray.cost": "Custo · estimado", + "tray.cached": "{percent} em cache", + "usage.incomplete": "Alguns registros de uso não puderam ser incluídos. Contagens, datas e rankings refletem apenas os registros legíveis.", + "models.pickerOrder.usageIncomplete": "Não é possível salvar a ordem mais usada porque o histórico de uso está incompleto. Escolha outra ordem ou repare o histórico primeiro.", + "api.attribution.noRecordedUse": "Nenhum uso nos registros legíveis", + "audio.dictation": "Ditado", + "audio.liveVoice": "Voz ao vivo", + "audio.configured": "Configurado, não verificado", + "audio.notConfigured": "Não configurado", + "audio.unknown": "Metadados de áudio indisponíveis", + "audio.key": "Chave de dados do OpenCodex", + "audio.file": "Arquivo de áudio (máx. 25 MB)", + "audio.transcribe": "Transcrever", + "audio.transcribing": "Transcrevendo...", + "audio.transcript": "Transcrição", + "audio.emptyTranscript": "Nenhuma fala detectada", + "audio.examples": "Exemplos de API", + "audio.streaming": "Ditado em streaming", + "audio.connect": "Verificar conexão", + "audio.disconnect": "Desconectar", + "audio.events": "Eventos da sessão", + "audio.state.idle": "Não verificado", + "audio.state.connecting": "Conectando...", + "audio.state.connected": "Sessão pronta", + "audio.state.disconnected": "Desconectado", + "audio.state.failed": "Falha na conexão", + "audio.error.auth": "Chave rejeitada. Verifique sua chave de dados do OpenCodex.", + "audio.error.unavailable": "Serviço de upstream indisponível. Verifique a conta do provedor.", + "audio.error.rateLimit": "Limite de requisições atingido. Tente novamente mais tarde.", + "audio.error.invalid": "Requisição rejeitada. Verifique o arquivo e o provedor.", + "audio.error.size": "Escolha um arquivo de áudio não vazio de até 25 MB.", + "audio.error.network": "Falha na conexão. Verifique o endereço do proxy.", + "audio.error.timeout": "A requisição excedeu o tempo limite (timeout). Tente novamente.", + "audio.error.protocol": "Resposta de áudio inesperada. Verifique a compatibilidade do provedor.", + "models.pickerOrder.label": "Ordem do seletor", + "models.pickerOrder.default": "Padrão", + "models.pickerOrder.alphabetical": "A a Z por model", + "models.pickerOrder.provider": "Agrupar por provedor", + "models.pickerOrder.mostUsed": "Snapshot de mais usados", + "models.pickerOrder.custom": "Ordem personalizada", + "models.pickerOrder.apply": "Aplicar ordem", + "models.pickerOrder.applying": "Aplicando…", + "models.pickerOrder.saved": "Ordem do seletor salva. Reabra os clientes que ainda mostram o catálogo antigo.", + "models.pickerOrder.pending": "Ordem salva; a atualização do catálogo está pendente.", + "models.pickerOrder.usageFailed": "Não foi possível carregar o uso do model.", + "models.pickerOrder.loadFailed": "Não foi possível carregar as configurações do seletor.", + "models.pickerOrder.retry": "Tentar novamente", + "models.pickerOrder.hint": "Salva a ordem roteada para descoberta do Codex e do Claude. As faixas em destaque/nativas permanecem no lugar; 'Mais usado' é um snapshot. As escolhas nativas anunciadas podem mudar.", + "models.fastRows.title": "Mostrar linhas de models Fast", + "models.fastRows.desc": "Adiciona seletores elegíveis de 'Model Fast' aos seletores de model de clientes externos. Isso não altera as opções de esforço de raciocínio no model base. Salvar atualiza as integrações conectadas quando possível; caso contrário, atualize a integração ou o catálogo do cliente.", + "models.fastRows.refreshHint": "Salvo. A atualização do catálogo está pendente.", + "models.fastRows.enabled": "Linhas de models Fast ativadas.", + "models.fastRows.disabled": "Linhas de modelos rápidos desativadas.", + "models.fastRows.loadFailed": "Não foi possível carregar a configuração de linhas rápidas.", + "models.fastRows.updateFailed": "Falha ao atualizar a configuração de linhas rápidas.", + "codexAuth.quotaAutoRefreshAllHint": "Controla as janelas suportadas de 5 horas e semanais para todas as contas atuais juntas. No modo Pool, uma pequena requisição é enviada após cada reinicialização e consome cota.", + "codexAuth.quotaAutoRefreshMixed": "Algumas janelas estão ativadas.", + "codexAuth.quotaAutoRefreshEmpty": "Nenhuma janela de cota suportada. Atualize as cotas da conta para verificar novamente.", + "codexAuth.quotaAutoRefreshLoadFailed": "Não foi possível carregar as configurações de ativação. Tente novamente para verificar o estado delas.", + "codexAuth.quotaAutoRefreshPartial": "Algumas configurações não puderam ser salvas. Tente novamente para concluir a alteração.", + "nav.dashboard": "Dashboard", + "uptime.day": "d", + "uptime.hour": "h", + "uptime.minute": "m", + "uptime.second": "s", + "nav.startup": "Inicialização", + "nav.providers": "Provedores", + "nav.models": "Modelos", + "nav.combos": "Combos", + "nav.subagents": "Subagentes", + "nav.logs": "Logs e Depuração", + "nav.usage": "Uso", + "common.github": "GitHub", + "sidebar.star": "Marcar com estrela no GitHub", + "sidebar.starred": "Com estrela no GitHub", + "sidebar.starUnauthenticated": "Abrir o GitHub para favoritar (CLI do gh não está conectada)", + "sidebar.starFailed": "Não foi possível favoritar pelo gh. Abrindo o GitHub.", + "onboarding.star.title": "Gostando do OpenCodex?", + "onboarding.star.body": "O OpenCodex é gratuito e de código aberto. Uma estrela no GitHub ajuda outros desenvolvedores a encontrá-lo e a manter o projeto ativo.", + "onboarding.star.cta": "Dar uma estrela no GitHub", + "onboarding.star.ghHint": "Dá uma estrela ao repositório usando a CLI do GitHub (gh) com sua sessão iniciada. Nenhuma estrela será dada até você clicar.", + "onboarding.star.browserHint": "Abre o repositório no github.com no seu navegador.", + "onboarding.star.openPage": "Abrir a página do GitHub em vez disso", + "onboarding.star.later": "Talvez mais tarde", + "onboarding.star.failed": "Não foi possível dar uma estrela usando a CLI do GitHub (gh). Você pode fazer isso na página do GitHub.", + "onboarding.star.starring": "Adicionando estrela…", + "onboarding.star.thanks": "Obrigado pela estrela!", + "onboarding.star.thanksBody": "Isso ajuda muito. O link do GitHub na barra lateral leva você de volta ao repositório quando quiser.", + "onboarding.star.done": "Concluído", + "sidebar.updateAvailable": "Atualização disponível: {version}", + "sidebar.checkUpdate": "Verificar atualizações", + "sidebar.desktopUpdate": "Abrir atualizações do aplicativo para desktop", + "common.save": "Salvar", + "common.saving": "Salvando…", + "common.cancel": "Cancelar", + "common.discard": "Descartar", + "common.delete": "Excluir", + "common.close": "Fechar", + "common.ok": "OK", + "common.remove": "Remover", + "common.loading": "Carregando…", + "common.retry": "Tentar novamente", + "auth.adminTokenTitle": "Token de admin do OpenCodex (OPENCODEX_ADMIN_AUTH_TOKEN)", + "auth.adminAccountLabel": "Conta", + "auth.adminTokenFieldLabel": "Token de admin", + "auth.adminTokenRejected": "Esse token de admin foi rejeitado. Verifique-o e tente novamente.", + "auth.adminTokenUnavailable": "Não foi possível verificar o token de admin. Tente novamente.", + "auth.adminTokenHelp": "Este é o token de gerenciamento administrativo do OpenCodex, não uma chave de API de provedor. O proxy grava isso em ~/.opencodex/admin-api-token (ou $OPENCODEX_HOME/admin-api-token) na primeira inicialização, e OPENCODEX_ADMIN_AUTH_TOKEN substitui esse valor.", + "auth.adminTokenDocsLink": "Como encontrá-lo", + "app.logoAria": "logo do opencodex", + "app.claudeOn": "Claude LIGADO", + "app.claudeOff": "Claude DESLIGADO", + "theme.label": "Tema", + "theme.light": "Claro", + "theme.dark": "Escuro", + "theme.system": "Sistema", + "lang.label": "Idioma", + "lang.nativeName": "Português (Brasil)", + "provider.name.commandCodeAuth": "Command Code - Auth", + "provider.name.commandCodeApi": "Command Code - API", + "provider.name.orcaRouterApi": "OrcaRouter - API", + "provider.name.orcaRouterAuth": "OrcaRouter - Auth", + "provider.name.volcengine": "Volcengine Ark", + "provider.name.volcengineCodingPlan": "Volcengine Ark Coding Plan", + "provider.name.volcengineAgentPlan": "Volcengine Ark Agent Plan", + "errorBoundary.title": "Falha ao carregar a página", + "errorBoundary.message": "Esta seção encontrou um erro de renderização. Recarregue-a para tentar novamente.", + "errorBoundary.details": "Erro", + "errorBoundary.reload": "Recarregar", + "routing.title": "Inteligência de Roteamento (beta)", + "routing.subtitle": "Perfis de política, avaliação de teste (dry-run) e análises de roteamento baseadas em fontes.", + "routing.loadFailed": "Não foi possível carregar os dados de roteamento", + "routing.empty": "Nenhum perfil de roteamento configurado. Adicione `routingProfiles` ao config.json.", + "routing.revision": "rev", + "routing.detail": "Perfil", + "routing.createProfile": "Criar perfil", + "routing.dryRunError": "Falha no teste (HTTP {status})", + "routing.removeConfirm": "Remover o perfil {id}?", + "routing.unknownEvidence.allow": "permitir", + "routing.unknownEvidence.penalize": "penalizar", + "routing.unknownEvidence.exclude": "excluir", + "routing.removeCandidate": "Remover candidato {provider}/{model}", + "routing.candidates": "Candidatos", + "routing.require": "Requisitos rígidos", + "routing.optimize": "Pesos de otimização", + "routing.limits": "Limites", + "routing.unknownEvidence": "Política para evidências desconhecidas", + "routing.compatibility.title": "Política de compatibilidade", + "routing.compatibility.enabled": "Exigir evidências do Laboratório de Compatibilidade", + "routing.compatibility.requiredSuites": "Suítes obrigatórias", + "routing.compatibility.loadingCatalog": "Carregando catálogo do laboratório…", + "routing.compatibility.catalogUnavailable": "Catálogo do laboratório indisponível — insira os IDs das suítes manualmente no config.json.", + "routing.compatibility.layer.protocol_conformance": "Conformidade de protocolo", + "routing.compatibility.layer.live_route_compatibility": "Compatibilidade de rota ativa", + "routing.compatibility.minStatus": "Status mínimo de compatibilidade", + "routing.none": "nenhum", + "routing.unavailable": "–", + "routing.dryRun": "Avaliação de teste", + "routing.dryRunContext": "Janela de contexto da requisição (tokens)", + "routing.dryRunTools": "A requisição requer ferramentas", + "routing.dryRunImage": "A requisição requer entrada de imagem", + "routing.dryRunStructured": "A requisição requer saída estruturada", + "routing.dryRunRun": "Avaliar candidatos", + "routing.candidate": "Candidato", + "routing.eligible": "Elegível", + "routing.exclusions": "Exclusões", + "routing.costCap": "Limite de custo", + "routing.capOutcome.satisfied": "dentro do limite", + "routing.capOutcome.exceeded": "acima do limite", + "routing.capOutcome.unknown-allowed": "desconhecido (permitido)", + "routing.capOutcome.unknown-excluded": "desconhecido (excluído)", + "routing.exclusion.capability-unsatisfied": "capacidade não atendida", + "routing.exclusion.unknown-capability": "capacidade desconhecida", + "routing.exclusion.cost-limit": "acima do limite de custo", + "routing.exclusion.cost-limit-unknown": "custo desconhecido sob o limite", + "routing.exclusion.cooldown": "cooldown", + "routing.exclusion.unknown-health": "saúde desconhecida", + "routing.exclusion.unknown-quota": "quota desconhecida", + "routing.exclusion.unknown-price": "preço desconhecido", + "routing.exclusion.other": "exclusão: {code}", + "routing.score": "Pontuação", + "routing.selected": "selecionado", + "routing.yes": "sim", + "routing.no": "não", + "routing.analytics": "Analytics de roteamento", + "routing.analyticsTotal": "Requisições", + "routing.analyticsSuccessRate": "Sucesso", + "routing.analyticsFallbackRate": "Fallback", + "routing.analyticsP50": "p50", + "routing.analyticsP95": "p95", + "routing.analyticsP99": "p99", + "routing.analyticsCooldown": "Falhas de cooldown", + "routing.analyticsConfidence": "Confiança", + "routing.analyticsTruncated": "histórico truncado", + "routing.analyticsRequests": "Requisições", + "routing.analyticsEmpty": "Nenhum analytics ainda — envie algumas requisições primeiro.", + "startup.title": "Segurança de inicialização", + "startup.subtitle": "Verifique se o Codex consegue alcançar o opencodex após uma reinicialização, antes que o roteamento do proxy local se torne um loop de reconexão.", + "startup.refresh": "Atualizar", + "startup.backToDashboard": "Voltar ao Dashboard", + "startup.loading": "Verificando proteção de inicialização…", + "startup.error": "Não foi possível ler a proteção de inicialização.", + "startup.staleData": "A última verificação de inicialização falhou. Os valores abaixo estão desatualizados e não devem ser tratados como prova de proteção.", + "startup.status.native": "Roteamento nativo", + "startup.status.protected": "Protegido contra reinicialização", + "startup.status.atRisk": "Ação necessária", + "startup.summary.native": "O Codex não depende do proxy local", + "startup.summary.protected": "O opencodex estará disponível após a reinicialização", + "startup.summary.atRisk": "O Codex pode perder o acesso ao model após a reinicialização", + "startup.riskDetail": "O Codex está fixado no proxy local, mas nenhum serviço persistente ou shim de inicialização saudável irá iniciá-lo novamente.", + "startup.riskDetailCustomLocal": "O Codex aponta para um gateway local personalizado. O opencodex não pode gerenciar ou verificar o ciclo de vida de reinicialização desse gateway.", + "startup.riskDetailWindowsShim": "O shim de inicialização protege scripts CLI suportados, mas o Codex Desktop e execuções diretas de codex.exe podem fazer o bypass dele no Windows.", + "startup.safeDetail": "O mecanismo atual de roteamento e inicialização é consistente. Nenhuma inicialização manual com ocx deve ser necessária após reiniciar.", + "startup.routing": "Roteamento do Codex", + "startup.routing.proxy": "Proxy local", + "startup.routing.native": "OpenAI nativo", + "startup.routing.customLocal": "Gateway local personalizado", + "startup.routing.customRemote": "Gateway remoto personalizado", + "startup.routing.unknown": "Roteamento desconhecido ou inválido", + "startup.restartProtection": "Proteção contra reinicialização", + "startup.preference": "Inicialização sob demanda", + "startup.enabled": "Ativado", + "startup.disabled": "Desativado", + "startup.protection.service": "Serviço em segundo plano", + "startup.protection.shim": "Shim do launcher", + "startup.protection.none": "Não instalado", + "startup.details": "Detalhes da proteção", + "startup.service": "Serviço em segundo plano", + "startup.serviceHint": "Inicia no login e reinicia o proxy após uma falha.", + "startup.installed": "Instalado", + "startup.notInstalled": "Não instalado", + "startup.unsupported": "Não suportado", + "startup.shim": "Shim do launcher do Codex", + "startup.shimHint": "Executa o ocx ensure quando um launcher de script do Codex suportado é iniciado.", + "startup.healthy": "Saudável", + "startup.cliOnly": "Apenas CLI", + "startup.stale": "Desatualizado", + "startup.viable": "Pronto", + "startup.unhealthy": "Instalado, mas com problemas", + "startup.conflict": "Conflito de serviço", + "startup.installedDisabled": "Instalado, mas desativado", + "startup.install": "Instalar", + "startup.installing": "Instalando…", + "startup.repair": "Reparar", + "startup.repairing": "Reparando…", + "startup.serviceInstalled": "Serviço em segundo plano instalado com sucesso.", + "startup.serviceRepaired": "Serviço em segundo plano reparado com sucesso.", + "startup.shimInstalled": "Shim do launcher do Codex instalado com sucesso.", + "startup.shimRepaired": "Shim do launcher do Codex reparado com sucesso.", + "startup.installFailed": "Falha na instalação:", + "startup.tray.title": "Área de notificação do Windows", + "startup.tray.hint": "Instale um ícone na área de notificação no login para iniciar, parar, reiniciar, acessar o dashboard e controlar o status do proxy com um clique.", + "startup.tray.login": "Iniciar bandeja no login do Windows", + "startup.tray.notProtection": "A bandeja é um controlador, não uma proteção contra reinicialização. Um serviço em segundo plano viável ainda é necessário para a recuperação autônoma do proxy.", + "startup.tray.running": "Em execução", + "startup.tray.stopped": "Instalado, oculto", + "startup.tray.stale": "Reparo necessário", + "startup.tray.notInstalled": "Não instalado", + "startup.tray.loading": "Verificando…", + "startup.tray.unavailable": "Status indisponível", + "startup.tray.install": "Instalar e mostrar bandeja", + "startup.tray.start": "Mostrar ícone da bandeja", + "startup.tray.stop": "Sair do ícone da bandeja", + "startup.tray.uninstall": "Remover bandeja de login", + "startup.tray.error": "A ação da bandeja do Windows falhou. Verifique o status com ocx tray para obter detalhes.", + "startup.recovery": "Opções de reparo", + "startup.recoveryHint": "Use os instaladores de um clique acima ou copie um comando para reparo manual. O serviço em segundo plano é recomendado para o Codex Desktop e executáveis do Windows.", + "startup.command.service": "Recomendado: serviço persistente em segundo plano", + "startup.command.shim": "Alternativa: atalho do inicializador CLI", + "startup.command.native": "Modo de segurança: restaurar o roteamento nativo do Codex", + "startup.copy": "Copiar", + "startup.copied": "Copiado", + "startup.recommended": "Reparo recomendado: {cmd}", + "startup.navRisk": "A proteção de inicialização requer atenção", + "startup.codexRuntime.clampHidden": "Algumas opções de esforço de raciocínio foram ocultadas porque o OpenCodex utilizou o Codex {version}.", + "startup.codexRuntime.clampHiddenWithEfforts": "Algumas opções de esforço de raciocínio foram ocultadas porque o OpenCodex utilizou o Codex {version} (removidas: {efforts}).", + "startup.codexRuntime.olderBinary": "O OpenCodex está utilizando um binário do Codex mais antigo ({version}). Uma instalação mais recente está disponível.", + "dash.subtitle": "Status em tempo real do proxy local do OpenCodex, seus provedores e os modelos roteados para o Codex.", + "dash.workspace.overview": "Visão geral", + "dash.workspace.sections": "Seções", + "dash.status": "Status", + "dash.online": "Online", + "dash.offline": "Offline", + "dash.version": "Versão", + "dash.uptime": "Tempo de atividade", + "dash.providers": "Provedores", + "dash.tokens30d": "Tokens (30d)", + "dash.coverage": "{pct} de cobertura", + "dash.mem.title": "Observabilidade de memória", + "dash.mem.hint": "Diagnósticos de tempo de execução somente leitura. A memória observada é max(RSS, external, ArrayBuffers) para que a otimização do conjunto de trabalho do Windows não oculte a retenção alocada.", + "dash.mem.rss": "Resident set (RSS)", + "dash.mem.jsHeap": "Heap JS em uso", + "dash.mem.jsHeapArena": "arena {total}", + "dash.mem.pressure": "Em relação ao limite de aviso", + "dash.mem.pressureOf": "{pct}% do limite", + "dash.mem.pressureUnknown": "Nenhum limite relatado", + "dash.mem.jscHeap": "Heap JSC", + "dash.mem.external": "Externo", + "dash.mem.arrayBuffers": "ArrayBuffers", + "dash.mem.observed": "Observado", + "dash.mem.runtime": "Contadores do runtime", + "dash.mem.growth": "Deriva observada / hora", + "dash.mem.perHour": "/h", + "dash.mem.store": "Armazenamento de continuação", + "dash.mem.storeHint": "Cache previous_response_id do proxy. O aumento total de bytes sob um heap em crescimento aponta para a retenção de conversas em vez do alocador do runtime.", + "dash.mem.storeEntries": "Entradas", + "dash.mem.storeTotal": "Total", + "dash.mem.storeLargest": "Maior", + "dash.mem.storeOldest": "Mais antigo", + "dash.mem.threshold": "Limite de aviso", + "dash.mem.lastWarn": "Último aviso", + "dash.mem.never": "Nunca", + "dash.mem.details": "Detalhes", + "dash.mem.unavailable": "Diagnósticos de memória indisponíveis (proxy mais antigo).", + "dash.mem.inFlight": "Requisições em andamento", + "dash.mem.restart": "Drenar e reiniciar", + "dash.mem.restartConfirm": "Aguardar {count} requisição(ões) em andamento e reiniciar (até {seconds}s; as requisições restantes serão interrompidas após o timeout).", + "dash.mem.draining": "Drenando {count} requisição(ões)… reiniciando ao concluir", + "dash.mem.reconnecting": "Reiniciando o proxy… aguardando reconexão", + "dash.mem.restartFailed": "Falha ao drenar e reiniciar. Verifique se o proxy está em execução.", + "dash.mem.restartNoSupervisor": "Nenhuma proteção de reinicialização detectada. O proxy pode permanecer inativo após reiniciar, a menos que você o inicie novamente.", + "dash.activeProviders": "Providers ativos", + "dash.noProviders": "Nenhum provider configurado. Execute {cmd}.", + "dash.col.name": "Nome", + "dash.col.adapter": "Adapter", + "dash.col.baseUrl": "Base URL", + "dash.col.model": "Model", + "dash.modelsNoResults": "Nenhum model corresponde à sua busca.", + "dash.availableModels": "Models disponíveis", + "dash.noModels": "Nenhum model encontrado. Verifique as API keys dos providers.", + "dash.cannotConnect": "Não foi possível conectar ao proxy. Ele está em execução?", + "dash.runStart": "Execute {cmd} para iniciar o proxy.", + "dash.stop": "Parar Proxy", + "dash.stopConfirm": "Parar o proxy e restaurar o Codex nativo?", + "dash.stopFailed": "Falha ao parar o proxy (HTTP {status}).", + "dash.stopStillRunning": "O proxy ainda está respondendo, então não foi interrompido.", + "dash.stopUnknown": "O proxy não confirmou a interrupção. Verifique se ele ainda está em execução antes de tentar novamente.", + "dash.maSwitchFailed": "Falha na troca de modo (HTTP {status}).", + "dash.maNetworkError": "Erro de rede — o proxy está em execução?", + "dash.stopping": "Parando…", + "dash.actions": "Proxy", + "dash.codexRestart": "Recarregar models do Codex", + "dash.codexRestarting": "Parando…", + "dash.codexRestartConfirm": "Parar os app-servers do Codex para recarregarem a lista de models? Qualquer turno do Codex em andamento será interrompido e o Codex não será reiniciado automaticamente — reabra-o depois.", + "dash.codexRestartDone": "{count} app-server(s) do Codex parado(s). Reabra o Codex para carregar a lista de models atual.", + "dash.codexRestartNothing": "Nenhum app-server do Codex está em execução. A próxima inicialização lerá a lista de models atual.", + "dash.codexRestartUnknown": "Não foi possível listar os processos, portanto nada foi parado.", + "dash.codexRestartPartial": "{count} app-server(s) não foram encerrados. Pare-os manualmente se a lista de models continuar desatualizada.", + "dash.codexRestartFailed": "Falha ao recarregar os models do Codex (HTTP {status}).", + "dash.codexRestartUnreachable": "Não foi possível alcançar o proxy.", + "dash.codexRestartMalformed": "O proxy retornou uma resposta inesperada.", + "dash.codexRestartTimeout": "O proxy não respondeu a tempo. Ele ainda pode estar parando os app-servers.", + "models.staleBanner": "O Codex está exibindo uma lista de models mais antiga que este catálogo. Reinicie o Codex para recarregá-la.", + "dash.codexAutoStart": "Iniciar o opencodex com o Codex", + "dash.codexAutoStartHint": "Permite que um shim de inicialização instalado execute ocx ensure. Esta configuração não instala proteção de reinicialização; verifique a segurança de inicialização para ver o estado efetivo.", + "dash.searchModel": "Model sidecar de busca", + "dash.searchModelHint": "Model usado para web_search em models roteados que não são da OpenAI. Requer login no ChatGPT.", + "dash.searchReasoning": "Esforço de reasoning da busca", + "dash.visionModel": "Model sidecar de visão", + "dash.visionModelHint": "Model usado para descrever imagens em models roteados apenas de texto. Requer login no ChatGPT.", + "dash.webSearchSidecar": "Sidecar de busca na web", + "dash.webSearchSidecarHint": "Escolha o backend e o model usados para busca na web em models roteados.", + "dash.webSearchOff": "Desativada", + "dash.webSearchCodexSync": "Salvo. A configuração do Codex não foi regravada — execute Sincronizar modelos para aplicar a alteração.", + "dash.webSearchStream": "Fazer streaming de respostas ao vivo", + "dash.webSearchStreamHint": "Faz streaming do texto inicial e do reasoning do model ao vivo até que ele decida por uma chamada de ferramenta; o restante do turno permanece em buffer para intercepção de busca. O texto escrito antes de uma busca pode se repetir parcialmente.", + "dash.visionSidecar": "Sidecar de visão", + "dash.visionSidecarHint": "Escolha o backend e o model usados para descrever imagens em models roteados apenas de texto.", + "dash.visionOff": "Desligado", + "dash.visionAdvanced": "Configurações avançadas", + "dash.visionMaxDescriptions": "Máximo de descrições por turno", + "dash.visionMaxDescriptionsInvalid": "Insira um número inteiro positivo.", + "dash.visionTimeout": "Timeout", + "dash.visionTimeoutInvalid": "Insira um número inteiro de {min} a {max} milissegundos.", + "dash.visionAdvancedPopover": "Configurações avançadas de visão", + "compactionRouting.title": "Roteamento de compactação", + "compactionRouting.description": "Escolha um modelo para solicitações de compactação do Codex e quais gatilhos ele cobre. Mensagens posteriores mantêm as configurações da conversa.", + "compactionRouting.model": "Modelo de compactação", + "compactionRouting.effort": "Esforço de raciocínio", + "compactionRouting.triggers": "Aplica-se a", + "compactionRouting.triggersManual": "Apenas /compact manual", + "compactionRouting.triggersBoth": "Manual e automático", + "compactionRouting.triggersAuto": "Apenas automático", + "compactionRouting.currentModel": "Usar modelo da conversa", + "compactionRouting.currentEffort": "Manter esforço da solicitação", + "compactionRouting.effortHint": "O raciocínio se aplica onde for suportado pelo endpoint de compactação. O modelo deve aceitar a conversa inteira.", + "compactionRouting.dataNotice": "Uma solicitação de compactação coberta envia a conversa inteira para o provedor do modelo selecionado para sumarização, mesmo quando a conversa roda em outro provedor.", + "compactionRouting.autoNotice": "A compactação automática roda sozinha, então uma conversa longa pode ser enviada para esse provedor sem que você precise solicitar.", + "compactionRouting.providerWarning": "Com esta configuração, cada solicitação de compactação coberta envia o conteúdo completo da conversa para {provider} para sumarização.", + "compactionRouting.comboWarning": "Com esta configuração, cada solicitação de compactação coberta envia o conteúdo completo da conversa para cada destino do combo {combo} ({providers}), incluindo destinos de failover, para sumarização.", + "compactionRouting.comboProvidersUnknown": "seus provedores de destino configurados", + "compactionRouting.loadFailed": "Não foi possível carregar as configurações de compactação.", + "compactionRouting.saved": "Configurações de compactação salvas.", + "compactionRouting.saveFailed": "Não foi possível salvar. Suas alterações ainda estão aqui; tente novamente.", + "dash.shadowCallIntercept": "Interceptação de Shadow Call", + "dash.shadowCallInterceptHint": "Intercepta chamadas auxiliares em segundo plano do Codex App ({models}) para geração de títulos e mensagens de commit e as redireciona para o seu modelo escolhido.", + "dash.shadowCallWarning": "⚠ Quando ativado, TODAS as solicitações para {models} serão substituídas pelo modelo selecionado.", + "dash.shadowCallOriginal": "Original", + "dash.shadowCallModel": "Modelo de substituição", + "dash.shadowCallTooltip": "O Codex App faz chamadas auxiliares em segundo plano para geração de títulos de tópicos, geração de mensagens de commit e orquestração de skills. O modelo auxiliar mudou entre versões do cliente, então o opencodex intercepta cada modelo neste conjunto: {models}. Ative isto para redirecionar essas chamadas para o seu modelo escolhido.", + "models.shadowCallIntercept": "Interceptação de Shadow Call", + "models.shadowCallInterceptHint": "Intercepta chamadas auxiliares em segundo plano do Codex App ({models}) para títulos e mensagens de commit e as redireciona para o seu modelo escolhido.", + "dash.sidecarBackend": "Backend", + "dash.sidecarModel": "Model", + "dash.backendAuto": "Auto", + "dash.backendOpenAI": "OpenAI", + "dash.backendAnthropic": "Anthropic", + "dash.sidecarSaved": "Configurações do sidecar salvas. Aplicado na próxima solicitação.", + "dash.sidecarSaveFailed": "Falha ao salvar as configurações do sidecar.", + "dash.injectionLabel": "Delegação de sub-agente", + "dash.injectionHint": "Escolha o modelo para o qual o Codex deve repassar o trabalho de sub-agentes. As duas chaves abaixo decidem onde essa escolha é usada.", + "dash.injectionManage": "Abrir configurações", + "dash.syncCodexSubagentDefaults": "Também salvar como padrão do Codex", + "dash.syncCodexSubagentDefaultsHint": "Ligado, a escolha acima é gravada na própria configuração do Codex, então novas tarefas começam com esse modelo também. Desligado, ela é lembrada apenas aqui. Ela entra em vigor na próxima sincronização ou reinicialização, e suas configurações [agents] escritas manualmente não são alteradas.", + "dash.multiAgentGuidance": "Diga ao Codex como dividir o trabalho", + "dash.multiAgentGuidanceHint": "Envia uma pequena nota dizendo ao Codex como repassar trabalho para sub-agentes. Na v2, ela nomeia os modelos que pode usar e quais preferir; na v1, ela se aplica apenas com esforço de raciocínio max ou ultra. Desligado, nenhuma nota é adicionada.", + "dash.injectionNone": "Nenhum", + "dash.injectionEffortLabel": "Esforço de raciocínio", + "dash.injectionEffortNone": "Padrão do modelo", + "dash.effortCapLabel": "Limite de esforço do V2 ultra", + "dash.subagentEffortCapLabel": "Limite de esforço do subagente V2", + "dash.effortCapHelp": "Limita o esforço de raciocínio para turnos do V2 em modo ultra. Quando definido, requisições de esforço máximo recebidas (do modo ultra) são limitadas ao nível selecionado. O limite do subagente aplica-se apenas a agentes filhos gerados. Os limites apenas reduzem o esforço, nunca o aumentam. Se um modelo não suportar o nível limitado, ele é reduzido para o nível suportado mais próximo.", + "dash.effortCapNone": "Sem limite", + "dash.maintenance": "Manutenção", + "dash.maintenanceHint": "Atualize o catálogo de modelos do Codex ou instale uma versão mais recente do opencodex.", + "dash.syncModels": "Sincronizar modelos", + "dash.syncModelsHint": "Reescreve o catálogo de modelos do Codex a partir dos provedores que você conectou.", + "dash.syncRun": "Sincronizar agora", + "dash.syncing": "Sincronizando…", + "dash.syncOk": "Sincronização concluída. {count} modelo(s) adicionado(s).", + "dash.syncStaleHint": "Se o Codex ainda mostrar uma lista antiga, reinicie o app-server de longa execução dele ({cmd}).", + "dash.syncFailed": "Falha na sincronização: {error}", + "dash.projectConfigTitle": "A configuração de projeto do Codex ignora o OpenCodex", + "dash.projectConfigHint": "Estas configurações locais do repositório substituem o proxy do OpenCodex (por exemplo, roteiam diretamente para o OpenCode Go). Remova-as para que o roteamento de ~/.codex/config.toml se aplique nesse projeto.", + "dash.checkUpdate": "Verificar atualização", + "dash.updateTitle": "Atualizar opencodex", + "dash.updateDesc": "Verifica o npm para o canal selecionado e, em seguida, escolhe se deseja reiniciar o proxy após a instalação.", + "dash.updateChannel": "Canal", + "dash.updateChecking": "Verificando atualizações…", + "dash.updateInstalled": "Instalado", + "dash.updateLatest": "Mais recente", + "dash.updateAvailable": "Atualização disponível", + "dash.updateCurrent": "Atualizado", + "dash.updateCommand": "Comando", + "dash.updateSource": "Este é um repositório clonado a partir do código-fonte. Atualize-o pelo terminal com o comando exibido.", + "dash.updateUnavailable": "Não foi possível ler a versão mais recente do npm. Tente novamente mais tarde.", + "dash.updateRetry": "Tentar novamente", + "dash.updateRecheck": "Verificar novamente", + "dash.updateCannotAuto": "A atualização com um clique não está disponível ({reason}).", + "dash.updateReason.source_checkout": "código-fonte clonado", + "dash.updateReason.latest_unavailable": "registro npm inacessível", + "dash.updateReason.already_latest": "já está na versão mais recente", + "dash.updateReason.externally_managed": "gerenciado externamente pelo mise; execute o comando exibido", + "dash.updateReason.external_ownership_invalid": "os metadados de propriedade do mise estão ilegíveis ou inconsistentes", + "dash.updateReason.unknown": "atualização indisponível", + "dash.updateRestart": "Reiniciar após a atualização", + "dash.updateRestartHint": "Recomendado. A GUI atual continua executando o código antigo até que o proxy seja reiniciado.", + "dash.runUpdate": "Atualizar", + "dash.updateReconnecting": "Aguardando o proxy reiniciado…", + "dash.updateStatus.running": "Atualizando o opencodex.", + "dash.updateStatus.restarting": "Atualização instalada. Reiniciando o proxy.", + "dash.updateStatus.succeeded": "Atualização concluída.", + "dash.updateVersionTransition": "{currentVersion} -> {latestVersion}.", + "dash.updateStatus.failed": "Falha na atualização.", + "prov.subtitle": "Configure os provedores upstream para os quais o opencodex roteia no Codex. Faça login com uma conta, adicione um provedor ou edite a configuração bruta.", + "prov.add": "Adicionar Provedor", + "prov.editJson": "Editar JSON", + "prov.accountLogin": "Login da conta", + "prov.noOauth": "Nenhum provedor OAuth disponível.", + "prov.loggedIn": "logado", + "prov.notLoggedIn": "não logado", + "prov.logout": "Sair", + "prov.login": "Entrar", + "prov.loginWith": "Entrar com {provider}", + "prov.waitingBrowser": "Aguardando o navegador…", + "prov.didntOpen": "Não abriu? Clique aqui", + "prov.copyLink": "Copiar link", + "prov.dontOpenBrowser": "Não abrir um navegador na máquina do proxy", + "prov.dontOpenBrowserHint": "Útil para um perfil de navegador diferente ou quando o painel não está na máquina do proxy.", + "prov.linkCopied": "Copiado", + "prov.linkCopyUnavailable": "Área de transferência indisponível", + "prov.deviceCode": "Código do dispositivo", + "prov.copyCode": "Copiar código", + "prov.codeCopied": "Código copiado", + "prov.editAlias": "Editar apelido", + "prov.aliasPrompt": "Nome de exibição (deixe em branco para limpar)", + "prov.aliasSaved": "Apelido salvo", + "prov.aliasSaveFailed": "Não foi possível salvar o apelido", + "prov.aliasInvalid": "Use no máximo 80 caracteres, sem caracteres de controle.", + "prov.accountId": "ID", + "prov.pasteRedirect": "Cole a URL de redirecionamento ou o código", + "prov.pasteRedirectHint": "Se o navegador mostrar um erro de localhost, copie a URL completa da barra de endereços e cole-a aqui (ou cole o código de autorização).", + "prov.pasteSubmit": "Enviar", + "prov.pasteSubmitting": "Enviando…", + "prov.pasteOk": "Código enviado — concluindo login…", + "prov.pasteFail": "Não foi possível enviar o código: {error}", + "prov.port": "Port", + "prov.default": "Padrão", + "prov.loadingConfig": "Carregando…", + "prov.saved": "Salvo! Reinicie o proxy para aplicar.", + "prov.loadConfigFail": "Falha ao carregar a configuração", + "prov.invalidJson": "JSON inválido", + "prov.saveFailed": "Falha ao salvar", + "prov.loginFailStart": "Falha ao iniciar o login em {provider}", + "prov.loginError": "Erro de login em {provider}: {error}", + "prov.loginRequestFail": "Falha na requisição de login em {provider}", + "prov.loginCancelled": "Login em {provider} cancelado", + "prov.loginTimeout": "O login em {provider} expirou — o navegador foi fechado ou nunca terminou. Tente novamente.", + "prov.loginOk": "Conectado a {provider}. Execute {cmd} (ou será aplicado em tempo real) para listar seus models.", + "prov.loginSameAccount": "Ainda é a mesma conta de {provider} — altere as contas no navegador e tente Adicionar conta novamente.", + "oauthTos.highTitle": "{provider}: risco de OAuth da assinatura", + "oauthTos.elevatedTitle": "{provider}: ponte OAuth não oficial", + "oauthTos.anthropicBody": "Reutilizar tokens OAuth de assinatura do Claude diretamente por meio de um proxy de terceiros, como o OpenCodex, não é uma integração suportada pela Anthropic e pode levar a restrições de acesso. Integrações de Agent SDK suportadas que usam assinaturas do Claude são separadas.", + "oauthTos.highBody": "O OpenCodex conecta o {provider} por meio de um caminho OAuth de terceiros. O uso não suportado pode levar a limites de acesso ou suspensão.", + "oauthTos.elevatedBody": "O OpenCodex conecta o {provider} por meio de um caminho OAuth não oficial. Use o cliente oficial quando possível; tráfego incomum ou automatizado pode ser tratado como abuso e o acesso pode ser limitado ou suspenso.", + "oauthTos.saferPath": "Opção mais segura: configure uma API key no OpenCodex.", + "oauthTos.acknowledge": "Compreendo o risco e desejo continuar com o OAuth mesmo assim.", + "oauthTos.continue": "Continuar com o OAuth", + "subagentSurface.selectionTitle": "Mudar a superfície do sub-agent para {mode}?", + "subagentSurface.selectionBody": "No modo {mode}, os models do ChatGPT que usam a superfície v2 — Sol e Terra na base, todos os models na v2 — repassam sua tarefa para um model roteado, como o Grok ou Claude, criptografado para o backend do ChatGPT, e o model roteado não consegue lê-la. Essa delegação falha com unreadable_encrypted_agent_task até que seja corrigida na origem. A v1 delega entre provedores de forma confiável.", + "subagentSurface.advisoryTitle": "A v1 agora é a superfície padrão do sub-agent", + "subagentSurface.advisoryBody": "Esta instalação executa {mode}, onde um model do ChatGPT na superfície v2 entrega a um model roteado uma tarefa criptografada que ele não consegue ler, fazendo com que a delegação entre provedores falhe. Recomendamos a v1 até que isso seja corrigido na origem. Sua configuração atual permanece inalterada até que você escolha.", + "subagentSurface.continue": "Continuar", + "subagentSurface.switchToV1": "Mudar para v1", + "subagentSurface.learnMore": "Por que isso falha", + "prov.logoutOk": "Desconectado de {provider}.", + "prov.logoutFail": "Não foi possível desconectar de {provider}. O estado da sua conta permanece inalterado.", + "prov.removed": "Removido \"{name}\".", + "prov.removedDefault": "Removido \"{name}\". O provedor padrão agora é \"{defaultProvider}\".", + "prov.removedShadowTarget": "\"{name}\" foi removido. A Interceptação de chamadas auxiliares ainda aponta para \"{model}\", então as chamadas auxiliares falharão até você escolher outro destino.", + "prov.removeFail": "Falha ao remover \"{name}\".", + "prov.removeLastProvider": "Você não pode remover este provedor quando nenhum outro provedor habilitado puder se tornar o padrão.", + "prov.removeHasDependentCombos": "Remova ou atualize estas combinações dependentes primeiro: {combos}.", + "prov.setDefault": "Definir como padrão", + "prov.setDefaultSuccess": "\"{name}\" agora é o provedor padrão.", + "prov.setDefaultFail": "Não foi possível definir \"{name}\" como o provedor padrão.", + "prov.defaultDisabled": "Habilite este provedor antes de torná-lo o padrão.", + "prov.updateFail": "Não foi possível atualizar este provedor.", + "prov.networkError": "Erro de rede. Verifique se o proxy está em execução e tente novamente.", + "prov.added": "Adicionado \"{name}\". No ar agora — execute {cmd} (ou reinicie) para listar seus modelos no seletor do Codex.", + "prov.modelsNoticeTitle": "Escolher modelos", + "prov.modelsNoticeChecking": "Verificando a lista de modelos. A alteração de modelos não desativa o provedor.", + "prov.modelsNoticePending": "A lista inicial de modelos ainda não foi confirmada. Os modelos ficam ocultos até que a descoberta seja concluída.", + "prov.modelsNoticeOff": "Todas as chaves de modelos foram desativadas (OFF) no registro. Habilite os modelos desejados na página Models.", + "prov.modelsNoticeReady": "Escolha quais modelos aparecem na página Models. A alteração de modelos não desativa o provedor.", + "prov.modelsNoticeFailed": "O provedor foi salvo, mas a lista de modelos não pôde ser atualizada. Tente novamente.", + "prov.modelsNoticeCount": "{count} modelos", + "prov.modelsNoticeOpen": "Abrir Models", + "models.initialSelectionPending": "Descoberta inicial pendente", + "prov.removeConfirm": "Remover o provedor \"{name}\"? Seus modelos desaparecerão do seletor do Codex.", + "prov.hasApiKey": "chave de API configurada", + "prov.hasHeaders": "cabeçalhos personalizados configurados", + "prov.accounts": "Contas ({n})", + "prov.accountsAria": "Alternar contas de {name}", + "prov.accountActive": "Ativo", + "prov.accountReauth": "Reconectar", + "prov.reauthenticate": "Reautenticar", + "prov.reauthAccountMissing": "A conta selecionada não foi encontrada após o login", + "prov.reauthIdentityMismatch": "A conta conectada não corresponde à conta selecionada", + "prov.accountAdd": "Adicionar conta", + "prov.accountNoLabel": "conta {id}", + "prov.accountSwitchTitle": "Usar esta conta", + "prov.accountSwitched": "Alternado para {email}.", + "prov.accountSwitchFail": "Falha ao alternar conta", + "prov.accountRemoved": "Removido {email}.", + "prov.accountRemoveFail": "Não foi possível remover {email}. A conta permanece inalterada.", + "prov.accountRemoveAria": "Remover {email}", + "prov.accountRemoveConfirm": "Remover a conta {email}? O login dela será excluído deste proxy.", + "prov.keyAdd": "Adicionar chave de API", + "prov.keyAdded": "Chave de API adicionada a {name}.", + "prov.keyAddFail": "Falha ao adicionar chave de API", + "prov.keyPlaceholder": "Cole a chave de API", + "prov.keySwitchTitle": "Usar esta chave", + "prov.keySwitched": "Alternado para a chave {key}.", + "prov.keySwitchFail": "Falha ao alternar a chave", + "prov.keyRemoved": "Chave {key} removida.", + "prov.keyRemoveAria": "Remover chave {key}", + "prov.keyRemoveConfirm": "Remover a chave de API {key}? Ela será excluída da configuração deste proxy.", + "prov.activeBadge": "Ativo", + "prov.disabledBadge": "Desativado", + "prov.defaultBadge": "Padrão", + "prov.enable": "Ativar", + "prov.disable": "Desativar", + "prov.enabled": "\"{name}\" ativado. Seus modelos podem aparecer no Codex novamente.", + "prov.disabled": "\"{name}\" desativado. As configurações são mantidas, mas seus modelos ficam ocultos.", + "prov.disabledShadowTarget": "\"{name}\" foi desativado. A Interceptação de chamadas auxiliares ainda aponta para \"{model}\", então as chamadas auxiliares falharão até você escolher outro destino ou reativar \"{name}\".", + "prov.enableFail": "Falha ao ativar \"{name}\".", + "prov.disableFail": "Falha ao desativar \"{name}\".", + "prov.enableAria": "Ativar provedor {name}", + "prov.disableAria": "Desativar provedor {name}", + "prov.defaultCannotDisable": "O provedor padrão não pode ser desativado", + "prov.openaiAccountMode": "Modo de conta do Codex", + "prov.openaiModePool": "Pool", + "prov.openaiModeDirect": "Direto", + "prov.openaiPoolDesc": "Padrão. Roteia o login principal e as contas adicionadas usando afinidade, cota, cooldown e failover.", + "prov.openaiDirectDesc": "Usa apenas o login atual/principal do Codex. As contas armazenadas no pool não são lidas nem rotacionadas.", + "prov.openaiModeSaved": "Modo de conta da OpenAI alterado para {mode}.", + "prov.openaiModeSaveFailed": "Não foi possível alterar o modo de conta da OpenAI.", + "prov.openaiApiDesc": "Usa uma chave de API da OpenAI e nunca usa credenciais de conta do Codex.", + "prov.manageCodexAccounts": "Gerenciar contas do Codex", + "prov.openaiApiMissing": "Chave de API obrigatória", + "prov.openaiApiSetup": "Configurar chave de API", + "models.tab.catalog": "Modelos", + "models.tab.combos": "Combos", + "models.tab.compatibility": "Compatibilidade", + "models.tab.routing": "Roteamento (beta)", + "models.tabsLabel": "Superfícies de modelos", + "models.subtitle.combos": "Grupos ordenados de modelos que respondem como um único ID. Encadeie alvos com failover ou distribua a carga com uma estratégia de balanceamento.", + "models.subtitle.compatibility": "Matriz de verificação de compatibilidade somente leitura com base em evidências de projeção de laboratório.", + "models.subtitle.routing": "Perfis de política, avaliação de teste (dry-run) e análises de roteamento baseadas em origem.", + "models.subtitle": "Ative ou desative quais modelos o Codex vê — passagem (passthrough) nativa do GPT e provedores roteados, agrupados por provedor (clique em um cabeçalho para recolher). Modelos ocultos saem do catálogo e do seletor de modelos, mas continuam chamáveis diretamente pelo ID exato. Salvar atualiza o catálogo do hub. Um cliente deve buscar esse catálogo antes de poder usá-lo; o OpenCodex não pode verificar a ativação em um cliente em execução.", + "models.delivery.title": "Como as alterações chegam ao Codex", + "models.delivery.chip.saved": "Salvo aqui", + "models.delivery.chip.savedHub": "Salvo no hub", + "models.delivery.chip.synced": "Sincronizado em {time}", + "models.delivery.chip.syncedUnknown": "Nenhuma sincronização registrada", + "models.delivery.chip.loaded": "O Codex carrega ao reiniciar", + "models.delivery.saved.title": "Salvo neste proxy", + "models.delivery.saved.body": "Salvar nesta página reescreve o catálogo de modelos que este proxy OpenCodex fornece ao Codex, ou seja, a lista exibida no seletor de modelos do Codex. A confirmação após salvar significa que essa etapa foi concluída.", + "models.delivery.savedHub.title": "Salvo no hub", + "models.delivery.savedHub.body": "Esta máquina está conectada a um hub OpenCodex compartilhado. Por isso, salvar aqui altera o catálogo do hub. A confirmação após salvar significa que o hub recebeu a alteração; esta máquina ainda precisa baixar o catálogo.", + "models.delivery.synced.title": "Sincronizado com esta máquina", + "models.delivery.synced.bodyAt": "Esta máquina baixou o catálogo do hub pela última vez em {time} e o gravou no local em que o Codex o lê. Esse horário indica apenas quando o download ocorreu. Se você salvou no hub depois disso, esta máquina mantém a lista anterior até a próxima sincronização.", + "models.delivery.synced.bodyUnknown": "Não há registro de que esta máquina tenha baixado o catálogo do hub, então o Codex ainda pode estar lendo uma lista antiga. A próxima sincronização baixará o catálogo.", + "models.delivery.loaded.title": "Carregado pelo Codex", + "models.delivery.loaded.body": "O Codex lê o catálogo ao iniciar. Por isso, uma janela do Codex que já estava aberta mantém a lista antiga de modelos. O OpenCodex não consegue verificar qual lista uma instância do Codex em execução está usando. Quando detecta que o Codex foi iniciado antes da sua alteração, um aviso para reiniciá-lo aparece acima das abas.", + "models.delivery.hint": "Se um modelo que você ativou não aparecer no Codex, clique em Recarregar modelos do Codex no canto superior direito desta página e, depois, reabra o Codex.", + "models.nativeGroupLabel": "Nativo da OpenAI", + "models.nativeHint": "Modelos de passagem usam a opção de conta Pool ou Direto selecionada em Provedores. Desativar um modelo o oculta do seletor do Codex (a entrada do catálogo é mantida, portanto, reativá-lo o restaura exatamente). Adicionar um modelo aqui registra um seletor roteado `openai/`, e não um novo ID de passagem bruto.", + "models.active": "{active}/{total} visíveis", + "models.workspace.providers": "Provedores", + "models.workspace.allProviders": "Todos os provedores", + "models.workspace.mainAria": "Detalhes do model", + "models.allOn": "Todos ativados", + "models.allOff": "Todos desativados", + "models.presetLabel": "Models", + "models.presetMode_preset": "Preset", + "models.presetMode_all": "Todos", + "models.presetMode_custom": "Personalizado", + "models.presetSummary": "{count} de {total} exibidos — preset principal v{version}", + "models.presetUpdateAvailable": "Preset v{version} disponível", + "models.presetAppliedToast": "{provider}: preset aplicado — {count} models selecionados", + "models.presetClearedToast": "{provider}: exibindo todos os models", + "models.presetEmpty": "{provider}: o preset não correspondeu a nenhum model — seleção inalterada", + "models.presetConfirmReplace": "Substituir sua seleção pelo preset de {count} models?", + "models.cap350k": "Limite de 350k", + "models.capApplied": "Limite de contexto aplicado — terá efeito no próximo turno do Codex.", + "models.capSaveFailed": "Falha ao salvar o limite de contexto", + "models.contextCapped": "Limite de 350k", + "models.contextCapLabel": "Janela / limite padrão", + "models.v2Label": "Sub-agent", + "models.shadowCallOriginal": "⚠ {models} →", + "models.v2DocsLink": "O que é v1 / v2?", + "models.v2Mode_v1": "v1", + "models.v2Mode_default": "base", + "models.v2Mode_v2": "v2", + "models.v2ModeDesc_v1": "Todos os models → superfície v1", + "models.v2ModeDesc_default": "Padrões do upstream (sol/terra=v2, luna=v1)", + "models.v2ModeDesc_v2": "Todos os models → superfície v2", + "models.keepNativeOnV1": "Manter o ChatGPT na v1", + "models.keepNativeOnV1Hint": "O ChatGPT criptografa tarefas filhas da v2 apenas quando um pai nativo do ChatGPT permanece na v2, para que Grok e Claude não possam lê-las. Ative isto para manter Sol/Terra na v1 e evitar essa criptografia. Os pais roteados mantêm a v2.", + "models.v2Help": "Controla a superfície multi-agent para todos os models.\\n\\nv1: Agent clássico de thread única. Cada model usa a superfície de colaboração v1.\\nbase: Padrões do upstream — sol/terra usam v2, luna usa v1, outros seguem a feature flag do codex.\\nv2: Agent multithread com spawn_agent. Cada model usa a superfície de colaboração v2.\\n\\nNa v2, Manter o ChatGPT na v1 deixa Sol/Terra na superfície v1 para que ainda possam invocar Grok ou Claude. O ChatGPT criptografa tarefas filhas da v2; models roteados não conseguem lê-las. Os pais roteados permanecem na v2.\\n\\nAs alterações se aplicam a novas sessões.", + "dash.multiAgent": "Sub-agent", + "dash.codexDesktopAuthless": "Abrir o Codex sem fazer login", + "dash.codexDesktopAuthlessHint": "Desativado por padrão. Pule o login separado do Desktop para conexões locais elegíveis. Credenciais do upstream ainda são necessárias. Reinicie o Codex após alterar esta configuração. Recursos do Desktop restritos por conta podem ficar indisponíveis.", + "dash.codexClientCompaction": "Usar compactação no lado do cliente", + "dash.codexClientCompactionHint": "Desativado por padrão; apenas loopback autenticado. Compactações futuras armazenam resumos portáteis em texto puro enquanto o roteamento de provedor OpenCodeX e V2 permanecem ativos; o provedor configurado pode processá-los e consumir cota. O histórico permanece intacto e os threads existentes continuam sendo roteados através do proxy via override openai_base_url que o OpenCodeX gerencia; se você definir essa linha por conta própria, ela será mantida e esses threads seguirão seu destino. O histórico ocx1 existente continua recuperável; recupere um thread separadamente apenas antes de reproduzi-lo no Codex nativo. Reinicie o Codex após alterar esta configuração.", + "models.v2Conflict": "[agents] max_threads está definido — o Codex recusará iniciar; remova-o de config.toml", + "models.v2Applied": "Modo sub-agent atualizado — aplica-se a novas sessões (reinicie o aplicativo Codex para atualizar o seletor)", + "models.v2ThreadsLabel": "Threads máximos", + "models.v2ThreadsDefault": "padrão (4)", + "models.v2ThreadsApplied": "Limite de thread atualizado — aplica-se a novas sessões", + "models.v2ThreadsInvalid": "O limite de thread deve ser um número inteiro >= 1", + "models.v2ThreadsApply": "Aplicar", + "models.capValue": "Padrão {value}", + "models.contextSettings": "Janelas personalizadas", + "models.contextSettingsTitle": "Janelas personalizadas — {provider}", + "models.contextDefault": "Padrão do provedor", + "models.contextModel": "Model", + "models.contextModelOverride": "Substituição de model", + "models.contextHint": "Insira a janela real do Codex aqui quando você já a souber. Isso preenche uma janela do upstream ausente e apenas reduz uma maior relatada. Deixe em branco para usar a janela / limite Padrão do provedor, ou 128k se esse limite estiver desativado.", + "models.contextAutomatic": "Descoberta automática", + "models.contextSaved": "Janelas de contexto atualizadas — entram em vigor no próximo turno do Codex.", + "models.contextUnchanged": "Nenhuma alteração na janela de contexto para salvar.", + "models.contextSaveFailed": "Falha ao salvar as janelas de contexto", + "models.contextInvalid": "As janelas de contexto devem ser números inteiros positivos", + "models.contextCappedValue": "Limite de {value}", + "models.setAll": "Definir tudo", + "models.setAllHint": "Ativa a janela padrão de {value} para cada provedor roteado. Relays que omitirem context_window / context_length usarão este valor como a janela real do Codex. Use janelas personalizadas na linha de um provedor para definir um modelo manualmente. Provedores nativos não são afetados.", + "models.collapseAll": "Recolher tudo", + "models.expandAll": "Expandir tudo", + "models.orderHint": "A ordem padrão segue as seleções em destaque e a prioridade do catálogo, com a ordenação de provedor/modelo para linhas roteadas empatadas. Uma ordem de seletor salva pode substituir a ordem de exibição; chaves de visibilidade filtram quais linhas aparecem. Um cliente pode manter um catálogo mais antigo até buscar novamente.", + "models.custom": "Personalizado…", + "models.customApply": "Aplicar", + "models.customPlaceholder": "Tokens (ex: 420000)", + "models.customAdd": "Adicionar modelo personalizado", + "models.customAddTitle": "Adicionar modelo personalizado — {provider}", + "models.customEditTitle": "Editar modelo personalizado — {provider}", + "pws.manageModelVisibility": "Gerenciar visibilidade em Modelos", + "pws.modelOwnershipLoading": "Verificando definições de modelo…", + "pws.modelOwnershipFailed": "Não foi possível carregar as definições de modelo. Tente novamente antes de fazer alterações.", + "pws.modelSelectionPending": "Conclua a seleção de modelos em Modelos antes de fazer alterações.", + "pws.modelSaved": "Definição de modelo personalizado salva.", + "pws.modelSavedHidden": "Definição salva. Este modelo está oculto; gerencie a visibilidade em Modelos.", + "pws.modelSavedRefreshPending": "Definição salva, mas não foi possível atualizar o catálogo de modelos. Tente atualizar novamente; não o adicione de novo.", + "pws.modelMutationUnconfirmed": "Não foi possível confirmar a alteração. Atualize os modelos antes de tentar novamente.", + "pws.modelRemovedRefreshPending": "A alteração foi salva, mas não foi possível atualizar o catálogo de modelos. Tente atualizar novamente.", + "pws.modelHidden": "Modelo oculto. Restaure a visibilidade em Modelos.", + "pws.modelDefinitionDeleted": "Definição personalizada excluída. Um modelo subjacente ainda pode aparecer.", + "pws.modelKnown": "Este modelo já é conhecido. Gerencie sua visibilidade in Modelos.", + "models.customAdded": "Modelo personalizado adicionado", + "models.customUpdated": "Modelo personalizado atualizado", + "models.customDeleted": "Modelo personalizado excluído", + "models.customSaveFailed": "Falha ao salvar o modelo personalizado", + "models.customSaving": "Salvando…", + "models.customAddBtn": "Adicionar", + "models.customEditBtn": "Atualizar", + "models.customEdit": "Editar", + "models.customDelete": "Excluir", + "models.customDeleteConfirm": "Excluir a definição personalizada para {name}? Um modelo nativo ou descoberto subjacente pode aparecer novamente.", + "models.hide": "Ocultar", + "models.hideConfirm": "Ocultar {name} do catálogo de modelos? Isso não remove sua definição nem altera a política de roteamento direto.", + "models.customBadge": "Personalizado", + "models.customSummary": "{count} personalizado", + "models.customFieldModelId": "ID do modelo (slug do endpoint)", + "models.customFieldModelIdPlaceholder": "ex: qwen4-max-preview", + "models.customFieldDisplayName": "Nome de exibição (opcional)", + "models.customFieldDisplayNamePlaceholder": "ex: Qwen 4 Max Preview", + "models.customFieldContext": "Janela de contexto", + "models.customFieldModalities": "Modalidades de entrada", + "models.customFieldReasoning": "Esforço de raciocínio", + "models.customFieldReasoningOverride": "Substituir esforço de raciocínio", + "models.reasoningEffort.none": "Nenhum", + "models.reasoningEffort.minimal": "Mínimo", + "models.reasoningEffort.low": "Baixo", + "models.reasoningEffort.medium": "Médio", + "models.reasoningEffort.high": "Alto", + "models.reasoningEffort.xhigh": "Extra alto", + "models.reasoningEffort.max": "Máximo", + "models.reasoningEffort.ultra": "Ultra", + "models.tipProvider": "Provider", + "models.tipContext": "Contexto", + "models.tipModalities": "Modalidades", + "models.tipStatus": "Status", + "models.tipActive": "Ativo", + "models.tipDisabled": "Desativado", + "models.applied": "Salvo no hub. A busca do cliente e a ativação em tempo de execução são estados separados.", + "models.integrationRefreshWarning": "Seleção de modelo salva. Alguns catálogos de clientes não puderam ser atualizados. Verifique as integrações antes de iniciar uma nova sessão.", + "models.saveFailed": "Falha ao salvar", + "models.networkError": "Erro de rede — o proxy está rodando?", + "models.loadFail": "Falha ao carregar modelos — o proxy está rodando?", + "models.noRouted": "Nenhum modelo roteado", + "models.noRoutedHint": "Faça login em um provider ou adicione um primeiro.", + "models.emptyDiscovery": "Nenhum modelo foi descoberto. Verifique o endpoint do provider ou adicione um modelo estático/customizado.", + "models.emptyDiscoveryDisabled": "A descoberta de modelos em tempo real está desativada e nenhum modelo estático está configurado.", + "models.discoveryFailedBadge": "Falha na descoberta", + "models.discoveryFailedHttp": "A descoberta de modelos falhou (HTTP {status}).", + "models.discoveryFailedBlocked": "A descoberta de modelos foi bloqueada pela política de destino.", + "models.discoveryFailedInvalidResponse": "A descoberta de modelos retornou uma resposta inválida.", + "models.discoveryFailedNetwork": "A descoberta de modelos falhou devido a um erro de rede.", + "models.discoveryFailedProvider": "O provider relatou um erro na descoberta de modelos.", + "models.discoveryFailedGeneric": "A descoberta de modelos falhou.", + "models.openProviderSettings": "Abrir configurações do provider", + "models.inactiveNoCredit": "Sem créditos", + "models.inactiveNoCreditHint": "Todos os providers por trás desta entrada estão sem créditos no momento, portanto uma requisição falharia. Ele permanece listado e voltará a ser utilizável quando os créditos forem redefinidos ou recarregados.", + "models.discoveryFailedDependency": "A descoberta de modelos está ativada para este provider. Enquanto continuar falhando, desative “{control}” nas configurações do provider para usar modelos estáticos ou adicionados manualmente.", + "models.loading": "Carregando...", + "models.search": "Buscar modelos...", + "models.showMore": "Mostrar mais {n}", + "models.freeOnly": "Apenas gratuitos", + "models.noFreeMatch": "Nenhum modelo gratuito aqui. Desative \"Apenas gratuitos\" para ver o resto.", + "models.allowlistLabel": "Apenas selecionados", + "models.allowlistHint": "Apenas os modelos marcados vão para o catálogo (vazio = todos). Útil para providers que expõem milhares de modelos.", + "models.selectedCount": "{n} selecionados", + "sub.subtitle": "O {cmd} do Codex anuncia apenas os primeiros 5 modelos (por prioridade) como substitutos. Escolha até 5 aqui — gpt nativo ou roteado — e o opencodex define a prioridade do catálogo deles para que exatamente estes liderem. Qualquer outro modelo ainda pode ser chamado pelo seu nome exato; isso controla apenas o que é exibido.", + "sub.featured": "Destaques", + "sub.advanced": "Avançado", + "sub.orderHintAria": "Como esta ordem é usada", + "sub.orderHint": "A ordem exibida aqui define as posições 1 a 5 no topo do seletor de modelos do Codex e os candidatos a modelo padrão para {cmd}.", + "sub.noneSelected": "Nenhum selecionado — escolha na lista abaixo.", + "sub.models": "Modelos", + "sub.search": "Buscar modelos (gpt nativo + roteado)...", + "sub.settings": "Configurações", + "sub.sections": "Seções de subagentes", + "sub.delegation.model": "Modelo para chamar primeiro", + "sub.delegation.modelHint": "O modelo que o Codex busca primeiro quando delega trabalho. Em destaque acima está a lista que ele pode chamar; este é o que ele chama primeiro.", + "sub.noModels": "Nenhum modelo — faça login em um provedor ou adicione um primeiro.", + "sub.saved": "{n} modelos salvos. Inicie uma nova sessão do Codex (or execute {cmd}) para vê-los como substituições de spawn_agent.", + "sub.saveFailed": "Falha ao salvar", + "sub.networkError": "Erro de rede — o proxy está rodando?", + "sub.loadFail": "Falha ao carregar modelos — o proxy está rodando?", + "sub.loading": "Carregando…", + "sub.moveUp": "Mover {m} para cima", + "sub.moveDown": "Mover {m} para baixo", + "sub.removeAria": "Remover {m}", + "sub.workspace.addToFeatured": "Adicionar {m} aos destaques", + "sub.workspace.allModels": "Todos os modelos", + "sub.workspace.featuredFull": "A lista de destaques está cheia (máx. 5)", + "sub.workspace.mainAria": "Detalhes do modelo de subagente", + "sub.workspace.notFeatured": "Não destacado", + "sub.workspace.priority": "Prioridade", + "sub.ultraMode": "Delegação sempre proativa", + "sub.ultraModeHint": "Ativa a política de delegação multi-agente proativa para cada modelo e esforço de raciocínio (não altera o esforço de raciocínio em si). Grava features.multi_agent_v2.multi_agent_mode_hint_text em config.toml.", + "sub.ultraModeV2Required": "Requer a interface multi-agente v2 — ative multi_agent_v2 e selecione v2 no controle do modo de subagente primeiro.", + "sub.ultraModeText": "Texto de delegação proativa", + "sub.ultraModePreset": "Restaurar predefinição", + "sub.ultraModeLoadFail": "Falha ao carregar as configurações de delegação proativa — o proxy está rodando?", + "sub.ultraModeSaveFail": "Falha ao salvar as configurações de delegação proativa", + "sub.ultraModeSaved": "Delegação proativa salva. Aplicada a novas sessões do Codex.", + "sub.workspace.removeFromFeatured": "Remover {m} dos destaques", + "sub.workspace.selectModel": "Selecione um modelo", + "sub.workspace.selectModelDesc": "Escolha um modelo da lista para ver os detalhes e destacá-lo para spawn_agent.", + "sub.workspace.selector": "Seletor público", + "sub.fallbackLabel": "Cadeia de fallback do subagente", + "sub.fallbackHint": "Modelos ordenados tentados quando um modelo de subagente está indisponível ou falha.", + "sub.fallbackAdd": "Adicionar modelo de fallback…", + "sub.fallbackPoll": "Intervalo de verificação de disponibilidade", + "sub.fallbackSaved": "Configurações de fallback do subagente salvas.", + "sub.fallbackSaveFailed": "Falha ao salvar as configurações de fallback", + "sub.fallbackUnavailable": "Não anunciado no momento; mantido na cadeia.", + "sub.fallbackPollInvalid": "Insira um número inteiro de 5000 a 600000 ms.", + "sub.v2Compatibility.title": "Compatibilidade V2 com pai nativo", + "sub.v2Compatibility.risk": "Se um pai nativo do ChatGPT delegar para este modelo roteado usando V2, a tarefa dele poderá ser criptografada e falhar antes da execução. Tarefas legíveis de pais roteados não são afetadas.", + "sub.v2Compatibility.recoveryUnknown": "O estado de habilitação/elegibilidade de recuperação não é exposto por este servidor. Use delegação compatível com V1/texto puro, ou habilite a recuperação experimental V2 apenas se for elegível. A recuperação adiciona cota, latência, dependência de backend e possível perda de fidelidade; ela não conserta o protocolo upstream.", + "sub.v2Compatibility.details": "Detalhes de compatibilidade", + "logs.title": "Logs de Requisições", + "logs.tabLogs": "Logs", + "logs.tabDebug": "Depuração", + "logs.subtitle": "Requisições recentes roteadas através do proxy local do opencodex, mais recentes primeiro.", + "logs.autoRefresh": "Atualização automática", + "logs.noRequests": "Nenhuma requisição ainda.", + "logs.loadError": "Não foi possível carregar os logs de requisições.", + "logs.filter.surface.label": "Interface", + "logs.filter.model.all": "Todos os modelos", + "logs.filter.provider.label": "Provedor", + "logs.filter.provider.all": "Todos os provedores", + "logs.filter.status.label": "Status", + "logs.filter.status.all": "Todos os status", + "logs.filter.status.success": "Sucesso (2xx)", + "logs.filter.status.errors": "Erros (4xx/5xx)", + "logs.filter.time.label": "Período", + "logs.filter.time.all": "Todo o período", + "logs.filter.time.15m": "Últimos 15 min", + "logs.filter.time.1h": "Última 1 hora", + "logs.filter.time.24h": "Último 1 dia", + "logs.filter.speed.label": "Velocidade", + "logs.filter.speed.all": "Todas as velocidades", + "logs.filter.speed.slow": "< 15 tok/s", + "logs.filter.speed.medium": "15–< 50 tok/s", + "logs.filter.speed.fast": "≥ 50 tok/s", + "logs.filter.reset": "Redefinir filtros", + "logs.filter.showingCount": "Mostrando {count} de {total}", + "logs.noMatchingRequests": "Nenhuma requisição correspondente.", + "logs.filter.surface.all": "Todas", + "logs.filter.surface.claude": "Claude", + "logs.filter.surface.codex": "Codex", + "logs.filter.surface.grok": "Grok", + "logs.filter.interceptedHelpersOnly": "Apenas helpers interceptados", + "logs.badge.interceptedHelper": "I · {model}", + "logs.badge.interceptedHelperTitle": "Requisição de helper interceptada", + "logs.filter.conversation.label": "Conversa", + "logs.filter.conversation.placeholder": "Cole o conversation id", + "logs.filter.conversation.clear": "Limpar", + "logs.filter.model.label": "Modelo", + "logs.filter.model.placeholder": "Filtrar por modelo ou provedor", + "logs.filter.conversation.apply": "Filtrar logs", + "logs.conversation.totals": "{requests} requisições · {tokens} tokens · {cost}", + "logs.conversation.scope": "Os totais cobrem apenas o anel de logs carregado no momento.", + "logs.conversation.excluded": "({unpriced} sem preço, {unmetered} não metrificados excluídos de ~$)", + "logs.cost.approximate": "{amount}", + "logs.cost.lowerBound": "≥{amount}", + "logs.cost.unavailable": "—", + "logs.detail.conversation": "Conversa", + "logs.badge.claude": "Claude", + "logs.badge.grok": "Grok", + "logs.col.time": "Horário", + "logs.col.request": "Requisição", + "logs.col.model": "Modelo", + "logs.col.effort": "Esforço", + "logs.col.provider": "Provedor", + "logs.col.status": "Status", + "logs.col.tokens": "Tokens", + "logs.col.tokPerSec": "tok/s", + "logs.col.estimatedCost": "~$", + "logs.metric.tokPerSecTitle": "Tokens de output por segundo durante toda a duração da requisição", + "logs.metric.estimatedCostTitle": "Equivalente ao preço de tabela da API, não é uma cobrança real; preços não correspondidos ficam indisponíveis", + "usage.cost.total": "Equivalente ao preço de tabela da API (este intervalo)", + "usage.cost.disclaimer": "Não é um recibo de cobrança. O uso de assinatura ou créditos do provedor podem ser aplicados em vez disso.", + "usage.cost.unpricedNote": "{count} requisições excluídas (sem preço ou uso)", + "usage.cost.excluded": "({count} requisições excluídas)", + "usage.cost.excludedOne": "({count} requisição excluída)", + "logs.detail.section.basic": "Informações básicas", + "logs.detail.route.section": "Decisão de rota", + "logs.detail.route.kind": "Tipo de rota", + "logs.detail.route.profile": "Perfil", + "logs.detail.route.selected": "Selecionada", + "logs.detail.route.candidates": "Candidatas", + "logs.detail.route.unknown": "Nenhum rastreamento de rota gravado para esta requisição (linha pré-rastreamento).", + "logs.filter.protocol.label": "Caminho do protocolo", + "logs.filter.protocol.all": "Todos os caminhos", + "logs.filter.protocol.none": "Sem dados de caminho", + "logs.protocol.mode.native": "Nativo", + "logs.protocol.mode.translated": "Traduzido", + "logs.protocol.mode.legacyBridge": "Ponte legada", + "logs.protocol.mode.blocked": "Bloqueado", + "logs.protocol.disposition.passthrough": "Encaminhado sem alterações", + "logs.protocol.disposition.translated": "Traduzido", + "logs.protocol.disposition.degraded": "Degradado", + "logs.protocol.disposition.unsupported": "Descartado", + "logs.protocol.wire.responses": "Responses", + "logs.protocol.wire.chat": "Chat", + "logs.protocol.wire.messages": "Messages", + "logs.protocol.wire.other": "Outro adaptador", + "logs.protocol.hop.ir": "IR", + "logs.protocol.hop.internal": "Responses (interno)", + "logs.protocol.badgeTitle": "Caminho do protocolo: {path} ({mode})", + "logs.detail.protocol.section": "Caminho do protocolo", + "logs.detail.protocol.inbound": "API do cliente", + "logs.detail.protocol.mode": "Modo de entrega", + "logs.detail.protocol.upstream": "Protocolo de upstream", + "logs.detail.protocol.requestPath": "Caminho da requisição", + "logs.detail.protocol.responsePath": "Caminho da resposta", + "logs.detail.protocol.reasons": "Motivos", + "logs.detail.protocol.features": "Efeitos nos recursos", + "logs.detail.protocol.attempts": "Caminhos das tentativas", + "logs.detail.protocol.attempt": "Tentativa {ordinal}", + "logs.detail.protocol.none": "Nenhum dado de caminho registrado para esta requisição.", + "logs.detail.section.performance": "Desempenho", + "logs.detail.section.cost": "Equivalente ao preço de tabela da API", + "logs.detail.section.attempts": "Tentativas de combo", + "logs.detail.section.usage": "Uso bruto", + "logs.detail.ttft": "TTFT", + "logs.detail.decodeTokPerSec": "Taxa de decodificação (est.)", + "logs.detail.reason.ttft_missing": "Nenhum tempo até o primeiro token (time-to-first-token) foi registrado para esta requisição, portanto não há janela de decodificação para medir.", + "logs.detail.reason.decode_window_too_short": "A janela após o primeiro token foi inferior a um segundo, o que é muito curto para estimar uma taxa de decodificação.", + "logs.detail.costTotal": "Equivalente ao preço de tabela", + "logs.detail.totalTokens": "Total de tokens", + "logs.detail.matchedKey": "Chave de preço correspondida", + "logs.detail.priceSource": "Origem do preço", + "logs.detail.unavailableReason": "Motivo da indisponibilidade", + "logs.detail.copyRequestId": "Copiar ID da requisição", + "logs.detail.copied": "Copiado", + "logs.detail.source.jawcode": "Catálogo jawcode", + "logs.detail.source.expected": "Sobrescrita de preço esperada", + "logs.detail.source.user": "Sobrescrita de preço configurada pelo provedor", + "logs.detail.verification.verified": "Verificado", + "logs.detail.verification.derived": "Derivado do modelo base", + "logs.detail.attempt.target": "Provedor / modelo", + "logs.detail.attempt.reason": "Resultado / motivo", + "logs.detail.attempt.completed": "Concluído", + "logs.detail.attempt.e2eNote": "O tok/s de nível superior é de ponta a ponta (end-to-end); cada tentativa usa sua própria duração.", + "logs.detail.attempt.recovery.transient5xx": "Erro 5xx transitório", + "logs.detail.attempt.recovery.connectionReset": "Conexão reiniciada", + "logs.detail.attempt.recovery.oauth401": "Reautenticação OAuth", + "logs.detail.attempt.recovery.key429": "Chave com limite de taxa excedido (429)", + "logs.detail.attempt.recovery.rateLimit429": "Limite de taxa excedido (429)", + "logs.detail.attempt.recovery.anthropicOauth429": "OAuth da Anthropic com limite de taxa excedido (429)", + "logs.detail.attempt.recovery.image413": "Payload da imagem muito grande (413)", + "logs.detail.attempt.recovery.emptyCompletion": "Nova tentativa de conclusão vazia", + "logs.detail.attempt.recovery.consoleGoUpload": "Nova tentativa de upload do console", + "logs.detail.attempt.recovery.key401": "Reautenticação da chave de API", + "logs.detail.attempt.recovery.oauthAccount429": "Limite de requisições da conta atingido (429)", + "logs.detail.attempt.recovery.oauthAccount403": "Validação da conta necessária (403)", + "logs.detail.attempt.recovery.opaqueBlobRejection": "Estado criptografado obsoleto descartado", + "logs.detail.attempt.recovery.reasoningEffortDowngrade": "Nível de raciocínio reduzido", + "logs.detail.attempt.recovery.anthropicFastDowngrade": "Modo rápido recusado; nova tentativa em velocidade padrão", + "logs.detail.outcome.label": "Resultado", + "logs.detail.outcome.completed": "Concluído", + "logs.detail.outcome.failed": "Falhou", + "logs.detail.outcome.incomplete": "Incompleto", + "logs.detail.outcome.aborted": "Abortado", + "logs.detail.sends.label": "Envios ao serviço upstream", + "logs.detail.sends.unresolved": "não resolvido", + "logs.detail.attempt.recovery.unknown": "Motivo de recuperação desconhecido", + "logs.detail.cause.label": "Causa da falha", + "logs.detail.stage.label": "etapa alcançada", + "logs.detail.resend.label": "Reenviar", + "logs.detail.cause.transportUnsent": "Nunca enviado ao serviço upstream", + "logs.detail.cause.transportAmbiguous": "Conexão perdida; estado do serviço upstream desconhecido", + "logs.detail.cause.upstreamDeclined": "O serviço upstream recusou iniciar", + "logs.detail.cause.rateLimit": "Limite de requisições atingido", + "logs.detail.cause.quotaExhausted": "Cota esgotada", + "logs.detail.cause.credentialRejected": "Credenciais rejeitadas", + "logs.detail.cause.policyRefusal": "Recusado pela política de conteúdo", + "logs.detail.cause.parameterRejected": "Parâmetro da requisição rejeitado", + "logs.detail.cause.ciphertextRefusal": "Estado criptografado rejeitado", + "logs.detail.cause.payloadTooLarge": "Payload muito grande", + "logs.detail.cause.payloadRejected": "Payload rejeitado", + "logs.detail.cause.upstreamFault": "Falha no serviço upstream", + "logs.detail.cause.emptyOutput": "Nenhuma saída utilizável", + "logs.detail.cause.clientCancelled": "Cancelado pelo cliente", + "logs.detail.cause.localRefusal": "Recusado por este proxy", + "logs.detail.stage.preHeader": "sem cabeçalhos de resposta", + "logs.detail.stage.headersOnly": "apenas cabeçalhos", + "logs.detail.stage.protocolPrelude": "preâmbulo do protocolo", + "logs.detail.stage.semanticOutput": "saída entregue", + "logs.detail.stage.sideEffect": "efeito colateral produzido", + "logs.detail.stage.terminal": "resposta entregue", + "logs.detail.resend.permitted": "Pode ser reenviado", + "logs.detail.resend.permittedAfterRepair": "Pode ser reenviado após correção", + "logs.detail.resend.refusedAmbiguous": "Não reenviado: estado do serviço upstream desconhecido", + "logs.detail.resend.refusedCommitted": "Não reenviado: o solicitante já recebeu a saída", + "logs.detail.resend.refusedFutile": "Não reenviado: a mesma solicitação falharia novamente", + "logs.detail.reason.usage_missing": "O uso nao foi reportado.", + "logs.detail.reason.usage_unsupported": "Este provedor nao reporta o uso.", + "logs.detail.reason.output_missing": "Nenhuma contagem de tokens de saida valida foi reportada.", + "logs.detail.reason.invalid_duration": "A duracao da requisicao e invalida.", + "logs.detail.reason.price_unmatched": "Nenhum preco correspondente foi encontrado.", + "logs.detail.reason.invalid_cache_breakdown": "Os detalhes dos tokens de cache entram em conflito com o total de tokens de entrada.", + "logs.detail.reason.invalid_usage": "O uso contem um valor de token invalido.", + "logs.detail.reason.combo_attempt_unavailable": "Pelo menos uma tentativa de combinacao nao pudo ser precificada.", + "logs.detail.estimate.usage_estimated": "O uso do provedor e estimado.", + "logs.detail.estimate.cache_detail_missing": "Os detalhes de cache nao estavam disponiveis; a entrada e uma estimativa de limite superior.", + "logs.detail.estimate.expected_price_overlay": "Foi utilizado um preco de tabela esperado e verificado.", + "logs.detail.estimate.provider_cost_overlay": "Foi utilizada uma sobreposicao de preco configurada pelo provedor.", + "logs.detail.estimate.priority_lower_bound": "O preco de Priority confirmado esta indisponivel; a estimativa exibida e um limite inferior conhecido.", + "logs.col.error": "Erro", + "logs.col.upstreamReason": "Motivo do upstream", + "logs.col.duration": "Duracao", + "logs.modelTooltip.model": "model", + "logs.modelTooltip.resolvedModel": "model resolvido", + "logs.modelTooltip.servedModel": "modelo usado na resposta", + "logs.modelTooltip.wireModel": "modelo enviado na requisição", + "logs.modelRerouteTitle": "O serviço upstream usou um modelo diferente do solicitado", + "logs.modelTooltip.requestedTier": "tier solicitado", + "logs.modelTooltip.configuredTier": "tier configurado", + "logs.modelTooltip.responseTier": "tier de resposta", + "logs.modelTooltip.supportsTier": "suporte a tier", + "logs.modelTooltip.tierOutcome.confirmed": "confirmado", + "logs.modelTooltip.tierOutcome.assumed": "assumido", + "logs.modelTooltip.tierOutcome.downgraded": "rebaixado", + "logs.modelTooltip.tierOutcome.unknown": "desconhecido", + "logs.tokens.reported": "reportado", + "logs.tokens.unreported": "nao reportado", + "logs.tokens.unsupported": "nao suportado", + "logs.tokens.estimated": "estimado", + "logs.tokens.input": "input", + "logs.tokens.output": "output", + "logs.tokens.cacheRead": "leitura de cache (c)", + "logs.tokens.cacheWrite": "escrita de cache (w)", + "logs.tokens.reasoning": "reasoning", + "logs.tokens.noCache": "sem dados de cache", + "logs.tokens.contextTotal": "contexto ativo", + "logs.tokens.noCacheNote": "este provedor nao reporta tokens de cache", + "logs.tokens.noCacheCursor": "Detalhes de cache do Cursor nao reportados", + "logs.tokens.noCacheCursorNote": "O Cursor nao expoe contagens de tokens de leitura/escrita de cache; isto e desconhecido, nao um cache miss confirmado", + "logs.tokens.estimatedNote": "estimado (o provedor nao reporta o uso exato)", + "logs.details": "Detalhes", + "logs.detailTitle": "Detalhes da requisicao", + "logs.detailRaw": "Entrada de log bruta", + "debug.title": "Debug", + "debug.subtitle": "Diagnosticos de extracao de uso e transporte do provedor opcionais. Erros de requisicao e 502s permanecem na aba Logs.", + "debug.debug": "Debug do provedor", + "debug.usage": "Extracao de uso", + "debug.injection": "Log de injecao", + "debug.claude": "Claude de entrada", + "debug.claudeInbound.title": "Requisições de entrada do Claude", + "debug.claudeInbound.sub": "O que o Claude Code/Desktop realmente envia (thinking, effort, metadados) — nenhum texto de prompt é armazenado.", + "debug.claudeInbound.empty": "Nenhuma requisição capturada ainda. Envie uma mensagem pelo Claude enquanto isto estiver ativado.", + "debug.claudeInbound.time": "Horário", + "debug.claudeInbound.endpoint": "Endpoint", + "debug.claudeInbound.model": "Model", + "debug.claudeInbound.none": "nenhum", + "debug.reset": "Limpar substituições de tempo de execução", + "debug.refresh": "Atualizar", + "debug.follow": "Acompanhar", + "debug.streamProvider": "Provider", + "debug.streamUsage": "Usage", + "debug.streamInjection": "Injection", + "debug.loading": "Carregando configurações de debug...", + "debug.loadFailed": "Não foi possível carregar as configurações de debug.", + "debug.emptyTitle": "O registro de debug está desativado", + "debug.empty": "Ative o debug de Provider ou a extração de Usage no card acima. As linhas aparecerão aqui após você enviar uma requisição pelo proxy.", + "debug.noLinesTitle": "Aguardando linhas", + "debug.noLines.provider": "O debug de Provider está ativado, mas ele registra apenas anomalias de transporte (quadros descartados ou malformados e eventos de discagem/tentativa do Cursor). Uma requisição limpa por um provider como a Anthropic pode não produzir linhas.", + "debug.noLines.usage": "A extração de Usage está ativada, mas nada foi capturado ainda. Envie um chat/requisição pelo Codex e aparecerá aqui.", + "debug.noLines.injection": "O log de Injection está ativado, mas nada foi capturado ainda. Ele registra injeção de diretrizes multi-agente e decisões de limite de esforço (effort-cap) em turnos de colaboração e sub-agentes.", + "usage.title": "Usage", + "usage.subtitle": "Contabilização de tokens local do seu proxy. O uso ausente nunca é exibido como zero.", + "usage.loading": "Carregando dados de usage...", + "usage.empty": "Nenhum usage registrado ainda. Envie uma requisição pelo proxy para ver a atividade aqui.", + "usage.loadError": "Não foi possível carregar os dados de usage.", + "usage.range.all": "Tudo", + "usage.range.available": "Histórico disponível", + "usage.historyTruncated": "Os totais cobrem apenas o histórico disponível porque o usage mais antigo não foi carregado.", + "usage.historyTruncatedWindow": "As linhas carregadas têm horários de início de requisição de {start} a {end}. Entradas de arquivo anteriores foram omitidas pelo limite de leitura, portanto qualquer intervalo selecionado pode estar incompleto.", + "usage.range.30d": "30d", + "usage.range.7d": "7d", + "usage.card.requests": "Requisições", + "usage.card.measured": "Medidos", + "usage.card.reported": "Reportados", + "usage.card.totalTokens": "Total de tokens", + "usage.card.cachedTokens": "Leituras de cache", + "usage.card.cachedTokensHint": "Tokens de prompt atendidos a partir do cache do provider (leituras). Gravações em cache são mostradas abaixo quando presentes.", + "usage.card.cacheWriteTokens": "gravações em cache", + "usage.card.coverage": "Cobertura", + "usage.card.activeDays": "Dias ativos", + "usage.section.heatmap": "Atividade diária", + "usage.section.overview": "Visão geral", + "usage.section.models": "Models", + "usage.section.providers": "Providers", + "usage.section.coverage": "Detalhamento de cobertura", + "usage.section.companion": "Barra de menus e widget", + "usage.companion.title": "Barra de menus e widget", + "usage.companion.description": "As configurações aqui controlam o aplicativo OpenCodex para desktop/barra de menus e seu widget.", + "usage.companion.installGuide": "Guia de instalação", + "usage.companion.loading": "Carregando linha do tempo…", + "usage.companion.timelineUnavailable": "Linha do tempo indisponível", + "usage.companion.empty": "Nenhum uso nas últimas {hours} h", + "usage.companion.chartLabel": "Linha do tempo de uso", + "usage.companion.olderRecordsSkipped": "Registros mais antigos foram ignorados", + "usage.companion.settingsUnavailable": "Configurações do aplicativo auxiliar indisponíveis", + "usage.companion.corrupt": "O arquivo de configurações do aplicativo auxiliar está corrompido. Os controles exibem os valores padrão; não é possível salvar até que você substitua o arquivo.", + "usage.companion.corruptReset": "Substituir pelos valores padrão", + "usage.companion.connected": "Aplicativo da barra de menus conectado · {age}", + "usage.companion.connectedDesktop": "Aplicativo para desktop conectado · {age}", + "usage.companion.installTitle": "Instalar o aplicativo para desktop", + "usage.companion.installOs": "Sistema operacional", + "usage.companion.osMac": "macOS", + "usage.companion.osWindows": "Windows", + "usage.companion.osLinux": "Linux", + "usage.companion.runningInDesktop": "Você está no aplicativo OpenCodex para desktop {version}", + "usage.companion.openInBrowser": "Abrir no navegador", + "usage.companion.installMacStep1": "Baixe OpenCodex--macos.dmg da versão mais recente e arraste OpenCodex.app para a pasta Aplicativos.", + "usage.companion.installMacStep2": "Na primeira execução, clique com o botão direito em OpenCodex.app → Abrir (o Gatekeeper solicita confirmação uma vez, até que o aplicativo seja autenticado).", + "usage.companion.installMacStep3": "O aplicativo encontra este proxy automaticamente; o widget aparece na galeria de widgets depois que o aplicativo é executado.", + "usage.companion.installWinStep1": "Baixe OpenCodex--windows-x64.msi da versão mais recente e execute-o.", + "usage.companion.installWinStep2": "Se o SmartScreen exibir um aviso, escolha Mais informações → Executar assim mesmo (o instalador ainda não tem assinatura de código).", + "usage.companion.installWinStep3": "O OpenCodex aparece na bandeja do sistema e se conecta a este proxy ou inicia o proxy integrado.", + "usage.companion.installLinuxStep1": "Baixe OpenCodex--linux-x86_64.AppImage (ou o arquivo .deb) da versão mais recente.", + "usage.companion.installLinuxStep2": "Execute chmod +x no AppImage e abra-o; o ícone na bandeja requer um ambiente de desktop compatível com AppIndicator.", + "usage.companion.installLinuxStep3": "O aplicativo se conecta a este proxy ou inicia o proxy integrado.", + "usage.companion.notConnected": "Nenhum aplicativo da barra de menus se conectou a este proxy ainda.", + "usage.companion.lastSeen": "Visto pela última vez há {age}", + "usage.companion.installAnother": "Instalar em outro dispositivo", + "usage.companion.saved": "Salvo · {time}", + "usage.companion.saveFailed": "Não foi possível salvar: {error}", + "usage.companion.reset": "Restaurar padrões", + "usage.companion.footer": "O widget mostra as requisições, os tokens e o custo de hoje, além do gráfico configurado aqui, e é atualizado quando o aplicativo consulta os dados.", + "usage.companion.menuBarShows": "A barra de menus mostra", + "usage.companion.menuRequests": "Requisições", + "usage.companion.menuTokens": "Tokens", + "usage.companion.menuCost": "Custo", + "usage.companion.menuQuota": "Cota", + "usage.companion.menuNone": "Apenas ícone", + "usage.companion.window": "Período", + "usage.companion.window6": "6 h", + "usage.companion.window24": "24 h", + "usage.companion.window72": "3 dias", + "usage.companion.window168": "7 dias", + "usage.companion.style": "Estilo", + "usage.companion.styleLine": "Linha", + "usage.companion.styleStacked": "Empilhado", + "usage.companion.metric": "Métrica", + "usage.companion.metricTotal": "Total", + "usage.companion.metricInput": "Entrada", + "usage.companion.metricOutput": "Saída", + "usage.companion.metricCached": "Em cache", + "usage.companion.groupBy": "Agrupar por", + "usage.companion.groupModel": "Modelo", + "usage.companion.groupAccount": "Modelo + conta", + "usage.companion.popoverSections": "Seções do popover", + "usage.companion.sectionToday": "Hoje", + "usage.companion.sectionChart": "Gráfico", + "usage.companion.sectionModels": "Modelos", + "usage.companion.sectionCost": "Custo", + "usage.companion.sectionAccounts": "Contas", + "usage.companion.advanced": "Avançado", + "usage.companion.aggregation": "Agregação", + "usage.companion.aggregationSum": "Soma", + "usage.companion.aggregationAverage": "Média", + "usage.companion.aggregationMax": "Máximo", + "usage.companion.menuText": "Texto da barra de menus", + "usage.companion.placeholders": "Marcadores de posição:", + "usage.companion.modelsOnChart": "Modelos no gráfico", + "usage.companion.modelsCount": "{selected} de {total} no gráfico", + "usage.companion.modelsShowAll": "Mostrar todos", + "usage.companion.hideProviders": "Ocultar provedores", + "usage.workspace.report": "Relatório de usage", + "usage.workspace.sections": "Seções de usage", + "usage.coverage.measured": "Medido", + "usage.coverage.reported": "Reportado pelo provider", + "usage.coverage.estimated": "Estimado", + "usage.coverage.note": "As entradas medidas incluem contagens de tokens relatadas pelo provedor e estimadas. Solicitações não relatadas e não suportadas são rastreadas, mas nunca infladas para zero tokens.", + "usage.search.models": "Buscar modelos…", + "usage.col.requests": "Solicitações", + "usage.col.measured": "Medido", + "usage.col.reported": "Relatado", + "usage.col.inputTokens": "Tokens de entrada", + "usage.col.outputTokens": "Tokens de saída", + "usage.col.cacheHits": "Acertos de cache", + "usage.col.cacheWrites": "Gravações no cache", + "usage.col.cacheHitRate": "Taxa de acertos", + "usage.cacheHitRate.partial": "Média calculada com base em {measured} de {total} tokens de entrada; as solicitações restantes não informaram detalhes do cache.", + "usage.cacheHitRate.unmeasured": "Nenhuma solicitação desta linha informou detalhes do cache, portanto não há taxa de acertos para calcular a média.", + "usage.unavailable": "—", + "usage.col.tokens": "Tokens", + "usage.col.apiListPrice": "Preço de lista da API", + "usage.col.share": "Participação", + "usage.heatmap.less": "Menos", + "usage.heatmap.more": "Mais", + "usage.dayMon": "Seg", + "usage.dayWed": "Qua", + "usage.dayFri": "Sex", + "usage.heatmap.tooltipTokens": "{tokens} tokens", + "usage.chart.dayDetail": "{date}: {requests} solicitações, {tokens} tokens", + "usage.heatmap.keyboardLabel": "Use Cima e Baixo para mover por dia; Esquerda e Direita para mover por semana.", + "usage.heatmap.tooltipRequests": "{requests} solicitações", + "nav.storage": "Armazenamento", + "storage.title": "Armazenamento", + "storage.subtitle": "Veja o que está usando o CODEX_HOME. A limpeza nunca afeta sessões ativas.", + "storage.loading": "Escaneando armazenamento…", + "storage.empty": "O CODEX_HOME está vazio ou ausente — nada para relatar.", + "storage.error": "Falha no escaneamento do armazenamento. Verifique se o CODEX_HOME aponta para um diretório válido.", + "storage.refresh": "Reescanear", + "storage.rescanned": "Escaneamento concluído.", + "storage.card.total": "Tamanho total", + "storage.card.files": "Arquivos", + "storage.card.home": "CODEX_HOME", + "storage.snapshot.lastScan": "Último escaneamento", + "storage.snapshot.scanning": "Escaneando…", + "storage.snapshot.unavailable": "Nenhum escaneamento ainda.", + "storage.cleanupCard.title": "Liberar espaço", + "storage.cleanupCard.tabs": "Opções de limpeza", + "storage.cleanupCard.tab.policy": "Política", + "storage.cleanupCard.tab.quarantine": "Quarentena", + "storage.cleanup.noArchives": "Nenhuma sessão arquivada para limpar.", + "storage.section.buckets": "Buckets", + "storage.section.largest": "Maiores arquivos", + "storage.workspace.overview": "Visão geral", + "storage.workspace.selectBucket": "Selecione um bucket da lista para ver seu detalhamento.", + "storage.col.bucket": "Bucket", + "storage.col.size": "Tamanho", + "storage.col.files": "Arquivos", + "storage.col.oldest": "Mais antigo", + "storage.col.newest": "Mais recente", + "storage.col.rows": "Linhas do DB", + "storage.rows.unknown": "desconhecido (bloqueado)", + "storage.bucket.sessions": "Sessões ativas", + "storage.bucket.archived_sessions": "Sessões arquivadas", + "storage.bucket.logs_db": "Banco de dados de logs", + "storage.bucket.state_db": "Banco de dados de estado", + "storage.bucket.attachments": "Anexos", + "storage.bucket.deletion_manifests": "Manifestos de exclusão", + "storage.bucket.other": "Outros", + "storage.cleanup.title": "Limpeza de arquivos compactados", + "storage.cleanup.help": "Remove as sessões arquivadas mais antigas por porcentagem. Sessões ativas nunca são afetadas. A quarentena é o padrão — os arquivos vão para CODEX_HOME/.trash.", + "storage.cleanup.slider": "Porcentagem dos mais antigos", + "storage.cleanup.percent": "{percent}%", + "storage.cleanup.preset": "{percent}", + "storage.cleanup.preview": "Visualizar", + "storage.cleanup.confirmTitle": "Confirmar limpeza de arquivos compactados", + "storage.cleanup.confirmBody": "Isso processará {count} arquivo(s) arquivado(s) (~{size}), correspondentes aos {percent}% mais antigos.", + "storage.cleanup.moreFiles": "...e mais {n}", + "storage.cleanup.permanent": "Excluir permanentemente (ignorar quarentena)", + "storage.cleanup.permanentWarn": "A exclusão permanente não pode ser desfeita.", + "storage.cleanup.quarantineNote": "Os arquivos vão para .trash em CODEX_HOME. Você pode restaurá-los na aba Quarentena.", + "storage.cleanup.cancel": "Cancelar", + "storage.cleanup.confirmQuarantine": "Quarentena", + "storage.cleanup.confirmPermanent": "Excluir permanentemente", + "storage.cleanup.doneQuarantine": "Movido(s) para quarentena: {count} arquivo(s) ({size}).", + "storage.cleanup.donePermanent": "{count} arquivo(s) excluído(s) permanentemente ({size}).", + "storage.cleanup.skippedReferenced": "Ignorado(s) {count} arquivo(s) referenciado(s).", + "storage.cleanup.previewFailed": "Falha na visualização.", + "storage.cleanup.cleanupFailed": "Falha na limpeza.", + "storage.cleanup.err.codex_busy": "O Codex está usando o state.sqlite — tente novamente após fechar o Codex.", + "storage.cleanup.err.stale_preview": "Os arquivos arquivados mudaram desde a visualização — execute a Visualização novamente.", + "storage.cleanup.err.restore_pending_overlap": "Os arquivos selecionados sobrepõem uma restauração pendente da lixeira — conclua ou tente novamente a restauração primeiro.", + "storage.cleanup.err.referenced_history": "Os arquivos selecionados ainda são referenciados pelo histórico bifurcado ou paginado.", + "storage.cleanup.err.invalid_digest": "O resumo (digest) da visualização está ausente ou é inválido.", + "storage.cleanup.err.invalid_mode": "O modo de limpeza deve ser quarentena ou permanente.", + "storage.cleanup.err.fs_failed": "Falha na limpeza do sistema de arquivos. Algumas alterações já podem ter sido aplicadas — verifique CODEX_HOME/.trash e qualquer caminho de recuperação exibido.", + "storage.cleanup.err.fs_failed_trash": "Falha na limpeza do sistema de arquivos. Algumas alterações já podem ter sido aplicadas — verifique {trashDir} e manifest.json para arquivos recuperáveis.", + "storage.cleanup.err.db_reconcile_failed": "Não foi possível atualizar o banco de dados de estado do Codex.", + "storage.cleanup.err.cleanup_failed": "Falha na limpeza.", + "storage.trash.title": "Quarentena", + "storage.trash.help": "Sessões arquivadas movidas para CODEX_HOME/.trash. A restauração devolve os arquivos JSONL e as linhas de thread.", + "storage.trash.empty": "Nenhum item em quarentena.", + "storage.trash.loading": "Carregando quarentena...", + "storage.trash.col.when": "Em quarentena", + "storage.trash.col.files": "Arquivos", + "storage.trash.col.size": "Tamanho", + "storage.trash.col.mode": "Modo", + "storage.trash.col.id": "Entrada", + "storage.trash.restore": "Restaurar", + "storage.trash.confirmTitle": "Restaurar item da quarentena?", + "storage.trash.confirmBody": "Restaurar {count} arquivo(s) (~{size}) de {id} de volta para as sessões arquivadas.", + "storage.trash.cancel": "Cancelar", + "storage.trash.confirmRestore": "Restaurar", + "storage.trash.done": "Restaurado(s) {count} arquivo(s) ({size}).", + "storage.trash.restoreFailed": "Falha na restauração.", + "storage.trash.listFailed": "Não foi possível listar os itens em quarentena.", + "storage.trash.mode.quarantine": "quarentena", + "storage.trash.mode.permanent": "permanente (incompleto)", + "storage.trash.err.codex_busy": "O Codex está usando o state.sqlite — tente novamente após fechar o Codex.", + "storage.trash.err.invalid_trash": "O ID do item na lixeira está ausente ou é inválido.", + "storage.trash.err.missing_trash": "O item da lixeira não foi encontrado.", + "storage.trash.err.dest_exists": "O destino da restauração já existe — remova ou renomeie o arquivo arquivado e tente novamente.", + "storage.trash.err.fs_failed": "Falha na restauração do sistema de arquivos. Alguns arquivos já podem ter sido restaurados — verifique archived_sessions e .trash.", + "storage.trash.err.db_reconcile_failed": "Não foi possível restaurar as linhas do banco de dados de estado do Codex.", + "storage.trash.err.storage_mutation_busy": "Outra limpeza ou restauração de armazenamento está em andamento — tente novamente em breve.", + "storage.trash.err.restore_failed": "Falha na restauração.", + "storage.trash.err.restore_worker_timeout": "A restauração demorou muito (mais de 10 minutos) e foi interrompida.", + "storage.trash.err.restore_worker_aborted": "A restauração foi cancelada durante o encerramento.", + "storage.trash.err.restore_worker_failed": "O worker de restauração travou ou falhou inesperadamente.", + "storage.policy.title": "Política de limpeza automática", + "storage.policy.help": "Limpeza em lote opcional quando as sessões arquivadas excedem um limite. Desativada por padrão — nunca ativada automaticamente.", + "storage.policy.loading": "Carregando política…", + "storage.policy.loadFailed": "Não foi possível carregar a política de limpeza.", + "storage.policy.saveFailed": "Não foi possível salvar a política de limpeza.", + "storage.policy.runFailed": "A execução da política falhou.", + "storage.policy.alreadyRunning": "Uma execução da política de limpeza já está em andamento.", + "storage.policy.invalid": "Valores de política inválidos.", + "storage.policy.enabled": "Ativar limpeza automática", + "storage.policy.enabledHint": "O padrão é desativado. A ativação é executada apenas no agendamento escolhido (ou em Executar agora).", + "storage.policy.threshold": "Quando o tamanho arquivado exceder (GiB)", + "storage.policy.trigger": "Gatilho", + "storage.policy.target": "Alvo da limpeza", + "storage.policy.targetPercent": "Remover arquivos mais antigos arquivados (%)", + "storage.policy.targetReduce": "Reduzir o tamanho arquivado para (GiB)", + "storage.policy.thresholdInc": "Aumentar limite", + "storage.policy.thresholdDec": "Diminuir limite", + "storage.policy.percentInc": "Aumentar porcentagem", + "storage.policy.percentDec": "Diminuir porcentagem", + "storage.policy.reduceInc": "Aumentar tamanho de redução", + "storage.policy.reduceDec": "Diminuir tamanho de redução", + "storage.policy.schedule": "Agendamento", + "storage.policy.schedule.manual": "Apenas manual", + "storage.policy.schedule.startup": "Na inicialização do proxy", + "storage.policy.schedule.daily": "Diariamente", + "storage.policy.schedule.weekly": "Semanalmente", + "storage.policy.mode": "Modo de exclusão", + "storage.policy.mode.quarantine": "Quarentena (padrão)", + "storage.policy.mode.permanent": "Exclusão permanente", + "storage.policy.permanentWarn": "O modo permanente não pode ser desfeito. Prefira a quarentena, a menos que tenha certeza.", + "storage.policy.lastRun": "Última execução", + "storage.policy.lastRunDetail": "Removidos {count} · liberados {size}", + "storage.policy.nextRun": "Próxima execução", + "storage.policy.never": "Nunca", + "storage.policy.save": "Salvar", + "storage.policy.runNow": "Executar agora", + "storage.policy.running": "Executando…", + "storage.policy.saved": "Política salva.", + "storage.policy.skippedDisabled": "A política está desativada — ative-a primeiro.", + "storage.policy.skippedUnder": "O tamanho arquivado está abaixo do limite — nada para fazer.", + "storage.policy.skippedEmpty": "Nenhum candidato arquivado correspondeu ao destino.", + "storage.policy.doneQuarantine": "A política colocou {count} arquivo(s) em quarentena ({size}).", + "storage.policy.donePermanent": "A política excluiu permanentemente {count} arquivo(s) ({size}).", + "storage.policy.metadataSaveWarning": "A execução da política terminou, mas seus metadados de agendamento não puderam ser salvos.", + "modal.addNamed": "Adicionar: {label}", + "modal.add": "Adicionar provider", + "modal.search": "Buscar providers…", + "modal.logInWith": "Entrar com {label}", + "modal.waitingBrowser": "Aguardando o navegador…", + "modal.providerName": "Nome do provider", + "modal.adapter": "Adapter", + "modal.baseUrl": "Base URL", + "modal.endpoint": "Endpoint", + "modal.endpoint.tokenPlan": "Plano de tokens", + "modal.endpoint.payAsYouGo": "Pague conforme o uso", + "modal.endpoint.custom": "Personalizado", + "modal.defaultModel": "Model padrão (opcional)", + "modal.allowPrivateNetwork": "Permitir rede local/privada", + "modal.allowPrivateNetworkHint": "Ative apenas para providers auto-hospedados intencionalmente. Os endpoints de metadados permanecem bloqueados.", + "modal.nameRequired": "O nome do provider é obrigatório", + "modal.baseUrlRequired": "A Base URL é obrigatória", + "modal.networkError": "Erro de rede — o proxy está rodando?", + "modal.loginFailStart": "Falha ao iniciar o login", + "modal.waitingLogin": "Aguardando o login no navegador…", + "modal.loggingIn": "Entrando…", + "modal.loginTimeout": "Tempo limite de login esgotado — tente novamente.", + "modal.back": "Voltar", + "modal.badge.oauth": "OAuth", + "modal.customProvider": "Provider personalizado", + "modal.failedStatus": "Falhou ({status})", + "modal.loginError": "Erro de login: {error}", + "modal.badge.codexLogin": "Login no Codex", + "modal.badge.local": "Local", + "modal.badge.apiKey": "API key", + "modal.badge.direct": "Direto", + "modal.badge.pool": "Pool", + "modal.badge.free": "Gratuito", + "modal.badge.sponsor": "Patrocinador", + "modal.badge.subscriptionCli": "CLI por assinatura", + "modal.subscriptionCliTitle": "CLI por assinatura, não uma chave de API", + "modal.subscriptionCliWarning": "Este provedor não usa chave de API. Ele aciona a CLI oficial do Claude Code autenticada nesta máquina ({cmd}) e cobra nessa conta de assinatura do Claude. O OpenCodex não guarda nenhuma chave para ele, e uma chave informada aqui nunca é usada. Para cobrança por chave de API, adicione {apiProvider}.", + "pws.sponsor.orcaTitle": "Um model para cada prompt", + "pws.sponsor.orcaDescription": "Um gateway compatível com OpenAI com roteamento adaptativo e failover automático.", + "pws.sponsor.packyTitle": "Claude Code, Codex e Gemini em um só lugar", + "pws.sponsor.packyDescription": "Um relay de API para suas ferramentas de IA de programação. Comece com um token do grupo Codex.", + "pws.sponsor.visit": "Explorar {provider}", + "pws.sponsor.console": "Abrir console", + "pws.sponsor.tokenlabTitle": "Uma chave de API para os principais models", + "pws.sponsor.tokenlabDescription": "Responses, Chat Completions, streaming e tool calling para agentes de programação, com o modo de entrega que você escolher e cobrança por uso.", + "pws.anthropicAccountThresholdHint": "Substitui o padrão do pool do Claude. 0 desliga somente a troca por uso nesta conta; a pausa e a recuperação de limite de requisições continuam valendo.", + "modal.invalidPreset": "Este preset de provider integrado está incompleto. Reinicie o proxy e tente novamente.", + "modal.freeTierTitle": "Camada gratuita", + "modal.freeTierDefault": "Nenhuma API key necessária. Funciona direto.", + "modal.tab.accounts": "Contas", + "modal.tab.free": "Gratuito", + "modal.tab.local": "Local", + "modal.tab.paid": "Pago", + "modal.noteMore": "Mostrar descrição completa", + "modal.searchResults": "{count} resultados em {tiers}", + "modal.accountsHint": "Faça login no ChatGPT/Codex, provedores OAuth e contas de API key aqui. A OpenAI já vem integrada — faça login em vez de adicioná-la novamente.", + "modal.accountsCodexAuthLink": "Autenticação do Codex", + "modal.notListed": "Provedor não listado? Adicione um personalizado", + "modal.catalogLoading": "Carregando catálogo…", + "modal.accountLogin": "Entrar", + "modal.accountLogout": "Sair", + "modal.accountAdd": "Adicionar conta", + "modal.accountManage": "Gerenciar", + "modal.accountCodexPool": "Pool de contas do ChatGPT", + "modal.accountLoggedIn": "Conectado", + "modal.accountLoggedOut": "Desconectado", + "quota.fiveHourLimit": "Limite de 5 horas", + "quota.ageMinutes": "{n}m", + "quota.ageHours": "{n}h", + "quota.ageDays": "{n}d", + "quota.observedAgo": "Observado há {age}", + "quota.observedHint": "A Meta relata o uso apenas durante uma resposta em streaming, portanto este é o último valor visto, não uma leitura em tempo real.", + "quota.weeklyLimit": "Limite semanal", + "quota.monthlyLimit": "Limite de 30 dias", + "quota.cursorFirstParty": "Modelos primários", + "quota.cursorApiUsage": "Uso de API", + "quota.totalSubscriptionCredits": "Total de créditos da assinatura", + "quota.creditsBalance": "Saldo de créditos", + "quota.creditsPeriodEnds": "O período de cobrança termina em {date}", + "quota.usedPercent": "{pct}% usado", + "quota.limitReached": "Limite atingido", + "quota.resetsToday": "Redefine hoje às {time}", + "quota.resetsTomorrow": "Redefine amanhã às {time}", + "quota.resetsAt": "Redefine em {when}", + "quota.resetsRelativeMinutes": "Redefine em {n} min", + "quota.resetsRelativeHours": "Redefine em {n} h", + "pws.status.ready": "Pronto", + "pws.status.needsSetup": "Requer configuração", + "pws.status.needsAttention": "Requer atenção", + "pws.auth.chatgptPassthrough": "Passthrough do ChatGPT", + "pws.auth.noKey": "Nenhuma key necessária", + "pws.freeTitle": "Preço gratuito (uma key ainda pode ser necessária)", + "pws.localTitle": "Runtime local", + "pws.modelCountOne": "1 modelo", + "pws.modelCount": "{count} modelos", + "pws.rail.suffixDefault": " · padrão", + "pws.rail.suffixLocal": " · local", + "pws.rail.suffixFree": " · gratuito", + "pws.rail.selectAria": "Selecionar {name} — {status}{suffix}", + "pws.searchPlaceholder": "Pesquisar provedores…", + "pws.filterAria": "Filtrar provedores", + "pws.providerFiltersAria": "Filtros de provedor", + "pws.filters": "Filtros", + "pws.filterStatus": "Status", + "pws.pricing": "Preços", + "pws.paid": "Pago", + "pws.filterType": "Tipo", + "pws.type.cloud": "Cloud", + "pws.type.local": "Local", + "pws.type.selfHosted": "Self-hosted", + "pws.type.login": "Login", + "pws.sort": "Ordenar", + "pws.sortProvidersAria": "Ordenar provedores", + "pws.sort.az": "A–Z", + "pws.sort.za": "Z–A", + "pws.sort.freePaid": "Gratuitos primeiro", + "pws.sort.paidFree": "Pagos primeiro", + "pws.sort.accountsFirst": "Contas primeiro", + "pws.resetAll": "Redefinir tudo", + "pws.providerList": "Lista de provedores", + "pws.providersAria": "Provedores", + "pws.groupReady": "Pronto ({count})", + "pws.groupNeedsSetup": "Precisa de configuração ({count})", + "pws.groupDisabled": "Desativado ({count})", + "pws.noSearchResults": "Nenhum provedor corresponde à sua pesquisa.", + "pws.noMatchFilters": "Nenhum provedor corresponde aos filtros.", + "pws.noProvidersConfigured": "Nenhum provedor configurado.", + "pws.workspaceMainAria": "Detalhes do provedor", + "pws.detailComingSoon": "Visualização de detalhes em breve — use a visualização clássica para gerenciar este provedor.", + "pws.selectPrompt": "Selecione um provedor da lista.", + "pws.connectFirst": "Conecte seu primeiro provedor", + "pws.empty.browseFree": "Explorar provedores gratuitos", + "pws.empty.browseFreeDesc": "Comece sem uma assinatura", + "pws.empty.connectAccount": "Conectar uma conta", + "pws.empty.connectAccountDesc": "Use seu login do ChatGPT ou do provedor", + "pws.empty.addEndpoint": "Adicionar um endpoint", + "pws.empty.addEndpointDesc": "URL base personalizada e API key", + "pws.tab.overview": "Visão geral", + "pws.tab.models": "Modelos", + "pws.tab.usage": "Uso", + "pws.tab.accounts": "Contas", + "pws.tab.settings": "Configurações", + "pws.connection": "Conexão", + "pws.status.connected": "Conectado", + "pws.attentionTitle": "Requer atenção", + "pws.attention.reauth": "A conta ativa precisa de reautenticação", + "pws.attention.reauthForward": "A conta ativa do Codex precisa de reautenticação — abra Contas para resolver", + "pws.attention.missingCredentials": "Credenciais ausentes", + "pws.cell.auth": "Autenticação", + "pws.cell.note": "Nota", + "pws.cell.defaultModel": "Modelo padrão", + "pws.statsAria": "Estatísticas do provedor", + "pws.statsTitle": "Estatísticas", + "pws.stats.totalRequests": "Requisições (30d)", + "pws.stats.totalTokens": "Tokens (30d)", + "pws.stats.quotaUpdated": "Cota atualizada", + "pws.stats.quotaTracked": "Limites de taxa monitorados na aba Uso.", + "pws.stats.source": "Origem", + "pws.usageLast30d": "Uso (últimos 30 dias)", + "pws.estimatedCost": "Custo estimado", + "pws.costDisclaimer": "Estimativa com base no preço de tabela da API, não em uma cobrança real.", + "pws.unresolvedRequestedModel": "Inclui uso de modelo solicitado não resolvido", + "pws.currentAccountUsage": "Uso da conta atual", + "pws.quotaUnsupported": "A consulta de cota não é suportada para esta conta.", + "pws.quotaUnobserved": "Nenhuma observação de uso ainda.", + "pws.quotaCheckCompleted": "Verificação de cota concluída", + "pws.modelBreakdown": "Detalhamento por modelo", + "pws.col.model": "Modelo", + "pws.col.cost": "Custo est.", + "pws.col.tokens": "Tokens", + "pws.col.requests": "Req.", + "pws.col.share": "Participação", + "pws.tokenInput": "Entrada", + "pws.tokenOutput": "Saída", + "pws.metricRequests": "requisições", + "pws.metricTokens": "tokens", + "pws.usageUnavailable": "Nenhum uso registrado ainda.", + "pws.rateLimits": "Limites de taxa", + "pws.quotaUnavailable": "Nenhum dado de cota para este provedor.", + "pws.accountQuotaUnavailable": "Dados de limite de taxa temporariamente indisponíveis; exibindo os últimos valores conhecidos quando disponíveis.", + "pws.quotaFailure.account_unavailable": "Os detalhes da conta estão indisponíveis para esta verificação de cota.", + "pws.quotaFailure.access_denied": "O provedor negou acesso aos dados de cota.", + "pws.quotaFailure.rate_limited": "O provedor aplicou limite de taxa à verificação de cota.", + "pws.quotaFailure.upstream_error": "O provedor não pôde concluir a verificação de cota.", + "pws.quotaFailure.redirect_blocked": "O endpoint de cota retornou um redirecionamento bloqueado.", + "pws.quotaFailure.destination_blocked": "O destino de cota foi bloqueado pela política de rede.", + "pws.quotaFailure.dns_failed": "Não foi possível resolver o hostname de cota.", + "pws.quotaFailure.timeout": "A requisição de cota esgotou o tempo limite.", + "pws.quotaFailure.transport_error": "A conexão de cota falhou.", + "pws.quotaFailure.response_unusable": "O provedor retornou dados de cota inutilizáveis.", + "pws.selected": "Selecionado", + "pws.copyModelId": "Copiar ID", + "pws.modelCopied": "Copiado!", + "pws.modelsAvailable": "{count} disponíveis", + "pws.modelSearchPlaceholder": "Filtrar modelos…", + "pws.modelsLoading": "Carregando modelos…", + "pws.modelsLoadFailed": "Não foi possível carregar os modelos.", + "pws.modelsNeedsReauth": "A conta precisa ser reconectada antes que a descoberta de modelos em tempo real funcione. Exibindo os modelos configurados por enquanto.", + "pws.modelsConfiguredFallback": "Exibindo os modelos configurados (descoberta em tempo real indisponível).", + "pws.modelsTruncated": "Exibindo os primeiros {shown} de {total} modelos. Filtre para refinar a lista.", + "pws.retry": "Tentar novamente", + "pws.noModels": "Nenhum modelo descoberto para este provedor.", + "pws.noModelMatch": "Nenhum modelo corresponde ao filtro.", + "pws.adapterBaseRequired": "O adapter e a URL base são obrigatórios.", + "pws.addAccount": "Adicionar conta", + "pws.addKey": "Adicionar API key", + "pws.apiKeys": "API Keys", + "pws.authMode": "Modo de autenticação", + "pws.availableAccounts": "Contas disponíveis", + "pws.accountOrdinal": "Conta {count}", + "pws.accountsLoading": "Carregando contas...", + "pws.accountsLoadFailed": "Não foi possível carregar as contas.", + "pws.retryAccounts": "Tentar novamente", + "pws.noAccounts": "Nenhuma conta conectada ainda.", + "pws.cockpitImportDescription": "Importe um arquivo JSON de exportação do Cockpit Tools Antigravity deste dispositivo. O conteúdo do arquivo não é exibido.", + "pws.cockpitImportFileLabel": "Exportação JSON do Cockpit Tools Antigravity", + "pws.cockpitImportChooseFile": "Escolher arquivo JSON", + "pws.cockpitImporting": "Importando...", + "pws.cockpitImportInvalid": "O arquivo selecionado não é uma exportação JSON válida ou é muito grande.", + "pws.cockpitImportFailed": "Não foi possível concluir a importação da conta.", + "pws.cockpitImportComplete": "Importação concluída: {imported} importados, {updated} atualizados, {failed} com falha, {unsupported} não suportados.", + "pws.accountSwitching": "Alternando...", + "pws.accountCurrent": "Conta atual", + "pws.defaultModelNone": "Nenhum (usar padrão do provedor)", + "pws.discardSettings": "Descartar", + "pws.jsonEditorDesc": "Edite a configuração JSON bruta do provedor. As alterações são salvas imediatamente.", + "pws.jsonEditorTitle": "Editor JSON — {name}", + "pws.jsonRestore": "Restaurar", + "pws.jsonSave": "Salvar", + "pws.loggedInTitle": "Conectado", + "pws.notLoggedInTitle": "Desconectado", + "pws.note": "Nota", + "pws.allowPrivateNetwork": "Permitir rede local/privada", + "pws.liveModels": "Descobrir modelos do provedor", + "pws.liveModelsDesc": "Busca o catálogo de modelos em tempo real do provedor. Desative para usar apenas modelos configurados/estáticos.", + "pws.xaiChatOptIn": "Usar Chat Completions para Grok 4.5 e 4.6", + "pws.xaiChatOptInDesc": "Desativado seleciona Responses. Solicitações via OAuth Responses usam essa opção por padrão. Outros modelos Grok e o comportamento de camadas permanecem inalterados.", + "pws.xaiChatOptInMixed": "Apenas um modelo usa Chat.", + "pws.cursorTransport": "Transporte do Cursor", + "pws.cursorTransportHttp2": "HTTP/2 (padrão)", + "pws.cursorTransportHttp1": "HTTP/1.1 (compatibilidade com proxy)", + "pws.cursorTransportDesc": "Use HTTP/1.1 quando o seu proxy não conseguir lidar de forma confiável com o fluxo HTTP/2 do Cursor.", + "pws.optionalPlaceholder": "Opcional", + "pws.providerId": "Provider ID", + "pws.reauth": "Reautenticação necessária", + "pws.reauthenticate": "Reautenticar", + "pws.copyDoctor": "Copiar ocx doctor", + "pws.doctorCopied": "Copiado", + "pws.doctorCopyUnavailable": "Área de transferência indisponível", + "pws.healthCooldownHint": "Aguarde o término do cooldown. Não teste esta conta por enquanto.", + "pws.healthLabel.rateLimited": "Rate limited", + "pws.healthLabel.quotaLimited": "Quota limited", + "pws.healthLabel.reauthRequired": "Reautenticação necessária", + "pws.healthLabel.refreshFailed": "Falha na atualização", + "pws.healthLabel.metadataMismatch": "Incompatibilidade de metadados", + "pws.healthLabel.validationPending": "Validação pendente", + "pws.healthSummary.validationPending": "{provider} {account}: cadastrada com cota limitada. Após a recuperação da cota, atualize as cotas para executar uma pequena requisição de validação. O roteamento permanece desativado até que seja bem-sucedido.", + "pws.healthLabel.credentialConflict": "Conflito de credenciais", + "pws.healthSummary.rateLimited": "{provider} {account}: rate limited até {until}. O roteamento para esta conta está pausado até lá.", + "pws.healthSummary.quotaLimited": "{provider} {account}: quota limited até {until}. O roteamento para esta conta está pausado até lá.", + "pws.healthSummary.reauthRequired": "{provider} {account}: reautenticação necessária.", + "pws.healthSummary.credentialConflict": "{provider} {account}: conflito de credenciais.", + "pws.healthSummary.metadataMismatch": "{provider} {account}: incompatibilidade de metadados.", + "pws.healthSummary.staleCredentials": "{provider} {account}: credenciais incompletas.", + "pws.removeConfirm": "Remover", + "pws.removeConfirmBody": "Remover o provedor \"{name}\"? Esta ação não pode ser desfeita.", + "pws.removeDefaultConfirmBody": "Remover o provedor padrão \"{name}\"? \"{defaultProvider}\" se tornará o provedor padrão. Esta ação não pode ser desfeita.", + "pws.removeConfirmTitle": "Remover provedor", + "pws.saveSettings": "Salvar", + "pws.pacingTitle": "Espaçamento de requisições", + "pws.pacingDesc": "Atrasa uniformemente o início das requisições de saída para este provedor. Respostas em streaming podem se sobrepor.", + "pws.pacingEnabled": "Ativado", + "pws.pacingRpm": "Requisições por minuto", + "pws.pacingRpmUnit": "RPM", + "pws.pacingConcurrency": "Máximo de requisições simultâneas", + "pws.pacingCapUnit": "×", + "pws.pacingCapInvalid": "O máximo de requisições simultâneas precisa ser um número inteiro maior ou igual a 1.", + "pws.pacingDelay": "Intervalo mínimo (ms)", + "pws.pacingSlowerWins": "O limite de provedor mais lento prevalece. Substituições de model podem apenas adicionar mais atraso.", + "pws.pacingQueued": "na fila", + "pws.pacingNextSlot": "até o próximo slot", + "pws.pacingLastModel": "último model", + "pws.pacingNone": "Nenhum", + "pws.pacingModelOverrides": "Substituições de model", + "pws.pacingModel": "Model", + "pws.pacingAdd": "Adicionar substituição", + "pws.pacingRemove": "Remover", + "pws.pacingRemoveModel": "Remover substituição de espaçamento de requisições para {model}", + "pws.pacingRuleRequired": "Ative o espaçamento de requisições somente após definir um limite de provedor ou uma substituição de model.", + "pws.saving": "Salvando…", + "pws.settingsSaved": "Configurações salvas.", + "pws.accountModeSaved": "Modo de conta salvo.", + "pws.accountModeFailed": "Não foi possível alternar o modo de conta.", + "pws.accountModeConfirm": "Alternar o modo de conta da OpenAI? As conversas em andamento serão reatribuídas ao conjunto de contas do outro modo, e o uso de cota será contabilizado no novo modo.", + "pws.settingsUnsavedBar": "Você tem alterações não salvas.", + "pws.unsavedLeaveBody": "Você tem alterações não salvas. Deseja salvá-las antes de sair?", + "pws.unsavedLeaveTitle": "Alterações não salvas", + "pws.attentionRequired": "Atenção necessária", + "pws.attentionAria": "{name}: {reason}", + "pws.missingCredentials": "Credenciais ausentes", + "pws.editJsonDesc": "Editar a configuração do proxy raw como JSON", + "pws.updatesUnavailable": "Atualizações de provedores indisponíveis.", + "pws.dashboard.title": "Visão geral dos provedores", + "pws.dashboard.subtitle": "Gerencie todos os seus provedores de model em um só lugar.", + "pws.dashboard.rateLimits": "LIMITES DE TAXA", + "pws.capacity.estimate": "Estimativa do pool com peso configurado", + "pws.capacity.currentAccount": "Conta efetiva atual", + "pws.capacity.nextRecovery": "Próxima recuperação de capacidade", + "pws.capacity.recoveryShare": "+{percent}% de capacidade do pool", + "pws.capacity.incomplete": "Cobertura incompleta: {excluded} conta(s) excluída(s)", + "pws.capacity.uncalibratedPlan": "{count} conta(s) em um plano não calibrado são contadas com o peso de assento base, portanto esta estimativa pode ser conservadora", + "pws.capacity.partial": "Cobertura de janela parcial: {count} conta(s) não reportam todas as janelas de limite exibidas", + "pws.capacity.windowPartial": "Parcial", + "pws.capacity.windowPartialA11y": "{window}: cobertura de contas incompleta", + "pws.dashboard.recentlyUsed": "USADOS RECENTEMENTE", + "pws.dashboard.requests": "{count} requisições", + "pws.dashboard.checkedAgo": "Verificado há {time}", + "pws.dashboard.noQuota": "Sem dados de cota", + "pws.dashboard.noUsage": "Ainda sem dados de uso", + "pws.dashboard.noRateLimits": "Ainda sem dados de limite de taxa", + "pws.allProviders": "Visão Geral do Provedor", + "pws.enabledLabel": "Ativado", + "pws.testConnection": "Testar conexão", + "pws.testing": "Testando…", + "pws.connectionOk": "Conexão OK", + "pws.connectionFailed": "Falha na conexão", + "pws.connectionNotApplicable": "Não aplicável — este provedor usa um catálogo de model estático.", + "pws.editSettings": "Editar configurações", + "pws.viewUsage": "Ver uso detalhado", + "pws.allSystemsOk": "Todos os sistemas operando normalmente", + "pws.apiKeyConfigured": "Chave de API configurada", + "pws.addApiKey": "Adicionar chave de API", + "pws.loggedInAs": "Conectado como {email}", + "pws.notLoggedIn": "Não conectado", + "pws.passthrough": "Passagem do Codex", + "pws.notes": "NOTAS", + "pws.notePlaceholder": "Adicionar uma nota sobre este provedor...", + "pws.noteSaved": "Nota salva", + "pws.authSummary": "AUTENTICAÇÃO", + "time.justNow": "Agora mesmo", + "time.notChecked": "Não verificado", + "time.minutesAgo": "há {n}m", + "time.hoursAgo": "há {n}h", + "time.daysAgo": "há {n}d", + "modal.noMatch": "Nenhum resultado correspondente.", + "modal.oauthDefaultNote": "Faça login com sua conta — nenhuma chave de API necessária.", + "modal.oauthComingSoon": "O login OAuth para {label} chega na próxima atualização. Use uma chave de API por enquanto.", + "modal.oauthComingSoonShort": "O login OAuth para este provedor chega na próxima atualização — use uma chave de API por enquanto.", + "modal.useApiKeyInstead": "Usar uma chave de API", + "modal.setupGuide": "Guia de configuração", + "modal.setupStep1Prefix": "Acesse o", + "modal.setupDashboardLink": "dashboard do {label}", + "modal.setupStep1Suffix": "e copie sua API key", + "modal.setupStep2": "Cole-a no campo de API key abaixo", + "modal.setupStep3": "Clique em Adicionar provedor — os models são descobertos automaticamente", + "modal.namePlaceholder": "ex: openrouter", + "modal.duplicateWarn": "O provedor \"{name}\" já existe e será substituído.", + "modal.forwardHintPrefix": "Nenhuma key necessária — o proxy encaminha suas", + "modal.forwardCredentials": "credenciais de login do codex", + "modal.forwardHintSuffix": "para este provedor.", + "modal.localHint": "Nenhuma API key é armazenada. Isso adiciona o catálogo público estático de models do Cursor para o Codex, mas o transporte ativo do Cursor e a execução nativa de arquivos/shell permanecem desativados até serem auditados.", + "modal.getApiKey": "Obtenha sua API key do {label}", + "modal.apiKey": "API key", + "modal.apiKeyTransport": "Cabeçalho da API key", + "modal.apiKeyTransportNative": "x-api-key (nativo da Anthropic)", + "modal.apiKeyTransportBearer": "Authorization: Bearer", + "modal.apiKeyPlaceholder": "sk-… (ou $ENV_VAR)", + "modal.defaultModelPlaceholder": "ex: gpt-5.5", + "modal.baseUrlPlaceholder": "https://...", + "modal.baseUrlPlaceholderError": "A Base URL contém um {placeholder} não resolvido. Substitua-o pelo seu valor real.", + "modal.baseUrlPlaceholderHint": "Substitua o {placeholder} na Base URL pelo seu Account ID real antes de adicionar.", + "modal.adding": "Adicionando…", + "modal.useOauthLogin": "← Usar login OAuth", + "nav.codexAuth": "Autenticação do Codex", + "nav.codexSet": "Configuração do Codex", + "codexSet.tab.multiauth": "Multi-auth", + "codexSet.tab.prompt": "Prompt", + "codexSet.prompt.title": "Camadas de prompt", + "codexSet.prompt.timing": "Aplica-se a sessões iniciadas recentemente. Sessões em execução mantêm suas configurações atuais de prompt.", + "codexSet.prompt.staleRevision": "A configuração foi alterada em outro lugar. A lista foi recarregada.", + "codexSet.prompt.writeFailed": "Não foi possível salvar a alteração.", + "codexSet.prompt.loadFailed": "Não foi possível carregar as camadas de prompt.", + "codexSet.prompt.repair": "Reparar", + "codexSet.prompt.repairFailed": "Não foi possível concluir o reparo.", + "codexSet.drift.journalPresent": "Uma gravação anterior não foi concluída. A recuperação é executada automaticamente na próxima gravação.", + "codexSet.drift.projectionStale": "As camadas salvas e o valor em config.toml divergem. O reparo reescreve o valor a partir de suas camadas.", + "codexSet.drift.storeMissing": "O arquivo de camada desapareceu enquanto as instruções permanecem em config.toml. O reparo mantém o texto como uma única camada e grava um backup primeiro.", + "codexSet.drift.ownedMalformed": "A linha gerada em config.toml foi modificada manualmente, portanto não é mais seguro reescrevê-la.", + "codexSet.custom.adoptUnsupported": "O valor em {path} na linha {line} não é uma string de linha única, portanto não pode ser importado. Mova-o manualmente para gerenciá-lo aqui.", + "codexSet.prompt.unreadable": "O arquivo de configuração do Codex existe, mas não pôde ser lido, portanto as alterações foram recusadas.", + "codexSet.layer.permissions": "Permissões", + "codexSet.layer.collaboration": "Modo de colaboração", + "codexSet.layer.environment": "Contexto do ambiente", + "codexSet.layer.apps": "Apps", + "codexSet.layer.skills": "Skills", + "codexSet.prompt.extensionsUnknown": "Extensões podem adicionar suas próprias camadas. O Codex não as expõe, portanto elas não podem ser listadas aqui.", + "codexSet.group.transition": "Avisos de transição", + "codexSet.group.transitionDesc": "Eles anunciam uma alteração em vez de descrever o estado, portanto aparecem apenas quando a sessão entra em tempo real ou troca de model.", + "codexSet.custom.slotNote": "Camadas personalizadas são combinadas em uma única seção nesta ordem.", + "codexSet.row.alwaysOn": "Sempre ativo", + "codexSet.row.onChange": "Dispara ao alterar", + "codexSet.row.featureGated": "Configurado em [features]", + "codexSet.row.openFeatures": "Abrir configurações", + "codexSet.dialog.setValue": "{value} (padrão {fallback})", + "codexSet.dialog.copyKey": "Copiar chave", + "codexSet.dialog.unknownLayer": "Esta compilação não tem descrição para esta camada. Ela veio de um runtime do Codex mais recente do que o painel.", + "codexSet.custom.heading": "Camadas personalizadas", + "codexSet.custom.add": "+ Adicionar camada", + "codexSet.custom.newTitle": "Nova camada", + "codexSet.custom.editTitle": "Editar camada", + "codexSet.custom.titleLabel": "Título", + "codexSet.custom.bodyLabel": "Instruções", + "codexSet.custom.bodySize": "{bytes} de {max} bytes", + "codexSet.custom.normalized": "As tabulações foram convertidas em quatro espaços e as quebras de linha em LF.", + "codexSet.custom.titleRequired": "Insira um título.", + "codexSet.custom.titleTooLong": "O título tem {count} caracteres; o limite é {max}.", + "codexSet.custom.titleMultiline": "O título deve ser em uma única linha.", + "codexSet.custom.bodyTooLarge": "Esta camada tem {bytes} bytes; o limite é {max}.", + "codexSet.custom.composedTooLarge": "Juntas, as camadas ativadas teriam {bytes} bytes, ultrapassando o limite.", + "codexSet.custom.invalidCharacter": "Um caractere de controle na posição {position} não pode ser salvo.", + "codexSet.custom.discardPrompt": "Descartar suas alterações?", + "codexSet.custom.discardOthersAndSave": "Descartar as alterações não salvas nas outras camadas e salvar esta camada?", + "codexSet.custom.keepEditing": "Continuar editando", + "codexSet.custom.delete": "Excluir {title}", + "codexSet.custom.deleteConfirm": "Excluir esta camada? Esta ação não pode ser desfeita.", + "codexSet.custom.layerGone": "Essa camada foi removida em outro lugar, portanto o editor foi fechado.", + "codexSet.custom.deleteConfirmNamed": "Excluir “{title}”? Esta ação não pode ser desfeita.", + "codexSet.custom.moveUp": "Mover {title} para cima", + "codexSet.custom.prevLayer": "Camada anterior", + "codexSet.custom.nextLayer": "Próxima camada", + "codexSet.custom.navPosition": "{position} / {total}", + "codexSet.custom.moveDown": "Mover {title} para baixo", + "codexSet.custom.limitReached": "Você pode manter até {max} camadas personalizadas.", + "codexSet.custom.notOwned": "developer_instructions foi gravado fora do opencodex, portanto não é editado por aqui. Importe-o para gerenciá-lo como uma camada.", + "codexSet.custom.adopt": "Importar instruções existentes", + "codexSet.custom.adoptConfirm": "Importar como uma camada", + "codexSet.custom.adoptRefused": "O valor existente não pôde ser importado.", + "codexSet.custom.baseReplaced": "model_instructions_file está definido como {path}, então algo fora do opencodex substituiu o prompt base.", + "codexSet.lint.identity": "Isso reivindica uma identidade diferente daquela estabelecida pelo Codex.", + "codexSet.lint.foreignTool": "As ferramentas vêm do registro; nomear uma aqui não a cria.", + "codexSet.lint.placeholder": "Nenhum motor de template é executado sobre as instruções, portanto isto é enviado literalmente.", + "codexSet.lint.applyPatch": "apply_patch é definido pelo registro de ferramentas, não pelas instruções.", + "codexSet.lint.approvalVocab": "O Codex injeta seu próprio vocabulário de aprovação; isto pode contradizê-lo.", + "codexSet.lint.environment": "Fatos do ambiente são gerados posteriormente e podem contradizer isto.", + "codexSet.lint.size": "Esta camada tem mais de 8 KB. Ela ainda será salva, mas custará tokens em cada requisição.", + "codexSet.preset.blank": "Camada em branco", + "codexSet.preset.concise.name": "Saída concisa", + "codexSet.preset.concise.description": "Respostas curtas, sem preâmbulo, formatação mínima.", + "codexSet.preset.concise.provenance": "Adaptado das diretrizes de concisão do Claude Code. Nossa redação, não uma cópia.", + "codexSet.preset.planFirst.name": "Planejar antes de editar", + "codexSet.preset.planFirst.description": "Declare o plano e, em seguida, faça a alteração.", + "codexSet.preset.planFirst.provenance": "Adaptado da postura de planejamento do Claude Code. Nossa redação, não uma cópia.", + "codexSet.preset.explainWhy.name": "Explicar raciocínio", + "codexSet.preset.explainWhy.description": "Diga o porquê, não apenas o quê.", + "codexSet.preset.explainWhy.provenance": "Adaptado do estilo de confirmação do Grok Build. Nossa redação, não uma cópia.", + "codexSet.preset.testFirst.name": "Testar primeiro", + "codexSet.preset.testFirst.description": "Escreva o teste que falha antes da correção.", + "codexSet.preset.testFirst.provenance": "Adaptado de práticas comuns de agentes. Nossa redação, não uma cópia.", + "codexSet.preset.korean.name": "Respostas em coreano", + "codexSet.preset.korean.description": "Responda em coreano, independentemente do idioma usado na requisição.", + "codexSet.preset.korean.provenance": "Escrito para o opencodex a partir de um recurso essencial solicitado pelo usuário. Nossa redação, não uma cópia.", + "codexSet.dialog.class": "Tipo", + "codexSet.dialog.key": "Chave de configuração", + "codexSet.dialog.fileValue": "Valor neste arquivo", + "codexSet.dialog.absentDefault": "não definido (padrão: {value})", + "codexSet.dialog.noRenderedText": "O Codex não expõe o texto montado de uma camada integrada, portanto, esta caixa de diálogo descreve a camada e nomeia sua chave em vez de exibir seu conteúdo.", + "codexSet.dialog.sourceText": "Texto enviado ao modelo", + "codexSet.dialog.sourceBytes": "{bytes} bytes", + "codexSet.dialog.notRendered": "Esta camada não enviou nada no turno que lemos. As seções só são reenviadas quando sofrem alterações, portanto, uma camada inalterada fica ausente em uma única amostra.", + "codexSet.dialog.emptySource": "O arquivo em {path} existe mas está vazio, portanto esta camada não envia nada.", + "codexSet.dialog.notExposed": "O prompt base trafega fora da lista de mensagens que o Codex pode exibir, portanto não pode ser mostrado aqui. É possível substituí-lo através de model_instructions_file.", + "codexSet.dialog.unmapped": "Esta camada não possui mapeamento confirmado na saída do prompt, portanto seu texto ainda não pode ser exibido aqui.", + "codexSet.dialog.textUnavailable": "Não foi possível ler o prompt do Codex nesta máquina, portanto o texto não está disponível.", + "codexSet.class.base": "Instruções base", + "codexSet.class.config-toggle": "Alternável aqui", + "codexSet.class.feature-gated": "Controlado por recurso", + "codexSet.class.runtime-conditional": "Condicional de tempo de execução", + "codexSet.class.extension-unknown": "Camada de extensão", + "codexSet.layer.base-instructions": "Instruções base", + "codexSet.layer.model-switch": "Aviso de troca de modelo", + "codexSet.layer.personality": "Personalidade", + "codexSet.layer.context-window-guidance": "Orientações da janela de contexto", + "codexSet.layer.realtime": "Tempo real", + "codexSet.layer.agents-md": "AGENTS.md", + "codexSet.layer.environments-instructions": "Ambientes", + "codexSet.layer.plugins": "Plugins", + "codexSet.layer.tools": "Ferramentas", + "codexSet.layer.multi-agent-mode": "Modo multi-agente", + "codexSet.layer.git-attribution": "Atribuição de commit", + "codexSet.about.base-instructions": "Instruções próprias do Codex. Elas acompanham a requisição em si e não podem ser desativadas.", + "codexSet.about.model-switch": "Adicionado quando a sessão altera o modelo no meio da conversa.", + "codexSet.about.personality": "Orientação de tom e voz, governada por uma flag de recurso.", + "codexSet.about.context-window-guidance": "Aviso sobre o orçamento de contexto restante, governado por uma flag de recurso.", + "codexSet.about.realtime": "Adicionado para sessões em tempo real.", + "codexSet.about.agents-md": "Os arquivos AGENTS.md do seu projeto. Esta página relata a camada; ela nunca edita a documentação do seu projeto.", + "codexSet.about.permissions": "Explica as configurações de sandbox e aprovação em vigor.", + "codexSet.about.collaboration": "Explica o modo de colaboração ativo.", + "codexSet.about.environment": "Diretório de trabalho, plataforma e outros fatos do ambiente.", + "codexSet.about.environments-instructions": "Orientações para ambientes de execução adiada, governadas por uma flag de recurso.", + "codexSet.about.apps": "Como usar aplicativos conectados.", + "codexSet.about.plugins": "Adicionado quando um plugin é selecionado ou qualquer plugin anuncia uma capacidade.", + "codexSet.about.tools": "Descrições de ferramentas adiadas, regidas por uma feature flag.", + "codexSet.about.skills": "A lista de skills disponíveis.", + "codexSet.about.multi-agent-mode": "Instruções de subagentes, regidas por uma feature flag.", + "codexSet.about.git-attribution": "Indica ao model para adicionar um rodapé Co-authored-by: Codex aos commits que ele escreve, e uma linha Generated with Codex. aos pull requests que ele abre. O Codex resolve isso a partir da sua conta, portanto não há configuração para isso aqui ou em [features]. Quando sua conta desativa essa opção, o Codex envia a instrução oposta em vez de não enviar nada.", + "codexSet.condition.model-switch": "Emitido apenas após uma alteração de model no meio da sessão.", + "codexSet.condition.realtime": "Emitido apenas em uma sessão em tempo real.", + "codexSet.condition.agents-md": "Emitido quando um documento de projeto é encontrado para o diretório de trabalho.", + "codexSet.condition.plugins": "Emitido quando um plugin é selecionado ou qualquer plugin anuncia uma capacidade.", + "codexSet.condition.git-attribution": "Definido pela política de atribuição da sua conta.", + "codexSet.base.title": "Prompt base", + "codexSet.base.prev": "Opção anterior", + "codexSet.base.next": "Próxima opção", + "codexSet.base.position": "{position} / {total}", + "codexSet.base.swipeHint": "Deslize para os lados, use as setas do teclado ou pressione as setas para navegar entre as opções. Aplica-se a sessões iniciadas recentemente.", + "codexSet.base.defaultTitle": "Prompt base nativo do Codex", + "codexSet.base.defaultBody": "O padrão não é armazenado aqui, portanto não há nada para editar ou excluir: escolhê-lo simplesmente remove model_instructions_file da sua configuração, e o Codex usa o prompt com o qual ele é distribuído.", + "codexSet.base.variantTitle": "Nome", + "codexSet.base.variantBody": "Prompt", + "codexSet.base.replacesWarning": "Isso SUBSTITUI o prompt base nativo do Codex em vez de adicioná-lo. Um prompt curto aqui significa um model com instruções curtas.", + "codexSet.base.use": "Usar esta", + "codexSet.base.inUse": "Em uso", + "codexSet.base.externalBlocked": "model_instructions_file já aponta para {path}, o que o opencodex não gravou. Limpe-o você mesmo antes de escolher uma opção aqui.", + "nav.api": "API", + "nav.integrations": "Integrações", + "nav.openMenu": "Abrir menu", + "nav.closeMenu": "Fechar menu", + "nav.goHome": "Ir para o painel", + "nav.collapseSidebar": "Recolher barra lateral", + "nav.expandSidebar": "Expandir barra lateral", + "pws.refreshAllQuotas": "Atualizar todas as cotas", + "pws.quotaRefreshDone": "Verificação de cota concluída", + "integrations.subtitle": "Conecte clientes ao opencodex, gerencie credenciais e restaure a configuração do cliente.", + "integrations.tabsLabel": "Superfícies de integração", + "integrations.tab.overview": "Visão geral", + "integrations.tab.keys": "Chaves de API", + "integrations.tab.codex": "Codex", + "integrations.tab.claude": "Claude", + "integrations.tab.grok": "Grok Build", + "integrations.tab.cursor": "Cursor", + "integrations.tab.opencode": "OpenCode", + "integrations.tab.pi": "Pi", + "integrations.tab.omp": "OMP", + "integrations.tab.hermes": "Hermes", + "integrations.tab.openclaw": "OpenClaw", + "integrations.tab.kimi": "Kimi Code", + "integrations.tab.gajae": "gjc", + "integrations.tab.dsh": "DSH", + "integrations.tab.mcode": "MiniMax Code", + "integrations.tab.zcode": "ZCode", + "integrations.tab.prime": "Prime Agent", + "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", + "integrations.tab.omo": "omo", + "integrations.tab.cline": "Cline CLI", + "integrations.aside.profilesTitle": "Perfis do Aside", + "integrations.aside.profilesHint": "Escolha quais perfis recebem os modelos selecionados. O perfil ativo do Aside permanece inalterado.", + "integrations.aside.all": "Sincronizar todos os perfis", + "integrations.aside.syncNow": "Sincronizar agora", + "integrations.aside.applied": "{count} de {total} perfis aplicados", + "integrations.aside.current": "Perfil atual", + "integrations.aside.profile": "Perfil {id}", + "integrations.aside.toggle": "Sincronizar {name}", + "integrations.aside.details": "Gerenciar {name}", + "integrations.aside.back": "Todos os perfis do Aside", + "integrations.aside.empty": "Abra o Aside e crie um perfil para conectá-lo.", + "integrations.aside.partial": "Alguns perfis precisam de atenção. Suas escolhas de sincronização foram salvas; verifique o estado de cada perfil.", + "integrations.aside.pending": "Escolha de sincronização salva; atualização de arquivo pendente.", + "integrations.aside.retry": "Tentar novamente {name}", + "integrations.aside.loadError": "Não foi possível carregar os perfis do Aside. Tente novamente para verificar o estado deles.", + "integrations.codex.title": "Codex CLI", + "integrations.codex.body": "O redirecionamento do Codex é gerenciado pelo serviço de proxy. Iniciar o opencodex aplica-o; parar o serviço restaura o roteamento nativo.", + "integrations.codex.openService": "Abrir controles do serviço", + "integrations.state.notInstalled": "Não instalado", + "integrations.state.unknown": "Verificando...", + "integrations.detail.codexRouted": "As requisições do Codex passam por este proxy", + "integrations.detail.codexAbsent": "O Codex ainda não está sendo roteado por este proxy", + "integrations.detail.keyCount": "{count} chave(s) emitida(s)", + "integrations.detail.keyNone": "Nenhuma chave emitida", + "integrations.detail.keyChecking": "Verificando...", + "integrations.detail.keyUnavailable": "Status da chave indisponível", + "integrations.detail.claudeOff": "A conexão está desativada", + "integrations.detail.desktopCurrent": "O Desktop está executando este perfil", + "integrations.detail.desktopStale": "O arquivo de perfil foi alterado após ser aplicado", + "integrations.detail.desktopNotServed": "O perfil existe, mas o Desktop está usando outro", + "integrations.detail.desktopAbsent": "Nenhum perfil aplicado", + "integrations.detail.desktopDesiredOff": "A integração com o Claude Desktop está desativada", + "integrations.detail.desktopDesiredOffCleanupPending": "O Claude Desktop ainda está usando o gateway; a limpeza está pendente", + "integrations.detail.desktopDesiredOnNotApplied": "A integração está ativada, mas o Desktop não está usando o perfil do gateway", + "integrations.detail.desktopSelectedElsewhere": "O Desktop está usando outro perfil", + "integrations.detail.desktopProfileDrift": "O perfil selecionado do Desktop foi alterado", + "integrations.detail.desktopObservedUnsafe": "O perfil selecionado do Desktop não pode ser alterado com segurança", + "integrations.detail.desktopNotInstalled": "A biblioteca de configuração do Claude Desktop não está instalada", + "integrations.detail.grokModels": "{count} modelo(s) configurado(s)", + "integrations.detail.grokAbsent": "Nenhum bloco opencodex encontrado na configuração", + "integrations.detail.cursorSeen": "O Cursor chamou este proxy recentemente", + "integrations.detail.cursorNeverSeen": "Private Inference instalado; nenhuma requisição detectada ainda", + "integrations.detail.cursorAbsent": "Cursor Private Inference não encontrado", + "integrations.cursor.title": "Cursor", + "integrations.cursor.intro": "O Cursor Private Inference executa seu agente localmente e se comunica com o opencodex via loopback. O Cursor normal não pode fazer isso: o backend dele chama o endpoint personalizado e precisa de uma URL HTTPS pública. Esta página nunca grava dados no Cursor; cole os valores abaixo no Cursor você mesmo.", + "integrations.cursor.loading": "Lendo o status do Cursor...", + "integrations.cursor.installerIntro": "O Cursor Private Inference é uma compilação separada em modo local. O canal de atualizações do Cursor anuncia o instalador e a versão {version}; instale-o e depois cole a Base URL e a chave de API abaixo em Configurações > Models > Gateway.", + "integrations.cursor.installerCheck": "Procurar o instalador do Private Inference", + "integrations.cursor.installerChecking": "Verificando o canal de atualizações do Cursor…", + "integrations.cursor.installerOpen": "Baixar o instalador", + "integrations.cursor.installerUnavailable": "Não foi possível obter o instalador do Private Inference no canal de atualizações do Cursor para este computador. Os valores do gateway abaixo passam a valer depois que ele for instalado.", + "integrations.cursor.unavailable": "Não foi possível ler o status do Cursor a partir do proxy.", + "integrations.cursor.detection": "Builds instaladas", + "integrations.cursor.privateInference": "Cursor Private Inference", + "integrations.cursor.regular": "Cursor (regular)", + "integrations.cursor.detected": "Detectado", + "integrations.cursor.notFound": "Não encontrado", + "integrations.cursor.regularOnly": "Apenas o Cursor regular foi encontrado. Ele encaminha endpoints personalizados pelos servidores do Cursor, portanto, um proxy loopback fica inacessível sem um túnel público. Consulte o guia para a compilação do Private Inference.", + "integrations.cursor.nothingFound": "Nenhuma instalação do Cursor foi encontrada nos locais habituais. Se estiver instalado em outro lugar, os valores abaixo ainda se aplicam.", + "integrations.cursor.gateway": "Valores do gateway", + "integrations.cursor.gatewayHint": "No Cursor Private Inference, abra Settings > Models > Gateway, cole estes dois valores e pressione Refresh model list.", + "integrations.cursor.baseUrl": "Base URL", + "integrations.cursor.apiKey": "API Key", + "integrations.cursor.apiKeyCredential": "Uma das suas chaves de API do opencodex (esta vinculação requer uma credencial)", + "integrations.cursor.copy": "Copiar", + "integrations.cursor.copied": "Copiado", + "integrations.cursor.connection": "Conexão", + "integrations.cursor.seen": "Última requisição do Cursor: {time} ({ua})", + "integrations.cursor.neverSeen": "Nenhuma requisição do Cursor desde que o proxy foi iniciado. Após salvar o gateway, pressione Refresh model list no Cursor.", + "integrations.cursor.models": "O que o Cursor exibirá", + "integrations.cursor.modelsHint": "O Cursor escolhe a escala de raciocínio a partir de sua própria tabela de modelos, portanto o opencodex só pode prevê-la. Context lista o padrão e a janela opcional (Max Mode do Cursor).", + "integrations.cursor.ladderFromBundle": "Escalas de raciocínio lidas do pacote do Cursor Private Inference {version} instalado. O Cursor as define; o opencodex apenas relata sua tabela.", + "integrations.cursor.ladderFromStatic": "As escalas de raciocínio são um espelho estático do Cursor 3.18.25 (nenhum pacote legível do Private Inference foi encontrado). Context lista o padrão e a janela opcional.", + "integrations.cursor.unknownVersion": "versão desconhecida", + "integrations.cursor.noControl": "—", + "integrations.cursor.singleWindow": "janela única", + "integrations.cursor.noControlTitle": "Este ID não está na tabela de esforço integrada do Cursor, portanto o Cursor não exibe nenhum controle de raciocínio.", + "integrations.cursor.effortRowsOne": "1 linha de esforço publicada", + "integrations.cursor.effortRowsMany": "{n} linhas de esforço publicadas", + "integrations.cursor.effortRowsOff": "nenhuma linha de esforço", + "integrations.cursor.tableLessHint": "Linhas marcadas com — não recebem controle de raciocínio no Cursor. Ative cursorEffortRows para publicar uma entrada de seleção por esforço (id--effort), ou defina modelDefaultReasoningEfforts no provedor para um padrão fixo.", + "integrations.cursor.colModel": "Modelo", + "integrations.cursor.colReasoning": "Raciocínio", + "integrations.cursor.colContext": "Contexto", + "integrations.cursor.guide": "Abrir o guia do Cursor Private Inference", + "integrations.dialog.codex.title": "Desativar a integração com o Codex?", + "integrations.dialog.codex.changes": "O opencodex removerá seu roteamento de {path}, removerá seu perfil gerado, restaurará o catálogo de modelos nativo e retagueará os threads retormáveis para o Codex nativo.", + "integrations.dialog.codex.breakage": "O Codex simples se conectará diretamente à OpenAI, e os modelos roteados de outros provedores desaparecerão do Codex. O proxy e /v1/responses continuarão funcionando para outros clientes.", + "integrations.dialog.codex.undo": "Reativar isso reconstrói o catálogo roteado a partir dos modelos disponíveis naquele momento e injeta o Codex novamente. O histórico de retomada é tornado utilizável na direção correspondente, mas seus arquivos não são restaurados byte a byte.", + "integrations.dialog.codex.sideEffect": "Se você selecionou um modelo raiz roteado após o opencodex injetar a configuração, desativar remove essa seleção de modelo e reativar a integração não consegue reconstruí-la; selecione o modelo novamente. Se um model_provider externo possuir o Codex, o opencodex removerá apenas seu diário obsoleto e deixará a configuração, o catálogo e o histórico inalterados.", + "integrations.dialog.codex.confirm": "Desativar", + "integrations.dialog.grok.title": "Desativar a integração com o Grok Build?", + "integrations.dialog.grok.changes": "Apenas o bloco marcado pelo opencodex será removido de {path}. O conteúdo gravado fora do bloco permanecerá inalterado.", + "integrations.dialog.grok.breakage": "Desativar remove os aliases de modelo do opencodex do Grok Build. Os modelos usados com sua conta xAI continuarão disponíveis.", + "integrations.dialog.grok.undo": "Se o opencodex estiver sendo executado em um endereço loopback, reativar isso gravará um novo bloco a partir dos modelos atualmente disponíveis.", + "integrations.dialog.grok.confirm": "Desativar", + "integrations.dialog.desktop.title": "Desativar a integração com o Claude Desktop?", + "integrations.dialog.desktop.changes": "Se {path} contiver um perfil de gateway gerenciado pelo opencodex, o Desktop selecionará primeiro um novo perfil padrão sem credenciais e, em seguida, removerá o perfil antigo e o backup.", + "integrations.dialog.desktop.breakage": "O Claude Desktop retornará ao Claude padrão em vez dos modelos roteados pelo opencodex.", + "integrations.dialog.desktop.undo": "Reativar isso regenera o perfil do opencodex a partir das suas atribuições de modelo salvas.", + "integrations.dialog.desktop.restart": "O Claude Desktop lê esta configuração apenas na inicialização. Encerre-o totalmente e reabra-o para que esta alteração tenha efeito.", + "integrations.dialog.desktop.confirm": "Desativar", + "integrations.native.msg.nonLoopbackRemoved": "O Grok Build só pode ser registrado automaticamente enquanto o opencodex estiver sendo executado em um endereço loopback. O bloco anterior que apontava para o loopback foi removido.", + "integrations.native.msg.nonLoopbackRemovedNoop": "O Grok Build só pode ser registrado automaticamente enquanto o opencodex estiver rodando em um endereço loopback. Não havia um bloco anterior para remover.", + "integrations.native.msg.nonLoopbackSuperseded": "O Grok Build só pode ser registrado automaticamente enquanto o opencodex estiver rodando em um endereço loopback. Outro processo gravou um novo bloco nesse meio tempo, portanto o bloco atual no arquivo não foi criado por esta requisição.", + "integrations.native.error.orphanedMarker": "{path} possui um marcador de início do opencodex mas nenhum marcador de fim. O arquivo não foi alterado porque o opencodex não consegue determinar onde seu bloco termina.", + "integrations.native.error.homeMismatch": "O diretório home do serviço instalado não corresponde ao home atual, portanto o arquivo não foi alterado.", + "integrations.native.error.notInstalled": "O Grok Build não está instalado, então não há nada para alterar.", + "integrations.native.error.configBusy": "A configuração está sendo salva em outro lugar e não pôde ser alterada. Tente novamente em breve.", + "integrations.native.error.desktopUnsafeMetadata": "Os metadados do Claude Desktop em {path} não puderam ser lidos com segurança, portanto sua biblioteca não foi alterada.", + "integrations.native.error.desktopCleanupIncomplete": "O Claude Desktop está apontado para o modo padrão, mas arquivos de credenciais antigos do opencodex permanecem em: {paths}.", + "integrations.native.msg.desktopDisabled": "Integração com o Claude Desktop desativada.", + "integrations.native.msg.desktopEnabled": "Integração com o Claude Desktop ativada.", + "integrations.state.absent": "Não aplicado", + "integrations.state.current": "Aplicado", + "integrations.state.stale": "Atualização necessária", + "integrations.state.conflict": "Conflito", + "integrations.state.unsafe": "Não é possível verificar", + "integrations.summary.detected": "Clientes detectados", + "integrations.summary.applied": "Clientes configurados", + "integrations.summary.stale": "Atualização necessária", + "integrations.summary.lastChange": "Última alteração", + "integrations.summary.disableAll": "Desativar tudo…", + "integrations.onboarding": "Aplicar grava um bloco de provider do opencodex após salvar um backup. Desativar remove apenas esse bloco, e um snapshot retido pode ser restaurado.", + "integrations.empty.title": "Nenhum cliente instalado foi detectado", + "integrations.empty.body": "Instale um cliente compatível e retorne aqui para aplicar o opencodex.", + "integrations.action.apply": "Aplicar", + "integrations.action.disable": "Desativar", + "integrations.action.refresh": "Atualizar", + "integrations.action.settings": "Configurações", + "integrations.action.manageKeys": "Gerenciar chaves", + "integrations.action.restore": "Restaurar…", + "integrations.action.undo": "Desfazer", + "integrations.action.restorePoint": "Restaurar este ponto…", + "integrations.action.snapshotExpired": "Backup expirado", + "integrations.rollback.title": "Central de reversão", + "integrations.rollback.empty": "Nenhum histórico de aplicação ainda", + "integrations.rollback.emptyBody": "Toda gravação bem-sucedida mantém um snapshot pré-gravação primeiro.", + "integrations.catalog.title": "Clientes", + "integrations.rollback.older": "Operações anteriores", + "integrations.rollback.showMore": "Mostrar mais {n}", + "integrations.rollback.failed": "Não foi possível carregar o histórico de reversão.", + "integrations.rollback.delete": "Excluir", + "integrations.rollback.deleteAria": "Excluir a entrada de reversão de {at}", + "integrations.rollback.deleteNewest": "A entrada mais recente para este cliente é mantida para que você ainda possa desfazê-la.", + "integrations.rollback.deleteGone": "Esta entrada já foi excluída. A lista será atualizada.", + "integrations.dialog.deleteEntry.title": "Excluir esta entrada de reversão?", + "integrations.dialog.deleteEntry.changes": "Esta entrada desaparece da lista de reversão, e qualquer backup que ela ainda mantenha para {path} é excluído do disco.", + "integrations.dialog.deleteEntry.breakage": "Você não poderá mais restaurar o arquivo para este ponto. Entradas mais recentes e o arquivo em si não são afetados.", + "integrations.dialog.deleteEntry.undo": "Isso não pode ser desfeito. A entrada mais recente para cada cliente é mantida e não pode ser excluída.", + "integrations.dialog.deleteEntry.confirm": "Excluir entrada", + "integrations.restore.title": "Restaurar este snapshot?", + "integrations.restore.body": "O arquivo atual passa por backup primeiro, e então o snapshot selecionado o substitui.", + "integrations.restore.driftTitle": "Edições mais recentes foram detectadas", + "integrations.restore.driftBody": "As alterações feitas após este snapshot serão copiadas para backup, e o arquivo será substituído.", + "integrations.restore.confirm": "Restaurar", + "integrations.restore.confirmDrift": "Fazer backup de edições recentes e restaurar", + "integrations.restore.pending": "Restaurando...", + "integrations.restore.manual": "A restauração automática falhou: {reason}. Restaure manualmente a partir de {path}.", + "integrations.error.load": "Não foi possível carregar o estado da integração.", + "integrations.error.stale": "A última atualização falhou. Os valores abaixo podem estar desatualizados.", + "integrations.error.busy": "Outra alteração para este cliente ainda está em execução. Tente novamente em breve.", + "integrations.error.conflict": "A config foi alterada após a gravação pelo opencodex. Nada foi removido.", + "integrations.error.unsafe": "A config não pode ser alterada com segurança.", + "integrations.error.generic": "A alteração da integração falhou. Seu estado anterior foi mantido.", + "integrations.error.nonLoopback": "{client} só consegue alcançar um proxy em localhost — a config dele não tem onde colocar o cabeçalho de admissão que um bind remoto exige, portanto, escrever um manualmente também não ajudará. Conceda acesso de loopback a ele, por meio de um túnel ou de um encaminhador local.", + "integrations.status.installed": "Instalado", + "integrations.status.notInstalled": "Não instalado", + "integrations.status.appliedAt": "Aplicado", + "integrations.status.supersededStore": "Este cliente agora lê os provedores de {path}, que o opencodex não modifica. Ativá-lo aqui não alteraria o que ele carrega.", + "integrations.status.backup": "Backup", + "integrations.status.lastRestore": "Última restauração", + "integrations.status.unknown": "Desconhecido", + "integrations.bulk.title": "Desativar integrações de cliente aplicadas?", + "integrations.bulk.body": "Apenas o bloco gerenciado pelo opencodex é removido. Um snapshot pré-gravação é mantido para cada cliente.", + "integrations.bulk.partial": "Alguns clientes não puderam ser desativados: {clients}", + "integrations.bulk.success": "As integrações de cliente aplicadasforam desativadas.", + "integrations.retention.degraded": "A limpeza de backup está atrasada; backups mais antigos ainda podem estar no disco.", + "integrations.error.residual": "O arquivo pode estar em um estado intermediário: {message} Restaure-o a partir de {path}.", + "integrations.error.residualNoSnapshot": "{message} A recuperação automática não terminou. Verifique a configuração do cliente antes de tentar novamente.", + "integrations.error.recover": "{message} Um backup está em {path}.", + "integrations.kind.apply": "Aplicado", + "integrations.kind.disable": "Desativado", + "integrations.kind.refresh": "Atualizado", + "integrations.kind.restore": "Restaurado", + "integrations.kind.overwrite": "Sobrescrito", + "integrations.dialog.overwrite.title": "Substituir o bloco nesta config?", + "integrations.dialog.overwrite.changesUnowned": "Um bloco que não escrevemos ocupa as configurações de que o opencodex precisa em {path}. Aplicar substitui esse bloco pelo que o opencodex escreveria.", + "integrations.dialog.overwrite.changesForeign": "Sua edição dentro do bloco do opencodex em {path} será descartada e substituída pelo bloco que o opencodex escreveria.", + "integrations.dialog.overwrite.breakage": "Tudo o que o outro bloco configurou deixará de ter efeito. O conteúdo em outras partes do arquivo não será afetado.", + "integrations.dialog.overwrite.undo": "Um snapshot é salvo primeiro, portanto isso aparece na lista de reversão abaixo e pode ser desfeito.", + "integrations.dialog.overwrite.confirm": "Substituir", + "integrations.action.overwrite": "Substituir", + "integrations.preview.loading": "Carregando o plano exato de alterações…", + "integrations.preview.failed": "Não foi possível carregar o plano de alterações. Nada foi alterado.", + "integrations.preview.stale": "A integração foi alterada enquanto você confirmava. Revise o plano atualizado e confirme novamente.", + "integrations.dialog.apply.title": "Aplicar esta integração?", + "integrations.dialog.apply.changes": "O opencodex adicionará suas configurações de provedor gerenciadas à configuração do client.", + "integrations.dialog.apply.breakage": "O client usará os models expostos atualmente por esta instância do opencodex.", + "integrations.dialog.apply.undo": "Um backup é salvo primeiro, e a alteração pode ser desfeita a partir da central de rollback.", + "integrations.dialog.apply.confirm": "Aplicar", + "integrations.dialog.disable.title": "Desativar esta integração?", + "integrations.dialog.disable.changes": "Apenas as configurações pertencentes ao opencodex serão removidas.", + "integrations.dialog.disable.breakage": "O client parará de usar os models roteados por esta instância do opencodex.", + "integrations.dialog.disable.undo": "Um backup é salvo primeiro, e a alteração pode ser desfeita a partir da central de rollback.", + "integrations.dialog.disable.confirm": "Desativar", + "integrations.plan.heading": "Plano de alterações do servidor", + "integrations.plan.operation": "Operação: {operation}", + "integrations.plan.operation.apply": "Aplicar", + "integrations.plan.operation.overwrite": "Substituir", + "integrations.plan.operation.disable": "Desativar", + "integrations.plan.operation.restore": "Restaurar", + "integrations.plan.change.add": "Adicionar", + "integrations.plan.change.replace": "Substituir", + "integrations.plan.change.remove": "Remover", + "integrations.plan.change.snapshot": "Salvar backup", + "integrations.plan.change.ownership": "Atualizar registro de propriedade", + "integrations.plan.change.journal": "Registrar entrada de rollback", + "integrations.plan.foreign.none": "Nenhuma edição externa foi detectada.", + "integrations.plan.foreign.unowned": "Um bloco de configurações não pertencente ao opencodex será substituído.", + "integrations.plan.foreign.foreignEdit": "Edições dentro do bloco gerenciado pelo opencodex serão substituídas.", + "integrations.plan.foreign.drift": "O arquivo foi alterado desde este ponto de rollback.", + "integrations.plan.noop.applied": "Nenhuma alteração no documento do client gerenciado é necessária; suas configurações de integração já estão presentes.", + "integrations.plan.noop.disabled": "Nenhuma alteração no documento do client gerenciado é necessária; suas configurações de integração já estão ausentes.", + "integrations.plan.noop.profilePreference": "A preferência de sincronização de perfil ainda será salva quando você confirmar.", + "integrations.plan.refused": "O servidor não pode aplicar este plano com segurança.", + "integrations.plan.refusal.notInstalled": "O client não está instalado. Instale-o, atualize esta página e visualize a alteração novamente.", + "integrations.plan.refusal.conflict": "As configurações gerenciadas entram em conflito com o arquivo atual. Revise o arquivo ou use Substituir quando essa ação estiver disponível.", + "integrations.plan.refusal.unsafe": "A configuração do client não pode ser alterada com segurança. Repare ou substitua o arquivo antes de tentar novamente.", + "integrations.plan.refusal.nonLoopback": "Este client requer um endereço de proxy loopback. Use o acesso localhost, um túnel ou um encaminhador local antes de tentar novamente.", + "integrations.plan.refusal.supersededStore": "Este cliente agora lê os provedores de um arquivo que o opencodex não modifica. Esta operação não alteraria o que ele carrega.", + "integrations.plan.refusal.driftRequiresConfirm": "O arquivo foi alterado após este ponto de rollback. Revise o plano sensível a drift antes de restaurar.", + "integrations.plan.refusal.snapshotExpired": "O backup para este ponto de rollback expirou e não pode mais ser restaurado.", + "integrations.plan.refusal.writeFailed": "O servidor não pôde preparar uma gravação segura. Atualize o estado da integração antes de tentar novamente.", + "integrations.mutation.pending": "Aplicando a alteração confirmada…", + "integrations.bulk.breakage": "Cada client parará de usar os models roteados por esta instância do opencodex.", + "integrations.bulk.undo": "Cada client mantém seu próprio backup e entrada de rollback.", + "integrations.bulk.confirm": "Desativar tudo", + "integrations.semantics.opencode": "Apenas inicializações diretas de disco; a injeção de ambiente ocx opencode tem prioridade.", + "integrations.semantics.pi": "Aplica-se a novas sessões.", + "integrations.semantics.omp": "Reinicie o OMP para carregar o catálogo.", + "integrations.semantics.hermes": "Aplica-se a novas sessões.", + "integrations.semantics.openclaw": "Aplica-se imediatamente a um gateway em execução.", + "integrations.semantics.kimi": "Reinicie ou execute /reload para aplicar (a v2 monitora o arquivo).", + "integrations.semantics.gajae": "Aplica-se a uma nova sessão ou ao abrir /model.", + "integrations.semantics.dsh": "O OpenCodex gerencia apenas llm-pi-ai.providers.opencodex em $DSH_HOME/settings.yaml. O DSH recarrega este provider dinamicamente; seu model padrão e o deepseek-official permanecem inalterados. Atualmente apenas loopback; nenhuma credencial real é escrita.", + "integrations.semantics.mcode": "Gerencia apenas custom_provider.opencodex. Seu model padrão e o login do MiniMax permanecem inalterados.", + "integrations.semantics.zcode": "Gerencia apenas provider.opencodex em ~/.zcode/v2/config.json. Seu login no Z.ai e outros providers permanecem inalterados. Reinicie o ZCode após as alterações.", + "integrations.semantics.prime": "Gerencia apenas providers.opencodex em models.json do Prime Agent — ~/.prime/agent, a menos que PRIME_AGENT_CODING_AGENT_DIR o redirecione. Seus outros providers e substituições de model permanecem inalterados. Aplica-se a novas sessões.", + "integrations.semantics.aside": "Gerencia apenas providers.opencodex no ~/.aside/u//models.json deste perfil. Seus outros providers permanecem inalterados. Encerre completamente e reabra o Aside após aplicar.", + "integrations.semantics.raycast": "Adiciona uma entrada de provider OpenCodex ao providers.yaml do Raycast para que cada model roteado apareça no seletor de AI do Raycast. Raycast Pro obrigatório.", + "integrations.semantics.omo": "Gerencia apenas providers.opencodex em models.json do omo — ~/.omo/agent, a menos que OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR ou PI_CODING_AGENT_DIR o redirecionem. Seus outros providers permanecem inalterados. Aplica-se a novas sessões.", + "integrations.semantics.cline": "Gerencia o OpenCodex nos arquivos providers.json e models.json do Cline CLI. Pare o Cline antes de alterar ou sincronizar esses arquivos e, em seguida, reinicie. A ação Desfazer restaura ambos os originais. Seu provider padrão permanece inalterado; selecione OpenCodex no Cline.", + "integrations.raycast.proRequired": "Custom Providers é um recurso do Raycast Pro. O arquivo será gravado, mas o Raycast o ignorará até que uma assinatura Pro esteja ativa.", + "integrations.raycast.planUnknown": "Não foi possível determinar se o Raycast Pro está ativo; Custom Providers requer o Raycast Pro.", + "integrations.raycast.revealConfig": "Abra o Raycast → Settings → AI e clique em Reveal Providers Config uma vez para que a pasta de providers exista.", + "codexAuth.mainAccount": "Conta Principal", + "codexAuth.logLabel": "Rótulo de log", + "codexAuth.codexApp": "Aplicativo Codex", + "codexAuth.moreActions": "Mostrar mais ações", + "codexAuth.copyId": "Copiar ID da conta", + "codexAuth.appLogin": "Login no app", + "codexAuth.accountPool": "Pool de Contas", + "codexAuth.accountModeTitle": "Modo de conta OpenAI", + "codexAuth.accountModePool": "Modo Pool", + "codexAuth.accountModePoolDesc": "O login principal e as contas adicionadas elegíveis alternam aqui.", + "codexAuth.accountModeDirect": "Modo Direto", + "codexAuth.accountModeDirectDesc": "As requisições usam apenas o login principal; as contas adicionadas permanecem armazenadas para o modo Pool.", + "codexAuth.openaiMissing": "O provider OpenAI integrado não está configurado.", + "codexAuth.openaiDisabled": "O provider OpenAI integrado está desativado.", + "codexAuth.openaiUnavailableDesc": "Suas contas OpenAI ainda estão disponíveis. Ative o provider para rotear as requisições do Codex.", + "codexAuth.enableOpenai": "Ativar OpenAI", + "codexAuth.enablingOpenai": "Ativando...", + "codexAuth.enableOpenaiFailed": "Falha ao ativar o provider OpenAI.", + "codexAuth.openaiPresetLoadFailed": "Falha ao carregar o preset do provider OpenAI.", + "codexAuth.openaiPresetUnavailable": "O preset do provider OpenAI está indisponível.", + "codexAuth.openProviders": "Abrir Providers", + "codexAuth.add": "Adicionar", + "codexAuth.refreshQuota": "Atualizar cotas", + "codexAuth.ultraFastTitle": "Nível de serviço Ultra Fast", + "codexAuth.mainHardLockTitle": "Bloquear conta principal em 99%", + "codexAuth.mainHardLockDesc": "Usa o uso de 5h quando disponível, caso contrário o semanal (mensal para contas apenas mensais). Uma leitura nova de 0% é desbloqueada automaticamente; a proteção permanece ativada.", + "codexAuth.mainHardLockConfirmTitle": "Ativar o bloqueio de 99% da conta principal?", + "codexAuth.mainHardLockConfirmBody": "Enquanto bloqueada, a conta principal não pode usar o Luna Reserve. Manter o uso normal abaixo da exaustão pode evitar a ativação do Reserve. Contas adicionadas e outros providers permanecem disponíveis. Requisições em execução, credenciais de chaveiro não correspondidas e tráfego fora deste proxy não estão protegidos.", + "codexAuth.mainHardLockConfirm": "Ativar proteção", + "codexAuth.mainHardLockEnabled": "A proteção de 99% está ativada.", + "codexAuth.mainHardLockDisabled": "A proteção de 99% está desativada. Outros limites de conta ainda se aplicam.", + "codexAuth.mainHardLockLoadFailed": "Não foi possível carregar esta configuração. Tente novamente para verificar o estado atual.", + "codexAuth.mainHardLockSaveFailed": "Não foi possível confirmar o salvamento. Recarregue a configuração antes de tentar novamente.", + "codexAuth.mainHardLockRefreshFailed": "Configuração salva, mas o status da conta não pôde ser atualizado. Tente novamente.", + "codexAuth.mainHardLockBlocked": "Bloqueado pela proteção de 99%", + "codexAuth.mainHardLockUnknown": "Proteção ativada · uso desconhecido", + "codexAuth.mainHardLockMonitoring": "Proteção ativada · monitorando", + "codexAuth.mainHardLockManage": "Ver configuração de proteção", + "codexAuth.ultraFastDesc": "Impede que um nível de serviço ultrarrápido configurado por você seja removido quando o catálogo for regenerado, e o nomeia nos logs de requisição. Ele não adiciona o Ultra Fast ao seletor de models: o upstream anuncia apenas Fast, portanto, uma linha no seletor ofereceria uma velocidade que a conexão não pode entregar.", + "codexAuth.ultraFastLoadFailed": "Não foi possível ler a configuração do Ultra Fast.", + "codexAuth.ultraFastEnabled": "Nível Ultra Fast ativado", + "codexAuth.ultraFastDisabled": "Nível Ultra Fast desativado", + "codexAuth.ultraFastFailed": "Não foi possível alterar a configuração do Ultra Fast", + "codexAuth.refreshingQuota": "Atualizando...", + "codexAuth.quotaRefreshed": "Cotas atualizadas", + "codexAuth.quotaRefreshFailed": "Falha ao atualizar as cotas", + "codexAuth.pauseExhausted": "Pausar esgotadas", + "codexAuth.pausingExhausted": "Verificando cotas...", + "codexAuth.pauseExhaustedSucceeded": "Contas no limite pausadas: {count}", + "codexAuth.pauseExhaustedNone": "Nenhuma conta confirmou 100% de uso.", + "codexAuth.pauseExhaustedFailed": "Falha ao verificar e pausar contas esgotadas.", + "codexAuth.noPool": "Nenhuma conta de pool adicionada ainda.", + "codexAuth.pause": "Pausar", + "codexAuth.resume": "Retomar", + "codexAuth.paused": "PAUSADO", + "codexAuth.planExcluded": "Não selecionado automaticamente", + "codexAuth.planExcludedHint": "O plano {plan} está excluído da seleção automática. Rotas de contas explícitas continuam disponíveis.", + "codexAuth.pauseSucceeded": "{email} está pausada", + "codexAuth.resumeSucceeded": "{email} está disponível para o pool novamente", + "codexAuth.pauseFailed": "Não foi possível pausar {email}. Nada foi alterado.", + "codexAuth.resumeFailed": "Não foi possível retomar {email}. Nada foi alterado.", + "codexAuth.pausedHint": "Excluído de alternância automática, novas tentativas, recuperação de cooldown e seleção manual até ser retomado.", + "codexAuth.pinned": "FIXADO", + "codexAuth.pinnedHint": "Você selecionou esta conta manualmente, portanto, uma ordem de seleção superior não passará por cima dela. A fixação dura até esta conta se esgotar, você selecionar outra ou alterar qualquer ordem de seleção.", + "codexAuth.fiveHour": "5h", + "codexAuth.weekly": "Semanal", + "codexAuth.quotaAutoRefresh": "Ativação automática de janela", + "codexAuth.quotaAutoRefreshHint": "Envia uma única solicitação mínima de aquecimento de Codex sem armazenamento quando esta janela de cota for redefinida.", + "codexAuth.quotaAutoRefreshUpdated": "Ativação automática de janela atualizada.", + "codexAuth.quotaAutoRefreshFailed": "Não foi possível atualizar a ativação automática de janela.", + "codexAuth.monthly": "30d", + "codexAuth.resets": "reseta", + "codexAuth.today": "Hoje", + "codexAuth.current": "ATUAL", + "codexAuth.nextSession": "SELECIONADO", + "codexAuth.poolPrepared": "PREPARADO PARA O POOL", + "codexAuth.preparePoolTitle": "Preparar esta conta para o modo Pool?", + "codexAuth.preparePoolDesc": "Solicitações diretas continuam usando o login principal. Esta conta se torna a seleção de Pool preparada quando o modo Pool está ativado.", + "codexAuth.prepareForPool": "Preparar para o Pool", + "codexAuth.poolPreparedToast": "{email} está preparado para o modo Pool", + "codexAuth.switchTitle": "Alternar conta ativa?", + "codexAuth.switchDesc": "Entra em vigor imediatamente. Threads vinculadas à conta existente e solicitações já em andamento mantêm sua conta capturada; solicitações novas ou não vinculadas usam o nível de ordem da conta selecionada, e contas com a mesma ordem de seleção ainda se revezam.", + "codexAuth.cacheWarning": "O cache de prompt é redefinido ao alternar de conta. A nova sessão começa com o cache vazio.", + "codexAuth.switchExceedsThresholdWarning": "O uso desta conta atinge ou excede o limite de alternância ({threshold}%). A seleção fixada será liberada se não houver margem de cota disponível.", + "codexAuth.setAsNext": "Usar esta conta em seguida", + "codexAuth.cancel": "Cancelar", + "codexAuth.switchBack": "Voltar para a Principal?", + "codexAuth.switchBackDesc": "Entra em vigor imediatamente. Threads vinculadas à conta existente e solicitações já em andamento mantêm sua conta capturada; solicitações novas ou não vinculadas usam o nível de ordem da sua conta de login do App, e contas com a mesma ordem de seleção ainda se revezam.", + "codexAuth.autoSwitch": "Alternância proativa baseada em uso", + "codexAuth.autoSwitchQuotaDesc": "Cota: a {threshold}% de uso ou mais, a próxima solicitação não vinculada pode migrar para uma conta elegível com menor uso. Tarefas vinculadas mantêm a afinidade por padrão e só se movem quando a conta não puder atender e apenas para uma margem de cota genuína; Go/Free usam apenas 30d.", + "codexAuth.autoSwitchQuotaOffDesc": "A alternância proativa baseada em uso está desativada. A atribuição nova/não vinculada e a recuperação de falhas ainda se aplicam.", + "codexAuth.autoSwitchRoundRobinDesc": "A atribuição por rodízio (round-robin) não usa este limite; ela continua a rotacionar tarefas novas/não vinculadas.", + "codexAuth.autoSwitchFillFirstDesc": "Preencher primeiro: {threshold}% é o ponto de esgotamento para tarefas novas/não vinculadas; tarefas vinculadas saudáveis mantêm sua conta.", + "codexAuth.autoSwitchFillFirstOffDesc": "O preenchimento primeiro não tem ponto de esgotamento de uso para tarefas novas/não vinculadas; cooldown, reautenticação e recuperação de falhas ainda podem mover o roteamento.", + "codexAuth.failureRecoveryNote": "A recuperação de falhas é separada: uma solicitação rejeitada antes da saída com 429/402, cooldown, reautenticação, exclusão ou failover transitório configurado pode selecionar outra conta elegível.", + "codexAuth.autoSwitchThreshold": "Limite de uso", + "codexAuth.autoSwitchThresholdAria": "Limite de uso, porcentagem", + "codexAuth.autoSwitchThresholdInc": "Aumentar limite de uso", + "codexAuth.autoSwitchThresholdDec": "Diminuir limite de uso", + "codexAuth.autoSwitchLoadFailed": "Não foi possível carregar a configuração de alternância baseada em uso.", + "codexAuth.autoSwitchThresholdInvalid": "Insira um número inteiro de 1 a 100", + "codexAuth.autoSwitchUpdated": "Alternância proativa baseada em uso atualizada", + "codexAuth.autoSwitchUpdateFailed": "Não foi possível confirmar a atualização da alternância baseada em uso. O último valor confirmado é exibido.", + "codexAuth.requestUserInput": "Solicitar entrada no modo Default", + "codexAuth.requestUserInputDesc": "Permite que o Codex pause uma sessão no modo Default e faça perguntas a você com a ferramenta request_user_input.", + "codexAuth.requestUserInputUpdated": "Feature flag atualizada - aplica-se a novas sessões.", + "codexAuth.requestUserInputUpdatedRestart": "Feature flag atualizada - aplica-se a novas sessões. Reinicie o aplicativo Codex para aplicar.", + "codexAuth.requestUserInputUpdateFailed": "Não foi possível atualizar a feature flag. Nada foi alterado.", + "codexAuth.requestUserInputLoadFailed": "Não foi possível ler a feature flag de config.toml.", + "codexAuth.accountPickerTitle": "Direcionar para uma conta específica do Codex a partir do seletor de model", + "codexAuth.accountPickerOffDesc": "Quando ativado, as linhas comuns do seletor GPT são substituídas por uma entrada por seletor de conta, para que você possa escolher a conta exata para uma conversa sem sair da conta. Desativar isso não remove nenhuma conta.", + "codexAuth.accountPickerOnDesc": "Cada seletor é um rótulo público para uma conta armazenada. Escolhê-lo vincula essa conversa à conta mapeada: ela nunca rota ou usa fallback, e não altera a conta ativa do Pool.", + "codexAuth.accountPickerCompatibility": "O login integrado do aplicativo Codex tem seu próprio seletor; os mapeamentos gerados normalmente o chamam de main e usam um sufixo seguro contra colisões, como main-2, quando necessário. Contas adicionadas recebem rótulos estáveis e seguros para privacidade, enquanto rótulos de seletores personalizados permanecem inalterados. Conversas existentes e seleções de model salvas continuam sendo roteadas. Desativar isso oculta as entradas geradas, mas preserva os seletores e rotas exatas. IDs de model GPT simples mantêm seu comportamento de Pool ou Direct.", + "codexAuth.accountPickerUpdated": "Direcionamento de conta atualizado.", + "codexAuth.accountPickerUpdateFailed": "Não foi possível atualizar o direcionamento de conta. A última configuração confirmada é exibida.", + "codexAuth.accountPickerLoadFailed": "Não foi possível carregar a configuração de direcionamento de conta.", + "codexAuth.accountPickerRefreshFailed": "Não foi possível atualizar esta configuração. O último valor confirmado ainda é exibido.", + "codexAuth.advancedSettings": "Configurações avançadas", + "codexAuth.advancedSettingsAria": "Mostrar ou ocultar configurações avançadas do Codex Auth", + "codexAuth.catalogRefreshPending": "A alteração foi salva, mas a atualização do catálogo de model do Codex está pendente. Execute ocx sync para tentar novamente.", + "anthropicPool.title": "Pool de contas do Claude (experimental)", + "anthropicPool.enabledDesc": "Sessões fixas (sticky sessions) e novas sessões preferem uso abaixo de {threshold}% ({window}).", + "anthropicPool.enabledNoProactiveDesc": "Sessões fixas (sticky sessions). A alternância proativa baseada em uso está desativada no limite 0, mas a seleção de novas sessões usa a janela {window}.", + "anthropicPool.disabledDesc": "Uma conta por sessão. Um erro 429 ainda faz failover para outra conta conectada - isso não pode ser desativado.", + "anthropicPool.experimentalWarning": "Experimental e não testado em produção. A Anthropic pode restringir contas que pareçam rotação automatizada de múltiplas contas. A mesma organização pode compartilhar cotas - agrupar essas contas não ajudará. Mantenha isto desativado, a menos que entenda o risco.", + "anthropicPool.needTwoAccounts": "Adicione pelo menos duas contas OAuth do Claude antes de habilitar o pool.", + "anthropicPool.threshold": "Limite de uso para novas sessões", + "anthropicPool.thresholdAria": "Limite de uso para novas sessões, porcentagem", + "anthropicPool.thresholdHelp": "0 desativa a seleção baseada em cota (apenas afinidade + conta ativa). O padrão é 80.", + "anthropicPool.thresholdInvalid": "Insira um número inteiro de 0 a 100", + "anthropicPool.loadFailed": "Não foi possível carregar as configurações do pool do Claude.", + "anthropicPool.saveFailed": "Não foi possível salvar as configurações do pool do Claude.", + "anthropicPool.on": "Atativado", + "anthropicPool.off": "Desativado", + "accountPool.strategy": "Estratégia de rotação", + "accountPool.strategyDesc": "Como o OpenCodex atribui uma conta a uma tarefa nova ou não vinculada.", + "accountPool.strategyResetFirst": "Redefinição mais próxima primeiro", + "accountPool.strategyHintResetFirst": "Prefere a próxima redefinição futura de 5 horas ou semanal entre as contas abaixo do limite de uso. Tarefas vinculadas seguem a política de afinidade configurada. Quotas de model independentes usam ordenação de cota.", + "accountPool.strategyQuota": "Cota", + "accountPool.strategyRoundRobin": "Round-robin", + "accountPool.strategyFillFirst": "Preenchimento primeiro", + "accountPool.strategyHintQuota": "A cota revincula uma tarefa existente no limite de uso somente quando `pool.cacheAffinity` estiver desativado (está ativado por padrão). Caso contrário, as tarefas vinculadas permanecem até que a conta não possa atender, passando então apenas para margem de cota real.", + "accountPool.strategyHintRoundRobin": "Round-robin alterna apenas tarefas sem vínculo ativo; o limite de uso não altera a rotação normal.", + "accountPool.strategyHintFillFirst": "Preenchimento primeiro usa o limite como ponto de esgotamento para tarefas não vinculadas; tarefas vinculadas saudáveis mantêm a afinidade.", + "accountPool.unboundDefinition": "Tarefa nova/não vinculada significa uma requisição sem vínculo de conta atual; uma tarefa visível existente pode se tornar não vinculada após um proxy ou redefinição de afinidade.", + "accountPool.stickyLimit": "Atribuições novas/não vinculadas antes da rotação", + "accountPool.stickyLimitAria": "Atribuições novas/não vinculadas antes da rotação", + "accountPool.stickyLimitInc": "Aumentar limite de fixação", + "accountPool.stickyLimitDec": "Diminuir limite de fixação", + "accountPool.stickyLimitHelp": "Mantenha a conta selecionada para este número de novas atribuições de tarefas/não vinculadas antes de avançar; o contador é incrementado quando a tarefa é vinculada, e não após o sucesso upstream.", + "accountPool.stickyLimitInvalid": "Insira um número inteiro de 1 a 100", + "accountPool.strategyLoadFailed": "Não foi possível carregar a estratégia de rotação.", + "accountPool.strategyUpdateFailed": "Não foi possível salvar a estratégia de rotação.", + "accountPool.switchAtThreshold": "alternar em {threshold}%", + "accountPool.drainAtThreshold": "esgotar em {threshold}%", + "accountPool.resetBelowThreshold": "redefinição mais próxima abaixo de {threshold}%", + "accountPool.thresholdNotUsed": "limite não utilizado", + "accountPool.proactiveSwitchingOff": "alternância proativa desativada", + "accountPool.quotaWindow": "Janela de cota", + "accountPool.quotaWindowDesc": "Qual barra de uso em cache controla a seleção de nova sessão baseada em cota, verificações de limite de preenchimento primeiro e substituições 429 elegíveis.", + "accountPool.quotaWindowFiveHour": "Barra de 5 horas", + "accountPool.quotaWindowWeekly": "Barra semanal", + "accountPool.quotaWindowMaxUtilization": "Barra superior", + "accountPool.quotaWindowHint": "A semanal ignora contas cuja barra de 5 horas esteja esgotada enquanto houver outra conta elegível, mas recorre a elas quando não houver. Empates semanais preferem menor uso em 5 horas; as barras semanais por conta só são conhecidas após a página de Providers consultá-las.", + "accountPool.quotaWindowInert": "Apenas a cota — ou preenchimento primeiro acima de um limite 0 — pontua em uma barra de uso, portanto esta configuração não altera nada para a estratégia de rotação atual.", + "accountPool.priority": "Ordem de seleção", + "accountPool.priorityAria": "Ordem de seleção para esta conta", + "accountPool.priorityHint": "Números mais altos são usados primeiro. O pool passa para um número menor apenas quando todas as contas acima dele estiverem esgotadas ou indisponíveis.", + "accountPool.priorityFirst": "Primeira", + "accountPool.priorityEarlier": "Mais cedo", + "accountPool.priorityNormal": "Normal", + "accountPool.priorityLater": "Mais tarde", + "accountPool.priorityLast": "Última", + "accountPool.priorityOption": "{name} ({value})", + "accountPool.priorityCustom": "Personalizado", + "accountPool.priorityUpdated": "Ordem de seleção atualizada para {email}", + "accountPool.priorityUpdateFailed": "Não foi possível salvar a ordem de seleção para {email}. O último valor confirmado é exibido.", + "accountPool.autoSwitchThreshold": "Limite personalizado da conta", + "accountPool.autoSwitchThresholdAria": "Limite de uso para {email}", + "accountPool.autoSwitchOverrideAria": "Substituir o limite global de uso para {email}", + "accountPool.autoSwitchHint": "Substitui o limite global para esta conta. O valor 0 desativa a troca proativa desta conta com base no uso.", + "accountPool.autoSwitchUpdated": "Limite de uso atualizado para {email}", + "accountPool.autoSwitchUpdateFailed": "Não foi possível salvar o limite de uso para {email}. O último valor confirmado é exibido.", + "codexAuth.switched": "{email} está selecionada para a próxima requisição", + "codexAuth.loadFailed": "Não foi possível carregar as configurações da conta Codex.", + "codexAuth.accountsRefreshFailed": "A última atualização das contas falhou. As contas abaixo são as últimas confirmadas.", + "codexAuth.switchFailed": "Não foi possível alternar a conta. Sua seleção anterior permanece inalterada.", + "codexAuth.removeConfirm": "Remover {id}?", + "codexAuth.removeFailed": "Não foi possível remover a conta. Nada foi alterado.", + "codexAuth.addTitle": "Adicionar Conta Codex", + "codexAuth.addIdLabel": "ID da conta (slug)", + "codexAuth.addIdPlaceholder": "codex-work, codex-alt, team...", + "codexAuth.resetCreditsAria": "{count} crédito(s) de redefinição", + "codexAuth.addJsonLabel": "conteúdo de auth.json", + "codexAuth.addHelp": "Copie de ~/.codex/auth.json de outra máquina ou use o export do codex-auth.", + "codexAuth.importBtn": "Importar", + "codexAuth.importInvalidJson": "JSON inválido", + "codexAuth.importMissingTokens": "Faltando access_token ou refresh_token no JSON", + "codexAuth.importMissingId": "O ID da conta é obrigatório", + "codexAuth.accountAdded": "Conta adicionada ao pool", + "codexAuth.addPickDesc": "Faça login com outra conta ChatGPT para adicioná-la ao pool.", + "codexAuth.oauthLogin": "Login OAuth", + "codexAuth.oauthDesc": "Abre o login do ChatGPT no navegador", + "codexAuth.deviceLogin": "Login com código de dispositivo", + "codexAuth.deviceDesc": "Para um proxy sem interface gráfica (headless) ou remoto: insira um código curto em outro dispositivo", + "codexAuth.importAuthJson": "Importar auth.json", + "codexAuth.importAuthJsonDesc": "De outra instalação do Codex ou de uma exportação do codex-auth", + "codexAuth.back": "Voltar", + "codexAuth.oauthAlreadyInProgress": "Login já em andamento. Conclua-o no seu navegador.", + "codexAuth.oauthWaiting": "Aguardando a conclusão do login do ChatGPT no seu navegador...", + "codexAuth.oauthSubmittingCode": "Enviando código...", + "codexAuth.oauthCodeSubmitted": "Código enviado — aguardando a conclusão do login...", + "codexAuth.oauthStatusRetrying": "Erro de rede ou proxy ao verificar o status de login — tentando novamente...", + "codexAuth.oauthCancelled": "O login foi cancelado.", + "codexAuth.loginFailed": "Falha no login", + "codexAuth.needsReauth": "Fazer login novamente", + "codexAuth.reauthenticate": "Autenticar novamente", + "codexAuth.tokenExpired": "Token expirado — autentique esta conta novamente", + "codexAuth.mainTokenExpired": "Token expirado — faça login novamente com o código de dispositivo abaixo ou pelo login do Codex App", + "codexAuth.mainReauthSucceeded": "Conectado", + "codexAuth.mainReauthFailed": "Falha ao refazer o login", + "codexAuth.mainReauthCancel": "Cancelar", + "codexAuth.mainReauthCode": "Código", + "codexAuth.mainReauthOpen": "Abrir", + "codexAuth.mainReauthPending": "Aguardando login...", + "codexAuth.mainReauthDevice": "Refazer login com código de dispositivo", + "codexAuth.emailCollision": "Esta conta coincide com seu login principal do Codex. Use uma conta diferente.", + "codexAuth.resetCreditsTitle": "Redefinir créditos", + "codexAuth.resetCreditsAvailable": "Você tem {count} crédito(s) de redefinição disponível(is).", + "codexAuth.resetCreditsDesc": "Cada crédito redefine seus limites de uso por hora e semana instantaneamente.", + "codexAuth.noResetCredits": "Você não tem nenhum crédito de redefinição.", + "codexAuth.earnCreditsHint": "Os créditos são obtidos mensalmente e pelo programa de indicação.", + "codexAuth.creditsExpireNote": "Os créditos expiram 30 dias após serem obtidos.", + "codexAuth.useOneCredit": "Usar 1 crédito", + "codexAuth.confirmResetTitle": "Usar crédito de redefinição?", + "codexAuth.confirmResetDesc": "Isso redefinirá instantaneamente seus limites de taxa atuais. Você tem {count} crédito(s) restante(s).", + "codexAuth.irreversible": "Esta ação não pode ser desfeita.", + "codexAuth.useCredit": "Usar crédito", + "codexAuth.redeeming": "Redefinindo...", + "codexAuth.resetSuccess": "Limites de taxa redefinidos! Restam {remaining} crédito(s).", + "codexAuth.resetSuccessGeneric": "Limites de taxa redefinidos!", + "codexAuth.resetAlreadyRedeemed": "Este crédito já foi resgatado. Créditos inalterados.", + "codexAuth.resetNothingToReset": "Nenhuma janela de limite de taxa precisa de redefinição no momento.", + "codexAuth.resetNoCredit": "Nenhum crédito de redefinição disponível.", + "codexAuth.resetError": "Falha ao resgatar o crédito de redefinição. Tente novamente.", + "codexAuth.fifoNote": "O crédito mais antigo é usado primeiro.", + "codexAuth.confirmWhichCredit": "O crédito de {date} será usado.", + "codexAuth.creditNext": "Próximo a ser usado", + "codexAuth.creditLabel": "Crédito #{n}", + "codexAuth.creditNextBadge": "PRÓXIMO", + "codexAuth.creditGranted": "Concedido em {date}", + "codexAuth.creditExpires": "Expira em {date} ({days}d restantes)", + "grokCoupon.badgeAria": "{count} cupom(ns) de redefinição do Grok", + "grokCoupon.badgeErrorAria": "Não foi possível ler os cupons de redefinição do Grok", + "grokCoupon.title": "Cupons de redefinição do Grok", + "grokCoupon.available": "Esta conta tem {count} cupom(ns) de redefinição.", + "grokCoupon.desc": "Um cupom reinicia a janela de uso do Grok desta conta imediatamente.", + "grokCoupon.none": "Esta conta não possui cupons de reinício.", + "grokCoupon.loadFailed": "Não foi possível ler os cupons de reinício para esta conta.", + "grokCoupon.loadFailedAuth": "Entre nesta conta xAI novamente para ler seus cupons.", + "grokCoupon.retry": "Tentar novamente", + "grokCoupon.couponLabel": "Cupom #{n}", + "grokCoupon.couponNext": "Próximo a ser usado", + "grokCoupon.couponNextBadge": "PRÓXIMO", + "grokCoupon.validFrom": "Válido a partir de {date}", + "grokCoupon.expires": "Expira em {date} ({days}d restantes)", + "grokCoupon.useOne": "Usar 1 cupom", + "grokCoupon.fifoNote": "O cupom mais próximo do vencimento é usado primeiro.", + "grokCoupon.confirmTitle": "Usar cupom de reinício?", + "grokCoupon.confirmDesc": "Isso reinicia a janela de uso do Grok desta conta agora. Você tem {count} cupom(ns).", + "grokCoupon.confirmWhich": "O cupom que expira em {date} será usado.", + "grokCoupon.irreversible": "Esta ação não pode ser desfeita.", + "grokCoupon.redeem": "Usar cupom", + "grokCoupon.redeeming": "Resgatando…", + "grokCoupon.redeemSuccess": "Cupom resgatado. Restam {count} cupom(ns).", + "grokCoupon.redeemReplayed": "Este resgate já foi concluído anteriormente. Nada foi consumido novamente.", + "grokCoupon.redeemFailed": "Falha no resgate. Verifique a lista de cupons antes de tentar novamente.", + "grokCoupon.authFailed": "Entre nesta conta xAI novamente para usar seus cupons.", + "grokCoupon.noAccount": "Nenhuma conta xAI está disponível para este resgate.", + "grokCoupon.noneAvailable": "Nenhum cupom de reinício disponível para resgate.", + "grokCoupon.identityMismatch": "Esse resgate pertence a outra conta. Feche esta caixa de diálogo e comece novamente.", + "grokCoupon.networkError": "Não foi possível contatar o proxy.", + "grokCoupon.capacity": "O diário de resgates está cheio no momento. Tente novamente em instantes.", + "grokCoupon.noOperationId": "Este navegador não pode gerar um ID de resgate, portanto o resgate está desativado aqui.", + "grokCoupon.unknownOutcome": "O resgate não respondeu a tempo, portanto seu resultado é desconhecido. Leia a conta novamente para ver se o cupom foi gasto.", + "grokCoupon.checkResult": "Ler conta novamente", + "grokCoupon.checking": "Lendo novamente…", + "grokCoupon.consumedElsewhere": "O cupom sumiu desta conta, então o resgate foi concluído.", + "grokCoupon.unresolved": "O cupom ainda está na lista. O resgate ainda pode estar em execução no upstream — leia novamente em um minuto antes de gastar outro cupom.", + "anthropicGrant.badgeAria": "Renovações dos limites de uso do Claude: {count}", + "anthropicGrant.badgeErrorAria": "Não foi possível consultar as renovações dos limites de uso do Claude", + "anthropicGrant.title": "Renovações dos limites de uso do Claude", + "anthropicGrant.available": "Esta conta tem {count} renovação(ões) dos limites de uso.", + "anthropicGrant.desc": "Uma renovação restaura imediatamente os limites de 5 horas e semanal do Claude para esta conta. O dia de renovação do limite semanal permanece o mesmo.", + "anthropicGrant.none": "Esta conta não tem renovações dos limites de uso.", + "anthropicGrant.ineligible": "Esta conta não se qualifica para renovações dos limites de uso no momento.", + "anthropicGrant.loadFailed": "Não foi possível consultar as renovações dos limites de uso desta conta.", + "anthropicGrant.loadFailedAuth": "Entre novamente nesta conta da Anthropic para consultar as renovações.", + "anthropicGrant.retry": "Tentar novamente", + "anthropicGrant.resetsLeft": "{left} de {total} restantes", + "anthropicGrant.validFrom": "Válido a partir de {date}", + "anthropicGrant.expires": "Expira em {date} ({days} dias restantes)", + "anthropicGrant.windowFiveHour": "5 horas: {percent}%", + "anthropicGrant.windowWeekly": "Semanal {percent}%", + "anthropicGrant.windowOverage": "Extra {percent}%", + "anthropicGrant.paused": "Pausado", + "anthropicGrant.notUsable": "Ainda não pode ser usado", + "anthropicGrant.requiresLimit": "Pode ser usado quando esta conta atingir um limite", + "anthropicGrant.useOne": "Usar 1 redefinição", + "anthropicGrant.confirmTitle": "Redefinir os limites de uso agora?", + "anthropicGrant.confirmDesc": "Isso restabelece os limites de uso do Claude nesta conta agora e consome uma redefinição.", + "anthropicGrant.confirmWhich": "Será usada: {label}", + "anthropicGrant.irreversible": "Esta ação não pode ser desfeita.", + "anthropicGrant.redeem": "Redefinir limites", + "anthropicGrant.redeeming": "Redefinindo…", + "anthropicGrant.resultReset": "Limites redefinidos. Restam {count} redefinição(ões).", + "anthropicGrant.resultAlreadyUsed": "Esta redefinição já foi usada.", + "anthropicGrant.resultNotLimited": "Esta conta não atingiu nenhum limite, então nenhuma redefinição foi usada.", + "anthropicGrant.resultCooldown": "As redefinições desta conta estão em período de espera. Nenhuma foi usada.", + "anthropicGrant.resultIneligible": "Esta conta não é mais elegível. Nenhuma redefinição foi usada.", + "anthropicGrant.resultUnavailable": "As redefinições estão indisponíveis no momento. Nenhuma foi usada.", + "anthropicGrant.resultRateLimited": "Muitas solicitações. Nenhuma redefinição foi usada; tente novamente em um minuto.", + "anthropicGrant.resultAuthError": "Entre novamente nesta conta da Anthropic. Nenhuma redefinição foi usada.", + "anthropicGrant.replayed": "Esta redefinição já foi concluída anteriormente. Nenhuma redefinição adicional foi usada.", + "anthropicGrant.notUsableNow": "Esta redefinição não pode ser usada no momento. Atualize os dados da conta.", + "anthropicGrant.inFlight": "Esta redefinição ainda está sendo processada. Aguarde um momento e atualize os dados da conta.", + "anthropicGrant.unresolvedPrior": "Uma tentativa anterior de usar esta redefinição ainda não foi confirmada. Tente novamente essa tentativa em vez de iniciar outra.", + "anthropicGrant.expired": "A tentativa anterior não pôde ser confirmada a tempo. Atualize os dados da conta antes de usar uma redefinição.", + "anthropicGrant.identityMismatch": "Essa redefinição pertence a outra conta. Feche esta janela e comece novamente.", + "anthropicGrant.sessionRequired": "Abra o painel usando o login da própria conta para usar as redefinições.", + "anthropicGrant.journalBusy": "O registro de redefinições está ocupado ou indisponível. Nada foi usado; tente novamente em instantes.", + "anthropicGrant.failed": "A solicitação de redefinição falhou. Verifique a conta antes de tentar novamente.", + "anthropicGrant.noOperationId": "Este navegador não consegue gerar um ID de solicitação, então as redefinições estão desativadas aqui.", + "anthropicGrant.unknownOutcome": "A redefinição não respondeu a tempo, então o resultado é desconhecido. Uma nova tentativa envia o mesmo ID de solicitação, portanto não pode iniciar uma segunda redefinição.", + "anthropicGrant.retrySame": "Tentar novamente com a mesma solicitação", + "anthropicGrant.checkResult": "Consultar a conta novamente", + "anthropicGrant.checking": "Consultando novamente…", + "api.title": "Acesso à API", + "api.subtitle": "Use chaves de API geradas para acessar o proxy do opencodex a partir de aplicativos externos. As chaves se autenticam via cabeçalho {authHeader}; consulte a tabela abaixo para ver o que cada endpoint aceita.", + "api.baseUrl": "URL Base", + "api.responsesEndpoint": "API de Responses", + "api.chatCompletionsEndpoint": "API de Chat Completions", + "api.messagesEndpoint": "API de Messages", + "api.modelsEndpoint": "API de Models", + "api.surface.on": "Ativado", + "api.surface.off": "Desativado", + "api.surface.source.fixed": "Sempre disponível", + "api.surface.source.explicit": "Configuração explícita", + "api.surface.source.inherited": "Herdado das configurações do Claude", + "api.surface.source.invalid": "Valor inválido — fechado", + "api.surface.messagesToggle": "Disponibilizar a API Messages", + "api.surface.messagesCloseNote": "Desativar a API Messages também desativa a integração com o Claude. Assim, versões mais antigas do opencodex também mantêm o endpoint fechado.", + "api.surface.openClaude": "Configurações do Claude", + "api.surface.toggleFailed": "Não foi possível salvar a configuração da API Messages.", + "api.surface.toggleUnavailable": "Esta versão do proxy não permite alterar a API Messages aqui. Use a página do Claude.", + "api.surface.closedNote": "As solicitações para este endpoint são recusadas com o código 403.", + "api.endpointNote": "Use a URL base com clientes compatíveis com OpenAI. Responses e Chat Completions são expostos em /v1.", + "api.endpointsTitle": "Endpoints", + "api.authTitle": "Autenticação", + "api.authLoopback": "O acesso loopback é específico por rota; clientes de áudio independentes exigem uma chave de dados do OpenCodex. Vínculos remotos exigem uma chave de dados ou OPENCODEX_API_AUTH_TOKEN.", + "api.authBaseUrlNote": "Configure os clientes com a URL base e escolha o endpoint específico do protocolo abaixo.", + "api.newKeyTitle": "Nova chave criada", + "api.newKeyNote": "Copie esta chave agora — ela não será exibida novamente.", + "api.copy": "Copiar", + "api.copied": "Copiado", + "api.dismiss": "Dispensar", + "api.generateTitle": "Gerar chave", + "api.keyNamePlaceholder": "Nome da chave (opcional)", + "api.generate": "Gerar", + "api.generating": "Criando…", + "api.activeKeys": "Chaves ativas ({count})", + "api.activeKeysLoading": "Chaves ativas", + "api.noKeys": "Nenhuma chave de API ainda. Gere uma acima.", + "api.workspace.sections": "Seções da API", + "api.section.keys": "Chaves", + "api.section.connect": "Conectar", + "api.section.endpoints": "Endpoints", + "api.section.models": "Models", + "api.section.examples": "Exemplos", + "api.section.plan": "Prévia do caminho", + "api.plan.title": "Prévia do caminho da solicitação", + "api.plan.description": "Mostra o caminho que uma solicitação para este modelo percorreria no proxy. A prévia não envia nada ao serviço upstream e não gera custos.", + "api.plan.modeNote": "Nativo descreve como uma solicitação é encaminhada. Não é um resultado de verificação.", + "api.plan.unavailable": "Esta versão do proxy não oferece prévias de caminhos.", + "api.plan.noModels": "Ainda não há modelos para pré-visualizar.", + "api.plan.model": "Modelo", + "api.plan.inbound": "API do cliente", + "api.plan.features": "Recursos da requisição", + "api.plan.preview": "Prévia", + "api.plan.previewing": "Gerando prévia…", + "api.plan.failed": "Não foi possível calcular a prévia.", + "api.plan.overallMode": "Entrega", + "api.plan.routeKind": "Rota", + "api.plan.reasons": "Motivos", + "api.plan.guaranteed": "Garantido por todos os candidatos", + "api.plan.partial": "Apenas alguns candidatos", + "api.plan.policyRevision": "Revisão da política", + "api.plan.noCandidates": "Nenhuma rota corresponde a este modelo.", + "api.plan.ineligible": "Recusado pela política atual", + "api.plan.requestPath": "Caminho da requisição", + "api.plan.responsePath": "Caminho da resposta", + "api.plan.fidelity": "Fidelidade", + "api.plan.none": "Nenhum", + "api.plan.noPath": "Nenhum caminho", + "api.plan.noFeatures": "Nenhum recurso da requisição selecionado.", + "api.plan.mode.native": "Nativo", + "api.plan.mode.translated": "Traduzido", + "api.plan.mode.legacyBridge": "Ponte legada", + "api.plan.mode.blocked": "Bloqueado", + "api.plan.fidelity.preserved": "Preservada", + "api.plan.fidelity.degraded": "Reduzida", + "api.plan.fidelity.unknown": "Desconhecida", + "api.plan.routeKind.direct": "Direto", + "api.plan.routeKind.combo": "Combo", + "api.plan.routeKind.policy": "Política de roteamento", + "api.plan.routeKind.unknown": "Modelo desconhecido", + "api.plan.disposition.passthrough": "Repassado sem alterações", + "api.plan.disposition.translated": "Traduzido", + "api.plan.disposition.degraded": "Degradado", + "api.plan.disposition.unsupported": "Descartado", + "api.plan.disposition.unknown": "Desconhecido", + "api.workspace.details": "Detalhes da chave de API", + "api.workspace.keyDetails": "Detalhes da chave", + "api.workspace.keyPrefix": "Prefixo da chave", + "api.workspace.deleteKey": "Excluir chave", + "api.workspace.deleteConfirm": "Tem certeza de que deseja excluir esta chave? Esta ação não pode ser desfeita.", + "api.workspace.usageExamples": "Exemplos de uso", + "api.copyUrlHint": "Clique para copiar a URL", + "api.urlCopied": "URL copiada", + "api.copyExampleHint": "Clique para copiar o exemplo", + "api.exampleCopied": "Exemplo copiado", + "api.colName": "Nome", + "api.colKey": "Chave", + "api.colCreated": "Criado em", + "api.confirm": "Confirmar", + "api.deleteAria": "Excluir chave de API", + "api.modelsTitle": "Catálogo de models externos", + "api.modelsCount": "{count} chamáveis", + "api.modelsLoading": "Carregando models…", + "api.modelsSearch": "Pesquisar models", + "api.modelsSubtitle": "Use estes IDs de model exatos com /v1/models e o protocolo de entrada escolhido.", + "api.modelsEmpty": "Nenhum model chamável externamente disponível no momento.", + "api.modelsNoMatch": "Nenhum model corresponde a “{query}”.", + "api.modelsLoadFailed": "Não foi possível carregar o catálogo de models externos.", + "api.colModel": "Model", + "api.colSource": "Origem", + "api.colProtocols": "Protocolos", + "api.sourceNative": "Pool do ChatGPT", + "api.sourceCombo": "Rota combinada", + "api.sourceCustom": "Personalizado", + "api.protocolResponses": "Responses", + "api.protocolChatCompletions": "Chat Completions", + "api.protocolMessages": "Messages", + "api.copyModelId": "Copiar ID", + "api.modelCopied": "Copiado", + "api.testModel": "Testar", + "api.testingModel": "Testando…", + "api.testSucceeded": "OK", + "api.testFailed": "Falhou", + "api.usageChatTitle": "Exemplo de Chat Completions", + "api.usageResponsesTitle": "Exemplo de Responses", + "api.usageMessagesTitle": "Exemplo de Messages", + "api.usageSampleInput": "Olá, mundo!", + "api.clientConfig.title": "Configuração do client", + "api.clientConfig.rowsLabel": "Conectar um client", + "api.clientConfig.details": "Detalhes", + "api.clientConfig.detailsAria": "Detalhes da configuração de {client}", + "api.clientConfig.copyAria": "Copiar configuração de {client}", + "api.clientConfig.downloadAria": "Baixar configuração de {client}", + "api.clientConfig.rowMeta": "{destination} · {count} model(s)", + "api.clientConfig.rowError": "Não foi possível gerar a configuração de {client}.", + "api.clientConfig.copiedAnnounceClient": "Configuração de {client} copiada para a área de transferência.", + "api.clientConfig.clientOpencode": "OpenCode", + "api.clientConfig.clientPi": "Pi", + "api.clientConfig.clientOmp": "OMP", + "api.clientConfig.clientHermes": "Hermes", + "api.clientConfig.clientOpenclaw": "OpenClaw", + "api.clientConfig.clientKimi": "Kimi Code", + "api.clientConfig.clientGajae": "gjc", + "api.clientConfig.clientDsh": "DeepSeek Harness (DSH)", + "api.clientConfig.clientMcode": "MiniMax Code", + "api.clientConfig.clientZcode": "ZCode", + "api.clientConfig.clientPrime": "Prime Agent", + "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", + "api.clientConfig.clientOmo": "omo", + "api.clientConfig.clientCline": "Cline CLI", + "api.clientConfig.clineBundle": "Este é um pacote de dois arquivos, não um arquivo de configurações do Cline. Mescle as configurações em providers.json e o catálogo em models.json adjacente. Use o alternador de integração para uma gravação com backup.", + "api.clientConfig.clineDownloaded": "Baixado {filename}. Nada foi alterado ainda; as configurações e o catálogo pertencem a dois arquivos separados do Cline.", + "api.clientConfig.copy": "Copiar configuração", + "api.clientConfig.download": "Baixar", + "api.clientConfig.loading": "Gerando configuração do client...", + "api.clientConfig.jsonLabel": "Configuração de {client}", + "api.clientConfig.destination": "Arquivo de destino", + "api.clientConfig.envHint": "Defina a key antes de iniciar", + "api.clientConfig.mergeWarning": "Mescle isso no arquivo de destino. Substituí-lo removeria seus outros providers e configurações do MCP.", + "api.clientConfig.modelCount": "{count} model(s) exportado(s)", + "api.clientConfig.missingLimits": "{count} de {total} model(s) não possuem limite de contexto especificado; o client aplica seus próprios padrões.", + "api.clientConfig.noKeyYet": "{env} ainda não possui uma key associada. Gere uma key acima antes de usar esta configuração fora do loopback.", + "api.clientConfig.loadFailed": "Não foi possível ler a lista de models, portanto nenhuma configuração de client foi produzida.", + "api.clientConfig.copiedAnnounce": "Configuração do client copiada para a área de transferência.", + "api.clientConfig.copyFailed": "Não foi possível copiar a configuração do client.", + "api.clientConfig.downloadedAnnounce": "Baixado {filename}. Nada foi alterado ainda — mescle-o em {destination} manualmente.", + "api.clientConfig.whereDisclosure": "Onde este arquivo fica", + "api.clientConfig.whereBody": "O destino acima é o caminho global. Um arquivo de configuração local do projeto no diretório de trabalho tem precedência sobre ele, e o client lê a key da environment variable nomeada na configuração — nunca deste arquivo.", + "api.keysLoadFailed": "Não foi possível carregar as API keys.", + "api.createFailed": "Não foi possível criar a API key.", + "api.deleteFailed": "Não foi possível excluir a API key.", + "api.auth.endpoint": "Endpoint", + "api.auth.required": "Obrigatório", + "api.auth.accepted": "Aceito", + "api.auth.rejected": "Não aceito", + "api.auth.testProtocol": "Testar {protocol}", + "api.auth.testNeedsFreshKey": "Gere uma key e mantenha seu valor de uso único na tela para executar um teste autenticado.", + "api.key.name": "Nome da key", + "api.key.rename": "Renomear", + "api.key.saveName": "Salvar nome", + "api.key.renaming": "Salvando…", + "api.key.renameFailed": "Não foi possível renomear a key. Seu rascunho foi mantido.", + "api.key.deleting": "Excluindo…", + "api.rotation.title": "Rotação de key", + "api.rotation.description": "Emita uma key de substituição enquanto a key atual permanece válida por um breve período de sobreposição.", + "api.rotation.start": "Iniciar rotação", + "api.rotation.starting": "Iniciando…", + "api.rotation.pending": "A rotação está pendente. Atualize e verifique o client antes de confirmar.", + "api.rotation.expires": "A sobreposição expira em:", + "api.rotation.secretOnce": "Key de substituição — exibida apenas uma vez. Copie-a antes de fechar este aviso.", + "api.rotation.commit": "Confirmar rotação", + "api.rotation.abort": "Cancelar rotação", + "api.rotation.failed": "A ação de rotação não foi concluída. Atualize antes de tentar novamente.", + "api.rotation.startFailed": "Não foi possível iniciar a rotação da key.", + "api.key.copyFailed": "Não foi possível copiar a key. Selecione-a e copie-a manualmente antes de fechar este painel.", + "api.attribution.title": "Uso atribuído", + "api.attribution.requests7d": "Requisições, últimos 7 dias", + "api.attribution.totalRequests": "Total de requisições atribuídas", + "api.attribution.totalRequestsAvailable": "Requisições no histórico disponível", + "api.attribution.sinceAvailable": "Atribuição disponível desde", + "api.attribution.lastUsed": "Último uso", + "api.attribution.since": "Atribuição disponível desde", + "api.attribution.neverUsed": "Não utilizado desde o início da atribuição", + "api.attribution.unavailable": "Uso indisponível", + "api.attribution.unavailableDetail": "Nenhum uso foi atribuído ainda. Requisições registradas antes do início da atribuição não podem ser atribuídas retroativamente.", + "api.attribution.ambiguous": "Duas keys compartilham este ID, portanto o uso não pode ser atribuído a apenas uma delas. Dê a cada key um ID exclusivo no arquivo de configuração.", + "api.attribution.railAmbiguous": "ID duplicado", + "claude.subtitle": "Use GPT, Gemini e outros models dentro do Claude Code.", + "claude.pageTitle": "Claude Code", + "claude.workspace.settings": "Configurações", + "claude.enabledLabel": "Conexão com o Claude", + "claude.enabledHint": "Quando desativado, o Claude Code não pode usar este proxy.", + "claude.authMode": "Modo de Autenticação", + "claude.authModeHint": "A assinatura requer uma conta Claude, o proxy funciona sem conta Anthropic", + "claude.authModeSubscription": "Assinatura (conta Claude)", + "claude.authModeProxy": "Proxy (sem necessidade de conta)", + "claude.authModeAuto": "Automático (detectar autenticação do Claude)", + "claude.effectiveMode.label": "Efetivo no próximo lançamento", + "claude.effectiveMode.manual": "Manual: {mode}", + "claude.effectiveMode.autoPresent": "Automático: assinatura — autenticação do Claude encontrada via {source}", + "claude.effectiveMode.autoAbsent": "Automático: modo proxy — nenhuma autenticação do Claude encontrada", + "claude.effectiveMode.autoUnknown": "Auto: assinatura — a autenticação não pôde ser verificada", + "claude.effectiveMode.admissionKey": "A chave de API deste proxy ainda é enviada.", + "claude.authSource.claude-json-oauth": "Conta Claude", + "claude.authSource.claude-credentials-file": "arquivo de credenciais", + "claude.authSource.macos-keychain": "Chaveiro do macOS", + "claude.authSource.exported-env": "variável de ambiente", + "claude.authSource.unknown": "uma credencial detectada", + "claude.systemEnv": "Conexão automática", + "claude.systemEnvDesc": "Quando ativado, executar o claude em qualquer terminal passa automaticamente pelo proxy.", + "claude.systemEnvUnsupported": "A conexão automática está disponível apenas no macOS. Neste sistema, inicie o Claude com {cmd}.", + "claude.systemEnvWarn": "⚠ Você deve fechar totalmente e reabrir o seu aplicativo de terminal para que isso tenha efeito. Não recomendado.", + "claude.fastMode": "Modo Rápido (OpenAI)", + "claude.fastModeDesc": "Controla o service_tier para modelos OpenAI. LIGADO = prioridade (mais rápido). DESLIGADO = padrão. Auto = pass-through (o cliente decide).", + "claude.fastAuto": "Auto", + "claude.fastOn": "LIGADO", + "claude.fastOff": "DESLIGADO", + "claude.autoContext": "Usar contexto grande automaticamente", + "claude.autoContextDesc": "Controla até onde a marcação de 1M vai. LIGADO: qualquer modelo cuja janela possa hospedar o limite de compactação recebe uma linha de contexto grande. DESLIGADO: apenas modelos 1M reais recebem uma.", + "claude.autoContextInert": "Inativo porque existe um valor de tamanho de contexto legado (maxContextTokens) no arquivo de configuração. Remova-o de lá para reativar.", + "claude.autoCompactWindow": "Ponto de resumo automático", + "claude.autoCompactDefault": "{value} (padrão)", + "claude.autoCompactWindowDesc": "Mensagens mais antigas são resumidas quando o chat atinge este ponto. Ele nunca excede o limite próprio de cada modelo, portanto modelos de 200k não são afetados.", + "claude.autoCompactWindowWarn": "Alterar isso pode quebrar os modelos GPT — se definido acima do limite real de um modelo, os chats apresentarão erro antes que o resumo seja acionado.", + "claude.injectAgents": "Registrar subagentes automaticamente", + "claude.injectAgentsDesc": "Registra os modelos escolhidos na aba Subagentes (além do modelo padrão atual) como agentes despacháveis do Claude Code (ocx-*). Aplica-se a partir da próxima sessão.", + "claude.webSearchSidecar": "Substituição do sidecar de busca na web", + "claude.webSearchSidecarHint": "Substitui o sidecar principal de busca na web para requisições do Claude Code.", + "claude.visionSidecar": "Substituição do sidecar de visão", + "claude.visionSidecarHint": "Substitui o sidecar principal de visão para requisições do Claude Code.", + "claude.useMainSetting": "Usar configuração principal", + "claude.sidecarModelPlaceholder": "Modelo da configuração principal", + "claude.quickstart": "Começar", + "claude.quickstartHint": "{cmd} abre o Claude Code através do proxy. Seu login no claude.ai permanece ativo.", + "claude.manualEnv": "Configuração manual (avançado)", + "claude.smallFastModel": "Modelo auxiliar de segundo plano", + "claude.smallFastModelHint": "O modelo que o Claude Code usa para trabalhos em segundo plano, como resumos de chat e detecção de tópicos. O alias do subagente haiku também o utiliza. Vazio = padrão do Claude (Haiku).", + "claude.smallFastModelAccurateHint": "O modelo que o Claude Code usa para trabalhos em segundo plano, tais como resumos de chat e detecção de tópicos. O alias do subagente haiku também o utiliza.", + "claude.smallFastModelUnsetOption": "Deixar o Claude Code escolher (modelo nativo)", + "claude.smallFastModelNativeWarning": "Quando não definido, o OpenCodex deixa as substituições do modelo auxiliar desfeitas. O Claude Code pode usar seu modelo Sonnet nativo, o que pode gerar cobranças do seu provedor nativo.", + "claude.slotUnset": "Usar o padrão do Claude", + "claude.modelMap": "Intercepção de modelos", + "claude.modelMapHint": "Intercepta requisições para um modelo específico e as redireciona para o que você escolher. Vazio por padrão — nada acontece até que você adicione uma regra.", + "claude.mapFrom": "Modelo original (ex: claude-sonnet-4-5)", + "claude.mapTo": "Trocar para (ex: gemini/gemini-3-pro)", + "claude.addMapping": "Adicionar regra", + "claude.removeMapping": "Remover regra", + "claude.aliases": "Modelos disponíveis", + "claude.aliasesHint": "Modelos que aparecem no menu /model do Claude Code.", + "claude.aliasProviderOther": "Outro", + "claude.loading": "Carregando…", + "claude.loadFail": "Falha ao carregar as configurações do Claude", + "claude.saved": "Salvo.", + "claude.saveFailed": "Falha ao salvar", + "claude.networkError": "Erro de rede — o proxy está rodando?", + "claude.toggleAria": "Alternar conexão do Claude", + "claude.none": "Nenhum", + "cws.loading": "Carregando combos…", + "cws.loadFailed": "Não foi possível carregar os combos.", + "cws.saveFailed": "Não foi possível salvar o combo.", + "cws.removeFailed": "Não foi possível remover o combo.", + "cws.saved": "Combo salvo.", + "cws.created": "Criado {model}.", + "cws.removed": "Removido combo/{id}.", + "cws.renamed": "Renomeado de {from} para {to}.", + "cws.add": "Adicionar combo", + "cws.addTitle": "Adicionar combo", + "cws.addSubtitle": "Crie um modelo virtual entre providers e escolha o nome exato do modelo que os clientes solicitarão.", + "cws.create": "Criar combo", + "cws.jev.create": "Criar JEV Auto", + "cws.jev.exists": "JEV Auto já existe.", + "cws.jev.setupHint": "Crie um Combo opcional e totalmente editável. O JEV escolhe um destino permitido e um nível de esforço de raciocínio para cada solicitação.", + "cws.jev.failOpen": "Destino de fallback em caso de falha", + "cws.jev.allowedEfforts": "O JEV pode selecionar", + "cws.jev.efforts": "Níveis de esforço de raciocínio: {efforts}", + "cws.jev.effortsUnknown": "Níveis de esforço de raciocínio não informados", + "cws.jev.effortsNone": "Nenhum nível de esforço de raciocínio explícito", + "cws.jev.stats.tab": "Estatísticas", + "cws.jev.stats.range": "Período das estatísticas do JEV", + "cws.jev.stats.refresh": "Atualizar", + "cws.jev.stats.loading": "Carregando estatísticas do JEV", + "cws.jev.stats.loadFailed": "Não foi possível carregar as estatísticas do JEV.", + "cws.jev.stats.historyIncomplete": "Alguns registros antigos do JEV foram omitidos, então estes totais podem estar incompletos.", + "cws.jev.stats.emptyTitle": "Ainda não há decisões do JEV", + "cws.jev.stats.emptyBody": "Execute este combo para registrar as escolhas e o uso de tokens dos modelos. As decisões tomadas antes da instalação do suporte a estatísticas não estão disponíveis.", + "cws.jev.stats.decisions": "Decisões", + "cws.jev.stats.appliedAndFailOpen": "{applied} aplicadas · {failOpen} com fail-open", + "cws.jev.stats.modelTokens": "Tokens dos modelos", + "cws.jev.stats.decisionTokens": "Tokens de decisão do JEV", + "cws.jev.stats.measuredAttempts": "{measured}/{total} tentativas medidas", + "cws.jev.stats.measuredDecisions": "{measured}/{total} decisões com uso de tokens registrado", + "cws.jev.stats.successful": "{count} solicitações bem-sucedidas", + "cws.jev.stats.fallbackOne": "{count} fallback de modelo", + "cws.jev.stats.fallbackMany": "{count} fallbacks de modelo", + "cws.jev.stats.averageLatency": "Latência média do JEV: {value}", + "cws.jev.stats.averageConfidence": "Confiança média: {value}", + "cws.jev.stats.gates": "Critérios de decisão do JEV", + "cws.jev.stats.model": "Modelo", + "cws.jev.stats.otherModels": "Outros modelos", + "cws.jev.stats.picks": "Escolhas", + "cws.jev.stats.efforts": "Níveis de esforço", + "cws.jev.stats.attempts": "Tentativas", + "cws.jev.stats.input": "Entrada", + "cws.jev.stats.output": "Saída", + "cws.jev.stats.reasoning": "Raciocínio", + "cws.jev.stats.cacheReadWrite": "Leitura/gravação de cache", + "cws.jev.stats.total": "Total", + "cws.jev.stats.noEffort": "nenhum", + "cws.jev.stats.measuredShort": "medido", + "cws.jev.stats.tokenFootnote": "Os tokens dos modelos vêm das tentativas reais nos destinos, incluindo novas tentativas e fallbacks. Os tokens de decisão do JEV são informados separadamente pelo serviço de decisão.", + "cws.railAria": "Lista de combos", + "cws.searchPlaceholder": "Buscar combos ou targets…", + "cws.noSearchResults": "Nenhum combo corresponde à sua busca.", + "cws.group.failover": "Failover", + "cws.group.roundRobin": "Round-robin", + "cws.group.other": "Outras estratégias", + "cws.targetCount": "{count} targets", + "cws.targetCountOne": "1 target", + "cws.overviewTitle": "Combos", + "cws.overviewBlurb": "Modelos virtuais que roteiam entre targets de provider/model com failover, round-robin, aleatório ponderado, menos usado ou redefinição de cota mais próxima.", + "cws.count.total": "Total", + "cws.count.failover": "Failover", + "cws.count.roundRobin": "Round-robin", + "cws.count.other": "Outros", + "cws.howTitle": "Como funciona", + "cws.howBody": "Peça ao Codex o nome de modelo público do combo. Sem um, o padrão é combo/. O OpenCodex seleciona um target e alterna apenas em falhas de upstream recuperáveis. Se nenhum target permanecer disponível, a requisição falha em vez de usar o provider padrão global.", + "cws.attentionTitle": "Requer atenção", + "cws.attention.empty": "Nenhum target configurado", + "cws.attention.few": "Apenas um target — o failover não tem para onde ir", + "cws.attention.catalogOmitted": "Ausente no catálogo de modelos — as capacidades dos membros estão incompletas ou incompatíveis (janela de contexto / metadados ausentes, ou interseção de modalidade vazia). O roteamento por alias ainda funciona", + "cws.attention.allTargetsExhausted": "Todos os targets habilitados estão sem cota", + "cws.emptyTitle": "Crie seu primeiro combo", + "cws.empty.createDesc": "Dê um nome a um modelo virtual e encadeie dois ou mais backends.", + "cws.backToAll": "Voltar para todos os combos", + "cws.allCombos": "Todos os combos", + "cws.copyModel": "Copiar id", + "cws.copied": "Copiado", + "cws.tabsLabel": "Seções de detalhes do combo", + "cws.tab.config": "Config", + "cws.tab.about": "Sobre", + "cws.strategy": "Estratégia", + "cws.strategy.failover": "Failover", + "cws.strategy.roundRobin": "Round-robin", + "cws.strategy.random": "Aleatório", + "cws.strategy.leastUsed": "Menos utilizado", + "cws.strategy.resetWindow": "Janela de reinício", + "cws.strategy.jev": "JEV", + "cws.strategy.failoverHint": "Tenta os alvos em ordem. Se o primeiro falhar com um erro recuperável (limite de taxa, indisponibilidade, barreira de assinatura), pula para o próximo.", + "cws.strategy.roundRobinHint": "Balanceia o tráfego deterministicamente por peso. Mantém cada alvo selecionado por um lote de requisições bem-sucedidas e, em seguida, avança.", + "cws.strategy.randomHint": "Sorteia um alvo elegível por requisição, com probabilidades proporcionais ao peso. Sem aderência (stickiness) entre as requisições.", + "cws.strategy.leastUsedHint": "Roteia cada requisição para o alvo elegível com o menor número de sucessos registrados. As contagens são reiniciadas com o proxy.", + "cws.strategy.resetWindowHint": "Prefere o alvo elegível cuja janela de cota é redefinida mais cedo. Retorna à ordem de configuração quando os dados de cota estiverem ausentes.", + "cws.strategy.jevHint": "Peça ao TypeSafe JEV para escolher um destino elegível e um nível de esforço compatível. Se a decisão não estiver disponível, use o primeiro destino elegível.", + "cws.field.id": "ID do combo", + "cws.field.idHint": "Os clientes solicitarão {model}", + "cws.field.idInternalHint": "ID interno do combo. Você pode alterá-lo após a criação.", + "cws.field.idHintEdit": "Renomear move o combo para um novo ID. Os clientes solicitam {model}.", + "cws.field.alias": "Nome público do model", + "cws.field.aliasPlaceholder": "deepseek-v4-flash ou vendor/model", + "cws.field.aliasHint": "Opcional. Use um nome puro sem prefixo, um prefixo personalizado como vendor/model ou deixe em branco para usar combo/.", + "cws.field.nativeAlias": "Alias nativo da OpenAI", + "cws.field.nativeAliasHint": "Permite que este combo assuma um ID de model nativo da OpenAI sem qualificação compatível. As rotas da OpenAI qualificadas por conta e provedor permanecem separadas.", + "cws.field.displayName": "Nome de exibição", + "cws.field.displayNameHint": "Rótulo do seletor para este combo. Obrigatório quando o alias nativo da OpenAI estiver ativado.", + "cws.field.stickyLimit": "Sucessos estáticos (sticky) antes da rotação", + "cws.field.stickyLimitHint": "Retém o alvo selecionado por este número de requisições bem-sucedidas antes que o seletor ponderado avance.", + "cws.field.defaultEffort": "Raciocínio padrão", + "cws.field.defaultEffortNone": "Nenhum (padrão do alvo)", + "cws.field.defaultEffortHint": "Usado apenas quando o cliente omite o esforço de raciocínio. As opções são a interseção dos esforços anunciados pelos alvos selecionados; alvos sem metadados de esforço no catálogo não oferecem nenhum.", + "cws.capability.imageInputUnavailable": "Indisponível até que todos os alvos selecionados suportem entrada de imagem.", + "cws.capability.imageInputHint": "Ativado por padrão quando todos os alvos suportam imagens. Desative para aceitar apenas texto.", + "cws.capability.imageInput": "Imagem / multimodal", + "cws.capability.adaptiveEffort": "Escada de raciocínio adaptativa", + "cws.capability.adaptiveEffortHint": "Desativado: um alvo sem controle de raciocínio ocultará o seletor de esforço para o combo inteiro. Ativado: esses alvos continuam utilizáveis e o seletor mantém os níveis que os alvos restantes compartilham.", + "cws.capabilities": "Capacidades", + "cws.field.defaultEffortUnsupported": "Este esforço não está na escada comum dos alvos — ele será ignorado ou ajustado no momento da requisição.", + "cws.field.defaultEffortUnsupportedOption": "fora da interseção", + "cws.targets": "Alvos", + "cws.targets.failoverHint": "A ordem importa — o primeiro é o primário.", + "cws.targets.roundRobinHint": "Os pesos controlam a seleção relativa determinística; a ordem desempata no anel de rotação.", + "cws.targets.randomHint": "Os pesos controlam as probabilidades de cada sorteio; a ordem não importa.", + "cws.targets.leastUsedHint": "A ordem apenas desempata entre alvos igualmente utilizados.", + "cws.targets.resetWindowHint": "A ordem se aplica quando os dados de cota estão ausentes ou empatados.", + "cws.targets.jevHint": "Apenas estes destinos podem ser selecionados. A ordem define o destino usado em caso de falha na decisão e o fallback posterior do Combo.", + "cws.target.provider": "Provedor", + "cws.target.model": "Model", + "cws.target.weight": "Peso", + "cws.target.pickProvider": "Selecionar provedor...", + "cws.target.pickProviderFirst": "Selecione um provedor primeiro...", + "cws.target.pickModel": "Selecionar model...", + "cws.target.noModels": "Nenhum model para este provedor", + "cws.target.modelPlaceholder": "id do model", + "cws.target.add": "Adicionar alvo", + "cws.target.drag": "Arraste para reordenar", + "cws.target.moveUp": "Mover para cima", + "cws.target.moveDown": "Mover para baixo", + "cws.quota.available": "Disponível", + "cws.quota.exhausted": "Cota esgotada", + "cws.quota.unknown": "Cota desconhecida", + "cws.quota.allExhausted": "Todos os targets ativados estão sem cota. Escolha outro target ou aguarde a recuperação da cota.", + "cws.aboutTitle": "Runtime", + "cws.aboutBody": "Targets com falha entram em cooldown brevemente, respeitando o cabeçalho Retry-After. Erros de contexto ou inválidos não são repassados. Cada target adapta o esforço às suas próprias capacidades; combinações esgotadas falham fechadas. Logs e Usage retêm as tentativas físicas ordenadas e o uso por tentativa.", + "cws.removeConfirmTitle": "Remover {model}?", + "cws.removeConfirmDesc": "Isso remove o modelo virtual da configuração e do catálogo do Codex. Nenhum provedor será excluído.", + "cws.unsavedTitle": "Alterações não salvas", + "cws.unsavedDesc": "Descartar edições desta combinação e continuar?", + "cws.keepEditing": "Continuar editando", + "cws.err.missingId": "O ID da combinação é obrigatório.", + "cws.err.invalidId": "O ID deve começar com uma letra ou número e usar apenas letras, números, pontos, sublinhados ou hífens (máx. 64).", + "cws.err.duplicateId": "Já existe uma combinação com este ID.", + "cws.err.invalidAlias": "O alias deve usar letras, números, pontos, sublinhados ou hífens, com no máximo um segmento \"/\".", + "cws.err.aliasReservedNamespace": "O alias não deve usar o namespace reservado \"combo/\".", + "cws.err.aliasNativeFamily": "Aliases simples na família nativa da OpenAI (gpt-*, o1-*, o3-*, o4-*, codex-*) não são permitidos.", + "cws.err.unsupportedNativeAlias": "O alias nativo deve ser um ID de modelo base da OpenAI atualmente suportado.", + "cws.err.missingNativeAliasDisplayName": "Um nome de exibição é obrigatório para aliases nativos.", + "cws.err.invalidDisplayName": "O nome de exibição deve ter no máximo 128 caracteres e não conter caracteres de controle.", + "cws.err.duplicateAlias": "Outra combinação já está usando este alias.", + "cws.err.noTargets": "Adicione pelo menos um target.", + "cws.err.incompleteTarget": "Cada target precisa de um provider e de um modelo.", + "cws.target.disabled": "{name} (desativado)", + "cws.err.reservedNamespace": "Um provider físico chamado combo deve ser renomeado antes de criar combinações.", + "cws.err.providerCollision": "O ID da combinação conflita com o nome de um provider configurado.", + "cws.err.unknownProvider": "Cada target deve usar um provider configurado.", + "cws.err.duplicateTarget": "O mesmo target de provider/modelo só pode aparecer uma vez.", + "cws.err.invalidStickyLimit": "Os sucessos sticky devem ser um número inteiro de 1 a 100.", + "cws.err.invalidWeight": "Cada peso round-robin deve ser um número inteiro de 1 a 10000.", + "cws.err.invalidReasoningEfforts": "Cada destino JEV deve permitir pelo menos um nível de esforço de raciocínio compatível e exclusivo.", + "cws.err.noEnabledTarget": "Pelo menos um target deve usar um provider ativado.", + "claude.tabsLabel": "Cliente Claude", + "claude.tabCode": "Código", + "claude.tabDesktop": "Desktop", + "claudeDesktop.title": "Claude Desktop", + "claudeDesktop.subtitle": "Roteie cada família de modelos do Claude através de um modelo disponível na porta {port}.", + "claudeDesktop.importJson": "Importar JSON", + "claudeDesktop.exportJson": "Exportar JSON", + "claudeDesktop.loading": "Carregando perfil do Claude Desktop…", + "claudeDesktop.loadFail": "Falha ao carregar o perfil do Claude Desktop.", + "claudeDesktop.retry": "Tentar novamente", + "claudeDesktop.saveFailed": "Falha ao salvar o perfil do Claude Desktop.", + "claudeDesktop.applyFailed": "O perfil foi salvo, mas não pôde ser aplicado.", + "claudeDesktop.updateFailed": "Falha na atualização do Claude Desktop.", + "claudeDesktop.savedApplied": "Perfil salvo e aplicado ao Claude Desktop.", + "claudeDesktop.appliedMarkerUnsaved": "Aplicado ao Claude Desktop, mas o marcador de aplicado não foi salvo — o estado de salvo vs. aplicado abaixo pode parecer desatualizado até que você aplique novamente.", + "claudeDesktop.savedAppliedAnnounce": "Perfil do Claude Desktop salvo e aplicado.", + "claudeDesktop.saved": "Perfil salvo.", + "claudeDesktop.savedAnnounce": "Perfil do Claude Desktop salvo.", + "claudeDesktop.exported": "Perfil exportado como JSON.", + "claudeDesktop.importExpected": "Esperado um perfil do Claude Desktop versão 1.", + "claudeDesktop.importReady": "JSON importado. Revise o rascunho, depois salve e aplique.", + "claudeDesktop.importedAnnounce": "Perfil JSON importado. Alterações não salvas prontas para revisão.", + "claudeDesktop.importInvalid": "O arquivo selecionado não é um perfil válido.", + "claudeDesktop.importFailed": "Falha na importação. {error}", + "claudeDesktop.moved": "{route} movido para {family}.", + "claudeDesktop.unsaved": "Alterações não salvas", + "claudeDesktop.upToDate": "O perfil está atualizado", + "claudeDesktop.saving": "Salvando...", + "claudeDesktop.applying": "Aplicando...", + "claudeDesktop.saveApply": "Salvar e aplicar", + "claudeDesktop.emptyTitle": "Nenhum model disponível", + "claudeDesktop.emptyHint": "Adicione ou habilite um provedor, depois volte para atribuir as rotas do Claude Desktop.", + "claudeDesktop.assignmentsLabel": "Atribuições de família de models do Claude", + "claudeDesktop.family.opus": "Opus", + "claudeDesktop.family.fable": "Fable", + "claudeDesktop.family.sonnet": "Sonnet", + "claudeDesktop.family.haiku": "Haiku", + "claudeDesktop.modelCountOne": "{count} model", + "claudeDesktop.modelCountMany": "{count} models", + "claudeDesktop.chooseDefault": "Escolher um padrão", + "claudeDesktop.temporaryDefault": "Padrão temporário", + "claudeDesktop.laneEmpty": "Solte um model aqui ou use o controle Mover.", + "claudeDesktop.laneNoMatch": "Nenhum model nesta família corresponde à sua pesquisa.", + "nav.grok": "Grok", + "grok.title": "Grok Build", + "grok.subtitle": "Models que o opencodex registrou na sua configuração do Grok.", + "grok.loading": "Carregando status do Grok...", + "grok.loadFail": "Não foi possível ler a configuração do Grok.", + "grok.notConfiguredTitle": "O Grok Build não está conectado", + "grok.notConfiguredHint": "Inicie ou reinicie o proxy com o Grok instalado e o opencodex grava um bloco gerenciado em:", + "grok.endpoint": "Endpoint", + "grok.colModel": "Model", + "grok.colAlias": "Alias do Grok", + "grok.colContext": "Contexto", + "grok.groupNative": "Models nativos", + "grok.groupRouted": "Models roteados", + "grok.enabledCount": "{on} de {total} registrados", + "grok.saved": "Seleção salva.", + "grok.savedApplied": "Seleção salva e gravada na sua configuração do Grok.", + "grok.saveFailed": "Não foi possível salvar a seleção do Grok.", + "grok.applyFailed": "Seleção salva, mas a configuração do Grok não pôde ser atualizada.", + "grok.applySkipped": "Seleção salva. A configuração do Grok não foi alterada.", + "grok.saveApply": "Salvar e aplicar", + "grok.saving": "Salvando...", + "grok.applying": "Aplicando...", + "grok.unsaved": "Alterações não salvas", + "grok.upToDate": "A seleção está atualizada", + "grok.toggleModel": "Registrar {id} no Grok", + "claudeDesktop.available": "Disponível", + "claudeDesktop.defaultBadge": "Padrão", + "claudeDesktop.supports1m": "1M", + "claudeDesktop.unavailable": "Indisponível", + "claudeDesktop.contextM": "contexto de {n}M", + "claudeDesktop.contextK": "contexto de {n}k", + "claudeDesktop.contextUnknown": "contexto desconhecido", + "claudeDesktop.alias": "Alias", + "claudeDesktop.useAsDefault": "Usar como padrão de {family}", + "claudeDesktop.moveTo": "Mover para", + "claudeDesktop.move": "Mover", + "claudeDesktop.status.applied": "Aplicado ao Desktop", + "claudeDesktop.status.stale": "Configuração desatualizada — reaplique", + "claudeDesktop.status.notApplied": "Não aplicado", + "claudeDesktop.status.notActiveProfile": "O Desktop está usando outro perfil — reaplique", + "claudeDesktop.status.disabled": "A integração com o Claude Desktop está desativada. Feche completamente e reabra o Desktop após ativá-la.", + "claudeDesktop.enableApply": "Ativar e aplicar", + "claudeDesktop.switchModeApply": "Trocar modo e aplicar", + "claudeDesktop.status.appliedFirstParty": "Primeira parte: aba Code roteada pelo proxy local", + "claudeDesktop.mode.legend": "Modo de conexão", + "claudeDesktop.mode.firstParty": "Primeira parte", + "claudeDesktop.mode.gateway": "Gateway (terceiros)", + "claudeDesktop.mode.defaultBadge": "padrão", + "claudeDesktop.mode.current": "atual", + "claudeDesktop.mode.firstPartyHint": "O Desktop permanece conectado ao claude.ai (chat, conectores e controle remoto). Apenas a aba Code, seus subagentes e a CLI do Claude Code passam pelo OpenCodex.", + "claudeDesktop.mode.firstPartyRisk": "Risco para a conta: no modo de primeira parte, o tráfego da sua assinatura Claude passa por um proxy local de interceptação. A Anthropic pode considerar isso uma violação dos termos e suspender a conta. Gateway é o modo padrão.", + "claudeDesktop.mode.gatewayHint": "O aplicativo inteiro passa a usar o OpenCodex como gateway. O chat é executado localmente; os recursos do claude.ai ficam indisponíveis.", + "claudeDesktop.mode.switchNote": "A troca substitui a configuração do outro modo. Depois, feche completamente o Desktop e abra-o novamente.", + "claudeDesktop.firstParty.proxyRunning": "Proxy local em 127.0.0.1:{port}", + "claudeDesktop.firstParty.proxyStopped": "O proxy local em 127.0.0.1:{port} não está em execução — reinicie o OpenCodex", + "claudeDesktop.firstParty.interceptDisabled": "O proxy de interceptação está desativado na configuração (claudeCode.intercept.enabled)", + "claudeDesktop.picker.title": "Seletor do Claude Desktop", + "claudeDesktop.picker.hint": "Exiba os modelos do OpenCodex no seletor da aba Code do Desktop por meio do proxy local dedicado.", + "claudeDesktop.picker.toggle": "Ativar o seletor do Claude Desktop", + "claudeDesktop.picker.state.active": "O seletor está ativo", + "claudeDesktop.picker.state.restart": "Encerre completamente o Claude Desktop e abra-o novamente para concluir a aplicação do perfil do seletor.", + "claudeDesktop.picker.state.trustPending": "Aguardando a etapa de confiança no Chaves", + "claudeDesktop.picker.state.trustDeclined": "A autorização no Chaves foi recusada", + "claudeDesktop.picker.state.proxyUnavailable": "O proxy do seletor não está em execução", + "claudeDesktop.picker.state.unsupported": "O modo de seletor não é compatível com este sistema operacional", + "claudeDesktop.picker.state.notFirstParty": "O seletor está disponível apenas no modo de primeira parte", + "claudeDesktop.picker.state.profileFailed": "Não foi possível aplicar o perfil do seletor", + "claudeDesktop.picker.models": "{count} modelos disponíveis no seletor", + "claudeDesktop.picker.offlineNote": "Enquanto o modo de seletor estiver ativo, o Claude Desktop acessa a rede pelo OpenCodex. Se o OpenCodex parar, o Desktop ficará sem conexão até que o OpenCodex seja reiniciado ou o modo de seletor seja desativado.", + "claudeDesktop.firstParty.bindings.title": "Associações de modelos da aba Code", + "claudeDesktop.firstParty.bindings.hint": "O Claude Desktop mantém os nomes da Anthropic no seletor da aba Code. Associe um modelo do seletor a um modelo do OpenCodex, e as solicitações feitas por essa opção do seletor serão atendidas pelo modelo associado. Apenas o tráfego do Claude Code que passa pelo proxy local (a aba Code do Desktop e a CLI claude) usa essas associações; ocx claude não é afetado. As associações entram em vigor na próxima solicitação — não é preciso encerrar e reabrir o aplicativo.", + "claudeDesktop.firstParty.bindings.empty": "Ainda não há associações — os modelos do seletor seguem suas rotas padrão.", + "claudeDesktop.firstParty.bindings.pickerLabel": "ID do modelo no seletor", + "claudeDesktop.firstParty.bindings.pickerPlaceholder": "claude-sonnet-4-6", + "claudeDesktop.firstParty.bindings.routeLabel": "Modelo do OpenCodex", + "claudeDesktop.firstParty.bindings.routePlaceholder": "Escolha um modelo", + "claudeDesktop.firstParty.bindings.add": "Adicionar associação", + "claudeDesktop.firstParty.bindings.remove": "Remover associação {id}", + "claudeDesktop.firstParty.bindings.saveFailed": "Não foi possível salvar as associações de modelos", + "claudeDesktop.health.lastRequest": "Última requisição", + "claudeDesktop.health.stats": "{count} req / {errors} err", + "claudeDesktop.effort.supported": "effort", + "claudeDesktop.effort.displayOnly": "effort (somente exibição)", + "lab.title": "Laboratório de Compatibilidade", + "lab.subtitle": "Matriz de veredito de compatibilidade somente leitura a partir de evidências de projeção do laboratório.", + "lab.loadFailed": "Não foi possível carregar os dados do laboratório de compatibilidade", + "lab.projectionUnavailable": "A projeção do laboratório não está disponível. Execute testes de conformidade ou sondas ativas primeiro.", + "lab.projectionIncompatible": "O esquema da projeção do laboratório é incompatível. Recompile a projeção.", + "lab.statusTitle": "Status da projeção", + "lab.matrixTitle": "Matriz de compatibilidade", + "lab.verdictsTitle": "Registros de veredito", + "lab.filter.layer": "Camada de evidência", + "lab.filter.verdict": "Veredito", + "lab.filter.subject": "ID do assunto", + "lab.filter.all": "Todos", + "lab.col.subject": "Assunto", + "lab.col.layer": "Camada", + "lab.col.suite": "Suíte", + "lab.col.verdict": "Veredito", + "lab.col.asOf": "Em", + "lab.col.protocol": "Conformidade de protocolo", + "lab.col.live": "Compatibilidade de rota ativa", + "lab.col.task": "Eficácia da tarefa", + "lab.empty": "Ainda não há vereditos de compatibilidade na projeção.", + "lab.subjectKind": "Tipo", + "lab.observationCount": "Observações", + "lab.eventCount": "Eventos", + "lab.verdictCount": "Vereditos", + "lab.subjectCount": "Assuntos", + "lab.builtAt": "Compilado", + "lab.loading": "Carregando evidências de compatibilidade…", + "lab.loadMore": "Carregar mais", + "lab.detailTitle": "Detalhes do veredito", + "lab.detailClose": "Fechar", + "lab.detailSubject": "Assunto", + "lab.detailObservations": "Observações", + "lab.detailEvents": "Eventos contribuintes", + "lab.detailArtifacts": "Metadados do artefato", + "lab.production.title": "Tráfego de produção observado", + "lab.production.notVerification": "Não é uma verificação de Lab", + "lab.production.attempts": "Tentativas", + "lab.production.successes": "Sucessos", + "lab.production.routeErrors": "Erros de rota", + "lab.production.lastObserved": "Última observação", + "lab.detailLoadFailed": "Não foi possível carregar os detalhes do veredito", + "lab.refresh": "Atualizar", + "lab.verdict.UNKNOWN": "Desconhecido", + "lab.verdict.CLAIMED": "Declarado", + "lab.verdict.PROBED": "Testado", + "lab.verdict.VERIFIED": "Verificado", + "lab.verdict.DEGRADED": "Degradado", + "lab.verdict.BLOCKED": "Bloqueado", + "lab.verdict.UNSUPPORTED": "Não suportado", + "lab.layer.protocol_conformance": "Conformidade de protocolo", + "lab.layer.live_route_compatibility": "Compatibilidade de rota ativa", + "lab.layer.task_effectiveness": "Eficácia da tarefa", + "models.newPolicyGlobal": "Novos models iniciam desativados", + "models.fastProvider": "Modo rápido", + "models.newPolicy_inherit": "Herdar", + "models.newBadge": "NOVO", + "models.aliases": "Aliases", + "models.aliasesTable": "Tabela de aliases", + "models.aliasPrompt": "Alias do provider (deixe em branco para limpar)", + "models.modelAliasPrompt": "Alias do model (deixe em branco para limpar)", + "models.aliasSaved": "Alias salvo", + "models.aliasConflict": "Esse alias conflita com um nome existente", + "models.editProviderAlias": "Editar alias do provider", + "models.editModelAlias": "Editar alias do model", + "models.useDefaultAliases": "Usar aliases padrão", + "models.useDefaultAliasesGlobal": "Usar aliases padrão globalmente", + "models.aliasAuto": "automático", + "models.aliasUser": "usuário", + "models.aliasStale": "desatualizado", + "connection.discovering": "Descobrindo destinos locais e compartilhados…", + "connection.machineUnavailable": "O plano da máquina local está indisponível. Requisições compartilhadas não foram redirecionadas localmente.", + "connection.disconnect": "Desconectar do hub", + "connection.disconnectConfirm": "Desconectar esta máquina do hub e reiniciá-la no modo autônomo?", + "connection.pairing.hub": "Hub", + "connection.pairing.getCode": "Execute este comando no hub para este navegador:", + "connection.pairing.askOperator": "Se outra pessoa opera o hub, envie este comando a ela e peça um código de pareamento único.", + "connection.pairing.notApiKey": "Cole um código de pareamento único aqui. Chaves da Data API e tokens de admin não pertencem a este campo.", + "connection.pairing.networkError": "Não foi possível contatar o hub. Verifique a conexão e tente novamente; seu código ainda está aqui.", + "connection.pairing.requestError": "O hub não pôde concluir a solicitação de pareamento. Verifique o status dele e tente novamente.", + "connection.pairing.responseError": "O hub não retornou uma sessão de browser válida. Atualize o hub ou peça ao operador dele, depois tente novamente.", + "dash.authRequired": "Autenticação de browser é necessária para visualizar este dashboard.", + "dash.permissionDenied": "Este browser não tem permissão para ler o dashboard. Verifique as configurações de acesso com o operador do servidor.", + "dash.dataUnavailable": "Não foi possível carregar os dados do dashboard. Verifique a conexão e tente novamente.", + "dash.staleData": "Mostrando os últimos dados recebidos; eles podem estar desatualizados.", + "connection.pairing.title": "Conectar este dashboard ao hub", + "connection.pairing.body": "Cole o código de pareamento único criado no hub.", + "connection.pairing.relayWarning": "Este código é trocado por meio do relay fixo do hub. O relay não pode ser redirecionado para outro host.", + "connection.pairing.code": "Código de pareamento único", + "connection.pairing.submit": "Conectar", + "connection.pairing.submitting": "Conectando…", + "connection.pairing.error": "O código de pareamento foi recusado ou expirou. O código foi mantido no lugar para que você possa verificá-lo.", + "connection.machine.title": "Esta máquina", + "connection.machine.shimHealthy": "O shim do Codex está saudável.", + "connection.machine.shimNeedsAttention": "O shim do Codex precisa de atenção.", + "connection.machine.repairShim": "Reparar shim", + "connection.machine.removeShim": "Remover shim", + "connection.clients.title": "Clientes conectados", + "connection.clients.none": "Nenhum status de cliente disponível", + "connection.clients.sync": "Sincronizar agora", + "connection.clients.syncing": "Sincronizando…", + "connection.sessionLogout": "Encerrar sessão remota", + "connection.sessionLoggingOut": "Encerrando sessão remota…", + "connection.sessionLogoutFailed": "Não foi possível encerrar a sessão remota. A sessão atual foi mantida.", + "usage.source.connected": "Origem: uso do hub", + "usage.source.local": "Origem: usage.jsonl local", + "usage.scope.label": "Escopo de uso", + "usage.scope.machine": "Esta máquina", + "usage.scope.hub": "Em todo o hub", + "usage.hubOffline": "O uso do hub está indisponível. O uso local não foi substituído.", + "models.displayNameSavedRefreshFailed": "A alteração foi salva, mas a lista de models não pôde ser atualizada. Tente novamente para atualizá-la.", + "models.displayNameOutcomeUnknown": "A solicitação não foi concluída. A alteração pode ter sido salva. Tente novamente para verificar o nome atual antes de fazer outra alteração.", + "models.displayNameCurrentUnavailable": "Nome atual indisponível até a atualização", + "models.displayNameReloaded": "Lista de models atualizada", + "models.displayNameAction": "Nome", + "models.displayNameActionLabel": "Editar nome amigável para {model}", + "models.displayNameTitle": "Nome amigável", + "models.displayNameModelId": "Model ID", + "models.displayNameCurrent": "Nome atual", + "models.displayNameSourceOperator": "Seu nome", + "models.displayNameSourceProvider": "Nome do provedor", + "models.displayNameSourceFallback": "Fallback de Model ID", + "models.displayNameField": "Nome amigável", + "models.displayNamePlaceholder": "ex: Grok 4.6", + "models.displayNameHelp": "Altera apenas a apresentação. O roteamento continua sendo {model}.", + "models.displayNameReset": "Redefinir nome", + "models.displayNameSaved": "Nome de exibição salvo", + "models.displayNameResetDone": "Nome de exibição redefinido", + "models.displayNameSaveFailed": "Falha ao salvar o nome de exibição", + "models.displayNameRequired": "Insira um nome amigável ou use Redefinir nome.", + "models.displayNameTooLong": "O nome amigável deve ter 128 caracteres ou menos.", + "models.displayNameNoSlash": "O nome amigável não pode conter /.", + "models.displayNameNoControl": "O nome amigável não pode conter caracteres de controle.", + "pricing.override.action": "Preço", + "pricing.override.actionLabel": "Editar preço para {model}", + "pricing.override.badge": "Preço manual", + "pricing.override.title": "Preço do model", + "pricing.override.modelId": "Model ID", + "pricing.override.help": "USD por 1M tokens. Insira as taxas de entrada e saída; taxas de cache em branco usam 0. Todas as quatro taxas definidas como 0 significam gratuito.", + "pricing.override.input": "Entrada", + "pricing.override.output": "Saída", + "pricing.override.cacheRead": "Leitura de cache", + "pricing.override.cacheWrite": "Escrita de cache", + "pricing.override.loading": "Carregando preço salvo...", + "pricing.override.loadFailed": "Não foi possível carregar o preço salvo. Recarregue para tentar novamente.", + "pricing.override.outcomeUnknown": "A solicitação não foi concluída de forma confiável. O preço pode ter mudado. Recarregue o preço salvo antes de editar novamente.", + "pricing.override.recoveryFailed": "Não foi possível recuperar o preço salvo. A edição permanece bloqueada; recarregue para tentar novamente.", + "pricing.override.recovered": "Último preço salvo carregado. A solicitação anterior ou outro cliente ainda pode alterá-lo.", + "pricing.override.refreshFailed": "O preço foi salvo, mas a lista de models não pôde ser atualizada. Tente atualizar a lista novamente.", + "pricing.override.invalid": "Insira as taxas de entrada e saída. Cada taxa deve ser um número finito de 0 a 1.000.000.", + "pricing.override.reset": "Redefinir para o automático", + "pricing.override.save": "Salvar", + "pricing.override.saving": "Salvando...", + "pricing.override.reload": "Recarregar preço", + "pricing.override.refresh": "Atualizar lista", + "pricing.override.cancel": "Cancelar", + "pricing.override.close": "Fechar", + "usage.range.custom": "Período personalizado", + "usage.range.start": "Início (hora local)", + "usage.range.end": "Fim (hora local)", + "usage.range.apply": "Aplicar", + "usage.range.clear": "Limpar", + "usage.range.help": "Hora local. Inclui todo o minuto final.", + "usage.range.required": "Insira uma data e hora de início e de fim.", + "usage.range.invalid": "Insira datas e horas locais válidas, em ou após 1970-01-01 UTC.", + "usage.range.reversed": "O fim deve ser igual ou posterior ao início.", + "usage.range.applied": "Intervalo selecionado: {start} – {end} (ambos inclusivos).", + "models.pickerOrder.editorHint": "Reordene os models roteados e salve seu rascunho. As linhas em destaque são fixas; os models nativos não são exibidos.", + "models.pickerOrder.nativeLocked": "Esta ordem salva inclui models nativos. Aplique uma predefinição roteada ou Padrão antes de editar Personalizado.", + "models.pickerOrder.unknownChosen": "As escolhas em destaque são desconhecidas. Recarregue antes de editar.", + "models.pickerOrder.changed": "As configurações do seletor foram alteradas. Seu rascunho foi mantido; recarregue para descartá-lo e usar as configurações atuais.", + "models.pickerOrder.savedReload": "Ordem salva. Recarregue as configurações atuais antes de editar novamente.", + "models.pickerOrder.requestFailed": "A solicitação falhou. Seu rascunho foi mantido; tente novamente ou recarregue.", + "models.pickerOrder.empty": "Nenhum model roteado disponível.", + "models.pickerOrder.dragModel": "Arrastar {model}", + "models.pickerOrder.featured": "Destaque", + "models.pickerOrder.upModel": "Mover {model} para cima", + "models.pickerOrder.downModel": "Mover {model} para baixo", + "models.pickerOrder.position": "{model}: posição {position} de {total}", + "models.pickerOrder.saveDraft": "Salvar rascunho", + "models.pickerOrder.reloadDraft": "Recarregar e descartar rascunho", + "models.pickerOrder.catalogRequired": "As identidades do model estão ausentes ou ambíguas. Recarregue a página de Models para atualizar o catálogo antes de editar o Custom.", + "nav.remote": "Workspace Remoto", + "nav.remoteWorkspace": "Espaço de trabalho remoto", + "link.title": "Conexão remota", + "link.subtitle": "Conecte-se a outro computador com OpenCodex via SSH.", + "link.switch": "Conexão remota", + "link.switchOffHint": "Ative a vinculação para escolher a função deste computador.", + "link.role.title": "Escolha a função deste computador", + "link.role.hint": "Como principal, este computador compartilha seus provedores com os computadores secundários. Como secundário, este computador se conecta a um principal quando executado de forma independente.", + "link.role.home": "Principal", + "link.role.homeHint": "Gerencie os computadores secundários neste painel.", + "link.role.child": "Secundário", + "link.role.childHint": "Use a configuração do OpenCodex de outro computador.", + "link.continue": "Continuar", + "link.sessionRequired": "Entre na sessão do painel local para gerenciar as vinculações.", + "link.workspaceUnavailable": "O Espaço de Trabalho Remoto não está disponível nesta instalação.", + "link.loading": "Carregando…", + "link.loadFailed": "Não foi possível carregar o status da vinculação remota.", + "link.refresh": "Atualizar", + "link.children": "Computadores secundários", + "link.addChild": "Adicionar computador secundário", + "link.sheetTitle": "Adicionar um computador secundário", + "link.candidates": "Hosts SSH", + "link.noCandidates": "Nenhum host SSH disponível foi encontrado.", + "link.alias": "Alias do host SSH", + "link.aliasPlaceholder": "Digite um alias da sua configuração SSH", + "link.probe": "Testar conexão", + "link.probing": "Testando conexão…", + "link.hostFingerprint": "Impressão digital da chave do host", + "link.confirmFingerprint": "Reconheço esta chave do host", + "link.confirming": "Confirmando…", + "link.confirm": "Confirmar host", + "link.ocxVersion": "Versão do OpenCodex {version}", + "link.apply": "Conectar nó filho", + "link.applying": "Conectando…", + "link.retry": "Tentar novamente", + "link.disconnect": "Desconectar", + "link.disconnectConfirm": "Desconectar {alias}? A chave de conexão será revogada.", + "link.close": "Fechar", + "link.cancel": "Cancelar", + "remoteLink.childDisabled": "Conexões de nós filhos só podem ser iniciadas a partir de uma instância independente.", + "remoteLink.findHome.title": "Encontrar Home", + "remoteLink.findHome.body": "Escolha o computador Home ao qual este nó filho será conectado.", + "remoteLink.findHome.action": "Encontrar Home", + "remoteLink.findHome.connect": "Conectar como nó filho", + "remoteLink.findHome.empty": "Ainda não há conexão com um Home.", + "remoteLink.joining": "Conectando ao Home…", + "remoteLink.restart.title": "Este computador será reiniciado para se conectar como nó filho.", + "remoteLink.restart.body": "O painel se reconectará automaticamente quando o nó filho estiver pronto.", + "remoteLink.restart.waiting": "Aguardando este computador se reconectar como nó filho…", + "remoteLink.error.standalone_required": "Conexões de nós filhos só podem ser iniciadas a partir de uma instância independente.", + "remoteLink.error.join_tunnel_failed": "Não foi possível iniciar o túnel para o Home. Verifique o acesso SSH e tente novamente.", + "remoteLink.error.admission_failed": "O Home não aceitou a nova conexão. Verifique se ele está em execução e tente novamente.", + "remoteLink.error.join_issue_failed": "O Home não conseguiu emitir uma chave de conexão. Verifique se o OpenCodex está em execução no Home e tente novamente.", + "remoteLink.error.join_in_progress": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.join_port_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.join_rollback_failed": "Não foi possível concluir a vinculação nem remover o vínculo no computador principal. Tente fazer a limpeza novamente ou execute ocx link revoke no computador principal.", + "remoteLink.error.join_restart_failed": "O vínculo está pronto. Reinicie o OpenCodex neste computador para concluir a conexão como computador secundário.", + "remoteLink.error.join_connect_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "link.noChildren": "Nenhum computador secundário está conectado.", + "remoteLink.status.connecting": "Conectando", + "remoteLink.status.connected": "Conectado", + "remoteLink.status.reconnecting": "Reconectando", + "remoteLink.status.failed": "A conexão requer atenção", + "remoteLink.status.idle": "Inativo", + "remoteLink.role.standalone": "Independente", + "remoteLink.role.home": "Principal", + "remoteLink.role.child": "Secundário", + "remoteLink.direction.hub": "Iniciada pelo hub", + "remoteLink.direction.client": "Iniciada pelo cliente", + "remoteLink.error.admission_timeout": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.compensation_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.fingerprint_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.forbidden": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.host_confirmation_expired": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.host_fingerprint_mismatch": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.host_not_confirmed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.invalid_alias": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.invalid_body": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.invalid_link_id": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.key_issue_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.key_revoke_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.link_apply_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.link_exists": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.link_not_found": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.link_remove_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.link_unavailable": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.listener_unavailable": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.probe_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.remote_connect_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.remote_disconnect_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.remote_port_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.tailscale_session_refused": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.version_probe_failed": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.error.generic": "Não foi possível concluir a solicitação de conexão remota.", + "remoteLink.reason.auth": "Falha na autenticação.", + "remoteLink.reason.hostkey": "Não foi possível verificar a chave do host.", + "remoteLink.reason.forward": "Falha no encaminhamento de porta.", + "remoteLink.reason.timeout": "O tempo limite da conexão foi excedido.", + "remoteLink.reason.bind": "Não foi possível vincular à porta local.", + "remoteLink.reason.persist": "Não foi possível salvar o estado da conexão.", + "remoteLink.reason.compensation_failed": "Falha na limpeza após estabelecer a conexão.", + "remoteLink.reason.staleTunnel": "Um túnel obsoleto ainda pode estar ocupando a porta.", + "remoteLink.reason.generic": "Motivo:", + "remoteLink.workspaceMoved.title": "O Espaço de Trabalho Remoto agora tem uma página própria", + "remoteLink.workspaceMoved.body": "Use a página separada do Espaço de Trabalho Remoto.", + "remoteLink.workspaceMoved.open": "Abrir espaço de trabalho remoto", + "remoteLink.forceRemove.title": "Esta máquina não conseguiu se conectar a {alias}", + "remoteLink.forceRemove.body": "Remover o vínculo apenas nesta máquina? Depois, execute {cmd} em {alias} por conta própria.", + "remoteLink.forceRemove.confirm": "Remover apenas nesta máquina", + "remote.title": "Workspace Remoto", + "remote.subtitle": "Execute Codex, Claude Code ou Pi a partir deste Hub enquanto arquivos, comandos, testes e builds permanecem no computador selecionado.", + "remote.loading": "Carregando Workspace Remoto...", + "remote.loadFailed": "Não foi possível carregar o Workspace Remoto.", + "remote.hubRequired": "Use o modo Hub e inicie o Hub com OCX_REMOTE_WORKSPACE_ENABLED=1 para habilitar o Workspace Remoto.", + "remote.refresh": "Atualizar", + "remote.addComputer": "Adicionar um computador", + "remote.addComputerHint": "Aprove uma ou mais pastas localmente e, em seguida, mantenha o executor exclusivo do OCX conectado a este Hub.", + "remote.createPairing": "Criar código de pareamento", + "remote.pairingCode": "Código de pareamento de uso único", + "remote.pairingExpires": "Expira às {time}", + "remote.pairingCommand": "Execute no computador que você está adicionando", + "remote.pairingCommandPosix": "Terminal Linux / macOS", + "remote.pairingCommandWindows": "Windows PowerShell", + "remote.copyCommand": "Copiar comando", + "remote.copied": "Copiado", + "remote.devices": "Computadores", + "remote.noDevices": "Nenhum computador pareado ainda.", + "remote.online": "Online", + "remote.offline": "Offline", + "remote.revoke": "Revogar computador", + "remote.revokeConfirm": "Revogar {name}? As sessões ativas neste computador serão interrompidas.", + "remote.newSession": "Nova sessão remota", + "remote.device": "Computador", + "remote.folder": "Pasta do workspace", + "remote.runtime": "Agente de codificação", + "remote.access": "Acesso ao workspace", + "remote.access.readOnly": "Somente leitura", + "remote.access.workspace": "Editar arquivos e executar comandos", + "remote.access.workspaceFilesOnly": "Apenas editar arquivos", + "remote.unavailable": "Indisponível", + "remote.capability.full": "Arquivos + comandos em sandbox", + "remote.capability.files": "Apenas ferramentas de arquivo", + "remote.runsOnHub": "O model e o login permanecem neste Hub", + "remote.runsReadOnly": "Os arquivos só podem ser lidos neste computador", + "remote.runsFilesCommands": "Arquivos, builds e comandos são executados aqui", + "remote.runsFilesOnly": "As ferramentas de arquivo são executadas aqui; sandbox de comandos indisponível", + "remote.execUnavailable": "Este computador pode editar arquivos, mas builds e comandos de terminal estão desativados porque um sandbox de SO compatível não está disponível.", + "remote.notResumable": "Esta sessão parou antes que o agente de codificação criasse um histórico durável. Inicie uma nova sessão remota.", + "remote.startSession": "Iniciar sessão remota", + "remote.sessionStarted": "A sessão remota está pronta.", + "remote.sessions": "Sessões", + "remote.noSessions": "Escolha um computador online, uma pasta e um agente de codificação para começar.", + "remote.events": "Atividade da sessão remota", + "remote.noEvents": "Nenhuma atividade ainda.", + "remote.prompt": "Mensagem", + "remote.promptPlaceholder": "Pedir para o agente do Hub trabalhar dentro da pasta remota selecionada...", + "remote.send": "Enviar", + "remote.stop": "Encerrar sessão", + "remote.requestFailed": "A requisição do Remote Workspace falhou.", + "remote.submissionUnknown": "O status do envio é desconhecido. Verifique a sessão antes de enviar novamente.", + "remote.status.starting": "Iniciando", + "remote.status.ready": "Pronto", + "remote.status.running": "Em execução", + "remote.status.waiting": "Executor offline", + "remote.status.failed": "Falhou", + "remote.status.stopped": "Parado", + "remote.event.status": "Status", + "remote.event.tool": "Ferramenta remota", + "remote.event.error": "Erro", + "quotaSummary.aria": "Resumo das cotas do provedor", + "quotaSummary.updated": "Atualizado em {time}", + "quotaSummary.dataAt": "Dados de {time}", + "quotaSummary.observedAt": "Observado em {time}", + "quotaSummary.warn": "70% ou mais usados", + "quotaSummary.critical": "90% ou mais usados", + "quotaSummary.credits": "Créditos", + "quotaSummary.refreshFailed": "A última atualização falhou; exibindo os dados anteriores", + "pws.protocol.title": "Protocolo de comunicação com o provedor", + "pws.protocol.note": "O formato de API que o opencodex usa para se comunicar com este provedor. Isso não ativa nem desativa nenhuma API para clientes; essas opções são controladas na página de APIs.", + "pws.protocol.adapterLabel": "Protocolo que este provedor recebe", + "pws.protocol.source": "Definido por", + "pws.protocol.source.hardPin": "Fixado pelo opencodex para este modelo", + "pws.protocol.source.operator": "Sua configuração", + "pws.protocol.source.registry": "Catálogo de provedores", + "pws.protocol.source.providerDefault": "Padrão do provedor", + "pws.protocol.pending": "Depois que você salvar, este provedor receberá {adapter}.", + "pws.protocol.overrides": "Modelos que usam outro protocolo", + "pws.protocol.noOverrides": "Todos os modelos usam o protocolo do provedor.", + "pws.protocol.overridesTruncated": "Exibindo os primeiros {count} modelos.", + "pws.protocol.col.model": "Modelo", + "pws.protocol.col.wire": "Protocolo de comunicação", + "pws.protocol.col.source": "Definido por", + "pws.protocol.loadFailed": "Não foi possível carregar o protocolo de comunicação do upstream.", + "compatProtocol.filter.inbound": "API do cliente", + "compatProtocol.filter.upstream": "Protocolo de comunicação do upstream", + "compatProtocol.anyProtocol": "qualquer", + "compatProtocol.pair": "{inbound} → {upstream}", + "compatProtocol.loading": "Lendo o par de protocolos de cada sujeito…", + "compatProtocol.unverified": "Ainda não há evidências do Lab para {pair}. O par não foi verificado, mas isso não significa que tenha falhado.", + "compatProtocol.unresolved": "Não foi possível ler o par de protocolos de {count} sujeitos; eles foram excluídos deste filtro.", + "compatProtocol.axisNote": "Estes são apenas vereditos do Lab. A forma como uma solicitação é encaminhada (nativamente ou por tradução) aparece na prévia do caminho da solicitação na página da API.", + "protocolLinks.labEvidence": "Evidências do Lab para este par", + "protocolLinks.providerSettings": "Configurações do provedor", + "cws.plan.title": "Caminhos candidatos", + "cws.plan.description": "Consulta o proxy para saber como cada destino encaminharia uma solicitação com todos os recursos que a API do cliente pode expressar e quais recursos são mantidos por todos os destinos. Nada é enviado ao upstream.", + "cws.plan.run": "Mostrar caminhos candidatos", + "cws.plan.savedOnly": "Mostra a combinação salva. Salve suas alterações para visualizá-las.", + "claude.firstParty.aria": "Alternar primeira parte da CLI do Claude Code", + "claude.firstParty.brokenProxy": "As configurações do Claude apontam para um proxy OpenCodex que não corresponde ao ouvinte em execução. Execute `ocx ensure` ou reinicie o OpenCodex.", + "claude.firstParty.deadProxy": "O ambiente de configurações do Claude aponta para um proxy que não está em execução. Inicie o OpenCodex ou desative a primeira parte do Desktop/CLI para remover as configurações antes de usar o Claude puro.", + "claude.firstParty.disabled": "O roteamento do Claude no OpenCodex está desativado. O proxy local ainda repassa essas requisições inalteradas até o OpenCodex reiniciar; depois disso, o Claude puro não conseguirá se conectar enquanto as configurações permanecerem. Desative a primeira parte para removê-las.", + "claude.firstParty.foreign": "~/.claude/settings.json aponta para o proxy OpenCodex mas confia em um certificado que o OpenCodex não gerencia, portanto as requisições falham. Corrija HTTPS_PROXY / NODE_EXTRA_CA_CERTS lá manualmente.", + "claude.firstParty.label": "Primeira parte da CLI do Claude Code", + "claude.firstParty.local": "~/.claude/settings.json envia o Claude Code através de um proxy local em 127.0.0.1 que o OpenCodex não consegue confirmar como seu próprio. Se não o usa mais, remova HTTPS_PROXY lá.", + "claude.firstParty.notApplied": "A primeira parte da CLI está ativada, mas suas configurações de proxy não estão aplicadas. Verifique o ambiente de configurações do Claude antes de usar o Claude puro.", + "claude.firstParty.refusal.caUnavailable": "A autoridade de certificação local não está disponível.", + "claude.firstParty.refusal.foreignEnv": "Outro programa possui as configurações de proxy do Claude.", + "claude.firstParty.refusal.interceptDisabled": "O proxy de interceptação está desativado.", + "claude.firstParty.refusal.interceptUnavailable": "O proxy de interceptação não está em execução neste processo.", + "claude.firstParty.refusal.unreadable": "Não foi possível ler as configurações do Claude.", + "claude.firstParty.refusal.writeFailed": "Não foi possível gravar as configurações do Claude.", + "claude.firstParty.residual": "As configurações do Claude ainda apontam para um proxy OpenCodex embora nem o Desktop nem a CLI de primeira parte estejam ativados. Remova a configuração restante de proxy ou execute `ocx ensure`.", + "claude.firstParty.risk": "Risco na conta: a primeira parte roteia o tráfego de assinatura do Claude através de um proxy de interceptação local. A Anthropic pode considerar isso uma violação dos termos e suspender a conta.", + "claude.firstParty.routingOff": "O OpenCodex não está servindo a interceptação do Claude em sua configuração atual (o roteamento do Claude ou a interceptação está desativada, ou esta máquina é cliente de outro hub OpenCodex), portanto essas configurações apontam para um proxy que não as atenderá. Reative-o nesta máquina ou desative a primeira parte para remover as configurações.", + "claude.firstParty.shared": "Quando o ambiente de proxy compartilhado é aplicado, o outro cliente Claude também transita pelo proxy local como um relay inalterado; o TLS termina localmente. Defina NO_PROXY='*' no shell para uso totalmente nativo no terminal.", + "claude.firstParty.unknown": "O OpenCodex não conseguiu determinar se ~/.claude/settings.json ainda aponta para seu proxy.", + "models.settingsPanel.attention": "Requer atenção", + "models.settingsPanel.off": "desativado", + "models.settingsPanel.title": "Configurações de modelos", + "quotaSummary.openAccounts": "Abrir gerenciamento de contas", + "quotaSummary.scrollNext": "Rolar provedores para a direita", + "quotaSummary.scrollPrev": "Rolar provedores para a esquerda", + "models.fastDisabled": "Modo rápido desativado", + "models.fastEnabled": "Modo rápido ativado", + "models.fastProviderHint": "Consome créditos de uso pelo dobro do preço", + "models.fastSaveFailed": "Não foi possível salvar o modo rápido", + "models.newCount": "{count} novos", + "models.newPolicyProvider": "Política para novos modelos deste provedor", + "models.newPolicy_off": "Novos modelos ficam desativados", + "models.newPolicy_on": "Novos modelos são ativados automaticamente", + "api.clientConfig.clientDroid": "Factory Droid", + "api.clientConfig.clientKilo": "Kilo", + "cws.err.invalidModelProfile": "As notas do modelo devem ter no máximo 512 caracteres; quebras de linha e tabulações são os únicos caracteres de controle permitidos.", + "cws.jev.modelProfile": "Notas adicionais do modelo para JEV", + "cws.jev.modelProfileHint": "Notas opcionais que complementam (nunca substituem) o perfil padrão integrado: capacidade, contexto e custo relativo da assinatura. Enviado ao TypeSafe por decisão do JEV.", + "cws.jev.modelProfilePlaceholder": "Opcional: deixe em branco para nenhuma nota adicional.", + "dash.codexRemoteHistoryHint": "O roteamento da tabela de provedores pode ocultar tópicos existentes marcados como openai em algumas listas remotas móveis. O histórico não é excluído. O cliente remoto deve listar todos os provedores; essa opção não repara esse filtro do cliente.", + "integrations.semantics.droid": "Adiciona os modelos personalizados do OpenCodex ao settings.json do Factory Droid. Desativar remove apenas as linhas gerenciadas; desfazer restaura o arquivo salvo.", + "integrations.semantics.kilo": "Gerencia apenas provider.opencodex na configuração global do Kilo — o primeiro arquivo existente entre kilo.jsonc, kilo.json, opencode.jsonc, opencode.json ou config.json em ~/.config/kilo (XDG_CONFIG_HOME realoca esse diretório; kilo.jsonc é criado quando nenhum existir). Outras chaves permanecem inalteradas. Aplicar reescreve todo o arquivo, portanto comentários e vírgulas finais não são preservados. Selecione opencodex/ no Kilo.", + "integrations.status.candidateConflict": "Outro arquivo de configuração do Kilo, {path}, também define provider.opencodex. Remova provider.opencodex desse arquivo antes de aplicar.", + "integrations.tab.droid": "Factory Droid", + "integrations.tab.kilo": "Kilo", + "kiroLogin.addDescription": "Adicione uma conta Kiro com login por dispositivo ou importe uma sessão do Kiro CLI.", + "kiroLogin.builderId": "Builder ID", + "kiroLogin.chooseMethod": "Escolha um método de login", + "kiroLogin.cli": "Kiro CLI", + "kiroLogin.copied": "Código copiado", + "kiroLogin.copyCode": "Copiar código", + "kiroLogin.copyUnavailable": "Cópia indisponível", + "kiroLogin.done": "Conta Kiro adicionada.", + "kiroLogin.duplicate": "Este perfil Kiro já está na lista de contas.", + "kiroLogin.ended": "Login finalizado. Verifique a lista de contas.", + "kiroLogin.expired": "Login por dispositivo expirado. Tente novamente.", + "kiroLogin.failed": "Falha no login Kiro.", + "kiroLogin.github": "GitHub", + "kiroLogin.google": "Google", + "kiroLogin.loginDescription": "Faça login com um dispositivo ou importe sua sessão do Kiro CLI.", + "kiroLogin.manualReview": "Pode ser necessária revisão manual para esta conta.", + "kiroLogin.openVerification": "Abrir página de verificação", + "kiroLogin.pending": "Digite este código na página de verificação e aguarde aqui.", + "kiroLogin.startFailed": "Não foi possível iniciar o login Kiro. Tente novamente.", + "kiroLogin.starting": "Iniciando login por dispositivo…", + "kiroLogin.title": "Entrar no Kiro", + "kiroLogin.tryAgain": "Tentar novamente", + "kiroLogin.unexpectedHost": "Host de verificação inesperado. Verifique o endereço antes de copiá-lo.", + "kiroSelection.cooldown": "Não selecionado automaticamente: em resfriamento", + "kiroSelection.generic": "Não selecionado automaticamente", + "kiroSelection.quotaExhausted": "Não selecionado automaticamente: cota esgotada", + "kiroSelection.suspended": "Não selecionado automaticamente: suspenso", + "memoryModels.accountNotice": "Apenas uma fase é roteada aqui; a outra mantém sua rota existente. O Shadow Call Intercept também pode enviar as chamadas de memória dessa fase para seu modelo configurado.", + "memoryModels.consolidation": "Consolidação", + "memoryModels.consolidationHint": "Mescla as memórias brutas nos arquivos de memória que o Codex lê posteriormente. Executa raramente e edita arquivos.", + "memoryModels.dataNotice": "O modelo escolhido recebe a entrada dessa fase: a sessão finalizada para Extração, as memórias brutas para Consolidação.", + "memoryModels.defaultEffort": "Padrão do Codex", + "memoryModels.description": "O Codex grava memórias após o término de uma sessão. Escolha um modelo para qualquer uma das fases ou mantenha sua rota existente.", + "memoryModels.effort": "Esforço de raciocínio", + "memoryModels.extract": "Extração", + "memoryModels.extractHint": "Resume cada sessão finalizada em uma memória bruta. Executa uma vez por sessão.", + "memoryModels.info": "O Codex transforma sessões finalizadas em memória em duas etapas. A Extração lê uma sessão finalizada e anota o que aconteceu: uma nota por sessão, fazendo muitas chamadas pequenas. A Consolidação pega essas notas e as grava nos arquivos de memória que o Codex lê no início das suas próximas sessões. Ela executa raramente, mas edita arquivos. Cada etapa solicita seu próprio modelo, e é por isso que estão listadas separadamente aqui.", + "memoryModels.infoLabel": "O que são Extração e Consolidação?", + "memoryModels.loadFailed": "Não foi possível carregar as configurações de memória.", + "memoryModels.model": "Modelo", + "memoryModels.off": "Desativado", + "memoryModels.saveFailed": "Não foi possível salvar. Suas alterações ainda estão aqui; tente novamente.", + "memoryModels.saved": "Configurações de memória salvas.", + "memoryModels.title": "Roteamento de memória", + "models.settingsContextInherit": "Não substituído — atualmente {value}", + "models.settingsContextUnknown": "desconhecido", + "models.settingsDefaultEffort": "Nível padrão", + "models.settingsModalitiesInherit": "Não substituído — seguindo a declaração upstream: {modalities}", + "models.settingsModalitiesUnknown": "não declarado", + "models.settingsNoChange": "Nenhuma configuração alterada para {model}", + "models.settingsNothingToRestore": "{model} não possui substituições; já está com os valores calculados", + "models.settingsRefreshFailed": "Salvo. A lista de modelos não recarregou, portanto a linha pode exibir valores antigos. Recarregue para verificar.", + "models.settingsRejected": "O servidor rejeitou estas configurações, portanto nada foi salvo. Verifique os valores e tente novamente.", + "models.settingsReload": "Recarregar", + "models.settingsReloaded": "Lista de modelos recarregada. Reabra {model} para ver os valores armazenados.", + "models.settingsRestore": "Restaurar", + "models.settingsRestoreConfirm": "Restaurar {model} para os valores calculados? Isso limpa suas substituições de janela de contexto, modalidade e raciocínio.", + "models.settingsRestoreHint": "Limpar todas as substituições neste modelo e reverter para os valores calculados.", + "models.settingsRestored": "{model} restaurado para os valores calculados", + "models.settingsSaveFailed": "Não foi possível confirmar se as configurações foram salvas. Recarregue a lista de modelos antes de tentar novamente.", + "models.settingsSaved": "Configurações de modelo salvas para {model}", + "models.settingsSavedCodexStale": "Salvo {model}, mas o catálogo de modelos do Codex não foi atualizado. Clique em Sincronizar agora no Painel para que o Codex reconheça a alteração.", + "models.settingsTitle": "Editar modelo — {model}", + "pws.accountPausedHint": "Excluído de seleção automática, tentativas, recuperação de resfriamento, seleção manual e atualização proativa de token até ser retomado.", + "remoteLink.error.join_port_mismatch": "O OpenCodex não está rodando na porta configurada, portanto não pode reiniciar como Child. Reinicie o OpenCodex na porta configurada e tente novamente.", + "remoteLink.error.remote_ocx_missing": "O ocx não foi encontrado no computador remoto. Instale o OpenCodex lá ou certifique-se de que o ocx esteja no PATH de sessões SSH não interativas.", + "remoteLink.error.remote_ocx_outdated": "O OpenCodex no computador remoto é muito antigo para o Remote Link. Execute ocx update lá (versão 2.66.0 ou superior) e tente novamente.", + "remoteLink.error.remote_ocx_unrecognized": "O computador remoto não informou uma versão do OpenCodex. O Remote Link requer OpenCodex 2.66.0 ou superior no macOS ou Linux.", + "remoteLink.findHome.notice": "A conexão reinicia o OpenCodex neste computador. As tarefas do Codex já em execução terminam primeiro, e novas requisições podem falhar por até um minuto. Depois disso, o Codex mantém o mesmo endereço local, e o Home o atende com seus próprios provedores e contas.", + "remoteLink.restart.slow": "A reinicialização está demorando mais do que o habitual. Esta página continua verificando e recarrega sozinha assim que o Child responder. Se o OpenCodex parou, inicie-o novamente.", +}; diff --git a/gui/src/i18n/routing-compatibility-labels.ts b/gui/src/i18n/routing-compatibility-labels.ts index c4e3de76b6b..016c56ea6d0 100644 --- a/gui/src/i18n/routing-compatibility-labels.ts +++ b/gui/src/i18n/routing-compatibility-labels.ts @@ -63,4 +63,9 @@ export const ROUTING_COMPATIBILITY_FIELD_LABELS: Record>; /** Localized display label for the wire-level vision reasoning value. */ diff --git a/gui/src/status-codes.ts b/gui/src/status-codes.ts index 08a36086d99..350ccb0a002 100644 --- a/gui/src/status-codes.ts +++ b/gui/src/status-codes.ts @@ -1,6 +1,6 @@ export interface StatusCodeInfo { label: string; description: string } -type Locale = "en" | "de" | "fr" | "ko" | "zh" | "zh-TW" | "ru" | "ja" | "tr" | "vi"; +type Locale = "en" | "de" | "fr" | "ko" | "zh" | "zh-TW" | "ru" | "ja" | "tr" | "vi" | "pt-BR"; type LocalizedInfo = Record; const STATUS_CODES: Record = { @@ -15,6 +15,7 @@ const STATUS_CODES: Record = { ja: { label: "不正なリクエスト", description: "プロキシがリクエストを解釈できませんでした。再試行前にモデル、メッセージ形式、ヘッダー、JSON 本文を確認してください。" }, tr: { label: "Hatalı istek", description: "Proxy isteği anlayamadı. Yeniden denemeden önce modeli, mesaj yapısını, başlıkları ve JSON gövdesini kontrol edin." }, vi: { label: "Yêu cầu không hợp lệ", description: "Proxy không thể hiểu yêu cầu. Hãy kiểm tra model, cấu trúc tin nhắn, header và nội dung JSON trước khi thử lại." }, + "pt-BR": { label: "Requisição inválida", description: "O proxy não conseguiu interpretar a requisição. Verifique o model, formato de mensagens, headers e o corpo JSON antes de tentar novamente." }, }, 401: { en: { label: "Unauthorized", description: "Credentials are missing, expired, or invalid. Re-login or refresh the account/provider credentials used by opencodex." }, @@ -27,6 +28,7 @@ const STATUS_CODES: Record = { ja: { label: "認証が必要", description: "認証情報が不在・期限切れ・無効です。opencodex が使用するアカウントまたはプロバイダー認証情報を再ログインまたは更新してください。" }, tr: { label: "Yetkisiz erişim", description: "Kimlik bilgileri eksik, süresi dolmuş veya geçersiz. opencodex tarafından kullanılan hesap veya sağlayıcı kimlik bilgilerini yeniden doğrulayın." }, vi: { label: "Chưa xác thực", description: "Thông tin xác thực bị thiếu, đã hết hạn hoặc không hợp lệ. Hãy đăng nhập lại hoặc làm mới thông tin xác thực của tài khoản hay nhà cung cấp mà opencodex sử dụng." }, + "pt-BR": { label: "Não autorizado", description: "As credenciais estão ausentes, expiradas ou são inválidas. Faça login novamente ou atualize as credenciais de conta/provedor usadas pelo opencodex." }, }, 402: { en: { label: "Payment required", description: "The upstream provider rejected the request because billing, credits, or plan access is not available. Add credits, update billing, or switch provider." }, @@ -39,6 +41,7 @@ const STATUS_CODES: Record = { ja: { label: "支払いが必要", description: "課金、クレジット、プランアクセスが利用できないため上流プロバイダーがリクエストを拒否しました。クレジット追加、支払い情報更新、プロバイダー切替が必要です。" }, tr: { label: "Ödeme gerekli", description: "Yukarı akış sağlayıcısı faturalandırma, kredi veya plan erişimi bulunmadığından isteği reddetti. Kredi ekleyin, ödeme bilgilerini güncelleyin veya sağlayıcı değiştirin." }, vi: { label: "Yêu cầu thanh toán", description: "Nhà cung cấp upstream đã từ chối yêu cầu vì không có quyền truy cập thanh toán, tín dụng hoặc gói dịch vụ. Hãy thêm tín dụng, cập nhật thanh toán hoặc đổi nhà cung cấp." }, + "pt-BR": { label: "Pagamento necessário", description: "O provedor upstream rejeitou a requisição porque o faturamento, créditos ou acesso ao plano não estão disponíveis. Adicione créditos, atualize o faturamento ou troque de provedor." }, }, 403: { en: { label: "Forbidden", description: "The account is authenticated but not allowed to use this model or operation. Often a plan/subscription gate (e.g. Ollama Cloud Pro), org policy, or model permission — not necessarily a bad API key." }, @@ -51,6 +54,7 @@ const STATUS_CODES: Record = { ja: { label: "アクセス禁止", description: "アカウントは認証済みですがこのモデルや操作の使用が許可されていません。多くはプラン/サブスクリプション制限(例: Ollama Cloud Pro)、組織ポリシー、モデル権限であり、API キーが不正とは限りません。" }, tr: { label: "Erişim yasaklandı", description: "Hesabın kimliği doğrulandı ancak bu modeli veya işlemi kullanma izni yok. Genellikle plan/abonelik sınırı (örn. Ollama Cloud Pro), organizasyon politikası veya model izni kaynaklıdır." }, vi: { label: "Bị cấm", description: "Tài khoản đã được xác thực nhưng không được phép dùng model hoặc thao tác này. Nguyên nhân thường là giới hạn gói hoặc thuê bao (ví dụ Ollama Cloud Pro), chính sách tổ chức hay quyền model — không nhất thiết do API key sai." }, + "pt-BR": { label: "Acesso proibido", description: "A conta está autenticada, mas não tem permissão para usar este model ou operação. Geralmente é um bloqueio de plano/assinatura (ex: Ollama Cloud Pro), política da organização ou permissão do model — não necessariamente uma chave de API inválida." }, }, 404: { en: { label: "Not found", description: "The requested route, model, account, or upstream resource was not found. Verify the model name and opencodex provider configuration." }, @@ -63,6 +67,7 @@ const STATUS_CODES: Record = { ja: { label: "見つかりません", description: "要求されたルート、モデル、アカウント、上流リソースが見つかりませんでした。モデル名と opencodex プロバイダー設定を確認してください。" }, tr: { label: "Bulunamadı", description: "İstenen rota, model, hesap veya yukarı akış kaynağı bulunamadı. Model adını ve opencodex sağlayıcı yapılandırmasını doğrulayın." }, vi: { label: "Không tìm thấy", description: "Không tìm thấy endpoint, model hoặc tài nguyên được yêu cầu. Hãy kiểm tra base URL, tên model và đường dẫn yêu cầu." }, + "pt-BR": { label: "Não encontrado", description: "A rota, model, conta ou recurso upstream solicitado não foi encontrado. Verifique o nome do model e a configuração de provedor do opencodex." }, }, 408: { en: { label: "Request timeout", description: "The request took too long before the proxy or upstream provider could complete it. Retry with a smaller request or a different provider." }, @@ -75,6 +80,7 @@ const STATUS_CODES: Record = { ja: { label: "リクエストタイムアウト", description: "プロキシまたは上流プロバイダーがリクエストを完了する前に時間切れになりました。より小さいリクエストで再試行するか、別のプロバイダーに切り替えてください。" }, tr: { label: "İstek zaman aşımı", description: "Proxy veya yukarı akış sağlayıcısı isteği tamamlayamadan zaman aşımına uğradı. Daha küçük bir istek veya farklı bir sağlayıcı ile tekrar deneyin." }, vi: { label: "Yêu cầu hết thời gian chờ", description: "Yêu cầu không hoàn tất trước thời hạn. Hãy thử lại với yêu cầu nhỏ hơn hoặc kiểm tra kết nối mạng." }, + "pt-BR": { label: "Tempo limite esgotado", description: "A requisição demorou muito antes que o proxy ou o provedor upstream pudesse concluí-la. Tente novamente com uma requisição menor ou outro provedor." }, }, 409: { en: { label: "Conflict", description: "The request conflicts with the current account, session, or provider state. Refresh the session or retry after the active operation finishes." }, @@ -87,6 +93,7 @@ const STATUS_CODES: Record = { ja: { label: "状態の衝突", description: "リクエストが現在のアカウント、セッション、プロバイダー状態と衝突しています。セッションを更新するか、進行中の操作が終わった後に再試行してください。" }, tr: { label: "Durum çakışması", description: "İstek mevcut hesap, oturum veya sağlayıcı durumuyla çakışıyor. Oturumu yenileyin veya aktif işlem bittikten sonra tekrar deneyin." }, vi: { label: "Xung đột", description: "Yêu cầu xung đột với trạng thái hiện tại của tài nguyên hoặc tài khoản. Hãy làm mới trạng thái rồi thử lại." }, + "pt-BR": { label: "Conflito", description: "A requisição entra em conflito com o estado atual da conta, sessão ou provedor. Atualize a sessão ou tente novamente após a conclusão da operação ativa." }, }, 413: { en: { label: "Request too large", description: "The prompt, attachments, or generated payload exceeds a proxy or upstream limit. Reduce tokens, file size, or conversation history." }, @@ -99,6 +106,7 @@ const STATUS_CODES: Record = { ja: { label: "リクエストが大きすぎます", description: "プロンプト、添付ファイル、生成ペイロードがプロキシまたは上流の制限を超えました。トークン、ファイルサイズ、会話履歴を減らしてください。" }, tr: { label: "İstek çok büyük", description: "İstemi, ekler veya oluşturulan veri proxy ya da yukarı akış sınırını aşıyor. Jeton sayısını, dosya boyutunu veya sohbet geçmişini azaltın." }, vi: { label: "Nội dung quá lớn", description: "Nội dung yêu cầu vượt quá giới hạn của proxy hoặc nhà cung cấp. Hãy giảm kích thước tin nhắn, tệp hoặc ngữ cảnh rồi thử lại." }, + "pt-BR": { label: "Requisição muito grande", description: "O prompt, anexos ou payload gerado excede o limite do proxy ou do upstream. Reduza os tokens, tamanho do arquivo ou histórico da conversa." }, }, 422: { en: { label: "Invalid content", description: "The provider accepted the request format but rejected its contents. Check model options, tool definitions, message roles, and unsupported fields." }, @@ -111,6 +119,7 @@ const STATUS_CODES: Record = { ja: { label: "内容の検証失敗", description: "プロバイダーはリクエスト形式を受け付けましたが内容を拒否しました。モデルオプション、ツール定義、メッセージロール、未サポートのフィールドを確認してください。" }, tr: { label: "Geçersiz içerik", description: "Sağlayıcı istek formatını kabul etti ancak içeriğini reddetti. Model seçeneklerini, araç tanımlarını, mesaj rollerini ve desteklenmeyen alanları kontrol edin." }, vi: { label: "Yêu cầu không thể xử lý", description: "Yêu cầu có cú pháp hợp lệ nhưng chứa giá trị hoặc tổ hợp tùy chọn mà model hay nhà cung cấp không hỗ trợ." }, + "pt-BR": { label: "Conteúdo inválido", description: "O provedor aceitou o formato da requisição, mas rejeitou seu conteúdo. Verifique opções do model, definições de ferramentas, papéis de mensagem e campos não suportados." }, }, 424: { en: { label: "Provider dependency failed", description: "A required upstream dependency failed while opencodex was routing the request. Retry later or switch to another configured provider." }, @@ -123,6 +132,7 @@ const STATUS_CODES: Record = { ja: { label: "プロバイダー依存の失敗", description: "opencodex がリクエストをルーティング中に必要な上流依存が失敗しました。後で再試行するか、別の設定済みプロバイダーに切り替えてください。" }, tr: { label: "Sağlayıcı bağımlılığı başarısız", description: "opencodex isteği yönlendirirken gerekli bir yukarı akış bağımlılığı başarısız oldu. Daha sonra tekrar deneyin veya başka bir sağlayıcıya geçin." }, vi: { label: "Phụ thuộc thất bại", description: "Không thể hoàn tất yêu cầu vì một dịch vụ phụ thuộc hoặc thao tác upstream đã thất bại. Hãy kiểm tra lỗi liên quan rồi thử lại." }, + "pt-BR": { label: "Falha na dependência do provedor", description: "Uma dependência upstream obrigatória falhou enquanto o opencodex roteava a requisição. Tente novamente mais tarde ou mude para outro provedor configurado." }, }, 429: { en: { label: "Rate limited", description: "The upstream provider rate or quota limit has been reached. Wait for the quota window to reset or switch account/provider." }, @@ -135,6 +145,7 @@ const STATUS_CODES: Record = { ja: { label: "レート制限", description: "上流プロバイダーのレートまたはクォータ制限に達しました。クォータウィンドウがリセットされるまで待つか、アカウント/プロバイダーを切り替えてください。" }, tr: { label: "Oran sınırı aşıldı", description: "Yukarı akış sağlayıcısının hız veya kota sınırına ulaşıldı. Kota penceresinin sıfırlanmasını bekleyin ya da hesap/sağlayıcı değiştirin." }, vi: { label: "Quá nhiều yêu cầu", description: "Tài khoản hoặc nhà cung cấp đã đạt giới hạn tốc độ hay hạn ngạch. Hãy chờ thời gian Retry-After, đổi tài khoản hoặc đổi nhà cung cấp." }, + "pt-BR": { label: "Limite de taxa atingido", description: "O limite de taxa ou cota do provedor upstream foi atingido. Aguarde a janela de cota reiniciar ou troque de conta/provedor." }, }, 499: { en: { label: "Client closed request", description: "The client disconnected or canceled the request before opencodex finished routing it. Retry if the cancellation was accidental." }, @@ -147,6 +158,7 @@ const STATUS_CODES: Record = { ja: { label: "クライアントがリクエストをクローズ", description: "opencodex がルーティングを終える前にクライアントが切断またはキャンセルしました。意図しないキャンセルなら再試行してください。" }, tr: { label: "İstemci isteği kapattı", description: "opencodex yönlendirmeyi bitirmeden önce istemci bağlantıyı kesti veya isteği iptal etti. İptal kazara yapıldıysa tekrar deneyin." }, vi: { label: "Máy khách đã đóng yêu cầu", description: "Máy khách đã ngắt kết nối hoặc hủy yêu cầu trước khi opencodex định tuyến xong. Nếu không chủ ý hủy, hãy thử lại." }, + "pt-BR": { label: "Cliente encerrou a requisição", description: "O cliente desconectou ou cancelou a requisição antes que o opencodex terminasse de roteá-la. Tente novamente se o cancelamento foi acidental." }, }, 500: { en: { label: "Proxy error", description: "opencodex hit an internal error while handling the request. Retry once, then check proxy logs if it repeats." }, @@ -159,6 +171,7 @@ const STATUS_CODES: Record = { ja: { label: "プロキシエラー", description: "opencodex がリクエスト処理中に内部エラーに遭遇しました。1 回再試行し、繰り返す場合はプロキシログを確認してください。" }, tr: { label: "Proxy hatası", description: "opencodex isteği işlerken dahili bir hatayla karşılaştı. Bir kez tekrar deneyin, tekrarlarsa proxy günlüklerini kontrol edin." }, vi: { label: "Lỗi proxy", description: "opencodex gặp lỗi nội bộ khi xử lý yêu cầu. Hãy thử lại một lần, rồi kiểm tra log proxy nếu lỗi lặp lại." }, + "pt-BR": { label: "Erro no proxy", description: "O opencodex encontrou um erro interno ao processar a requisição. Tente novamente uma vez; se persistir, verifique os logs do proxy." }, }, 502: { en: { label: "Bad upstream response", description: "The upstream provider returned an invalid or failed response through the proxy. Retry or route the request to another provider." }, @@ -171,6 +184,7 @@ const STATUS_CODES: Record = { ja: { label: "上流レスポンス不良", description: "上流プロバイダーがプロキシ経由で無効または失敗したレスポンスを返しました。再試行するか、リクエストを別のプロバイダーにルーティングしてください。" }, tr: { label: "Kötü yukarı akış yanıtı", description: "Yukarı akış sağlayıcısı proxy üzerinden geçersiz veya başarısız bir yanıt döndürdü. Tekrar deneyin veya isteği başka bir sağlayıcıya yönlendirin." }, vi: { label: "Phản hồi upstream không hợp lệ", description: "Nhà cung cấp upstream trả về phản hồi không hợp lệ hoặc thất bại qua proxy. Hãy thử lại hoặc định tuyến yêu cầu sang nhà cung cấp khác." }, + "pt-BR": { label: "Resposta inválida do upstream", description: "O provedor upstream retornou uma resposta inválida ou com falha através do proxy. Tente novamente ou roteie a requisição para outro provedor." }, }, 503: { en: { label: "Provider unavailable", description: "The proxy or upstream provider is temporarily unavailable or overloaded. Wait briefly, then retry or switch provider." }, @@ -183,6 +197,7 @@ const STATUS_CODES: Record = { ja: { label: "プロバイダー利用不可", description: "プロキシまたは上流プロバイダーが一時的に利用不可または過負荷です。少し待ってから再試行するか、プロバイダーを切り替えてください。" }, tr: { label: "Sağlayıcı kullanılamıyor", description: "Proxy veya yukarı akış sağlayıcısı geçici olarak kullanılamıyor veya aşırı yüklü. Kısa bir süre bekleyip tekrar deneyin ya da sağlayıcı değiştirin." }, vi: { label: "Nhà cung cấp không khả dụng", description: "Proxy hoặc nhà cung cấp upstream tạm thời không khả dụng hay đang quá tải. Hãy chờ một lát rồi thử lại hoặc đổi nhà cung cấp." }, + "pt-BR": { label: "Provedor indisponível", description: "O proxy ou provedor upstream está temporariamente indisponível ou sobrecarregado. Aguarde alguns instantes e tente novamente ou troque de provedor." }, }, 504: { en: { label: "Upstream timeout", description: "The upstream provider did not respond before the proxy timeout. Retry with a smaller request or choose a faster provider." }, @@ -195,6 +210,7 @@ const STATUS_CODES: Record = { ja: { label: "上流タイムアウト", description: "上流プロバイダーがプロキシタイムアウト前に応答しませんでした。より小さいリクエストで再試行するか、より速いプロバイダーを選んでください。" }, tr: { label: "Yukarı akış zaman aşımı", description: "Yukarı akış sağlayıcısı proxy zaman aşımı süresinden önce yanıt vermedi. Daha küçük bir istekle tekrar deneyin veya daha hızlı bir sağlayıcı seçin." }, vi: { label: "Upstream hết thời gian chờ", description: "Nhà cung cấp upstream không phản hồi trước thời hạn của proxy. Hãy thử lại với yêu cầu nhỏ hơn hoặc chọn nhà cung cấp nhanh hơn." }, + "pt-BR": { label: "Tempo limite do upstream", description: "O provedor upstream não respondeu antes do tempo limite do proxy. Tente novamente com uma requisição menor ou escolha um provedor mais rápido." }, }, 529: { en: { label: "Provider overloaded", description: "The upstream provider is overloaded or capacity-limited. Wait and retry, or switch to another account/provider." }, @@ -207,6 +223,7 @@ const STATUS_CODES: Record = { ja: { label: "プロバイダー過負荷", description: "上流プロバイダーが過負荷または容量制限されています。待ってから再試行するか、別のアカウント/プロバイダーに切り替えてください。" }, tr: { label: "Sağlayıcı aşırı yüklü", description: "Yukarı akış sağlayıcısı aşırı yüklü veya kapasitesi sınırlı. Bekleyip tekrar deneyin veya başka bir hesap/sağlayıcıya geçin." }, vi: { label: "Nhà cung cấp quá tải", description: "Nhà cung cấp upstream đang quá tải hoặc bị giới hạn công suất. Hãy chờ rồi thử lại, hoặc đổi sang tài khoản hay nhà cung cấp khác." }, + "pt-BR": { label: "Provedor sobrecarregado", description: "O provedor upstream está sobrecarregado ou com capacidade limitada. Aguarde e tente novamente, ou troque de conta/provedor." }, }, }; @@ -222,6 +239,7 @@ const GENERIC_STATUS: { client: LocalizedInfo; server: LocalizedInfo } = { ja: { label: "リクエストエラー", description: "プロキシまたは上流プロバイダーがリクエストを拒否しました。リクエスト形式、認証情報、モデル名、プロバイダー設定を確認してください。" }, tr: { label: "İstek hatası", description: "Proxy veya yukarı akış sağlayıcısı isteği reddetti. İstek yapısını, kimlik bilgilerini, model adını ve sağlayıcı yapılandırmasını kontrol edin." }, vi: { label: "Lỗi yêu cầu", description: "Proxy hoặc nhà cung cấp upstream đã từ chối yêu cầu. Hãy kiểm tra cấu trúc yêu cầu, thông tin xác thực, tên model và cấu hình nhà cung cấp." }, + "pt-BR": { label: "Erro na requisição", description: "O proxy ou o provedor upstream rejeitou a requisição. Verifique a estrutura da requisição, credenciais, nome do model e configuração do provedor." }, }, server: { en: { label: "Server or upstream error", description: "opencodex or an upstream provider failed while processing the request. Retry later or route the request to another provider." }, @@ -234,12 +252,14 @@ const GENERIC_STATUS: { client: LocalizedInfo; server: LocalizedInfo } = { ja: { label: "サーバーまたは上流エラー", description: "opencodex または上流プロバイダーがリクエスト処理中に失敗しました。後で再試行するか、リクエストを別のプロバイダーにルーティングしてください。" }, tr: { label: "Sunucu veya yukarı akış hatası", description: "opencodex veya bir yukarı akış sağlayıcısı isteği işlerken başarısız oldu. Daha sonra tekrar deneyin veya isteği başka bir sağlayıcıya yönlendirin." }, vi: { label: "Lỗi máy chủ hoặc upstream", description: "opencodex hoặc một nhà cung cấp upstream đã thất bại khi xử lý yêu cầu. Hãy thử lại sau hoặc định tuyến yêu cầu sang nhà cung cấp khác." }, + "pt-BR": { label: "Erro no servidor ou upstream", description: "O opencodex ou um provedor upstream falhou ao processar a requisição. Tente novamente mais tarde ou roteie para outro provedor." }, }, }; function normalizeLocale(locale: string): Locale { if (locale.toLowerCase().startsWith("fr")) return "fr"; if (locale.toLowerCase().startsWith("vi")) return "vi"; + if (locale.toLowerCase().startsWith("pt")) return "pt-BR"; return locale === "de" || locale === "ko" || locale === "zh" || locale === "zh-TW" || locale === "ru" || locale === "ja" || locale === "tr" ? locale : "en"; } diff --git a/gui/tests/i18n-locales.test.ts b/gui/tests/i18n-locales.test.ts index 991cf6c5790..1b83e5ca418 100644 --- a/gui/tests/i18n-locales.test.ts +++ b/gui/tests/i18n-locales.test.ts @@ -22,6 +22,11 @@ describe("i18n locale contracts", () => { } }); + test("Brazilian Portuguese locale is registered", () => { + expect(LOCALES.some(locale => locale.code === "pt-BR")).toBe(true); + expect(DICTS["pt-BR"]["lang.nativeName"]).toBe("Português (Brasil)"); + }); + test("Vietnamese locale is registered", () => { expect(LOCALES.some(locale => locale.code === "vi")).toBe(true); expect(DICTS.vi["lang.nativeName"]).toBe("Tiếng Việt"); @@ -105,6 +110,41 @@ describe("i18n locale contracts", () => { expect(duplicates).toEqual([]); }); + test("pt-BR renders no literal backslash-escape inside a value", () => { + // A value holding `\\"` in the source renders as \" in the GUI, so the user sees + // stray backslashes around a provider name. The key-set and placeholder tests + // cannot see this, so it gets its own assertion. Scoped to this PR's locale: + // vi carries three pre-existing offenders that are not ours to change here. + const offenders: string[] = []; + const pt = DICTS["pt-BR"]; + + for (const key of Object.keys(en) as Array) { + const value = pt[key]; + if (value.includes("\\\"") || value.includes("\\\\")) { + offenders.push(`pt-BR.${key}`); + } + } + + expect(offenders).toEqual([]); + }); + + test("pt-BR provider messages read as Portuguese, not as broken machine text", () => { + const pt = DICTS["pt-BR"]; + + // Regression values: the key set and placeholder contracts both passed while + // these three read as malformed or as the wrong subject in the GUI. + expect(pt["prov.removeLastProvider"]).toBe( + "Você não pode remover este provedor quando nenhum outro provedor habilitado puder se tornar o padrão.", + ); + expect(pt["pws.allSystemsOk"]).toBe("Todos os sistemas operando normalmente"); + // English means "all systems operational" — not "all operating systems". + expect(pt["pws.allSystemsOk"]).not.toMatch(/sistemas operacionais/); + // A provider name is quoted, not backslash-quoted. + expect(pt["prov.setDefaultSuccess"]).toBe( + "\"{name}\" agora é o provedor padrão.", + ); + }); + test("formatUptime uses catalog units for every locale", () => { for (const { code } of LOCALES) { const day = DICTS[code]["uptime.day"]; diff --git a/gui/tests/logs-cost-plain-dollar.test.ts b/gui/tests/logs-cost-plain-dollar.test.ts index 85624496e86..ce1a949f482 100644 --- a/gui/tests/logs-cost-plain-dollar.test.ts +++ b/gui/tests/logs-cost-plain-dollar.test.ts @@ -15,6 +15,7 @@ const LOCALE_TAGS: Record = { ru: "ru-RU", tr: "tr-TR", vi: "vi-VN", + "pt-BR": "pt-BR", }; function translator(locale: Locale): TFn { diff --git a/gui/tests/subagent-surface-warning.test.tsx b/gui/tests/subagent-surface-warning.test.tsx index 9f9c36325ad..0cd04ccdd5c 100644 --- a/gui/tests/subagent-surface-warning.test.tsx +++ b/gui/tests/subagent-surface-warning.test.tsx @@ -31,7 +31,7 @@ test("the fallback guide URL matches the runtime constant", async () => { test("every locale defines the dialog keys, and Korean uses the wording that was asked for", () => { // Read the loaded catalogs, not the source text: a key mentioned only in a comment would // satisfy a grep and still render the raw key id to the operator. - expect(LOCALES.length).toBe(10); + expect(LOCALES.length).toBe(11); for (const { code } of LOCALES) { for (const key of KEYS) { const value = DICTS[code][key as keyof (typeof DICTS)[typeof code]]; diff --git a/scripts/file-size-ratchet.ts b/scripts/file-size-ratchet.ts index 8d636cc1582..3bd64431033 100644 --- a/scripts/file-size-ratchet.ts +++ b/scripts/file-size-ratchet.ts @@ -43,7 +43,7 @@ export const GENERATED_PATHS = [ /** * Translation catalogues. Hand-written, and exempt for a different reason: they grow by one - * line per UI string in ten locales at once, so a cap would block every new string in the + * line per UI string in eleven locales at once, so a cap would block every new string in the * GUI rather than any oversized module. gui/src/i18n/en.ts describes itself as the TKey * source of truth; nothing generates these. */ @@ -55,6 +55,7 @@ export const I18N_CATALOG_PATHS = [ "gui/src/i18n/ko.ts", "gui/src/i18n/ru.ts", "gui/src/i18n/tr.ts", + "gui/src/i18n/pt-BR.ts", "gui/src/i18n/vi.ts", "gui/src/i18n/zh.ts", "gui/src/i18n/zh-TW.ts", diff --git a/structure/dashboard-and-usage.md b/structure/dashboard-and-usage.md index 29ddb52d626..7a3bd322bc9 100644 --- a/structure/dashboard-and-usage.md +++ b/structure/dashboard-and-usage.md @@ -19,7 +19,7 @@ Codex account panels expose no Spark quota toggle or setting and retain quota re ## Dashboard surfaces Dashboard localization uses the English `gui/src/i18n/en.ts` catalog as the complete key and -placeholder contract. Every registered locale, including Vietnamese, supplies the same keys; +placeholder contract. Every registered locale, including Vietnamese and Brazilian Portuguese, supplies the same keys; locale-specific Compatibility Lab, log-guard, routing, vision, status-code, and quota-formatting maps remain total rather than silently falling back to English. diff --git a/structure/design-methodology.md b/structure/design-methodology.md index bb4ee16d0a2..5df5afb4b74 100644 --- a/structure/design-methodology.md +++ b/structure/design-methodology.md @@ -17,8 +17,8 @@ interview engine. The rule stands on its own; it does not depend on an external Native-main device cancellation, polling and restart follow the [flow-ownership contract](dashboard-and-usage.md#dashboard-surfaces), including status-gated error DTO handling. Visible dashboard copy follows the total catalog contract in -[`gui-and-management-api.md`](dashboard-and-usage.md#dashboard-surfaces); Vietnamese is a -first-class locale across page copy and auxiliary label maps. +[`dashboard-and-usage.md`](dashboard-and-usage.md#dashboard-surfaces); Vietnamese and Brazilian Portuguese are +first-class locales across page copy and auxiliary label maps. ## Existing surfaces and their design direction diff --git a/structure/overview.md b/structure/overview.md index 390e9d215b9..c7bd63a860a 100644 --- a/structure/overview.md +++ b/structure/overview.md @@ -3,7 +3,7 @@ Management provider-validation calls use the [shared relative send-path validation](config.md#provider-relative-send-paths) before persistence. Native steering follows [the shared WebSocket contract](transports/streaming-health.md#experimental-native-mid-turn-steering); this surface's defaults remain unchanged. -The dashboard's compile-checked locale catalogs include Vietnamese. Locale registration, browser +The dashboard's compile-checked locale catalogs include Vietnamese and Brazilian Portuguese. Locale registration, browser detection, Compatibility Lab labels, status descriptions, and locale-sensitive quota formatting advance together under the `gui/` catalog parity contract. diff --git a/tests/ci-workflows/file-size-ratchet.test.ts b/tests/ci-workflows/file-size-ratchet.test.ts index 9eaf307c3e4..19518103510 100644 --- a/tests/ci-workflows/file-size-ratchet.test.ts +++ b/tests/ci-workflows/file-size-ratchet.test.ts @@ -237,7 +237,7 @@ describe("file-size ratchet: exemption classification", () => { // contradictory reasons and reviewable under neither. expect(new Set(all).size).toBe(all.length); expect([...all].sort()).toEqual([...EXEMPT_PATHS]); - expect(EXEMPT_PATHS.length).toBe(13); + expect(EXEMPT_PATHS.length).toBe(14); // Every exemption names a file that is actually here. A stale entry exempts nothing and // hides the fact that the policy no longer describes this tree. diff --git a/tests/fixtures/file-size-baseline.json b/tests/fixtures/file-size-baseline.json index 716b586605b..13f063c2d4a 100644 --- a/tests/fixtures/file-size-baseline.json +++ b/tests/fixtures/file-size-baseline.json @@ -6,6 +6,7 @@ "gui/src/i18n/fr.ts", "gui/src/i18n/ja.ts", "gui/src/i18n/ko.ts", + "gui/src/i18n/pt-BR.ts", "gui/src/i18n/ru.ts", "gui/src/i18n/tr.ts", "gui/src/i18n/vi.ts",