From 973d55de54a5d70d1e724793ee826ed2cdc02834 Mon Sep 17 00:00:00 2001 From: rriosfelipe Date: Fri, 2 Oct 2026 09:15:35 -0300 Subject: [PATCH] feat(gui): add Brazilian Portuguese (pt-BR) dashboard locale Register `pt` (htmlLang pt-BR) as an eleventh GUI locale: - gui/src/i18n/pt.ts: full catalog for the en.ts TKey set (3728 keys) - lab-translations, log-guard-*, routing-compatibility, vision-reasoning, native-main-translations and status-codes: pt entries - shared.ts / catalogs.ts / index.html: locale list, stored-value check, navigator.language detection (pt*) and the pre-paint html lang guard - QuotaBars / ProviderCapacityQuota: pt-BR number/date formatting tag - tests: pt registration, DSH copy, pool-toggle copy, hard-coded locale counts (10 -> 11), cost-format tag map; pt.ts added to the file-size ratchet exemptions and baseline like the other catalogs Brand names, protocol names and widely used technical terms (token, endpoint, proxy, sidecar, cache) stay in English, as in the other catalogs. Co-Authored-By: Claude Sonnet 5.5 --- gui/index.html | 3 +- gui/src/components/QuotaBars.tsx | 2 + .../ProviderCapacityQuota.tsx | 1 + gui/src/i18n/catalogs.ts | 2 + gui/src/i18n/lab-translations.ts | 65 +- gui/src/i18n/log-guard-labels.ts | 27 + gui/src/i18n/log-guard-operation-labels.ts | 12 + gui/src/i18n/log-guard-state-labels.ts | 5 + gui/src/i18n/native-main-translations.ts | 40 +- gui/src/i18n/pt.ts | 3750 +++++++++++++++++ gui/src/i18n/routing-compatibility-labels.ts | 5 + gui/src/i18n/shared.ts | 4 +- gui/src/i18n/vision-reasoning-labels.ts | 1 + gui/src/status-codes.ts | 22 +- gui/tests/anthropic-pool-conditions.test.tsx | 2 +- gui/tests/i18n-locales.test.ts | 5 + gui/tests/locale-parity.test.ts | 5 + gui/tests/logs-cost-plain-dollar.test.ts | 1 + gui/tests/oauth-tos-warning-modal.test.tsx | 2 +- gui/tests/remote-link.test.tsx | 2 +- gui/tests/subagent-surface-warning.test.tsx | 2 +- scripts/file-size-ratchet.ts | 1 + .../anthropic-pool-toggle-copy.test.ts | 1 + tests/ci-workflows/file-size-ratchet.test.ts | 2 +- tests/fixtures/file-size-baseline.json | 1 + 25 files changed, 3953 insertions(+), 10 deletions(-) create mode 100644 gui/src/i18n/pt.ts diff --git a/gui/index.html b/gui/index.html index 33b3b525656..10cc833c9f8 100644 --- a/gui/index.html +++ b/gui/index.html @@ -17,6 +17,7 @@ // FOUT guard: set before first paint so :lang() font stacks apply immediately. // Mirrors detectInitial() + LOCALES in src/i18n/shared.ts. var langMap = { en: "en", de: "de", fr: "fr", ko: "ko", zh: "zh-CN", "zh-TW": "zh-TW", ru: "ru", ja: "ja", tr: "tr", vi: "vi" }; + langMap.pt = "pt-BR"; var stored = null; try { stored = localStorage.getItem("ocx-lang"); @@ -29,7 +30,7 @@ if (nav.indexOf("zh") === 0) { locale = /tw|hk|mo|hant/.test(nav) ? "zh-TW" : "zh"; } else { - locale = ["de", "fr", "ko", "ru", "ja", "tr", "vi"].filter(function (c) { return nav.indexOf(c) === 0; })[0] || "en"; + locale = ["de", "fr", "ko", "ru", "ja", "tr", "vi", "pt"].filter(function (c) { return nav.indexOf(c) === 0; })[0] || "en"; } } document.documentElement.lang = langMap[locale]; diff --git a/gui/src/components/QuotaBars.tsx b/gui/src/components/QuotaBars.tsx index ec18b78b65a..fc72b0bb5f3 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": + 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..992e9d6df3c 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": 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..d64033f412d 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 { pt } from "./pt"; 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: withLabTranslations("pt", pt), }; /** 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..ce25d4fcacf 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"; export type LabCatalogKey = Exclude, `lab.production.${string}`>; export type LabSupplementKey = | "subjectKindUnknown" @@ -514,6 +514,56 @@ const vi: Record = { "lab.layer.task_effectiveness": "Hiệu quả tác vụ", }; +const pt: Record = { + "lab.title": "Laboratório de Compatibilidade", + "lab.subtitle": "Matriz de vereditos de compatibilidade somente leitura, gerada a partir das evidências da 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 primeiro os testes de conformidade ou as sondagens ao vivo.", + "lab.projectionIncompatible": "O esquema da 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 veredito", + "lab.filter.layer": "Camada de evidência", + "lab.filter.verdict": "Veredito", + "lab.filter.subject": "ID do sujeito", + "lab.filter.all": "Todos", + "lab.col.subject": "Sujeito", + "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 da rota ao vivo", + "lab.col.task": "Eficácia nas tarefas", + "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": "Sujeitos", + "lab.builtAt": "Gerada em", + "lab.loading": "Carregando evidências de compatibilidade…", + "lab.loadMore": "Carregar mais", + "lab.detailTitle": "Detalhes do veredito", + "lab.detailClose": "Fechar", + "lab.detailSubject": "Sujeito", + "lab.detailObservations": "Observações", + "lab.detailEvents": "Eventos de evidência", + "lab.detailArtifacts": "Metadados dos artefatos", + "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": "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 da rota ao vivo", + "lab.layer.task_effectiveness": "Eficácia nas tarefas", +}; + export const LAB_CATALOG_OVERRIDES: Record> = { en, de, @@ -525,6 +575,7 @@ export const LAB_CATALOG_OVERRIDES: Record> = { @@ -648,6 +699,18 @@ const supplements: Record> = { "community.activeRecords": "Bản ghi đang hoạt động", "community.revokedRecords": "Bản ghi đã thu hồi", }, + pt: { + subjectKindUnknown: "Desconhecido", + "artifact.present": "Presente", + "artifact.corrupt": "Corrompido", + "artifact.purged_unavailable": "Removido / indisponível", + selectVerdict: "Ver veredito de {subject}", + "community.title": "Evidências da comunidade", + "community.notLocalVerdict": "Contexto somente leitura não confiável. Não incluído neste veredito local.", + "community.bundles": "Pacotes", + "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..c32a5662efb 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: { + compact: 'Compactar', + compactComplete: "Compactação concluída (lógico / recuperado em disco)", + pagesUnit: "páginas", + compactPartial: "Compactação parcial (lógico / recuperado em disco)", + confirmCompact: 'Confirmar compactação', + cancel: 'Cancelar', + inspectionOnly: 'Somente inspeção', + externalSqliteHome: 'Armazenamento SQLite externo', + inspectionUnavailable: "A inspeção do log de diagnóstico não está disponível.", + metricsSkippedLarge: "Métricas de linhas ignoradas: o banco de dados excede {threshold} e a varredura travaria 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á parado. 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 foi alterado, mas o OpenCodex não conseguiu salvar a configuração de proteção. Corrija o armazenamento de configuração 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..173fee49002 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: { + 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 está parado. 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 incremental vacuum; por isso, não é possível recuperar espaço sem uma reconstruçã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..71c789cbb1c 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: { + 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: "Desconhecida" }, + 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-translations.ts b/gui/src/i18n/native-main-translations.ts index a1f53768ae2..59ae5f2d294 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": { + "nativeMain.title": "Login principal do Codex nativo", + "nativeMain.manage": "Gerenciar login principal", + "nativeMain.close": "Fechar o gerenciador de login principal", + "nativeMain.separate": "Estes controles alteram o login do Codex nativo, não a conta selecionada para a próxima requisição do Pool.", + "nativeMain.home": "CODEX_HOME efetivo", + "nativeMain.current": "Perfil ativo registrado", + "nativeMain.unregistered": "Não registrado", + "nativeMain.physicalHint": "Este diretório home pertence ao servidor do OpenCodex, que pode ser outro computador. O backend verifica o login físico antes de qualquer troca.", + "nativeMain.busyOther": "Outra operação de login nativo está em andamento. 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 de novo; uma resposta perdida não prova que houve reversão. Use o comando de diagnóstico no servidor abaixo.", + "nativeMain.doctorHint": "Execute {cmd} no servidor para ver os detalhes.", + "nativeMain.saved": "Login atual salvo como perfil. O login físico não foi alterado.", + "nativeMain.restart": "Troca 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 já 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 exige o armazenamento de credenciais em arquivo.", + "nativeMain.recoveryHint": "Uma transação interrompida precisa de recuperação. Recuperar conclui a reconciliação; restaurar reverte a transação pendente. Nenhuma das ações é executada até você confirmar.", + "nativeMain.recover": "Recuperar alteração interrompida", + "nativeMain.rollback": "Restaurar transação pendente", + "nativeMain.empty": "Nenhum perfil nativo registrado ainda. Salve primeiro o login atual.", + "nativeMain.active": "Ativo", + "nativeMain.switchTo": "Trocar o login nativo para {label}", + "nativeMain.switch": "Trocar", + "nativeMain.restore": "Voltar ao perfil exibido anteriormente: {label}", + "nativeMain.restoreHint": "Este atalho seleciona o perfil exibido antes da sua última troca, 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 o rótulo. Não adiciona um novo login.", + "nativeMain.confirmHint": "Isto altera apenas o login nativo no diretório home abaixo. Feche primeiro o Codex nativo naquele computador. Este painel não edita estratégia do Pool, membros, chaves de provedor nem dados de tarefas/histórico.", + "nativeMain.stopped": "Parei o Codex nativo que usa este CODEX_HOME e entendo que pode ser necessário reiniciá-lo.", + "nativeMain.cancel": "Cancelar", + "nativeMain.confirm": "Confirmar alteração do login nativo", + "nativeMain.unavailable": "As alterações de perfil estão 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", Record>; diff --git a/gui/src/i18n/pt.ts b/gui/src/i18n/pt.ts new file mode 100644 index 00000000000..2705c415c3f --- /dev/null +++ b/gui/src/i18n/pt.ts @@ -0,0 +1,3750 @@ +// Brazilian Portuguese — generated from en.ts. Must match TKey set (compile-checked). +import type { TKey } from "./en"; + +/** + * Brazilian Portuguese (pt-BR) i18n catalog. Must match the `TKey` set (compile-checked). + * Technical terms and model identifiers intentionally remain English. + */ +export const pt: Record = { + "nav.claude": "Claude", + "claude.tabAccount": "Conta", + "claude.tabSettings": "Configurações", + "claude.pageSub": "Contas e roteamento do OpenCodex para o Claude Code e o Claude Desktop.", + "claude.addAnthropic": "Adicionar Anthropic", + "claude.changeOnCode": "Altere na aba {tab}", + "claude.interceptRunning": "Em execução", + "claude.interceptStopped": "Parada", + "claude.routingLoadFail": "Não foi possível carregar o status do roteamento do Claude.", + "claude.interceptLoadFail": "Não foi possível carregar o status da interceptação.", + "claude.accountEmpty": "Adicione o provedor Anthropic e entre com sua conta Claude. Suas contas, cota e configurações aparecerão aqui.", + "claude.accountEmptyTitle": "A Anthropic ainda não foi configurada", + "claude.interceptStatus": "Interceptação", + "claude.interceptDesc": "Encaminha pelo proxy local o tráfego do Claude Code/Desktop destinado aos serviços da Anthropic.", + "claude.interceptPort": "Porta de interceptação", + "claude.interceptPortDesc": "Porta local do proxy de interceptação, separada da porta do proxy do OpenCodex.", + "claude.stateOn": "Ativada", + "claude.stateOff": "Desativada", + "claude.settingsHint": "As configurações de compatibilidade, instruções do agente e contexto podem ser alteradas na aba Code.", + "pws.anthropicAccountThresholdHint": "Substitui o padrão do pool do Claude. 0 desativa a troca por uso apenas para esta conta; a pausa e a recuperação de limite de taxa continuam valendo.", + "kiroLogin.title": "Entrar no Kiro", + "kiroLogin.chooseMethod": "Escolha um método de login", + "kiroLogin.cli": "Kiro CLI", + "kiroLogin.builderId": "Builder ID", + "kiroLogin.google": "Google", + "kiroLogin.github": "GitHub", + "kiroLogin.addDescription": "Adicione uma conta Kiro com login por dispositivo ou importe uma sessão do Kiro CLI.", + "kiroLogin.loginDescription": "Entre com um dispositivo ou importe sua sessão do Kiro CLI.", + "kiroLogin.starting": "Iniciando login por dispositivo…", + "kiroLogin.pending": "Digite este código na página de verificação e aguarde aqui.", + "kiroLogin.done": "Conta Kiro adicionada.", + "kiroLogin.expired": "O login por dispositivo expirou. Tente novamente.", + "kiroLogin.ended": "Login encerrado. Verifique a lista de contas.", + "kiroLogin.failed": "Falha no login do Kiro.", + "kiroLogin.startFailed": "Não foi possível iniciar o login do Kiro. Tente novamente.", + "kiroLogin.tryAgain": "Tentar novamente", + "kiroLogin.copyCode": "Copiar código", + "kiroLogin.copied": "Código copiado", + "kiroLogin.copyUnavailable": "Cópia indisponível", + "kiroLogin.openVerification": "Abrir página de verificação", + "kiroLogin.unexpectedHost": "Host de verificação inesperado. Confira o endereço antes de copiá-lo.", + "kiroLogin.duplicate": "Este perfil do Kiro já está na lista de contas.", + "kiroLogin.manualReview": "Esta conta pode precisar de revisão manual.", + "kiroSelection.suspended": "Não selecionada automaticamente: suspensa", + "kiroSelection.quotaExhausted": "Não selecionada automaticamente: cota esgotada", + "kiroSelection.cooldown": "Não selecionada automaticamente: em espera", + "kiroSelection.generic": "Não selecionada automaticamente", + "tray.updated": "Atualizado {time} · a cada 60 s", + "tray.today": "Hoje", + "tray.input": "Entrada", + "tray.output": "Saída", + "tray.cost": "Custo · est.", + "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 por mais usados porque o histórico de uso está incompleto. Escolha outra ordem ou repare o histórico primeiro.", + "api.attribution.noRecordedUse": "Sem 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": "Upstream indisponível. Verifique a conta do provedor.", + "audio.error.rateLimit": "Limite de taxa 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 expirou. 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–Z por modelo", + "models.pickerOrder.provider": "Agrupar por provedor", + "models.pickerOrder.mostUsed": "Instantâneo dos 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 dos modelos.", + "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 a descoberta do Codex e do Claude. As faixas em destaque/nativas permanecem no lugar; Mais usados é um instantâneo. As opções nativas anunciadas podem mudar.", + "models.fastRows.title": "Mostrar linhas de modelos Fast", + "models.fastRows.desc": "Adiciona seletores “Model Fast” elegíveis aos seletores de modelos de clientes externos. Isso não altera as opções de esforço de raciocínio do modelo base. Ao salvar, as integrações conectadas são atualizadas 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 modelos Fast ativadas.", + "models.fastRows.disabled": "Linhas de modelos Fast desativadas.", + "models.fastRows.loadFailed": "Não foi possível carregar a configuração das linhas Fast.", + "models.fastRows.updateFailed": "Falha ao atualizar a configuração das linhas Fast.", + "codexAuth.quotaAutoRefreshAllHint": "Controla juntas as janelas compatíveis de 5 horas e semanal de todas as contas atuais. No modo Pool, uma pequena requisição é enviada após cada redefinição e consome cota.", + "codexAuth.quotaAutoRefreshMixed": "Algumas janelas estão ativadas.", + "codexAuth.quotaAutoRefreshEmpty": "Nenhuma janela de cota compatível. Atualize as cotas das contas 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 mesma alteração.", + "nav.dashboard": "Painel", + "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": "Dar estrela no GitHub", + "sidebar.starred": "Estrela dada no GitHub", + "sidebar.starUnauthenticated": "Abra o GitHub para dar a estrela (a CLI gh não está autenticada)", + "sidebar.starFailed": "Não foi possível dar a estrela 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 mantém o projeto vivo.", + "onboarding.star.cta": "Dar estrela no GitHub", + "onboarding.star.ghHint": "Dá a estrela no repositório com a CLI do GitHub (gh) autenticada. Nada é marcado até você clicar.", + "onboarding.star.browserHint": "Abre o repositório em github.com no navegador.", + "onboarding.star.openPage": "Abrir a página do GitHub", + "onboarding.star.later": "Talvez depois", + "onboarding.star.failed": "Não foi possível dar a estrela pela CLI do GitHub (gh). Você pode dá-la na página do GitHub.", + "onboarding.star.starring": "Dando estrela…", + "onboarding.star.thanks": "Obrigado pela estrela!", + "onboarding.star.thanksBody": "Ajuda muito. O link do GitHub na barra lateral leva você de volta ao repositório a qualquer momento.", + "onboarding.star.done": "Concluído", + "sidebar.updateAvailable": "Atualização disponível: {version}", + "sidebar.checkUpdate": "Verificar atualizações", + "sidebar.desktopUpdate": "Abrir atualizações do 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 administrador do OpenCodex (OPENCODEX_ADMIN_AUTH_TOKEN)", + "auth.adminAccountLabel": "Conta", + "auth.adminTokenFieldLabel": "Token de administrador", + "auth.adminTokenRejected": "Esse token de administrador foi rejeitado. Confira-o e tente novamente.", + "auth.adminTokenUnavailable": "Não foi possível verificar o token de administrador. Tente novamente.", + "auth.adminTokenHelp": "Este é o token de administrador de gerenciamento do OpenCodex, não uma chave de API de provedor. O proxy o grava em ~/.opencodex/admin-api-token (ou $OPENCODEX_HOME/admin-api-token) na primeira inicialização, e OPENCODEX_ADMIN_AUTH_TOKEN o substitui.", + "auth.adminTokenDocsLink": "Como encontrá-lo", + "app.logoAria": "logotipo do opencodex", + "app.claudeOn": "Claude ON", + "app.claudeOff": "Claude OFF", + "theme.label": "Tema", + "theme.light": "Claro", + "theme.dark": "Escuro", + "theme.system": "Sistema", + "lang.label": "Idioma", + "lang.nativeName": "Português", + "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 em dry-run e análises de roteamento com base 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 dry-run (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 obrigatórios", + "routing.optimize": "Pesos de otimização", + "routing.limits": "Limites", + "routing.unknownEvidence": "Política para evidência desconhecida", + "routing.compatibility.title": "Política de compatibilidade", + "routing.compatibility.enabled": "Exigir evidência do Compatibility Lab", + "routing.compatibility.requiredSuites": "Suítes obrigatórias", + "routing.compatibility.loadingCatalog": "Carregando catálogo do lab…", + "routing.compatibility.catalogUnavailable": "Catálogo do lab indisponível — informe 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 ao vivo", + "routing.compatibility.minStatus": "Status mínimo de compatibilidade", + "routing.none": "nenhum", + "routing.unavailable": "–", + "routing.dryRun": "Avaliação em dry-run", + "routing.dryRunContext": "Janela de contexto da requisição (tokens)", + "routing.dryRunTools": "A requisição exige ferramentas", + "routing.dryRunImage": "A requisição exige entrada de imagem", + "routing.dryRunStructured": "A requisição exige saída estruturada", + "routing.dryRunRun": "Avaliar candidatos", + "routing.candidate": "Candidato", + "routing.eligible": "Elegível", + "routing.exclusions": "Exclusões", + "routing.costCap": "Teto 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 teto de custo", + "routing.exclusion.cost-limit-unknown": "custo desconhecido sob o teto", + "routing.exclusion.cooldown": "em espera", + "routing.exclusion.unknown-health": "saúde desconhecida", + "routing.exclusion.unknown-quota": "cota 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": "Análises 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 espera", + "routing.analyticsConfidence": "Confiança", + "routing.analyticsTruncated": "histórico truncado", + "routing.analyticsRequests": "Requisições", + "routing.analyticsEmpty": "Ainda não há análises — envie algumas requisições primeiro.", + "startup.title": "Segurança na inicialização", + "startup.subtitle": "Verifique se o Codex consegue alcançar o opencodex após uma reinicialização, antes que o roteamento pelo proxy local vire um loop de reconexão.", + "startup.refresh": "Atualizar", + "startup.backToDashboard": "Voltar ao painel", + "startup.loading": "Verificando a 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 aos modelos após a reinicialização", + "startup.riskDetail": "O Codex está fixado no proxy local, mas nenhum serviço persistente ou shim de inicializador íntegro o iniciará novamente.", + "startup.riskDetailCustomLocal": "O Codex aponta para um gateway local personalizado. O opencodex não consegue gerenciar nem verificar o ciclo de reinicialização desse gateway.", + "startup.riskDetailWindowsShim": "O shim do inicializador protege os scripts de CLI compatíveis, mas o Codex Desktop e as execuções diretas de codex.exe podem contorná-lo no Windows.", + "startup.safeDetail": "O roteamento atual e o mecanismo de inicialização são consistentes. Nenhum ocx start manual deve ser necessário após a reinicialização.", + "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": "Ativada", + "startup.disabled": "Desativada", + "startup.protection.desktop": "App desktop", + "startup.desktopHint": "Inicia no login; o app desktop supervisiona o proxy embutido. A propriedade e os processos ativos são verificados.", + "startup.desktopRecovery": "O OpenCodex é dono deste proxy. Reabra o app desktop e marque Iniciar no login. As alterações de serviço e de inicializador ficam desativadas enquanto o app desktop for o dono.", + "startup.protection.service": "Serviço em segundo plano", + "startup.protection.shim": "Shim do inicializador", + "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": "Sem suporte", + "startup.shim": "Shim do inicializador do Codex", + "startup.shimHint": "Executa ocx ensure quando um inicializador de script do Codex compatível é iniciado.", + "startup.healthy": "Íntegro", + "startup.cliOnly": "Somente 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 inicializador do Codex instalado com sucesso.", + "startup.shimRepaired": "Shim do inicializador do Codex reparado com sucesso.", + "startup.installFailed": "Falha na instalação:", + "startup.tray.title": "Bandeja do sistema do Windows", + "startup.tray.hint": "Instale um ícone de bandeja no login para iniciar, parar e reiniciar o proxy, abrir o painel e ver o status com um clique.", + "startup.tray.login": "Iniciar a bandeja no login do Windows", + "startup.tray.notProtection": "A bandeja é um controlador, não uma proteção contra reinicialização. Ainda é necessário um serviço em segundo plano viável para a recuperação autônoma do proxy.", + "startup.tray.running": "Em execução", + "startup.tray.stopped": "Instalada, oculta", + "startup.tray.stale": "Reparo necessário", + "startup.tray.notInstalled": "Não instalada", + "startup.tray.loading": "Verificando…", + "startup.tray.unavailable": "Status indisponível", + "startup.tray.install": "Instalar e mostrar a bandeja", + "startup.tray.start": "Mostrar ícone da bandeja", + "startup.tray.stop": "Sair do ícone da bandeja", + "startup.tray.uninstall": "Remover bandeja do login", + "startup.tray.error": "A ação da bandeja do Windows falhou. Consulte ocx tray status para mais 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 para executáveis do Windows.", + "startup.command.service": "Recomendado: serviço persistente em segundo plano", + "startup.command.shim": "Alternativa: shim do inicializador da CLI", + "startup.command.native": "À prova de falhas: 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 usou o Codex {version}.", + "startup.codexRuntime.clampHiddenWithEfforts": "Algumas opções de esforço de raciocínio foram ocultadas porque o OpenCodex usou o Codex {version} (removidas: {efforts}).", + "startup.codexRuntime.olderBinary": "O OpenCodex está usando um binário do Codex mais antigo ({version}). Há uma instalação mais recente disponível.", + "dash.subtitle": "Status ao vivo do proxy local do opencodex, de seus provedores e dos 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 ativo", + "dash.providers": "Provedores", + "dash.tokens30d": "Tokens (30d)", + "dash.coverage": "{pct} de cobertura", + "dash.mem.title": "Observabilidade de memória", + "dash.mem.hint": "Diagnóstico de runtime somente leitura. A memória observada é max(RSS, external, ArrayBuffers), para que o corte do working set no Windows não esconda retenção já alocada.", + "dash.mem.rss": "Conjunto residente (RSS)", + "dash.mem.jsHeap": "Heap JS em uso", + "dash.mem.jsHeapArena": "arena {total}", + "dash.mem.pressure": "Em relação ao limite de alerta", + "dash.mem.pressureOf": "{pct}% do limite", + "dash.mem.pressureUnknown": "Nenhum limite informado", + "dash.mem.jscHeap": "Heap JSC", + "dash.mem.external": "Externa", + "dash.mem.arrayBuffers": "ArrayBuffers", + "dash.mem.observed": "Observada", + "dash.mem.runtime": "Contadores de runtime", + "dash.mem.growth": "Deriva observada / hora", + "dash.mem.perHour": "/h", + "dash.mem.store": "Armazenamento de continuação", + "dash.mem.storeHint": "Cache de previous_response_id do proxy. Um total de bytes crescente com um heap crescente aponta para retenção de conversas, e não para o alocador do runtime.", + "dash.mem.storeEntries": "Entradas", + "dash.mem.storeTotal": "Total", + "dash.mem.storeLargest": "Maior", + "dash.mem.storeOldest": "Mais antiga", + "dash.mem.threshold": "Limite de alerta", + "dash.mem.lastWarn": "Último alerta", + "dash.mem.never": "Nunca", + "dash.mem.details": "Detalhes", + "dash.mem.unavailable": "Diagnóstico de memória indisponível (proxy mais antigo).", + "dash.mem.inFlight": "Requisições em andamento", + "dash.mem.restart": "Esvaziar e reiniciar", + "dash.mem.restartConfirm": "Aguarde {count} requisição(ões) em andamento e reinicie (até {seconds}s; as requisições restantes são cortadas ao esgotar o tempo).", + "dash.mem.draining": "Esvaziando {count} requisição(ões)… reiniciando ao concluir", + "dash.mem.reconnecting": "Proxy reiniciando… aguardando reconexão", + "dash.mem.restartFailed": "Falha ao esvaziar e reiniciar. Verifique se o proxy está em execução.", + "dash.mem.restartNoSupervisor": "Nenhuma proteção contra reinicialização detectada. O proxy pode permanecer parado após a reinicialização, a menos que você o inicie novamente.", + "dash.activeProviders": "Provedores ativos", + "dash.noProviders": "Nenhum provedor configurado. Execute {cmd}.", + "dash.col.name": "Nome", + "dash.col.adapter": "Adaptador", + "dash.col.baseUrl": "URL base", + "dash.col.model": "Modelo", + "dash.modelsNoResults": "Nenhum modelo corresponde à sua busca.", + "dash.availableModels": "Modelos disponíveis", + "dash.noModels": "Nenhum modelo encontrado. Verifique as chaves de API dos provedores.", + "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 parado.", + "dash.stopUnknown": "O proxy não confirmou a parada. 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 modelos do Codex", + "dash.codexRestarting": "Parando…", + "dash.codexRestartConfirm": "Parar os app-servers do Codex para que recarreguem a lista de modelos? Qualquer turno do Codex em andamento será interrompido, e o Codex não é reiniciado sozinho — reabra-o depois.", + "dash.codexRestartDone": "{count} app-server(s) do Codex parado(s). Reabra o Codex para carregar a lista de modelos atual.", + "dash.codexRestartNothing": "Nenhum app-server do Codex em execução. A próxima inicialização lerá a lista de modelos atual.", + "dash.codexRestartUnknown": "Não foi possível listar os processos, então nada foi parado.", + "dash.codexRestartPartial": "{count} app-server(s) não encerrou(aram). Pare-os manualmente se a lista de modelos continuar desatualizada.", + "dash.codexRestartFailed": "Falha ao recarregar os modelos 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á mostrando uma lista de modelos 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 inicializador instalado execute ocx ensure. Esta configuração não instala proteção contra reinicialização; confira Segurança na inicialização para ver o estado efetivo.", + "dash.searchModel": "Modelo do sidecar de busca", + "dash.searchModelHint": "Modelo usado para web_search em modelos roteados que não são da OpenAI. Requer login no ChatGPT.", + "dash.searchReasoning": "Esforço de raciocínio da busca", + "dash.visionModel": "Modelo do sidecar de visão", + "dash.visionModelHint": "Modelo usado para descrever imagens para modelos roteados somente de texto. Requer login no ChatGPT.", + "dash.webSearchSidecar": "Sidecar de busca na web", + "dash.webSearchSidecarHint": "Escolha o backend e o modelo usados para busca na web em modelos roteados.", + "dash.webSearchOff": "Desligado", + "dash.webSearchCodexSync": "Salvo. A configuração do Codex não foi reescrita — execute Sincronizar modelos para aplicá-la.", + "dash.webSearchStream": "Transmitir respostas ao vivo", + "dash.webSearchStreamHint": "Transmite ao vivo o texto inicial e o raciocínio do modelo até ele decidir por uma chamada de ferramenta; o restante do turno continua em buffer para a interceptação da 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 modelo usados para descrever imagens para modelos roteados somente de texto.", + "dash.visionOff": "Desligado", + "dash.visionAdvanced": "Configurações avançadas", + "dash.visionMaxDescriptions": "Máximo de descrições por turno", + "dash.visionMaxDescriptionsInvalid": "Informe um número inteiro positivo.", + "dash.visionTimeout": "Tempo limite", + "dash.visionTimeoutInvalid": "Informe 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 as requisições de compactação do Codex e quais gatilhos ele cobre. As mensagens seguintes 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": "Somente /compact manual", + "compactionRouting.triggersBoth": "Manual e automática", + "compactionRouting.triggersAuto": "Somente automática", + "compactionRouting.currentModel": "Usar o modelo da conversa", + "compactionRouting.currentEffort": "Manter o esforço da requisição", + "compactionRouting.effortHint": "O raciocínio se aplica onde o endpoint de compactação der suporte. O modelo precisa aceitar a conversa completa.", + "compactionRouting.dataNotice": "Uma requisição de compactação coberta envia a conversa inteira ao provedor do modelo selecionado para resumo, mesmo quando a conversa roda em outro provedor.", + "compactionRouting.autoNotice": "A compactação automática roda por conta própria, então uma conversa longa pode ser enviada a esse provedor sem que você peça.", + "compactionRouting.providerWarning": "Com esta configuração, toda requisição de compactação coberta envia o conteúdo completo da conversa para {provider} para resumo.", + "compactionRouting.comboWarning": "Com esta configuração, toda requisição de compactação coberta envia o conteúdo completo da conversa para o combo {combo} para resumo. O combo tenta seus destinos ({providers}) em ordem e usa o primeiro que responder, então qualquer um deles pode receber a conversa.", + "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 continuam aqui; tente novamente.", + "memoryModels.title": "Roteamento de memória", + "memoryModels.description": "O Codex grava memórias após o término de uma sessão. Escolha um modelo para cada fase ou mantenha a rota existente.", + "memoryModels.infoLabel": "O que são Extração e Consolidação?", + "memoryModels.info": "O Codex transforma sessões encerradas em memória em duas etapas. A Extração lê uma sessão encerrada e anota o que aconteceu: uma nota por sessão, então faz 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 próximas sessões. Roda raramente, mas edita arquivos. Cada etapa pede seu próprio modelo, por isso aparecem separadas aqui.", + "memoryModels.extract": "Extração", + "memoryModels.extractHint": "Resume cada sessão encerrada em uma memória bruta. Roda uma vez por sessão.", + "memoryModels.consolidation": "Consolidação", + "memoryModels.consolidationHint": "Mescla as memórias brutas nos arquivos de memória que o Codex lê depois. Roda raramente e edita arquivos.", + "memoryModels.model": "Modelo", + "memoryModels.effort": "Esforço de raciocínio", + "memoryModels.off": "Desativado", + "memoryModels.defaultEffort": "Padrão do Codex", + "memoryModels.dataNotice": "O modelo escolhido recebe a entrada daquela fase: a sessão encerrada na Extração e as memórias brutas na Consolidação.", + "memoryModels.accountNotice": "Somente uma fase é roteada aqui; a outra mantém a rota existente. O Shadow Call Intercept também pode enviar as chamadas de memória dessa fase ao modelo configurado nele.", + "memoryModels.loadFailed": "Não foi possível carregar as configurações de memória.", + "memoryModels.saved": "Configurações de memória salvas.", + "memoryModels.saveFailed": "Não foi possível salvar. Suas alterações continuam aqui; tente novamente.", + "dash.shadowCallIntercept": "Shadow Call Intercept", + "dash.shadowCallInterceptHint": "Intercepta as chamadas auxiliares em segundo plano do Codex App ({models}) para geração de títulos e mensagens de commit e as redireciona ao modelo escolhido.", + "dash.shadowCallWarning": "⚠ Quando ativado, TODAS as requisições para {models} serão substituídas pelo modelo selecionado.", + "dash.shadowCallOriginal": "Original", + "dash.shadowCallModel": "Modelo substituto", + "dash.shadowCallTooltip": "O Codex App faz chamadas auxiliares em segundo plano para geração de título de thread, geração de mensagem de commit e orquestração de skills. O modelo auxiliar mudou entre versões do cliente, então o opencodex intercepta todos os modelos deste conjunto: {models}. Ative para redirecionar essas chamadas ao modelo escolhido.", + "models.shadowCallIntercept": "Shadow Call Intercept", + "models.shadowCallInterceptHint": "Intercepta as chamadas auxiliares em segundo plano do Codex App ({models}) para títulos e mensagens de commit e as redireciona ao modelo escolhido.", + "dash.sidecarBackend": "Backend", + "dash.sidecarModel": "Modelo", + "dash.backendAuto": "Automático", + "dash.backendOpenAI": "OpenAI", + "dash.backendAnthropic": "Anthropic", + "dash.sidecarSaved": "Configurações do sidecar salvas. Aplicadas na próxima requisição.", + "dash.sidecarSaveFailed": "Falha ao salvar as configurações do sidecar.", + "dash.injectionLabel": "Delegação a subagentes", + "dash.injectionHint": "Escolha o modelo para o qual o Codex deve delegar o trabalho de subagentes. As duas opções abaixo definem onde essa escolha é usada.", + "dash.injectionManage": "Abrir configurações", + "dash.syncCodexSubagentDefaults": "Salvar também como padrão do Codex", + "dash.syncCodexSubagentDefaultsHint": "Ativado, a escolha acima é gravada na configuração do próprio Codex, e novas tarefas também começam com esse modelo. Desativado, ela fica salva apenas aqui. Entra em vigor na próxima sincronização ou reinicialização, e suas configurações [agents] escritas à mão são preservadas.", + "dash.multiAgentGuidance": "Orientar o Codex a dividir o trabalho", + "dash.multiAgentGuidanceHint": "Envia uma nota curta dizendo ao Codex como repassar trabalho a subagentes. Na v2, ela cita os modelos que podem ser usados e qual preferir; na v1, só se aplica com esforço de raciocínio max ou ultra. Desativado, 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 ultra na V2", + "dash.subagentEffortCapLabel": "Limite de esforço de subagentes na V2", + "dash.effortCapHelp": "Limita o esforço de raciocínio dos turnos em modo ultra da V2. Quando definido, requisições de esforço máximo (do modo ultra) são limitadas ao nível selecionado. O limite de subagentes se aplica apenas aos agentes filhos criados. Os limites só reduzem o esforço, nunca o aumentam. Se um modelo não suportar o nível limitado, ele desce 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 nova do opencodex.", + "dash.syncModels": "Sincronizar modelos", + "dash.syncModelsHint": "Reescreve o catálogo de modelos do Codex a partir dos provedores conectados.", + "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 duração dele ({cmd}).", + "dash.syncFailed": "Falha na sincronização: {error}", + "dash.projectConfigTitle": "A configuração de Codex do projeto ignora o OpenCodex", + "dash.projectConfigHint": "Estas configurações locais do repositório substituem o proxy do OpenCodex (por exemplo, roteando direto para o OpenCode Go). Remova-as para que o roteamento de ~/.codex/config.toml valha nesse projeto.", + "dash.checkUpdate": "Verificar atualização", + "dash.updateTitle": "Atualizar o opencodex", + "dash.updateDesc": "Verifica no npm o canal selecionado e depois permite escolher se o proxy será reiniciado após a instalação.", + "dash.updateChannel": "Canal", + "dash.updateChecking": "Verificando atualizações…", + "dash.updateInstalled": "Instalada", + "dash.updateLatest": "Mais recente", + "dash.updateAvailable": "Atualização disponível", + "dash.updateCurrent": "Atualizado", + "dash.updateCommand": "Comando", + "dash.updateSource": "Esta é uma cópia do código-fonte. Atualize-a pelo terminal com o comando exibido.", + "dash.updateUnavailable": "Não foi possível ler a versão mais recente no npm. Tente novamente mais tarde.", + "dash.updateRetry": "Tentar novamente", + "dash.updateRecheck": "Verificar de novo", + "dash.updateCannotAuto": "A atualização com um clique não está disponível ({reason}).", + "dash.updateReason.source_checkout": "cópia do código-fonte", + "dash.updateReason.latest_unavailable": "registro do 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 atualizar", + "dash.updateRestartHint": "Recomendado. A GUI atual continua executando o código antigo até o proxy reiniciar.", + "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 o 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 de conta", + "prov.noOauth": "Nenhum provedor OAuth disponível.", + "prov.loggedIn": "conectado", + "prov.notLoggedIn": "não conectado", + "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 usar outro perfil de navegador 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.copyCodeAndOpen": "Copiar código e abrir", + "prov.openSignInPage": "Abrir página de login", + "prov.browserLaunchFailed": "O navegador não abriu automaticamente. Abra a página de login abaixo ou copie o link.", + "prov.codeCopied": "Código copiado", + "prov.editAlias": "Editar apelido", + "prov.aliasPrompt": "Nome de exibição (deixe vazio 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 aqui (ou cole o código de autorização).", + "prov.pasteSubmit": "Enviar", + "prov.pasteSubmitting": "Enviando…", + "prov.pasteOk": "Código enviado — concluindo o login…", + "prov.pasteFail": "Não foi possível enviar o código: {error}", + "prov.port": "Porta", + "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": "O login de {provider} não conseguiu iniciar", + "prov.loginError": "Erro no login de {provider}: {error}", + "prov.loginRequestFail": "A requisição de login de {provider} falhou", + "prov.loginCancelled": "Login de {provider} cancelado", + "prov.loginTimeout": "O login de {provider} expirou — o navegador foi fechado ou o processo nunca terminou. Tente novamente.", + "prov.loginOk": "Login em {provider} concluído. Execute {cmd} (ou ele se aplica ao vivo) para listar seus modelos.", + "prov.loginSameAccount": "Ainda é a mesma conta de {provider} — troque de conta no navegador e tente adicionar a conta novamente.", + "oauthTos.highTitle": "{provider}: risco do OAuth de assinatura", + "oauthTos.elevatedTitle": "{provider}: ponte OAuth não oficial", + "oauthTos.anthropicBody": "Isto conecta uma assinatura do Claude por meio do proxy de terceiros do OpenCodex. A Anthropic não endossou esta conexão nem o pooling automatizado de contas; o acesso depende dos termos e da fiscalização vigentes.", + "oauthTos.highBody": "O OpenCodex conecta {provider} por um caminho OAuth de terceiros. O uso sem suporte pode levar a limites de acesso ou suspensão.", + "oauthTos.elevatedBody": "O OpenCodex conecta {provider} por um caminho OAuth não oficial. Use o cliente oficial sempre que 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 chave de API no OpenCodex.", + "oauthTos.acknowledge": "Entendo o risco e quero continuar com OAuth mesmo assim.", + "oauthTos.continue": "Continuar com OAuth", + "oauthTos.anthropicTitle": "Conexão de assinatura do Claude", + "oauthTos.anthropicConditions": "Use uma conta que você possua ou esteja autorizado a usar. Usar o cliente Claude Code genuíno com uma pessoa supervisionando a sessão é diferente de enviar tokens de assinatura por outros clientes. O OpenCodex também oferece suporte a esses outros clientes, portanto esta conexão não garante que todo uso seja permitido. As integrações com o Agent SDK compatíveis são tratadas à parte.", + "oauthTos.anthropicSaferPath": "Para outros clientes ou automação sem supervisão, configure uma chave de API da Anthropic.", + "oauthTos.anthropicAcknowledge": "Entendo que esta é uma conexão de assinatura de terceiros e verificarei os termos aplicáveis.", + "oauthTos.anthropicContinue": "Continuar com a assinatura do Claude", + "subagentSurface.selectionTitle": "Mudar a superfície de subagentes para {mode}?", + "subagentSurface.selectionBody": "Em {mode}, os modelos do ChatGPT que usam a superfície v2 — Sol e Terra na base, todos os modelos na v2 — entregam sua tarefa a um modelo roteado, como Grok ou Claude, criptografada para o backend do ChatGPT, e o modelo roteado não consegue lê-la. Essa delegação falha com unreadable_encrypted_agent_task até que seja corrigido upstream. A v1 delega entre provedores de forma confiável.", + "subagentSurface.advisoryTitle": "A v1 agora é a superfície de subagentes padrão", + "subagentSurface.advisoryBody": "Esta instalação roda {mode}, em que um modelo do ChatGPT na superfície v2 entrega a um modelo roteado uma tarefa criptografada que ele não consegue ler, e a delegação entre provedores falha. Recomendamos a v1 até que isso seja corrigido upstream. Sua configuração atual não muda até você escolher.", + "subagentSurface.continue": "Continuar", + "subagentSurface.switchToV1": "Mudar para a v1", + "subagentSurface.learnMore": "Por que isso falha", + "prov.logoutOk": "Sessão de {provider} encerrada.", + "prov.logoutFail": "Não foi possível sair de {provider}. O estado da sua conta não mudou.", + "prov.removed": "\"{name}\" removido.", + "prov.removedDefault": "\"{name}\" removido. O provedor padrão agora é \"{defaultProvider}\".", + "prov.removedShadowTarget": "\"{name}\" removido. O Shadow Call Intercept ainda aponta para \"{model}\", então as chamadas auxiliares vão falhar 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 pode se tornar o padrão.", + "prov.removeHasDependentCombos": "Remova ou atualize antes estes combos dependentes: {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 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": "\"{name}\" adicionado. Já está ativo — execute {cmd} (ou reinicie) para listar seus modelos no seletor do Codex.", + "prov.modelsNoticeTitle": "Escolha os modelos", + "prov.modelsNoticeChecking": "Verificando a lista de modelos. Alternar modelos não desativa o provedor.", + "prov.modelsNoticePending": "A lista inicial de modelos ainda não foi confirmada. Os modelos ficam ocultos até a descoberta terminar.", + "prov.modelsNoticeOff": "Todas as chaves de modelo foram DESLIGADAS no registro. Ative os modelos desejados na página Modelos.", + "prov.modelsNoticeReady": "Escolha quais modelos aparecem na página Modelos. Alternar modelos não desativa o provedor.", + "prov.modelsNoticeFailed": "O provedor foi salvo, mas não foi possível atualizar a lista de modelos. Tente novamente.", + "prov.modelsNoticeCount": "{count} modelos", + "prov.modelsNoticeOpen": "Abrir Modelos", + "models.initialSelectionPending": "Descoberta inicial pendente", + "prov.removeConfirm": "Remover o provedor \"{name}\"? Os modelos dele somem 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": "Ativa", + "prov.accountReauth": "Entrar de novo", + "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": "Trocado para {email}.", + "prov.accountSwitchFail": "Falha ao trocar de conta", + "prov.accountRemoved": "{email} removida.", + "prov.accountRemoveFail": "Não foi possível remover {email}. A conta não foi alterada.", + "prov.accountRemoveAria": "Remover {email}", + "prov.accountRemoveConfirm": "Remover a conta {email}? O login dela é excluído deste proxy.", + "prov.keyAdd": "Adicionar chave de API", + "prov.keyAdded": "Chave de API adicionada a {name}.", + "prov.keyAddFail": "Falha ao adicionar a chave de API", + "prov.keyPlaceholder": "Cole a chave de API", + "prov.keySwitchTitle": "Usar esta chave", + "prov.keySwitched": "Trocado para a chave {key}.", + "prov.keySwitchFail": "Falha ao trocar de chave", + "prov.keyRemoved": "Chave {key} removida.", + "prov.keyRemoveAria": "Remover a chave {key}", + "prov.keyRemoveConfirm": "Remover a chave de API {key}? Ela é excluída da configuração deste proxy.", + "prov.activeBadge": "Ativa", + "prov.disabledBadge": "Desativado", + "prov.defaultBadge": "Padrão", + "prov.enable": "Habilitar", + "prov.disable": "Desabilitar", + "prov.enabled": "\"{name}\" habilitado. Seus modelos podem voltar a aparecer no Codex.", + "prov.disabled": "\"{name}\" desabilitado. As configurações são mantidas, mas os modelos ficam ocultos.", + "prov.disabledShadowTarget": "\"{name}\" desabilitado. O Shadow Call Intercept ainda aponta para \"{model}\", então as chamadas auxiliares vão falhar até você escolher outro destino ou reabilitar \"{name}\".", + "prov.enableFail": "Falha ao habilitar \"{name}\".", + "prov.disableFail": "Falha ao desabilitar \"{name}\".", + "prov.enableAria": "Habilitar o provedor {name}", + "prov.disableAria": "Desabilitar o provedor {name}", + "prov.defaultCannotDisable": "O provedor padrão não pode ser desabilitado", + "prov.openaiAccountMode": "Modo de conta do Codex", + "prov.openaiModePool": "Pool", + "prov.openaiModeDirect": "Direto", + "prov.openaiPoolDesc": "Padrão. Alterna entre o login principal e as contas adicionadas usando afinidade, cota, cooldown e failover.", + "prov.openaiDirectDesc": "Usa somente o login atual/principal do Codex. As contas armazenadas no pool não são lidas nem alternadas.", + "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 as credenciais da 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 destinos com failover ou distribua a carga com uma estratégia de balanceamento.", + "models.subtitle.compatibility": "Matriz somente leitura de veredictos de compatibilidade, com base em evidências de projeção de laboratório.", + "models.subtitle.routing": "Perfis de política, avaliação em modo de simulação (dry-run) e análises de roteamento com base em fontes.", + "models.subtitle": "Alterne quais modelos o Codex enxerga — passthrough nativo do GPT e provedores roteados, agrupados por provedor (clique em um cabeçalho para recolher). Modelos ocultos ficam fora do catálogo e do seletor de modelos, mas continuam acessíveis diretamente pelo id exato.", + "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 {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 entrega ao Codex, que é a lista exibida no seletor de modelos do Codex. A confirmação após salvar significa que esta 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, então salvar aqui altera o catálogo do hub. A confirmação após salvar significa que o hub o recebeu; esta máquina ainda precisa baixá-lo.", + "models.delivery.synced.title": "Sincronizado nesta máquina", + "models.delivery.synced.bodyAt": "Esta máquina baixou o catálogo do hub pela última vez em {time} e o gravou onde o Codex 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": "Esta máquina ainda não tem registro de download do catálogo do hub, então o Codex pode estar lendo uma lista antiga. A próxima sincronização fará o download.", + "models.delivery.loaded.title": "Carregado pelo Codex", + "models.delivery.loaded.body": "O Codex lê o catálogo ao iniciar, então uma janela do Codex que já estava aberta mantém a lista de modelos antiga. O OpenCodex não consegue ver dentro de um Codex em execução para saber qual lista ele usa. Quando consegue perceber que o Codex iniciou antes da sua alteração, um aviso de reinicialização 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 reabra o Codex.", + "models.nativeGroupLabel": "OpenAI nativo", + "models.nativeHint": "Os modelos em passthrough usam a opção de conta Pool ou Direto selecionada em Provedores. Desativar um deles o oculta do seletor do Codex (a entrada do catálogo é mantida, então reativar restaura exatamente como estava). Adicionar um modelo aqui registra um seletor roteado `openai/`, não um novo id de passthrough simples.", + "models.active": "{active}/{total} visíveis", + "models.workspace.providers": "Provedores", + "models.workspace.allProviders": "Todos os provedores", + "models.workspace.mainAria": "Detalhes do modelo", + "models.allOn": "Ativar todos", + "models.allOff": "Desativar todos", + "models.presetLabel": "Modelos", + "models.presetMode_preset": "Preset", + "models.presetMode_all": "Todos", + "models.presetMode_custom": "Personalizado", + "models.presetSummary": "{count} de {total} exibidos — preset básico v{version}", + "models.presetUpdateAvailable": "Preset v{version} disponível", + "models.presetAppliedToast": "{provider}: preset aplicado — {count} modelos selecionados", + "models.presetClearedToast": "{provider}: exibindo todos os modelos", + "models.presetEmpty": "{provider}: o preset não correspondeu a nenhum modelo — seleção inalterada", + "models.presetConfirmReplace": "Substituir sua seleção pelo preset de {count} modelos?", + "models.cap350k": "Limite de 350k", + "models.capApplied": "Limite de contexto aplicado — vale a partir do próximo turno do Codex.", + "models.capSaveFailed": "Falha ao salvar o limite de contexto", + "models.contextCapped": "limite de 350k", + "models.contextCapLabel": "Janela padrão / limite", + "models.v2Label": "Subagente", + "models.shadowCallOriginal": "{models} →", + "models.v2DocsLink": "O que são v1 / v2?", + "models.v2Mode_v1": "v1", + "models.v2Mode_default": "base", + "models.v2Mode_v2": "v2", + "models.v2ModeDesc_v1": "Todos os modelos → superfície v1", + "models.v2ModeDesc_default": "Padrões do upstream (sol/terra=v2, luna=v1)", + "models.v2ModeDesc_v2": "Todos os modelos → superfície v2", + "models.keepNativeOnV1": "Manter o ChatGPT na v1", + "models.keepNativeOnV1Hint": "O ChatGPT só criptografa as tarefas filhas da v2 quando um pai nativo do ChatGPT permanece na v2, então Grok e Claude não conseguem lê-las. Ative para manter Sol/Terra na v1 e evitar essa criptografia. Pais roteados continuam na v2.", + "models.v2Help": "Controla a superfície multiagente para todos os modelos.\n\nv1: agente clássico de thread única. Todos os modelos usam a superfície collab da v1.\nbase: padrões do upstream — sol/terra usam a v2, luna usa a v1, os demais seguem a feature flag do codex.\nv2: agente multithread com spawn_agent. Todos os modelos usam a superfície collab da v2.\n\nNa v2, Manter o ChatGPT na v1 deixa Sol/Terra na superfície v1 para que ainda possam acionar Grok ou Claude. O ChatGPT criptografa as tarefas filhas da v2; modelos roteados não conseguem lê-las. Pais roteados permanecem na v2.\n\nAs alterações valem para novas sessões.", + "dash.multiAgent": "Subagente", + "dash.codexDesktopAuthless": "Abrir o Codex sem fazer login", + "dash.codexDesktopAuthlessHint": "Desativado por padrão. Dispensa o login separado do Desktop em conexões locais elegíveis. As credenciais upstream continuam sendo necessárias. Reinicie o Codex após alterar esta configuração. Recursos do Desktop que dependem de conta podem ficar indisponíveis.", + "dash.codexClientCompaction": "Usar compactação no cliente", + "dash.codexClientCompactionHint": "Desativado por padrão; somente loopback autenticado. As próximas compactações armazenam resumos portáveis em texto simples enquanto o roteamento de provedores do OpenCodeX e da V2 permanece ativo; o provedor configurado pode processá-los e consumir cota. O histórico não é alterado, e as threads existentes continuam roteando pelo proxy por meio do override openai_base_url gerenciado pelo OpenCodeX; se você definir essa linha manualmente, ela é mantida, e essas threads seguem o seu destino. O histórico ocx1 existente continua recuperável; recupere uma thread separadamente apenas antes de reproduzi-la no Codex nativo. Reinicie o Codex após alterar esta configuração.", + "dash.codexRemoteHistoryHint": "O roteamento por tabela de provedores pode ocultar threads existentes marcadas como openai em algumas listas remotas do celular. O histórico não é excluído. O cliente remoto precisa listar todos os provedores; esta opção não corrige o filtro desse cliente.", + "models.v2Conflict": "[agents] max_threads está definido — o codex se recusará a iniciar; remova-o do config.toml", + "models.v2Applied": "Modo de subagente atualizado — vale para novas sessões (reinicie o app do Codex para atualizar o seletor)", + "models.v2ThreadsLabel": "Máx. de threads", + "models.v2ThreadsDefault": "padrão (4)", + "models.v2ThreadsApplied": "Limite de threads atualizado — vale para novas sessões", + "models.v2ThreadsInvalid": "O limite de threads deve ser um 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": "Modelo", + "models.contextModelOverride": "Substituição do modelo", + "models.contextHint": "Informe aqui a janela real do Codex quando já a conhecer. Isso preenche uma janela upstream ausente e só reduz uma janela maior informada. Deixe em branco para usar a Janela padrão / limite do provedor, ou 128k se esse limite estiver desativado.", + "models.contextAutomatic": "Descoberta automática", + "models.contextSaved": "Janelas de contexto atualizadas — valem a partir do próximo turno do Codex.", + "models.contextUnchanged": "Nenhuma alteração de 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 para todos", + "models.setAllHint": "Ativa a janela padrão de {value} para todos os provedores roteados. Relays que omitem context_window / context_length recebem este valor como a janela real do Codex. Use Janelas personalizadas na linha de um provedor para ajustar 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 ordenação por provedor/modelo para linhas roteadas empatadas. Uma ordem salva do seletor pode sobrepor a ordem de exibição; as chaves de visibilidade filtram quais linhas aparecem. Um cliente pode manter um catálogo antigo até buscá-lo novamente.", + "models.settingsPanel.title": "Configurações do modelo", + "models.settingsPanel.off": "desativado", + "models.settingsPanel.attention": "Requer atenção", + "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}", + "models.settingsTitle": "Editar modelo — {model}", + "models.settingsContextInherit": "Sem substituição — atualmente {value}", + "models.settingsContextUnknown": "desconhecido", + "models.settingsReload": "Recarregar", + "models.settingsReloaded": "Lista de modelos recarregada. Reabra {model} para ver os valores armazenados.", + "models.settingsNoChange": "Nenhuma configuração alterada para {model}", + "models.settingsSaved": "Configurações do modelo salvas para {model}", + "models.settingsSaveFailed": "Não foi possível confirmar se as configurações foram salvas. Recarregue a lista de modelos antes de tentar novamente.", + "models.settingsRefreshFailed": "Salvo. A lista de modelos não foi recarregada, então a linha pode mostrar valores antigos. Recarregue para conferir.", + "models.settingsSavedCodexStale": "{model} salvo, mas o catálogo de modelos do Codex não foi atualizado. Clique em Sincronizar agora no Painel para o Codex receber a alteração.", + "models.settingsRejected": "O servidor rejeitou estas configurações, então nada foi salvo. Confira os valores e tente novamente.", + "models.settingsDefaultEffort": "Nível padrão", + "models.settingsModalitiesInherit": "Sem substituição — seguindo atualmente a declaração do upstream: {modalities}", + "models.settingsModalitiesUnknown": "não declarado", + "models.settingsRestore": "Restaurar", + "models.settingsRestoreHint": "Limpa todas as substituições deste modelo e volta aos valores calculados.", + "models.settingsRestoreConfirm": "Restaurar {model} para os valores calculados? Isso limpa as substituições de janela de contexto, modalidade e raciocínio.", + "models.settingsRestored": "{model} restaurado para os valores calculados", + "models.settingsNothingToRestore": "{model} não tem substituições; já está nos valores calculados", + "pws.manageModelVisibility": "Gerenciar visibilidade em Modelos", + "pws.modelOwnershipLoading": "Verificando as definições de modelos…", + "pws.modelOwnershipFailed": "Não foi possível carregar as definições de modelos. 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 a atualização 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 a atualização 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 a visibilidade dele em 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 de {name}? Um modelo nativo ou descoberto subjacente pode voltar a aparecer.", + "models.hide": "Ocultar", + "models.hideConfirm": "Ocultar {name} do catálogo de modelos? Isso não remove a definição nem altera a política de roteamento direto.", + "models.customBadge": "Personalizado", + "models.customSummary": "{count} personalizado(s)", + "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 o 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": "Provedor", + "models.tipContext": "Contexto", + "models.tipModalities": "Modalidades", + "models.tipStatus": "Status", + "models.tipActive": "Ativo", + "models.tipDisabled": "Desativado", + "models.applied": "Salvo. O Codex mostra a alteração depois de recarregar a lista de modelos.", + "models.integrationRefreshWarning": "Seleção de modelos salva. Alguns catálogos de clientes não puderam ser atualizados. Verifique Integrações antes de iniciar uma nova sessão.", + "models.saveFailed": "Falha ao salvar", + "models.networkError": "Erro de rede — o proxy está em execução?", + "models.loadFail": "Falha ao carregar os modelos — o proxy está em execução?", + "models.noRouted": "Nenhum modelo roteado", + "models.noRoutedHint": "Faça login em um provedor ou adicione um primeiro.", + "models.emptyDiscovery": "Nenhum modelo foi descoberto. Verifique o endpoint do provedor ou adicione um modelo estático/personalizado.", + "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 do destino.", + "models.discoveryFailedInvalidResponse": "A descoberta de modelos retornou uma resposta inválida.", + "models.discoveryFailedNetwork": "A descoberta de modelos falhou por erro de rede.", + "models.discoveryFailedProvider": "O provedor informou um erro na descoberta de modelos.", + "models.discoveryFailedGeneric": "A descoberta de modelos falhou.", + "models.openProviderSettings": "Abrir configurações do provedor", + "models.inactiveNoCredit": "Sem crédito", + "models.inactiveNoCreditHint": "Todos os provedores por trás desta entrada estão sem crédito no momento, então uma requisição falharia. Ela continua listada e volta a ser utilizável quando o crédito for renovado ou recarregado.", + "models.discoveryFailedDependency": "A descoberta de modelos está ativada para este provedor. Enquanto continuar falhando, desative “{control}” nas configurações do provedor para usar modelos adicionados manualmente ou estáticos.", + "models.loading": "Carregando…", + "models.search": "Buscar modelos…", + "models.showMore": "Mostrar mais {n}", + "models.freeOnly": "Somente gratuitos", + "models.noFreeMatch": "Nenhum modelo gratuito aqui. Desative “Somente gratuitos” para ver os demais.", + "models.allowlistLabel": "Somente selecionados", + "models.allowlistHint": "Somente os modelos marcados vão para o catálogo (vazio = todos). Útil para provedores que expõem milhares de modelos.", + "models.selectedCount": "{n} selecionados", + "sub.subtitle": "O {cmd} do Codex anuncia apenas os 5 primeiros modelos (por prioridade) como substituições. Escolha até 5 aqui — gpt nativo ou roteado — e o opencodex define a prioridade deles no catálogo para que exatamente esses fiquem à frente. Qualquer outro modelo continua acessível pelo nome exato; isto controla apenas o que é exibido.", + "sub.featured": "Em destaque", + "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 modelos padrão candidatos para {cmd}.", + "sub.noneSelected": "Nenhum selecionado — escolha na lista abaixo.", + "sub.models": "Modelos", + "sub.search": "Buscar modelos (gpt nativo + roteados)…", + "sub.settings": "Configurações", + "sub.sections": "Seções de subagentes", + "sub.delegation.model": "Modelo a chamar primeiro", + "sub.delegation.modelHint": "O modelo que o Codex aciona primeiro ao delegar trabalho. “Em destaque” acima é a lista que ele pode chamar; este é o que ele chama primeiro.", + "sub.suggest.button": "Sugerir", + "sub.suggest.label": "Trabalho delegado", + "sub.suggest.placeholder": "O que o Codex costuma delegar? Ex.: buscas somente leitura em todo o repositório ou refatorações em vários módulos", + "sub.suggest.submit": "Dimensionar", + "sub.suggest.running": "Dimensionando…", + "sub.suggest.failed": "Não foi possível dimensionar o trabalho delegado.", + "sub.suggest.title": "Modelo sugerido", + "sub.suggest.accept": "Usar este", + "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 (ou execute {cmd}) para vê-los como substituições de spawn_agent.", + "sub.saveFailed": "Falha ao salvar", + "sub.networkError": "Erro de rede — o proxy está em execução?", + "sub.loadFail": "Falha ao carregar os modelos — o proxy está em execução?", + "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": "Fora dos destaques", + "sub.workspace.priority": "Prioridade", + "sub.ultraMode": "Delegação sempre proativa", + "sub.ultraModeHint": "Ativa a política de delegação multiagente proativa para todos os modelos e esforços de raciocínio (não altera o esforço de raciocínio em si). Grava features.multi_agent_v2.multi_agent_mode_hint_text no config.toml.", + "sub.ultraModeV2Required": "Requer a superfície multiagente v2 — ative multi_agent_v2 e selecione v2 no controle de modo de subagente primeiro.", + "sub.ultraModeText": "Texto da delegação proativa", + "sub.ultraModePreset": "Restaurar predefinição", + "sub.ultraModeLoadFail": "Falha ao carregar as configurações de delegação proativa — o proxy está em execução?", + "sub.ultraModeSaveFail": "Falha ao salvar as configurações de delegação proativa", + "sub.ultraModeSaved": "Delegação proativa salva. Vale para novas sessões do Codex.", + "sub.workspace.removeFromFeatured": "Remover {m} dos destaques", + "sub.workspace.selectModel": "Selecione um modelo", + "sub.workspace.selectModelDesc": "Escolha um modelo na lista para ver os detalhes e colocá-lo em destaque para o spawn_agent.", + "sub.workspace.selector": "Seletor público", + "sub.fallbackLabel": "Cadeia de fallback de subagente", + "sub.fallbackHint": "Modelos tentados, em ordem, quando o modelo do subagente estiver indisponível ou falhar.", + "sub.fallbackAdd": "Adicionar modelo de fallback…", + "sub.fallbackPoll": "Intervalo de verificação de disponibilidade", + "sub.fallbackSaved": "Configurações de fallback de subagente salvas.", + "sub.fallbackSaveFailed": "Falha ao salvar as configurações de fallback", + "sub.fallbackUnavailable": "Não anunciado no momento; mantido na cadeia.", + "sub.fallbackPollInvalid": "Informe 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 a este modelo roteado usando V2, a tarefa pode ser criptografada e falhar antes da execução. Tarefas legíveis vindas de pais roteados não são afetadas.", + "sub.v2Compatibility.recoveryUnknown": "O estado de recuperação ativada/elegibilidade não é exposto por este servidor. Use delegação V1/compatível com texto simples, ou ative a recuperação V2 experimental somente se elegível. A recuperação adiciona consumo de cota, latência, dependência do backend e possível perda de fidelidade; ela não corrige o protocolo upstream.", + "sub.v2Compatibility.details": "Detalhes de compatibilidade", + "logs.title": "Logs de requisições", + "logs.tabLogs": "Logs", + "logs.tabDebug": "Debug", + "logs.subtitle": "Requisições recentes roteadas pelo proxy local do opencodex, das mais novas para as mais antigas.", + "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": "Superfície", + "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 h", + "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": "Limpar filtros", + "logs.filter.showingCount": "Exibindo {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": "Somente auxiliares interceptados", + "logs.badge.interceptedHelper": "I · {model}", + "logs.badge.interceptedHelperTitle": "Requisição de auxiliar interceptada", + "logs.filter.conversation.label": "Conversa", + "logs.filter.conversation.placeholder": "Cole o ID da conversa", + "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 buffer de logs atualmente carregado.", + "logs.conversation.excluded": "({unpriced} sem preço, {unmetered} sem medição excluídas do ~$)", + "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": "Hora", + "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 saída 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 sem correspondência ficam indisponíveis", + "usage.cost.total": "Equivalente ao preço de tabela da API (este período)", + "usage.cost.disclaimer": "Não é um comprovante de cobrança. Pode valer o uso da assinatura ou créditos do provedor.", + "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": "Selecionado", + "logs.detail.route.candidates": "Candidatos", + "logs.detail.route.unknown": "Nenhum rastreio de rota registrado para esta requisição (linha anterior ao rastreio).", + "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": "Repassado", + "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": "Wire 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 do 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 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, curta demais para estimar a 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 correspondente", + "logs.detail.priceSource": "Fonte 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": "Sobreposição de preço esperado", + "logs.detail.source.user": "Sobreposição de preço configurada no 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ída", + "logs.detail.attempt.e2eNote": "O tok/s de nível superior é ponta a ponta; cada tentativa usa sua própria duração.", + "logs.detail.attempt.recovery.transient5xx": "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 (429)", + "logs.detail.attempt.recovery.rateLimit429": "Limite de taxa (429)", + "logs.detail.attempt.recovery.anthropicOauth429": "OAuth da Anthropic com limite de taxa (429)", + "logs.detail.attempt.recovery.image413": "Payload de imagem grande demais (413)", + "logs.detail.attempt.recovery.emptyCompletion": "Nova tentativa por conclusão vazia", + "logs.detail.attempt.recovery.consoleGoUpload": "Nova tentativa de upload no console", + "logs.detail.attempt.recovery.key401": "Reautenticação da chave de API", + "logs.detail.attempt.recovery.oauthAccount403": "Validação da conta necessária (403)", + "logs.detail.attempt.recovery.oauthAccount429": "Conta com limite de taxa (429)", + "logs.detail.attempt.recovery.opaqueBlobRejection": "Estado criptografado obsoleto descartado", + "logs.detail.attempt.recovery.reasoningEffortDowngrade": "Esforço de raciocínio reduzido", + "logs.detail.attempt.recovery.anthropicFastDowngrade": "Modo rápido recusado, repetido em velocidade padrão", + "logs.detail.outcome.label": "Resultado", + "logs.detail.outcome.completed": "Concluída", + "logs.detail.outcome.failed": "Falhou", + "logs.detail.outcome.incomplete": "Incompleta", + "logs.detail.outcome.aborted": "Abortada", + "logs.detail.sends.label": "Envios 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": "chegou a", + "logs.detail.resend.label": "Reenvio", + "logs.detail.cause.transportUnsent": "Nunca enviada ao upstream", + "logs.detail.cause.transportAmbiguous": "Conexão perdida, estado do upstream desconhecido", + "logs.detail.cause.upstreamDeclined": "O upstream recusou iniciar", + "logs.detail.cause.rateLimit": "Limite de taxa atingido", + "logs.detail.cause.quotaExhausted": "Cota esgotada", + "logs.detail.cause.credentialRejected": "Credenciais rejeitadas", + "logs.detail.cause.policyRefusal": "Recusada 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 grande demais", + "logs.detail.cause.payloadRejected": "Payload rejeitado", + "logs.detail.cause.upstreamFault": "Falha do upstream", + "logs.detail.cause.emptyOutput": "Nenhuma saída utilizável", + "logs.detail.cause.clientCancelled": "Cancelada pelo cliente", + "logs.detail.cause.localRefusal": "Recusada por este proxy", + "logs.detail.stage.preHeader": "sem cabeçalho de resposta", + "logs.detail.stage.headersOnly": "somente cabeçalhos", + "logs.detail.stage.protocolPrelude": "preâmbulo do protocolo", + "logs.detail.stage.semanticOutput": "saída entregue", + "logs.detail.stage.sideEffect": "efeito colateral emitido", + "logs.detail.stage.terminal": "resposta entregue", + "logs.detail.resend.permitted": "Poderia ser reenviada", + "logs.detail.resend.permittedAfterRepair": "Poderia ser reenviada após reparo", + "logs.detail.resend.refusedAmbiguous": "Não reenviada: estado do upstream desconhecido", + "logs.detail.resend.refusedCommitted": "Não reenviada: o chamador já viu a saída", + "logs.detail.resend.refusedFutile": "Não reenviada: a mesma requisição falharia de novo", + "logs.detail.reason.usage_missing": "O uso não foi informado.", + "logs.detail.reason.usage_unsupported": "Este provedor não informa o uso.", + "logs.detail.reason.output_missing": "Nenhuma contagem positiva de tokens de saída foi informada.", + "logs.detail.reason.invalid_duration": "A duração da requisição não é válida.", + "logs.detail.reason.price_unmatched": "Nenhum preço correspondente foi encontrado.", + "logs.detail.reason.invalid_cache_breakdown": "Os detalhes de tokens de cache conflitam com o total de tokens de entrada.", + "logs.detail.reason.invalid_usage": "O uso contém um valor de token inválido.", + "logs.detail.reason.combo_attempt_unavailable": "Pelo menos uma tentativa do combo não pôde ser precificada.", + "logs.detail.estimate.usage_estimated": "O uso do provedor é estimado.", + "logs.detail.estimate.cache_detail_missing": "Os detalhes de cache estavam indisponíveis; a entrada é uma estimativa de limite superior.", + "logs.detail.estimate.expected_price_overlay": "Foi usado um preço de tabela esperado verificado.", + "logs.detail.estimate.provider_cost_overlay": "Foi usada uma sobreposição de preço configurada no provedor.", + "logs.detail.estimate.priority_lower_bound": "O preço Priority confirmado está indisponível; a estimativa exibida é um limite inferior conhecido.", + "logs.col.error": "Erro", + "logs.col.upstreamReason": "Motivo do upstream", + "logs.col.duration": "Duração", + "logs.modelTooltip.model": "modelo", + "logs.modelTooltip.resolvedModel": "modelo resolvido", + "logs.modelTooltip.servedModel": "modelo atendido", + "logs.modelTooltip.wireModel": "modelo no wire", + "logs.modelRerouteTitle": "O upstream atendeu um modelo diferente do enviado", + "logs.modelTooltip.requestedTier": "nível solicitado", + "logs.modelTooltip.configuredTier": "nível configurado", + "logs.modelTooltip.responseTier": "nível da resposta", + "logs.modelTooltip.supportsTier": "suporte a nível", + "logs.modelTooltip.tierOutcome.confirmed": "confirmado", + "logs.modelTooltip.tierOutcome.assumed": "presumido", + "logs.modelTooltip.tierOutcome.downgraded": "rebaixado", + "logs.modelTooltip.tierOutcome.unknown": "desconhecido", + "logs.tokens.reported": "informado", + "logs.tokens.unreported": "não informado", + "logs.tokens.unsupported": "não suportado", + "logs.tokens.estimated": "estimado", + "logs.tokens.input": "entrada", + "logs.tokens.output": "saída", + "logs.tokens.cacheRead": "leitura de cache (c)", + "logs.tokens.cacheWrite": "gravação de cache (w)", + "logs.tokens.reasoning": "raciocínio", + "logs.tokens.noCache": "sem dados de cache", + "logs.tokens.contextTotal": "contexto ativo", + "logs.tokens.noCacheNote": "este provedor não informa tokens de cache", + "logs.tokens.noCacheCursor": "Detalhe de cache do Cursor não informado", + "logs.tokens.noCacheCursorNote": "O Cursor não expõe as contagens de tokens de leitura/gravação de cache; isso é desconhecido, não um cache miss confirmado", + "logs.tokens.estimatedNote": "estimado (o provedor não informa o uso exato)", + "logs.details": "Detalhes", + "logs.detailTitle": "Detalhes da requisição", + "logs.detailRaw": "Entrada de log bruta", + "debug.title": "Debug", + "debug.subtitle": "Diagnósticos opcionais de transporte do provedor e de extração de uso. Erros de requisição e 502 permanecem na aba Logs.", + "debug.debug": "Debug do provedor", + "debug.usage": "Extração de uso", + "debug.injection": "Log de injeção", + "debug.claude": "Entrada do Claude", + "debug.claudeInbound.title": "Requisições de entrada do Claude", + "debug.claudeInbound.sub": "O que o Claude Code/Desktop realmente envia (thinking, esforço, 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": "Hora", + "debug.claudeInbound.endpoint": "Endpoint", + "debug.claudeInbound.model": "Modelo", + "debug.claudeInbound.none": "nenhum", + "debug.reset": "Limpar substituições em tempo de execução", + "debug.refresh": "Atualizar", + "debug.follow": "Acompanhar", + "debug.streamProvider": "Provedor", + "debug.streamUsage": "Uso", + "debug.streamInjection": "Injeção", + "debug.loading": "Carregando configurações de debug…", + "debug.loadFailed": "Não foi possível carregar as configurações de debug.", + "debug.emptyTitle": "O log de debug está desativado", + "debug.empty": "Ative Debug do provedor ou Extração de uso no cartão acima. As linhas aparecem aqui depois que você enviar uma requisição pelo proxy.", + "debug.noLinesTitle": "Aguardando linhas", + "debug.noLines.provider": "O debug do provedor está ativado, mas registra apenas anomalias de transporte (frames descartados ou malformados e eventos de conexão/nova tentativa do Cursor). Uma requisição normal por um provedor como a Anthropic pode não gerar nenhuma linha.", + "debug.noLines.usage": "A extração de uso está ativada, mas nada foi capturado ainda. Envie um chat/requisição pelo Codex e ele aparecerá aqui.", + "debug.noLines.injection": "O log de injeção está ativado, mas nada foi capturado ainda. Ele registra a injeção de orientação multiagente e as decisões de limite de esforço em turnos de colaboração e de subagentes.", + "usage.title": "Uso", + "usage.subtitle": "Contabilização local de tokens do seu proxy. O uso ausente nunca é exibido como zero.", + "usage.loading": "Carregando dados de uso…", + "usage.empty": "Nenhum uso registrado ainda. Envie uma requisição pelo proxy para ver a atividade aqui.", + "usage.loadError": "Não foi possível carregar os dados de uso.", + "usage.range.all": "Tudo", + "usage.range.available": "Histórico disponível", + "usage.historyTruncated": "Os totais cobrem apenas o histórico disponível porque o uso mais antigo não foi carregado.", + "usage.historyTruncatedWindow": "As linhas carregadas têm horários de início de requisição entre {start} e {end}. Entradas anteriores do arquivo foram omitidas pelo limite de leitura, então qualquer período selecionado pode estar incompleto.", + "usage.range.30d": "30d", + "usage.range.7d": "7d", + "usage.card.requests": "Requisições", + "usage.card.measured": "Medidas", + "usage.card.reported": "Informadas", + "usage.card.totalTokens": "Total de tokens", + "usage.card.cachedTokens": "Leituras de cache", + "usage.card.cachedTokensHint": "Tokens do prompt atendidos pelo cache do provedor (leituras). As gravações de cache aparecem abaixo quando houver.", + "usage.card.cacheWriteTokens": "gravações de 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": "Modelos", + "usage.section.providers": "Provedores", + "usage.section.coverage": "Detalhamento da 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 app desktop/de barra de menus do OpenCodex 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 companion indisponíveis", + "usage.companion.corrupt": "O arquivo de configurações do companion está corrompido. Os controles mostram os padrões; o salvamento fica pausado até você substituir o arquivo.", + "usage.companion.corruptReset": "Substituir pelos padrões", + "usage.companion.connected": "App da barra de menus conectado · {age}", + "usage.companion.connectedDesktop": "App desktop conectado · {age}", + "usage.companion.installTitle": "Instalar o app desktop", + "usage.companion.installOs": "Sistema operacional", + "usage.companion.osMac": "macOS", + "usage.companion.osWindows": "Windows", + "usage.companion.osLinux": "Linux", + "usage.companion.runningInDesktop": "Você está no app desktop do OpenCodex {version}", + "usage.companion.openInBrowser": "Abrir no navegador", + "usage.companion.installMacStep1": "Baixe OpenCodex--macos.dmg da versão mais recente e arraste OpenCodex.app para Aplicativos.", + "usage.companion.installMacStep2": "Primeira execução: clique com o botão direito em OpenCodex.app → Abrir (o Gatekeeper pergunta uma vez até o app ser notarizado).", + "usage.companion.installMacStep3": "O app encontra este proxy sozinho; o widget aparece na galeria de widgets depois que o app for executado.", + "usage.companion.installWinStep1": "Baixe OpenCodex--windows-x64.msi da versão mais recente e execute-o.", + "usage.companion.installWinStep2": "Se o SmartScreen avisar, 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 embutido.", + "usage.companion.installLinuxStep1": "Baixe OpenCodex--linux-x86_64.AppImage (ou o .deb) da versão mais recente.", + "usage.companion.installLinuxStep2": "Use chmod +x no AppImage e execute-o; o ícone na bandeja exige um desktop compatível com AppIndicator.", + "usage.companion.installLinuxStep3": "O app se conecta a este proxy ou inicia o proxy embutido.", + "usage.companion.notConnected": "Nenhum app da barra de menus se conectou a este proxy ainda.", + "usage.companion.lastSeen": "Visto pela última vez {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 app consulta o proxy.", + "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": "Somente ícone", + "usage.companion.window": "Janela", + "usage.companion.window6": "6h", + "usage.companion.window24": "24h", + "usage.companion.window72": "3d", + "usage.companion.window168": "7d", + "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áx.", + "usage.companion.menuText": "Texto da barra de menus", + "usage.companion.placeholders": "Marcadores:", + "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 uso", + "usage.workspace.sections": "Seções de uso", + "usage.coverage.measured": "Medido", + "usage.coverage.reported": "Informado pelo provedor", + "usage.coverage.estimated": "Estimado", + "usage.coverage.note": "As entradas medidas incluem contagens de tokens informadas pelo provedor e estimadas. Requisições sem informação ou sem suporte são registradas, mas nunca contabilizadas como zero token.", + "usage.search.models": "Buscar modelos…", + "usage.col.requests": "Requisições", + "usage.col.measured": "Medido", + "usage.col.reported": "Informado", + "usage.col.inputTokens": "Tokens de entrada", + "usage.col.outputTokens": "Tokens de saída", + "usage.col.cacheHits": "Acertos de cache", + "usage.col.cacheWrites": "Gravações em cache", + "usage.col.cacheHitRate": "Taxa de acerto", + "usage.cacheHitRate.partial": "Média sobre {measured} de {total} tokens de entrada; as demais requisições não informaram detalhes de cache.", + "usage.cacheHitRate.unmeasured": "Nenhuma requisição desta linha informou detalhes de cache, então não há taxa de acerto para calcular a média.", + "usage.unavailable": "—", + "usage.col.tokens": "Tokens", + "usage.col.apiListPrice": "Preço de tabela 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} requisiçõ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} requisições", + "nav.storage": "Armazenamento", + "storage.title": "Armazenamento", + "storage.subtitle": "Veja o que está ocupando o CODEX_HOME. A limpeza nunca afeta sessões ativas.", + "storage.loading": "Analisando o armazenamento…", + "storage.empty": "CODEX_HOME está vazio ou ausente — nada a relatar.", + "storage.error": "Falha na análise do armazenamento. Verifique se CODEX_HOME aponta para um diretório válido.", + "storage.refresh": "Reanalisar", + "storage.rescanned": "Análise concluída.", + "storage.card.total": "Tamanho total", + "storage.card.files": "Arquivos", + "storage.card.home": "CODEX_HOME", + "storage.snapshot.lastScan": "Última análise", + "storage.snapshot.scanning": "Analisando…", + "storage.snapshot.unavailable": "Nenhuma análise 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": "Categorias", + "storage.section.largest": "Maiores arquivos", + "storage.workspace.overview": "Visão geral", + "storage.workspace.selectBucket": "Selecione uma categoria na lista para ver o detalhamento.", + "storage.col.bucket": "Categoria", + "storage.col.size": "Tamanho", + "storage.col.files": "Arquivos", + "storage.col.oldest": "Mais antigo", + "storage.col.newest": "Mais recente", + "storage.col.rows": "Linhas do BD", + "storage.rows.unknown": "desconhecido (bloqueado)", + "storage.bucket.sessions": "Sessões ativas", + "storage.bucket.archived_sessions": "Sessões arquivadas", + "storage.bucket.logs_db": "Banco de logs", + "storage.bucket.state_db": "Banco de estado", + "storage.bucket.attachments": "Anexos", + "storage.bucket.deletion_manifests": "Manifestos de exclusão", + "storage.bucket.other": "Outros", + "storage.cleanup.title": "Limpeza de arquivados", + "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 são movidos para CODEX_HOME/.trash.", + "storage.cleanup.slider": "Porcentagem dos arquivados mais antigos", + "storage.cleanup.percent": "{percent}%", + "storage.cleanup.preset": "{percent}", + "storage.cleanup.preview": "Pré-visualizar", + "storage.cleanup.confirmTitle": "Confirmar limpeza de arquivados", + "storage.cleanup.confirmBody": "Isto processará {count} arquivo(s) arquivado(s) (~{size}), os {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 são movidos para .trash em CODEX_HOME. Você pode restaurá-los na aba Quarentena.", + "storage.cleanup.cancel": "Cancelar", + "storage.cleanup.confirmQuarantine": "Colocar em quarentena", + "storage.cleanup.confirmPermanent": "Excluir permanentemente", + "storage.cleanup.doneQuarantine": "{count} arquivo(s) em quarentena ({size}).", + "storage.cleanup.donePermanent": "{count} arquivo(s) excluído(s) permanentemente ({size}).", + "storage.cleanup.skippedReferenced": "{count} arquivo(s) referenciado(s) ignorado(s).", + "storage.cleanup.previewFailed": "Falha na pré-visualização.", + "storage.cleanup.cleanupFailed": "Falha na limpeza.", + "storage.cleanup.err.codex_busy": "O Codex está usando o state.sqlite — tente novamente após encerrar o Codex.", + "storage.cleanup.err.stale_preview": "Os arquivos arquivados mudaram desde a pré-visualização — execute a pré-visualização novamente.", + "storage.cleanup.err.restore_pending_overlap": "Os arquivos selecionados se sobrepõem a uma restauração incompleta da lixeira — conclua ou tente novamente a restauração primeiro.", + "storage.cleanup.err.referenced_history": "Os arquivos selecionados ainda são referenciados por históricos bifurcados ou paginados.", + "storage.cleanup.err.invalid_digest": "O digest da pré-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 podem já 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 podem já 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 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": "Nenhuma entrada em quarentena.", + "storage.trash.loading": "Carregando quarentena…", + "storage.trash.col.when": "Em quarentena desde", + "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 entrada da quarentena?", + "storage.trash.confirmBody": "Restaurar {count} arquivo(s) (~{size}) de {id} para as sessões arquivadas.", + "storage.trash.cancel": "Cancelar", + "storage.trash.confirmRestore": "Restaurar", + "storage.trash.done": "{count} arquivo(s) restaurado(s) ({size}).", + "storage.trash.restoreFailed": "Falha na restauração.", + "storage.trash.listFailed": "Não foi possível listar as entradas da 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 encerrar o Codex.", + "storage.trash.err.invalid_trash": "O ID da entrada da lixeira está ausente ou é inválido.", + "storage.trash.err.missing_trash": "A entrada da lixeira não foi encontrada.", + "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 podem já 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 estado do Codex.", + "storage.trash.err.storage_mutation_busy": "Outra limpeza ou restauração de armazenamento está em andamento — tente novamente em instantes.", + "storage.trash.err.restore_failed": "Falha na restauração.", + "storage.trash.err.restore_worker_timeout": "A restauração demorou demais (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": "Falha na execução da política.", + "storage.policy.alreadyRunning": "Já há uma execução da política de limpeza em andamento.", + "storage.policy.invalid": "Valores de política inválidos.", + "storage.policy.enabled": "Ativar limpeza automática", + "storage.policy.enabledHint": "O padrão é desativada. Quando ativada, executa apenas no agendamento escolhido (ou em Executar agora).", + "storage.policy.threshold": "Quando o tamanho dos arquivados exceder (GiB)", + "storage.policy.trigger": "Gatilho", + "storage.policy.target": "Alvo da limpeza", + "storage.policy.targetPercent": "Remover os arquivados mais antigos (%)", + "storage.policy.targetReduce": "Reduzir o tamanho dos arquivados 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 alvo", + "storage.policy.reduceDec": "Diminuir tamanho alvo", + "storage.policy.schedule": "Agendamento", + "storage.policy.schedule.manual": "Somente manual", + "storage.policy.schedule.startup": "Ao iniciar o proxy", + "storage.policy.schedule.daily": "Diário", + "storage.policy.schedule.weekly": "Semanal", + "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 dos arquivados está abaixo do limite — nada a fazer.", + "storage.policy.skippedEmpty": "Nenhum candidato arquivado correspondeu ao alvo.", + "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 provedor", + "modal.search": "Buscar provedores…", + "modal.logInWith": "Entrar com {label}", + "modal.waitingBrowser": "Aguardando o navegador…", + "modal.providerName": "Nome do provedor", + "modal.adapter": "Adaptador", + "modal.baseUrl": "URL base", + "modal.endpoint": "Endpoint", + "modal.endpoint.tokenPlan": "Plano de tokens", + "modal.endpoint.payAsYouGo": "Pague conforme o uso", + "modal.endpoint.custom": "Personalizado", + "modal.defaultModel": "Modelo padrão (opcional)", + "modal.allowPrivateNetwork": "Permitir rede local/privada", + "modal.allowPrivateNetworkHint": "Ative apenas para provedores hospedados por você de propósito. Os endpoints de metadados continuam bloqueados.", + "modal.nameRequired": "O nome do provedor é obrigatório", + "modal.baseUrlRequired": "A URL base é obrigatória", + "modal.networkError": "Erro de rede — o proxy está em execução?", + "modal.loginFailStart": "Falha ao iniciar o login", + "modal.waitingLogin": "Aguardando login no navegador…", + "modal.loggingIn": "Entrando…", + "modal.loginTimeout": "Tempo de login esgotado — tente novamente.", + "modal.back": "Voltar", + "modal.badge.oauth": "OAuth", + "modal.customProvider": "Provedor personalizado", + "modal.failedStatus": "Falhou ({status})", + "modal.loginError": "Erro de login: {error}", + "modal.badge.codexLogin": "Login do Codex", + "modal.badge.local": "Local", + "modal.badge.apiKey": "Chave de API", + "modal.badge.direct": "Direto", + "modal.badge.pool": "Pool", + "modal.badge.free": "Grátis", + "modal.badge.sponsor": "Patrocinador", + "modal.badge.subscriptionCli": "CLI por assinatura", + "pws.sponsor.orcaTitle": "Um modelo 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 programação com IA. Comece com um token do grupo Codex.", + "pws.sponsor.tokenlabTitle": "Uma chave de API para os principais modelos", + "pws.sponsor.tokenlabDescription": "Responses, Chat Completions, streaming e chamada de ferramentas para agentes de programação, com modo de entrega à sua escolha e cobrança conforme o uso.", + "pws.sponsor.visit": "Conhecer {provider}", + "pws.sponsor.console": "Abrir console", + "modal.invalidPreset": "Este preset de provedor integrado está incompleto. Reinicie o proxy e tente novamente.", + "modal.freeTierTitle": "Plano gratuito", + "modal.subscriptionCliTitle": "CLI por assinatura, não 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 da conta de assinatura do Claude. O OpenCodex não armazena nenhuma chave para ele, e uma chave informada aqui nunca é usada. Para cobrança por chave de API, adicione {apiProvider}.", + "modal.freeTierDefault": "Não requer chave de API. Funciona de imediato.", + "modal.tab.accounts": "Contas", + "modal.tab.free": "Grátis", + "modal.tab.local": "Local", + "modal.tab.paid": "Pago", + "modal.noteMore": "Mostrar descrição completa", + "modal.searchResults": "{count} resultados em {tiers}", + "modal.accountsHint": "Entre aqui no ChatGPT/Codex, em provedores OAuth e em contas com chave de API. A OpenAI já está 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": "Não conectado", + "quota.fiveHourLimit": "Limite de 5 horas", + "quota.ageMinutes": "{n}min", + "quota.ageHours": "{n}h", + "quota.ageDays": "{n}d", + "quota.observedAgo": "Observado há {age}", + "quota.observedHint": "A Meta informa o uso apenas durante uma resposta em streaming, então 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 próprios", + "quota.cursorApiUsage": "Uso da 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 {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": "Sem chave necessária", + "pws.freeTitle": "Preço gratuito (uma chave 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": " · grátis", + "pws.rail.selectAria": "Selecionar {name} — {status}{suffix}", + "pws.searchPlaceholder": "Buscar provedores…", + "pws.filterAria": "Filtrar provedores", + "pws.providerFiltersAria": "Filtros de provedores", + "pws.filters": "Filtros", + "pws.filterStatus": "Status", + "pws.pricing": "Preço", + "pws.paid": "Pago", + "pws.filterType": "Tipo", + "pws.type.cloud": "Nuvem", + "pws.type.local": "Local", + "pws.type.selfHosted": "Autohospedado", + "pws.type.login": "Login", + "pws.sort": "Ordenar", + "pws.sortProvidersAria": "Ordenar provedores", + "pws.sort.az": "A–Z", + "pws.sort.za": "Z–A", + "pws.sort.freePaid": "Grátis primeiro", + "pws.sort.paidFree": "Pagos primeiro", + "pws.sort.accountsFirst": "Contas primeiro", + "pws.resetAll": "Limpar tudo", + "pws.providerList": "Lista de provedores", + "pws.providersAria": "Provedores", + "pws.groupReady": "Prontos ({count})", + "pws.groupNeedsSetup": "Requerem configuração ({count})", + "pws.groupDisabled": "Desativados ({count})", + "pws.noSearchResults": "Nenhum provedor corresponde à busca.", + "pws.noMatchFilters": "Nenhum provedor corresponde aos filtros.", + "pws.noProvidersConfigured": "Nenhum provedor configurado.", + "pws.workspaceMainAria": "Detalhes do provedor", + "pws.detailComingSoon": "Visão detalhada em breve — use a visão clássica para gerenciar este provedor.", + "pws.selectPrompt": "Selecione um provedor na lista.", + "pws.connectFirst": "Conecte seu primeiro provedor", + "pws.empty.browseFree": "Explorar provedores gratuitos", + "pws.empty.browseFreeDesc": "Comece sem 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 e chave de API personalizadas", + "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 ser autenticada novamente", + "pws.attention.reauthForward": "A conta ativa do Codex precisa ser autenticada novamente — abra Contas para corrigir", + "pws.attention.missingCredentials": "Credenciais ausentes", + "pws.cell.auth": "Autenticação", + "pws.cell.note": "Observação", + "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 acompanhados na aba Uso.", + "pws.stats.source": "Fonte", + "pws.usageLast30d": "Uso (últimos 30 dias)", + "pws.estimatedCost": "Custo estimado", + "pws.costDisclaimer": "Estimativa pelo preço de tabela da API, não 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 é compatível com 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": "Part.", + "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": "Sem dados de cota para este provedor.", + "pws.accountQuotaUnavailable": "Dados de limite de taxa temporariamente indisponíveis; exibindo os últimos valores conhecidos, quando houver.", + "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 limitou a taxa da verificação de cota.", + "pws.quotaFailure.upstream_error": "O provedor não conseguiu concluir a verificação de cota.", + "pws.quotaFailure.redirect_blocked": "O endpoint de cota retornou um redirecionamento bloqueado.", + "pws.quotaFailure.destination_blocked": "O destino da cota foi bloqueado pela política de rede.", + "pws.quotaFailure.dns_failed": "Não foi possível resolver o hostname da cota.", + "pws.quotaFailure.timeout": "A requisição de cota expirou.", + "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 fazer login novamente para a descoberta de modelos ao vivo funcionar. Exibindo os modelos configurados por enquanto.", + "pws.modelsConfiguredFallback": "Exibindo os modelos configurados (descoberta ao vivo indisponível).", + "pws.modelsTruncated": "Exibindo os primeiros {shown} de {total} modelos. Use o filtro 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": "Adaptador e URL base são obrigatórios.", + "pws.addAccount": "Adicionar conta", + "pws.addKey": "Adicionar chave de API", + "pws.apiKeys": "Chaves de API", + "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 uma exportação JSON do Antigravity do Cockpit Tools a partir deste dispositivo. O conteúdo do arquivo não é exibido.", + "pws.cockpitImportFileLabel": "Exportação JSON do Antigravity do Cockpit Tools", + "pws.cockpitImportChooseFile": "Escolher arquivo JSON", + "pws.cockpitImporting": "Importando…", + "pws.cockpitImportInvalid": "O arquivo selecionado não é uma exportação JSON válida ou é grande demais.", + "pws.cockpitImportFailed": "Não foi possível concluir a importação das contas.", + "pws.cockpitImportComplete": "Importação concluída: {imported} importadas, {updated} atualizadas, {failed} com falha, {unsupported} sem suporte.", + "pws.accountSwitching": "Alternando…", + "pws.accountCurrent": "Conta atual", + "pws.accountPausedHint": "Excluída da seleção automática, das novas tentativas, da recuperação de cooldown, da seleção manual e da renovação proativa de token até ser retomada.", + "pws.defaultModelNone": "Nenhum (usar o 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": "Não conectado", + "pws.note": "Observação", + "pws.allowPrivateNetwork": "Permitir rede local/privada", + "pws.liveModels": "Descobrir modelos a partir do provedor", + "pws.liveModelsDesc": "Busca o catálogo de modelos ao vivo do provedor. Desative para usar apenas os modelos configurados/estáticos.", + "pws.xaiChatOptIn": "Usar Chat Completions para Grok 4.5 e 4.6", + "pws.xaiChatOptInDesc": "Desativado seleciona Responses. Requisições OAuth Responses o usam por padrão. Os demais modelos Grok e o comportamento por plano 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 seu proxy não conseguir transportar de forma confiável o stream HTTP/2 do Cursor.", + "pws.optionalPlaceholder": "Opcional", + "pws.providerId": "ID do provedor", + "pws.reauth": "Requer nova autenticação", + "pws.reauthenticate": "Autenticar novamente", + "pws.copyDoctor": "Copiar ocx doctor", + "pws.doctorCopied": "Copiado", + "pws.doctorCopyUnavailable": "Área de transferência indisponível", + "pws.healthCooldownHint": "Aguarde o fim do cooldown. Não teste esta conta ainda.", + "pws.healthLabel.rateLimited": "Limite de requisições atingido", + "pws.healthLabel.quotaLimited": "Cota esgotada", + "pws.healthLabel.reauthRequired": "Reautenticação necessária", + "pws.healthLabel.refreshFailed": "Falha na renovação", + "pws.healthLabel.metadataMismatch": "Metadados divergentes", + "pws.healthLabel.validationPending": "Validação pendente", + "pws.healthSummary.validationPending": "{provider} {account}: registrada com a cota esgotada. Após a cota se recuperar, atualize as cotas para executar uma pequena requisição de validação. O roteamento permanece desativado até que ela tenha êxito.", + "pws.healthLabel.credentialConflict": "Conflito de credenciais", + "pws.healthSummary.rateLimited": "{provider} {account}: limite de requisições atingido até {until}. O roteamento desta conta fica pausado até lá.", + "pws.healthSummary.quotaLimited": "{provider} {account}: cota esgotada até {until}. O roteamento desta conta fica 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}: metadados divergentes.", + "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}\" passará a ser o provedor padrão. Esta ação não pode ser desfeita.", + "pws.removeConfirmTitle": "Remover provedor", + "pws.saveSettings": "Salvar", + "pws.pacingTitle": "Ritmo de requisições", + "pws.pacingDesc": "Distribui uniformemente o início das requisições de saída deste provedor. Respostas em streaming podem se sobrepor.", + "pws.pacingEnabled": "Ativado", + "pws.pacingRpm": "Requisições por minuto", + "pws.pacingConcurrency": "Máximo de requisições simultâneas", + "pws.pacingRpmUnit": "RPM", + "pws.pacingCapUnit": "×", + "pws.pacingDelay": "Intervalo mínimo (ms)", + "pws.pacingSlowerWins": "Prevalece o limite mais lento do provedor. As substituições por modelo só podem acrescentar mais atraso ou reduzir o limite de simultaneidade.", + "pws.pacingQueued": "na fila", + "pws.pacingNextSlot": "até o próximo slot", + "pws.pacingLastModel": "último modelo", + "pws.pacingNone": "Nenhum", + "pws.pacingModelOverrides": "Substituições por modelo", + "pws.pacingModel": "Modelo", + "pws.pacingAdd": "Adicionar substituição", + "pws.pacingRemove": "Remover", + "pws.pacingRemoveModel": "Remover a substituição de ritmo de requisições de {model}", + "pws.pacingRuleRequired": "Ative o ritmo de requisições somente após definir um limite do provedor ou uma substituição por modelo.", + "pws.pacingCapInvalid": "O máximo de requisições simultâneas deve ser um número inteiro igual ou maior que 1.", + "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 passará a ser contabilizado no novo modo.", + "pws.settingsUnsavedBar": "Você tem alterações não salvas.", + "pws.unsavedLeaveBody": "Você tem alterações não salvas. Salvar antes de sair?", + "pws.unsavedLeaveTitle": "Alterações não salvas", + "pws.attentionRequired": "Requer atenção", + "pws.attentionAria": "{name}: {reason}", + "pws.missingCredentials": "Credenciais ausentes", + "pws.editJsonDesc": "Edite a configuração bruta do proxy em JSON", + "pws.updatesUnavailable": "As atualizações de provedores não estão disponíveis.", + "pws.dashboard.title": "Visão geral dos provedores", + "pws.dashboard.subtitle": "Gerencie todos os seus provedores de modelos em um só lugar.", + "pws.dashboard.rateLimits": "LIMITES DE REQUISIÇÕES", + "pws.capacity.estimate": "Estimativa do pool por pesos configurados", + "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 de referência, portanto esta estimativa pode ser conservadora", + "pws.capacity.partial": "Cobertura parcial de janelas: {count} conta(s) não informam 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 {time}", + "pws.dashboard.noQuota": "Sem dados de cota", + "pws.dashboard.noUsage": "Ainda sem dados de uso", + "pws.dashboard.noRateLimits": "Ainda sem dados de limites de requisições", + "pws.allProviders": "Visão geral dos provedores", + "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 se aplica — este provedor usa um catálogo de modelos estático.", + "pws.editSettings": "Editar configurações", + "pws.viewUsage": "Ver uso detalhado", + "pws.allSystemsOk": "Todos os sistemas operacionais", + "pws.apiKeyConfigured": "Chave de API configurada", + "pws.addApiKey": "Adicionar chave de API", + "pws.loggedInAs": "Conectado como {email}", + "pws.notLoggedIn": "Não conectado", + "pws.passthrough": "Passthrough do Codex", + "pws.notes": "OBSERVAÇÕES", + "pws.notePlaceholder": "Adicione uma observação sobre este provedor...", + "pws.noteSaved": "Observação salva", + "pws.authSummary": "AUTENTICAÇÃO", + "time.justNow": "Agora mesmo", + "time.notChecked": "Não verificado", + "time.minutesAgo": "há {n} min", + "time.hoursAgo": "há {n} h", + "time.daysAgo": "há {n} d", + "modal.noMatch": "Nenhuma correspondência.", + "modal.oauthDefaultNote": "Entre com sua conta — sem necessidade de chave de API.", + "modal.oauthComingSoon": "O login OAuth para {label} chega na próxima atualização. Por enquanto, use uma chave de API.", + "modal.oauthComingSoonShort": "O login OAuth para este provedor chega na próxima atualização — por enquanto, use uma chave de API.", + "modal.useApiKeyInstead": "Usar uma chave de API", + "modal.setupGuide": "Guia de configuração", + "modal.setupStep1Prefix": "Acesse o", + "modal.setupDashboardLink": "painel de {label}", + "modal.setupStep1Suffix": "e copie sua chave de API", + "modal.setupStep2": "Cole-a no campo de chave de API abaixo", + "modal.setupStep3": "Clique em Adicionar provedor — os modelos são descobertos automaticamente", + "modal.namePlaceholder": "ex.: openrouter", + "modal.duplicateWarn": "O provedor \"{name}\" já existe e será sobrescrito.", + "modal.forwardHintPrefix": "Não é necessária chave — o proxy encaminha suas credenciais de", + "modal.forwardCredentials": "codex login", + "modal.forwardHintSuffix": "para este provedor.", + "modal.localHint": "Nenhuma chave de API é armazenada. Isto adiciona o catálogo estático público de modelos do Cursor para o Codex, mas o transporte ao vivo do Cursor e a execução nativa de arquivos/shell permanecem desativados até serem auditados.", + "modal.getApiKey": "Obtenha sua chave de API de {label}", + "modal.apiKey": "Chave de API", + "modal.apiKeyTransport": "Cabeçalho da chave de API", + "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 URL base contém um {placeholder} não resolvido. Substitua-o pelo valor real.", + "modal.baseUrlPlaceholderHint": "Substitua o {placeholder} na URL base pelo ID real da sua conta antes de adicionar.", + "modal.adding": "Adicionando…", + "modal.useOauthLogin": "← Usar login OAuth", + "nav.codexAuth": "Autenticação do Codex", + "nav.codexSet": "Config. do Codex", + "codexSet.tab.multiauth": "Multiautenticação", + "codexSet.tab.prompt": "Prompt", + "codexSet.prompt.title": "Camadas de prompt", + "codexSet.prompt.timing": "Aplica-se a sessões recém-iniciadas. As sessões em andamento mantêm suas configurações de prompt atuais.", + "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 das suas camadas.", + "codexSet.drift.storeMissing": "O arquivo de camadas sumiu, mas as instruções permanecem em config.toml. O reparo mantém o texto como uma única camada e grava um backup antes.", + "codexSet.drift.ownedMalformed": "A linha gerada em config.toml foi remodelada manualmente e, por isso, não é mais seguro reescrevê-la.", + "codexSet.custom.adoptUnsupported": "O valor em {path}, linha {line}, não é uma string de linha única e 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; por isso as alterações são 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": "As extensões podem adicionar suas próprias camadas. O Codex não as expõe, portanto não é possível listá-las aqui.", + "codexSet.group.transition": "Avisos de transição", + "codexSet.group.transitionDesc": "Estes anunciam uma mudança em vez de descrever um estado, por isso aparecem apenas quando a sessão entra em tempo real ou troca de modelo.", + "codexSet.custom.slotNote": "As camadas personalizadas são unidas em uma única seção, nesta ordem.", + "codexSet.row.alwaysOn": "Sempre ativa", + "codexSet.row.onChange": "Disparada em mudanças", + "codexSet.row.featureGated": "Configurada em [features]", + "codexSet.row.openFeatures": "Abrir configurações", + "codexSet.dialog.setValue": "{value} (padrão {fallback})", + "codexSet.dialog.copyKey": "Copiar chave", + "codexSet.dialog.unknownLayer": "Esta versão não tem descrição para esta camada. Ela vem de um runtime do Codex mais recente que o dashboard.", + "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": "Tabulações viraram quatro espaços e as quebras de linha viraram LF.", + "codexSet.custom.titleRequired": "Informe um título.", + "codexSet.custom.titleTooLong": "O título tem {count} caracteres; o limite é {max}.", + "codexSet.custom.titleMultiline": "O título deve ter uma única linha.", + "codexSet.custom.bodyTooLarge": "Esta camada tem {bytes} bytes; o limite é {max}.", + "codexSet.custom.composedTooLarge": "Somadas, as camadas ativadas teriam {bytes} bytes, acima do 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 edições não salvas das outras camadas e salvar esta camada?", + "codexSet.custom.keepEditing": "Continuar editando", + "codexSet.custom.delete": "Excluir {title}", + "codexSet.custom.deleteConfirm": "Excluir esta camada? Não há como desfazer.", + "codexSet.custom.layerGone": "Essa camada foi removida em outro lugar, então o editor foi fechado.", + "codexSet.custom.deleteConfirmNamed": "Excluir “{title}”? Não há como desfazer.", + "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 e, por isso, não é editado aqui. Importe-o para gerenciá-lo como uma camada.", + "codexSet.custom.adopt": "Importar instruções existentes", + "codexSet.custom.adoptConfirm": "Importar como camada", + "codexSet.custom.adoptRefused": "Não foi possível importar o valor existente.", + "codexSet.custom.baseReplaced": "model_instructions_file está definido como {path}, ou seja, algo fora do opencodex substituiu o prompt base.", + "codexSet.lint.identity": "Isto declara uma identidade diferente da que o Codex estabelece.", + "codexSet.lint.foreignTool": "As ferramentas vêm do registro; nomeá-las aqui não as cria.", + "codexSet.lint.placeholder": "Nenhum mecanismo de template é executado sobre as instruções, então 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": "Os fatos do ambiente são gerados depois e podem contradizer isto.", + "codexSet.lint.size": "Esta camada tem mais de 8 KB. Ela ainda é salva, mas consome tokens a 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, com formatação mínima.", + "codexSet.preset.concise.provenance": "Adaptado das diretrizes de concisão do Claude Code. Redação nossa, não uma cópia.", + "codexSet.preset.planFirst.name": "Planejar antes de editar", + "codexSet.preset.planFirst.description": "Apresente o plano e depois faça a alteração.", + "codexSet.preset.planFirst.provenance": "Adaptado da postura de planejamento do Claude Code. Redação nossa, não uma cópia.", + "codexSet.preset.explainWhy.name": "Explicar o 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. Redação nossa, 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. Redação nossa, não uma cópia.", + "codexSet.preset.korean.name": "Respostas em coreano", + "codexSet.preset.korean.description": "Responda em coreano, qualquer que seja o idioma da requisição.", + "codexSet.preset.korean.provenance": "Escrito para o opencodex a partir de um pedido recorrente de usuários. Redação nossa, 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 nativa; por isso este diálogo descreve a camada e indica sua chave, em vez de mostrar 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 mudam, então uma camada inalterada fica ausente de uma única amostra.", + "codexSet.dialog.emptySource": "O arquivo em {path} existe, mas está vazio, então esta camada não envia nada.", + "codexSet.dialog.notExposed": "O prompt base trafega fora da lista de mensagens que o Codex consegue imprimir, então não pode ser exibido aqui. É possível substituí-lo por meio de model_instructions_file.", + "codexSet.dialog.unmapped": "Esta camada não tem mapeamento confirmado na saída do prompt, então 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, então o texto está indisponível.", + "codexSet.class.base": "Instruções base", + "codexSet.class.config-toggle": "Alternável aqui", + "codexSet.class.feature-gated": "Controlada por recurso", + "codexSet.class.runtime-conditional": "Condicional ao runtime", + "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ção sobre a 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 multiagente", + "codexSet.layer.git-attribution": "Atribuição de commits", + "codexSet.about.base-instructions": "As instruções do próprio Codex. Elas viajam com a própria requisição e não podem ser desativadas.", + "codexSet.about.model-switch": "Adicionada quando a sessão troca de modelo no meio da conversa.", + "codexSet.about.personality": "Orientação de tom e voz, controlada por uma feature flag.", + "codexSet.about.context-window-guidance": "Orientação sobre o orçamento de contexto restante, controlada por uma feature flag.", + "codexSet.about.realtime": "Adicionada em sessões em tempo real.", + "codexSet.about.agents-md": "Os arquivos AGENTS.md do seu projeto. Esta página apenas informa a camada; nunca edita a documentação do seu projeto.", + "codexSet.about.permissions": "Explica as configurações de sandbox e de 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ção para ambientes de execução adiada, controlada por uma feature flag.", + "codexSet.about.apps": "Como usar os apps conectados.", + "codexSet.about.plugins": "Adicionada quando um plugin é selecionado ou quando qualquer plugin anuncia uma capacidade.", + "codexSet.about.tools": "Descrições de ferramentas adiadas, controladas por uma feature flag.", + "codexSet.about.skills": "A lista de skills disponíveis.", + "codexSet.about.multi-agent-mode": "Instruções de subagentes, controladas por uma feature flag.", + "codexSet.about.git-attribution": "Instrui o modelo a adicionar um trailer 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 nem em [features]. Quando sua conta o desativa, o Codex envia a instrução oposta em vez de não enviar nada.", + "codexSet.condition.model-switch": "Emitida apenas após uma troca de modelo no meio da sessão.", + "codexSet.condition.realtime": "Emitida apenas em uma sessão em tempo real.", + "codexSet.condition.agents-md": "Emitida quando um documento de projeto é encontrado para o diretório de trabalho.", + "codexSet.condition.plugins": "Emitida quando um plugin é selecionado ou quando qualquer plugin anuncia uma capacidade.", + "codexSet.condition.git-attribution": "Definida 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 o lado, use as teclas de seta ou pressione as setas para alternar entre as opções. Aplica-se a sessões recém-iniciadas.", + "codexSet.base.defaultTitle": "Prompt base do próprio Codex", + "codexSet.base.defaultBody": "O padrão não é armazenado aqui, então 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 que já acompanha o produto.", + "codexSet.base.variantTitle": "Nome", + "codexSet.base.variantBody": "Prompt", + "codexSet.base.replacesWarning": "Isto SUBSTITUI o prompt base do Codex em vez de acrescentar a ele. Um prompt curto aqui significa um modelo com instruções curtas.", + "codexSet.base.use": "Usar este", + "codexSet.base.inUse": "Em uso", + "codexSet.base.externalBlocked": "model_instructions_file já aponta para {path}, que não foi gravado pelo opencodex. 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 dashboard", + "nav.collapseSidebar": "Recolher barra lateral", + "nav.expandSidebar": "Expandir barra lateral", + "pws.refreshAllQuotas": "Atualizar todas as cotas", + "pws.quotaRefreshDone": "Verificação de cotas concluída", + "integrations.subtitle": "Conecte clientes ao opencodex, gerencie credenciais e restaure a configuração dos clientes.", + "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.tab.kilo": "Kilo", + "integrations.tab.droid": "Factory Droid", + "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 requerem 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 do arquivo pendente.", + "integrations.aside.retry": "Tentar {name} novamente", + "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": "A integração do Codex pertence ao serviço do proxy. Iniciar o opencodex a aplica; 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 é 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 serve 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; limpeza 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) conectado(s)", + "integrations.detail.grokAbsent": "Nenhum bloco do opencodex na configuração", + "integrations.detail.cursorSeen": "O Cursor chamou este proxy recentemente", + "integrations.detail.cursorNeverSeen": "Private Inference instalado; nenhuma requisição vista 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 em loopback. O Cursor comum não consegue: o backend dele chama o endpoint personalizado e exige uma URL HTTPS pública. Esta página nunca grava no Cursor; cole os valores abaixo no Cursor você mesmo.", + "integrations.cursor.loading": "Lendo o status do Cursor…", + "integrations.cursor.unavailable": "Não foi possível ler o status do Cursor a partir do proxy.", + "integrations.cursor.detection": "Versões instaladas", + "integrations.cursor.privateInference": "Cursor Private Inference", + "integrations.cursor.regular": "Cursor (padrão)", + "integrations.cursor.detected": "Detectado", + "integrations.cursor.notFound": "Não encontrado", + "integrations.cursor.regularOnly": "Apenas o Cursor regular foi encontrado. Ele roteia endpoints personalizados pelos servidores do Cursor, então um proxy em loopback fica inacessível sem um túnel público. Consulte o guia da versão Private Inference.", + "integrations.cursor.installerIntro": "O Cursor Private Inference é uma versão separada em modo local. O canal de atualização do Cursor anuncia o instalador, versão {version}; instale-o e cole a Base URL e a chave de API abaixo em Settings > Models > Gateway.", + "integrations.cursor.installerOpen": "Baixar o instalador", + "integrations.cursor.installerUnavailable": "Não foi possível resolver o instalador do Private Inference a partir do canal de atualização do Cursor para este computador. Os valores do gateway abaixo valem depois que ele for instalado.", + "integrations.cursor.installerCheck": "Procurar o instalador do Private Inference", + "integrations.cursor.installerChecking": "Consultando o canal de atualização do Cursor…", + "integrations.cursor.nothingFound": "Nenhuma instalação do Cursor foi encontrada nos locais habituais. Se estiver instalado em outro lugar, os valores abaixo continuam valendo.", + "integrations.cursor.gateway": "Valores do gateway", + "integrations.cursor.gatewayHint": "No Cursor Private Inference, abra Settings > Models > Gateway, cole estes dois valores e clique em Refresh model list.", + "integrations.cursor.baseUrl": "Base URL", + "integrations.cursor.apiKey": "Chave de API", + "integrations.cursor.apiKeyCredential": "Uma das suas chaves de API do opencodex (este bind exige 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 iniciou. Depois de salvar o gateway, clique em Refresh model list no Cursor.", + "integrations.cursor.models": "O que o Cursor vai mostrar", + "integrations.cursor.modelsHint": "O Cursor escolhe a escala de Reasoning a partir da própria tabela de modelos, então o opencodex só consegue prevê-la. Context lista a janela padrão e a opcional (Max Mode do Cursor).", + "integrations.cursor.ladderFromBundle": "Escalas de Reasoning lidas do bundle instalado do Cursor Private Inference {version}. Quem decide é o Cursor; o opencodex apenas informa a tabela dele.", + "integrations.cursor.ladderFromStatic": "As escalas de Reasoning são um espelho estático do Cursor 3.18.25 (nenhum bundle legível do Private Inference foi encontrado). Context lista a janela padrão e a 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 embutida do Cursor, então o Cursor não mostra controle de Reasoning.", + "integrations.cursor.effortRowsOne": "1 linha de esforço publicada", + "integrations.cursor.effortRowsMany": "{n} linhas de esforço publicadas", + "integrations.cursor.effortRowsOff": "sem linhas de esforço", + "integrations.cursor.tableLessHint": "Linhas marcadas com — ficam sem controle de Reasoning no Cursor. Ative cursorEffortRows para publicar uma entrada no seletor 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 vai remover seu roteamento de {path}, remover o perfil gerado, restaurar o catálogo de modelos nativo e reetiquetar as threads retomáveis para o Codex nativo.", + "integrations.dialog.codex.breakage": "O codex puro vai se conectar direto à OpenAI, e os modelos roteados de outros provedores vão desaparecer do Codex. O proxy e o /v1/responses continuam rodando para outros clientes.", + "integrations.dialog.codex.undo": "Ativar de novo reconstrói o catálogo roteado com os modelos disponíveis na hora e injeta o Codex novamente. O histórico de retomada é adaptado à 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 depois que o opencodex injetou a configuração, desativar remove essa seleção e reativar a integração não consegue reconstruí-la; selecione o modelo de novo. Se um model_provider externo controla o Codex, o opencodex remove apenas seu journal obsoleto e deixa 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 escrito fora do bloco permanece inalterado.", + "integrations.dialog.grok.breakage": "Desativar remove os aliases de modelo do opencodex no Grok Build. Os modelos usados com sua conta xAI continuam disponíveis.", + "integrations.dialog.grok.undo": "Se o opencodex estiver rodando em um endereço loopback, reativar grava um novo bloco com os modelos disponíveis no momento.", + "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 primeiro selecionará um novo perfil padrão sem credenciais e depois removerá o perfil antigo e o backup.", + "integrations.dialog.desktop.breakage": "O Claude Desktop voltará ao Claude padrão, em vez dos modelos roteados pelo opencodex.", + "integrations.dialog.desktop.undo": "Reativar 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. Feche-o completamente e reabra para que a mudança tenha efeito.", + "integrations.dialog.desktop.confirm": "Desativar", + "integrations.native.msg.nonLoopbackRemoved": "O Grok Build só pode ser registrado automaticamente enquanto o opencodex roda em um endereço loopback. O bloco anterior que apontava para loopback foi removido.", + "integrations.native.msg.nonLoopbackRemovedNoop": "O Grok Build só pode ser registrado automaticamente enquanto o opencodex roda em um endereço loopback. Não havia bloco anterior para remover.", + "integrations.native.msg.nonLoopbackSuperseded": "O Grok Build só pode ser registrado automaticamente enquanto o opencodex roda em um endereço loopback. Outro processo gravou um novo bloco nesse meio-tempo, então o bloco atual no arquivo não foi criado por esta requisição.", + "integrations.native.error.orphanedMarker": "{path} tem um marcador de início do opencodex, mas nenhum marcador de fim. O arquivo foi mantido inalterado porque o opencodex não consegue determinar onde seu bloco termina.", + "integrations.native.error.homeMismatch": "O home do serviço instalado não corresponde ao home atual, então o arquivo foi mantido inalterado.", + "integrations.native.error.notInstalled": "O Grok Build não está instalado, então não há nada a alterar.", + "integrations.native.error.configBusy": "A configuração está sendo salva em outro lugar e não pôde ser alterada. Tente novamente em instantes.", + "integrations.native.error.desktopUnsafeMetadata": "Os metadados do Claude Desktop em {path} não puderam ser lidos com segurança, então sua biblioteca não foi alterada.", + "integrations.native.error.desktopCleanupIncomplete": "O Claude Desktop está apontado para o modo padrão, mas ainda restam arquivos de credencial antigos do opencodex 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 foi 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 todos…", + "integrations.onboarding": "Aplicar grava um bloco de provedor do opencodex depois de 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 volte 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 rollback", + "integrations.rollback.empty": "Ainda não há histórico de aplicações", + "integrations.rollback.emptyBody": "Toda gravação bem-sucedida mantém antes um snapshot do estado anterior.", + "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 rollback.", + "integrations.rollback.delete": "Excluir", + "integrations.rollback.deleteAria": "Excluir a entrada de rollback de {at}", + "integrations.rollback.deleteNewest": "A entrada mais recente deste cliente é mantida para que você ainda possa desfazer.", + "integrations.rollback.deleteGone": "Esta entrada já foi excluída. A lista será atualizada.", + "integrations.dialog.deleteEntry.title": "Excluir esta entrada de rollback?", + "integrations.dialog.deleteEntry.changes": "Esta entrada some da lista de rollback, e qualquer backup que ela ainda guarde de {path} é apagado do disco.", + "integrations.dialog.deleteEntry.breakage": "Você não poderá mais restaurar o arquivo para este ponto. As entradas mais novas e o próprio arquivo não são afetados.", + "integrations.dialog.deleteEntry.undo": "Isso não pode ser desfeito. A entrada mais recente de 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 recebe um backup primeiro, e então o snapshot selecionado o substitui.", + "integrations.restore.driftTitle": "Foram detectadas edições mais novas", + "integrations.restore.driftBody": "As alterações feitas depois deste snapshot receberão backup, e então o arquivo será substituído.", + "integrations.restore.confirm": "Restaurar", + "integrations.restore.confirmDrift": "Fazer backup das edições novas 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 das integrações.", + "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 andamento. Tente novamente em instantes.", + "integrations.error.conflict": "A configuração mudou depois que o opencodex a gravou. Nada foi removido.", + "integrations.error.unsafe": "A configuração 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 configuração dele não tem onde colocar o cabeçalho de admissão que um bind remoto exige, então gravá-lo manualmente também não ajudaria. Dê a ele acesso loopback, 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ê seus provedores de {path}, que o opencodex não grava, então ativá-lo aqui não mudaria nada do que ele carrega.", + "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.status.backup": "Backup", + "integrations.status.lastRestore": "Última restauração", + "integrations.status.unknown": "Desconhecido", + "integrations.bulk.title": "Desativar as integrações de clientes aplicadas?", + "integrations.bulk.body": "Apenas o bloco pertencente ao opencodex é removido. Um snapshot anterior à gravação é mantido para cada cliente.", + "integrations.bulk.partial": "Alguns clientes não puderam ser desativados: {clients}", + "integrations.bulk.success": "As integrações de clientes aplicadas foram desativadas.", + "integrations.retention.degraded": "A limpeza de backups 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 foi concluída. Verifique a configuração do cliente antes de tentar de novo.", + "integrations.error.recover": "{message} Há um backup 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 configuração?", + "integrations.dialog.overwrite.changesUnowned": "Um bloco que não foi escrito por nós ocupa as configurações de que o opencodex precisa em {path}. Aplicar o substitui pelo bloco que o opencodex gravaria.", + "integrations.dialog.overwrite.changesForeign": "Sua edição dentro do bloco do opencodex em {path} será descartada e substituída pelo bloco que o opencodex gravaria.", + "integrations.dialog.overwrite.breakage": "Tudo o que o outro bloco configurava deixa de valer. O restante do arquivo não é tocado.", + "integrations.dialog.overwrite.undo": "Um snapshot é salvo antes, então isto aparece na lista de rollback 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 mudou enquanto você confirmava. Revise o plano atualizado e confirme novamente.", + "integrations.dialog.apply.title": "Aplicar esta integração?", + "integrations.dialog.apply.changes": "O opencodex vai adicionar suas configurações de provedor gerenciadas à configuração do cliente.", + "integrations.dialog.apply.breakage": "O cliente passará a usar os modelos expostos atualmente por esta instância do opencodex.", + "integrations.dialog.apply.undo": "Um backup é salvo antes, e a alteração pode ser desfeita pela 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 cliente deixará de usar os modelos roteados por esta instância do opencodex.", + "integrations.dialog.disable.undo": "Um backup é salvo antes, e a alteração pode ser desfeita pela 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 o 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 que não pertence ao opencodex será substituído.", + "integrations.plan.foreign.foreignEdit": "As edições dentro do bloco gerenciado pelo opencodex serão substituídas.", + "integrations.plan.foreign.drift": "O arquivo mudou desde este ponto de rollback.", + "integrations.plan.noop.applied": "Nenhuma alteração é necessária no documento do cliente gerenciado; as configurações da integração já estão presentes.", + "integrations.plan.noop.disabled": "Nenhuma alteração é necessária no documento do cliente gerenciado; as configurações da integração já estão ausentes.", + "integrations.plan.noop.profilePreference": "A preferência de sincronização do perfil ainda será salva quando você confirmar.", + "integrations.plan.refused": "O servidor não consegue aplicar este plano com segurança.", + "integrations.plan.refusal.notInstalled": "O cliente 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 cliente não pode ser alterada com segurança. Repare ou substitua o arquivo antes de tentar de novo.", + "integrations.plan.refusal.nonLoopback": "Este cliente exige um endereço de proxy loopback. Use acesso por localhost, um túnel ou um encaminhador local antes de tentar de novo.", + "integrations.plan.refusal.supersededStore": "Este cliente agora lê seus provedores de um arquivo que o opencodex não grava, então esta operação não mudaria nada do que ele carrega.", + "integrations.plan.refusal.driftRequiresConfirm": "O arquivo mudou depois deste ponto de rollback. Revise o plano com as diferenças antes de restaurar.", + "integrations.plan.refusal.snapshotExpired": "O backup deste ponto de rollback expirou, então ele não pode mais ser restaurado.", + "integrations.plan.refusal.writeFailed": "O servidor não conseguiu preparar uma gravação segura. Atualize o estado da integração antes de tentar de novo.", + "integrations.mutation.pending": "Aplicando a alteração confirmada…", + "integrations.bulk.breakage": "Cada cliente deixará de usar os modelos roteados por esta instância do opencodex.", + "integrations.bulk.undo": "Cada cliente mantém seu próprio backup e sua entrada de rollback.", + "integrations.bulk.confirm": "Desativar todos", + "integrations.semantics.opencode": "Apenas inicializações diretas do disco; a injeção de ambiente do ocx opencode tem precedência.", + "integrations.semantics.pi": "Vale para novas sessões.", + "integrations.semantics.omp": "Reinicie o OMP para carregar o catálogo.", + "integrations.semantics.hermes": "Vale para novas sessões.", + "integrations.semantics.openclaw": "Vale imediatamente para um gateway em execução.", + "integrations.semantics.kimi": "Reinicie ou execute /reload para aplicar (a v2 observa o arquivo).", + "integrations.semantics.gajae": "Vale para 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 esse provedor a quente; seu modelo padrão e o deepseek-official permanecem inalterados. Atualmente somente loopback; nenhuma credencial real é gravada.", + "integrations.semantics.mcode": "Gerencia apenas custom_provider.opencodex. Seu modelo padrão e o login do MiniMax permanecem inalterados.", + "integrations.semantics.zcode": "Gerencia apenas provider.opencodex em ~/.zcode/v2/config.json. Seu login do Z.ai e os outros provedores permanecem inalterados. Reinicie o ZCode após as alterações.", + "integrations.semantics.prime": "Gerencia apenas providers.opencodex no models.json do Prime Agent — ~/.prime/agent, a menos que PRIME_AGENT_CODING_AGENT_DIR o redirecione. Seus outros provedores e substituições de modelo permanecem inalterados. Vale para novas sessões.", + "integrations.semantics.aside": "Gerencia apenas providers.opencodex no ~/.aside/u//models.json deste perfil. Seus outros provedores permanecem inalterados. Feche completamente e reabra o Aside após aplicar.", + "integrations.semantics.raycast": "Adiciona uma entrada de provedor OpenCodex ao providers.yaml do Raycast, para que todos os modelos roteados apareçam no seletor de modelos do Raycast AI. Requer Raycast Pro.", + "integrations.semantics.omo": "Gerencia apenas providers.opencodex no models.json do omo — ~/.omo/agent, a menos que OMO_CODING_AGENT_DIR, SENPI_CODING_AGENT_DIR ou PI_CODING_AGENT_DIR o redirecione. Seus outros provedores permanecem inalterados. Vale para novas sessões.", + "integrations.lazycodexRoles.title": "omo (Codex / LazyCodex) · Modelos das funções de agente do Codex", + "integrations.lazycodexRoles.hint": "Escolha o modelo que o Codex executa em cada função de agente. Ao salvar, só a linha do modelo no arquivo da função em $CODEX_HOME/agents é alterada, e a escolha é espelhada em omo.jsonc para o LazyCodex apenas quando esse arquivo puder ser reescrito com segurança.", + "integrations.lazycodexRoles.role": "Função", + "integrations.lazycodexRoles.current": "Modelo atual", + "integrations.lazycodexRoles.model": "Novo modelo", + "integrations.lazycodexRoles.modelFor": "Modelo para {role}", + "integrations.lazycodexRoles.none": "Nenhum modelo fixado", + "integrations.lazycodexRoles.choose": "Escolha um modelo", + "integrations.lazycodexRoles.empty": "Nenhuma função de agente do Codex foi encontrada.", + "integrations.lazycodexRoles.loadFailed": "Não foi possível carregar as funções de agente do Codex.", + "integrations.lazycodexRoles.saveFailed": "Não foi possível salvar o modelo de {role}.", + "integrations.lazycodexRoles.saved": "{role} agora usa {model}.", + "integrations.lazycodexRoles.omoAbsent": "{role} agora usa {model}. O omo.jsonc não foi encontrado, então só o arquivo da função foi alterado.", + "integrations.lazycodexRoles.omoComments": "{role} agora usa {model} no arquivo da função. O omo.jsonc não foi alterado porque salvar removeria seus comentários; defina codex.agents.{role}.model nele manualmente.", + "integrations.lazycodexRoles.omoInvalid": "{role} agora usa {model} no arquivo da função. O omo.jsonc não foi alterado porque não é um objeto JSON com um objeto codex.agents.", + "integrations.lazycodexRoles.omoFailed": "{role} agora usa {model} no arquivo da função, mas não foi possível gravar o omo.jsonc.", + "integrations.lazycodexRoles.retryMirror": "Tentar omo.jsonc novamente", + "integrations.lazycodexRoles.omoCommentsState": "O omo.jsonc contém comentários, então salvar aqui altera apenas os arquivos das funções. Edite codex.agents no omo.jsonc manualmente para mantê-lo sincronizado.", + "integrations.lazycodexRoles.auto.button": "Atribuir automaticamente", + "integrations.lazycodexRoles.auto.running": "Dimensionando funções…", + "integrations.lazycodexRoles.auto.hint": "Dimensiona cada função com seu modelo padrão e propõe o modelo suficiente mais barato para cada uma. Nada muda até você aplicar.", + "integrations.lazycodexRoles.auto.failed": "Não foi possível dimensionar as funções de agente do Codex.", + "integrations.lazycodexRoles.auto.title": "Modelos propostos", + "integrations.lazycodexRoles.auto.sizedWith": "Dimensionado com {model}", + "integrations.lazycodexRoles.auto.applyAll": "Aplicar todos", + "integrations.lazycodexRoles.auto.discard": "Descartar", + "integrations.lazycodexRoles.auto.sizingFailed": "A chamada de dimensionamento falhou: {error}", + "integrations.lazycodexRoles.auto.appliedCount": "{count} de {total} propostas aplicadas.", + "integrations.lazycodexRoles.auto.proposalFor": "Proposta para {role}", + "integrations.lazycodexRoles.auto.tierEffort": "Nível {tier}, esforço {effort}", + "integrations.lazycodexRoles.auto.tierFast": "Rápido", + "integrations.lazycodexRoles.auto.tierStandard": "Padrão", + "integrations.lazycodexRoles.auto.tierFrontier": "Frontier", + "integrations.lazycodexRoles.auto.effortGlance": "olhada rápida", + "integrations.lazycodexRoles.auto.effortMeasured": "moderado", + "integrations.lazycodexRoles.auto.effortThorough": "minucioso", + "integrations.lazycodexRoles.auto.effortExhaustive": "exaustivo", + "integrations.lazycodexRoles.auto.unsized": "Não dimensionado: {reason}", + "integrations.lazycodexRoles.auto.unassigned": "Sem modelo: {reason}", + "integrations.lazycodexRoles.auto.applied": "Aplicado", + "integrations.lazycodexRoles.auto.alreadySet": "Já definido", + "integrations.lazycodexRoles.auto.apply": "Aplicar", + "integrations.lazycodexRoles.auto.moveUp": "Suba de nível se: {text}", + "integrations.lazycodexRoles.auto.moveDown": "Desça de nível se: {text}", + "integrations.semantics.cline": "Gerencia o OpenCodex no providers.json e no models.json do Cline CLI. Pare o Cline antes de alterar ou sincronizar esses arquivos e reinicie depois. Desfazer restaura os dois originais. Seu provedor padrão permanece inalterado; selecione o OpenCodex no Cline.", + "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 existe). As demais chaves permanecem inalteradas. Aplicar reescreve o arquivo inteiro, então comentários e vírgulas finais não são preservados. Selecione opencodex/ no Kilo.", + "integrations.semantics.droid": "Adiciona modelos personalizados do OpenCodex ao settings.json do Factory Droid. Desativar remove apenas as linhas gerenciadas; desfazer restaura o arquivo salvo.", + "integrations.raycast.proRequired": "Custom Providers é um recurso do Raycast Pro. O arquivo será gravado, mas o Raycast o ignora 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 Raycast → Settings → AI e clique uma vez em Reveal Providers Config para que a pasta de provedores exista.", + "codexAuth.mainAccount": "Conta principal", + "codexAuth.logLabel": "Rótulo no log", + "codexAuth.codexApp": "App Codex", + "codexAuth.moreActions": "Mostrar mais ações", + "codexAuth.copyId": "Copiar ID da conta", + "codexAuth.appLogin": "Login do 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 se alternam aqui.", + "codexAuth.accountModeDirect": "Modo direto", + "codexAuth.accountModeDirectDesc": "As requisições usam apenas o login principal; as contas adicionadas continuam armazenadas para o modo Pool.", + "codexAuth.openaiMissing": "O provedor OpenAI integrado não está configurado.", + "codexAuth.openaiDisabled": "O provedor OpenAI integrado está desativado.", + "codexAuth.openaiUnavailableDesc": "Suas contas OpenAI continuam disponíveis. Ative o provedor para rotear as requisições do Codex.", + "codexAuth.enableOpenai": "Ativar OpenAI", + "codexAuth.enablingOpenai": "Ativando...", + "codexAuth.enableOpenaiFailed": "Falha ao ativar o provedor OpenAI.", + "codexAuth.openaiPresetLoadFailed": "Falha ao carregar o preset do provedor OpenAI.", + "codexAuth.openaiPresetUnavailable": "O preset do provedor OpenAI não está disponível.", + "codexAuth.openProviders": "Abrir Provedores", + "codexAuth.add": "Adicionar", + "codexAuth.credits": "Créditos", + "codexAuth.creditsRemaining": "restantes", + "codexAuth.creditsUnlimited": "Ilimitado", + "codexAuth.creditsOverage": "Limite de excedente atingido", + "codexAuth.creditsApprox": "Mensagens aprox.: local {local} · nuvem {cloud}", + "codexAuth.creditsToggle": "Créditos do Codex", + "codexAuth.creditsToggleHint": "Mostra os créditos restantes do Codex nos cartões das contas. Oculto por padrão.", + "codexAuth.creditsShown": "Créditos do Codex visíveis", + "codexAuth.creditsHidden": "Créditos do Codex ocultos", + "codexAuth.creditsToggleFailed": "Não foi possível alterar a configuração de créditos do Codex", + "codexAuth.refreshQuota": "Atualizar cotas", + "codexAuth.ultraFastTitle": "Nível de serviço Ultra Fast", + "codexAuth.mainHardLockTitle": "Bloquear conta principal (5h {short}%, longa {long}%)", + "codexAuth.mainHardLockDesc": "Bloqueia em {short}% na janela de 5h ou em {long}% na janela semanal (mensal, para contas apenas mensais). Desbloqueia quando todas as janelas bloqueantes ficam abaixo do limite; a proteção continua ativa. Ativada por padrão.", + "codexAuth.mainHardLockConfirmTitle": "Ativar a proteção da conta principal (5h {short}%, longa {long}%)?", + "codexAuth.mainHardLockConfirmBody": "Enquanto estiver bloqueada, a conta principal não pode usar a Luna Reserve. Manter o uso normal abaixo do esgotamento pode impedir a ativação da Reserve. As contas adicionadas e os outros provedores continuam disponíveis. Requisições em andamento, credenciais de keyring sem correspondência e tráfego fora deste proxy não são protegidos.", + "codexAuth.mainHardLockConfirm": "Ativar proteção", + "codexAuth.mainHardLockEnabled": "A proteção está ativada (5h {short}%, longa {long}%).", + "codexAuth.mainHardLockDisabled": "A proteção da conta principal está desativada. Os limites das outras contas continuam valendo.", + "codexAuth.mainHardLockLoadFailed": "Não foi possível carregar esta configuração. Tente de novo para verificar o estado atual.", + "codexAuth.mainHardLockSaveFailed": "Não foi possível confirmar o salvamento. Recarregue a configuração antes de tentar de novo.", + "codexAuth.mainHardLockRefreshFailed": "Configuração salva, mas não foi possível atualizar o status das contas. Tente novamente.", + "codexAuth.mainHardLockBlocked": "Bloqueada pela proteção da conta principal (5h {short}%, longa {long}%)", + "codexAuth.mainHardLockUnknown": "Proteção ativa · uso desconhecido", + "codexAuth.mainHardLockMonitoring": "Proteção ativa · monitorando", + "codexAuth.mainExternalUsageWarning": "Possível uso fora do opencodex. O bloqueio pode não impedir o esgotamento.", + "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 é regenerado e o nomeia nos logs de requisição. Não adiciona o Ultra Fast ao seletor de modelos: o upstream anuncia apenas o Fast, então uma linha no seletor ofereceria uma velocidade que a conexão não consegue 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 tem 100% de uso confirmado.", + "codexAuth.pauseExhaustedFailed": "Falha ao verificar e pausar as contas esgotadas.", + "codexAuth.noPool": "Nenhuma conta do pool foi adicionada ainda.", + "codexAuth.pause": "Pausar", + "codexAuth.resume": "Retomar", + "codexAuth.paused": "PAUSADA", + "codexAuth.planExcluded": "Não selecionada automaticamente", + "codexAuth.planExcludedHint": "O plano {plan} está excluído da seleção automática. As rotas explícitas por conta continuam disponíveis.", + "codexAuth.pauseSucceeded": "{email} está pausada", + "codexAuth.resumeSucceeded": "{email} voltou a ficar disponível para o pool", + "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ída da troca automática, das novas tentativas, da recuperação de cooldown e da seleção manual até ser retomada.", + "codexAuth.creditsAfterLimit": "Usar créditos após o limite", + "codexAuth.creditsAfterLimitHint": "Desativado por padrão: uma conta cuja janela de uso chega a 100% é retirada de uso até a janela reiniciar, para que seus créditos do ChatGPT não sejam gastos. Ative em uma conta para que ela continue trabalhando com seus créditos. Contas novas começam desativadas.", + "codexAuth.creditsAfterLimitAria": "Usar créditos após o limite de uso para {email}", + "codexAuth.creditsAfterLimitMainHint": "O bloqueio rígido da conta principal (ativado por padrão) ainda a interrompe primeiro. Desative o bloqueio para que a conta principal gaste créditos.", + "codexAuth.creditSpend": "Usar créditos", + "codexAuth.creditSpendAria": "Usar créditos do ChatGPT após o limite de uso", + "codexAuth.creditsOn": "Usa créditos", + "codexAuth.creditsOnSucceeded": "{email} pode usar créditos após o limite de uso.", + "codexAuth.creditsOffSucceeded": "{email} será retirada de uso ao atingir o limite, e seus créditos serão preservados.", + "codexAuth.creditsUpdateFailed": "Não foi possível atualizar a configuração de créditos de {email}. Nada foi alterado.", + "codexAuth.creditsAllOnSucceeded": "Agora todas as contas podem usar créditos após o limite de uso.", + "codexAuth.creditsAllOffSucceeded": "Nenhuma conta gastará créditos. As contas são retiradas de uso ao chegar a 100%.", + "codexAuth.creditsAllUpdateFailed": "Não foi possível atualizar a configuração de créditos. Nada foi alterado.", + "codexAuth.pinned": "FIXADA", + "codexAuth.pinnedHint": "Você selecionou esta conta manualmente, então uma ordem de seleção mais alta não passará por cima dela. A fixação dura até esta conta ser esgotada, você selecionar outra ou alterar qualquer ordem de seleção.", + "codexAuth.fiveHour": "5h", + "codexAuth.weekly": "Semana", + "codexAuth.quotaAutoRefresh": "Ativação automática da janela", + "codexAuth.quotaAutoRefreshHint": "Envia uma requisição mínima de aquecimento do Codex, sem armazenamento, quando esta janela de cota é reiniciada.", + "codexAuth.quotaAutoRefreshUpdated": "Ativação automática da janela atualizada.", + "codexAuth.quotaAutoRefreshFailed": "Não foi possível atualizar a ativação automática da janela.", + "codexAuth.monthly": "30d", + "codexAuth.resets": "reinicia", + "codexAuth.today": "Hoje", + "codexAuth.current": "ATUAL", + "codexAuth.nextSession": "SELECIONADA", + "codexAuth.poolPrepared": "PREPARADA PARA O POOL", + "codexAuth.preparePoolTitle": "Preparar esta conta para o modo Pool?", + "codexAuth.preparePoolDesc": "As requisições diretas continuam usando o login principal. Esta conta passa a ser a seleção preparada do Pool quando o modo Pool for ativado.", + "codexAuth.prepareForPool": "Preparar para o Pool", + "codexAuth.poolPreparedToast": "{email} está preparada para o modo Pool", + "codexAuth.switchTitle": "Trocar a conta ativa?", + "codexAuth.switchDesc": "Vale imediatamente. As threads com afinidade de conta e as requisições já em andamento mantêm a conta capturada; as requisições novas ou sem vínculo usam a faixa de ordem da conta selecionada, e as contas com a mesma ordem de seleção continuam se revezando.", + "codexAuth.cacheWarning": "O cache de prompt é reiniciado ao trocar de conta. A nova sessão começa com o cache vazio.", + "codexAuth.switchExceedsThresholdWarning": "O uso desta conta atinge ou excede o limite de troca ({threshold}%). A seleção fixada será liberada se não houver folga de cota.", + "codexAuth.setAsNext": "Usar esta conta em seguida", + "codexAuth.cancel": "Cancelar", + "codexAuth.switchBack": "Voltar para a conta principal?", + "codexAuth.switchBackDesc": "Vale imediatamente. As threads com afinidade de conta e as requisições já em andamento mantêm a conta capturada; as requisições novas ou sem vínculo usam a faixa de ordem da conta do login do app, e as contas com a mesma ordem de seleção continuam se revezando.", + "codexAuth.autoSwitch": "Troca proativa por uso", + "codexAuth.autoSwitchQuotaDesc": "Cota: com {threshold}% de uso ou mais, a próxima requisição sem vínculo pode ir para uma conta elegível de menor uso. As tarefas vinculadas mantêm a afinidade por padrão e só mudam quando a conta não consegue atender, e apenas para uma conta com folga real de cota; Go/Free usam somente 30d.", + "codexAuth.autoSwitchQuotaOffDesc": "A troca proativa por uso está desativada. A atribuição de tarefas novas/sem vínculo e a recuperação de falhas continuam valendo.", + "codexAuth.autoSwitchRoundRobinDesc": "A atribuição round-robin não usa este limite; continua alternando as tarefas novas/sem vínculo.", + "codexAuth.autoSwitchFillFirstDesc": "Fill-first: {threshold}% é o ponto de esgotamento para tarefas novas/sem vínculo; as tarefas vinculadas saudáveis mantêm a conta.", + "codexAuth.autoSwitchFillFirstOffDesc": "O fill-first não tem ponto de esgotamento por uso para tarefas novas/sem vínculo; cooldown, reautenticação e recuperação de falhas ainda podem mudar o roteamento.", + "codexAuth.failureRecoveryNote": "A recuperação de falhas é separada: uma requisição rejeitada antes de qualquer 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, em porcentagem", + "codexAuth.autoSwitchThresholdInc": "Aumentar o limite de uso", + "codexAuth.autoSwitchThresholdDec": "Diminuir o limite de uso", + "codexAuth.autoSwitchLoadFailed": "Não foi possível carregar a configuração de troca por uso.", + "codexAuth.autoSwitchThresholdInvalid": "Digite um número inteiro de 1 a 100", + "codexAuth.autoSwitchUpdated": "Troca proativa por uso atualizada", + "codexAuth.autoSwitchUpdateFailed": "Não foi possível confirmar a atualização da troca por uso. O último valor confirmado é exibido.", + "codexAuth.requestUserInput": "Pedir 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 - vale para novas sessões.", + "codexAuth.requestUserInputUpdatedRestart": "Feature flag atualizada - vale para novas sessões. Reinicie o app Codex para aplicá-la.", + "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 do config.toml.", + "codexAuth.accountPickerTitle": "Direcionar uma conta específica do Codex pelo seletor de modelos", + "codexAuth.accountPickerOffDesc": "Quando ativado, as linhas comuns de GPT no seletor são substituídas por uma entrada por seletor de conta, para que você escolha a conta exata de uma conversa sem precisar sair da sessão. Desativar não remove nenhuma conta.", + "codexAuth.accountPickerOnDesc": "Cada seletor é um rótulo público de uma conta armazenada. Escolhê-lo trava a conversa na conta mapeada: ela nunca alterna nem recorre a outra, e não muda a conta ativa do Pool.", + "codexAuth.accountPickerCompatibility": "O login integrado do app Codex tem seu próprio seletor; os mapas gerados normalmente o chamam de main e usam um sufixo à prova de colisão, como main-2, quando necessário. As contas adicionadas recebem rótulos estáveis que preservam a privacidade, enquanto os rótulos personalizados de seletor permanecem inalterados. As conversas existentes e as seleções de modelo salvas continuam roteando. Desativar oculta as entradas geradas, mas preserva os seletores e as rotas exatas. Os IDs simples de modelos GPT mantêm o 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 continua sendo exibido.", + "codexAuth.advancedSettings": "Configurações avançadas", + "codexAuth.advancedSettingsAria": "Mostrar ou ocultar as configurações avançadas do Codex Auth", + "codexAuth.catalogRefreshPending": "A alteração foi salva, mas a atualização do catálogo de modelos do Codex está pendente. Execute ocx sync para tentar de novo.", + "anthropicPool.title": "Pool de contas Claude (experimental)", + "anthropicPool.enabledDesc": "Sessões fixas, e as novas sessões preferem contas com uso abaixo de {threshold}% ({window}).", + "anthropicPool.enabledNoProactiveDesc": "Os limites de uso não movem uma sessão saudável existente nem uma conta ativa saudável. Quando a conta ativa fica indisponível, e durante a recuperação de recusa, é escolhida a conta com menor uso ({window}).", + "anthropicPool.enabledFillFirstDesc": "Sessões fixas. As novas sessões permanecem na conta ativa até ela atingir {threshold}% ({window}), entrar em cooldown ou precisar de novo login; depois passam para a próxima conta, em ordem. A recuperação de recusa também usa a próxima conta, em ordem.", + "anthropicPool.enabledFillFirstNoThresholdDesc": "Sessões fixas. As novas sessões permanecem na conta ativa até ela entrar em cooldown ou precisar de novo login; depois passam para a próxima conta, em ordem. A recuperação de recusa também usa a próxima conta, em ordem.", + "anthropicPool.enabledRoundRobinDesc": "Sessões fixas. As novas sessões e a recuperação de recusa se revezam entre as contas elegíveis; uso, limite e janela de cota não são considerados.", + "anthropicPool.disabledDesc": "A seleção proativa de contas está desativada. O OpenCodex usa a conta selecionada e ainda pode trocar após uma resposta de limite de taxa (429) ou uma recusa de conta classificada, quando houver outra conta elegível conectada.", + "anthropicPool.experimentalWarning": "Use apenas assinaturas que você possua ou esteja autorizado a usar. O pooling automatizado de contas não é endossado pela Anthropic e continua experimental. Use o cliente Claude Code genuíno com uma pessoa supervisionando a sessão e verifique os termos vigentes da Anthropic. As contas podem compartilhar a cota de uma organização, então adicionar uma conta pode não aumentar a capacidade.", + "anthropicPool.detailsSummary": "Como funciona a seleção de contas", + "anthropicPool.detailsEnabling": "Ativar o pool mantém cada sessão em sua conta enquanto ela estiver saudável e permite que a estratégia selecionada escolha as contas das novas sessões e após uma recusa.", + "anthropicPool.detailsFailover": "Desativá-lo não desativa o failover: após um 429 ou uma recusa de conta classificada, uma requisição ainda pode passar para outra conta conectada. Pause uma conta para mantê-la fora do failover.", + "anthropicPool.detailsActivity": "O OpenCodex não envia requisições keep-warm. Por padrão, não renova tokens do Claude nem consulta o uso em segundo plano; o uso só é lido quando o painel, o app da barra de menus ou um comando ocx o solicita.", + "anthropicPool.detailsGuide": "Guia do pool de contas", + "anthropicPool.needTwoAccounts": "Adicione pelo menos duas contas Claude OAuth antes de ativar o pool.", + "anthropicPool.threshold": "Limite de uso para novas sessões", + "anthropicPool.thresholdAria": "Limite de uso para novas sessões, em porcentagem", + "anthropicPool.thresholdHelp": "É uma preferência para a seleção de contas, não um limite rígido de uso ou de cobrança. 0 desativa a troca proativa por este limite. Padrão: 80%.", + "anthropicPool.thresholdInvalid": "Digite um número inteiro de 0 a 100", + "anthropicPool.loadFailed": "Não foi possível carregar as configurações do pool Claude.", + "anthropicPool.saveFailed": "Não foi possível salvar as configurações do pool Claude.", + "anthropicPool.on": "Ligado", + "anthropicPool.off": "Desligado", + "accountPool.strategy": "Estratégia de rotação", + "accountPool.strategyDesc": "Como o OpenCodex atribui uma conta a uma tarefa nova/sem vínculo.", + "accountPool.strategyResetFirst": "Reinício mais próximo primeiro", + "accountPool.strategyHintResetFirst": "Prefere o reinício de 5 horas ou semanal futuro mais próximo entre as contas abaixo do limite de uso. As tarefas vinculadas seguem a política de afinidade configurada. Cotas independentes por modelo usam a ordenação por cota.", + "accountPool.strategyQuota": "Cota", + "accountPool.strategyRoundRobin": "Round-robin", + "accountPool.strategyFillFirst": "Fill-first", + "accountPool.strategyHintQuota": "A cota revincula uma tarefa existente no limite de uso apenas quando `pool.cacheAffinity` está desativado (por padrão, ele vem ativado). Caso contrário, as tarefas vinculadas permanecem até a conta não conseguir atender, e então só vão para uma conta com folga real de cota.", + "accountPool.strategyHintRoundRobin": "O round-robin alterna apenas as tarefas sem vínculo ativo; o limite de uso não altera a rotação normal.", + "accountPool.strategyHintFillFirst": "O fill-first usa o limite como ponto de esgotamento para tarefas sem vínculo; as tarefas vinculadas saudáveis mantêm a afinidade.", + "accountPool.unboundDefinition": "Tarefa nova/sem vínculo é uma requisição sem vínculo atual com uma conta; uma tarefa visível existente pode ficar sem vínculo após um reset do proxy ou da afinidade.", + "accountPool.stickyLimit": "Atribuições novas/sem vínculo antes de alternar", + "accountPool.stickyLimitAria": "Atribuições novas/sem vínculo antes de alternar", + "accountPool.stickyLimitInc": "Aumentar o limite de fixação", + "accountPool.stickyLimitDec": "Diminuir o limite de fixação", + "accountPool.stickyLimitHelp": "Mantém a conta selecionada por esta quantidade de atribuições de tarefas novas/sem vínculo antes de avançar; o contador aumenta quando a tarefa é vinculada, não após o sucesso no upstream.", + "accountPool.stickyLimitInvalid": "Digite 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": "trocar em {threshold}%", + "accountPool.drainAtThreshold": "esgotar em {threshold}%", + "accountPool.resetBelowThreshold": "reinício mais próximo abaixo de {threshold}%", + "accountPool.thresholdNotUsed": "limite não utilizado", + "accountPool.proactiveSwitchingOff": "troca proativa desativada", + "accountPool.quotaWindow": "Janela de cota", + "accountPool.quotaWindowDesc": "Qual barra de uso em cache controla a seleção de novas sessões baseada em cota, as verificações de limite do fill-first e as substituições elegíveis por 429.", + "accountPool.quotaWindowFiveHour": "Barra de 5 horas", + "accountPool.quotaWindowWeekly": "Barra semanal", + "accountPool.quotaWindowMaxUtilization": "Barra mais alta", + "accountPool.quotaWindowHint": "A semanal ignora as contas cuja barra de 5 horas está esgotada enquanto houver outra conta elegível, mas recorre a elas quando não houver. Empates na semanal preferem o menor uso de 5 horas; as barras semanais por conta só são conhecidas depois que a página Provedores as consultar.", + "accountPool.quotaWindowInert": "Só a cota — ou o fill-first com limite acima de 0 — pontua uma barra de uso, então esta configuração não muda nada na estratégia de rotação atual.", + "accountPool.priority": "Ordem de seleção", + "accountPool.priorityAria": "Ordem de seleção desta conta", + "accountPool.priorityHint": "Números maiores 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": "Antes", + "accountPool.priorityNormal": "Normal", + "accountPool.priorityLater": "Depois", + "accountPool.priorityLast": "Última", + "accountPool.priorityOption": "{name} ({value})", + "accountPool.priorityCustom": "Personalizada", + "accountPool.priorityUpdated": "Ordem de seleção atualizada para {email}", + "accountPool.priorityUpdateFailed": "Não foi possível salvar a ordem de seleção de {email}. O último valor confirmado é exibido.", + "accountPool.autoSwitchThreshold": "Limite personalizado da conta", + "accountPool.autoSwitchThresholdAria": "Limite de uso de {email}", + "accountPool.autoSwitchOverrideAria": "Substituir o limite de uso global de {email}", + "accountPool.autoSwitchHint": "Substitui o limite global desta conta. 0 desativa a troca proativa por uso a partir desta conta.", + "accountPool.autoSwitchUpdated": "Limite de uso atualizado para {email}", + "accountPool.autoSwitchUpdateFailed": "Não foi possível salvar o limite de uso de {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 trocar de conta. Sua seleção anterior foi mantida.", + "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 reset", + "codexAuth.addJsonLabel": "Conteúdo do auth.json", + "codexAuth.addHelp": "Copie do ~/.codex/auth.json de outra máquina ou use codex-auth export.", + "codexAuth.importBtn": "Importar", + "codexAuth.importInvalidJson": "JSON inválido", + "codexAuth.importMissingTokens": "access_token ou refresh_token ausente no JSON", + "codexAuth.importMissingId": "O ID da conta é obrigatório", + "codexAuth.accountAdded": "Conta adicionada ao pool", + "codexAuth.addPickDesc": "Faça login com outra conta do ChatGPT para adicioná-la ao pool.", + "codexAuth.oauthLogin": "Login OAuth", + "codexAuth.oauthDesc": "Abre o login do ChatGPT no navegador", + "codexAuth.deviceLogin": "Login por código de dispositivo", + "codexAuth.deviceDesc": "Para proxy headless ou remoto: digite um código curto em outro dispositivo", + "codexAuth.importAuthJson": "Importar auth.json", + "codexAuth.importAuthJsonDesc": "De outra instalação do Codex ou de um codex-auth export", + "codexAuth.back": "Voltar", + "codexAuth.oauthAlreadyInProgress": "Já há um login em andamento. Conclua-o no navegador.", + "codexAuth.oauthWaiting": "Aguardando a conclusão do login do ChatGPT no navegador...", + "codexAuth.oauthSubmittingCode": "Enviando código…", + "codexAuth.oauthCodeSubmitted": "Código enviado — aguardando a conclusão do login…", + "codexAuth.oauthStatusRetrying": "Erro de rede ou de proxy ao verificar o status do login — tentando novamente…", + "codexAuth.oauthCancelled": "O login foi cancelado.", + "codexAuth.loginFailed": "Falha no login", + "codexAuth.needsReauth": "Refazer login", + "codexAuth.reauthenticate": "Reautenticar", + "codexAuth.tokenExpired": "Token expirado — reautentique esta conta", + "codexAuth.mainTokenExpired": "Token expirado — refaça o login com um código de dispositivo abaixo ou pelo login do Codex App", + "codexAuth.mainReauthSucceeded": "Login realizado", + "codexAuth.mainReauthFailed": "Falha ao refazer o login", + "codexAuth.mainReauthCancel": "Cancelar", + "codexAuth.mainReauthCode": "Código", + "codexAuth.mainReauthOpen": "Abrir", + "codexAuth.mainReauthPending": "Aguardando o login…", + "codexAuth.mainReauthDevice": "Refazer login com código de dispositivo", + "codexAuth.emailCollision": "Esta conta corresponde ao seu login principal do Codex. Use outra conta.", + "codexAuth.resetCreditsTitle": "Créditos de reset", + "codexAuth.resetCreditsAvailable": "Você tem {count} crédito(s) de reset disponível(is).", + "codexAuth.resetCreditsDesc": "Cada crédito zera imediatamente seus limites de uso por hora e por semana.", + "codexAuth.noResetCredits": "Você não tem créditos de reset.", + "codexAuth.earnCreditsHint": "Os créditos são ganhos mensalmente e pelo programa de indicação.", + "codexAuth.creditsExpireNote": "Os créditos expiram 30 dias após serem ganhos.", + "codexAuth.useOneCredit": "Usar 1 crédito", + "codexAuth.confirmResetTitle": "Usar crédito de reset?", + "codexAuth.confirmResetDesc": "Isso zerará imediatamente seus limites de taxa atuais. Restam {count} crédito(s).", + "codexAuth.irreversible": "Esta ação não pode ser desfeita.", + "codexAuth.useCredit": "Usar crédito", + "codexAuth.redeeming": "Zerando...", + "codexAuth.resetSuccess": "Limites de taxa zerados! Restam {remaining} crédito(s).", + "codexAuth.resetSuccessGeneric": "Limites de taxa zerados!", + "codexAuth.resetAlreadyRedeemed": "Este crédito já foi resgatado. Créditos inalterados.", + "codexAuth.resetNothingToReset": "Nenhuma janela de limite de taxa precisa ser zerada no momento.", + "codexAuth.resetNoCredit": "Nenhum crédito de reset disponível.", + "codexAuth.resetError": "Falha ao resgatar o crédito de reset. 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 usar", + "codexAuth.creditLabel": "Crédito nº {n}", + "codexAuth.creditNextBadge": "PRÓXIMO", + "codexAuth.creditGranted": "Concedido em {date}", + "codexAuth.creditExpires": "Expira em {date} ({days}d restantes)", + "grokCoupon.badgeAria": "{count} cupom(ns) de reset do Grok", + "grokCoupon.badgeErrorAria": "Não foi possível ler os cupons de reset do Grok", + "grokCoupon.title": "Cupons de reset do Grok", + "grokCoupon.available": "Esta conta tem {count} cupom(ns) de reset.", + "grokCoupon.desc": "Um cupom zera imediatamente a janela de uso do Grok desta conta.", + "grokCoupon.none": "Esta conta não tem cupons de reset.", + "grokCoupon.loadFailed": "Não foi possível ler os cupons de reset desta conta.", + "grokCoupon.loadFailedAuth": "Faça login novamente nesta conta xAI para ler os cupons.", + "grokCoupon.retry": "Tentar novamente", + "grokCoupon.couponLabel": "Cupom nº {n}", + "grokCoupon.couponNext": "Próximo a usar", + "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 reset?", + "grokCoupon.confirmDesc": "Isso zera agora a janela de uso do Grok desta conta. 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 antes. Nada foi consumido novamente.", + "grokCoupon.redeemFailed": "Falha no resgate. Confira a lista de cupons antes de tentar novamente.", + "grokCoupon.authFailed": "Faça login novamente nesta conta xAI para usar os cupons.", + "grokCoupon.noAccount": "Nenhuma conta xAI está disponível para este resgate.", + "grokCoupon.noneAvailable": "Não há cupons de reset disponíveis para resgatar.", + "grokCoupon.identityMismatch": "Esse resgate pertence a outra conta. Feche este diálogo e comece de novo.", + "grokCoupon.networkError": "Não foi possível alcançar o proxy.", + "grokCoupon.capacity": "O registro de resgates está cheio no momento. Tente novamente em instantes.", + "grokCoupon.noOperationId": "Este navegador não consegue gerar um ID de resgate, então o resgate está desativado aqui.", + "grokCoupon.unknownOutcome": "O resgate não respondeu a tempo, então seu resultado é desconhecido. Releia a conta para ver se o cupom foi gasto.", + "grokCoupon.checkResult": "Reler conta", + "grokCoupon.checking": "Relendo…", + "grokCoupon.consumedElsewhere": "O cupom não está mais nesta conta, então o resgate foi concluído.", + "grokCoupon.unresolved": "O cupom ainda aparece na lista. O resgate pode ainda estar em andamento no upstream — releia em um minuto antes de gastar outro cupom.", + "anthropicGrant.badgeAria": "{count} reset(s) de uso do Claude", + "anthropicGrant.badgeErrorAria": "Não foi possível ler os resets de uso do Claude", + "anthropicGrant.title": "Resets de uso do Claude", + "anthropicGrant.available": "Esta conta tem {count} reset(s) de uso.", + "anthropicGrant.desc": "Um reset recompõe imediatamente os limites de 5 horas e semanais do Claude desta conta. O dia do reset semanal permanece o mesmo.", + "anthropicGrant.none": "Esta conta não tem resets de uso.", + "anthropicGrant.ineligible": "Esta conta não é elegível para resets de uso no momento.", + "anthropicGrant.loadFailed": "Não foi possível ler os resets de uso desta conta.", + "anthropicGrant.loadFailedAuth": "Faça login novamente nesta conta Anthropic para ler os resets.", + "anthropicGrant.retry": "Tentar novamente", + "anthropicGrant.resetsLeft": "{left} de {total} restante(s)", + "anthropicGrant.validFrom": "Válido a partir de {date}", + "anthropicGrant.expires": "Expira em {date} ({days}d restantes)", + "anthropicGrant.windowFiveHour": "5 horas {percent}%", + "anthropicGrant.windowWeekly": "Semanal {percent}%", + "anthropicGrant.windowOverage": "Extra {percent}%", + "anthropicGrant.paused": "Pausado", + "anthropicGrant.notUsable": "Ainda não utilizável", + "anthropicGrant.requiresLimit": "Utilizável quando esta conta atingir um limite", + "anthropicGrant.useOne": "Usar 1 reset", + "anthropicGrant.confirmTitle": "Zerar os limites de uso agora?", + "anthropicGrant.confirmDesc": "Isso recompõe agora os limites de uso do Claude desta conta e consome um reset.", + "anthropicGrant.confirmWhich": "Usa: {label}", + "anthropicGrant.irreversible": "Esta ação não pode ser desfeita.", + "anthropicGrant.redeem": "Zerar limites", + "anthropicGrant.redeeming": "Zerando…", + "anthropicGrant.resultReset": "Limites zerados. Restam {count} reset(s).", + "anthropicGrant.resultAlreadyUsed": "Este reset já foi usado.", + "anthropicGrant.resultNotLimited": "Esta conta não está em um limite, então nada foi usado.", + "anthropicGrant.resultCooldown": "Os resets estão em período de espera para esta conta. Nada foi usado.", + "anthropicGrant.resultIneligible": "Esta conta não é mais elegível. Nada foi usado.", + "anthropicGrant.resultUnavailable": "Os resets estão indisponíveis no momento. Nada foi usado.", + "anthropicGrant.resultRateLimited": "Requisições demais. Nada foi usado; tente novamente em um minuto.", + "anthropicGrant.resultAuthError": "Faça login novamente nesta conta Anthropic. Nada foi usado.", + "anthropicGrant.replayed": "Este reset já foi concluído antes. Nada foi usado novamente.", + "anthropicGrant.notUsableNow": "Este reset não pode ser usado no momento. Releia a conta.", + "anthropicGrant.inFlight": "Este reset ainda está sendo processado. Aguarde um instante e releia a conta.", + "anthropicGrant.unresolvedPrior": "Uma tentativa anterior deste reset ainda não foi confirmada. Repita essa tentativa em vez de iniciar uma nova.", + "anthropicGrant.expired": "A tentativa anterior não pôde ser confirmada a tempo. Releia a conta antes de usar um reset.", + "anthropicGrant.identityMismatch": "Esse reset pertence a outra conta. Feche este diálogo e comece de novo.", + "anthropicGrant.sessionRequired": "Abra o painel pelo login próprio dele para usar os resets.", + "anthropicGrant.journalBusy": "O registro de resets está ocupado ou indisponível. Nada foi usado; tente novamente em instantes.", + "anthropicGrant.failed": "A requisição de reset falhou. Verifique a conta antes de tentar novamente.", + "anthropicGrant.noOperationId": "Este navegador não consegue gerar um ID de requisição, então os resets estão desativados aqui.", + "anthropicGrant.unknownOutcome": "O reset não respondeu a tempo, então seu resultado é desconhecido. Tentar de novo envia o mesmo ID de requisição, portanto não pode iniciar um segundo reset.", + "anthropicGrant.retrySame": "Repetir a mesma requisição", + "anthropicGrant.checkResult": "Reler conta", + "anthropicGrant.checking": "Relendo…", + "api.title": "Acesso à API", + "api.subtitle": "Use chaves de API geradas para acessar o proxy opencodex a partir de apps externos. As chaves se autenticam pelo cabeçalho {authHeader}; veja na tabela abaixo o que cada endpoint aceita.", + "api.baseUrl": "URL base", + "api.responsesEndpoint": "API Responses", + "api.chatCompletionsEndpoint": "API Chat Completions", + "api.messagesEndpoint": "API Messages", + "api.modelsEndpoint": "API 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 o Messages também desativa a integração com o Claude, para que uma versão mais antiga do opencodex mantenha o endpoint fechado também.", + "api.surface.openClaude": "Configurações do Claude", + "api.surface.toggleFailed": "Não foi possível salvar a configuração do 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 requisições a este endpoint são recusadas com 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 por loopback depende da rota; clientes de áudio independentes exigem uma chave de dados do OpenCodex. Binds remotos exigem uma chave de dados ou OPENCODEX_API_AUTH_TOKEN.", + "api.authBaseUrlNote": "Configure os clientes com a URL base e depois 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": "Modelos", + "api.section.examples": "Exemplos", + "api.section.plan": "Prévia do caminho", + "api.plan.title": "Prévia do caminho da requisição", + "api.plan.description": "Mostra o caminho que uma requisição para este modelo percorreria pelo proxy. A prévia não envia nada ao upstream e não tem custo.", + "api.plan.modeNote": "Nativo descreve como a requisição é entregue. Não é um resultado de verificação.", + "api.plan.unavailable": "Esta versão do proxy não oferece prévias de caminho.", + "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é-visualizar", + "api.plan.previewing": "Pré-visualizando…", + "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": "Sem caminho", + "api.plan.noFeatures": "Nenhum recurso de 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": "Degradada", + "api.plan.fidelity.unknown": "Desconhecida", + "api.plan.routeKind.direct": "Direta", + "api.plan.routeKind.combo": "Combo", + "api.plan.routeKind.policy": "Política de roteamento", + "api.plan.routeKind.unknown": "Modelo desconhecido", + "api.plan.disposition.passthrough": "Repassado", + "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? Isso não pode ser desfeito.", + "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": "Criada em", + "api.confirm": "Confirmar", + "api.deleteAria": "Excluir chave de API", + "api.modelsTitle": "Catálogo de modelos externos", + "api.modelsCount": "{count} chamável(is)", + "api.modelsLoading": "Carregando modelos…", + "api.modelsSearch": "Buscar modelos", + "api.modelsSubtitle": "Use exatamente estes IDs de modelo com /v1/models e o protocolo de entrada escolhido.", + "api.modelsEmpty": "Ainda não há modelos chamáveis externamente.", + "api.modelsNoMatch": "Nenhum modelo corresponde a “{query}”.", + "api.modelsLoadFailed": "Não foi possível carregar o catálogo de modelos externos.", + "api.colModel": "Modelo", + "api.colSource": "Origem", + "api.colProtocols": "Protocolos", + "api.sourceNative": "Pool do ChatGPT", + "api.sourceCombo": "Rota combo", + "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 cliente", + "api.clientConfig.rowsLabel": "Conectar um cliente", + "api.clientConfig.details": "Detalhes", + "api.clientConfig.detailsAria": "Detalhes da configuração de {client}", + "api.clientConfig.copyAria": "Copiar a configuração de {client}", + "api.clientConfig.downloadAria": "Baixar a configuração de {client}", + "api.clientConfig.rowMeta": "{destination} · {count} modelo(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.clientKilo": "Kilo", + "api.clientConfig.clientDroid": "Factory Droid", + "api.clientConfig.clineBundle": "Este é um pacote de dois arquivos, não um arquivo de configurações do Cline. Mescle settings em providers.json e catalog no models.json vizinho. Use o interruptor de integração para uma gravação com backup.", + "api.clientConfig.clineDownloaded": "{filename} baixado. Nada foi alterado ainda; settings e catalog pertencem a dois arquivos separados do Cline.", + "api.clientConfig.copy": "Copiar configuração", + "api.clientConfig.download": "Baixar", + "api.clientConfig.loading": "Gerando configuração do cliente…", + "api.clientConfig.jsonLabel": "Configuração de {client}", + "api.clientConfig.destination": "Arquivo de destino", + "api.clientConfig.envHint": "Defina a chave antes de iniciar", + "api.clientConfig.mergeWarning": "Mescle isto no arquivo de destino. Substituí-lo apagaria seus outros provedores e configurações de MCP.", + "api.clientConfig.modelCount": "{count} modelo(s) exportado(s)", + "api.clientConfig.missingLimits": "{count} de {total} modelo(s) saem sem limite de contexto; o cliente aplica seus próprios padrões.", + "api.clientConfig.noKeyYet": "{env} ainda não tem nenhuma chave por trás. Gere uma chave acima antes de usar esta configuração fora do loopback.", + "api.clientConfig.loadFailed": "Não foi possível ler a lista de modelos, então nenhuma configuração de cliente foi gerada.", + "api.clientConfig.copiedAnnounce": "Configuração do cliente copiada para a área de transferência.", + "api.clientConfig.copyFailed": "Não foi possível copiar a configuração do cliente.", + "api.clientConfig.downloadedAnnounce": "{filename} baixado. Nada foi alterado ainda — mescle-o você mesmo em {destination}.", + "api.clientConfig.whereDisclosure": "Onde este arquivo vai", + "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 cliente lê a chave da variável de ambiente indicada na configuração — nunca deste arquivo.", + "api.keysLoadFailed": "Não foi possível carregar as chaves de API.", + "api.createFailed": "Não foi possível criar a chave de API.", + "api.deleteFailed": "Não foi possível excluir a chave de API.", + "api.auth.endpoint": "Endpoint", + "api.auth.required": "Obrigatória", + "api.auth.accepted": "Aceita", + "api.auth.rejected": "Não aceita", + "api.auth.testProtocol": "Testar {protocol}", + "api.auth.testNeedsFreshKey": "Gere uma chave e mantenha seu valor único na tela para executar um teste autenticado.", + "api.key.name": "Nome da chave", + "api.key.rename": "Renomear", + "api.key.saveName": "Salvar nome", + "api.key.renaming": "Salvando…", + "api.key.renameFailed": "Não foi possível renomear a chave. Seu rascunho foi mantido.", + "api.key.deleting": "Excluindo…", + "api.rotation.title": "Rotação de chave", + "api.rotation.description": "Emita uma chave substituta enquanto a chave atual continua válida por um curto 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 cliente antes de confirmar.", + "api.rotation.expires": "A sobreposição expira em:", + "api.rotation.secretOnce": "Chave substituta — exibida uma única 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 a página antes de tentar novamente.", + "api.rotation.startFailed": "Não foi possível iniciar a rotação da chave.", + "api.key.copyFailed": "Não foi possível copiar a chave. Selecione-a e copie 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 usada desde o início da atribuição", + "api.attribution.unavailable": "Uso indisponível", + "api.attribution.unavailableDetail": "Nenhum uso foi atribuído ainda. As requisições registradas antes do início da atribuição não podem ser atribuídas retroativamente.", + "api.attribution.ambiguous": "Duas chaves compartilham este ID, então o uso não pode ser atribuído a nenhuma delas. Dê a cada chave um ID exclusivo no arquivo de configuração.", + "api.attribution.railAmbiguous": "ID duplicado", + "claude.subtitle": "Use GPT, Gemini e outros modelos dentro do Claude Code.", + "claude.pageTitle": "Claude Code", + "claude.workspace.settings": "Geral", + "claude.enabledLabel": "Conexão com o Claude", + "claude.enabledHint": "Quando desativada, o Claude Code não consegue usar este proxy.", + "claude.authMode": "Modo de autenticação", + "claude.authModeHint": "Assinatura exige conta Claude; 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": "Vale a partir da próxima inicialização", + "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": "Automático: assinatura — não foi possível verificar a autenticação", + "claude.effectiveMode.admissionKey": "A chave de API deste proxy continua sendo enviada.", + "claude.authSource.claude-json-oauth": "conta Claude", + "claude.authSource.claude-credentials-file": "arquivo de credenciais", + "claude.authSource.macos-keychain": "Keychain 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 ativada, executar 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": "⚠ É preciso fechar totalmente e reabrir o aplicativo de terminal para que isto tenha efeito. Não recomendado.", + "claude.fastMode": "Modo rápido (OpenAI)", + "claude.fastModeDesc": "Controla o service_tier dos modelos OpenAI. ON = priority (mais rápido). OFF = default. Auto = repasse (o cliente decide).", + "claude.fastAuto": "Auto", + "claude.fastOn": "ON", + "claude.fastOff": "OFF", + "claude.autoContext": "Usar contexto grande automaticamente", + "claude.autoContextDesc": "Controla até onde vai a marcação de 1M. ON: qualquer modelo cuja janela comporte o limite de compactação ganha uma linha de contexto grande. OFF: só os modelos de 1M de verdade ganham uma.", + "claude.autoContextInert": "Inativo porque existe um valor legado de tamanho de contexto (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": "As mensagens mais antigas são resumidas quando a conversa chega a este ponto. Ele nunca excede o limite de cada modelo, então modelos de 200k não são afetados.", + "claude.autoCompactWindowWarn": "Alterar isto pode quebrar modelos GPT — se for definido acima do limite real do modelo, as conversas darão erro antes de o resumo entrar em ação.", + "claude.injectAgents": "Registrar subagentes automaticamente", + "claude.injectAgentsDesc": "Registra os modelos escolhidos na aba Subagentes (mais o modelo padrão atual) como agentes despacháveis do Claude Code (ocx-*). Vale 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 nas requisições do Claude Code.", + "claude.visionSidecar": "Substituição do sidecar de visão", + "claude.visionSidecarHint": "Substitui o sidecar principal de visão nas requisições do Claude Code.", + "claude.useMainSetting": "Usar configuração principal", + "claude.sidecarModelPlaceholder": "Modelo da configuração principal", + "claude.quickstart": "Primeiros passos", + "claude.quickstartHint": "{cmd} abre o Claude Code por meio do proxy. Seu login no claude.ai continua ativo.", + "claude.manualEnv": "Configuração manual (avançado)", + "claude.smallFastModel": "Modelo auxiliar em segundo plano", + "claude.smallFastModelHint": "O modelo que o Claude Code usa em tarefas de segundo plano, como resumos de conversa e detecção de tópico. O alias de subagente haiku também o utiliza. Vazio = padrão do Claude (Haiku).", + "claude.smallFastModelAccurateHint": "O modelo que o Claude Code usa em tarefas de segundo plano, como resumos de conversa e detecção de tópico. O alias de subagente haiku também o utiliza.", + "claude.smallFastModelUnsetOption": "Deixar o Claude Code escolher (modelo nativo)", + "claude.smallFastModelNativeWarning": "Quando não definido, o OpenCodex deixa sem definir as substituições do modelo auxiliar. O Claude Code pode usar seu modelo Sonnet nativo, o que pode gerar cobranças do seu provedor nativo.", + "claude.slotUnset": "Usar padrão do Claude", + "claude.modelMap": "Interceptação de modelo", + "claude.modelMapHint": "Intercepta requisições de um modelo específico e as redireciona para o modelo que você escolher. Vazio por padrão: nada acontece até você adicionar uma regra.", + "claude.mapFrom": "Modelo original (ex.: claude-sonnet-4-5)", + "claude.mapTo": "Trocar por (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": "Outros", + "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á em execução?", + "claude.toggleAria": "Alternar conexão com o 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": "{model} criado.", + "cws.removed": "combo/{id} removido.", + "cws.renamed": "{from} renomeado para {to}.", + "cws.add": "Adicionar combo", + "cws.addTitle": "Adicionar combo", + "cws.addSubtitle": "Crie um modelo virtual entre provedores e escolha o nome exato do modelo que os clientes vão solicitar.", + "cws.create": "Criar combo", + "cws.jev.create": "Criar JEV Auto", + "cws.jev.exists": "O JEV Auto já existe.", + "cws.jev.setupHint": "Crie um Combo opcional e totalmente editável. O JEV escolhe um destino permitido e um esforço de raciocínio para cada requisição.", + "cws.jev.decisionService": "Serviço de decisão", + "cws.jev.decisionServiceDefault": "TypeSafe JEV (padrão)", + "cws.err.invalidDecisionProvider": "O serviço de decisão {name} não pode ser usado ({reason}). Escolha outro serviço ou o TypeSafe JEV.", + "cws.jev.decisionIssue.missing": "não configurado", + "cws.jev.decisionIssue.notDecision": "não é um serviço de decisão", + "cws.jev.decisionIssue.disabled": "desativado", + "cws.jev.decisionIssue.endpoint": "a URL base deve terminar em /systemone", + "cws.jev.decisionIssue.model": "sem modelo padrão", + "cws.jev.decisionServiceDefaultHint": "O serviço de decisão TypeSafe hospedado, autenticado com a chave do provedor jev.", + "cws.jev.decisionServiceHint": "Serviço de decisão auto-hospedado. Apenas a chave de API do próprio provedor é enviada ao seu endpoint:", + "cws.jev.decisionServicesTitle": "Serviços de decisão do JEV", + "cws.jev.decisionTimeout": "Timeout da decisão (ms)", + "cws.jev.decisionTimeoutHint": "Deixe vazio para o padrão ({default} ms); permitido de {min} a {max} ms. Quando expira, o JEV recorre ao primeiro destino elegível. Aumente para modelos auto-hospedados lentos ou frios.", + "cws.jev.decisionTimeoutShort": "Timeout de {ms} ms", + "cws.jev.decisionTimeoutDefaultShort": "Timeout padrão", + "cws.jev.decisionMethod": "Método de decisão", + "cws.jev.method.typesafe": "TypeSafe JEV (padrão)", + "cws.jev.method.systemone": "Servidor compatível com System One", + "cws.jev.method.model": "modelo do opencodex", + "cws.jev.method.systemoneEmpty": "Nenhum servidor System One está configurado. Adicione um provedor com o adaptador jev-decision cuja URL base termine em /systemone, por exemplo um servidor Ollama executando o tev1.", + "cws.jev.decisionModel": "Modelo de decisão", + "cws.jev.decisionModelHint": "Qualquer modelo que o opencodex roteie. Ele recebe o estado de decisão limitado e as opções permitidas e deve responder com uma chave de opção em JSON. Usa as credenciais armazenadas em seu próprio provedor, nunca as do chamador, e não pode ser este combo nem outro combo JEV.", + "cws.err.invalidDecisionModel": "Escolha um modelo de decisão que o opencodex consiga rotear. Ele não pode ser este combo nem outro combo JEV.", + "cws.jev.test": "Testar", + "cws.jev.testing": "Testando…", + "cws.jev.testHint": "Envia uma tarefa sintética com opções de exemplo ao método selecionado. Nada é salvo.", + "cws.jev.testOk": "Respondeu em {ms} ms via {backend}.", + "cws.jev.testFailOpen": "Falhou em modo aberto ({gate}) após {ms} ms. As requisições usariam o primeiro destino elegível.", + "cws.jev.testError": "Não foi possível executar o teste: {error}", + "cws.jev.backend.typesafe": "TypeSafe", + "cws.jev.backend.systemone": "Servidor System One", + "cws.jev.backend.model": "modelo do opencodex", + "cws.jev.backend.unknown": "Desconhecido (registros antigos)", + "cws.jev.stats.backends": "Decisões por método", + "cws.jev.stats.backend": "Método", + "cws.jev.stats.applied": "Aplicadas", + "cws.jev.stats.latency": "Latência média", + "cws.err.invalidDecisionTimeout": "O timeout da decisão deve ser um inteiro de {min} a {max} ms, ou vazio para o padrão.", + "cws.jev.failOpen": "Destino de fail-open", + "cws.jev.modelProfile": "Notas adicionais de modelo para o JEV", + "cws.jev.modelProfilePlaceholder": "Opcional: deixe em branco para nenhuma nota adicional.", + "cws.jev.modelProfileHint": "Notas opcionais que complementam (nunca substituem) o perfil padrão integrado: capacidade, contexto e custo relativo da assinatura. Enviadas ao serviço de decisão selecionado a cada decisão do JEV.", + "cws.err.invalidModelProfile": "As notas de modelo devem ter no máximo 512 caracteres; quebras de linha e tabulações são os únicos caracteres de controle permitidos.", + "cws.jev.allowedEfforts": "O JEV pode selecionar", + "cws.jev.efforts": "Esforços de raciocínio: {efforts}", + "cws.jev.effortsUnknown": "Esforços de raciocínio não informados", + "cws.jev.effortsNone": "Sem 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. 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} em fail-open", + "cws.jev.stats.modelTokens": "Tokens do modelo", + "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 informaram uso", + "cws.jev.stats.successful": "{count} requisiçõ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": "Portões 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": "Esforços", + "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": "Cache L/E", + "cws.jev.stats.total": "Total", + "cws.jev.stats.noEffort": "nenhum", + "cws.jev.stats.measuredShort": "medido", + "cws.jev.stats.tokenFootnote": "Os tokens do modelo vêm das tentativas físicas 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 destinos…", + "cws.noSearchResults": "Nenhum combo corresponde à busca.", + "cws.group.failover": "Failover", + "cws.group.roundRobin": "Round-robin", + "cws.group.other": "Outras estratégias", + "cws.targetCount": "{count} destinos", + "cws.targetCountOne": "1 destino", + "cws.overviewTitle": "Combos", + "cws.overviewBlurb": "Modelos virtuais que roteiam entre destinos provedor/modelo com failover, round-robin, sorteio ponderado, menos usado ou reinício de cota mais próximo.", + "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 público do modelo do combo. Se não houver um, o padrão é combo/. O OpenCodex seleciona um destino e só passa ao próximo em falhas recuperáveis do upstream. Se nenhum destino estiver disponível, a requisição falha em modo fechado em vez de usar o provedor padrão global.", + "cws.attentionTitle": "Requer atenção", + "cws.attention.empty": "Nenhum destino configurado", + "cws.attention.few": "Apenas um destino — o failover não tem para onde ir", + "cws.attention.catalogOmitted": "Ausente do catálogo de modelos — as capacidades dos membros estão incompletas ou incompatíveis (janela de contexto/metadados ausentes, ou interseção de modalidades vazia). O roteamento por alias continua funcionando", + "cws.attention.allTargetsExhausted": "Todos os destinos habilitados estão sem cota", + "cws.emptyTitle": "Crie seu primeiro combo", + "cws.empty.createDesc": "Dê 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 detalhe do combo", + "cws.tab.config": "Configuração", + "cws.tab.about": "Sobre", + "cws.strategy": "Estratégia", + "cws.strategy.failover": "Failover", + "cws.strategy.roundRobin": "Round-robin", + "cws.strategy.random": "Aleatória", + "cws.strategy.leastUsed": "Menos usado", + "cws.strategy.resetWindow": "Janela de reinício", + "cws.strategy.jev": "JEV", + "cws.strategy.failoverHint": "Tenta os destinos em ordem. Se o primeiro falhar com um erro recuperável (limite de taxa, indisponibilidade, bloqueio de assinatura), passa ao próximo.", + "cws.strategy.roundRobinHint": "Distribui o tráfego de forma determinística por peso. Mantém cada destino selecionado por um lote de requisições bem-sucedidas e depois avança.", + "cws.strategy.randomHint": "Sorteia um destino elegível por requisição, com probabilidade proporcional ao peso. Sem afinidade entre requisições.", + "cws.strategy.leastUsedHint": "Encaminha cada requisição ao destino elegível com menos sucessos registrados. As contagens reiniciam com o proxy.", + "cws.strategy.resetWindowHint": "Prefere o destino elegível cuja janela de cota reinicia primeiro. Recorre à ordem da configuração quando faltam dados de cota.", + "cws.strategy.jevHint": "Pede ao serviço de decisão JEV selecionado que escolha um destino elegível e um esforço compatível. Se a decisão estiver indisponível, usa 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 modelo", + "cws.field.aliasPlaceholder": "deepseek-v4-flash ou fornecedor/modelo", + "cws.field.aliasHint": "Opcional. Use um nome simples sem prefixo, um prefixo personalizado como fornecedor/modelo, 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 modelo nativo da OpenAI sem qualificador e compatível. As rotas da OpenAI qualificadas por conta e por provedor permanecem separadas.", + "cws.field.displayName": "Nome de exibição", + "cws.field.displayNameHint": "Rótulo deste combo no seletor. Obrigatório quando o alias nativo da OpenAI está habilitado.", + "cws.field.stickyLimit": "Sucessos fixos antes de alternar", + "cws.field.stickyLimitHint": "Mantém o destino selecionado por este número de requisições bem-sucedidas antes de o seletor ponderado avançar.", + "cws.field.defaultEffort": "Raciocínio padrão", + "cws.field.defaultEffortNone": "Nenhum (padrão do destino)", + "cws.field.defaultEffortHint": "Usado somente quando o cliente omite o esforço de raciocínio. As opções são a interseção dos esforços informados pelos destinos selecionados; destinos sem metadados de esforço no catálogo não oferecem nenhuma.", + "cws.capability.imageInputUnavailable": "Indisponível até que todos os destinos selecionados aceitem entrada de imagem.", + "cws.capability.imageInputHint": "Ativado por padrão quando todos os destinos aceitam imagens. Desative para aceitar somente texto.", + "cws.capability.imageInput": "Imagem / multimodal", + "cws.capability.adaptiveEffort": "Escala de raciocínio adaptativa", + "cws.capability.adaptiveEffortHint": "Desativado: um destino sem controle de raciocínio oculta o seletor de esforço para o combo inteiro. Ativado: esses destinos continuam utilizáveis e o seletor mantém os níveis compartilhados pelos demais destinos.", + "cws.capabilities": "Capacidades", + "cws.field.defaultEffortUnsupported": "Este esforço não está na escala comum dos destinos — será ignorado ou ajustado no momento da requisição.", + "cws.field.defaultEffortUnsupportedOption": "fora da interseção", + "cws.targets": "Destinos", + "cws.targets.failoverHint": "A ordem importa — o primeiro é o principal.", + "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 a probabilidade de cada sorteio; a ordem não importa.", + "cws.targets.leastUsedHint": "A ordem só desempata entre destinos igualmente usados.", + "cws.targets.resetWindowHint": "A ordem vale quando faltam dados de cota ou há empate.", + "cws.targets.jevHint": "Somente estes destinos podem ser selecionados. A ordem define o destino de fail-open e o fallback posterior do Combo.", + "cws.target.provider": "Provedor", + "cws.target.model": "Modelo", + "cws.target.weight": "Peso", + "cws.target.pickProvider": "Selecione o provedor…", + "cws.target.pickProviderFirst": "Selecione um provedor primeiro…", + "cws.target.pickModel": "Selecione o modelo…", + "cws.target.noModels": "Nenhum modelo para este provedor", + "cws.target.modelPlaceholder": "id do modelo", + "cws.target.add": "Adicionar destino", + "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": "Sem cota", + "cws.quota.unknown": "Cota desconhecida", + "cws.quota.allExhausted": "Todos os destinos habilitados estão sem cota. Escolha outro destino ou aguarde a recuperação da cota.", + "cws.aboutTitle": "Execução", + "cws.aboutBody": "Destinos que falham entram em pausa breve, respeitando o Retry-After. Erros de requisição inválida ou de contexto não passam ao próximo destino. Cada destino adapta o esforço às próprias capacidades; combos esgotados falham em modo fechado. Logs e Uso mantêm as tentativas físicas em ordem 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 é excluído.", + "cws.unsavedTitle": "Alterações não salvas", + "cws.unsavedDesc": "Descartar as edições deste combo e continuar?", + "cws.keepEditing": "Continuar editando", + "cws.err.missingId": "O id do combo é obrigatório.", + "cws.err.invalidId": "O id deve começar com letra ou número e usar apenas letras, números, pontos, sublinhados ou hifens (máx. 64).", + "cws.err.duplicateId": "Já existe um combo com este id.", + "cws.err.invalidAlias": "O alias deve usar letras, números, pontos, sublinhados ou hifens, com no máximo um segmento \"/\".", + "cws.err.aliasReservedNamespace": "O alias não pode usar o namespace reservado \"combo/\".", + "cws.err.aliasNativeFamily": "Aliases simples da 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 simples da OpenAI atualmente compatível.", + "cws.err.missingNativeAliasDisplayName": "É necessário um nome de exibição 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": "Outro combo já usa este alias.", + "cws.err.noTargets": "Adicione pelo menos um destino.", + "cws.err.incompleteTarget": "Cada destino precisa de um provedor e um modelo.", + "cws.target.disabled": "{name} (desabilitado)", + "cws.err.reservedNamespace": "Um provedor físico chamado combo precisa ser renomeado antes de criar combos.", + "cws.err.providerCollision": "O id do combo conflita com o nome de um provedor configurado.", + "cws.err.unknownProvider": "Cada destino deve usar um provedor configurado.", + "cws.err.duplicateTarget": "O mesmo destino provedor/modelo só pode aparecer uma vez.", + "cws.err.invalidStickyLimit": "Os sucessos fixos devem ser um número inteiro de 1 a 100.", + "cws.err.invalidWeight": "Cada peso de round-robin deve ser um número inteiro de 1 a 10000.", + "cws.err.invalidReasoningEfforts": "Cada destino do JEV deve permitir pelo menos um esforço de raciocínio único e compatível.", + "cws.err.noEnabledTarget": "Pelo menos um destino deve usar um provedor habilitado.", + "claude.tabsLabel": "Cliente Claude", + "claude.tabCode": "Code", + "claude.tabDesktop": "Desktop", + "claudeDesktop.title": "Claude Desktop", + "claudeDesktop.subtitle": "Roteia cada família de modelos do Claude por um modelo disponível na porta {port} do proxy.", + "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 aplicação não foi salvo — o estado salvo versus aplicado abaixo pode aparecer desatualizado até você aplicar 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": "Era esperado um perfil do Claude Desktop versão 1.", + "claudeDesktop.importReady": "JSON importado. Revise o rascunho e depois salve e aplique.", + "claudeDesktop.importedAnnounce": "JSON do perfil importado. As alterações não salvas estão 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 modelo disponível", + "claudeDesktop.emptyHint": "Adicione ou habilite um provedor e volte para atribuir rotas ao Claude Desktop.", + "claudeDesktop.assignmentsLabel": "Atribuições das famílias de modelos do Claude", + "claudeDesktop.family.opus": "Opus", + "claudeDesktop.family.fable": "Fable", + "claudeDesktop.family.sonnet": "Sonnet", + "claudeDesktop.family.haiku": "Haiku", + "claudeDesktop.modelCountOne": "{count} modelo", + "claudeDesktop.modelCountMany": "{count} modelos", + "claudeDesktop.chooseDefault": "Escolha um padrão", + "claudeDesktop.temporaryDefault": "Padrão temporário", + "claudeDesktop.laneEmpty": "Solte um modelo aqui ou use o controle Mover.", + "claudeDesktop.laneNoMatch": "Nenhum modelo desta família corresponde à sua busca.", + "nav.grok": "Grok", + "grok.title": "Grok Build", + "grok.subtitle": "Modelos 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á configurado", + "grok.notConfiguredHint": "Inicie ou reinicie o proxy com o Grok instalado e o opencodex grava um bloco gerenciado em:", + "grok.endpoint": "Endpoint", + "grok.colModel": "Modelo", + "grok.colAlias": "Alias do Grok", + "grok.colContext": "Contexto", + "grok.groupNative": "Modelos nativos", + "grok.groupRouted": "Modelos 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 — aplique novamente", + "claudeDesktop.status.notApplied": "Não aplicado", + "claudeDesktop.status.notActiveProfile": "O Desktop está usando outro perfil — aplique novamente", + "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 de modo e aplicar", + "claudeDesktop.status.appliedFirstParty": "Primeira parte: a aba Code do Desktop 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 continua conectado ao claude.ai. A aba Code usa o OpenCodex quando a primeira parte do Desktop está ativada; a CLI independente tem seu próprio interruptor. Ambos leem o mesmo env das configurações.", + "claude.intercept.start": "Iniciar interceptação", + "claude.intercept.starting": "Iniciando interceptação…", + "claude.intercept.reason.disabled": "Ative primeiro o roteamento e a interceptação do Claude.", + "claude.intercept.reason.client_role": "Este processo é um cliente do hub. Ative a interceptação em um servidor local.", + "claude.intercept.reason.ephemeral_port": "Defina claudeCode.intercept.port quando a porta pública for efêmera.", + "claude.intercept.reason.port_in_use": "A porta {port} está em uso. Libere-a ou altere claudeCode.intercept.port.", + "claude.intercept.reason.port_mismatch": "Esta execução usa a porta {bound}; a porta configurada {configured} é diferente. Use a porta vinculada ou restaure o valor configurado.", + "claude.intercept.reason.failed": "Não foi possível iniciar a interceptação. Tente novamente após verificar a configuração do proxy local.", + "claude.intercept.reason.stopped": "O ciclo de vida da interceptação foi encerrado. Inicie um serviço OpenCodex em execução.", + "claude.firstParty.label": "Primeira parte da CLI do Claude Code", + "claude.firstParty.desc": "Permite que a CLI claude independente mantenha o login do Claude enquanto seu tráfego passa pelo proxy de interceptação local.", + "claude.firstParty.aria": "Alternar primeira parte da CLI do Claude Code", + "claude.firstParty.risk": "Risco para a conta: a primeira parte encaminha o tráfego da assinatura do Claude por um proxy local de interceptação. A Anthropic pode tratar isso como violação dos termos e suspender a conta.", + "claude.firstParty.shared": "Quando o env compartilhado do proxy é aplicado, o outro cliente do Claude também passa pelo proxy local como um relay inalterado; o TLS é encerrado localmente. Defina NO_PROXY='*' no shell para uso totalmente nativo no terminal.", + "claude.firstParty.deadProxy": "O env das 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.notApplied": "A primeira parte da CLI está ativada, mas suas configurações de proxy não foram aplicadas. Verifique o env das configurações do Claude antes de usar o claude puro.", + "claude.firstParty.brokenProxy": "Não foi possível iniciar a interceptação. Tente novamente após verificar a configuração do proxy local.", + "claude.firstParty.residual": "As configurações do Claude ainda apontam para um proxy do OpenCodex, embora nem a primeira parte do Desktop nem a da CLI esteja ativada. Remova a configuração de proxy restante ou execute `ocx ensure`.", + "claude.firstParty.routingOff": "O opencodex não está atendendo à interceptação do Claude na configuração atual (o roteamento do Claude ou a interceptação está desativado, ou esta máquina é cliente de outro hub opencodex), então estas configurações apontam para um proxy que não vai atendê-las. Reative-o nesta máquina ou desative a primeira parte para remover as configurações.", + "claude.firstParty.disabled": "Ative primeiro o roteamento e a interceptação do Claude.", + "claude.firstParty.foreign": "O ~/.claude/settings.json aponta para o proxy do opencodex, mas confia em um certificado que o opencodex não gerencia, então as requisições falham. Corrija HTTPS_PROXY / NODE_EXTRA_CA_CERTS manualmente ali.", + "claude.firstParty.local": "O ~/.claude/settings.json envia o Claude Code por um proxy local em 127.0.0.1 que o opencodex não consegue confirmar como seu. Se você não o usa mais, remova HTTPS_PROXY dali.", + "claude.firstParty.unknown": "O opencodex não conseguiu determinar se o ~/.claude/settings.json ainda aponta para o seu proxy.", + "claude.firstParty.refusal.interceptDisabled": "O proxy de interceptação está desativado.", + "claude.firstParty.refusal.interceptUnavailable": "Não foi possível iniciar a interceptação. Tente novamente após verificar a configuração do proxy local.", + "claude.firstParty.refusal.foreignEnv": "Outro programa é dono das configurações de proxy do Claude.", + "claude.firstParty.refusal.caUnavailable": "A autoridade certificadora local está indisponível.", + "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.", + "claudeDesktop.mode.firstPartyRisk": "Risco para a conta: a primeira parte envia o tráfego da sua assinatura do Claude por um proxy local de interceptação. A Anthropic pode tratar isso como violação dos termos e suspender a conta. O Gateway é o padrão.", + "claudeDesktop.mode.gatewayHint": "O aplicativo inteiro passa a usar o OpenCodex como gateway. O chat roda localmente; os recursos do claude.ai ficam indisponíveis.", + "claudeDesktop.mode.switchNote": "A troca substitui a configuração do outro modo. Depois, feche completamente e reabra o Desktop.", + "claudeDesktop.firstParty.proxyRunning": "Proxy local em 127.0.0.1:{port}", + "claudeDesktop.firstParty.proxyStopped": "Não foi possível iniciar a interceptação. Tente novamente após verificar a configuração do proxy local. ({port})", + "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": "Mostra 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": "Feche completamente e reabra o Claude Desktop para concluir a aplicação do perfil do seletor.", + "claudeDesktop.picker.state.trustPending": "Aguardando a etapa do chaveiro", + "claudeDesktop.picker.state.trustDeclined": "A confiança no chaveiro foi recusada", + "claudeDesktop.picker.state.proxyUnavailable": "O proxy do seletor não está em execução", + "claudeDesktop.picker.state.unsupported": "O modo seletor não é compatível com este sistema operacional", + "claudeDesktop.picker.state.notFirstParty": "O seletor só está disponível 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": "Com o modo seletor ativado, o Claude Desktop acessa a rede por meio do OpenCodex. Se o OpenCodex parar, o Desktop fica offline até ele reiniciar ou o modo seletor ser desativado.", + "claudeDesktop.firstParty.bindings.title": "Vínculos de modelo da aba Code", + "claudeDesktop.firstParty.bindings.hint": "O Claude Desktop mantém os nomes da Anthropic no seletor da aba Code. Vincule um modelo do seletor a um modelo do OpenCodex e as requisições dessa entrada do seletor serão atendidas pelo modelo vinculado. Somente o tráfego do Claude Code pelo proxy local (a aba Code do Desktop e a CLI claude) usa estes vínculos; o ocx claude não é afetado. Os vínculos valem a partir da próxima requisição — não é preciso fechar e reabrir completamente.", + "claudeDesktop.firstParty.bindings.empty": "Ainda não há vínculos — os modelos do seletor seguem a rota 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 vínculo", + "claudeDesktop.firstParty.bindings.remove": "Remover vínculo {id}", + "claudeDesktop.firstParty.bindings.saveFailed": "Não foi possível salvar os vínculos de modelo", + "claudeDesktop.health.lastRequest": "Última requisição", + "claudeDesktop.health.stats": "{count} req / {errors} err", + "claudeDesktop.effort.supported": "esforço", + "claudeDesktop.effort.displayOnly": "esforço (apenas exibição)", + "lab.title": "Laboratório de Compatibilidade", + "lab.subtitle": "Matriz de veredictos de compatibilidade somente leitura, a partir de evidências da 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 primeiro a conformidade ou as sondagens ao vivo.", + "lab.projectionIncompatible": "O esquema da 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 veredicto", + "lab.filter.layer": "Camada de evidência", + "lab.filter.verdict": "Veredicto", + "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": "Veredicto", + "lab.col.asOf": "Posição em", + "lab.col.protocol": "Conformidade de protocolo", + "lab.col.live": "Compatibilidade de rota ao vivo", + "lab.col.task": "Eficácia na tarefa", + "lab.empty": "Ainda não há veredictos de compatibilidade na projeção.", + "lab.subjectKind": "Tipo", + "lab.observationCount": "Observações", + "lab.eventCount": "Eventos", + "lab.verdictCount": "Veredictos", + "lab.subjectCount": "Assuntos", + "lab.builtAt": "Gerado em", + "lab.loading": "Carregando evidências de compatibilidade…", + "lab.loadMore": "Carregar mais", + "lab.detailTitle": "Detalhe do veredicto", + "lab.detailClose": "Fechar", + "lab.detailSubject": "Assunto", + "lab.detailObservations": "Observações", + "lab.detailEvents": "Eventos contribuintes", + "lab.detailArtifacts": "Metadados dos artefatos", + "lab.production.title": "Tráfego de produção observado", + "lab.production.notVerification": "Não é verificação do Laboratório", + "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 o detalhe do veredicto", + "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": "Sem suporte", + "lab.layer.protocol_conformance": "Conformidade de protocolo", + "lab.layer.live_route_compatibility": "Compatibilidade de rota ao vivo", + "lab.layer.task_effectiveness": "Eficácia na tarefa", + "models.newPolicyGlobal": "Novos modelos começam desativados", + "models.newPolicyProvider": "Política de novos modelos", + "models.fastProvider": "Modo rápido", + "models.fastProviderHint": "Consome créditos de uso a 2x o preço", + "models.fastEnabled": "Modo rápido ativado", + "models.fastDisabled": "Modo rápido desativado", + "models.fastSaveFailed": "Não foi possível salvar o modo Fast", + "models.newPolicy_inherit": "Herdar", + "models.newPolicy_off": "Desativado", + "models.newPolicy_on": "Ativado", + "models.newBadge": "NOVO", + "models.newCount": "{count} novos, desativados", + "models.aliases": "Aliases", + "models.aliasesTable": "Tabela de aliases", + "models.aliasPrompt": "Alias do provedor (deixe vazio para limpar)", + "models.modelAliasPrompt": "Alias do modelo (deixe vazio para limpar)", + "models.aliasSaved": "Alias salvo", + "models.aliasConflict": "Esse alias conflita com um nome existente", + "models.editProviderAlias": "Editar alias do provedor", + "models.editModelAlias": "Editar alias do modelo", + "models.useDefaultAliases": "Usar aliases padrão", + "models.useDefaultAliasesGlobal": "Usar aliases padrão globalmente", + "models.aliasAuto": "auto", + "models.aliasUser": "usuário", + "models.aliasStale": "obsoleto", + "connection.discovering": "Descobrindo destinos locais e compartilhados…", + "connection.machineUnavailable": "O plano da máquina local está indisponível. As requisições compartilhadas não foram redirecionadas para o local.", + "connection.disconnect": "Desconectar do hub", + "connection.disconnectConfirm": "Desconectar esta máquina do hub e reiniciá-la no modo standalone?", + "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 a ela este comando e peça um código de pareamento de uso único.", + "connection.pairing.notApiKey": "Cole aqui um código de pareamento de uso único. Chaves de API de dados e tokens de administrador não devem ser colocados neste campo.", + "connection.pairing.networkError": "Não foi possível alcançar o hub. Verifique a conexão e tente novamente; seu código continua aqui.", + "connection.pairing.requestError": "O hub não conseguiu 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 navegador válida. Atualize o hub ou fale com o operador dele e tente novamente.", + "dash.authRequired": "É necessária autenticação do navegador para ver este dashboard.", + "dash.permissionDenied": "Este navegador 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": "Exibindo os últimos dados recebidos; podem estar desatualizados.", + "connection.pairing.title": "Conectar este dashboard ao hub", + "connection.pairing.body": "Cole o código de pareamento de uso ú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 de uso ú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 para que você possa conferi-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": "Fonte: uso do hub", + "usage.source.local": "Fonte: usage.jsonl local", + "usage.scope.label": "Escopo de uso", + "usage.scope.machine": "Esta máquina", + "usage.scope.hub": "Todo o hub", + "usage.hubOffline": "O uso do hub está indisponível. O uso local não foi usado como substituto.", + "models.displayNameSavedRefreshFailed": "A alteração foi salva, mas não foi possível atualizar a lista de modelos. Tente novamente para atualizá-la.", + "models.displayNameOutcomeUnknown": "A requisiçã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 modelos atualizada", + "models.displayNameAction": "Nome", + "models.displayNameActionLabel": "Editar nome amigável de {model}", + "models.displayNameTitle": "Nome amigável", + "models.displayNameModelId": "ID do modelo", + "models.displayNameCurrent": "Nome atual", + "models.displayNameSourceOperator": "Seu nome", + "models.displayNameSourceProvider": "Nome do provedor", + "models.displayNameSourceFallback": "Fallback para o ID do modelo", + "models.displayNameField": "Nome amigável", + "models.displayNamePlaceholder": "ex.: Grok 4.6", + "models.displayNameHelp": "Altera apenas a apresentação. O roteamento continua {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": "Informe um nome amigável ou use Redefinir nome.", + "models.displayNameTooLong": "O nome amigável deve ter no máximo 128 caracteres.", + "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 de {model}", + "pricing.override.badge": "Preço manual", + "pricing.override.title": "Preço do modelo", + "pricing.override.modelId": "ID do modelo", + "pricing.override.help": "USD por 1M de tokens. Informe as taxas de entrada e saída; taxas de cache em branco usam 0. As quatro taxas em 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 de novo.", + "pricing.override.outcomeUnknown": "A requisição não terminou 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 continua bloqueada; recarregue para tentar de novo.", + "pricing.override.recovered": "Último preço salvo carregado. A requisição anterior ou outro cliente ainda pode alterá-lo.", + "pricing.override.refreshFailed": "O preço foi salvo, mas não foi possível atualizar a lista de modelos. Tente atualizar a lista novamente.", + "pricing.override.invalid": "Informe as taxas de entrada e saída. Cada taxa deve ser um número finito de 0 a 1.000.000.", + "pricing.override.reset": "Voltar ao 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": "Intervalo de datas 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 o minuto final inteiro.", + "usage.range.required": "Informe a data e hora de início e de fim.", + "usage.range.invalid": "Informe datas e horas locais válidas, a partir de 01/01/1970 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 modelos roteados e salve seu rascunho. As linhas em destaque são fixas; modelos nativos não são exibidos.", + "models.pickerOrder.nativeLocked": "Esta ordem salva inclui modelos nativos. Aplique um preset roteado ou Padrão antes de editar o Personalizado.", + "models.pickerOrder.unknownChosen": "As escolhas em destaque são desconhecidas. Recarregue antes de editar.", + "models.pickerOrder.changed": "As configurações do seletor mudaram. 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 requisição falhou. Seu rascunho foi mantido; tente novamente ou recarregue.", + "models.pickerOrder.empty": "Nenhum modelo roteado disponível.", + "models.pickerOrder.dragModel": "Arrastar {model}", + "models.pickerOrder.featured": "Em 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 dos modelos estão ausentes ou ambíguas. Recarregue a página Modelos para atualizar o catálogo antes de editar o Personalizado.", + "nav.remote": "Remote Link", + "nav.remoteWorkspace": "Workspace remoto", + "link.title": "Remote Link", + "link.subtitle": "Conecte outro computador com OpenCodex por SSH.", + "link.switch": "Vinculaçã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": "O Home compartilha os provedores deste computador com computadores Child. O Child conecta este computador a um Home quando ele roda no modo standalone.", + "link.role.home": "Principal", + "link.role.homeHint": "Gerencie computadores Child a partir deste dashboard.", + "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 local do dashboard para gerenciar vínculos.", + "link.workspaceUnavailable": "O Remote Workspace não está disponível nesta instalação.", + "link.loading": "Carregando…", + "link.loadFailed": "Não foi possível carregar o status do Remote Link.", + "link.refresh": "Atualizar", + "link.children": "Computadores Child", + "link.addChild": "Adicionar Child", + "link.sheetTitle": "Adicionar um computador Child", + "link.candidates": "Hosts SSH", + "link.noCandidates": "Nenhum host SSH candidato foi encontrado.", + "link.alias": "Alias do host SSH", + "link.aliasPlaceholder": "Informe 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 Child", + "link.applying": "Conectando…", + "link.retry": "Tentar novamente", + "link.disconnect": "Desconectar", + "link.disconnectConfirm": "Desconectar {alias}? A chave de vínculo dele será revogada.", + "link.close": "Fechar", + "link.cancel": "Cancelar", + "remoteLink.childDisabled": "Vínculos Child só podem ser iniciados a partir de um runtime standalone.", + "remoteLink.findHome.title": "Encontrar Home", + "remoteLink.findHome.body": "Escolha o computador Home ao qual conectar este Child.", + "remoteLink.findHome.action": "Encontrar Home", + "remoteLink.findHome.connect": "Conectar como Child", + "remoteLink.findHome.notice": "Conectar reinicia o OpenCodex neste computador. Os turnos do Codex em andamento 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 os próprios provedores e contas.", + "remoteLink.findHome.empty": "Ainda não conectado a um Home.", + "remoteLink.joining": "Entrando no Home…", + "remoteLink.restart.title": "Este computador será reiniciado para se conectar como Child.", + "remoteLink.restart.body": "Os turnos do Codex em execução terminam primeiro; depois o OpenCodex é reiniciado como Child. Esta página recarrega sozinha quando o Child estiver pronto.", + "remoteLink.restart.waiting": "Aguardando este computador se reconectar como Child…", + "remoteLink.restart.slow": "A reinicialização está demorando mais que o normal. Esta página continua verificando e recarrega sozinha assim que o Child responder. Se o OpenCodex parou, inicie-o novamente.", + "remoteLink.error.standalone_required": "Vínculos Child só podem ser iniciados a partir de um runtime standalone.", + "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 o novo vínculo. Verifique se ele está em execução e tente novamente.", + "remoteLink.error.join_issue_failed": "O Home não conseguiu emitir um vínculo. 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 vínculo remoto.", + "remoteLink.error.join_port_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.join_port_mismatch": "O OpenCodex não está rodando na porta configurada, por isso não pode reiniciar como Child. Reinicie o OpenCodex na porta configurada e tente novamente.", + "remoteLink.error.join_rollback_failed": "A entrada falhou e o vínculo no Home não pôde ser removido. Tente a limpeza novamente ou execute ocx link revoke no Home.", + "remoteLink.error.join_restart_failed": "O vínculo está pronto. Reinicie o OpenCodex neste computador para concluir a conexão como Child.", + "remoteLink.error.join_connect_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "link.noChildren": "Nenhum computador Child conectado.", + "remoteLink.status.connecting": "Conectando", + "remoteLink.status.connected": "Conectado", + "remoteLink.status.reconnecting": "Reconectando", + "remoteLink.status.failed": "A conexão precisa de atenção", + "remoteLink.status.idle": "Ocioso", + "remoteLink.role.standalone": "Independente", + "remoteLink.role.home": "Principal", + "remoteLink.role.child": "Secundário", + "remoteLink.direction.hub": "Iniciado pelo hub", + "remoteLink.direction.client": "Iniciado 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 ler a chave do host SSH. Teste a conexão novamente.", + "remoteLink.error.forbidden": "Esta sessão do dashboard não pode gerenciar vínculos remotos. Abra o dashboard neste computador (instalação standalone) ou use uma sessão de Hub pareada.", + "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 vínculo remoto.", + "remoteLink.error.link_apply_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.link_exists": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.link_not_found": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.link_remove_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.link_unavailable": "O Remote Link não está disponível neste runtime. Reinicie o OpenCodex e tente novamente.", + "remoteLink.error.listener_unavailable": "O listener do Remote Link não pôde ser iniciado neste computador. Verifique se há conflito de porta e tente novamente.", + "remoteLink.error.probe_failed": "Não foi possível conectar ao host SSH. Verifique se ele aceita sua chave SSH e se o auxiliar de ProxyCommand está instalado.", + "remoteLink.error.remote_connect_failed": "O computador remoto não conseguiu se conectar a este Home. Verifique o serviço OpenCodex dele e tente novamente.", + "remoteLink.error.remote_disconnect_failed": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.remote_ocx_missing": "O ocx não foi encontrado no computador remoto. Instale o OpenCodex lá ou garanta que o ocx esteja no PATH das sessões SSH não interativas.", + "remoteLink.error.remote_ocx_outdated": "O OpenCodex no computador remoto é antigo demais para o Remote Link. Execute ocx update lá (2.66.0 ou posterior) e tente novamente.", + "remoteLink.error.remote_ocx_unrecognized": "O computador remoto não informou uma versão do OpenCodex. O Remote Link exige o OpenCodex 2.66.0 ou posterior no macOS ou Linux.", + "remoteLink.error.remote_port_failed": "O computador remoto não conseguiu informar a porta de vínculo. Verifique se o OpenCodex 2.66.0 ou posterior está em execução lá e tente novamente.", + "remoteLink.error.tailscale_session_refused": "Não foi possível concluir a solicitação de vínculo remoto.", + "remoteLink.error.version_probe_failed": "Não foi possível executar o ocx no computador remoto por SSH. Verifique o acesso SSH e tente novamente.", + "remoteLink.error.generic": "Não foi possível concluir a solicitação de vínculo remoto.", + "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": "A conexão expirou.", + "remoteLink.reason.bind": "Não foi possível associar a porta local.", + "remoteLink.reason.persist": "Não foi possível salvar o estado do vínculo.", + "remoteLink.reason.compensation_failed": "A limpeza após a vinculação falhou.", + "remoteLink.reason.staleTunnel": "Um túnel obsoleto ainda pode estar mantendo a porta.", + "remoteLink.reason.generic": "Motivo:", + "remoteLink.workspaceMoved.title": "O Remote Workspace agora tem página própria", + "remoteLink.workspaceMoved.body": "Use a página separada do Remote Workspace.", + "remoteLink.workspaceMoved.open": "Abrir Remote Workspace", + "remoteLink.forceRemove.title": "Esta máquina não conseguiu alcançar {alias}", + "remoteLink.forceRemove.body": "Remover o vínculo somente nesta máquina? Depois, execute {cmd} você mesmo em {alias}.", + "remoteLink.forceRemove.confirm": "Remover somente aqui", + "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 Remote Workspace…", + "remote.loadFailed": "Não foi possível carregar o Remote Workspace.", + "remote.hubRequired": "Use o modo Hub e inicie o Hub com OCX_REMOTE_WORKSPACE_ENABLED=1 para ativar o Remote Workspace.", + "remote.refresh": "Atualizar", + "remote.addComputer": "Adicionar um computador", + "remote.addComputerHint": "Aprove uma ou mais pastas localmente e 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 código", + "remote.access": "Acesso ao workspace", + "remote.access.readOnly": "Somente leitura", + "remote.access.workspace": "Editar arquivos e executar comandos", + "remote.access.workspaceFilesOnly": "Somente editar arquivos", + "remote.unavailable": "Indisponível", + "remote.capability.full": "Arquivos + comandos em sandbox", + "remote.capability.files": "Somente ferramentas de arquivo", + "remote.runsOnHub": "O modelo 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 rodam aqui; sandbox de comandos indisponível", + "remote.execUnavailable": "Este computador pode editar arquivos, mas builds e comandos de terminal estão desativados porque não há um sandbox de SO compatível.", + "remote.notResumable": "Esta sessão parou antes de o agente de código criar 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 código para começar.", + "remote.events": "Atividade da sessão remota", + "remote.noEvents": "Nenhuma atividade ainda.", + "remote.prompt": "Mensagem", + "remote.promptPlaceholder": "Peça ao agente do Hub para trabalhar dentro da pasta remota selecionada…", + "remote.send": "Enviar", + "remote.stop": "Parar 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 de cota dos provedores", + "quotaSummary.updated": "Atualizado {time}", + "quotaSummary.dataAt": "Dados de {time}", + "quotaSummary.observedAt": "Observado em {time}", + "quotaSummary.warn": "70%+ usado", + "quotaSummary.critical": "90%+ usado", + "quotaSummary.credits": "Créditos", + "quotaSummary.refreshFailed": "A última atualização falhou; exibindo a leitura anterior", + "quotaSummary.scrollPrev": "Rolar provedores para a esquerda", + "quotaSummary.scrollNext": "Rolar provedores para a direita", + "quotaSummary.openAccounts": "Abrir gerenciamento de contas", + "pws.protocol.title": "Wire upstream", + "pws.protocol.note": "O formato de API que o opencodex usa para falar com este provedor. Ele não ativa nem desativa nenhuma API de cliente; a página de API controla isso.", + "pws.protocol.adapterLabel": "Wire upstream 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 de salvar, este provedor receberá {adapter}.", + "pws.protocol.overrides": "Modelos em outro wire", + "pws.protocol.noOverrides": "Todos os modelos usam o wire do provedor.", + "pws.protocol.overridesTruncated": "Exibindo os primeiros {count} modelos.", + "pws.protocol.col.model": "Modelo", + "pws.protocol.col.wire": "Wire", + "pws.protocol.col.source": "Definido por", + "pws.protocol.loadFailed": "Não foi possível carregar o wire upstream.", + "compatProtocol.filter.inbound": "API do cliente", + "compatProtocol.filter.upstream": "Wire upstream", + "compatProtocol.anyProtocol": "qualquer", + "compatProtocol.pair": "{inbound} → {upstream}", + "compatProtocol.loading": "Lendo o par de protocolos de cada subject…", + "compatProtocol.unverified": "Ainda não há evidência do Lab para {pair}. O par não foi verificado, não que tenha falhado.", + "compatProtocol.unresolved": "Não foi possível ler o par de protocolos de {count} subjects; eles ficam fora deste filtro.", + "compatProtocol.axisNote": "Estes são apenas veredictos do Lab. A forma como uma requisição é entregue (nativa ou traduzida) é mostrada na prévia do caminho da requisição, na página de API.", + "protocolLinks.labEvidence": "Evidência do Lab para este par", + "protocolLinks.providerSettings": "Configurações do provedor", + "cws.plan.title": "Caminhos candidatos", + "cws.plan.description": "Pergunta ao proxy como cada destino carregaria uma requisição com todos os recursos que a API do cliente consegue expressar, e quais recursos todos os destinos preservam. Nada é enviado ao upstream.", + "cws.plan.run": "Mostrar caminhos candidatos", + "cws.plan.savedOnly": "Mostra o combo salvo. Salve suas alterações para visualizá-las.", +}; diff --git a/gui/src/i18n/routing-compatibility-labels.ts b/gui/src/i18n/routing-compatibility-labels.ts index c4e3de76b6b..42b8d75a8ad 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..f09e35c304c 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"; 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: { label: "Requisição inválida", description: "O proxy não conseguiu entender a requisição. Verifique o modelo, a estrutura das mensagens, os cabeçalhos 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: { label: "Não autorizado", description: "As credenciais estão ausentes, expiradas ou inválidas. Faça login novamente ou atualize as credenciais da 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: { label: "Pagamento necessário", description: "O provedor upstream rejeitou a requisição porque 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: { label: "Acesso negado", description: "A conta está autenticada, mas não tem permissão para usar este modelo ou esta operação. Costuma ser limite de plano/assinatura (ex.: Ollama Cloud Pro), política da organização ou permissão do modelo — não necessariamente uma API key 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: { label: "Não encontrado", description: "A rota, o modelo, a conta ou o recurso upstream solicitado não foi encontrado. Verifique o nome do modelo e a configuração do provedor no 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: { label: "Tempo limite da requisição", description: "A requisição demorou demais para o proxy ou o provedor upstream 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: { label: "Conflito", description: "A requisição conflita com o estado atual da conta, da sessão ou do provedor. Atualize a sessão ou tente novamente quando a operação ativa terminar." }, }, 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: { label: "Requisição grande demais", description: "O prompt, os anexos ou o conteúdo gerado excedem um limite do proxy ou do upstream. Reduza tokens, tamanho de arquivos 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: { label: "Conteúdo inválido", description: "O provedor aceitou o formato da requisição, mas rejeitou o conteúdo. Verifique as opções do modelo, as definições de ferramentas, os papéis das mensagens 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: { label: "Falha em dependência do provedor", description: "Uma dependência upstream necessária falhou enquanto o opencodex roteava a requisição. Tente novamente mais tarde ou troque 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: { label: "Limite de requisições excedido", description: "O limite de taxa ou de 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: { label: "Requisição encerrada pelo cliente", description: "O cliente desconectou ou cancelou a requisição antes de o opencodex terminar de rotear. 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: { label: "Erro do proxy", description: "O opencodex encontrou um erro interno ao tratar a requisição. Tente novamente uma vez; se repetir, 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: { label: "Resposta upstream inválida", 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: { label: "Provedor indisponível", description: "O proxy ou o provedor upstream está temporariamente indisponível ou sobrecarregado. Aguarde um instante 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: { 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: { label: "Provedor sobrecarregado", description: "O provedor upstream está sobrecarregado ou com capacidade limitada. Aguarde e tente novamente, ou troque para outra 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: { label: "Erro na requisição", description: "O proxy ou o provedor upstream rejeitou a requisição. Verifique a estrutura da requisição, as credenciais, o nome do modelo e a 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: { label: "Erro do servidor ou do upstream", description: "O opencodex ou um provedor upstream falhou ao processar a requisição. Tente novamente mais tarde ou roteie a requisição 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"; return locale === "de" || locale === "ko" || locale === "zh" || locale === "zh-TW" || locale === "ru" || locale === "ja" || locale === "tr" ? locale : "en"; } diff --git a/gui/tests/anthropic-pool-conditions.test.tsx b/gui/tests/anthropic-pool-conditions.test.tsx index f5697226365..23f7e3c9814 100644 --- a/gui/tests/anthropic-pool-conditions.test.tsx +++ b/gui/tests/anthropic-pool-conditions.test.tsx @@ -230,7 +230,7 @@ describe("every locale carries the same pool claims", () => { ] as const; test("keys exist and the checkable tokens survive translation", () => { - expect(LOCALES.length).toBe(10); + expect(LOCALES.length).toBe(11); for (const { code } of LOCALES) { const dict = DICTS[code]; for (const key of KEYS) { diff --git a/gui/tests/i18n-locales.test.ts b/gui/tests/i18n-locales.test.ts index 991cf6c5790..3910ae9222d 100644 --- a/gui/tests/i18n-locales.test.ts +++ b/gui/tests/i18n-locales.test.ts @@ -27,6 +27,11 @@ describe("i18n locale contracts", () => { expect(DICTS.vi["lang.nativeName"]).toBe("Tiếng Việt"); }); + test("Brazilian Portuguese locale is registered", () => { + expect(LOCALES.find(locale => locale.code === "pt")?.htmlLang).toBe("pt-BR"); + expect(DICTS.pt["lang.nativeName"]).toBe("Português"); + }); + test("every locale has a catalog-backed display name", () => { for (const { code } of LOCALES) { const displayName = DICTS[code]["lang.nativeName"]; diff --git a/gui/tests/locale-parity.test.ts b/gui/tests/locale-parity.test.ts index 076d9c467c8..d1b64031f35 100644 --- a/gui/tests/locale-parity.test.ts +++ b/gui/tests/locale-parity.test.ts @@ -332,6 +332,11 @@ const DSH_VISIBLE_COPY: Record<(typeof LOCALE_CODES)[number], readonly [string, "DSH", "OpenCodex chỉ quản lý llm-pi-ai.providers.opencodex trong $DSH_HOME/settings.yaml. DSH sẽ hot reload provider này; model mặc định của bạn và deepseek-official không thay đổi. Hiện chỉ hỗ trợ loopback; không ghi credential thật nào.", ], + pt: [ + "DeepSeek Harness (DSH)", + "DSH", + "O OpenCodex gerencia apenas llm-pi-ai.providers.opencodex em $DSH_HOME/settings.yaml. O DSH recarrega esse provedor a quente; seu modelo padrão e o deepseek-official permanecem inalterados. Atualmente somente loopback; nenhuma credencial real é gravada.", + ], }; test("every locale carries the exact DSH label and ownership semantics", async () => { diff --git a/gui/tests/logs-cost-plain-dollar.test.ts b/gui/tests/logs-cost-plain-dollar.test.ts index 85624496e86..3b6cc3ac8ed 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: "pt-BR", }; function translator(locale: Locale): TFn { diff --git a/gui/tests/oauth-tos-warning-modal.test.tsx b/gui/tests/oauth-tos-warning-modal.test.tsx index 04bd53fcdd7..8b15934bc0a 100644 --- a/gui/tests/oauth-tos-warning-modal.test.tsx +++ b/gui/tests/oauth-tos-warning-modal.test.tsx @@ -146,7 +146,7 @@ test("every locale carries the Anthropic dialog copy with the same anchors", () "oauthTos.anthropicAcknowledge", "oauthTos.anthropicContinue", ] as const; - expect(LOCALES.length).toBe(10); + expect(LOCALES.length).toBe(11); for (const { code } of LOCALES) { const dict = DICTS[code]; for (const key of keys) { diff --git a/gui/tests/remote-link.test.tsx b/gui/tests/remote-link.test.tsx index 649a56f359c..8d962adb3aa 100644 --- a/gui/tests/remote-link.test.tsx +++ b/gui/tests/remote-link.test.tsx @@ -479,7 +479,7 @@ test("readLinkJson preserves unknown server codes and status", async () => { expect((caught as LinkApiError).code).toBe("future_code"); expect((caught as LinkApiError).status).toBe(418); expect((caught as LinkApiError).hint).toBeNull(); - expect(LOCALES).toHaveLength(10); + expect(LOCALES).toHaveLength(11); let hinted: unknown; try { await readLinkJson(new Response(JSON.stringify({ error: { code: "probe_failed", hint: `bad\u202e\u0007 line ${"x".repeat(300)}` } }), { status: 502 })); } catch (error) { hinted = error; } const hint = (hinted as LinkApiError).hint ?? ""; 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..e3263873a49 100644 --- a/scripts/file-size-ratchet.ts +++ b/scripts/file-size-ratchet.ts @@ -53,6 +53,7 @@ export const I18N_CATALOG_PATHS = [ "gui/src/i18n/fr.ts", "gui/src/i18n/ja.ts", "gui/src/i18n/ko.ts", + "gui/src/i18n/pt.ts", "gui/src/i18n/ru.ts", "gui/src/i18n/tr.ts", "gui/src/i18n/vi.ts", diff --git a/tests/adapters/anthropic/anthropic-pool-toggle-copy.test.ts b/tests/adapters/anthropic/anthropic-pool-toggle-copy.test.ts index 3bebc94a471..d6260b9fd95 100644 --- a/tests/adapters/anthropic/anthropic-pool-toggle-copy.test.ts +++ b/tests/adapters/anthropic/anthropic-pool-toggle-copy.test.ts @@ -20,6 +20,7 @@ const LOCALE_PATHS = [ "gui/src/i18n/fr.ts", "gui/src/i18n/ja.ts", "gui/src/i18n/ko.ts", + "gui/src/i18n/pt.ts", "gui/src/i18n/ru.ts", "gui/src/i18n/tr.ts", "gui/src/i18n/vi.ts", 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..1997a97adf3 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.ts", "gui/src/i18n/ru.ts", "gui/src/i18n/tr.ts", "gui/src/i18n/vi.ts",