diff --git a/apps/desktop/src/i18n/catalog.ts b/apps/desktop/src/i18n/catalog.ts index f35c957076db..2a36e4a8ec4b 100644 --- a/apps/desktop/src/i18n/catalog.ts +++ b/apps/desktop/src/i18n/catalog.ts @@ -1,6 +1,7 @@ import { ar } from './ar' import { en } from './en' import { ja } from './ja' +import { pt } from './pt' import type { Locale, Translations } from './types' import { zh } from './zh' import { zhHant } from './zh-hant' @@ -10,5 +11,6 @@ export const TRANSLATIONS: Record = { zh, 'zh-hant': zhHant, ja, - ar + ar, + pt } diff --git a/apps/desktop/src/i18n/languages.ts b/apps/desktop/src/i18n/languages.ts index e4a1fb1e02eb..c41a248af09b 100644 --- a/apps/desktop/src/i18n/languages.ts +++ b/apps/desktop/src/i18n/languages.ts @@ -34,6 +34,12 @@ export const LOCALE_OPTIONS = [ name: 'العربية', englishName: 'Arabic', configValue: 'ar' + }, + { + id: 'pt', + name: 'Português', + englishName: 'Portuguese', + configValue: 'pt' } ] as const satisfies readonly { configValue: string; englishName: string; id: Locale; name: string }[] @@ -79,7 +85,14 @@ const LOCALE_ALIASES: Record = { 'ar-eg': 'ar', ar_eg: 'ar', arabic: 'ar', - العربية: 'ar' + العربية: 'ar', + pt: 'pt', + 'pt-br': 'pt', + pt_br: 'pt', + 'pt-pt': 'pt', + pt_pt: 'pt', + portuguese: 'pt', + 'português': 'pt' } export function isLocale(value: unknown): value is Locale { diff --git a/apps/desktop/src/i18n/pt.ts b/apps/desktop/src/i18n/pt.ts new file mode 100644 index 000000000000..21af5fa9e149 --- /dev/null +++ b/apps/desktop/src/i18n/pt.ts @@ -0,0 +1,2967 @@ +import { FIELD_DESCRIPTIONS, FIELD_LABELS } from '@/app/settings/constants' + +import { defineLocale } from './define-locale' + +// Tradução pt-BR completa (gerada por Stacy em 2026-08-01). +// Fallback automático para inglês via defineLocale (padrão do projeto). +export const pt = defineLocale({ +common: { + apply: 'Aplicar', + back: 'Voltar', + save: 'Salvar', + saving: 'Salvando…', + cancel: 'Cancelar', + change: 'Alterar', + choose: 'Escolher', + clear: 'Limpar', + close: 'Fechar', + collapse: 'Recolher', + confirm: 'Confirmar', + connect: 'Conectar', + connecting: 'Conectando', + continue: 'Continuar', + copied: 'Copiado', + copy: 'Copiar', + copyFailed: 'Falha ao copiar', + delete: 'Excluir', + docs: 'Docs', + done: 'Concluído', + error: 'Erro', + expand: 'Expandir', + failed: 'Falhou', + formatJson: 'Formatar JSON', + free: 'Grátis', + loading: 'Carregando…', + notSet: 'Não definido', + refresh: 'Atualizar', + remove: 'Remover', + replace: 'Substituir', + retry: 'Tentar novamente', + run: 'Executar', + send: 'Enviar', + set: 'Definir', + skip: 'Pular', + update: 'Atualizar', + tryHint: term => `Tente “${term}”`, + on: 'Ligado', + off: 'Desligado' + }, + + remoteDisplayBanner: { + message: reason => + `Renderização por software ativa — exibição remota detectada (${reason}). A aceleração de GPU está desativada para evitar oscilações.` + }, + + billingBlock: { + titleNous: 'Créditos Nous esgotados', + titleProvider: provider => `Créditos esgotados — ${provider}`, + fallbackMessage: 'Sua conta está sem créditos. Adicione créditos para continuar.', + openBilling: 'Abrir cobrança', + addCredits: 'Adicionar créditos', + dismiss: 'Dispensar' + }, + + keybinds: { + title: 'Atalhos de teclado', + subtitle: open => `Clique em um atalho para reatribuí-lo · ${open} reabre este painel.`, + search: 'Pesquisar atalhos…', + rebind: 'Reatribuir', + reset: 'Restaurar padrão', + resetAll: 'Restaurar tudo', + pressKey: 'Pressione uma tecla…', + set: 'definir', + conflictWith: label => `Também atribuído a “${label}”`, + categories: { + composer: 'Compositor', + profiles: 'Perfis', + session: 'Sessão', + navigation: 'Navegação', + view: 'Exibição' + }, + actions: { + 'keybinds.openPanel': 'Abrir atalhos de teclado', + 'nav.commandPalette': 'Abrir paleta de comandos', + 'nav.commandCenter': 'Abrir central de comandos', + 'nav.settings': 'Abrir configurações', + 'nav.profiles': 'Abrir perfis', + 'nav.skills': 'Abrir habilidades', + 'nav.messaging': 'Abrir mensagens', + 'nav.artifacts': 'Abrir artefatos', + 'nav.cron': 'Abrir tarefas agendadas', + 'nav.agents': 'Abrir agentes', + 'session.new': 'Nova sessão', + 'session.newTab': 'Nova aba de sessão', + 'session.newWindow': 'Nova janela', + 'session.next': 'Próxima sessão', + 'session.prev': 'Sessão anterior', + 'session.slot.1': 'Ir para a sessão recente 1', + 'session.slot.2': 'Ir para a sessão recente 2', + 'session.slot.3': 'Ir para a sessão recente 3', + 'session.slot.4': 'Ir para a sessão recente 4', + 'session.slot.5': 'Ir para a sessão recente 5', + 'session.slot.6': 'Ir para a sessão recente 6', + 'session.slot.7': 'Ir para a sessão recente 7', + 'session.slot.8': 'Ir para a sessão recente 8', + 'session.slot.9': 'Ir para a sessão recente 9', + 'session.focusSearch': 'Pesquisar sessões', + 'session.togglePin': 'Fixar / desafixar sessão atual', + 'workspace.newWorktree': 'Novo worktree', + 'workspace.openFolder': 'Abrir pasta como projeto', + 'composer.focus': 'Focar compositor', + 'composer.modelPicker': 'Abrir seletor de modelo', + 'composer.voice': 'Iniciar / parar conversa por voz', + 'view.toggleSidebar': 'Alternar barra lateral de sessões', + 'view.toggleRightSidebar': 'Alternar navegador de arquivos', + 'view.toggleReview': 'Alternar painel de revisão', + 'view.toggleStatusbar': 'Alternar barra de status', + 'view.showFiles': 'Mostrar navegador de arquivos', + 'view.showTerminal': 'Alternar terminal', + 'view.newTerminal': 'Novo terminal', + 'view.nextTerminal': 'Próximo terminal', + 'view.prevTerminal': 'Terminal anterior', + 'view.closeTerminal': 'Fechar terminal', + 'view.terminalSelection': 'Enviar seleção do terminal ao compositor', + 'view.terminalCopy': 'Copiar seleção do terminal', + 'view.terminalPaste': 'Colar no terminal', + 'view.closeTab': 'Fechar aba', + 'view.reopenTab': 'Reabrir aba fechada', + 'view.flipPanes': 'Trocar lados da barra lateral', + 'view.findInPage': 'Localizar na página', + 'view.findNext': 'Próxima correspondência', + 'view.findPrevious': 'Correspondência anterior', + 'appearance.toggleMode': 'Alternar claro / escuro', + 'profile.default': 'Alternar para o perfil padrão', + 'profile.switch.1': 'Alternar para o perfil 1', + 'profile.switch.2': 'Alternar para o perfil 2', + 'profile.switch.3': 'Alternar para o perfil 3', + 'profile.switch.4': 'Alternar para o perfil 4', + 'profile.switch.5': 'Alternar para o perfil 5', + 'profile.switch.6': 'Alternar para o perfil 6', + 'profile.switch.7': 'Alternar para o perfil 7', + 'profile.switch.8': 'Alternar para o perfil 8', + 'profile.switch.9': 'Alternar para o perfil 9', + 'profile.switch.10': 'Alternar para o perfil 10', + 'profile.switch.11': 'Alternar para o perfil 11', + 'profile.switch.12': 'Alternar para o perfil 12', + 'profile.switch.13': 'Alternar para o perfil 13', + 'profile.switch.14': 'Alternar para o perfil 14', + 'profile.switch.15': 'Alternar para o perfil 15', + 'profile.switch.16': 'Alternar para o perfil 16', + 'profile.switch.17': 'Alternar para o perfil 17', + 'profile.switch.18': 'Alternar para o perfil 18', + 'profile.next': 'Próximo perfil', + 'profile.prev': 'Perfil anterior', + 'profile.toggleAll': 'Alternar exibição de todos os perfis', + 'profile.create': 'Criar perfil', + 'composer.send': 'Enviar mensagem', + 'composer.newline': 'Inserir nova linha', + 'composer.steer': 'Direcionar o turno em execução', + 'composer.queue': 'Enfileirar mensagem', + 'composer.sendQueued': 'Enviar próximo turno enfileirado', + 'composer.mention': 'Referenciar arquivos, pastas, URLs', + 'composer.slash': 'Paleta de comandos de barra', + 'composer.help': 'Ajuda rápida', + 'composer.history': 'Alternar popover / histórico', + 'composer.cancel': 'Fechar popover · cancelar execução' + } + }, + + starmap: { + title: 'Grafo de Memória', + subtitle: (nodes, clusters) => `${nodes} habilidades em ${clusters} categorias`, + close: 'Fechar grafo de memória', + refresh: 'Atualizar', + memory: 'Memória', + filterAll: 'Todas', + filterUsed: 'Usadas', + filterLearned: 'Aprendidas', + viewGraph: 'Grafo', + loadFailed: 'Não foi possível carregar o grafo de memória', + loading: 'Carregando…', + emptyTitle: 'Nada aprendido ainda', + emptyDesc: 'Conforme o Hermes cria habilidades e memórias para o seu trabalho, elas aparecem aqui.', + share: 'Compartilhar mapa', + shareHint: + 'Copie o código para compartilhar este mapa ou cole um para carregar. Ele inclui apenas o layout, não a sua memória ou texto de habilidades.', + shareTitle: 'Importar / exportar mapa', + sharePlaceholder: 'Cole um código de mapa…', + copy: 'Copiar código do mapa', + copied: 'Copiado!', + importMap: 'Importar um mapa', + importBtn: 'Carregar', + importEmpty: 'Cole um código de mapa para carregá-lo.', + importSuccess: nodes => `Mapa carregado com ${nodes} ${nodes === 1 ? 'nó' : 'nós'}.`, + importedBadge: 'mapa importado', + resetToMine: 'Voltar ao meu mapa' + }, + commandCenter: { + close: 'Fechar central de comandos', + paletteTitle: 'Paleta de comandos', + back: 'Voltar', + searchPlaceholder: 'Pesquisar sessões, exibições e ações', + goTo: 'Ir para', + goToSession: 'Ir para a sessão', + branches: 'Ramos', + projects: 'Projetos', + openFolder: 'Abrir pasta como projeto…', + openFolderAt: path => `Abrir pasta como projeto — ${path}`, + newSessionInProject: project => `Nova sessão em ${project}`, + commands: 'Comandos', + startInBranch: branch => `Nova conversa em ${branch}`, + commandCenter: 'Central de Comandos', + appearance: 'Aparência', + settings: 'Configurações', + changeTheme: 'Alterar tema', + changeColorMode: 'Alterar modo de cor…', + pets: { + title: 'Mascotes', + placeholder: 'Pesquisar mascotes…', + loading: 'Carregando a galeria petdex…', + error: 'Não foi possível acessar a galeria petdex.', + staleBackend: 'Reinicie o Hermes para usar mascotes — o backend é anterior a este recurso.', + empty: 'Nenhuma mascote correspondente.', + turnOff: 'Desligar', + turnOn: 'Ligar', + installed: 'Instaladas', + generatedTag: 'Gerada', + adoptFailed: 'Não foi possível adotar essa mascote.', + toggleFailed: enabled => `Não foi possível ${enabled ? 'ligar' : 'desligar'} a mascote.`, + noneAvailable: 'Nenhuma mascote disponível — escolha uma abaixo para instalar.' + }, + generatePet: { + title: 'Gerar uma mascote', + placeholder: 'Descreva uma mascote para gerar…', + promptHint: 'Digite uma descrição e pressione Enter para esboçar quatro looks.', + readyHint: 'Pressione Enter para esboçar quatro looks a partir da sua descrição.', + generate: 'Gerar', + generating: 'Gerando…', + retry: 'Tentar novamente', + hatch: 'Eclodir', + spawning: 'Gerando…', + hatching: 'Eclodindo sua mascote…', + hatchingSub: 'Dando vida a ela…', + hatched: 'Ela eclodiu!', + hatchRow: (_state, done, total) => `Esboçando quadro ${done} de ${total}…`, + hatchComposing: 'Montando…', + hatchSaving: 'Quase lá…', + namePlaceholder: 'Dê um nome à sua mascote', + staleBackend: 'Atualize o Hermes para gerar mascotes.', + backgroundHint: 'Você pode fechar — o Hermes avisa quando terminar.', + slowProviderHint: 'Isso pode levar vários minutos', + remix: 'Remixar', + remixConfirmTitle: 'Remixar este look?', + remixConfirmBody: + 'Isso gera um novo conjunto de esboços usando este como ponto de partida. Pode levar vários minutos.', + genericError: 'Falha na geração — tente novamente ou escolha uma sugestão.', + referenceImageTooLarge: 'A imagem de referência é muito grande. Use uma abaixo de 16 MB.', + referenceImageInvalid: 'Não foi possível ler essa imagem de referência. Tente PNG, JPG, WebP ou GIF.', + adopt: 'Adotar', + startOver: 'Recomeçar' + }, + installTheme: { + title: 'Instalar tema…', + pageTitle: 'Instalar tema', + placeholder: 'Pesquisar no VS Code Marketplace...', + loading: 'Pesquisando no Marketplace...', + error: 'Não foi possível acessar o Marketplace.', + empty: 'Nenhum tema correspondente.', + install: 'Instalar', + installing: 'Instalando...', + installed: 'Instalado', + installs: count => `${count} instalações` + }, + settingsFields: 'Campos de configuração', + mcpServers: 'Servidores MCP', + archivedChats: 'Conversas arquivadas', + sections: { maintenance: 'Manutenção', sessions: 'Sessões', system: 'Sistema', usage: 'Uso' }, + sectionDescriptions: { + maintenance: 'Diagnóstico, backups, curador e dados de memória', + sessions: 'Pesquisar e gerenciar sessões', + system: 'Status, logs e ações do sistema', + usage: 'Atividade de tokens, custos e habilidades ao longo do tempo' + }, + nav: { + newChat: { title: 'Nova sessão', detail: 'Iniciar uma sessão nova' }, + settings: { title: 'Configurações', detail: 'Configurar o Hermes desktop' }, + skills: { title: 'Capacidades', detail: 'Habilidades, ferramentas e servidores MCP' }, + messaging: { title: 'Mensagens', detail: 'Configurar Telegram, Slack, Discord e mais' }, + artifacts: { title: 'Artefatos', detail: 'Navegar pelos resultados gerados' } + }, + sectionEntries: { + sessions: { title: 'Painel de sessões', detail: 'Pesquisar, fixar e gerenciar sessões' }, + system: { title: 'Painel do sistema', detail: 'Status do gateway, logs, reiniciar/atualizar' }, + usage: { title: 'Painel de uso', detail: 'Atividade de tokens, custos e habilidades' } + }, + providerNavigate: 'Navegar', + providerSessions: 'Sessões', + refresh: 'Atualizar', + refreshing: 'Atualizando...', + noResults: 'Nenhum resultado correspondente encontrado.', + pinSession: 'Fixar sessão', + unpinSession: 'Desafixar sessão', + exportSession: 'Exportar sessão', + deleteSession: 'Excluir sessão', + noSessions: 'Nenhuma sessão ainda.', + gatewayRunning: 'Gateway de mensagens em execução', + gatewayStopped: 'Gateway de mensagens parado', + hermesActiveSessions: (version, count) => `Hermes ${version} · Sessões ativas ${count}`, + restartGateway: 'Reiniciar gateway', + gatewayRestartFailed: 'Falha ao reiniciar o gateway.', + updateHermes: 'Atualizar Hermes', + actionRunning: 'executando', + actionDone: 'concluído', + actionFailed: 'falhou', + actionStartedWaiting: 'Ação iniciada, aguardando status...', + loadingStatus: 'Carregando status...', + recentLogs: 'Logs recentes', + noLogs: 'Nenhum log carregado ainda.', + days: count => `${count}d`, + statSessions: 'Sessões', + statApiCalls: 'Chamadas de API', + statTokens: 'Tokens in/out', + statCost: 'Custo estimado', + actualCost: cost => `real ${cost}`, + loadingUsage: 'Carregando uso...', + noUsage: period => `Nenhum uso nos últimos ${period} dias.`, + retry: 'Tentar novamente', + dailyTokens: 'Tokens diários', + input: 'entrada', + output: 'saída', + noDailyActivity: 'Nenhuma atividade diária.', + topModels: 'Principais modelos', + noModelUsage: 'Nenhum uso de modelo ainda.', + topSkills: 'Principais habilidades', + noSkillActivity: 'Nenhuma atividade de habilidades ainda.', + actions: count => `${count} ações`, + logFile: 'Arquivo de log', + logLevel: 'Nível', + logSearchPlaceholder: 'Filtrar linhas de log...', + maintenance: { + runOps: 'Diagnóstico', + doctor: 'Executar doctor', + doctorDesc: 'Verifica a saúde da instalação, config e provedores', + securityAudit: 'Auditoria de segurança', + securityAuditDesc: 'Verifica config e habilidades em busca de configurações arriscadas', + backup: 'Criar backup', + backupDesc: 'Compacta config, memórias, habilidades e sessões', + debugShare: 'Compartilhar diagnóstico', + debugShareDesc: 'Envia um relatório e logs anonimizados, gera links compartilháveis (auto-exclui em 6h)', + debugShareRunning: 'Enviando relatório de diagnóstico...', + debugShareLinks: 'Links de compartilhamento', + debugShareFailed: 'Falha ao compartilhar diagnóstico', + copyLink: 'Copiar link', + linkCopied: 'Link copiado', + curator: 'Curador de habilidades', + curatorDesc: 'Revisão em segundo plano que arquiva habilidades antigas criadas por agentes', + curatorPaused: 'Pausado', + curatorActive: 'Ativo', + curatorDisabled: 'Desativado', + curatorLastRun: when => `Última execução ${when}`, + curatorNeverRan: 'Nunca executou', + pause: 'Pausar', + resume: 'Retomar', + runNow: 'Executar agora', + memoryData: 'Dados de memória', + memoryDataDesc: 'Arquivos de memória integrados injetados em toda sessão', + memoryProvider: name => `Provedor ativo: ${name}`, + builtinMemory: 'integrado', + memoryFile: 'Memória do agente (MEMORY.md)', + userFile: 'Perfil do usuário (USER.md)', + bytes: size => size, + empty: 'vazio', + resetMemory: 'Redefinir memória', + resetUser: 'Redefinir perfil', + resetAll: 'Redefinir ambos', + resetConfirm: target => `Excluir ${target}? Isso não pode ser desfeito.`, + resetDone: files => `${files} excluídos.`, + resetFailed: 'Falha ao redefinir a memória', + actionStarted: name => `${name} iniciado — acompanhando o log...`, + actionFailed: name => `${name} falhou ao iniciar`, + running: 'Executando...', + viewLog: 'Log da ação' + } + }, + + profiles: { + close: 'Fechar perfis', + nameHint: 'Letras minúsculas, números, hífens e sublinhados. Deve começar com letra ou número.', + title: 'Perfis', + count: count => `${count} ${count === 1 ? 'perfil' : 'perfis'}`, + search: 'Pesquisar perfis...', + loading: 'Carregando perfis...', + newProfile: 'Novo perfil', + allProfiles: 'Todos os perfis', + showAllProfiles: 'Mostrar todos os perfis', + switchToProfile: name => `Alternar para ${name}`, + manageProfiles: 'Gerenciar perfis…', + actions: 'Ações', + color: 'Cor…', + colorFor: 'Cor', + setColor: color => `Definir cor ${color}`, + autoColor: 'Automática', + noProfiles: 'Nenhum perfil ainda.', + selectPrompt: 'Selecione um perfil para ver os detalhes.', + refresh: 'Atualizar perfis', + refreshing: 'Atualizando perfis', + default: 'padrão', + skills: count => `${count} ${count === 1 ? 'habilidade' : 'habilidades'}`, + env: 'env', + defaultBadge: 'Padrão', + rename: 'Renomear', + renameMenu: 'Renomear…', + editSoul: 'Editar SOUL.md…', + copySetup: 'Copiar configuração', + copying: 'Copiando...', + modelLabel: 'Modelo', + skillsLabel: 'Habilidades', + notSet: 'Não definido', + soulDesc: 'O prompt de sistema e a persona embutidos neste perfil.', + soulOptional: 'opcional', + soulPlaceholder: mode => `O prompt de sistema / persona deste perfil.\nDeixe em branco para manter o padrão ${mode}.`, + soulPlaceholderCloned: 'clonado', + soulPlaceholderEmpty: 'vazio', + unsavedChanges: 'Alterações não salvas', + loadingSoul: 'Carregando SOUL.md...', + emptySoul: 'SOUL.md vazio — comece a escrever a persona...', + saving: 'Salvando...', + saveSoul: 'Salvar SOUL.md', + deleteTitle: 'Excluir perfil?', + deleteDescPrefix: 'Isso excluirá ', + deleteDescMid: ' e removerá o diretório ', + deleteDescSuffix: '. Isso não pode ser desfeito.', + deleting: 'Excluindo...', + createDesc: 'Perfis são ambientes Hermes independentes: config, habilidades e SOUL.md separados.', + nameLabel: 'Nome', + cloneFrom: 'Clonar de', + cloneFromNone: 'Nenhum (em branco)', + cloneFromDesc: 'Copia config, habilidades e SOUL.md do perfil de origem selecionado.', + cloneFromDefault: 'Clonar do padrão', + cloneFromDefaultDesc: 'Copia config, habilidades e SOUL.md do seu perfil padrão.', + invalidName: hint => `Nome inválido. ${hint}`, + nameRequired: 'O nome é obrigatório.', + creating: 'Criando...', + createAction: 'Criar perfil', + renameTitle: 'Renomear perfil', + renameDescPrefix: 'Renomear atualiza o diretório do perfil e quaisquer scripts de wrapper em ', + renameDescSuffix: '.', + newNameLabel: 'Novo nome', + renaming: 'Renomeando...', + created: 'Perfil criado', + renamed: 'Perfil renomeado', + deleted: 'Perfil excluído', + setupCopied: 'Comando de configuração copiado', + soulSaved: 'SOUL.md salvo', + failedLoad: 'Falha ao carregar perfis', + failedDelete: 'Falha ao excluir perfil', + failedCopy: 'Falha ao copiar comando de configuração', + failedLoadSoul: 'Falha ao carregar SOUL.md', + failedSaveSoul: 'Falha ao salvar SOUL.md', + failedCreate: 'Falha ao criar perfil', + failedRename: 'Falha ao renomear perfil' + }, + + artifacts: { + search: 'Pesquisar artefatos...', + refresh: 'Atualizar artefatos', + refreshing: 'Atualizando artefatos', + indexing: 'Indexando artefatos de sessões recentes', + tabAll: 'Todos', + tabImages: 'Imagens', + tabFiles: 'Arquivos', + tabLinks: 'Links', + noArtifactsTitle: 'Nenhum artefato encontrado', + noArtifactsDesc: 'Imagens geradas e saídas de arquivos aparecerão aqui conforme as sessões as produzem.', + failedLoad: 'Falha ao carregar artefatos', + openFailed: 'Falha ao abrir', + itemsImage: 'imagens', + itemsLink: 'links', + itemsFile: 'arquivos', + itemsGeneric: 'itens', + zero: '0', + rangeOf: (start, end, total) => `${start}-${end} de ${total}`, + goToPage: (itemLabel, page) => `Ir para a página ${page} de ${itemLabel}`, + colTitleLink: 'Título do link', + colTitleFile: 'Nome', + colTitleDefault: 'Título / nome', + colLocationLink: 'URL', + colLocationFile: 'Caminho', + colLocationDefault: 'Local', + colSession: 'Sessão', + kindImage: 'imagem', + kindFile: 'arquivo', + kindLink: 'link', + chat: 'Chat', + copyUrl: 'Copiar URL', + copyPath: 'Copiar caminho' + }, + + artifactCard: { + kind: { code: 'Código', html: 'Página interativa', svg: 'Gráfico' }, + generating: lines => `Gerando… ${lines} linhas`, + versionBadge: count => `${count} versões`, + open: 'Abrir' + }, + + artifactPreview: { + versionOf: (current, total) => `v${current} de ${total}`, + olderVersion: 'Versão mais antiga', + newerVersion: 'Versão mais recente', + latest: 'Mais recente', + copyContent: 'Copiar conteúdo', + download: 'Baixar', + openInBrowser: 'Abrir no navegador', + openInBrowserFailed: 'Não foi possível abrir no navegador', + missingTitle: 'Artefato indisponível', + missingBody: 'Este artefato não está mais no registro local.' + }, + + sidebar: { + nav: { + 'new-session': 'Nova sessão', + skills: 'Capacidades', + messaging: 'Mensagens', + artifacts: 'Artefatos' + }, + searchAria: 'Pesquisar sessões', + searchPlaceholder: 'Pesquisar sessões…', + clearSearch: 'Limpar pesquisa', + noMatch: query => `Nenhuma sessão corresponde a “${query}”.`, + results: 'Resultados', + pinned: 'Fixadas', + sessions: 'Sessões', + cronJobs: 'Tarefas agendadas', + groupAriaGrouped: 'Mostrar sessões como uma lista única', + groupAriaUngrouped: 'Agrupar sessões por workspace', + showProjects: 'Mostrar projetos', + showSessions: 'Mostrar sessões', + groupTitleGrouped: 'Desagrupar sessões', + groupTitleUngrouped: 'Agrupar por workspace', + allPinned: 'Tudo aqui está fixado. Desafixe uma conversa para mostrá-la em recentes.', + shiftClickHint: 'Shift-clique em uma conversa para fixar', + noWorkspace: 'Sem workspace', + projectEmpty: 'Nenhuma sessão ainda', + noSessions: 'Nenhuma sessão ainda', + projects: { + sectionLabel: 'Projetos', + home: 'Início', + newButton: 'Novo projeto', + createTitle: 'Novo projeto', + createDesc: 'Dê um nome a um workspace e adicione uma ou mais pastas.', + renameTitle: 'Renomear projeto', + addFolderTitle: 'Adicionar pasta', + namePlaceholder: 'ex.: Skunkworks', + foldersLabel: 'Pastas', + ideaLabel: 'Ideia', + ideaPlaceholder: 'Sobre o que é este projeto? (salvo em IDEA.md)', + ideaGenerate: 'Gerar ideia', + ideaGenerating: 'Gerando…', + ideaShuffle: 'Embaralhar modelos', + noFolders: 'Nenhuma pasta adicionada ainda.', + addFolder: 'Adicionar pasta', + primaryBadge: 'principal', + removeFolder: 'Remover', + create: 'Criar', + menu: 'Ações', + menuRename: 'Renomear', + menuAppearance: 'Aparência', + noColor: 'Sem cor', + menuAddFolder: 'Adicionar pasta', + menuSetActive: 'Definir ativo', + menuDelete: 'Excluir', + reveal: 'Revelar na pasta', + copyPath: 'Copiar caminho', + removeFromSidebar: 'Ocultar da barra lateral', + createFailed: 'Não foi possível criar o projeto', + staleBackend: + 'Atualize o backend do Hermes para criar projetos — seu backend é mais antigo que este app desktop (Configurações → Atualizações → Backend).', + deleteConfirm: 'Isso remove o projeto salvo do Hermes. Arquivos, repositórios git e worktrees permanecem intactos.', + startWork: 'Novo worktree', + newWorktreeTitle: 'Novo worktree', + newWorktreeDesc: 'Dê um nome ao ramo deste worktree.', + branchPlaceholder: 'ex.: minha-funcionalidade', + branchOff: () => ({ after: '', before: 'ramo a partir de ' }), + baseBranchPlaceholder: 'Pesquisar ramos…', + baseBranchNone: 'Nenhum ramo encontrado', + startWorkFailed: 'Não foi possível criar o worktree', + convertBranch: 'Converter um ramo…', + convertBranchTitle: 'Converter um ramo', + convertBranchDesc: 'Abrir ramos com checkout, ou criar um worktree para um ramo livre.', + convertBranchPlaceholder: 'Pesquisar ramos…', + convertBranchInstead: 'Converter um ramo existente', + branchOpenExisting: 'abrir', + branchSwitchHome: 'trocar para o home', + branchCreateWorktree: 'novo worktree', + branchesLoading: 'Carregando ramos…', + noBranches: 'Nenhum ramo encontrado', + removeWorktree: 'Remover worktree', + removeWorktreeFailed: 'Não foi possível remover o worktree (alterações não commitadas?)', + removeWorktreeConfirm: + 'Removê-lo do git (exclui o diretório do worktree; o ramo permanece), ou apenas ocultar a faixa da barra lateral e deixar o worktree no disco.', + removeWorktreeDirty: + 'Este worktree tem alterações não commitadas. Forçar a remoção (descarta essas alterações), ou apenas ocultar a faixa e mantê-lo no disco.', + forceRemove: 'Forçar remoção', + enter: label => `Abrir ${label}`, + reorder: label => `Reordenar ${label}`, + toggle: (label, open) => `${open ? 'Mostrar' : 'Ocultar'} sessões de ${label}`, + back: 'Todos os projetos' + }, + newSessionIn: label => `Nova sessão em ${label}`, + showMoreIn: (count, label) => `Mostrar mais ${count} em ${label}`, + loading: 'Carregando…', + loadMore: 'Carregar mais', + loadCount: step => `Carregar mais ${step}`, + row: { + pin: 'Fixar', + unpin: 'Desafixar', + copyId: 'Copiar ID', + export: 'Exportar', + branchFrom: 'Ramo', + rename: 'Renomear', + archive: 'Arquivar', + newWindow: 'Nova janela', + hideTabBar: 'Ocultar barra de abas', + openInNewTab: 'Abrir em nova aba', + openInSplit: 'Abrir em divisão', + copyIdFailed: 'Não foi possível copiar o ID da sessão', + sessionActions: 'Ações da sessão', + sessionRunning: 'Sessão em execução', + needsInput: 'Precisa da sua resposta', + waitingForAnswer: 'Aguardando sua resposta', + finishedUnread: 'Concluída — não lida', + backgroundRunning: 'Tarefa em segundo plano em execução', + handoffOrigin: platform => `Repassada de ${platform}`, + ownedByProfile: profile => `Perfil: ${profile}`, + renamed: 'Renomeada', + renameFailed: 'Falha ao renomear', + renameTitle: 'Renomear sessão', + renameDesc: 'Deixe vazio para limpar.', + untitledPlaceholder: 'Sessão sem título', + untitledChat: id => `Chat ${id}`, + ageNow: 'agora', + ageDay: 'd', + ageHour: 'h', + ageMin: 'm' + }, + dateDivider: { + today: 'Hoje mais cedo', + yesterday: 'Ontem', + thisWeek: 'Esta semana mais cedo', + lastWeek: 'Semana passada', + thisMonth: 'Este mês mais cedo' + } + }, + + statusStack: { + agents: 'Agentes', + background: count => `${count} em segundo plano`, + goalActive: 'Objetivo ativo', + goalDone: 'Objetivo concluído', + goalPaused: 'Objetivo pausado', + goalWaiting: 'Objetivo aguardando', + subagents: count => `${count} Subagente${count === 1 ? '' : 's'}`, + todos: (done, total) => `Tarefas ${done}/${total}`, + running: 'Executando', + stop: 'Parar', + dismiss: 'Dispensar', + exit: code => `sair ${code}`, + coding: { + title: 'Árvore de trabalho', + noBranch: 'Sem ramo', + detached: 'desanexado', + clean: 'Limpo', + changed: count => `${count} alterado${count === 1 ? '' : 's'}`, + ahead: count => `${count} à frente`, + behind: count => `${count} atrás`, + review: 'Revisar', + close: 'Fechar', + openChanges: 'Abrir Alterações', + openFile: 'Abrir Arquivo', + stage: 'Adicionar', + unstage: 'Remover da área', + stageAll: 'Adicionar tudo', + viewAsTree: 'Ver como árvore', + viewAsList: 'Ver como lista', + revert: 'Reverter', + revertAll: 'Reverter tudo', + revertConfirm: 'Descartar as alterações deste arquivo e restaurá-lo ao estado commitado? Isso não pode ser desfeito.', + revertAllConfirm: 'Descartar todas as alterações e restaurar os arquivos ao estado commitado? Isso não pode ser desfeito.', + staged: 'Adicionados', + noChanges: 'Sem alterações', + notRepo: 'Não é um repositório git', + noDiff: 'Nenhuma diferença para mostrar', + scopeUncommitted: 'Não commitado', + scopeBranch: 'Ramo', + scopeLastTurn: 'Último turno', + commit: 'Commitar', + commitAndPush: 'Commitar e Enviar', + commitPlaceholder: 'Mensagem (⌘↵ para commitar)', + generateCommitMessage: 'Gerar mensagem de commit', + stopGenerating: 'Parar geração', + createPr: 'Criar PR', + openPr: 'Abrir PR', + ghMissing: 'Instale a CLI do GitHub (gh) e faça login para abrir PRs', + agentShip: 'Pedir ao Hermes para abrir PR', + agentShipPrompt: + 'Revise as alterações atuais, faça o commit com uma mensagem convencional clara, envie o ramo e abra um pull request.', + newBranch: 'Novo ramo', + branchOffFrom: base => `Novo ramo a partir de ${base}`, + switchTo: branch => `Alternar para ${branch}`, + switchFailed: branch => `Não foi possível alternar para ${branch}`, + worktrees: 'Worktrees' + } + }, + + updates: { + stages: { + idle: 'Preparando…', + prepare: 'Preparando…', + fetch: 'Baixando…', + pull: 'Quase lá…', + pydeps: 'Finalizando…', + update: 'Atualizando o Hermes…', + rebuild: 'Reconstruindo o app desktop…', + restart: 'Reiniciando o Hermes…', + done: 'Atualização concluída', + manual: 'Atualizar pelo terminal', + guiSkew: 'Atualizar o app desktop', + error: 'Atualização pausada' + }, + checking: 'Procurando atualizações…', + checkFailedTitle: 'Não foi possível verificar atualizações', + tryAgain: 'Tentar novamente', + notAvailableTitle: 'Nenhuma atualização disponível', + unsupportedMessage: 'Esta versão do Hermes não consegue se atualizar de dentro do app.', + connectionRetry: 'Verifique sua conexão e tente novamente.', + latestBody: 'Você está executando a versão mais recente.', + latestBodyBackend: 'O backend está executando a versão mais recente.', + allSetTitle: 'Tudo pronto', + availableTitle: 'Nova atualização disponível', + availableBody: 'Uma nova versão do Hermes está pronta para instalar.', + availableTitleBackend: 'Atualização de backend disponível', + availableBodyBackend: 'Uma versão mais nova do backend Hermes conectado está pronta para instalar.', + availableBodyNoChangelog: 'Uma versão mais nova está pronta. As notas de versão não estão disponíveis para este tipo de instalação.', + updateNow: 'Atualizar agora', + maybeLater: 'Talvez depois', + moreChanges: count => `+ mais ${count} alteração${count === 1 ? '' : 'ões'} incluída${count === 1 ? '' : 's'}.`, + manualTitle: 'Atualizar pelo terminal', + manualBody: 'Você instalou o Hermes pela linha de comando, então as atualizações também rodam por lá. Cole isto no seu terminal:', + manualPickedUp: 'O Hermes usará a nova versão na próxima inicialização.', + guiSkewTitle: 'Atualizar o app desktop', + guiSkewBody: + 'O backend foi atualizado, mas este pacote do app desktop não mudou. Atualize ou reinstale o app desktop do Hermes (seu AppImage / .deb / .rpm) para alinhar.', + copy: 'Copiar', + copied: 'Copiado', + done: 'Concluído', + applyingBody: + 'O atualizador do Hermes assume o controle em sua própria janela e reabre o Hermes automaticamente ao terminar. Por favor, não reabra o Hermes enquanto ele atualiza.', + applyingBodyBackend: + 'O backend remoto está aplicando a atualização e será reiniciado. O Hermes reconecta automaticamente quando voltar.', + applyingClose: 'Esta janela fechará enquanto a atualização roda; depois o Hermes reabre sozinho.', + errorTitle: 'A atualização não terminou', + errorBody: 'Sem problemas — nada foi perdido. Você pode tentar novamente agora.', + notNow: 'Agora não', + applyStatus: { + preparing: 'Atualizando backend…', + pulling: 'Backend atualizando…', + restarting: 'Backend reiniciando para carregar a atualização…', + notAvailable: 'Atualização indisponível para este backend.', + failed: 'Falha na atualização do backend.', + noReturn: 'O backend não voltou a ficar online. A atualização pode não ter sido concluída — verifique o host do backend.' + } + }, + + modelPicker: { + title: 'Alternar modelo', + current: 'atual:', + unknown: '(desconhecido)', + search: 'Filtrar provedores e modelos...', + noModels: 'Nenhum modelo encontrado.', + addProvider: 'Adicionar provedor', + loadFailed: 'Não foi possível carregar os modelos', + noAuthenticatedProviders: 'Nenhum provedor autenticado.', + pro: 'Pro', + proNeedsSubscription: 'Os modelos Pro exigem uma assinatura Nous paga.', + free: 'Grátis', + freeTier: 'Plano gratuito', + priceTitle: 'Preço de entrada / saída por milhão de tokens', + wasPrice: 'era' + }, + + shell: { + windowControls: 'Controles da janela', + paneControls: 'Controles do painel', + appControls: 'Controles do app', + modelMenu: { + search: 'Pesquisar modelos', + noModels: 'Nenhum modelo encontrado', + editModels: 'Editar Modelos…', + refreshModels: 'Atualizar Modelos', + fast: 'Rápido' + }, + modelOptions: { + noOptions: 'Nenhuma opção para este modelo', + options: 'Opções', + thinking: 'Raciocínio', + fast: 'Rápido', + effort: 'Esforço', + minimal: 'Mínimo', + low: 'Baixo', + medium: 'Médio', + high: 'Alto', + xhigh: 'Extra alto', + max: 'Máximo', + ultra: 'Ultra', + updateFailed: 'Falha ao atualizar a opção do modelo', + fastFailed: 'Falha ao atualizar o modo rápido' + }, + gatewayMenu: { + gateway: 'Gateway', + connected: 'Conectado', + connecting: 'Conectando', + offline: 'Offline', + inferenceReady: 'Inferência pronta', + inferenceNotReady: 'Inferência não pronta', + checkingInference: 'Verificando inferência', + disconnected: 'Desconectado', + openSystem: 'Abrir painel do sistema', + connection: label => `Conexão: ${label}`, + recentActivity: 'Atividade recente', + viewAllLogs: 'Ver todos os logs →', + messagingPlatforms: 'Plataformas de mensagens' + }, + approvalMode: { + title: 'Modo de aprovação', + ariaLabel: mode => `Modo de aprovação: ${mode}`, + manual: 'Manual', + manualDescription: 'Perguntar antes de ações que exigem aprovação', + smart: 'Inteligente', + smartDescription: 'Avaliar ações automaticamente e perguntar quando necessário', + off: 'Desligado', + offDescription: 'Executar sem solicitações de aprovação' + }, + statusbar: { + unknown: 'desconhecido', + restart: 'reiniciar', + update: 'atualizar', + updateInProgress: 'Atualização em andamento', + commitsBehind: (count, branch) => `${count} commit${count === 1 ? '' : 's'} atrás de ${branch}`, + desktopVersion: version => `Hermes Desktop v${version}`, + backendVersion: version => `Backend v${version}`, + clientLabel: version => `cliente v${version}`, + connectionSsh: host => `SSH: ${host}`, + connectionRemote: host => `Remoto: ${host}`, + connectionCloud: host => `Nuvem: ${host}`, + connectionCloudTooltip: host => `Hermes Cloud · ${host}`, + connectionSshTooltip: host => `SSH · ${host}`, + connectionRemoteTooltip: host => `Remoto · ${host}`, + backendLabel: version => `backend v${version}`, + commit: sha => `commit ${sha}`, + branch: branch => `ramo ${branch}`, + closeCommandCenter: 'Fechar Central de Comandos', + openCommandCenter: 'Abrir Central de Comandos', + showTerminal: 'Mostrar terminal', + hideTerminal: 'Ocultar terminal', + gateway: 'Gateway', + gatewayReady: 'pronto', + gatewayNeedsSetup: 'precisa de configuração', + gatewayChecking: 'verificando', + gatewayConnecting: 'conectando', + gatewayOffline: 'offline', + gatewayRestarting: 'reiniciando…', + gatewayTitle: 'Gateway', + customizeTitle: 'Mostrar na barra de status', + hideStatusbar: 'Ocultar barra de status', + toggleApprovalMode: 'Aprovações', + toggleBackendVersion: 'Versão do backend', + toggleCommandCenter: 'Central de Comandos', + toggleContextUsage: 'Medidor de contexto', + toggleRunningTimer: 'Cronômetro do turno', + toggleSessionTimer: 'Cronômetro da sessão', + toggleTerminal: 'Terminal', + toggleVersion: 'Versão e atualizações', + toggleWorkspace: 'Workspace', + agents: 'Agentes', + closeAgents: 'Fechar agentes', + openAgents: 'Abrir agentes', + subagents: count => `${count} subagente${count === 1 ? '' : 's'}`, + failed: count => `${count} falharam`, + running: count => `${count} em execução`, + cron: 'Cron', + openCron: 'Abrir tarefas agendadas', + webhooks: 'Webhooks', + openWebhooks: 'Abrir webhooks', + starmap: 'Grafo de Memória', + openStarmap: 'Abrir grafo de memória', + turnRunning: 'Executando', + contextUsage: 'Uso de contexto', + contextUsagePanel: { + categories: { + conversation: 'Conversa', + mcp: 'MCP', + memory: 'Memória', + rules: 'Regras', + skills: 'Habilidades', + subagent_definitions: 'Definições de subagentes', + system_prompt: 'Prompt de sistema', + tool_definitions: 'Definições de ferramentas' + }, + empty: 'Nenhum dado de contexto ainda', + loading: 'Carregando detalhamento…', + percentFull: percent => `${percent}% Cheio`, + title: 'Uso de Contexto', + tokenSummary: (used, max) => `${used} / ${max} Tokens` + }, + session: 'Sessão', + yoloOn: 'YOLO ligado — comandos perigosos aprovados automaticamente. Shift+clique alterna globalmente.', + yoloOff: 'YOLO desligado. Shift+clique alterna globalmente.', + modelNone: 'nenhum', + noModel: 'sem modelo', + switchModel: 'Alternar modelo', + openModelPicker: 'Abrir seletor de modelo', + modelPinned: 'fixado por você; novos chats usam este em vez do padrão das Configurações', + modelTitle: (provider, model) => `Modelo · ${provider}: ${model}`, + providerModelTitle: (provider, model) => `${provider} · ${model}` + } + }, + + errors: { + genericFailure: 'Algo deu errado', + boundaryTitle: 'Algo quebrou na interface', + boundaryDesc: 'A exibição encontrou um erro inesperado. Suas conversas e configurações estão seguras.', + reloadWindow: 'Recarregar janela', + openLogs: 'Abrir logs' + }, + + ui: { + search: { + clear: 'Limpar pesquisa' + }, + pagination: { + label: 'paginação', + previous: 'Anterior', + previousAria: 'Ir para a página anterior', + next: 'Próxima', + nextAria: 'Ir para a próxima página' + }, + sidebar: { + title: 'Barra lateral', + description: 'Exibe a barra lateral do celular.', + toggle: open => `${open ? 'Mostrar' : 'Ocultar'} barra lateral` + } + }, +fileMenu: { + revealFinder: 'Mostrar no Finder', + revealExplorer: 'Mostrar no Explorador de Arquivos', + revealFileManager: 'Abrir pasta contenedora', + revealInSidebar: 'Mostrar na árvore de arquivos', + copyPath: 'Copiar caminho', + copyRelativePath: 'Copiar caminho relativo', + rename: 'Renomear…', + delete: 'Excluir', + renameTitle: 'Renomear', + renameLabel: 'Novo nome', + deleteTitle: name => `Excluir ${name}?`, + deleteBody: 'Será movido para a Lixeira — você pode restaurá-lo de lá.', + pathCopied: 'Caminho copiado' + }, + + notifications: { + region: 'Notificações', + hide: 'Ocultar', + show: 'Mostrar', + more: count => `${count} ${count === 1 ? 'notificação a mais' : 'notificações a mais'}`, + clearAll: 'Limpar todas', + dismiss: 'Dispensar notificação', + details: 'Detalhes', + copyDetail: 'Copiar detalhe', + copyDetailFailed: 'Não foi possível copiar o detalhe da notificação', + backendOutOfDateTitle: 'Backend desatualizado', + backendOutOfDateMessage: + 'Seu backend do Hermes é mais antigo que esta versão do desktop e pode não funcionar corretamente. Atualize para alinhá-los.', + installMethodUnsupportedTitle: 'Método de instalação não suportado', + updateHermes: 'Atualizar Hermes', + updateReadyTitle: 'Atualização pronta', + updateReadyMessage: count => `${count} nova alteração${count === 1 ? '' : 's'} disponível.`, + seeWhatsNew: 'Ver novidades', + errors: { + elevenLabsNeedsKey: 'STT do ElevenLabs precisa de ELEVENLABS_API_KEY.', + elevenLabsRejectedKey: 'ElevenLabs rejeitou a chave de API (401).', + diskFull: 'Disco cheio — libere espaço e tente novamente.', + gatewayAuthFailed: 'Autenticação do gateway falhou — verifique sua API_SERVER_KEY.', + methodNotAllowed: + 'O backend do desktop rejeitou essa solicitação (405 Method Not Allowed). Tente reiniciar o Hermes Desktop.', + microphonePermission: 'Permissão de microfone foi negada.', + openaiRejectedApiKey: 'OpenAI rejeitou a chave de API.', + openaiRejectedApiKeyWithStatus: status => `OpenAI rejeitou a chave de API (${status} invalid_api_key).`, + openaiTtsNeedsKey: 'TTS do OpenAI precisa de VOICE_TOOLS_OPENAI_KEY ou OPENAI_API_KEY.' + }, + voice: { + configureSpeechToText: 'Configure o speech-to-text para usar o modo de voz.', + couldNotStartSession: 'Não foi possível iniciar a sessão de voz', + microphoneAccessDenied: 'Acesso ao microfone negado.', + microphoneConstraintsUnsupported: 'As restrições de microfone não são suportadas por este dispositivo.', + microphoneFailed: 'Falha no microfone', + microphoneInUse: 'O microfone já está em uso por outro aplicativo.', + microphonePermissionDenied: 'Permissão de microfone foi negada.', + microphoneStartFailed: 'Não foi possível iniciar a gravação do microfone.', + microphoneUnsupported: 'Este ambiente de execução não suporta gravação de microfone.', + noMicrophone: 'Nenhum microfone encontrado.', + noSpeechDetected: 'Nenhuma fala detectada', + playbackFailed: 'Reprodução de voz falhou', + recordingFailed: 'Gravação de voz falhou', + sayStopToEnd: phrase => `Diga "${phrase}" para encerrar o chat de voz.`, + transcriptionFailed: 'Transcrição de voz falhou', + transcriptionUnavailable: 'A transcrição de voz ainda não está disponível.', + tryRecordingAgain: 'Tente gravar novamente.', + unavailable: 'Voz indisponível' + }, + native: { + approvalTitle: 'Aprovação necessária', + approveAction: 'Aprovar', + rejectAction: 'Rejeitar', + inputTitle: 'Entrada necessária', + inputBody: 'O Hermes está aguardando sua resposta.', + turnDoneTitle: 'Hermes concluído', + turnDoneBody: '', + turnErrorTitle: 'Turno falhou', + backgroundDoneTitle: 'Tarefa em segundo plano concluída', + backgroundFailedTitle: 'Tarefa em segundo plano falhou', + creditsTitle: 'Créditos' + } + }, + + settings: { + closeSettings: 'Fechar configurações', + exportConfig: 'Exportar configuração', + importConfig: 'Importar configuração', + resetToDefaults: 'Restaurar padrões', + resetConfirm: 'Restaurar todas as configurações para os padrões do Hermes?', + exportFailed: 'Falha na exportação', + resetFailed: 'Falha na restauração', + nav: { + providers: 'Provedores', + providerAccounts: 'Contas', + providerApiKeys: 'Chaves de API', + providerCustomEndpoints: 'Endpoints personalizados', + gateway: 'Gateway', + apiKeys: 'Ferramentas & Chaves', + keybinds: 'Atalhos de teclado', + keysTools: 'Ferramentas', + keysSettings: 'Configurações', + mcp: 'MCP', + archivedChats: 'Conversas arquivadas', + about: 'Sobre', + billing: 'Cobrança', + notifications: 'Notificações', + plugins: 'Plugins' + }, + plugins: { + title: 'Plugins do desktop', + blurb: 'Embutidos ou colocados na pasta desktop-plugins. Desative para descarregar em tempo real.', + count: n => `${n} instalado${n === 1 ? '' : 's'}`, + openFolder: 'Abrir pasta de plugins', + rescan: 'Reescanear', + reveal: 'Mostrar no gerenciador de arquivos', + enable: 'Ativar', + disable: 'Desativar', + failed: 'falhou', + empty: 'Nenhum plugin de desktop instalado ainda.', + kinds: { bundled: 'embutido', disk: 'no disco', runtime: 'em tempo de execução' } + }, + notifications: { + title: 'Notificações', + intro: 'Notificações do sistema operacional (não toasts no app). Por dispositivo.', + enableAll: 'Ativar notificações', + enableAllDesc: 'Desligado silencia todas as notificações abaixo.', + focusedHint: 'Alertas de conclusão só disparam quando o Hermes está em segundo plano.', + kinds: { + approval: { + label: 'Aprovação necessária', + description: 'Um comando está aguardando você aprová-lo ou rejeitá-lo.' + }, + input: { + label: 'Entrada necessária', + description: 'O Hermes fez uma pergunta ou precisa de uma senha ou segredo.' + }, + turnDone: { + label: 'Resposta pronta', + description: 'Um turno foi concluído enquanto o Hermes estava em segundo plano.' + }, + turnError: { + label: 'Turno falhou', + description: 'Erros de turno em segundo plano.' + }, + backgroundDone: { + label: 'Tarefa em segundo plano concluída', + description: 'Um comando de terminal em segundo plano foi concluído.' + }, + credits: { + label: 'Alertas de crédito', + description: 'O acesso a créditos foi pausado ou restaurado.' + } + }, + test: 'Enviar notificação de teste', + testTitle: 'Hermes', + testBody: 'As notificações estão funcionando.', + testSent: 'Teste enviado. Se nada aparecer, verifique as permissões de notificação do seu sistema e o modo Não Perturbe/Foco.', + testUnsupported: 'Este sistema não suporta notificações nativas.', + completionSoundTitle: 'Som de conclusão', + completionSoundDesc: 'Toca quando um turno do agente termina. Escolha um preset e visualize aqui.', + completionSoundPreview: 'Visualizar' + }, + sections: { + model: 'Modelo', + chat: 'Conversa', + appearance: 'Aparência', + workspace: 'Espaço de trabalho', + safety: 'Segurança', + memory: 'Memória & Contexto', + voice: 'Voz', + advanced: 'Avançado' + }, + searchPlaceholder: { + about: 'Sobre o Hermes Desktop', + config: 'Buscar configurações...', + gateway: 'Conexão do gateway...', + keys: 'Buscar chaves de API...', + mcp: 'Buscar servidores MCP...', + sessions: 'Buscar sessões arquivadas...' + }, + modeOptions: { + light: { label: 'Claro', description: 'Superfícies brilhantes do desktop' }, + dark: { label: 'Escuro', description: 'Espaço de trabalho com pouco ofuscamento' }, + system: { label: 'Sistema', description: 'Seguir a aparência do sistema' } + }, + appearance: { + title: 'Aparência', + intro: 'Somente desktop. O modo é o brilho; o tema é a paleta e o visual da conversa.', + colorMode: 'Modo de cor', + colorModeDesc: 'Escolha um modo fixo ou deixe o Hermes seguir a configuração do seu sistema.', + toolViewTitle: 'Exibição de chamadas de ferramenta', + toolViewDesc: 'Produto oculta os dados brutos das ferramentas; Técnico mostra entrada/saída completa.', + uiScaleTitle: 'Escala da interface', + uiScaleDesc: (percent: number) => + `Dimensiona textos e controles em todo o app. Cmd/Ctrl com +, - e 0 também funciona. Atual: ${percent}%.`, + terminalFontTitle: 'Fonte do terminal', + terminalFontDesc: + 'Escolha uma fonte instalada para os terminais do Desktop. Nerd Fonts renderizam Powerlevel10k e ícones de shell; deixe em branco para usar a JetBrains Mono inclusa.', + terminalFontPlaceholder: 'MesloLGS NF ou uma pilha de fontes CSS', + terminalFontPreview: 'Pré-visualização de glifos', + terminalFontReset: 'Usar padrão', + translucencyTitle: 'Translucidez da janela', + translucencyDesc: 'Veja seu desktop através de toda a janela. Somente macOS e Windows.', + backdropTitle: 'Imagem de fundo da conversa', + backdropDesc: 'A imagem suave de estátua atrás da conversa.', + reactionsTitle: 'Reações a mensagens', + reactionsDesc: 'Reações de emoji no estilo iMessage — reaja a mensagens, e o Hermes pode reagir às suas.', + embedsTitle: 'Incorporações inline', + embedsDesc: + 'Pré-visualizações ricas carregadas de sites de terceiros (YouTube, X, …). Perguntar mostra um placeholder até você permitir cada um; Sempre carrega automaticamente; Desligado mantém links simples.', + embedsAsk: 'Perguntar', + embedsAlways: 'Sempre', + embedsOff: 'Desligado', + embedsReset: (count: number) => `Redefinir ${count} ${count === 1 ? 'serviço permitido' : 'serviços permitidos'}`, + product: 'Produto', + productDesc: 'Atividade de ferramentas amigável com resumos concisos.', + technical: 'Técnico', + technicalDesc: 'Inclui argumentos/resultados brutos das ferramentas e detalhes de baixo nível.', + themeTitle: 'Tema', + themeDesc: 'Apenas paletas de desktop. O modo selecionado é aplicado por cima.', + themeProfileNote: profile => `Salvo para o perfil ${profile} — cada perfil mantém seu próprio tema.`, + installTitle: 'Instalar do VS Code', + installDesc: + 'Cole um ID de extensão do Marketplace (ex. dracula-theme.theme-dracula) para converter seu tema de cores em uma paleta de desktop.', + installPlaceholder: 'publisher.extension', + installButton: 'Instalar', + installing: 'Instalando…', + installError: 'Não foi possível instalar esse tema.', + installed: name => `Instalado "${name}".`, + removeTheme: 'Remover tema', + importedBadge: 'Importado', + pet: { + title: 'Mascote', + intro: + 'Adote um mascote animado do petdex que flutua sobre o app e reage ao que o Hermes está fazendo — correndo enquanto ferramentas executam, comemorando em sucesso, frustrado em erros.', + restartHint: + 'Os mascotes precisam de uma reinicialização rápida — o app em execução foi iniciado antes deste recurso ser adicionado. Saia e reabra o Hermes, depois volte aqui.', + on: 'Ligado', + off: 'Desligado', + scaleTitle: 'Tamanho', + scaleDesc: 'Redimensione o mascote flutuante. Aplica-se em todo lugar instantaneamente.', + roamTitle: 'Vagar', + roamDesc: 'Deixe o mascote percorrer a janela por conta própria enquanto está ocioso.', + chooseTitle: 'Escolha um mascote', + chooseDesc: 'Escolher um instala-o (se necessário) e o torna ativo.', + searchPlaceholder: 'Buscar mascotes…', + unreachable: 'Não foi possível acessar a galeria do petdex. Verifique sua conexão e reabra esta página.', + noMatch: query => `Nenhum mascote corresponde a "${query}".`, + installedTag: 'instalado', + generatedTag: 'Gerado', + countCapped: (cap, total) => `Mostrando ${cap} de ${total} — digite para refinar a busca.`, + count: n => `${n} mascote${n === 1 ? '' : 's'}.`, + uninstall: name => `Desinstalar ${name}`, + delete: name => `Excluir ${name}`, + deleteTitle: name => `Excluir ${name}?`, + deleteBody: 'Isso exclui o mascote permanentemente — não poderá ser reinstalado.', + deleteConfirm: 'Excluir', + rename: name => `Renomear ${name}`, + renameTitle: 'Renomear mascote', + renamePlaceholder: 'Dê um nome ao seu mascote', + renameSave: 'Salvar', + exportPet: name => `Exportar ${name}`, + adoptFailed: slug => `Não foi possível adotar ${slug}`, + uninstallFailed: slug => `Não foi possível desinstalar ${slug}`, + renameFailed: slug => `Não foi possível renomear ${slug}`, + exportFailed: slug => `Não foi possível exportar ${slug}`, + noneAvailable: 'Nenhum mascote disponível para ativar agora.', + turnOnFailed: 'Não foi possível ligar o mascote.', + turnOffFailed: 'Não foi possível desligar o mascote.' + } + }, + fieldLabels: FIELD_LABELS, + fieldDescriptions: FIELD_DESCRIPTIONS, + about: { + heading: 'Hermes Desktop', + version: value => `Versão ${value}`, + versionUnavailable: 'Versão indisponível', + updates: 'Atualizações', + checkNow: 'Verificar agora', + checking: 'Verificando…', + seeWhatsNew: 'Ver novidades', + updateNow: 'Atualizar agora', + releaseNotes: 'Notas da versão', + onLatest: 'Você está na versão mais recente.', + installing: 'Uma atualização está sendo instalada no momento.', + cantUpdate: 'Esta versão não pode se atualizar de dentro do app.', + cantReach: 'Não foi possível acessar o servidor de atualização.', + tapCheck: 'Toque em "Verificar agora" para procurar atualizações.', + updateReady: count => `Uma nova atualização está pronta (${count} alteração${count === 1 ? '' : 's'} incluída${count === 1 ? '' : 's'}).`, + lastChecked: age => `Última verificação ${age}`, + justNowSuffix: ' · agora há pouco', + automaticUpdates: 'Atualizações automáticas', + automaticUpdatesDesc: + 'O Hermes verifica atualizações automaticamente em segundo plano e avisa quando uma está pronta.', + branchCommit: (branch, commit) => `Branch ${branch} · Commit ${commit}`, + never: 'nunca', + justNow: 'agora há pouco', + minAgo: count => `${count} min atrás`, + hoursAgo: count => `${count} h atrás`, + daysAgo: count => `${count} dias atrás` + }, + config: { + none: 'Nenhum', + noneParen: '(nenhum)', + builtinOnly: 'Apenas embutido', + notSet: 'Não definido', + commaSeparated: 'valores separados por vírgula', + searchPlaceholder: 'Buscar…', + noResults: 'Nenhum resultado encontrado', + systemDefault: 'Padrão do sistema', + loading: 'Carregando configuração do Hermes...', + emptyTitle: 'Nada para configurar', + emptyDesc: 'Esta seção não tem configurações ajustáveis.', + failedLoad: 'Falha ao carregar configurações', + autosaveFailed: 'Falha no salvamento automático', + imported: 'Configuração importada', + invalidJson: 'JSON de configuração inválido', + keepAwakeTitle: 'Manter computador acordado', + keepAwakeDesc: 'Impede esta máquina de hibernar para que execuções longas ou noturnas continuem. A tela ainda pode escurecer.', + attachmentSizeTitle: 'Tamanho máximo de pré-visualização / carregamento de imagem', + attachmentSizeDesc: + 'O quão grande um arquivo local que o Desktop carregará para pré-visualizações e anexos de imagem, em MB. O padrão é 16. Anexos remotos que não são imagens usam um limite separado de 256 MB. Definir isso muito alto carrega o arquivo inteiro na memória e pode congelar ou travar o app.', + attachmentSizeUnit: 'MB', + attachmentSizeLabel: 'Tamanho máximo de pré-visualização / carregamento de imagem em megabytes' + }, + quickEntry: { + enabledTitle: 'Entrada rápida', + enabledDesc: + 'Invoque um pequeno compositor de qualquer lugar com um atalho global e envie um prompt sem abrir o Hermes.', + shortcutTitle: 'Atalho de Entrada rápida', + shortcutDesc: 'Precisa de pelo menos um modificador, ex. CommandOrControl+Shift+Space.', + active: 'O atalho está ativo.', + takenBy: 'Outro app já usa este atalho — escolha um diferente.', + invalidShortcut: 'Atalho inválido. Inclua pelo menos uma tecla modificadora.' + }, + credentials: { + pasteKey: 'Colar chave', + pasteLabelKey: label => `Colar chave de ${label}`, + optional: 'Opcional', + enterValueFirst: 'Digite um valor primeiro.', + couldNotSave: 'Não foi possível salvar a credencial.', + remove: 'Remover', + getKey: 'Obter uma chave', + saving: 'Salvando' + }, + envActions: { + actions: 'Ações', + manageInKeys: 'Gerenciar em Chaves de API', + docs: 'Documentação', + hideValue: 'Ocultar valor', + revealValue: 'Revelar valor', + replace: 'Substituir', + set: 'Definir', + clear: 'Limpar' + }, + gateway: { + loading: 'Carregando configurações do gateway...', + unavailableTitle: 'Configurações de gateway indisponíveis', + unavailableDesc: 'A ponte IPC do desktop não expõe configurações de gateway.', + title: 'Conexão do gateway', + envOverride: 'substituição por env', + intro: + 'Local por padrão. Use remoto quando este app deve controlar um backend do Hermes em outro lugar. Substituições por perfil abaixo.', + appliesTo: 'Aplica-se a', + allProfiles: 'Todos os perfis', + defaultConnection: 'Conexão padrão para todo perfil que não tenha sua própria substituição.', + profileConnection: profile => + `Conexão usada apenas quando "${profile}" é o perfil ativo. Escolha Usar gateway padrão para remover sua substituição.`, + envOverrideTitle: 'Variáveis de ambiente estão controlando esta sessão do desktop.', + envOverrideDesc: + 'Remova HERMES_DESKTOP_REMOTE_URL e HERMES_DESKTOP_REMOTE_TOKEN para usar a configuração salva abaixo.', + modeTitle: 'Modo de conexão', + localTitle: 'Gateway local', + localDesc: 'Inicia um backend privado do Hermes em localhost. Este é o padrão e funciona offline.', + inheritTitle: 'Usar gateway padrão', + inheritDesc: 'Remove a substituição deste perfil e usa a conexão padrão.', + remoteTitle: 'Gateway remoto', + remoteDesc: 'Conecta este shell do desktop a um backend remoto do Hermes.', + remoteAuthHint: 'Gateways hospedados usam OAuth ou usuário e senha; os auto-hospedados podem usar um token de sessão.', + cloudTitle: 'Hermes Cloud', + cloudDesc: 'Entre uma vez no Hermes Cloud e escolha entre os agentes da sua conta — sem URL para colar.', + cloudSignInTitle: 'Hermes Cloud', + cloudSignIn: 'Entrar no Hermes Cloud', + cloudSignedIn: 'Conectado ao Hermes Cloud', + cloudNeedsSignIn: 'Entre no Hermes Cloud para descobrir os agentes da sua conta.', + cloudSignedInDesc: 'Você está conectado. Escolha um agente abaixo; a sessão é atualizada automaticamente.', + cloudAgentsTitle: 'Seus agentes', + cloudOrgPickerTitle: 'Escolha uma organização', + cloudOrgSelect: 'Selecionar', + cloudOrgChange: 'Trocar organização', + cloudOrgRole: role => `Função: ${role}`, + cloudLoadingAgents: 'Carregando seus agentes…', + cloudNoAgents: { + before: 'Nenhum agente encontrado nesta conta. Crie um no ', + linkText: 'portal da Nous', + after: ', depois atualize.' + }, + cloudRefresh: 'Atualizar', + cloudConnect: 'Conectar', + cloudConnecting: 'Conectando…', + cloudDiscoverFailed: 'Não foi possível carregar seus agentes do Hermes Cloud', + cloudConnectFailed: 'Não foi possível conectar a esse agente', + cloudSignInFailed: 'Falha no login no Hermes Cloud', + cloudSignedOutTitle: 'Desconectado do Hermes Cloud', + cloudSignedOutMessage: 'Sessão do Hermes Cloud limpa.', + cloudConnectedTitle: 'Conectado', + cloudConnectedPill: 'Conectado', + cloudConnectedTo: name => `Conectado a ${name}.`, + cloudAgentProvisioning: 'Provisionando…', + cloudStatusLabel: status => `Status: ${status}`, + remoteUrlTitle: 'URL remota', + remoteUrlDesc: 'URL base para o backend remoto do dashboard. Prefixos de caminho são suportados, por exemplo /hermes.', + probing: 'Verificando como este gateway autentica…', + probeError: 'Ainda não foi possível acessar este gateway. Verifique a URL — o método de autenticação aparecerá assim que ele responder.', + signedIn: 'Conectado', + signIn: 'Entrar', + signOut: 'Sair', + signInWith: provider => `Entrar com ${provider}`, + authTitle: 'Autenticação', + authSignedInPassword: + 'Este gateway usa usuário e senha. Você está conectado; a sessão é atualizada automaticamente.', + authSignedInOauth: 'Este gateway usa OAuth. Você está conectado; a sessão é atualizada automaticamente.', + authNeedsPassword: 'Este gateway usa usuário e senha. Entre para autorizar este app desktop.', + authNeedsOauth: provider => `Este gateway usa OAuth. Entre com ${provider} para autorizar este app desktop.`, + tokenTitle: 'Token de sessão', + tokenDesc: 'O token de sessão do dashboard usado para acesso REST e WebSocket. Deixe em branco para manter o token salvo.', + existingToken: value => `Token existente ${value}`, + savedToken: 'salvo', + pasteSessionToken: 'Colar token de sessão', + testRemote: 'Testar remoto', + saveForRestart: 'Salvar para próxima reinicialização', + saveAndReconnect: 'Salvar e reconectar', + diagnostics: 'Diagnóstico', + diagnosticsDesc: 'Mostra o desktop.log no seu gerenciador de arquivos — útil quando o gateway falha ao iniciar.', + openLogs: 'Abrir logs', + incompleteTitle: 'Gateway remoto incompleto', + incompleteSignIn: 'Digite uma URL remota e entre antes de mudar para remoto.', + incompleteToken: 'Digite uma URL remota e um token de sessão antes de mudar para remoto.', + incompleteSignInTest: 'Digite uma URL remota e entre antes de testar.', + incompleteTokenTest: 'Digite uma URL remota e um token de sessão antes de testar.', + enterUrlFirst: 'Digite uma URL remota primeiro.', + restartingTitle: 'Reiniciando conexão do gateway', + savedTitle: 'Configurações do gateway salvas', + restartingMessage: 'O Hermes Desktop vai reconectar usando as configurações salvas — o shell permanece aberto.', + savedMessage: 'Salvo para a próxima reinicialização.', + connectedTo: (baseUrl, version) => `Conectado a ${baseUrl}${version ? ` · Hermes ${version}` : ''}`, + reachableTitle: 'Gateway remoto acessível', + signedOutTitle: 'Desconectado', + signedOutMessage: 'Sessão do gateway remoto limpa.', + failedLoad: 'Falha ao carregar configurações do gateway', + signInFailed: 'Falha no login', + signOutFailed: 'Falha ao sair', + testFailed: 'Falha no teste do gateway remoto', + applyFailed: 'Não foi possível aplicar as configurações do gateway', + saveFailed: 'Não foi possível salvar as configurações do gateway', + sshTitle: 'Conectar via SSH', + sshDesc: + 'O Hermes é iniciado no remoto via SSH e tunelado para este app — nada para iniciar ou expor por conta própria. Requer acesso SSH funcional baseado em chave ao host.', + sshTrustHint: 'A primeira chave de host apresentada é confiável e fixada; mudanças posteriores falham por segurança.', + sshHostTitle: 'Host', + sshHostDesc: 'user@host, ou um alias de Host do ~/.ssh/config.', + sshHostPick: 'Selecione um host…', + sshHostPickTitle: 'Host', + sshHostPickDesc: 'Um alias de Host do ~/.ssh/config, ou Personalizado para digitar um.', + sshHostCustom: 'Personalizado (digitar manualmente)…', + sshUserTitle: 'Usuário', + sshUserDesc: 'Em branco = ~/.ssh/config ou seu usuário atual.', + sshUserPlaceholder: 'do ~/.ssh/config', + sshPortTitle: 'Porta', + sshPortDesc: 'Em branco = 22 ou a porta do ~/.ssh/config.', + sshKeyTitle: 'Arquivo de identidade', + sshKeyDesc: 'Caminho da chave privada. Em branco = ssh-agent ou ~/.ssh/config.', + sshHermesPathTitle: 'Caminho do Hermes (opcional)', + sshHermesPathDesc: 'Caminho completo para o binário remoto do hermes. Em branco = detecção automática.', + sshHermesPathPlaceholder: 'detecção automática', + sshRemoteProfileTitle: 'Perfil remoto (opcional)', + sshRemoteProfileDesc: 'Nome do perfil no host remoto. Em branco = usar o nome do perfil do Desktop.', + sshTestConnection: 'Testar SSH', + sshConnect: 'Conectar', + sshButtonsHint: 'Salvar aplica na próxima inicialização. Conectar reconecta agora.', + sshReachable: (host, platform) => `Acessível: ${host} (${platform}) — Hermes encontrado`, + sshIncompleteHost: 'Digite um host SSH antes de conectar.', + sshErrUnreachable: 'Não foi possível acessar esse host via SSH. Verifique o host, a porta e sua rede.', + sshErrAuth: + 'Autenticação SSH falhou. Carregue sua chave no ssh-agent (ssh-add) ou defina um IdentityFile no ~/.ssh/config — o Hermes executa ssh de forma não interativa.', + sshErrHostKey: + 'A chave do host MUDOU desde a última conexão. Verifique se isso é esperado, depois execute ssh-keygen -R e reconecte.', + sshErrNotInstalled: + 'O Hermes não está instalado no host remoto. Instale-o lá (curl -fsSL https://hermes-agent.nousresearch.com/install.sh | sh) ou defina o caminho do Hermes.', + sshErrPlatform: + 'Plataforma remota não suportada. O modo SSH do Hermes Desktop suporta hosts remotos Linux, macOS e Windows.', + sshErrTimeout: 'A conexão SSH atingiu o tempo limite. O host pode estar inacessível ou adormecido.', + sshErrUpdateRequired: 'Atualize o Hermes no host remoto antes de conectar com Desktop SSH.', + sshErrUnknown: 'Falha na conexão SSH.' + }, + keys: { + loading: 'Carregando chaves de API e credenciais...', + failedLoad: 'Falha ao carregar chaves de API', + empty: 'Nada configurado nesta categoria ainda.' + }, + mcp: { + loading: 'Carregando servidores MCP...', + failedLoad: 'Falha ao carregar configuração do MCP', + nameRequiredTitle: 'Nome obrigatório', + nameRequiredMessage: 'Dê a este servidor MCP uma chave de configuração.', + objectRequired: 'A configuração do servidor deve ser um objeto JSON', + invalidJson: 'JSON do MCP inválido', + saveFailed: 'Falha ao salvar', + removeFailed: 'Falha ao remover', + gatewayUnavailableTitle: 'Gateway indisponível', + gatewayUnavailableMessage: 'Reconecte o gateway antes de recarregar o MCP.', + reloadedTitle: 'Ferramentas MCP recarregadas', + reloadedMessage: 'Novos esquemas de ferramentas aplicam-se a novos turnos.', + reloadFailed: 'Falha ao recarregar MCP', + savedTitle: 'Servidor MCP salvo', + savedMessage: name => `${name} aplica-se após recarregar o MCP.`, + newServer: 'Novo servidor', + reload: 'Recarregar MCP', + reloading: 'Recarregando...', + emptyTitle: 'Nenhum servidor MCP', + emptyDesc: 'Adicione um servidor stdio ou HTTP para expor ferramentas MCP.', + disabled: 'desativado', + editServer: 'Editar servidor', + name: 'Nome', + serverJson: 'JSON do servidor', + remove: 'Remover', + saveServer: 'Salvar servidor', + test: 'Testar conexão', + testing: 'Testando...', + testOk: count => `Conectado — ${count} ferramenta${count === 1 ? '' : 's'} disponível${count === 1 ? '' : 's'}`, + testFailed: 'Falha na conexão', + enableServer: name => `Ativar ${name}`, + disableServer: name => `Desativar ${name}`, + serverEnabled: name => `${name} ativado — aplica-se a novas sessões.`, + serverDisabled: name => `${name} desativado — aplica-se a novas sessões.`, + toggleFailed: (name, enabled) => `Falha ao ${enabled ? 'ativar' : 'desativar'} ${name}`, + tabServers: 'Servidores', + tabCatalog: 'Catálogo', + catalogLoading: 'Carregando catálogo MCP...', + catalogLoadFailed: 'Falha ao carregar catálogo MCP', + catalogEmpty: 'Nenhuma entrada de catálogo disponível.', + catalogInstalled: 'Instalado', + catalogEnabled: 'Ativado', + catalogNeedsInstall: 'Precisa de build', + catalogInstall: 'Instalar', + catalogInstalling: 'Instalando...', + catalogInstallStarted: name => `Instalando ${name}... aplica-se a novas sessões quando concluído.`, + catalogInstallFailed: name => `Falha ao instalar ${name}`, + catalogEnvPrompt: name => `${name} requer credenciais`, + catalogEnvRequired: 'Preencha os valores obrigatórios antes de instalar.', + capabilitySummary: (tools, prompts, resources) => + `${[`${tools} ferramentas`, ...(prompts ? [`${prompts} prompts`] : []), ...(resources ? [`${resources} recursos`] : [])].join(', ')} ativado(s)`, + statusConnecting: 'Conectando…', + statusNeedsAuth: 'Precisa de autenticação', + statusError: 'Erro', + statusOff: 'Desligado', + allServers: 'Todos os servidores', + authenticatedTitle: 'Autenticado', + authenticatedMessage: (server, count) => `${server}: ${count} ferramentas`, + waitingForBrowser: 'Aguardando o navegador…', + authenticate: 'Autenticar', + unsavedConnect: 'Não salvo — salve o mcp.json para conectar.', + enableTool: tool => `Ativar ${tool}`, + disableTool: tool => `Desativar ${tool}`, + noOutput: 'Nenhuma saída ainda.' + }, + model: { + loading: 'Carregando configuração de modelo...', + appliesDesc: 'Aplica-se a novas sessões. Use o seletor de modelo no compositor para trocar o chat ativo em tempo real.', + provider: 'Provedor', + model: 'Modelo', + applying: 'Aplicando...', + defaultsLabel: 'Padrões', + reasoning: 'Raciocínio', + reasoningOff: 'Desligado', + defaultsFailed: 'Falha ao salvar padrões de modelo', + auxiliaryTitle: 'Modelos auxiliares', + resetAllToMain: 'Restaurar todos para o principal', + auxiliaryDesc: 'Tarefas auxiliares usam o modelo principal por padrão. Atribua um modelo dedicado a qualquer tarefa para substituir.', + setToMain: 'Definir como principal', + change: 'Alterar', + autoUseMain: 'auto · usar modelo principal', + providerDefault: '(padrão do provedor)', + fallbackAdd: 'Adicionar fallback', + fallbackEmpty: 'Nenhum modelo de fallback — o modelo padrão é usado a menos que falhe.', + notInCatalog: 'não está na lista de modelos deste provedor — chamadas podem recorrer a um backup.', + tasks: { + vision: { label: 'Visão', hint: 'Análise de imagens' }, + web_extract: { label: 'Extração web', hint: 'Resumo de páginas' }, + compression: { label: 'Compressão', hint: 'Compactação de contexto' }, + skills_hub: { label: 'Central de skills', hint: 'Busca de skills' }, + approval: { label: 'Aprovação', hint: 'Aprovação automática inteligente' }, + mcp: { label: 'MCP', hint: 'Roteamento de ferramentas MCP' }, + title_generation: { label: 'Geração de título', hint: 'Títulos de sessão' }, + curator: { label: 'Curador', hint: 'Revisão de uso de skills' } + } + }, + providers: { + connectAccount: 'Conectar uma conta', + haveApiKey: 'Prefere usar uma chave de API?', + intro: + 'Entre com uma assinatura — sem chave de API para copiar. O Hermes faz o login pelo navegador para você, direto no app.', + connected: 'Conectado', + collapse: 'Recolher', + connectAnother: 'Conectar outro provedor', + otherProviders: 'Outros provedores', + disconnect: 'Desconectar', + disconnectInTerminal: 'Desconectar (executa o comando de remoção no terminal)', + removeConfirm: provider => `Remover ${provider}?`, + removeExternalGeneric: provider => `${provider} é gerenciado por seu próprio CLI — remova-o lá.`, + removeKeyManaged: provider => `${provider} é configurado a partir de uma chave de API. Remova-o em Chaves de API.`, + removeTerminalConfirm: (provider, command) => + `Desconectar ${provider}? Isso executa "${command}" no terminal para limpar a credencial.`, + removeTerminalRunning: provider => `Executando desconexão de ${provider} no terminal…`, + removedTitle: 'Conta removida', + removedMessage: provider => `${provider} foi removido.`, + failedRemove: provider => `Não foi possível remover ${provider}`, + noProviderKeys: 'Nenhuma chave de API de provedor disponível.', + searchKeys: 'Buscar provedores…', + noKeysMatch: 'Nenhum provedor corresponde à sua busca.', + localEndpoint: { + title: 'Endpoint local / personalizado', + description: 'Aponte o Hermes para qualquer endpoint compatível com OpenAI (Zyphra, vLLM, llama.cpp, Ollama, etc).' + }, + loading: 'Carregando provedores...' + }, + sessions: { + loading: 'Carregando sessões arquivadas…', + archivedTitle: 'Sessões arquivadas', + archivedIntro: + 'Conversas arquivadas são ocultadas da barra lateral, mas mantêm todas as suas mensagens. Ctrl/⌘-clique em uma conversa na barra lateral para arquivá-la.', + emptyArchivedTitle: 'Nada arquivado', + emptyArchivedDesc: 'Arquive uma conversa para ocultá-la aqui.', + unarchive: 'Desarquivar', + deletePermanently: 'Excluir permanentemente', + messages: count => `${count} ${count === 1 ? 'mensagem' : 'mensagens'}`, + restored: 'Restaurado', + deleteConfirm: title => `Excluir permanentemente "${title}"? Isso não pode ser desfeito.`, + autoArchiveTitle: 'Arquivar conversas inativas automaticamente', + autoArchiveDesc: + 'Arquiva automaticamente conversas que você não toca há um tempo. Conversas fixadas nunca são arquivadas, e nada é excluído — conversas arquivadas apenas vêm para cá.', + autoArchiveDaysLabel: 'Arquivar após', + autoArchiveDaysUnit: 'dias de inatividade', + autoArchiveFailed: 'Não foi possível atualizar o arquivamento automático', + defaultDirTitle: 'Diretório de projeto padrão', + defaultDirDesc: + 'Novas sessões começam nesta pasta a menos que você escolha outra. Deixe em branco para usar seu diretório home.', + defaultDirUpdated: 'Diretório de projeto padrão atualizado — inicie uma nova conversa (Ctrl/⌘+N) para que entre em vigor', + defaultsTo: label => `Padrão: ${label}.`, + change: 'Alterar', + choose: 'Escolher', + clear: 'Limpar', + notSet: 'Não definido', + failedLoad: 'Não foi possível carregar sessões arquivadas', + unarchiveFailed: 'Falha ao desarquivar', + deleteFailed: 'Falha ao excluir', + updateDirFailed: 'Não foi possível atualizar o diretório padrão', + clearDirFailed: 'Não foi possível limpar o diretório padrão' + }, + toolsets: { + loadingConfig: 'Carregando configuração', + savedTitle: 'Credencial salva', + savedMessage: key => `${key} atualizada.`, + removedTitle: 'Credencial removida', + removedMessage: key => `${key} removida.`, + failedSave: key => `Falha ao salvar ${key}`, + failedRemove: key => `Falha ao remover ${key}`, + failedReveal: key => `Falha ao revelar ${key}`, + removeConfirm: key => `Remover ${key} do .env?`, + set: 'Definir', + notSet: 'Não definido', + selectedTitle: 'Provedor selecionado', + selectedMessage: provider => `${provider} agora está ativo.`, + failedSelect: provider => `Falha ao selecionar ${provider}`, + failedLoad: 'Falha ao carregar configuração de ferramentas', + noProviderOptions: 'Este conjunto de ferramentas não tem opções de provedor — ative-o e funcionará com sua configuração atual.', + noProviders: 'Nenhum provedor disponível para este conjunto de ferramentas no momento.', + ready: 'Pronto', + needsSignIn: 'Precisa de login', + needsSetup: 'Configuração necessária', + activeBackend: 'Ativo', + activeBackendHint: 'Este é seu backend ativo', + useBackend: 'Usar este backend', + nousIncluded: 'Incluso com assinatura Nous — entre no Portal Nous para ativar.', + nousAuthNeededTitle: 'Entrar no Portal Nous', + nousAuthNeededMessage: provider => `${provider} está salvo, mas não será ativado até você entrar no Portal Nous.`, + nousAuthSignIn: 'Entrar', + nousAuthDoneTitle: 'Portal Nous conectado', + nousAuthDoneMessage: 'Seus backends de assinatura agora estão ativos.', + nousAuthFailed: 'O login no Portal Nous não foi concluído', + noApiKeyRequired: 'Nenhuma chave de API necessária.', + postSetupHint: step => + `Este backend precisa de uma instalação única (${step}). Executa nesta máquina — pode levar alguns minutos.`, + postSetupInstalledHint: 'Instalado. Execute a configuração novamente apenas se algo estiver quebrado.', + postSetupRun: 'Executar configuração', + postSetupRerun: 'Executar configuração novamente', + postSetupInstalled: 'Instalado', + postSetupRunning: 'Instalando…', + postSetupStarting: 'Iniciando…', + postSetupCompleteTitle: 'Configuração concluída', + postSetupCompleteMessage: step => `${step} instalado.`, + postSetupErrorTitle: 'Configuração concluída com erros', + postSetupErrorMessage: step => `Verifique o log de ${step}.`, + postSetupFailed: step => `Falha ao executar a configuração de ${step}`, + webSearchActive: backend => `Busca: ${backend}`, + webExtractActive: backend => `Extração: ${backend}`, + webCapabilityUnset: 'não definido', + webUseForSearch: 'Usar para busca', + webUseForExtract: 'Usar para extração', + webUsedForSearch: 'Backend de busca', + webUsedForExtract: 'Backend de extração', + webCapabilitySelectedMessage: (provider, capability) => `${provider} agora cuida da web ${capability}.`, + failedSelectCapability: provider => `Falha ao definir ${provider}`, + loadingModels: 'Carregando catálogo de modelos...', + modelSectionTitle: 'Modelo', + modelCount: count => `${count} modelo${count === 1 ? '' : 's'}`, + modelInUse: 'Em uso', + modelDefault: 'padrão', + modelInactiveHint: 'Selecione este backend primeiro para alterar seu modelo.', + modelSelectedTitle: 'Modelo selecionado', + modelSelectedMessage: model => `${model} aplica-se a novas sessões.`, + failedSelectModel: model => `Falha ao selecionar ${model}`, + terminalBackend: { + sectionTitle: 'Backend de execução', + loading: 'Verificando backends de execução…', + failedLoad: 'Não foi possível carregar backends de terminal', + ready: 'Pronto', + needsSetup: 'Precisa de configuração', + unavailable: 'Indisponível', + inUse: 'Em uso', + selectedTitle: 'Backend selecionado', + selectedMessage: backend => `Comandos de terminal agora executam via ${backend}. Aplica-se a novas sessões.`, + failedSelect: backend => `Falha ao selecionar ${backend}`, + needsSetupHint: 'Você pode selecionar este backend agora — os comandos falharão até a configuração ser concluída.' + } + } + }, + + onboarding: { + headerTitle: 'Vamos configurar o Hermes Agent para você', + headerDesc: 'Conecte um provedor de modelo para começar a conversar. A maioria das opções leva um clique.', + preparingInstall: 'O Hermes está finalizando a instalação. Isso geralmente leva menos de um minuto na primeira execução.', + starting: 'Iniciando o Hermes…', + lookingUpProviders: 'Procurando provedores...', + collapse: 'Recolher', + otherProviders: 'Outros provedores', + haveApiKey: 'Já tenho uma chave de API', + chooseLater: 'Escolherei um provedor depois', + recommended: 'Recomendado', + connected: 'Conectado', + featuredPitch: 'Uma assinatura, mais de 300 modelos de ponta — a forma recomendada de usar o Hermes', + fireworksPitch: 'API direta de modelos — modelos de ponta hospedados na Fireworks', + openRouterPitch: 'Uma chave, centenas de modelos — uma boa opção padrão', + apiKeyOptions: { + fireworks: { + short: 'API direta de modelos', + description: 'Acesso direto a modelos hospedados pela Fireworks AI.' + }, + openrouter: { + short: 'uma chave, muitos modelos', + description: 'Hospeda centenas de modelos com uma única chave. Bom padrão para novas instalações.' + }, + openai: { short: 'Modelos GPT', description: 'Acesso direto aos modelos da OpenAI.' }, + gemini: { short: 'Modelos Gemini', description: 'Acesso direto aos modelos do Google Gemini.' }, + xai: { short: 'Modelos Grok', description: 'Acesso direto aos modelos Grok da xAI.' }, + local: { + short: 'auto-hospedado', + description: 'Aponte o Hermes para um endpoint local ou auto-hospedado compatível com OpenAI (vLLM, llama.cpp, Ollama, etc).' + } + }, + backToSignIn: 'Voltar ao login', + getKey: 'Obter uma chave', + replaceCurrent: 'Substituir valor atual', + pasteApiKey: 'Colar chave de API', + localApiKeyPlaceholder: 'Chave de API (opcional — apenas se seu endpoint exigir uma)', + couldNotSave: 'Não foi possível salvar a credencial.', + connecting: 'Conectando', + update: 'Atualizar', + flowSubtitles: { + pkce: 'Abre seu navegador para entrar, depois continua aqui', + device_code: 'Abre uma página de verificação no seu navegador — o Hermes conecta automaticamente', + external: 'Entre uma vez no seu terminal, depois volte para conversar' + }, + startingSignIn: provider => `Iniciando login para ${provider}...`, + verifyingCode: provider => `Verificando seu código com ${provider}...`, + connectedProvider: provider => `${provider} conectado`, + connectedPicking: provider => `${provider} conectado. Escolhendo um modelo padrão...`, + signInFailed: 'Falha no login. Tente novamente.', + pickDifferentProvider: 'Escolher um provedor diferente', + signInWith: provider => `Entrar com ${provider}`, + openedBrowser: provider => `Abrimos ${provider} no seu navegador.`, + authorizeThere: 'Autorize o Hermes lá.', + copyAuthCode: 'Copie o código de autorização e cole abaixo.', + pasteAuthCode: 'Colar código de autorização', + reopenAuthPage: 'Reabrir página de autorização', + autoBrowser: provider => + `Abrimos ${provider} no seu navegador. Autorize o Hermes lá e você será conectado automaticamente — nada para copiar ou colar.`, + reopenSignInPage: 'Reabrir página de login', + waitingAuthorize: 'Aguardando você autorizar...', + externalPending: provider => + `${provider} faz login através de seu próprio CLI. Execute este comando em um terminal, depois volte e escolha "Já entrei":`, + signedIn: 'Já entrei', + deviceCodeOpened: provider => `Abrimos ${provider} no seu navegador. Digite este código lá:`, + reopenVerification: 'Reabrir página de verificação', + copy: 'Copiar', + defaultModel: 'Modelo padrão', + freeTier: 'Camada gratuita', + pro: 'Pro', + free: 'Gratuito', + price: (input, output) => `${input} entrada / ${output} saída por Mtok`, + change: 'Alterar', + startChatting: 'Começar', + docs: provider => `documentação de ${provider}` + }, + + preview: { + tab: 'Pré-visualização', + closeTab: label => `Fechar ${label}`, + closeOthers: 'Fechar outras', + closeToRight: 'Fechar à direita', + closeAll: 'Fechar todas', + closePane: 'Fechar painel de pré-visualização', + loading: 'Carregando pré-visualização', + unavailable: 'Pré-visualização indisponível', + opening: 'Abrindo...', + hide: 'Ocultar', + openPreview: 'Abrir pré-visualização', + openInBrowser: 'Abrir no navegador', + linkHint: '⌘/Ctrl-clique para painel de pré-visualização', + sourceLineTitle: 'Clique para selecionar · shift-clique para estender · arraste para o compositor', + source: 'FONTE', + renderedPreview: 'PRÉ-VISUALIZAÇÃO', + diff: 'DIFF', + unknownSize: 'tamanho desconhecido', + binaryTitle: 'Parece ser um arquivo binário', + binaryBody: label => `Pré-visualizar ${label} pode mostrar texto ilegível.`, + largeTitle: 'Este arquivo é grande', + largeBody: (label, size) => `${label} tem ${size}. O Hermes mostrará apenas os primeiros 512 KB.`, + previewAnyway: 'Pré-visualizar mesmo assim', + truncated: 'Mostrando os primeiros 512 KB.', + noInlineTitle: 'Sem pré-visualização inline', + noInlineBody: mimeType => `${mimeType || 'Este tipo de arquivo'} ainda pode ser anexado como contexto.`, + edit: 'Editar', + editing: 'Editando', + unsavedChanges: 'Alterações não salvas', + saveFailed: message => `Não foi possível salvar: ${message}`, + diskChangedTitle: 'Arquivo alterado no disco', + diskChangedBody: + 'Este arquivo foi alterado desde que você o abriu. Sobrescrever com sua versão, ou descartar suas edições e recarregar?', + overwrite: 'Sobrescrever', + discardReload: 'Descartar & recarregar', + console: { + deselect: 'Desselecionar entrada', + select: 'Selecionar entrada', + copyFailed: 'Não foi possível copiar a saída do console', + copyEntry: 'Copiar esta entrada', + sendEntry: 'Enviar esta entrada para o chat', + messages: count => `${count} mensagens de console`, + resize: 'Redimensionar console de pré-visualização', + title: 'Console de pré-visualização', + selected: count => `${count} selecionada${count === 1 ? '' : 's'}`, + sendToChat: 'Enviar para o chat', + copySelected: 'Copiar selecionadas para a área de transferência', + copyAll: 'Copiar tudo para a área de transferência', + copy: 'Copiar', + clear: 'Limpar', + empty: 'Nenhuma mensagem de console ainda.', + promptHeader: 'Console de pré-visualização:', + sentTitle: 'Enviado para o chat', + sentMessage: count => `${count} entrada${count === 1 ? ' de log' : 's de log'} adicionada${count === 1 ? '' : 's'} ao compositor` + }, + web: { + appFailedToBoot: 'App de pré-visualização falhou ao iniciar', + serverNotFound: 'Servidor não encontrado', + failedToLoad: 'Falha ao carregar pré-visualização', + tryAgain: 'Tentar novamente', + restarting: 'O Hermes está reiniciando...', + askRestart: 'Pedir ao Hermes para reiniciar o servidor', + lookingRestart: taskId => `O Hermes está procurando um servidor de pré-visualização para reiniciar (${taskId})`, + restartingTitle: 'Reiniciando servidor de pré-visualização', + restartingMessage: 'O Hermes está trabalhando em segundo plano. Acompanhe o console de pré-visualização para ver o progresso.', + startRestartFailed: message => `Não foi possível iniciar a reinicialização do servidor: ${message}`, + restartFailed: 'Falha na reinicialização do servidor', + hideConsole: 'Ocultar console de pré-visualização', + showConsole: 'Mostrar console de pré-visualização', + hideDevTools: 'Ocultar DevTools de pré-visualização', + openDevTools: 'Abrir DevTools de pré-visualização', + finishedRestarting: message => `O Hermes terminou de reiniciar o servidor de pré-visualização${message ? `: ${message}` : ''}`, + failedRestarting: message => `Falha na reinicialização do servidor: ${message}`, + unknownError: 'erro desconhecido', + restartedTitle: 'Servidor de pré-visualização reiniciado', + reloadingNow: 'Recarregando a pré-visualização agora.', + restartFailedTitle: 'Falha na reinicialização da pré-visualização', + restartFailedMessage: 'O Hermes não conseguiu reiniciar o servidor.', + stillWorking: + 'O Hermes ainda está trabalhando, mas nenhum resultado de reinicialização chegou ainda. O comando do servidor pode estar em execução em primeiro plano.', + workspaceReloading: 'Espaço de trabalho alterado, recarregando pré-visualização', + fileChanged: url => `Arquivo alterado, recarregando pré-visualização: ${url}`, + filesChanged: (count, url) => `${count} alterações de arquivo, recarregando pré-visualização: ${url}`, + watchFailed: message => `Não foi possível monitorar o arquivo de pré-visualização: ${message}`, + moduleMimeDescription: + 'Scripts de módulo estão sendo servidos com o tipo MIME errado. Isso geralmente significa que um servidor de arquivos estáticos está servindo um app Vite/React em vez do servidor de desenvolvimento do projeto.', + loadFailedConsole: (code, message) => `Falha ao carregar${code ? ` (${code})` : ''}: ${message}`, + unreachableDescription: 'A página de pré-visualização não pôde ser acessada.', + openTarget: url => `Abrir ${url}`, + fallbackTitle: 'Pré-visualização' + } + }, + + prompts: { + gatewayDisconnected: 'O gateway do Hermes não está conectado', + sudoSendFailed: 'Não foi possível enviar a senha de sudo', + secretSendFailed: 'Não foi possível enviar o segredo', + sudoTitle: 'Senha de administrador', + sudoDesc: 'O Hermes precisa da sua senha de sudo para executar um comando privilegiado. Ela é enviada apenas para seu agente local.', + sudoPlaceholder: 'senha de sudo', + secretTitle: 'Segredo necessário', + secretDesc: 'O Hermes precisa de uma credencial para continuar.', + secretPlaceholder: 'valor do segredo' + }, + + desktop: { + audioReadFailed: 'Não foi possível ler o áudio gravado', + sessionUnavailable: 'Sessão indisponível', + createSessionFailed: 'Não foi possível criar uma nova sessão', + promptFailed: 'Falha no prompt', + providerCredentialRequired: 'Adicione uma credencial de provedor antes de enviar sua primeira mensagem.', + emptySlashCommand: 'comando slash vazio', + desktopCommands: 'Comandos do desktop', + skillCommandsAvailable: count => `${count} comandos de skill disponíveis.`, + warningLine: message => `aviso: ${message}`, + yoloArmed: 'YOLO ativado para esta conversa', + yoloOff: 'YOLO desligado', + yoloSystem: active => `YOLO ${active ? 'ativado' : 'desligado'} para esta sessão`, + yoloTitle: 'YOLO', + yoloToggleFailed: 'Não foi possível alternar YOLO', + profileStatus: current => + `Perfil: ${current}. Use /profile ou o seletor de "Nova sessão" para iniciar um chat em outro perfil.`, + unknownProfile: 'Perfil desconhecido', + noProfileNamed: (target, available) => `Nenhum perfil chamado "${target}". Disponíveis: ${available}`, + newChatsProfile: name => `Novas conversas usarão o perfil ${name}.`, + setProfileFailed: 'Falha ao definir perfil', + sttDisabled: 'Speech-to-text está desativado nas configurações.', + stopFailed: 'Falha ao parar', + regenerateFailed: 'Falha ao regenerar', + editFailed: 'Falha ao editar', + resumeFailed: 'Falha ao retomar', + resumeStrandedTitle: 'Não foi possível carregar esta sessão', + resumeStrandedBody: + 'A conexão com esta sessão falhou e as tentativas automáticas de reenvio desistiram. Verifique se o gateway está em execução, depois tente novamente.', + resumeRetry: 'Tentar novamente', + nothingToBranch: 'Nada para ramificar', + branchNeedsChat: 'Inicie ou retome uma conversa antes de ramificar.', + sessionBusy: 'Sessão ocupada', + branchStopCurrent: 'Pare o turno atual antes de ramificar esta conversa.', + branchNoText: 'Esta mensagem não tem texto para ramificar.', + branchTitle: n => `Rascunho: Ramificação #${n}`, + branchFailed: 'Falha ao ramificar', + deleteFailed: 'Falha ao excluir', + archived: 'Arquivado', + archiveFailed: 'Falha ao arquivar', + cwdChangeFailed: 'Falha na alteração do diretório de trabalho', + cwdStagedTitle: 'Diretório de trabalho preparado', + cwdStagedMessage: 'Reinicie o backend do desktop para aplicar alterações de cwd a esta sessão ativa.', + modelSwitchFailed: 'Falha na troca de modelo', + sessionExported: 'Sessão exportada', + sessionExportFailed: 'Não foi possível exportar a sessão', + imageSaved: 'Imagem salva', + downloadStarted: 'Download iniciado', + restartToUseSaveImage: 'Reinicie o Hermes Desktop para usar Salvar Imagem.', + restartToSaveImages: 'Reinicie o Hermes Desktop para salvar imagens', + imageDownloadFailed: 'Falha no download da imagem', + openImage: 'Abrir imagem', + downloadImage: 'Baixar imagem', + savingImage: 'Salvando imagem', + imagePreviewFailed: 'Falha na pré-visualização da imagem', + imageAttach: 'Anexar imagem', + imageWriteFailed: 'Falha ao gravar imagem no disco.', + imageAttachFailed: 'Falha ao anexar imagem', + attachImages: 'Anexar imagens', + clipboard: 'Área de transferência', + noClipboardImage: 'Nenhuma imagem encontrada na área de transferência', + clipboardPasteFailed: 'Falha ao colar da área de transferência', + dropFiles: 'Solte arquivos', + handoff: { + pickPlatform: 'Escolha um destino', + success: platform => `Transferido para ${platform}. Retome aqui a qualquer momento.`, + systemNote: platform => `↻ Transferido para ${platform} — retome aqui a qualquer momento.`, + failed: error => `Falha na transferência: ${error}`, + timedOut: 'Tempo limite aguardando o gateway. O `hermes gateway` está em execução?' + } + }, +boot: { + ready: 'Hermes Desktop está pronto', + desktopBootFailedWithMessage: message => `Falha na inicialização do desktop: ${message}`, + steps: { + connectingGateway: 'Conectando ao gateway do desktop', + loadingSettings: 'Carregando configurações do Hermes', + loadingSessions: 'Carregando sessões recentes', + startingDesktopConnection: 'Iniciando conexão do desktop', + startingHermesDesktop: 'Iniciando Hermes Desktop…' + }, + errors: { + backgroundExited: 'O processo em segundo plano do Hermes foi encerrado.', + backgroundExitedDuringStartup: 'O processo em segundo plano do Hermes foi encerrado durante a inicialização.', + backendStopped: 'Backend interrompido', + desktopBootFailed: 'Falha na inicialização do desktop', + gatewayConnectionLost: 'Conexão com o gateway perdida', + gatewaySignInRequired: 'É necessário entrar no gateway', + ipcBridgeUnavailable: 'A ponte IPC do desktop está indisponível.' + }, + failure: { + title: "Hermes não pôde iniciar", + description: + "O gateway em segundo plano não subiu. Tente uma das etapas de recuperação abaixo. Nada aqui apaga seus chats ou configurações.", + remoteTitle: 'Entrar no gateway remoto é necessário', + remoteDescription: + 'Sua sessão no gateway remoto expirou. Entre novamente para reconectar. Nada aqui apaga seus chats ou configurações.', + retry: 'Tentar novamente', + repairInstall: 'Reparar instalação', + useLocalGateway: 'Usar gateway local', + gatewaySettings: 'Configurações do gateway', + back: 'Voltar', + openLogs: 'Abrir logs', + repairHint: 'Reparar reexecuta o instalador e pode levar alguns minutos em uma máquina nova.', + remoteSignInHint: signInLabel => + `Encerra a sessão remota salva do navegador e abre ${signInLabel}. Use o gateway local para alternar ao backend integrado.`, + signOutAndSignIn: 'Sair & entrar', + remoteFailureHint: 'Verifique a URL do gateway e o login em Configurações do gateway, ou alternar para o gateway local.', + hideRecentLogs: 'Ocultar logs recentes', + showRecentLogs: 'Mostrar logs recentes', + signedInTitle: 'Conectado', + signedInMessage: 'Reconectando ao gateway remoto…', + signInIncompleteTitle: 'Login incompleto', + signInIncompleteMessage: 'A janela de login foi fechada antes da autenticação terminar.', + signInFailed: 'Falha no login', + signInToRemoteGateway: 'Entrar no gateway remoto', + signInWithProvider: provider => `Entrar com ${provider}`, + identityProvider: 'seu provedor de identidade' + } + }, + + titlebar: { + hideSidebar: 'Ocultar barra lateral', + showSidebar: 'Mostrar barra lateral', + search: 'Buscar', + searchTitle: 'Buscar sessões, visões e ações', + swapSidebarSides: 'Trocar lados da barra lateral', + hideRightSidebar: 'Ocultar barra lateral direita', + showRightSidebar: 'Mostrar barra lateral direita', + muteHaptics: 'Silenciar háptica', + unmuteHaptics: 'Ativar háptica', + openSettings: 'Abrir configurações', + openStarmap: 'Abrir grafo de memória', + openKeybinds: 'Atalhos de teclado', + layoutEditor: 'Editor de layout', + layoutEditorTitle: 'Editor de layout — ⌘-clique reinicia o layout' + }, + + findInPage: { + next: 'Próxima ocorrência', + previous: 'Ocorrência anterior' + }, + + language: { + label: 'Idioma', + description: 'Escolha o idioma da interface do desktop.', + saving: 'Salvando idioma…', + saveError: 'Falha ao atualizar idioma', + switchTo: 'Trocar idioma', + searchPlaceholder: 'Buscar idiomas…', + noResults: 'Nenhum idioma encontrado' + }, + + skills: { + tabSkills: 'Skills', + tabToolsets: 'Ferramentas', + tabMcp: 'MCP', + tabHub: 'Explorar Hub', + all: 'Todas', + searchSkills: 'Buscar skills...', + searchToolsets: 'Buscar ferramentas...', + refresh: 'Atualizar skills', + refreshing: 'Atualizando skills', + loading: 'Carregando capacidades...', + noSkillsTitle: 'Nenhuma skill encontrada', + noSkillsDesc: 'Tente uma busca mais ampla ou uma categoria diferente.', + noToolsetsTitle: 'Nenhum conjunto de ferramentas encontrado', + noToolsetsDesc: 'Tente uma busca mais ampla.', + noDescription: 'Sem descrição.', + configured: 'Configurado', + needsKeys: 'Precisa de chaves', + visionModelHint: + 'A visão usa sua configuração de modelo auxiliar — o modelo com capacidade de imagem é escolhido lá, não por provedor aqui.', + visionModelLink: 'Escolher modelo de visão em Configurações → Modelos', + toolsetsEnabled: (enabled, total) => `${enabled}/${total} conjuntos de ferramentas ativados`, + configureToolset: label => `Configurar ${label}`, + toggleToolset: (label, enabled) => `${enabled ? 'Ativar' : 'Desativar'} conjunto de ferramentas ${label}`, + skillsLoadFailed: 'Falha ao carregar skills', + toolsetsRefreshFailed: 'Falha ao atualizar conjuntos de ferramentas', + skillEnabled: 'Skill ativada', + skillDisabled: 'Skill desativada', + toolsetEnabled: 'Conjunto de ferramentas ativado', + toolsetDisabled: 'Conjunto de ferramentas desativado', + appliesToNewSessions: name => `${name} se aplica a novas sessões.`, + failedToUpdate: name => `Falha ao atualizar ${name}`, + sortMostUsed: 'Mais usadas', + sortAlpha: 'A–Z', + sortMostUsedDesc: '↓ Mais usadas', + sortLeastUsedAsc: '↑ Menos usadas', + enableAll: 'Ativar todas', + disableAll: 'Desativar todas', + disableUnused: 'Desativar não usadas', + bulkUpdated: count => `${count === 1 ? 'item' : 'itens'} ${count} atualizado${count === 1 ? '' : 's'} para novas sessões.`, + bulkNoChange: 'Nada para alterar.', + usageCount: count => `usada ${count}×`, + provenance: { + agent: 'Aprendida', + bundled: 'Integrada', + hub: 'Hub' + }, + emptyNoneFound: noun => `Nenhum(a) ${noun} encontrado(a)`, + emptyNothingMatches: query => `Nada corresponde a "${query}".`, + emptyNoneAvailable: noun => `Nenhum(a) ${noun} disponível ainda.`, + changesApplyNewSessions: 'Alterações se aplicam a novas sessões.', + skillUpdated: 'Skill atualizada', + edit: 'Editar', + archive: 'Arquivar', + skillArchivedTitle: 'Skill arquivada', + skillArchivedMessage: 'Restaurável via hermes curator restore.', + hub: { + searchPlaceholder: 'Buscar no hub de skills', + search: 'Buscar', + searching: 'Buscando...', + connectingHubs: 'Conectando a hubs de skills...', + connectedHubs: 'Hubs conectados:', + featured: 'Skills em destaque', + landingHint: + 'Busque no hub para navegar por skills instaláveis do índice oficial, GitHub e fontes da comunidade.', + noResults: 'Nenhuma skill correspondente encontrada no hub.', + resultCount: (count, ms) => `${count} resultado${count === 1 ? '' : 's'}${ms !== null ? ` em ${ms}ms` : ''}`, + timedOut: sources => `Tempo esgotado: ${sources}`, + installed: 'Instalada', + install: 'Instalar', + installing: 'Instalando...', + uninstall: 'Desinstalar', + uninstalling: 'Desinstalando...', + updateAll: 'Atualizar instaladas', + updating: 'Atualizando...', + preview: 'Pré-visualizar', + scan: 'Escanear', + scanning: 'Escaneando...', + close: 'Fechar', + files: 'Arquivos', + noReadme: 'Esta skill não tem pré-visualização de SKILL.md.', + trust: { + builtin: 'integrada', + trusted: 'confiável', + community: 'comunidade' + }, + verdictSafe: 'Segura', + verdictCaution: 'Cautela', + verdictDangerous: 'Perigosa', + policyAllow: 'Instalação permitida', + policyAsk: 'Revisar antes de instalar', + policyBlock: 'Instalação bloqueada por política', + findings: count => `${count} achado${count === 1 ? '' : 's'}`, + noFindings: 'Nenhum achado de segurança.', + installStarted: name => `Instalando ${name}...`, + uninstallStarted: name => `Desinstalando ${name}...`, + updateStarted: 'Atualizando skills instaladas...', + actionFailed: 'Falha na ação da skill', + actionLog: 'Log da ação', + loadFailed: 'Falha ao carregar o hub de skills', + previewFailed: 'Falha na pré-visualização da skill', + scanFailed: 'Falha no escaneamento de segurança', + searchFailed: 'Falha na busca no hub' + } + }, + + agents: { + close: 'Fechar agentes', + title: 'Árvore de spawn', + subtitle: 'Atividade de subagentes em tempo real para o turno atual.', + emptyTitle: 'Nenhum subagente ativo', + emptyDesc: 'Quando um turno delega trabalho, agentes filhos transmitem seu progresso aqui.', + running: 'Executando', + failed: 'Falhou', + done: 'Concluído', + streaming: 'Transmitindo', + files: 'Arquivos', + moreFiles: count => `+${count} arquivos a mais`, + delegation: index => `Delegação ${index}`, + workers: count => `${count} workers`, + workersActive: count => `${count} ativos`, + agentsCount: count => `${count} ${count === 1 ? 'agente' : 'agentes'}`, + activeCount: count => `${count} ativos`, + failedCount: count => `${count} falharam`, + toolsCount: count => `${count} ferramentas`, + filesCount: count => `${count} arquivos`, + updatedAgo: age => `atualizado ${age}`, + ageNow: 'agora', + ageSeconds: seconds => `${seconds}s atrás`, + ageMinutes: minutes => `${minutes}m atrás`, + ageHours: hours => `${hours}h atrás`, + ageDays: days => `${days}d atrás`, + durationSeconds: seconds => `${seconds}s`, + durationMinutes: (minutes, seconds) => `${minutes}m ${seconds}s`, + tokens: value => `${value} tok` + }, + + messaging: { + search: 'Buscar plataformas...', + loading: 'Carregando plataformas de mensageria...', + loadFailed: 'Falha ao carregar plataformas de mensageria', + states: { + connected: 'Conectado', + connecting: 'Conectando', + disabled: 'Desativado', + fatal: 'Erro', + gateway_stopped: 'Gateway de mensageria parado', + not_configured: 'Precisa de configuração', + pending_restart: 'Reinício necessário', + retrying: 'Tentando novamente', + startup_failed: 'Falha na inicialização' + }, + unknown: 'Desconhecido', + hintPendingRestart: 'Reinicie o gateway pela barra de status para aplicar esta alteração.', + hintGatewayStopped: 'Inicie o gateway pela barra de status para conectar.', + credentialsSet: 'Credenciais definidas', + needsSetup: 'Precisa de configuração', + gatewayStopped: 'Gateway de mensageria parado', + getCredentials: 'Obter suas credenciais', + openSetupGuide: 'Abrir guia de configuração', + required: 'Obrigatório', + recommended: 'Recomendado', + advanced: count => `Avançado (${count})`, + noTokenNeeded: 'Esta plataforma não precisa de token aqui. Use o guia de configuração acima, depois ative-a abaixo.', + enabled: 'Ativado', + disabled: 'Desativado', + unsavedChanges: 'Alterações não salvas', + saving: 'Salvando...', + saveChanges: 'Salvar alterações', + saved: 'Salvo', + replaceValue: 'Substituir valor atual', + openDocs: 'Abrir documentação', + clearField: key => `Limpar ${key}`, + enableAria: name => `Ativar ${name}`, + disableAria: name => `Desativar ${name}`, + platformEnabled: name => `${name} ativado`, + platformDisabled: name => `${name} desativado`, + restartToApply: 'Esta alteração entra em vigor após reiniciar o gateway.', + setupSaved: name => `Configuração de ${name} salva`, + restartToReconnect: 'Novas credenciais entram em vigor após reiniciar o gateway.', + keyCleared: key => `${key} limpo`, + setupUpdated: name => `Configuração de ${name} foi atualizada.`, + failedUpdate: name => `Falha ao atualizar ${name}`, + failedSave: name => `Falha ao salvar ${name}`, + failedClear: key => `Falha ao limpar ${key}`, + pendingRequests: count => `Solicitações pendentes (${count})`, + pendingAria: count => `${count} ${count === 1 ? 'solicitação de pareamento pendente' : 'solicitações de pareamento pendentes'}`, + approvedUsers: count => `Usuários aprovados (${count})`, + approve: 'Aprovar', + approving: 'Aprovando...', + revoke: 'Revogar', + revoking: 'Revogando...', + revokeAria: name => `Revogar ${name}`, + revokeTitle: 'Revogar acesso', + revokeDesc: (name: string) => `${name} perderá acesso e não será mais reconhecido na próxima mensagem.`, + approvedUser: name => `${name} aprovado`, + approvedHint: 'Reconhecido automaticamente na próxima mensagem.', + revokedUser: name => `${name} revogado`, + failedApprove: name => `Falha ao aprovar ${name}`, + failedRevoke: name => `Falha ao revogar ${name}`, + pairingLockedOut: 'Muitas aprovações falhadas — esta plataforma foi bloqueada. Tente novamente mais tarde.', + waitingSince: minutes => (minutes < 1 ? 'agora mesmo' : `${minutes}m atrás`), + fieldCopy: { + TELEGRAM_BOT_TOKEN: { + label: 'Token do bot', + help: 'Crie um bot com o @BotFather e cole o token fornecido.', + placeholder: 'Cole o token do bot do Telegram' + }, + TELEGRAM_ALLOWED_USERS: { + label: 'IDs de usuários do Telegram permitidos', + help: 'Recomendado. IDs numéricos separados por vírgula do @userinfobot. Sem isso, qualquer pessoa pode enviar mensagens ao seu bot.' + }, + TELEGRAM_PROXY: { label: 'URL do proxy', help: 'Necessário apenas em redes onde o Telegram é bloqueado.' }, + DISCORD_BOT_TOKEN: { + label: 'Token do bot', + help: 'Crie uma aplicação no Discord Developer Portal, adicione um bot e cole seu token.' + }, + DISCORD_ALLOWED_USERS: { + label: 'IDs de usuários do Discord permitidos', + help: 'Recomendado. IDs de usuários do Discord separados por vírgula.' + }, + DISCORD_REPLY_TO_MODE: { label: 'Estilo de resposta', help: 'first, all ou off.' }, + DISCORD_ALLOW_ALL_USERS: { + label: 'Permitir todos os usuários do Discord', + help: 'Apenas para desenvolvimento. Quando ativo, qualquer pessoa pode enviar mensagens ao bot sem uma lista de permitidos.' + }, + DISCORD_HOME_CHANNEL: { + label: 'ID do canal principal', + help: 'Canal onde o bot envia mensagens proativas (saída de cron, lembretes).' + }, + DISCORD_HOME_CHANNEL_NAME: { + label: 'Nome do canal principal', + help: 'Nome de exibição do canal principal em logs e saída de status.' + }, + BLUEBUBBLES_ALLOW_ALL_USERS: { + label: 'Permitir todos os usuários do iMessage', + help: 'Quando ativo, ignora a lista de permitidos do BlueBubbles.' + }, + MATTERMOST_ALLOW_ALL_USERS: { label: 'Permitir todos os usuários do Mattermost' }, + MATTERMOST_HOME_CHANNEL: { label: 'Canal principal' }, + QQ_ALLOW_ALL_USERS: { label: 'Permitir todos os usuários do QQ' }, + QQBOT_HOME_CHANNEL: { label: 'Canal principal do QQ', help: 'Canal ou grupo padrão para entrega de cron.' }, + QQBOT_HOME_CHANNEL_NAME: { label: 'Nome do canal principal do QQ' }, + SLACK_BOT_TOKEN: { + label: 'Token do bot do Slack', + help: 'Use o token do bot em OAuth & Permissions após instalar seu app do Slack.', + placeholder: 'Cole o token do bot do Slack' + }, + SLACK_APP_TOKEN: { + label: 'Token do app do Slack', + help: 'Use o token de nível de aplicativo necessário para o Socket Mode.', + placeholder: 'Cole o token do app do Slack' + }, + SLACK_ALLOWED_USERS: { label: 'IDs de usuários do Slack permitidos', help: 'Recomendado. IDs de usuários do Slack separados por vírgula.' }, + MATTERMOST_URL: { label: 'URL do servidor', placeholder: 'https://mattermost.exemplo.com' }, + MATTERMOST_TOKEN: { label: 'Token do bot' }, + MATTERMOST_ALLOWED_USERS: { + label: 'IDs de usuários permitidos', + help: 'Recomendado. IDs de usuários do Mattermost separados por vírgula.' + }, + MATRIX_HOMESERVER: { label: 'URL do homeserver', placeholder: 'https://matrix.org' }, + MATRIX_ACCESS_TOKEN: { label: 'Token de acesso' }, + MATRIX_USER_ID: { label: 'ID de usuário do bot', placeholder: '@hermes:exemplo.org' }, + MATRIX_ALLOWED_USERS: { + label: 'IDs de usuários do Matrix permitidos', + help: 'Recomendado. IDs de usuários separados por vírgula no formato @usuario:servidor.' + }, + SIGNAL_HTTP_URL: { + label: 'URL da ponte Signal', + placeholder: 'http://127.0.0.1:8080', + help: 'URL de uma ponte REST signal-cli em execução.' + }, + SIGNAL_ACCOUNT: { label: 'Número de telefone', help: 'O número registrado na sua ponte signal-cli.' }, + SIGNAL_ALLOWED_USERS: { label: 'Usuários do Signal permitidos', help: 'Recomendado. Identificadores do Signal separados por vírgula.' }, + WHATSAPP_ENABLED: { + label: 'Ativar ponte do WhatsApp', + help: 'Definido automaticamente pelo alternador abaixo. Deixe como está, a menos que saiba que precisa alterar.' + }, + WHATSAPP_MODE: { label: 'Modo da ponte' }, + WHATSAPP_ALLOWED_USERS: { + label: 'Usuários do WhatsApp permitidos', + help: 'Recomendado. Números de telefone ou IDs do WhatsApp separados por vírgula.' + } + }, + platformIntro: {} + }, + + webhooks: { + search: 'Buscar webhooks...', + loading: 'Carregando webhooks...', + loadFailed: 'Falha ao carregar webhooks', + subscriptions: (count: number) => `Inscrições (${count})`, + hint: 'Alterações de inscrição recarregam em tempo real quando o receptor está em execução. Inscrições desativadas rejeitam eventos recebidos.', + empty: 'Nenhuma inscrição de webhook ainda.', + disabledTitle: 'Receptor de webhook desativado', + disabledBody: + 'Webhooks são uma plataforma de gateway própria. Ative-os aqui para aceitar eventos HTTP recebidos; canais de chat são necessários apenas quando uma inscrição entrega no Telegram, Discord, Slack ou outro canal.', + enable: 'Ativar webhooks', + enabling: 'Ativando...', + enabled: (name: string) => `Ativado: "${name}"`, + disabled: (name: string) => `Desativado: "${name}"`, + enableRow: 'Ativar', + disableRow: 'Desativar', + delete: 'Excluir', + deleting: 'Excluindo...', + deleted: 'Webhook excluído', + deleteTitle: 'Excluir webhook', + deleteDescPrefix: 'Isso removerá permanentemente ', + deleteDescSuffix: '. Isso não pode ser desfeito.', + deleteFailed: (name: string) => `Falha ao excluir "${name}"`, + toggleFailed: (name, enabled) => `Falha ao ${enabled ? 'ativar' : 'desativar'} "${name}"`, + newSubscription: 'Nova inscrição', + restarting: 'Reiniciando gateway...', + restartNeeded: 'Webhooks estão ativados, mas o gateway ainda precisa de um reinício antes que o receptor fique online.', + restartGateway: 'Reiniciar gateway', + restartingGateway: 'Reiniciando...', + restartFailed: (detail: string) => `Falha ao reiniciar o gateway${detail}`, + enabledRestarting: 'Webhooks ativados; gateway reiniciando...', + all: '(todos)', + deliverOnly: 'apenas entregar', + createdTitle: 'Inscrição criada', + createdSecretHint: 'Copie o segredo agora — ele é exibido apenas uma vez.', + webhookUrl: 'URL do webhook', + secretOnce: 'Segredo (exibido uma vez)', + done: 'Concluído', + fieldName: 'Nome', + fieldNamePlaceholder: 'ex. github-push', + fieldDescription: 'Descrição', + fieldDescriptionPlaceholder: 'O que este webhook faz (opcional)', + fieldEvents: 'Eventos', + fieldEventsPlaceholder: 'separados por vírgula, deixe vazio para todos', + fieldSkills: 'Skills', + fieldSkillsPlaceholder: 'nomes de skills separados por vírgula (opcional)', + fieldDeliver: 'Entregar para', + fieldDeliverOnly: 'Entregar apenas o payload', + fieldPrompt: 'Prompt', + fieldPromptPlaceholder: 'Instruções para o agente quando este webhook disparar (opcional)', + nameRequired: 'Nome obrigatório', + create: 'Criar', + creating: 'Criando...', + created: 'Criado', + createFailed: (detail: string) => `Falha ao criar: ${detail}`, + copy: 'Copiar', + deliverOptions: { + log: 'Log', + telegram: 'Telegram', + discord: 'Discord', + slack: 'Slack', + email: 'E-mail', + github_comment: 'Comentário no GitHub' + } + }, + + cron: { + close: 'Fechar cron', + title: 'Tarefas agendadas', + count: count => `${count} ${count === 1 ? 'tarefa' : 'tarefas'}`, + search: 'Buscar tarefas cron...', + loading: 'Carregando tarefas cron...', + states: { + enabled: 'ativado', + scheduled: 'agendado', + running: 'executando', + paused: 'pausado', + disabled: 'desativado', + error: 'erro', + completed: 'concluído' + }, + deliveryLabels: { + local: 'Este desktop', + telegram: 'Telegram', + discord: 'Discord', + slack: 'Slack', + email: 'E-mail' + }, + scheduleLabels: { + daily: 'Diariamente', + weekdays: 'Dias úteis', + weekly: 'Semanalmente', + monthly: 'Mensalmente', + hourly: 'A cada hora', + 'every-15-minutes': 'A cada 15 minutos', + custom: 'Personalizado' + }, + scheduleHints: { + daily: 'Todos os dias às 9:00', + weekdays: 'Segunda a sexta às 9:00', + weekly: 'Toda segunda-feira às 9:00', + monthly: 'No primeiro dia de cada mês às 9:00', + hourly: 'No início de cada hora', + 'every-15-minutes': 'A cada 15 minutos', + custom: 'Sintaxe cron ou linguagem natural' + }, + days: { + '0': 'Domingo', + '1': 'Segunda-feira', + '2': 'Terça-feira', + '3': 'Quarta-feira', + '4': 'Quinta-feira', + '5': 'Sexta-feira', + '6': 'Sábado', + '7': 'Domingo' + }, + dayFallback: value => `dia ${value}`, + everyDayAt: time => `Todos os dias às ${time}`, + weekdaysAt: time => `Dias úteis às ${time}`, + everyDayOfWeekAt: (day, time) => `Todo(a) ${day} às ${time}`, + monthlyOnDayAt: (dayOfMonth, time) => `Mensalmente no dia ${dayOfMonth} às ${time}`, + topOfHour: 'No início de cada hora', + everyHourAt: minute => `A cada hora no minuto :${minute}`, + newCron: 'Novo cron', + emptyDescNew: + 'Agende um prompt para executar em uma expressão cron. O Hermes vai executá-lo e entregar os resultados ao destino escolhido.', + emptyDescSearch: 'Tente uma busca mais ampla.', + emptyTitleNew: 'Nenhuma tarefa agendada ainda', + emptyTitleSearch: 'Nenhum resultado', + last: 'Última:', + next: 'Próxima:', + noRuns: 'Nenhuma execução ainda', + manage: 'Gerenciar', + showRuns: 'Mostrar execuções', + hideRuns: 'Ocultar execuções', + runHistory: 'Histórico de execuções', + actionsTitle: 'Ações da tarefa cron', + resume: 'Retomar cron', + pause: 'Pausar cron', + resumeTitle: 'Retomar', + pauseTitle: 'Pausar', + triggerNow: 'Disparar agora', + edit: 'Editar cron', + deleteTitle: 'Excluir tarefa cron?', + deleteDescPrefix: 'Isso removerá ', + deleteDescSuffix: ' permanentemente. Ele parará de disparar imediatamente.', + deleting: 'Excluindo...', + resumed: 'Cron retomado', + paused: 'Cron pausado', + triggered: 'Cron disparado', + deleted: 'Cron excluído', + created: 'Cron criado', + updated: 'Cron atualizado', + failedLoad: 'Falha ao carregar tarefas cron', + failedUpdate: 'Falha ao atualizar tarefa cron', + failedTrigger: 'Falha ao disparar tarefa cron', + failedDelete: 'Falha ao excluir tarefa cron', + failedSave: 'Falha ao salvar tarefa cron', + editTitle: 'Editar tarefa cron', + createTitle: 'Nova tarefa cron', + editDesc: 'Atualize o agendamento, prompt ou destino de entrega. As alterações se aplicam na próxima execução.', + createDesc: 'Agende um prompt para executar automaticamente. Use sintaxe cron ou uma frase natural como "a cada 15 minutos".', + nameLabel: 'Nome', + namePlaceholder: 'Resumo matinal', + promptLabel: 'Prompt', + promptPlaceholder: 'Resumir meus tópicos não lidos do Slack e enviar por e-mail os 5 principais...', + frequencyLabel: 'Frequência', + deliverLabel: 'Entregar para', + deliverNeedsHomeChannel: 'defina um canal principal primeiro', + modelLabel: 'Modelo', + modelDefault: 'Padrão (modelo global)', + customScheduleLabel: 'Agendamento personalizado', + customPlaceholder: '0 9 * * * ou dias úteis às 9h', + customHint: 'Expressão cron ou frases como "a cada hora" ou "dias úteis às 9h".', + optional: 'Opcional', + promptRequired: 'Prompt é obrigatório.', + promptScheduleRequired: 'Prompt e agendamento são obrigatórios.', + scheduleRequired: 'Agendamento é obrigatório.', + scriptOnlyEditHint: 'Tarefa apenas de script (sem prompt de IA). ID da tarefa:', + saveChanges: 'Salvar alterações', + createAction: 'Criar cron', + tabs: { + jobs: 'Tarefas', + blueprints: 'Modelos' + }, + blueprints: { + tab: 'Modelos', + startFrom: 'Começar com', + custom: 'Personalizado', + subtitle: 'Automações prontas', + dialogDesc: 'Preencha os detalhes e agende.', + scheduleIt: 'Agendar', + scheduling: 'Agendando...', + scheduled: 'Modelo agendado', + loading: 'Carregando modelos...', + failedLoad: 'Falha ao carregar modelos', + emptyTitle: 'Nenhum modelo disponível', + emptyDesc: 'Nenhum modelo de automação disponível neste backend.' + } + }, + + composer: { + message: 'Mensagem', + wakingProfile: profile => `Acordando ${profile}…`, + placeholderStarting: 'Iniciando Hermes...', + placeholderReconnecting: 'Reconectando ao Hermes…', + placeholderFollowUp: 'Enviar acompanhamento', + newSessionPlaceholders: [ + 'O que vamos construir?', + 'Dê uma tarefa ao Hermes', + 'O que você tem em mente?', + 'Descreva o que você precisa', + 'O que vamos resolver?', + 'Pergunte qualquer coisa', + 'Comece com um objetivo' + ], + followUpPlaceholders: [ + 'Enviar um acompanhamento', + 'Adicionar mais contexto', + 'Refinar o pedido', + 'O que vem a seguir?', + 'Continuar a conversa', + 'Ir além', + 'Ajustar ou continuar' + ], + startVoice: 'Iniciar conversa por voz', + openDirective: 'Abrir', + queueMessage: 'Enfileirar mensagem', + steer: 'Direcionar a execução atual', + stop: 'Parar', + send: 'Enviar', + speaking: 'Falando', + transcribing: 'Transcrevendo', + thinking: 'Pensando', + muted: 'Silenciado', + listening: 'Ouvindo', + muteMic: 'Silenciar microfone', + unmuteMic: 'Ativar microfone', + stopListening: 'Parar de ouvir e enviar', + stopShort: 'Parar', + endConversation: 'Encerrar conversa por voz', + endShort: 'Encerrar', + stopDictation: 'Parar ditado', + transcribingDictation: 'Transcrevendo ditado', + voiceDictation: 'Dictado por voz', + speakReplies: 'Ler respostas em voz alta', + stopSpeakingReplies: 'Parar de ler respostas em voz alta', + wakeWordListening: phrase => `Palavra de ativação: "${phrase}" — ouvindo`, + wakeWordOff: phrase => `Palavra de ativação: "${phrase}" — desativada`, + wakeWordPausedVoice: phrase => `Palavra de ativação: "${phrase}" — pausada durante conversa por voz`, + lookupLoading: 'Buscando…', + lookupNoMatches: 'Nenhum resultado.', + lookupTry: 'Tente', + lookupOr: 'ou', + commonCommands: 'Comandos comuns', + hotkeys: 'Atalhos', + helpFooter: 'abre o painel completo · backspace fecha', + commandDescs: { + '/help': 'lista completa de comandos + atalhos', + '/clear': 'iniciar uma nova sessão', + '/resume': 'retomar uma sessão anterior', + '/details': 'controlar o nível de detalhe da transcrição', + '/copy': 'copiar seleção ou última mensagem do assistente', + '/quit': 'sair do hermes' + }, + hotkeyDescs: { + 'composer.mention': 'referenciar arquivos, pastas, urls, git', + 'composer.slash': 'paleta de comandos slash', + 'composer.help': 'ajuda rápida (delete para fechar)', + 'composer.sendNewline': 'enviar · Shift+Enter para nova linha', + 'composer.sendQueued': 'enviar próximo turno enfileirado', + 'keybinds.openPanel': 'todos os atalhos de teclado', + 'composer.cancel': 'fechar popover · cancelar execução', + 'composer.history': 'alternar popover / histórico' + }, + attachUrlTitle: 'Anexar uma URL', + attachUrlDesc: 'O Hermes vai buscar a página e incluí-la como contexto para este turno.', + urlPlaceholder: 'https://exemplo.com/post', + urlHintPre: 'Inclua a URL completa, ex. ', + attach: 'Anexar', + queued: count => `${count} na fila`, + queuedPaused: count => `${count} na fila — pausado`, + attachmentOnly: 'Turno apenas com anexo', + emptyTurn: 'Turno vazio', + attachments: count => `${count} anexo${count === 1 ? '' : 's'}`, + editingInComposer: 'Editando no compositor', + editingQueuedInComposer: 'Editando turno enfileirado no compositor', + queueEdit: 'Editar', + queueSendNext: 'Próximo', + queueSend: 'Enviar', + queueDelete: 'Excluir', + queueResume: 'Retomar', + queueResumeTip: 'Pausado por Parar — retome o envio dos turnos enfileirados', + queueStuckTitle: 'Mensagem enfileirada não enviada', + queueStuckBody: 'Um turno enfileirado continuou falhando ao enviar. Ele ainda está na fila — tente enviá-lo novamente.', + previewUnavailable: 'Pré-visualização indisponível', + previewLabel: label => `Pré-visualizar ${label}`, + couldNotPreview: label => `Não foi possível pré-visualizar ${label}`, + removeAttachment: label => `Remover ${label}`, + dictating: 'Ditando', + preparingAudio: 'Preparando áudio', + speakingResponse: 'Falando resposta', + readingAloud: 'Lendo em voz alta', + themeSuggestions: 'Sugestões de tema do desktop', + noMatchingThemes: 'Nenhum tema correspondente.', + themeTryPre: 'Tente ', + themeTryPost: '.', + attachLabel: 'Anexar', + files: 'Arquivos…', + folder: 'Pasta…', + images: 'Imagens…', + pasteImage: 'Colar imagem', + url: 'URL…', + promptSnippets: 'Trechos de prompt…', + tipPre: 'Dica: digite ', + tipPost: ' para referenciar arquivos inline.', + snippetsTitle: 'Trechos de prompt', + snippetsDesc: 'Escolha um prompt inicial para inserir no compositor.', + dropFiles: 'Solte arquivos para anexar', + dropSession: 'Solte para vincular este chat', + snippets: { + codeReview: { + label: 'Revisão de código', + description: 'Auditar a alteração atual por regressões, casos extremos perdidos e testes faltantes.', + text: 'Revise isto por bugs, regressões e testes faltantes.' + }, + implementationPlan: { + label: 'Plano de implementação', + description: 'Esboçar uma abordagem antes de modificar o código para manter o diff focado.', + text: 'Faça um plano de implementação conciso antes de alterar o código.' + }, + explainThis: { + label: 'Explicar isto', + description: 'Passar por como o código selecionado funciona e indicar os arquivos principais.', + text: 'Explique como isso funciona e me indique os arquivos principais.' + } + } + }, + + install: { + stageStates: { + pending: 'Pendente', + running: 'Instalando', + succeeded: 'Concluído', + skipped: 'Pulado', + failed: 'Falhou' + }, + oneTimeTitle: 'O Hermes precisa de uma instalação única', + unsupportedDesc: platform => + `A instalação automática no primeiro lançamento não está disponível em ${platform} ainda. Abra o Terminal e execute o comando abaixo, depois reabra este app. Os próximos lançamentos pularão esta etapa.`, + installCommand: 'Comando de instalação', + copyCommand: 'Copiar comando', + viewDocs: 'Ver documentação de instalação', + installTo: 'Será instalado em', + retryAfterRun: 'Já executei -- tentar novamente', + setupChoiceTitle: 'Configurar Hermes Desktop', + setupChoiceDesc: + 'Conecte este app a um gateway do Hermes que você já executa, ou instale o Hermes localmente neste computador.', + connectExistingTitle: 'Conectar a Hermes existente', + connectExistingShort: 'Conectar existente', + connectExistingDesc: 'Use um backend remoto com um token de sessão ou login pelo navegador. Nenhuma instalação local será iniciada.', + installLocalTitle: 'Instalar Hermes localmente', + installLocalDesc: 'Baixar o Hermes, criar seu ambiente Python e executar o backend neste computador.', + localStartUnavailable: 'A instalação local não pôde iniciar. Reinicie o Hermes Desktop e tente novamente.', + remoteSetupTitle: 'Conectar a Hermes existente', + remoteSetupDesc: 'Digite a URL do seu gateway. O Hermes Desktop detectará se precisa de token ou login pelo navegador.', + remoteUrlTitle: 'URL do gateway', + remoteUrlDesc: 'Use a URL base do gateway do Hermes, incluindo https:// quando remoto.', + remoteUrlPlaceholder: 'https://gateway.exemplo.com/hermes', + probing: 'Detectando autenticação do gateway...', + probeError: 'Não foi possível alcançar esse gateway do Hermes.', + identityProvider: 'seu provedor de identidade', + authTitle: 'Autenticação', + authNeedsOauth: provider => `Entre com ${provider} antes de testar este gateway.`, + authSignedIn: 'Login pelo navegador concluído.', + connected: 'Conectado', + signIn: 'Entrar', + signInWith: provider => `Entrar com ${provider}`, + enterUrlFirst: 'Digite uma URL de gateway primeiro.', + signInIncomplete: 'A janela de login fechou antes da autenticação ser concluída.', + tokenTitle: 'Token de sessão', + tokenDesc: 'Cole o token de sessão do arquivo .env do gateway remoto.', + pasteSessionToken: 'Cole o token de sessão', + incompleteSignInTest: 'Entre antes de testar este gateway com OAuth.', + incompleteTokenTest: 'Digite um token de sessão antes de testar este gateway.', + testConnection: 'Testar conexão', + testSucceeded: (baseUrl, version) => `Conectado a ${baseUrl}${version ? ` (${version})` : ''}.`, + applyRemote: 'Aplicar e reconectar', + backToSetup: 'Voltar', + failedTitle: 'Falha na instalação', + settingUpTitle: 'Configurando Hermes Agent', + finishingTitle: 'Finalizando', + failedDesc: + 'Uma das etapas de instalação falhou. No Windows, isso pode acontecer se outra instância do Hermes CLI ou desktop estiver em execução. Encerre quaisquer instâncias do Hermes em execução e tente novamente. Confira os detalhes abaixo ou o log do desktop para a transcrição completa.', + activeDesc: + 'Esta é uma configuração única. O instalador do Hermes está baixando dependências e configurando sua máquina. Os próximos lançamentos pularão esta etapa.', + progress: (completed, total) => `${completed} de ${total} etapas concluídas`, + currentStage: stage => ` -- agora: ${stage}`, + fetchingManifest: 'Buscando manifesto do instalador...', + error: 'Erro', + hideOutput: 'Ocultar saída do instalador', + showOutput: 'Mostrar saída do instalador', + lines: count => `${count} linha${count === 1 ? '' : 's'}`, + noOutput: 'Nenhuma saída ainda.', + cancelling: 'Cancelando...', + cancelInstall: 'Cancelar instalação', + transcriptSaved: 'Transcrição completa salva em', + copiedOutput: 'Copiado!', + copyOutput: 'Copiar saída', + reloadRetry: 'Recarregar e tentar novamente' + }, + + modelVisibility: { + title: 'Modelos', + search: 'Buscar modelos', + noAuthenticatedProviders: 'Nenhum provedor autenticado.', + addProvider: 'Adicionar provedor…' + }, + + rightSidebar: { + aria: 'Barra lateral direita', + panelsAria: 'Painéis da barra lateral direita', + files: 'Sistema de arquivos', + terminal: 'Terminal', + noFolderSelected: 'Nenhuma pasta selecionada', + changeCwdTitle: 'Alterar diretório de trabalho', + remotePickerTitle: 'Escolher pasta remota', + remotePickerDescription: 'Navegue pelas pastas no backend conectado.', + remotePickerSelect: 'Selecionar pasta', + folderTip: cwd => cwd, + openFolder: 'Abrir pasta', + refreshTree: 'Atualizar árvore', + collapseAll: 'Recolher todas as pastas', + previewUnavailable: 'Pré-visualização indisponível', + couldNotPreview: path => `Não foi possível pré-visualizar ${path}`, + noProjectTitle: 'Nenhum projeto', + noProjectBody: 'Abra um projeto para navegar pelos seus arquivos e revisar alterações.', + noProjectOpen: 'Nenhum projeto aberto', + noDiffs: 'Sem diffs', + unreadableTitle: 'Ilegível', + unreadableBody: error => `Não foi possível ler esta pasta (${error}).`, + emptyTitle: 'Vazio', + emptyBody: 'Esta pasta está vazia.', + treeErrorTitle: 'Erro na árvore', + treeErrorBody: 'A árvore de arquivos encontrou um erro ao renderizar esta pasta.', + tryAgain: 'Tentar novamente', + loadingTree: 'Carregando árvore de arquivos', + loadingFiles: 'Carregando arquivos', + terminalHide: 'Ocultar terminal', + terminalsAria: 'Terminais', + terminalNew: 'Novo terminal', + terminalCloseOthers: 'Fechar outros', + terminalCloseAll: 'Fechar todos', + addToChat: 'Adicionar ao chat' + }, + + zones: { + showHeader: 'Mostrar cabeçalho', + hideHeader: 'Ocultar cabeçalho', + minimize: 'Minimizar', + restore: 'Restaurar', + closeRunningTitle: 'Fechar aba em execução?', + closeRunningBody: + 'Este chat ainda está trabalhando (ou aguardando seu input). Fechar a aba o oculta — a sessão mantém seu progresso e pode ser reaberta pela barra lateral.', + closeRunningConfirm: 'Fechar aba', + closeOthers: 'Fechar outras', + closeToRight: 'Fechar à direita', + closeAll: 'Fechar todas', + newSessionTab: 'Nova aba de sessão', + pluginDisabled: pluginId => `Plugin "${pluginId}" desativado`, + pluginDisabledBody: 'Reative-o em Configurações → Plugins para trazer o painel de volta.', + missingPane: paneId => `painel ausente: ${paneId}`, + editTitle: 'Layouts', + editHint: 'Escolha um layout ou arraste painéis entre zonas.', + reset: 'Redefinir', + templates: 'Modelos', + custom: 'Personalizado', + newGridLayout: 'Novo layout em grade', + saveCurrentAs: 'Salvar arranjo atual como modelo', + nameLayoutPlaceholder: 'Nomeie este layout…', + deletePreset: name => `Excluir ${name}`, + zoneEditorTitle: 'Editor de zonas', + editorHintPre: 'clique para dividir · ', + editorHintPost: ' inverte a linha · arraste entre zonas para mesclar · arraste bordas compartilhadas para redimensionar', + templateColumns: 'Colunas', + templateRows: 'Linhas', + templateGrid: 'Grade', + templatePriority: 'Prioridade', + zoneTag: index => `zona ${index}`, + mergeZones: count => `Mesclar ${count} zonas`, + customZoneName: count => `Personalizado com ${count} zonas`, + layoutNamePlaceholder: fallback => `Nome do layout (${fallback})`, + saveApply: 'Salvar & aplicar', + notExpressible: 'este arranjo entrelaça (catavento) — não é expressível como divisões aninhadas ainda', + zoneCount: count => `${count} zonas` + }, + + assistant: { + thread: { + loadingSession: 'Carregando sessão', + showEarlier: 'Mostrar mensagens anteriores', + loadingResponse: 'O Hermes está carregando uma resposta', + resumeWhenBackgroundDone: count => + count === 1 + ? 'Retomará quando a tarefa em segundo plano terminar' + : `Retomará quando ${count} tarefas em segundo plano terminarem`, + thinking: 'Pensando', + thought: 'Pensou', + thoughtBriefly: 'Pensou brevemente', + thoughtFor: duration => `Pensou por ${duration}`, + today: time => `Hoje, ${time}`, + yesterday: time => `Ontem, ${time}`, + copy: 'Copiar', + refresh: 'Atualizar', + moreActions: 'Mais ações', + branchNewChat: 'Ramificar em novo chat', + react: 'Reagir', + dismissError: 'Descartar erro', + filesChanged: count => (count === 1 ? '1 arquivo alterado' : `${count} arquivos alterados`), + reviewChanges: 'Revisar', + readAloudFailed: 'Falha ao ler em voz alta', + preparingAudio: 'Preparando áudio...', + stopReading: 'Parar leitura', + readAloud: 'Ler em voz alta', + editMessage: 'Editar mensagem', + expandMessage: 'Expandir mensagem', + scrollToBottom: 'Rolar até o fim', + stop: 'Parar', + restorePrevious: 'Restaurar ponto de verificação anterior', + restoreCheckpoint: 'Restaurar ponto de verificação', + restoreFromHere: 'Restaurar ponto de verificação — reexecutar a partir deste prompt', + restoreTitle: 'Restaurar para este ponto de verificação?', + restoreBody: + 'Tudo após este prompt é removido da conversa e o prompt é executado novamente a partir daqui.', + restoreConfirm: 'Restaurar & reexecutar', + restoreNext: 'Restaurar próximo ponto de verificação', + goForward: 'Avançar', + sendEdited: 'Enviar mensagem editada', + attachingFile: 'Anexando…' + }, + approval: { + gatewayDisconnected: 'O gateway do Hermes não está conectado', + sendFailed: 'Não foi possível enviar a resposta de aprovação', + run: 'Executar', + command: 'Comando', + moreOptions: 'Mais opções de aprovação', + allowSession: 'Permitir nesta sessão', + alwaysAllowMenu: 'Permitir sempre…', + jumpToApproval: 'Aprovação necessária', + reject: 'Rejeitar', + alwaysTitle: 'Permitir sempre este comando?', + alwaysDescription: pattern => + `Isso adiciona o padrão "${pattern}" à sua lista de permitidos permanente (~/.hermes/config.yaml). O Hermes não perguntará novamente para comandos como este — nesta sessão ou em qualquer outra futura.`, + alwaysAllow: 'Permitir sempre' + }, + clarify: { + notReady: 'A solicitação de esclarecimento ainda não está pronta', + gatewayDisconnected: 'O gateway do Hermes não está conectado', + sendFailed: 'Não foi possível enviar a resposta de esclarecimento', + loadingQuestion: 'Carregando pergunta…', + other: 'Outro (digite sua resposta)', + placeholder: 'Digite sua resposta…', + skip: 'Pular', + skipped: 'Pulado', + continueLabel: 'Continuar', + lateAnswer: (question, choice) => `Re: "${question}" — minha resposta: ${choice}`, + lateAnswerTip: 'Rascunhar esta resposta como mensagem de acompanhamento', + lateAnswerHint: 'Este prompt não está mais aguardando. Escolha uma opção para rascunhá-lo como mensagem de acompanhamento.' + }, + tool: { + copyCode: 'Copiar código', + renderingImage: 'Renderizando imagem', + copyOutput: 'Copiar saída', + copyCommand: 'Copiar comando', + copyContent: 'Copiar conteúdo', + copyUrl: 'Copiar URL', + copyResults: 'Copiar resultados', + copyQuery: 'Copiar consulta', + copyFile: 'Copiar arquivo', + copyPath: 'Copiar caminho', + outputAlt: 'Saída da ferramenta', + rawResponse: 'Resposta bruta', + copyActivity: 'Copiar atividade', + recoveredOne: 'Recuperado após 1 etapa falha', + recoveredMany: count => `Recuperado após ${count} etapas falhas`, + failedOne: '1 etapa falhou', + failedMany: count => `${count} etapas falharam`, + statusRunning: 'Executando', + statusError: 'Erro', + statusRecovered: 'Recuperado', + statusDone: 'Concluído', + memoryWriteNoted: 'Escrita em memória registrada', + actions: { + read: 'Lido', + reading: 'Lendo', + opened: 'Aberto', + opening: 'Abrindo', + failedToOpen: 'Falha ao abrir', + searched: 'Buscado', + searching: 'Buscando', + ran: 'Executou', + running: 'Executando', + ranCode: 'Executou código', + runningCode: 'Scriptando' + }, + prefixes: { + browser: 'Navegador', + web: 'Web' + }, + titleTemplates: { + actionCommand: (action, command) => `${action} ${command}`, + actionQuoted: (action, value) => `${action} "${value}"`, + actionTarget: (action, target) => `${action} ${target}`, + prefixedDone: (prefix, action) => `${prefix} ${action}`, + runningPrefixedTool: (prefix, action) => `Executando ${prefix.toLowerCase()} ${action.toLowerCase()}`, + runningTool: action => `Executando ${action.toLowerCase()}` + }, + titles: { + browser_click: { done: 'Clicou em elemento da página', pending: 'Clicando em elemento da página', pendingAction: 'Clicando' }, + browser_fill: { done: 'Preencheu campo de formulário', pending: 'Preenchendo campo de formulário', pendingAction: 'Preenchendo' }, + browser_navigate: { done: 'Abriu página', pending: 'Abrindo página', pendingAction: 'Abrindo' }, + browser_snapshot: { + done: 'Capturou snapshot da página', + pending: 'Capturando snapshot da página', + pendingAction: 'Capturando' + }, + browser_take_screenshot: { + done: 'Capturou screenshot', + pending: 'Capturando screenshot', + pendingAction: 'Capturando' + }, + browser_type: { done: 'Digitou na página', pending: 'Digitando na página', pendingAction: 'Digitando' }, + clarify: { done: 'Fez uma pergunta', pending: 'Fazendo uma pergunta', pendingAction: 'Perguntando' }, + cronjob: { done: 'Tarefa cron', pending: 'Agendando tarefa cron', pendingAction: 'Agendando' }, + edit_file: { done: 'Editou arquivo', pending: 'Editando arquivo', pendingAction: 'Editando' }, + execute_code: { done: 'Executou código', pending: 'Scriptando', pendingAction: 'Scriptando' }, + image_generate: { done: 'Gerou imagem', pending: 'Gerando imagem', pendingAction: 'Gerando' }, + list_files: { done: 'Listou arquivos', pending: 'Listando arquivos', pendingAction: 'Listando' }, + memory: { done: 'Salvo na memória', pending: 'Salvando na memória', pendingAction: 'Salvando' }, + patch: { done: 'Aplicou patch em arquivo', pending: 'Aplicando patch em arquivo', pendingAction: 'Aplicando patch' }, + read_file: { done: 'Leu arquivo', pending: 'Lendo arquivo', pendingAction: 'Lendo' }, + search_files: { done: 'Buscou arquivos', pending: 'Buscando arquivos', pendingAction: 'Buscando' }, + session_search_recall: { + done: 'Buscou histórico de sessões', + pending: 'Buscando histórico de sessões', + pendingAction: 'Buscando' + }, + terminal: { done: 'Executou comando', pending: 'Executando comando', pendingAction: 'Executando' }, + todo: { done: 'Atualizou tarefas', pending: 'Atualizando tarefas', pendingAction: 'Atualizando' }, + vision_analyze: { done: 'Analisou imagem', pending: 'Analisando imagem', pendingAction: 'Analisando' }, + web_extract: { done: 'Leu página web', pending: 'Lendo página web', pendingAction: 'Lendo' }, + web_search: { done: 'Buscou na web', pending: 'Buscando na web', pendingAction: 'Buscando' }, + write_file: { done: 'Editou arquivo', pending: 'Editando arquivo', pendingAction: 'Editando' } + } + } + } +}) diff --git a/apps/desktop/src/i18n/types.ts b/apps/desktop/src/i18n/types.ts index 79b56030d6c6..96e7d4aefa7a 100644 --- a/apps/desktop/src/i18n/types.ts +++ b/apps/desktop/src/i18n/types.ts @@ -5,7 +5,7 @@ // partial locales should use `defineLocale()` so missing desktop-only strings // fall back to English while new keys remain type-checked. -export type Locale = 'en' | 'zh' | 'zh-hant' | 'ja' | 'ar' +export type Locale = 'en' | 'zh' | 'zh-hant' | 'ja' | 'ar' | 'pt' export type ToolTitleKey = | 'browser_click'