diff --git a/ui/src/ui/i18n.ts b/ui/src/ui/i18n.ts index 000ab1a69..0c5c1a7b0 100644 --- a/ui/src/ui/i18n.ts +++ b/ui/src/ui/i18n.ts @@ -1,14 +1,16 @@ -export type Locale = "en" | "zh-CN"; +export type Locale = "en" | "zh-CN" | "pt-BR"; export type MessageParams = Record; export type Messages = Record; import { en } from "./locales/en"; import { zhCN } from "./locales/zh-CN"; +import { ptBR } from "./locales/pt-BR"; const BUNDLES: Record = { en, "zh-CN": zhCN, + "pt-BR": ptBR, }; let currentLocale: Locale = "en"; @@ -20,6 +22,7 @@ export function normalizeLocale(input: string | null | undefined): Locale | null if (!raw) return null; const lower = raw.toLowerCase(); if (lower === "zh" || lower === "zh-cn" || lower.startsWith("zh-")) return "zh-CN"; + if (lower === "pt" || lower === "pt-br" || lower.startsWith("pt-")) return "pt-BR"; if (lower === "en" || lower === "en-us" || lower.startsWith("en-")) return "en"; return null; } diff --git a/ui/src/ui/locales/en.ts b/ui/src/ui/locales/en.ts index 2927341d4..cdf88b208 100644 --- a/ui/src/ui/locales/en.ts +++ b/ui/src/ui/locales/en.ts @@ -155,6 +155,8 @@ export const en: Messages = { "settings.lang.en": "English", "settings.lang.zhShort": "中", "settings.lang.enShort": "EN", + "settings.lang.ptBR": "Português (Brasil)", + "settings.lang.ptShort": "PT", "overview.gatewayAccess.title": "Gateway Access", "overview.gatewayAccess.subtitle": "Where the dashboard connects and how it authenticates.", diff --git a/ui/src/ui/locales/pt-BR.ts b/ui/src/ui/locales/pt-BR.ts new file mode 100644 index 000000000..d44390a8b --- /dev/null +++ b/ui/src/ui/locales/pt-BR.ts @@ -0,0 +1,265 @@ +import type { Messages } from "../i18n"; + +export const ptBR: Messages = { + "common.na": "n/a", + "common.loading": "Carregando…", + "common.refresh": "Atualizar", + "common.save": "Salvar", + "common.apply": "Aplicar", + "common.cancel": "Cancelar", + "common.close": "Fechar", + "common.search": "Buscar", + "common.filter": "Filtrar", + "common.export": "Exportar", + "common.copy": "Copiar", + "common.openInNewTab": "Abrir em nova aba", + "common.enabled": "Habilitado", + "common.disabled": "Desabilitado", + "common.on": "Ligado", + "common.off": "Desligado", + "common.start": "Iniciar", + "common.stop": "Parar", + "common.add": "Adicionar", + "common.remove": "Remover", + "common.delete": "Excluir", + "common.edit": "Editar", + "common.view": "Visualizar", + "common.useDefault": "Usar padrão", + "common.useDefaultWith": "Usar padrão (${value})", + "common.ok": "OK", + "common.yes": "Sim", + "common.no": "Não", + "common.agent": "Agente", + "common.inherit": "herdar", + "common.file": "Arquivo", + "common.none": "nenhum", + "common.never": "nunca", + "common.unknown": "desconhecido", + "common.enable": "Habilitar", + "common.disable": "Desabilitar", + "common.run": "Executar", + "common.export.visible": "visível", + "common.export.filtered": "filtrado", + + "nav.chat": "Chat", + "nav.control": "Controle", + "nav.agent": "Agente", + "nav.settings": "Configurações", + "nav.resources": "Recursos", + "nav.docs": "Documentação", + + "tab.overview.title": "Visão Geral", + "tab.channels.title": "Canais", + "tab.instances.title": "Instâncias", + "tab.sessions.title": "Sessões", + "tab.cron.title": "Tarefas Cron", + "tab.skills.title": "Skills", + "tab.nodes.title": "Nós", + "tab.chat.title": "Chat", + "tab.config.title": "Configuração", + "tab.debug.title": "Depuração", + "tab.logs.title": "Logs", + "tab.control.title": "Controle", + + "tab.overview.subtitle": "Status do gateway e leitura rápida de saúde.", + "tab.channels.subtitle": "Gerenciar canais e configurações.", + "tab.instances.subtitle": "Beacons de presença de clientes e nós conectados.", + "tab.sessions.subtitle": "Inspecionar sessões ativas e ajustar padrões.", + "tab.cron.subtitle": "Agendar despertares e execuções recorrentes de agentes.", + "tab.skills.subtitle": "Gerenciar disponibilidade de skills e chaves de API.", + "tab.nodes.subtitle": "Dispositivos pareados, capacidades e exposição de comandos.", + "tab.chat.subtitle": "Sessão de chat direta com o gateway para intervenções rápidas.", + "tab.config.subtitle": "Editar ~/.clawdbot/clawdbot.json com segurança.", + "tab.debug.subtitle": "Snapshots do gateway, eventos e chamadas RPC manuais.", + "tab.logs.subtitle": "Acompanhamento em tempo real dos logs do gateway.", + + "topbar.expandSidebar": "Expandir barra lateral", + "topbar.collapseSidebar": "Recolher barra lateral", + "topbar.gatewayDashboard": "Painel do Gateway", + "topbar.health": "Saúde", + "topbar.healthOk": "OK", + "topbar.healthOffline": "Offline", + + "gateway.disconnected": "desconectado (${code}): ${reason}", + "gateway.noReason": "sem motivo", + "gateway.eventGap": "lacuna de eventos detectada (esperado seq ${expected}, recebido ${received}); atualização recomendada", + "gateway.reason.tokenMissing": "não autorizado: token do gateway faltando (abra uma URL de painel tokenizada ou cole o token nas configurações)", + "gateway.reason.tokenMismatch": "não autorizado: incompatibilidade de token do gateway (atualize o token nas configurações para corresponder ao gateway)", + "gateway.reason.tokenNotConfigured": "não autorizado: token do gateway não configurado no gateway (defina gateway.auth.token)", + "gateway.reason.passwordMissing": "não autorizado: senha do gateway faltando (cole a senha nas configurações ou use token)", + "gateway.reason.passwordMismatch": "não autorizado: senha incorreta (verifique a senha nas configurações)", + "gateway.reason.passwordNotConfigured": "não autorizado: senha do gateway não configurada no gateway (defina gateway.auth.password)", + "gateway.reason.tailscaleIdentityMissing": "não autorizado: identidade tailscale faltando (use autenticação Tailscale Serve ou token/senha)", + "gateway.reason.tailscaleProxyHeadersMissing": "não autorizado: cabeçalhos de proxy tailscale faltando (use Tailscale Serve ou token/senha)", + "gateway.reason.tailscaleIdentityCheckFailed": "não autorizado: verificação de identidade tailscale falhou (use autenticação Tailscale Serve ou token/senha)", + "gateway.reason.tailscaleIdentityMismatch": "não autorizado: incompatibilidade de identidade tailscale (use autenticação Tailscale Serve ou token/senha)", + "gateway.reason.unauthorized": "não autorizado", + + "format.ago.justNow": "agora mesmo", + "format.ago.seconds": "${seconds}s atrás", + "format.ago.minutes": "${minutes}m atrás", + "format.ago.hours": "${hours}h atrás", + "format.ago.days": "${days}d atrás", + "format.duration.seconds": "${seconds}s", + "format.duration.minutes": "${minutes}m", + "format.duration.hours": "${hours}h", + "format.duration.days": "${days}d", + + "chat.loading": "Carregando chat…", + "chat.disconnectedReason": "Desconectado do gateway.", + "chat.compacting": "Compactando contexto...", + "chat.compacted": "Contexto compactado", + "chat.attachmentPreview": "Prévia do anexo", + "chat.attachedImage": "Imagem anexada", + "chat.removeAttachment": "Remover anexo", + "chat.exitFocusMode": "Sair do modo foco", + "chat.queued": "Na fila (${count})", + "chat.removeQueuedMessage": "Remover mensagem da fila", + "chat.imageCount": "Imagem (${count})", + "chat.messageLabel": "Mensagem", + "chat.placeholder.connected": "Mensagem (↩ para enviar, Shift+↩ para quebra de linha, colar imagens)", + "chat.placeholder.connectedWithAttachments": "Adicione uma mensagem ou cole mais imagens...", + "chat.placeholder.disconnected": "Conecte-se ao gateway para iniciar o chat…", + "chat.stop": "Parar", + "chat.newSession": "Nova sessão", + "chat.queue": "Fila", + "chat.send": "Enviar", + "chat.showingLast": "Mostrando últimas ${limit} mensagens (${hidden} ocultas).", + "chat.tool.commandLabel": "Comando:", + "chat.tool.noOutput": "Sem saída — ferramenta concluída com sucesso.", + "chat.tool.completed": "Concluído", + "chat.role.you": "Você", + "chat.role.assistant": "Assistente", + "chat.role.user": "Usuário", + "chat.role.system": "Sistema", + "chat.role.tool": "Ferramenta", + + "sidebar.toolOutput": "Saída da Ferramenta", + "sidebar.viewRawText": "Ver Texto Puro", + "sidebar.noContent": "Nenhum conteúdo disponível", + + "execApproval.title": "Aprovação de execução necessária", + "execApproval.expiresIn": "expira em ${remaining}", + "execApproval.expired": "expirado", + "execApproval.pendingCount": "${count} pendentes", + "execApproval.meta.host": "Host", + "execApproval.meta.agent": "Agente", + "execApproval.meta.session": "Sessão", + "execApproval.meta.cwd": "CWD", + "execApproval.meta.resolved": "Resolvido", + "execApproval.meta.security": "Segurança", + "execApproval.meta.ask": "Perguntar", + "execApproval.allowOnce": "Permitir uma vez", + "execApproval.allowAlways": "Permitir sempre", + "execApproval.deny": "Negar", + + "settings.language": "Idioma", + "settings.lang.zhCN": "中文", + "settings.lang.en": "English", + "settings.lang.zhShort": "中", + "settings.lang.enShort": "EN", + "settings.lang.ptBR": "Português (Brasil)", + "settings.lang.ptShort": "PT", + + "overview.gatewayAccess.title": "Acesso ao Gateway", + "overview.gatewayAccess.subtitle": "Onde o painel se conecta e como se autentica.", + "overview.websocketUrl": "URL do WebSocket", + "overview.gatewayToken": "Token do Gateway", + "overview.passwordNotStored": "Senha (não armazenada)", + "overview.passwordPlaceholder": "senha do sistema ou compartilhada", + "overview.defaultSessionKey": "Chave de Sessão Padrão", + "overview.connect": "Conectar", + "overview.refresh": "Atualizar", + "overview.connectHint": "Clique em Conectar para aplicar as alterações.", + + "overview.snapshot.title": "Snapshot", + "overview.snapshot.subtitle": "Informações mais recentes do handshake do gateway.", + "overview.status": "Status", + "overview.connected": "Conectado", + "overview.disconnected": "Desconectado", + "overview.uptime": "Tempo de Atividade", + "overview.tickInterval": "Intervalo de Tick", + "overview.lastChannelsRefresh": "Última Atualização de Canais", + "overview.channelsHint": "Use Canais para vincular WhatsApp, Telegram, Discord, Signal ou iMessage.", + + "overview.instances": "Instâncias", + "overview.instancesHint": "Beacons de presença nos últimos 5 minutos.", + "overview.sessions": "Sessões", + "overview.sessionsHint": "Chaves de sessão recentes rastreadas pelo gateway.", + "overview.cron": "Cron", + "overview.enabled": "Habilitado", + "overview.disabled": "Desabilitado", + "overview.nextWake": "Próximo despertar ${when}", + + "overview.notes.title": "Notas", + "overview.notes.subtitle": "Lembretes rápidos para configurações de controle remoto.", + "overview.notes.tailscaleServe.title": "Tailscale Serve", + "overview.notes.tailscaleServe.body": "Prefira o modo serve para manter o gateway em loopback com autenticação tailnet.", + "overview.notes.sessionHygiene.title": "Higiene de sessão", + "overview.notes.sessionHygiene.body": "Use /new ou sessions.patch para redefinir o contexto.", + "overview.notes.cronReminders.title": "Lembretes do Cron", + "overview.notes.cronReminders.body": "Use sessões isoladas para execuções recorrentes.", + + "overview.auth.required": "Este gateway requer autenticação. Adicione um token ou senha e clique em Conectar.", + "overview.auth.tokenizedUrl": "URL tokenizada", + "overview.auth.setToken": "definir token", + "overview.auth.docsTitle": "Docs de auth da UI de Controle (abre nova aba)", + "overview.auth.docsLabel": "Docs: Auth UI de Controle", + "overview.auth.failed": "Falha na autenticação. Copie novamente uma URL tokenizada com ", + "overview.auth.failedAfterCommand": ", ou atualize o token, depois clique em Conectar.", + + "overview.insecureHttp": "Esta página é HTTP, então o navegador bloqueia a identidade do dispositivo. Use HTTPS (Tailscale Serve) ou abra ", + "overview.insecureHttpAfterUrl": " no host do gateway.", + "overview.insecureHttpOption": "Se você precisa ficar em HTTP, defina ", + "overview.insecureHttpOptionAfter": " (apenas token).", + "overview.docs.opensNewTab": "Documentação (abre nova aba)", + "overview.docs.tailscaleServe": "Docs: Tailscale Serve", + "overview.docs.insecureHttp": "Docs: Insecure HTTP", + + "chatControls.refreshHistory": "Atualizar histórico do chat", + "chatControls.disabledOnboarding": "Desabilitado durante onboarding", + "chatControls.toggleThinking": "Alternar saída de pensamento/trabalho do assistente", + "chatControls.toggleFocus": "Alternar modo foco (ocultar barra lateral + cabeçalho)", + + "theme.label": "Tema", + "theme.system": "Sistema", + "theme.light": "Claro", + "theme.dark": "Escuro", + + "logs.subtitle": "Logs de arquivo do gateway (JSONL).", + "logs.searchPlaceholder": "Buscar logs", + "logs.autoFollow": "Seguir automaticamente", + "logs.truncated": "Saída de log truncada; mostrando trecho mais recente.", + "logs.empty": "Nenhuma entrada de log.", + + "sessions.subtitle": "Chaves de sessão ativas e substituições por sessão.", + "sessions.filters.activeWithin": "Ativo em (minutos)", + "sessions.filters.limit": "Limite", + "sessions.filters.includeGlobal": "Incluir global", + "sessions.filters.includeUnknown": "Incluir desconhecido", + "sessions.store": "Armazenamento: ${path}", + "sessions.table.key": "Chave", + "sessions.table.label": "Rótulo", + "sessions.table.kind": "Tipo", + "sessions.table.updated": "Atualizado", + "sessions.table.tokens": "Tokens", + "sessions.table.thinking": "Pensando", + "sessions.table.verbose": "Verbo", + "sessions.table.reasoning": "Raciocínio", + "sessions.table.actions": "Ações", + "sessions.empty": "Nenhuma sessão encontrada.", + "sessions.optional": "(opcional)", + "sessions.deleteConfirm": "Apagar sessão \"${key}\"?\n\nApaga a entrada da sessão e arquiva sua transcrição.", + "sessions.verbose.offExplicit": "desligado (explícito)", + "sessions.verbose.on": "ligado", + "sessions.level.off": "desligado", + "sessions.level.minimal": "mínimo", + "sessions.level.low": "baixo", + "sessions.level.medium": "médio", + "sessions.level.high": "alto", + "sessions.level.on": "ligado", + "sessions.level.stream": "stream", + "sessions.kind.global": "global", + "sessions.kind.agent": "agente", + "sessions.kind.isolated": "isolado", +};