diff --git a/src/app/api/oauth/[provider]/[action]/route.ts b/src/app/api/oauth/[provider]/[action]/route.ts index 03d7f50d44..a9ffaaf886 100755 --- a/src/app/api/oauth/[provider]/[action]/route.ts +++ b/src/app/api/oauth/[provider]/[action]/route.ts @@ -91,9 +91,10 @@ export async function GET( provider === "github" || provider === "kiro" || provider === "amazon-q" || + provider === "kimi-coding" || provider === "kilocode" ) { - // GitHub, Kiro, and KiloCode don't use PKCE for device code + // GitHub, Kiro/Amazon Q, Kimi Coding, and KiloCode don't use PKCE for device code deviceData = await runWithProxyContext(proxy, () => (requestDeviceCode as any)(provider)); } else { // Qwen and other providers use PKCE @@ -329,7 +330,7 @@ export async function POST( // Poll for token (through proxy if configured) let result; if (provider === "github" || provider === "kimi-coding" || provider === "kilocode") { - // For providers that don't use PKCE (like GitHub, Kiro, Kimi Coding), don't pass codeVerifier + // For providers that don't use PKCE (GitHub, Kimi Coding, KiloCode), don't pass codeVerifier result = await runWithProxyContext(proxy, () => (pollForToken as any)(provider, deviceCode) ); diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index 6b3cc77509..3eea5c7d53 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -36,7 +36,7 @@ "time": "Tempo", "details": "Detalhes", "created": "Criado", - "lastUsed": "Last Refreshed", + "lastUsed": "Última atualização", "loadMore": "Carregar Mais", "noResults": "Nenhum resultado encontrado", "reloadPage": "Recarregar Página", @@ -57,8 +57,8 @@ "note": "Nota", "free": "Gratuito", "skipToContent": "Pular para conteúdo", - "maintenanceServerIssues": "Server is experiencing issues. Some features may be unavailable.", - "maintenanceServerUnreachable": "Server is unreachable. Reconnecting...", + "maintenanceServerIssues": "O servidor está enfrentando problemas. Alguns recursos podem estar indisponíveis.", + "maintenanceServerUnreachable": "O servidor está inacessível. Reconectando...", "accept": "Aceitar", "accountId": "ID da conta", "alias": "Alias", @@ -137,14 +137,14 @@ "Failed to reset pricing": "Falha ao redefinir o preço", "apikey": "Chave de API", "http": "HTTP", - "nothingHere": "Nothing here yet", - "checkSystemStatus": "Check System Status", - "goToDashboard": "Go to Dashboard", - "selectModel": "Select Model", + "nothingHere": "Nada aqui ainda", + "checkSystemStatus": "Verifique o status do sistema", + "goToDashboard": "Vá para o painel", + "selectModel": "Selecione o modelo", "combos": "Combos", - "noModelsFound": "No models found", - "clear": "Clear", - "done": "Done" + "noModelsFound": "Nenhum modelo encontrado", + "clear": "Claro", + "done": "Feito" }, "sidebar": { "home": "Início", @@ -160,16 +160,16 @@ "media": "Mídia", "settings": "Configurações", "translator": "Tradutor", - "playground": "Playground", - "searchTools": "Search Tools", + "playground": "Parque infantil", + "searchTools": "Ferramentas de pesquisa", "agents": "Agentes", "memory": "Memória", "skills": "Habilidades", "docs": "Documentação", "issues": "Problemas", - "endpoints": "Endpoints", + "endpoints": "Pontos finais", "apiManager": "Gerenciador API", - "logs": "Logs", + "logs": "Registros", "auditLog": "Log de Auditoria", "shutdown": "Desligar", "restart": "Reiniciar", @@ -179,38 +179,38 @@ "debug": "Depuração", "system": "Sistema", "help": "Ajuda", - "primarySection": "Main", + "primarySection": "Principal", "cliSection": "CLI", - "debugSection": "Debug", - "systemSection": "System", - "helpSection": "Help", + "debugSection": "Depurar", + "systemSection": "Sistema", + "helpSection": "Ajuda", "serverDisconnected": "Servidor Desconectado", "serverDisconnectedMsg": "O servidor proxy foi parado ou está reiniciando.", "expandSidebar": "Expandir barra lateral", "collapseSidebar": "Recolher barra lateral", - "themes": "Themes", - "presetColors": "Popular colors", - "createTheme": "Create theme", - "chooseColor": "Pick one color", + "themes": "Temas", + "presetColors": "Cores populares", + "createTheme": "Criar tema", + "chooseColor": "Escolha uma cor", "themeCoral": "Coral", - "themeBlue": "Blue", - "themeRed": "Red", - "themeGreen": "Green", - "themeViolet": "Violet", - "themeOrange": "Orange", - "themeCyan": "Cyan", + "themeBlue": "Azul", + "themeRed": "Vermelho", + "themeGreen": "Verde", + "themeViolet": "Violeta", + "themeOrange": "Laranja", + "themeCyan": "Ciano", "cliToolsShort": "Ferramentas", "cache": "Cache", "cacheShort": "Cache" }, "themesPage": { - "title": "Themes", - "description": "Choose a preset theme or create your own with a single color", - "presetColors": "Popular colors", - "customTheme": "Custom theme", - "customThemeDesc": "Click create theme and pick one color", - "createTheme": "Create theme", - "activePreset": "Active theme" + "title": "Temas", + "description": "Escolha um tema predefinido ou crie o seu próprio com uma única cor", + "presetColors": "Cores populares", + "customTheme": "Tema personalizado", + "customThemeDesc": "Clique em criar tema e escolha uma cor", + "createTheme": "Criar tema", + "activePreset": "Tema ativo" }, "header": { "logout": "Sair", @@ -227,20 +227,20 @@ "cliToolsDescription": "Configurar ferramentas de linha de comando", "home": "Início", "homeDescription": "Bem-vindo ao OmniRoute", - "endpoint": "Endpoints", + "endpoint": "Pontos finais", "endpointDescription": "Gerenciar endpoints proxy, MCP, A2A e endpoints de API", "mcp": "MCP", - "mcpDescription": "Model Context Protocol server management and tools", + "mcpDescription": "Gerenciamento e ferramentas de servidor do Model Context Protocol", "a2a": "A2A", - "a2aDescription": "Agent-to-Agent protocol tasks and observability", + "a2aDescription": "Tarefas e observabilidade do protocolo agente para agente", "settings": "Configurações", "settingsDescription": "Gerencie suas preferências", "openaiCompatible": "Compatível com OpenAI", "anthropicCompatible": "Compatível com Anthropic", "media": "Mídia", "mediaDescription": "Gerar imagens, vídeos e músicas", - "themes": "Themes", - "themesDescription": "Choose a color theme for the whole dashboard panel" + "themes": "Temas", + "themesDescription": "Escolha um tema de cores para todo o painel do painel" }, "home": { "quickStart": "Início Rápido", @@ -270,10 +270,10 @@ "activeError": "{active} ativo · {errors} erro", "oauthLabel": "OAuth", "apiKeyLabel": "Chave de API", - "requestsShort": "{count} reqs", + "requestsShort": "{count} requisitos", "providerModelsTitle": "{provider} - Modelos", "copiedModel": "Copiado: {model}", - "aliasLabel": "alias", + "aliasLabel": "apelido", "updateNow": "Atualizar agora", "updating": "Atualizando...", "updateAvailableDesc": "Uma nova versão está disponível. Clique para atualizar.", @@ -325,7 +325,7 @@ "usage": "Uso", "created": "Criado", "actions": "Ações", - "reqs": "reqs", + "reqs": "requisitos", "neverUsed": "Nunca usada", "deleteConfirm": "Excluir esta chave de API?", "usageTips": "Dicas de Uso", @@ -341,7 +341,7 @@ "keyCreatedNote": "Copie e armazene esta chave agora — ela não será mostrada novamente.", "done": "Pronto", "savePermissions": "Salvar Permissões", - "autoResolve": "Auto-Resolve", + "autoResolve": "Resolução automática", "autoResolveDesc": "Resolve automaticamente nomes ambíguos de modelo para o provedor nativo desta API key.", "keyActive": "Chave Ativa", "keyActiveDesc": "Ativa ou desativa esta API key. Chaves desativadas são bloqueadas com 403.", @@ -385,7 +385,7 @@ "failedUpdatePermissionsRetry": "Falha ao atualizar permissões. Tente novamente.", "unknownProvider": "desconhecido", "copyMaskedKey": "Copiar chave mascarada", - "keyOnlyAvailableAtCreation": "Full key available only at creation time — copy it when you first create the key", + "keyOnlyAvailableAtCreation": "Chave completa disponível apenas no momento da criação — copie-a quando você criar a chave pela primeira vez", "modelsCount": "{count, plural, one {# modelo} other {# modelos}}", "lastUsedOn": "Último: {date}", "editPermissions": "Editar permissões", @@ -423,7 +423,7 @@ "title": "Playground de Mídia", "subtitle": "Gere imagens, vídeos e música", "model": "Modelo", - "prompt": "Prompt", + "prompt": "Incitar", "generate": "Gerar", "generating": "Gerando...", "loadingModels": "Carregando modelos disponíveis...", @@ -435,55 +435,55 @@ "musicDescription": "Componha músicas usando Stable Audio Open ou MusicGen via ComfyUI." }, "search": { - "searchQuery": "Search Query", - "searchResults": "Search Results", - "cachedResult": "Cached", - "searchCost": "Cost", - "searchTools": "Search Tools", - "searchToolsDesc": "Advanced search testing with provider comparison", - "compareProviders": "Compare Providers", - "rerankResults": "Rerank Results", - "searchHistory": "Search History", - "urlOverlap": "URL Overlap", - "noSearchProviders": "No search providers configured. Add providers in Settings.", - "noRerankModels": "No rerank model available", - "webSearch": "Web Search", - "provider": "Provider", - "searchType": "Search Type", - "maxResults": "Max Results", - "filters": "Filters", - "country": "Country", - "language": "Language", - "timeRange": "Time Range", - "includeDomains": "Include Domains", - "excludeDomains": "Exclude Domains", - "safeSearch": "Safe Search", - "safeSearchOff": "Off", - "safeSearchModerate": "Moderate", - "safeSearchStrict": "Strict", - "queryPlaceholder": "Enter search query...", - "providerAuto": "auto (cheapest)", - "searchTypeWeb": "web", - "searchTypeNews": "news", - "optionAny": "any", - "timeRangeDay": "Past day", - "timeRangeWeek": "Past week", - "timeRangeMonth": "Past month", - "timeRangeYear": "Past year", + "searchQuery": "Consulta de pesquisa", + "searchResults": "Resultados da pesquisa", + "cachedResult": "Em cache", + "searchCost": "Custo", + "searchTools": "Ferramentas de pesquisa", + "searchToolsDesc": "Teste de pesquisa avançada com comparação de provedores", + "compareProviders": "Comparar provedores", + "rerankResults": "Reclassificar resultados", + "searchHistory": "Histórico de pesquisa", + "urlOverlap": "Sobreposição de URL", + "noSearchProviders": "Nenhum provedor de pesquisa configurado. Adicione provedores em Configurações.", + "noRerankModels": "Nenhum modelo de reclassificação disponível", + "webSearch": "Pesquisa na Web", + "provider": "Provedor", + "searchType": "Tipo de pesquisa", + "maxResults": "Resultados máximos", + "filters": "Filtros", + "country": "País", + "language": "Linguagem", + "timeRange": "Intervalo de tempo", + "includeDomains": "Incluir Domínios", + "excludeDomains": "Excluir domínios", + "safeSearch": "Pesquisa segura", + "safeSearchOff": "Desligado", + "safeSearchModerate": "Moderado", + "safeSearchStrict": "Estrito", + "queryPlaceholder": "Insira a consulta de pesquisa...", + "providerAuto": "automático (mais barato)", + "searchTypeWeb": "rede", + "searchTypeNews": "notícias", + "optionAny": "qualquer", + "timeRangeDay": "Último dia", + "timeRangeWeek": "Semana passada", + "timeRangeMonth": "Mês passado", + "timeRangeYear": "Ano passado", "domainPlaceholder": "example.com", - "requestTimedOut": "Request timed out ({seconds}s)", - "networkError": "Network error", - "formatted": "Formatted", + "requestTimedOut": "A solicitação expirou ({seconds}s)", + "networkError": "Erro de rede", + "formatted": "Formatado", "rawJson": "JSON", - "cacheMiss": "cache miss", - "cacheHit": "cache hit", - "latency": "Latency", - "cost": "Cost", - "results": "Results", - "rerank": "Rerank", - "rerankModel": "Rerank Model", - "positionDelta": "Position Change", - "emptyState": "Send a search query to see results" + "cacheMiss": "falta de cache", + "cacheHit": "acerto no cache", + "latency": "Latência", + "cost": "Custo", + "results": "Resultados", + "rerank": "Reclassificar", + "rerankModel": "Modelo de reclassificação", + "positionDelta": "Mudança de posição", + "emptyState": "Envie uma consulta de pesquisa para ver os resultados" }, "cliTools": { "title": "Ferramentas CLI", @@ -530,7 +530,7 @@ "cliRuntimeNotDetected": "Runtime de CLI não detectado", "binary": "Binário", "configPath": "Caminho de config", - "configPathShort": "Config", + "configPathShort": "Configuração", "failedCheckRuntimeStatus": "Falha ao verificar status de runtime.", "copy": "Copiar", "copied": "Copiado", @@ -557,11 +557,11 @@ "antigravityStep2Prefix": "2. Adicione", "antigravityStep2Suffix": "ao arquivo hosts como 127.0.0.1.", "antigravityStep3": "3. Abra o Antigravity e as requisições serão proxyadas.", - "mitmHowWorksDesc": "{toolName} sends requests to its provider endpoint. MITM intercepts and redirects them to OmniRoute.", - "mitmStep1": "1. Start MITM to route requests through OmniRoute.", - "mitmStep2Prefix": "2. Add", - "mitmStep2Suffix": "to your hosts file as 127.0.0.1.", - "mitmStep3": "3. Open {toolName} and requests will be proxied.", + "mitmHowWorksDesc": "{toolName} envia solicitações ao endpoint do provedor. O MITM os intercepta e os redireciona para o OmniRoute.", + "mitmStep1": "1. Inicie o MITM para rotear solicitações por meio do OmniRoute.", + "mitmStep2Prefix": "2. Adicionar", + "mitmStep2Suffix": "ao seu arquivo hosts como 127.0.0.1.", + "mitmStep3": "3. Abra {toolName} e as solicitações serão enviadas por proxy.", "sudoPasswordRequiredTitle": "Senha sudo necessária", "sudoPasswordHint": "A senha de administrador é necessária para modificar hosts e configurações de proxy do sistema.", "enterSudoPassword": "Digite a senha sudo", @@ -585,7 +585,7 @@ "hide": "Ocultar", "howToInstall": "Como instalar", "installationGuide": "Guia de instalação", - "platforms": "macOS / Linux / Windows:", + "platforms": "macOS/Linux/Windows:", "afterInstallationRun": "Após a instalação, execute", "toVerify": "para verificar.", "current": "Atual", @@ -595,7 +595,7 @@ "apply": "Aplicar", "reset": "Resetar", "manualConfig": "Configuração manual", - "backups": "Backups", + "backups": "Cópias de segurança", "configBackups": "Backups de configuração", "noBackupsYet": "Ainda não há backups. Backups são criados automaticamente antes de cada Aplicar ou Resetar.", "restore": "Restaurar", @@ -672,12 +672,11 @@ "cursor": "Use ao codificar no Cursor e você precisar de modelos personalizados compatíveis com OpenAI por meio do OmniRoute.", "continue": "Use ao executar Continue em IDEs e você precisar de uma configuração de provedor portátil baseada em JSON.", "opencode": "Use quando preferir execuções de agentes nativos de terminal e automação com script via OpenCode.", - "amp": "Use quando quiser fluxos com atalhos do Amp, mas ainda precisar de aliases e regras de roteamento do OmniRoute.", + "amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.", "kiro": "Use ao integrar o Kiro e controlar o roteamento do modelo centralmente no OmniRoute.", "antigravity": "Use quando o tráfego Antigravity/Kiro deve ser interceptado através do MITM e roteado para OmniRoute.", "copilot": "Use quando desejar UX no estilo de bate-papo do Copilot enquanto impõe chaves OmniRoute e regras de roteamento.", "windsurf": "Use quando quiser uma IDE AI-first com modelos Codeium/Windsurf roteados pelo OmniRoute.", - "amp": "Use when you want Amp CLI routed through OmniRoute with stable shorthand aliases and OpenAI-compatible setup.", "qwen": "Use quando precisar do Alibaba Qwen Code CLI para tarefas de programação.", "custom": "Use quando seu CLI ou SDK não estiver hardcoded no OmniRoute, mas ainda aceitar base URL, chave de API e model string compatíveis com OpenAI." }, @@ -692,12 +691,11 @@ "cursor": "Editor de código com IA Cursor", "continue": "Assistente de IA Continue", "opencode": "Agente de código OpenCode (Terminal)", - "amp": "CLI do assistente de código Sourcegraph Amp", + "amp": "CLI do assistente de codificação Sourcegraph Amp", "kiro": "Amazon Kiro — IDE com IA", "windsurf": "Windsurf — Editor de Código com IA", "copilot": "GitHub Copilot — Assistente de IA", - "qwen": "Alibaba Qwen Code CLI", - "amp": "Sourcegraph Amp coding assistant CLI", + "qwen": "CLI do código Alibaba Qwen", "custom": "Gerador genérico de configuração para CLI ou SDK OpenAI-compatible" }, "guides": { @@ -754,22 +752,22 @@ "opencode": { "steps": { "1": { - "title": "Install OpenCode", - "desc": "Install via npm: npm install -g opencode-ai" + "title": "Instale o OpenCode", + "desc": "Instale via npm: npm install -g opencode-ai" }, "2": { - "title": "API Key" + "title": "Chave de API" }, "3": { - "title": "Set Base URL", - "desc": "opencode config set baseUrl {{baseUrl}}" + "title": "Definir URL base", + "desc": "conjunto de configuração opencode baseUrl {{baseUrl}}" }, "4": { - "title": "Select Model" + "title": "Selecione o modelo" }, "5": { - "title": "Use Thinking Variant", - "desc": "For thinking models, run with --variant high/low/max (example command below)." + "title": "Use a variante de pensamento", + "desc": "Para modelos de pensamento, execute com --variant high/low/max (exemplo de comando abaixo)." } }, "notes": { @@ -780,18 +778,18 @@ "kiro": { "steps": { "1": { - "title": "Open Kiro Settings", - "desc": "Go to Settings → AI Provider" + "title": "Abra as configurações do Kiro", + "desc": "Vá para Configurações → Provedor de IA" }, "2": { - "title": "Base URL", - "desc": "Paste your OmniRoute endpoint URL" + "title": "URL base", + "desc": "Cole o URL do endpoint do OmniRoute" }, "3": { - "title": "API Key" + "title": "Chave de API" }, "4": { - "title": "Select Model" + "title": "Selecione o modelo" } }, "notes": { @@ -801,24 +799,24 @@ "windsurf": { "steps": { "1": { - "title": "Open AI Settings", - "desc": "Click the AI Settings icon in Windsurf or go to Settings" + "title": "Abra as configurações de IA", + "desc": "Clique no ícone Configurações de IA no Windsurf ou vá para Configurações" }, "2": { - "title": "Add Custom Provider", - "desc": "Select \"Add custom provider\" (OpenAI-compatible)" + "title": "Adicionar provedor personalizado", + "desc": "Selecione \"Adicionar provedor personalizado\" (compatível com OpenAI)" }, "3": { - "title": "Base URL", + "title": "URL base", "desc": "http://127.0.0.1:20128/v1" }, "4": { - "title": "API Key", - "desc": "Select your OmniRoute API key" + "title": "Chave de API", + "desc": "Selecione sua chave de API OmniRoute" }, "5": { - "title": "Select Model", - "desc": "Choose a model from the dropdown" + "title": "Selecione o modelo", + "desc": "Escolha um modelo no menu suspenso" } } } @@ -836,11 +834,11 @@ "addModelToCombo": "Adicionar Modelo ao Combo", "routingStrategy": "Estratégia de Roteamento", "maxRetries": "Máximo de Tentativas", - "timeout": "Timeout (ms)", + "timeout": "Tempo limite (ms)", "healthcheck": "Verificação de Saúde", "priority": "Prioridade", "fallback": "Fallback", - "roundRobin": "Round Robin", + "roundRobin": "Rodada Robin", "random": "Aleatório", "leastLatency": "Menor Latência", "comboName": "Nome do Combo", @@ -860,7 +858,7 @@ "testResults": "Resultados do Teste — {name}", "resolvedBy": "Resolvido por:", "more": "+{count} mais", - "reqs": "reqs", + "reqs": "requisitos", "success": "sucesso", "proxyConfigured": "Proxy configurado", "copyComboName": "Copiar nome do combo", @@ -875,7 +873,7 @@ "priorityDesc": "Fallback sequencial: tenta modelo 1 primeiro, depois 2, etc.", "weightedDesc": "Distribui tráfego por porcentagem de peso com fallback", "roundRobinDesc": "Distribuição circular: cada requisição vai para o próximo modelo na rotação", - "contextRelay": "Context Relay", + "contextRelay": "Retransmissão de Contexto", "contextRelayDesc": "Preserva a continuidade da sessão com resumos de handoff quando as contas giram", "randomDesc": "Seleção aleatória uniforme, depois fallback para modelos restantes", "leastUsedDesc": "Escolhe o modelo com menos requisições, equilibrando carga ao longo do tempo", @@ -944,14 +942,14 @@ "example": "Múltiplas contas do mesmo modelo para distribuir uso de forma equilibrada." }, "p2c": { - "avoid": "Avoid for small combos with 2 or fewer models — no benefit over round-robin.", - "example": "Example: High-throughput inference across 4+ equivalent model endpoints.", - "when": "Use when you want low-latency selection using Power-of-Two-Choices algorithm." + "avoid": "Evite combos pequenos com 2 ou menos modelos – nenhum benefício em relação ao round-robin.", + "example": "Exemplo: inferência de alto rendimento em mais de 4 endpoints de modelo equivalentes.", + "when": "Use quando desejar seleção de baixa latência usando o algoritmo Power-of-Two-Choices." }, "context-relay": { - "avoid": "Avoid when account switching is rare or when you do not want extra summarization requests.", - "when": "Use when long sessions must survive account rotation without losing the working context.", - "example": "Example: Codex sessions that rotate across multiple accounts near quota exhaustion." + "avoid": "Evite quando a troca de conta for rara ou quando você não quiser solicitações extras de resumo.", + "when": "Use quando sessões longas precisam sobreviver à rotação de contas sem perder o contexto de trabalho.", + "example": "Exemplo: sessões do Codex que alternam entre várias contas perto do esgotamento da cota." } }, "advancedHelp": { @@ -999,10 +997,10 @@ "saveBlockModels": "Adicione pelo menos um modelo.", "saveBlockWeighted": "Ajuste os pesos para 100% (atual: {total}%).", "saveBlockPricing": "Adicione preço para pelo menos um modelo ou escolha outra estratégia.", - "recommendationsLabel": "Recommended setup", - "applyRecommendations": "Apply recommendations", - "recommendationsUpdated": "Recommendations updated for {strategy}.", - "recommendationsApplied": "Recommendations applied to this combo.", + "recommendationsLabel": "Configuração recomendada", + "applyRecommendations": "Aplicar recomendações", + "recommendationsUpdated": "Recomendações atualizadas para {strategy}.", + "recommendationsApplied": "Recomendações aplicadas a este combo.", "strategyRecommendations": { "priority": { "title": "Fail-safe básico", @@ -1054,125 +1052,125 @@ "tip3": "Combine com health checks para pular contas indisponíveis sem quebrar o ciclo." } }, - "templateFreeStack": "Free Stack ($0)", - "templateFreeStackDesc": "Round-robin across all free providers: Kiro (Claude), Qoder (5 models), Qwen (4 models), Gemini CLI. Zero cost, never stops coding.", + "templateFreeStack": "Pilha Grátis ($0)", + "templateFreeStackDesc": "Round-robin entre todos os provedores gratuitos: Kiro (Claude), Qoder (5 modelos), Qwen (4 modelos), Gemini CLI. Custo zero, nunca para de codificar.", "auto": "Auto Combo", "autoDesc": "Pool de roteamento inteligente (Otimizado)", "lkgp": "Modo LKGP", "lkgpDesc": "Último Provedor Bom Conhecido (Resiliência previsível)", - "wizardGuideTitle": "Getting Started with Combos", - "wizardGuideDesc": "Create model combos to route AI traffic intelligently", - "wizardGuideHint": "or click + Create Combo above", - "createFirstCombo": "Create Your First Combo", - "wizardStep1Title": "Name Your Combo", - "wizardStep1Desc": "Give your combo a unique name to identify it in routing rules", - "wizardStep2Title": "Add Models", - "wizardStep2Desc": "Select AI models and arrange their fallback priority order", - "wizardStep3Title": "Choose Strategy", - "wizardStep3Desc": "Pick how requests are distributed across your models - 13 strategies available", - "wizardStep4Title": "Review & Save", - "wizardStep4Desc": "Review your configuration and activate the combo", - "builderPreview": "Preview", + "wizardGuideTitle": "Primeiros passos com combos", + "wizardGuideDesc": "Crie combinações de modelos para rotear o tráfego de IA de maneira inteligente", + "wizardGuideHint": "ou clique em + Criar Combo acima", + "createFirstCombo": "Crie seu primeiro combo", + "wizardStep1Title": "Dê um nome ao seu combo", + "wizardStep1Desc": "Dê ao seu combo um nome exclusivo para identificá-lo nas regras de roteamento", + "wizardStep2Title": "Adicionar modelos", + "wizardStep2Desc": "Selecione modelos de IA e organize sua ordem de prioridade substituta", + "wizardStep3Title": "Escolha a estratégia", + "wizardStep3Desc": "Escolha como as solicitações são distribuídas em seus modelos – 13 estratégias disponíveis", + "wizardStep4Title": "Revise e salve", + "wizardStep4Desc": "Revise sua configuração e ative o combo", + "builderPreview": "Visualização", "builderStage": { "strategy": { - "label": "Strategy", - "description": "Routing behavior and advanced settings" + "label": "Estratégia", + "description": "Comportamento de roteamento e configurações avançadas" }, "review": { - "description": "Final validation before saving", - "label": "Review" + "description": "Validação final antes de salvar", + "label": "Análise" }, "basics": { - "label": "Basics", - "description": "Name and starting template" + "label": "Noções básicas", + "description": "Nome e modelo inicial" }, "steps": { - "label": "Steps", - "description": "Provider, model, and account selection" + "label": "Passos", + "description": "Seleção de provedor, modelo e conta" }, "intelligent": { - "label": "Smart Routing", - "description": "Auto-routing candidate pool, presets, and scoring" + "label": "Roteamento Inteligente", + "description": "Roteamento automático de pool de candidatos, predefinições e pontuação" } }, - "routerStrategyLabel": "Router Strategy", + "routerStrategyLabel": "Estratégia de roteador", "emailVisibilityStateOn": "On", - "reviewAdvanced": "Advanced Settings", - "reviewComboRefs": "Combo References", - "weightStability": "Stability", - "excludedProvidersHint": "Providers with an OPEN circuit breaker are temporarily excluded from routing.", - "builderIntelligentTitle": "Intelligent Routing Configuration", - "builderComboRefStep": "Add combo reference", - "builderStageCurrent": "Current stage", - "builderStageVisited": "Stage completed", - "builderAccount": "Account", - "explorationRateLabel": "Exploration Rate", - "excludedProviders": "Excluded Providers", - "weightLatencyInv": "Latency", - "reorderHandle": "Drag to reorder", - "builderTitle": "Build a Combo", - "builderProviderFirst": "Pick provider first", - "intelligentPanelDesc": "Real-time scoring and health status for this auto-routing combo.", - "statusOverview": "Status Overview", - "filterEmptyTitle": "No combos match this strategy filter.", - "builderStageLocked": "Locked — complete previous stage first", - "builderPinnedAccount": "Pinned Account", - "budgetCapLabel": "Budget Cap (USD / request)", - "modePackUpdated": "Mode pack updated to {pack}.", - "incidentMode": "Incident Mode", - "providerScores": "Provider Scores", - "noExcludedProviders": "No providers are currently excluded.", - "normalOperation": "Normal Operation", - "reviewProviders": "Providers", - "builderSelectModel": "Select model", - "filterEmptyDeterministicDescription": "Only auto and LKGP combos exist right now. Switch back to All or create a deterministic combo.", - "builderFlowTitle": "Combo Builder Flow", - "highCircuitBreakerRate": "High circuit breaker trip rate detected.", - "filterIntelligent": "Intelligent", - "weightTierPriority": "Tier", - "intelligentPanelTitle": "Intelligent Routing Dashboard", - "candidatePoolHint": "Select which providers this engine should evaluate. Leave empty to use all active providers.", - "filterDeterministic": "Deterministic", - "builderSelectProvider": "Select provider", - "modePackHint": "Switch presets to bias the routing engine without rebuilding the combo.", - "budgetCapPlaceholder": "No limit", - "builderAddStep": "Add step", - "builderLegacyEntry": "Legacy entry", - "allProvidersHealthy": "Providers are reporting healthy routing conditions.", - "filterAll": "All", - "candidatePoolEmpty": "No active providers available yet.", - "allProvidersEvaluated": "No candidate pool configured. All active providers are evaluated at runtime.", - "builderComboRef": "Combo Ref", - "builderLoadingProviders": "Loading providers...", - "emailVisibilityStateOff": "Off", - "reviewSequence": "Model Sequence", - "reviewSteps": "Steps", - "candidatePoolLabel": "Candidate Pool", - "reviewAgentFlags": "Agent Flags", - "cooldownMinutes": "Cooldown: {minutes}m", - "modePackLabel": "Mode Pack", - "reviewName": "Name", - "weightHealth": "Health", - "explorationRateHint": "{percent}% of requests can explore non-optimal providers.", - "activeModePack": "Active Mode Pack", - "reviewStrategy": "Strategy", - "candidatePoolAllProviders": "All providers", - "advancedWeightsTitle": "Advanced: Scoring Weights", - "reviewIntelligentTitle": "Intelligent Routing Config", - "filterEmptyIntelligentDescription": "Create an auto or LKGP combo to populate the intelligent routing dashboard.", - "failedReorder": "Failed to reorder models", - "builderBrowseCatalog": "Browse catalog", - "weightTaskFit": "Task Fit", - "builderProvider": "Provider", - "reviewAccounts": "Accounts", - "strategyRules": "Rules (6-Factor Scoring)", - "weightCostInv": "Cost", - "builderAddComboRef": "Add combo reference", - "weightQuota": "Quota", - "reviewNoSteps": "No steps configured", - "builderModel": "Model", - "builderStagePending": "Pending", - "builderIntelligentDesc": "Configure the multi-factor scoring engine for this auto-routing combo." + "reviewAdvanced": "Configurações avançadas", + "reviewComboRefs": "Referências combinadas", + "weightStability": "Estabilidade", + "excludedProvidersHint": "Provedores com disjuntor ABERTO estão temporariamente excluídos do roteamento.", + "builderIntelligentTitle": "Configuração de roteamento inteligente", + "builderComboRefStep": "Adicionar referência de combinação", + "builderStageCurrent": "Estágio atual", + "builderStageVisited": "Etapa concluída", + "builderAccount": "Conta", + "explorationRateLabel": "Taxa de Exploração", + "excludedProviders": "Provedores excluídos", + "weightLatencyInv": "Latência", + "reorderHandle": "Arraste para reordenar", + "builderTitle": "Construa um Combo", + "builderProviderFirst": "Escolha o provedor primeiro", + "intelligentPanelDesc": "Pontuação e status de integridade em tempo real para esta combinação de roteamento automático.", + "statusOverview": "Visão geral do status", + "filterEmptyTitle": "Nenhum combo corresponde a este filtro de estratégia.", + "builderStageLocked": "Bloqueado – conclua primeiro o estágio anterior", + "builderPinnedAccount": "Conta fixada", + "budgetCapLabel": "Limite de orçamento (USD/solicitação)", + "modePackUpdated": "Pacote de modo atualizado para {pack}.", + "incidentMode": "Modo Incidente", + "providerScores": "Pontuações do provedor", + "noExcludedProviders": "Nenhum fornecedor está atualmente excluído.", + "normalOperation": "Operação Normal", + "reviewProviders": "Provedores", + "builderSelectModel": "Selecione o modelo", + "filterEmptyDeterministicDescription": "Atualmente, existem apenas combos automáticos e LKGP. Volte para Todos ou crie uma combinação determinística.", + "builderFlowTitle": "Fluxo do Combo Builder", + "highCircuitBreakerRate": "Alta taxa de disparo do disjuntor detectada.", + "filterIntelligent": "Inteligente", + "weightTierPriority": "Nível", + "intelligentPanelTitle": "Painel de roteamento inteligente", + "candidatePoolHint": "Selecione quais provedores este mecanismo deve avaliar. Deixe em branco para usar todos os provedores ativos.", + "filterDeterministic": "Determinístico", + "builderSelectProvider": "Selecione o provedor", + "modePackHint": "Alterne as predefinições para influenciar o mecanismo de roteamento sem reconstruir o combo.", + "budgetCapPlaceholder": "Sem limite", + "builderAddStep": "Adicionar etapa", + "builderLegacyEntry": "Entrada herdada", + "allProvidersHealthy": "Os provedores estão relatando condições de roteamento saudáveis.", + "filterAll": "Todos", + "candidatePoolEmpty": "Nenhum provedor ativo disponível ainda.", + "allProvidersEvaluated": "Nenhum pool de candidatos configurado. Todos os provedores ativos são avaliados em tempo de execução.", + "builderComboRef": "Referência de combinação", + "builderLoadingProviders": "Carregando provedores...", + "emailVisibilityStateOff": "Desligado", + "reviewSequence": "Sequência do modelo", + "reviewSteps": "Passos", + "candidatePoolLabel": "Grupo de Candidatos", + "reviewAgentFlags": "Sinalizadores de agente", + "cooldownMinutes": "Tempo de espera: {minutes}m", + "modePackLabel": "Pacote de modos", + "reviewName": "Nome", + "weightHealth": "Saúde", + "explorationRateHint": "{percent}% das solicitações podem explorar provedores não ideais.", + "activeModePack": "Pacote de modo ativo", + "reviewStrategy": "Estratégia", + "candidatePoolAllProviders": "Todos os provedores", + "advancedWeightsTitle": "Avançado: Pontuação de Pesos", + "reviewIntelligentTitle": "Configuração de roteamento inteligente", + "filterEmptyIntelligentDescription": "Crie um combo automático ou LKGP para preencher o painel de roteamento inteligente.", + "failedReorder": "Falha ao reordenar modelos", + "builderBrowseCatalog": "Navegar no catálogo", + "weightTaskFit": "Ajuste de tarefa", + "builderProvider": "Provedor", + "reviewAccounts": "Contas", + "strategyRules": "Regras (pontuação de 6 fatores)", + "weightCostInv": "Custo", + "builderAddComboRef": "Adicionar referência de combinação", + "weightQuota": "Contingente", + "reviewNoSteps": "Nenhuma etapa configurada", + "builderModel": "Modelo", + "builderStagePending": "Pendente", + "builderIntelligentDesc": "Configure o mecanismo de pontuação multifator para esta combinação de roteamento automático." }, "costs": { "title": "Custos", @@ -1214,7 +1212,7 @@ "baseUrl": "URL Base", "apiKeyLabel": "Chave de API", "registeredKeys": "Chaves Registradas", - "chatCompletions": "Chat Completions", + "chatCompletions": "Conclusões de bate-papo", "responses": "Respostas", "listModels": "Listar Modelos", "usingCloudProxy": "Usando Proxy na Nuvem", @@ -1224,13 +1222,13 @@ "enableCloud": "Ativar Nuvem", "modelsAcrossEndpoints": "{models} modelos em {endpoints} endpoints", "chatDesc": "Chat streaming e não-streaming com todos os provedores", - "embeddings": "Embeddings", + "embeddings": "Incorporações", "embeddingsDesc": "Embeddings de texto para busca e pipelines RAG", "imageGeneration": "Geração de Imagens", "imageDesc": "Gerar imagens a partir de prompts de texto", "videoGeneration": "Geração de Vídeo", "videoDesc": "Gerar vídeos via ComfyUI, Stable Diffusion WebUI e provedores compatíveis", - "rerank": "Rerank", + "rerank": "Reclassificar", "rerankDesc": "Reordenar documentos por relevância a uma consulta", "audioTranscription": "Transcrição de Áudio", "audioTranscriptionDesc": "Transcrever arquivos de áudio para texto (Whisper)", @@ -1241,15 +1239,15 @@ "responsesDesc": "API Responses do OpenAI para Codex e fluxos de trabalho agênticos avançados", "listModelsDesc": "Listar todos os modelos disponíveis em todos os provedores conectados", "settingsApiDesc": "Ler e modificar a configuração do OmniRoute via API", - "settingsApi": "Settings API", + "settingsApi": "API de configurações", "categoryCore": "APIs Principais", "categoryMedia": "Mídia e Multi-Modal", - "categorySearch": "Search & Discovery", + "categorySearch": "Pesquisa e descoberta", "categoryUtility": "Utilidades e Gerenciamento", - "webSearch": "Web Search", - "webSearchDesc": "Unified web search across multiple providers with automatic failover and caching", - "searchProvider": "Search Provider", - "searchProviderDesc": "This provider is used for web search via POST /v1/search. No model configuration needed — search providers are ready to use once an API key is connected.", + "webSearch": "Pesquisa na Web", + "webSearchDesc": "Pesquisa unificada na web em vários provedores com failover e cache automáticos", + "searchProvider": "Provedor de pesquisa", + "searchProviderDesc": "Este provedor é usado para pesquisa na web via POST /v1/search. Nenhuma configuração de modelo é necessária – os provedores de pesquisa estão prontos para uso assim que uma chave de API é conectada.", "enableCloudTitle": "Ativar Proxy na Nuvem", "whatYouGet": "O que você terá", "cloudBenefitAccess": "Acesse sua API de qualquer lugar do mundo", @@ -1282,31 +1280,31 @@ "cloudWorkerUnreachable": "Não foi possível alcançar o worker de nuvem. Verifique se o serviço cloud está rodando (npm run dev em /cloud).", "connectionFailed": "Falha na conexão", "syncFailed": "Falha ao sincronizar dados da nuvem", - "cloudflaredTitle": "Cloudflare Quick Tunnel", + "cloudflaredTitle": "Túnel rápido Cloudflare", "cloudflaredDescription": "Create a Cloudflare Quick Tunnel for this endpoint to make it accessible from the internet without configuring DNS.", "cloudflaredUrlNotice": "Creates a temporary Cloudflare Quick Tunnel. URLs change after restart.", - "cloudflaredEnable": "Enable Tunnel", - "cloudflaredInstallAndEnable": "Install & Enable", - "cloudflaredDisable": "Stop Tunnel", - "cloudflaredRunning": "Running", - "cloudflaredStarting": "Starting", - "cloudflaredStoppedState": "Stopped", - "cloudflaredNotInstalled": "Not installed", - "cloudflaredUnsupported": "Unsupported", - "cloudflaredError": "Error", - "cloudflaredStarted": "Cloudflare tunnel started", - "cloudflaredStopped": "Cloudflare tunnel stopped", - "cloudflaredRequestFailed": "Failed to update Cloudflare tunnel", + "cloudflaredEnable": "Habilitar túnel", + "cloudflaredInstallAndEnable": "Instalar e ativar", + "cloudflaredDisable": "Pare o túnel", + "cloudflaredRunning": "Correndo", + "cloudflaredStarting": "Começando", + "cloudflaredStoppedState": "Parou", + "cloudflaredNotInstalled": "Não instalado", + "cloudflaredUnsupported": "Não compatível", + "cloudflaredError": "Erro", + "cloudflaredStarted": "Túnel Cloudflare iniciado", + "cloudflaredStopped": "Túnel Cloudflare interrompido", + "cloudflaredRequestFailed": "Falha ao atualizar o túnel Cloudflare", "cloudflaredTemporaryNote": "Quick Tunnel URLs are temporary and will change after restart.", "cloudflaredUnsupportedNote": "This platform is not supported for managed installation.", - "cloudflaredIdleNote": "Create a temporary Cloudflare Quick Tunnel for this endpoint.", - "cloudflaredLastError": "Last error: {error}", + "cloudflaredIdleNote": "Crie um Cloudflare Quick Tunnel temporário para este endpoint.", + "cloudflaredLastError": "Último erro: {error}", "providerModelsTitle": "{provider} — Modelos", "noModelsForProvider": "Nenhum modelo disponível para este provedor.", - "chat": "Chat", - "embedding": "Embedding", + "chat": "Bater papo", + "embedding": "Incorporação", "image": "Imagem", - "custom": "custom", + "custom": "personalizado", "modelsCount": "{count, plural, one {# modelo} other {# modelos}}", "sectionTitle": "Superfície de Integração", "sectionDescription": "APIs compatíveis com OpenAI e endpoints operacionais de protocolos", @@ -1334,13 +1332,13 @@ "a2aQuickStartStep1": "Descubra o agent card em `/.well-known/agent.json`.", "a2aQuickStartStep2": "Envie requisições JSON-RPC para `POST /a2a` usando `message/send` ou `message/stream`.", "a2aQuickStartStep3": "Acompanhe e controle tarefas com `tasks/get` e `tasks/cancel`.", - "completionsLegacy": "Completions (Legacy)", - "completionsLegacyDesc": "Legacy OpenAI text completions — accepts both prompt string and messages array format", - "musicDesc": "Generate music and audio tracks via ComfyUI (Stable Audio, MusicGen)", - "musicGeneration": "Music Generation" + "completionsLegacy": "Conclusões (legado)", + "completionsLegacyDesc": "Conclusões de texto herdadas do OpenAI — aceita string de prompt e formato de array de mensagens", + "musicDesc": "Gere músicas e faixas de áudio via ComfyUI (Stable Audio, MusicGen)", + "musicGeneration": "Geração Musical" }, "endpoints": { - "tabProxy": "Endpoint Proxy", + "tabProxy": "Proxy de terminal", "tabApiEndpoints": "Endpoints de API", "apiEndpointsTitle": "Endpoints de API", "apiEndpointsDescription": "Endpoints de API backend que podem ser consumidos por outras aplicações e serviços.", @@ -1365,8 +1363,8 @@ "resetBreakersFailed": "Falha ao resetar circuit breakers.", "resetBreakersSuccess": "Circuit breakers resetados.", "processStatus": "Status do processo", - "online": "Online", - "offline": "Offline", + "online": "On-line", + "offline": "Off-line", "pid": "PID", "sessionUptime": "Uptime da sessão", "lastHeartbeat": "Último heartbeat", @@ -1399,7 +1397,7 @@ "resetAllBreakers": "Resetar todos os breakers", "toolsAndScopes": "Ferramentas e scopes", "tableTool": "Ferramenta", - "tableScopes": "Scopes", + "tableScopes": "Escopos", "tablePhase": "Fase", "tableAudit": "Auditoria", "auditLog": "Log de auditoria", @@ -1411,7 +1409,7 @@ "apiKeyIdPlaceholder": "apiKeyId", "loadingAuditEntries": "Carregando registros de auditoria...", "noAuditEntriesForFilters": "Nenhum registro de auditoria para os filtros atuais.", - "tableTimestamp": "Timestamp", + "tableTimestamp": "Carimbo de data e hora", "tableDuration": "Duração", "tableResult": "Resultado", "tableApiKey": "Chave API", @@ -1426,7 +1424,7 @@ "cancelTaskSuccess": "Tarefa {taskId} cancelada.", "smokeSendFailed": "Falha no smoke test de message/send.", "smokeSendSuccessWithTask": "message/send ok (tarefa {taskId}).", - "smokeSendSuccess": "message/send ok.", + "smokeSendSuccess": "mensagem/enviar ok.", "smokeStreamFailed": "Falha no smoke test de message/stream.", "smokeStreamSuccessWithTask": "message/stream ok (tarefa {taskId}{stateSuffix}).", "smokeStreamNoTaskId": "message/stream finalizado sem task id.", @@ -1459,7 +1457,7 @@ "loadingTasks": "Carregando tarefas...", "noTasksForFilters": "Nenhuma tarefa encontrada para os filtros atuais.", "tableTask": "Tarefa", - "tableSkill": "Skill", + "tableSkill": "Habilidade", "tableState": "Estado", "tableUpdated": "Atualizada", "tableActions": "Ações", @@ -1492,11 +1490,11 @@ "content": "Conteúdo", "created": "Criado", "actions": "Ações", - "factual": "Factual", + "factual": "Fato", "episodic": "Episódica", - "procedural": "Procedural", + "procedural": "Processual", "semantic": "Semântica", - "delete": "Delete" + "delete": "Excluir" }, "skills": { "title": "Skills", @@ -1520,7 +1518,7 @@ "cpuLimitDesc": "Tempo máximo de execução por skill", "memoryLimit": "Limite de Memória", "memoryLimitDesc": "Alocação máxima de memória", - "timeout": "Timeout", + "timeout": "Tempo esgotado", "timeoutDesc": "Tempo máximo de espera por resposta", "networkAccess": "Acesso à Rede", "networkAccessDesc": "Permitir requisições de rede de saída" @@ -1534,7 +1532,7 @@ "uptime": "Tempo Ativo", "memory": "Memória", "memoryRss": "Memória (RSS)", - "heap": "Heap", + "heap": "Pilha", "cpu": "CPU", "database": "Banco de Dados", "version": "Versão", @@ -1552,7 +1550,7 @@ "updatedAt": "Atualizado {time}", "latency": "Latência", "latencyP50": "p50", - "latencyP95": "p95", + "latencyP95": "pág.95", "latencyP99": "p99", "millisecondsShort": "{value}ms", "notAvailable": "—", @@ -1575,12 +1573,12 @@ "providers": "Provedores", "configuredProvidersLabel": "Configurado no painel", "configuredProvidersHint": "Provedores com credenciais salvas em /dashboard/providers, independentemente do estado do tempo de execução.", - "activeProviders": "{count} active", + "activeProviders": "{count} ativo", "activeProvidersHint": "Provedores configurados atualmente habilitados para solicitações de roteamento.", - "monitoredProviders": "{count} monitored", + "monitoredProviders": "{count} monitorado", "monitoredProvidersHint": "Provedores atualmente monitorados por monitores de integridade dos disjuntores.", "healthyCount": "{count} saudáveis", - "nodeVersion": "Node {version}", + "nodeVersion": "Nó {version}", "failures": "{count} falha", "failuresPlural": "{count} falhas", "lastFailure": "Última", @@ -1613,7 +1611,7 @@ "dailyLimit": "Limite Diário" }, "logs": { - "title": "Logs", + "title": "Registros", "requestLogs": "Logs de Requisições", "proxyLogs": "Logs do Proxy", "auditLog": "Log de Auditoria", @@ -1725,12 +1723,12 @@ "testSuccess": "Conexão bem-sucedida", "testFailed": "Falha na conexão", "available": "Disponível", - "cooldown": "Cooldown", + "cooldown": "Esfriar", "unavailable": "Indisponível", "unknown": "Desconhecido", "oauthLabel": "OAuth", "compatibleLabel": "Compatível", - "chat": "Chat", + "chat": "Bater papo", "responses": "Responses", "messages": "Mensagens", "oauthProviders": "Provedores OAuth", @@ -1852,7 +1850,7 @@ "openaiCompatibleDetails": "Detalhes Compatível OpenAI", "messagesApi": "API de Mensagens", "responsesApi": "API de Respostas", - "chatCompletions": "Chat Completions", + "chatCompletions": "Conclusões de bate-papo", "importingModels": "Importando...", "importFromModels": "Importar de /models", "allModelsAlreadyImported": "Todos os modelos já foram importados", @@ -1902,13 +1900,13 @@ "importDoneCount": "✓ Concluído! {count, plural, one {# modelo importado.} other {# modelos importados.}}", "unexpectedErrorOccurred": "Ocorreu um erro inesperado", "connectionCountLabel": "{count, plural, one {# conexão} other {# conexões}}", - "messagesPath": "messages", + "messagesPath": "mensagens", "responsesPath": "responses", - "chatCompletionsPath": "chat/completions", + "chatCompletionsPath": "bate-papo/conclusões", "add": "Adicionar", "edit": "Editar", "delete": "Excluir", - "anthropic": "Anthropic", + "anthropic": "Antrópico", "openai": "OpenAI", "singleConnectionPerCompatible": "Apenas uma conexão é permitida por nó compatível. Adicione outro nó se precisar de mais conexões.", "connections": "Conexões", @@ -1920,8 +1918,8 @@ "addFirstConnectionHint": "Adicione sua primeira conexão para começar", "addConnection": "Adicionar Conexão", "availableModels": "Modelos Disponíveis", - "builtInModels": "Built-in models", - "builtInModelsHint": "Registry models for this provider. Use the pencil to set compatibility options.", + "builtInModels": "Modelos integrados", + "builtInModelsHint": "Modelos de registro para este provedor. Use o lápis para definir as opções de compatibilidade.", "pageAutoRefresh": "A página será atualizada automaticamente...", "statusDisabled": "desativado", "statusConnected": "conectado", @@ -1939,7 +1937,7 @@ "errorTypeMissingCredential": "Credencial ausente", "errorTypeRefreshFailed": "Falha ao renovar", "errorTypeTokenExpired": "Token expirado", - "errorTypeRateLimited": "Rate limited", + "errorTypeRateLimited": "Taxa limitada", "errorTypeUpstreamUnavailable": "Upstream indisponível", "errorTypeNetworkError": "Erro de rede", "errorTypeTestUnsupported": "Teste não suportado", @@ -1948,7 +1946,7 @@ "proxySourceProvider": "Provedor", "proxySourceKey": "Chave", "proxyConfiguredBySource": "Proxy ({source}): {host}", - "autoPriority": "Auto: {priority}", + "autoPriority": "Automático: {priority}", "proxy": "Proxy", "retestAuthentication": "Retestar autenticação", "retest": "Retestar", @@ -1962,26 +1960,26 @@ "openRouterModelPlaceholder": "anthropic/claude-3-opus", "customModels": "Modelos Personalizados", "customModelsHint": "Adicione IDs de modelo que não estão na lista padrão. Eles ficarão disponíveis para roteamento.", - "normalizeToolCallIdLabel": "Normalize tool call IDs to 9 characters (e.g. Mistral)", - "preserveDeveloperRoleLabel": "Keep OpenAI Responses developer role (do not map to system)", - "compatAdjustmentsTitle": "Compatibility", - "compatButtonLabel": "Compatibility", - "compatToolIdShort": "Tool ID 9", - "compatDeveloperShort": "Developer role", - "compatDoNotPreserveDeveloper": "Do not preserve developer role", - "compatBadgeNoPreserve": "No preserve", - "compatProtocolLabel": "Client request protocol", - "compatProtocolHint": "These options apply when OmniRoute detects this request shape (OpenAI Chat, Responses API, or Anthropic Messages).", - "compatProtocolOpenAI": "OpenAI Chat Completions", - "compatProtocolOpenAIResponses": "OpenAI Responses API", - "compatProtocolClaude": "Anthropic Messages", - "compatUpstreamHeadersLabel": "Extra upstream headers", - "compatUpstreamHeadersHint": "High-privilege setting — same trust level as editing provider API credentials; only trusted admins should use it. Merged after OmniRoute adds auth from the provider API key. If a custom header uses the same name as an existing one (e.g. Authorization), your value fully replaces the auto-generated header (including the Bearer token) — the upstream only sees what you typed, not the key from settings. Misconfiguration can cause 401 or broken upstream auth. One row per header (e.g. extra Authentication for some gateways). Hover or focus the value to preview. Saves on blur, outside click, or closing this panel.", - "compatUpstreamHeaderName": "Header name", - "compatUpstreamHeaderValue": "Value", - "compatUpstreamAddRow": "Add header", - "compatUpstreamRemoveRow": "Remove row", - "compatBadgeUpstreamHeaders": "Headers", + "normalizeToolCallIdLabel": "Normalize os IDs de chamada de ferramenta para 9 caracteres (por exemplo, Mistral)", + "preserveDeveloperRoleLabel": "Manter a função de desenvolvedor do OpenAI Responses (não mapear para o sistema)", + "compatAdjustmentsTitle": "Compatibilidade", + "compatButtonLabel": "Compatibilidade", + "compatToolIdShort": "ID da ferramenta 9", + "compatDeveloperShort": "Função do desenvolvedor", + "compatDoNotPreserveDeveloper": "Não preserve a função de desenvolvedor", + "compatBadgeNoPreserve": "Sem conserva", + "compatProtocolLabel": "Protocolo de solicitação do cliente", + "compatProtocolHint": "Essas opções se aplicam quando o OmniRoute detecta esse formato de solicitação (OpenAI Chat, Responses API ou Anthropic Messages).", + "compatProtocolOpenAI": "Conclusões do bate-papo OpenAI", + "compatProtocolOpenAIResponses": "API de respostas OpenAI", + "compatProtocolClaude": "Mensagens Antrópicas", + "compatUpstreamHeadersLabel": "Cabeçalhos extras upstream", + "compatUpstreamHeadersHint": "Configuração de alto privilégio — mesmo nível de confiança da edição das credenciais da API do provedor; apenas administradores confiáveis devem usá-lo. Mesclado depois que o OmniRoute adiciona autenticação da chave de API do provedor. Se um cabeçalho personalizado usar o mesmo nome de um existente (por exemplo, Autorização), seu valor substituirá totalmente o cabeçalho gerado automaticamente (incluindo o token do portador) — o upstream verá apenas o que você digitou, não a chave das configurações. A configuração incorreta pode causar 401 ou autenticação upstream interrompida. Uma linha por cabeçalho (por exemplo, autenticação extra para alguns gateways). Passe o mouse ou foque o valor para visualizar. Salva no desfoque, clique externo ou fechamento deste painel.", + "compatUpstreamHeaderName": "Nome do cabeçalho", + "compatUpstreamHeaderValue": "Valor", + "compatUpstreamAddRow": "Adicionar cabeçalho", + "compatUpstreamRemoveRow": "Remover linha", + "compatBadgeUpstreamHeaders": "Cabeçalhos", "modelId": "ID do Modelo", "customModelPlaceholder": "ex.: gpt-4.5-turbo", "loading": "Carregando...", @@ -2014,8 +2012,8 @@ "save": "Salvar", "editConnection": "Editar Conexão", "accountName": "Nome da conta", - "email": "Email", - "healthCheckMinutes": "Health Check (min)", + "email": "E-mail", + "healthCheckMinutes": "Verificação de integridade (min)", "healthCheckHint": "Intervalo proativo de renovação de token. 0 = desativado.", "selectAllModels": "Selecionar todos", "deselectAllModels": "Desmarcar todos", @@ -2040,17 +2038,17 @@ "codexAuthExportFailed": "Falha ao exportar o auth.json do Codex", "advancedSettings": "Configurações Avançadas", "chatPathLabel": "Caminho do Endpoint de Chat", - "chatPathPlaceholder": "/chat/completions", + "chatPathPlaceholder": "/chat/conclusões", "chatPathHint": "Caminho de chat personalizado para provedores com APIs fora do padrão (ex.: /v4/chat/completions)", "modelsPathLabel": "Caminho do Endpoint de Models", - "modelsPathPlaceholder": "/models", + "modelsPathPlaceholder": "/modelos", "modelsPathHint": "Caminho de models personalizado para validação (ex.: /v4/models)", "statusDeactivated": "Desativado (Manual)", "statusBanned": "Banido / Sandbox Violation", "statusCreditsExhausted": "Saldo Insuficiente", "modelsImported": "{count} modelos importados", "close": "Fechar", - "embeddings": "Embeddings", + "embeddings": "Incorporações", "audioSpeech": "Áudio para Fala", "imagesGenerations": "Geração de Imagens", "repairEnv": "Reparar env", @@ -2186,7 +2184,7 @@ "resilience": "Resiliência", "systemPrompt": "Prompt do Sistema", "thinkingBudget": "Orçamento de Raciocínio", - "proxy": "Proxy", + "proxy": "Procurador", "pricing": "Preços", "storage": "Armazenamento", "policies": "Políticas", @@ -2198,8 +2196,8 @@ "darkMode": "Modo Escuro", "lightMode": "Modo Claro", "systemTheme": "Tema do Sistema", - "debugToggle": "Enable Debug Mode", - "sidebarVisibilityToggle": "Show Sidebar Items", + "debugToggle": "Habilitar modo de depuração", + "sidebarVisibilityToggle": "Mostrar itens da barra lateral", "enableCache": "Ativar Cache", "cacheTTL": "TTL do Cache", "maxCacheSize": "Tamanho Máximo do Cache", @@ -2208,28 +2206,28 @@ "cacheMisses": "Erros de Cache", "hitRate": "Taxa de Acerto", "cacheEntries": "Entradas no Cache", - "cacheSettings": "Cache Settings", - "semanticCache": "Semantic Cache", - "maxEntries": "Max Entries", - "ttlMinutes": "TTL (minutes)", + "cacheSettings": "Configurações de cache", + "semanticCache": "Cache Semântico", + "maxEntries": "Máximo de entradas", + "ttlMinutes": "TTL (minutos)", "promptCache": "Cache de Prompt", - "strategy": "Strategy", - "preserveClientCache": "Preserve Client Cache", - "enabled": "Enabled", - "loading": "Loading...", + "strategy": "Estratégia", + "preserveClientCache": "Preservar cache do cliente", + "enabled": "Habilitado", + "loading": "Carregando...", "saving": "Salvando...", - "save": "Save", + "save": "Salvar", "circuitBreaker": "Disjuntor", "retryPolicy": "Política de Retentativa", "maxRetries": "Máximo de Tentativas", "retryDelay": "Intervalo de Retentativa", - "timeoutMs": "Timeout (ms)", + "timeoutMs": "Tempo limite (ms)", "enableSystemPrompt": "Ativar Prompt do Sistema", "systemPromptText": "Texto do Prompt do Sistema", - "autoDisableBannedAccounts": "Auto-Disable Banned Accounts", - "autoDisableDescription": "Permanently mark provider connections as deactivated if they return specific terminal ban signals (e.g. HTTP 403 'verify your account'). This removes them from the combo rotation.", - "autoDisableThreshold": "Ban Threshold", - "autoDisableThresholdDesc": "Consecutive ban signals required before permanent deactivation.", + "autoDisableBannedAccounts": "Desativar automaticamente contas banidas", + "autoDisableDescription": "Marcar permanentemente as conexões do provedor como desativadas se elas retornarem sinais específicos de proibição de terminal (por exemplo, HTTP 403 'verifique sua conta'). Isso os remove da rotação combinada.", + "autoDisableThreshold": "Limite de proibição", + "autoDisableThresholdDesc": "Sinais de banimento consecutivos necessários antes da desativação permanente.", "enableThinking": "Ativar Raciocínio", "maxThinkingTokens": "Máximo de Tokens de Raciocínio", "enableProxy": "Ativar Proxy", @@ -2290,7 +2288,7 @@ "themeLight": "Claro", "themeDark": "Escuro", "themeSystem": "Sistema", - "sidebarVisibility": "Hide sidebar items", + "sidebarVisibility": "Ocultar itens da barra lateral", "sidebarVisibilityDesc": "Hide any sidebar navigation entry to reduce visual clutter.", "sidebarVisibilityHint": "Any sidebar section is hidden automatically when a...", "hideHealthLogs": "Ocultar Logs de Health Check", @@ -2305,20 +2303,20 @@ "themeViolet": "Violeta", "themeOrange": "Laranja", "themeCyan": "Ciano", - "whitelabeling": "Branding", - "whitelabelingDesc": "Customize the application name and logo", - "appName": "Application Name", - "appNameDesc": "Display name shown in sidebar and browser tab", - "customLogo": "Custom Logo URL", - "customLogoDesc": "URL to your custom logo image", - "uploadLogo": "Upload Logo", - "resetLogo": "Reset to Default", - "logoPreview": "Preview", - "customFavicon": "Browser Favicon", - "customFaviconDesc": "URL to your custom favicon (shown in browser tab)", - "uploadFavicon": "Upload Favicon", - "resetFavicon": "Reset Favicon", - "faviconPreview": "Favicon Preview", + "whitelabeling": "Marca", + "whitelabelingDesc": "Personalize o nome e o logotipo do aplicativo", + "appName": "Nome do aplicativo", + "appNameDesc": "Nome de exibição mostrado na barra lateral e na guia do navegador", + "customLogo": "URL do logotipo personalizado", + "customLogoDesc": "URL para a imagem do seu logotipo personalizado", + "uploadLogo": "Carregar logotipo", + "resetLogo": "Redefinir para o padrão", + "logoPreview": "Visualização", + "customFavicon": "Favicon do navegador", + "customFaviconDesc": "URL para seu favicon personalizado (mostrado na guia do navegador)", + "uploadFavicon": "Carregar Favicon", + "resetFavicon": "Redefinir ícone favorito", + "faviconPreview": "Visualização do favicon", "flushCache": "Limpar Cache", "flushing": "Limpando…", "size": "Tamanho", @@ -2340,7 +2338,7 @@ "thinkingBudgetDesc": "Controle o uso de tokens de raciocínio da IA em todas as requisições", "passthrough": "Passagem Direta", "passthroughDesc": "Sem alterações — cliente controla orçamento de raciocínio", - "auto": "Auto Combo", + "auto": "Combinação automática", "autoDesc": "Pool de roteamento inteligente (Otimizado)", "custom": "Personalizado", "customDesc": "Define um orçamento fixo de tokens para todas as requisições", @@ -2351,7 +2349,7 @@ "effortMedium": "Médio (10K tokens)", "effortHigh": "Alto (128K tokens)", "tokenBudget": "Orçamento de Tokens", - "tokens": "tokens", + "tokens": "fichas", "baseEffortLevel": "Nível de Esforço Base", "adaptiveHint": "Modo adaptativo escala a partir deste nível base baseado na quantidade de mensagens, uso de ferramentas e tamanho do prompt.", "requireLogin": "Exigir login", @@ -2387,7 +2385,7 @@ "routingAdvancedGuideHint2": "Se os fornecedores variarem em qualidade/custo, comece com Opção de custo para trabalho em segundo plano e Menos usado para desgaste equilibrado.", "fillFirst": "Preencher Primeiro", "fillFirstDesc": "Usar contas em ordem de prioridade", - "roundRobin": "Round Robin", + "roundRobin": "Rodada Robin", "roundRobinDesc": "Ciclar entre todas as contas", "p2c": "P2C", "p2cDesc": "Escolher 2 aleatórias, usar a mais saudável", @@ -2403,7 +2401,7 @@ "stickyLimitDesc": "Chamadas por conta antes de trocar", "modelAliases": "Aliases de Modelo", "modelAliasesTitle": "Aliases de Modelo", - "modelAliasesDesc": "Remap model names using exact matches or wildcard patterns.", + "modelAliasesDesc": "Remapear nomes de modelos usando correspondências exatas ou padrões curinga.", "addCustomAlias": "Adicionar Alias Personalizado", "deprecatedModelId": "ID do modelo depreciado", "newModelId": "Novo ID do modelo", @@ -2419,8 +2417,8 @@ "cheapModel": "Modelo barato", "detectionPatterns": "Padrões de Detecção", "newPattern": "ex: \"gerar um título\"", - "aliasPatternPlaceholder": "claude-sonnet-*", - "aliasTargetPlaceholder": "claude-sonnet-4-20250514", + "aliasPatternPlaceholder": "claude-soneto-*", + "aliasTargetPlaceholder": "claude-soneto-4-20250514", "pattern": "Padrão", "targetModel": "Modelo Alvo", "add": "+ Adicionar", @@ -2463,9 +2461,9 @@ "fallbackChainsDesc": "Definir ordem de fallback de provedores por modelo", "addChain": "+ Adicionar Cadeia", "modelName": "Nome do Modelo", - "modelNamePlaceholder": "claude-sonnet-4-20250514", + "modelNamePlaceholder": "claude-soneto-4-20250514", "providersCommaSeparated": "Provedores (separados por vírgula, em ordem de prioridade)", - "providersCommaSeparatedPlaceholder": "anthropic, openai, gemini", + "providersCommaSeparatedPlaceholder": "antrópico, openai, gêmeos", "createChain": "Criar Cadeia", "noFallbackChains": "Sem Cadeias de Fallback", "noFallbackChainsDesc": "Crie uma cadeia para definir a ordem de fallback de provedores para um modelo.", @@ -2488,11 +2486,11 @@ "comboStrategyAria": "Estratégia de combo", "priority": "Prioridade", "weighted": "Ponderado", - "contextRelay": "Context Relay", + "contextRelay": "Retransmissão de Contexto", "contextRelayDesc": "Roteamento estilo prioridade com handoffs automáticos de contexto quando a conta gira", "maxRetriesLabel": "Máx. Tentativas", "retryDelayLabel": "Atraso entre Tentativas (ms)", - "timeoutLabel": "Timeout (ms)", + "timeoutLabel": "Tempo limite (ms)", "healthCheck": "Verificação de Saúde", "healthCheckDesc": "Verificar disponibilidade do provedor antes", "trackMetrics": "Rastrear Métricas", @@ -2672,54 +2670,54 @@ "memorySkillsDesc": "Contexto persistente e capacidades A2A", "purgeExpiredLogs": "Purgar Logs Expirados", "purgeLogsFailed": "Falha ao purgar logs", - "modelsDevTitle": "Model Database", - "modelsDevDesc": "Auto-sync pricing, capabilities & specs from models.dev", - "modelsDevEnabled": "Enable models.dev Sync", - "modelsDevEnabledDesc": "Fetch model pricing, capabilities, and specs from the open-source models.dev database", - "modelsDevInterval": "Sync Interval", - "syncNow": "Sync Now", - "syncing": "Syncing...", - "lastSync": "Last sync", - "never": "Never", - "modelsDevStats": "Sync Statistics", - "modelsDevStatsDesc": "Current models.dev data coverage", - "modelsWithPricing": "Models with Pricing", - "capabilities": "Capabilities", - "lastSyncCount": "Last Sync Count", - "lastSyncFull": "Last full sync", - "modelsDevInfo": "How It Works", - "modelsDevInfoDesc": "models.dev is an open-source database of AI model specifications maintained by the SST/OpenCode team. It provides pricing, capabilities, context limits, and modalities for 4,000+ models across 100+ providers.", - "modelsDevInfoResolution": "Pricing resolution order (highest priority first):", - "modelsDevInfoOrder": "User Override → models.dev → LiteLLM → Hardcoded Default", - "cacheCleared": "Cache cleared successfully", - "clearCacheFailed": "Failed to clear cache", - "lkgpToggleTitle": "Last Known Good Provider (LKGP)", - "lkgpToggleDesc": "When enabled, the router remembers which provider last served a successful response and tries it first on subsequent requests.", - "clearLkgpCache": "Clear LKGP Cache", - "lkgpCacheCleared": "LKGP cache cleared successfully", - "lkgpCacheClearFailed": "Failed to clear LKGP cache", - "maintenance": "Maintenance", - "contextOpt": "Context Optimized", - "contextOptDesc": "Routes based on context window requirements and conversation length", - "priorityDesc": "Sequential fallback - tries provider 1 first, then provider 2, and so on", - "weightedDesc": "Distributes traffic by percentage weights across providers", - "modelRoutingTitle": "Model Routing Rules", - "modelRoutingDesc": "Automatically route models to specific combos using glob patterns", - "addRule": "Add Rule", - "routeToCombo": "Route to Combo", - "selectCombo": "Select combo...", - "priorityHint": "Higher = checked first. Use 10+ for specific patterns.", - "patternHint": "Use * for any chars, ? for single char. Case-insensitive.", - "noRoutingRules": "No routing rules configured. Requests use the global combo by default.", - "routingRuleHint": "Add a rule like claude-opus* -> frontier-combo to automatically route requests.", - "deleteRoutingRule": "Delete this model routing rule?", - "exactMatchMode": "Exact Match", - "wildcardPatternMode": "Wildcard Pattern", - "exactMatchModeDesc": "Use exact aliases for deprecated or renamed model IDs.", - "wildcardPatternModeDesc": "Use wildcard aliases with * and ? when a family of models should map to one target.", - "noExactAliasesConfigured": "No exact-match aliases configured.", - "wildcardRulesTitle": "Wildcard Rules", - "noWildcardAliasesConfigured": "No wildcard aliases configured." + "modelsDevTitle": "Banco de dados modelo", + "modelsDevDesc": "Preços, recursos e especificações de sincronização automática de models.dev", + "modelsDevEnabled": "Ativar sincronização de models.dev", + "modelsDevEnabledDesc": "Obtenha preços, recursos e especificações do modelo no banco de dados models.dev de código aberto", + "modelsDevInterval": "Intervalo de sincronização", + "syncNow": "Sincronizar agora", + "syncing": "Sincronizando...", + "lastSync": "Última sincronização", + "never": "Nunca", + "modelsDevStats": "Sincronizar estatísticas", + "modelsDevStatsDesc": "Cobertura de dados atual do models.dev", + "modelsWithPricing": "Modelos com preços", + "capabilities": "Capacidades", + "lastSyncCount": "Contagem da última sincronização", + "lastSyncFull": "Última sincronização completa", + "modelsDevInfo": "Como funciona", + "modelsDevInfoDesc": "models.dev é um banco de dados de código aberto de especificações de modelos de IA mantido pela equipe SST/OpenCode. Ele fornece preços, recursos, limites de contexto e modalidades para mais de 4.000 modelos em mais de 100 fornecedores.", + "modelsDevInfoResolution": "Ordem de resolução de preços (prioridade mais alta primeiro):", + "modelsDevInfoOrder": "Substituição do usuário → models.dev → LiteLLM → Padrão codificado", + "cacheCleared": "Cache limpo com sucesso", + "clearCacheFailed": "Falha ao limpar o cache", + "lkgpToggleTitle": "Último provedor válido conhecido (LKGP)", + "lkgpToggleDesc": "Quando ativado, o roteador lembra qual provedor atendeu pela última vez uma resposta bem-sucedida e tenta primeiro nas solicitações subsequentes.", + "clearLkgpCache": "Limpar cache LKGP", + "lkgpCacheCleared": "Cache LKGP limpo com sucesso", + "lkgpCacheClearFailed": "Falha ao limpar o cache LKGP", + "maintenance": "Manutenção", + "contextOpt": "Contexto otimizado", + "contextOptDesc": "Rotas baseadas nos requisitos da janela de contexto e na duração da conversa", + "priorityDesc": "Fallback sequencial - tenta primeiro o provedor 1, depois o provedor 2 e assim por diante", + "weightedDesc": "Distribui o tráfego por pesos percentuais entre provedores", + "modelRoutingTitle": "Regras de roteamento de modelo", + "modelRoutingDesc": "Roteie modelos automaticamente para combos específicos usando padrões glob", + "addRule": "Adicionar regra", + "routeToCombo": "Rota para Combo", + "selectCombo": "Selecione a combinação...", + "priorityHint": "Maior = verificado primeiro. Use 10+ para padrões específicos.", + "patternHint": "Use * para qualquer caractere, ? para um único caractere. Não diferencia maiúsculas de minúsculas.", + "noRoutingRules": "Nenhuma regra de roteamento configurada. As solicitações usam o combo global por padrão.", + "routingRuleHint": "Adicione uma regra como claude-opus* -> frontier-combo para rotear solicitações automaticamente.", + "deleteRoutingRule": "Excluir esta regra de roteamento de modelo?", + "exactMatchMode": "Correspondência exata", + "wildcardPatternMode": "Padrão curinga", + "exactMatchModeDesc": "Use aliases exatos para IDs de modelos obsoletos ou renomeados.", + "wildcardPatternModeDesc": "Use aliases curinga com * e ? quando uma família de modelos deve ser mapeada para um alvo.", + "noExactAliasesConfigured": "Nenhum aliase de correspondência exata configurado.", + "wildcardRulesTitle": "Regras curinga", + "noWildcardAliasesConfigured": "Nenhum aliase curinga configurado." }, "translator": { "title": "Tradutor", @@ -2785,7 +2783,7 @@ "passed": "aprovados", "failed": "falharam", "passedIconLabel": "✅ Aprovado", - "chunks": "chunks", + "chunks": "pedaços", "scenarioSimpleChat": "Chat Simples", "scenarioToolCalling": "Chamada de Ferramenta", "scenarioMultiTurn": "Multiturno", @@ -3125,7 +3123,7 @@ "loadingQuotas": "Carregando...", "account": "Conta", "modelQuotas": "Cotas de Modelo", - "lastUsed": "Last Refreshed", + "lastUsed": "Última atualização", "actions": "Ações", "refreshQuota": "Atualizar cota", "today": "Hoje", @@ -3142,9 +3140,9 @@ "noQuotaDataAvailable": "Nenhum dado de cota disponível", "noAccountsForTierFilter": "Nenhuma conta encontrada para o filtro de plano", "tierAll": "Todos", - "tierEnterprise": "Enterprise", - "tierTeam": "Team", - "tierBusiness": "Business", + "tierEnterprise": "Empresa", + "tierTeam": "Equipe", + "tierBusiness": "Negócios", "tierUltra": "Ultra", "tierPro": "Pro", "tierPlus": "Plus", @@ -3159,8 +3157,8 @@ "connectedSuccess": "Conectado com Sucesso!", "connectionFailed": "Falha na Conexão", "chooseAuthMethod": "Escolha seu método de autenticação:", - "awsBuilderId": "AWS Builder ID", - "awsIamIdentity": "AWS IAM Identity Center", + "awsBuilderId": "ID do construtor AWS", + "awsIamIdentity": "Centro de identidade AWS IAM", "googleAccount": "Conta Google", "githubAccount": "Conta GitHub", "importToken": "Importar Token", @@ -3190,10 +3188,10 @@ "noLogEntries": "Nenhuma entrada de log encontrada", "noPayloadData": "Nenhum dado de payload disponível para esta entrada.", "proxyEvent": "Evento do Proxy", - "proxy": "Proxy", + "proxy": "Procurador", "level": "Nível", "directNative": "Direto (nativo)", - "combo": "Combo", + "combo": "Combinação", "inputTokens": "E:", "outputTokens": "S:" }, @@ -3205,7 +3203,7 @@ "usageByAccount": "Uso por Conta", "failedToLoad": "Falha ao carregar estatísticas de uso.", "tokenHealth": "Saúde dos Tokens", - "totalOAuth": "Total OAuth", + "totalOAuth": "OAuth total", "healthy": "Saudável", "warning": "Aviso", "errored": "Com Erro", @@ -3268,7 +3266,7 @@ "restartServerWithNewPassword": "Reinicie o servidor - ele usará a nova senha", "backToLogin": "Voltar para o Login", "forgotPassword": "Esqueceu a senha?", - "defaultPasswordHint": "Default password: CHANGEME (unless INITIAL_PASSWORD was set)", + "defaultPasswordHint": "Senha padrão: CHANGEME (a menos que INITIAL_PASSWORD tenha sido definido)", "Authorization": "Autorização", "Content-Disposition": "Disposição de conteúdo", "waitingForAuthorization": "Aguardando autorização...", @@ -3277,17 +3275,17 @@ "waitingForAntigravityAuthorization": "Aguardando autorização antigravidade...", "waitingForQoderAuthorization": "Aguardando autorização do Qoder...", "exchangingCodeForTokens": "Trocando código por tokens...", - "nodeIncompatibleTitle": "Incompatible Node.js Version", - "nodeIncompatibleFixLabel": "Fix: install a patched Node.js 22 LTS release", - "nodeIncompatibleDesc": "You are running Node.js {version}, which is outside OmniRoute's supported secure runtime policy. Use a patched Node.js 20.x or 22.x LTS release.", - "nodeIncompatibleHint": "OmniRoute requires Node.js 20.20.2+ (20.x LTS), 22.22.2+ (22.x LTS) or 24.0.0+ (24.x LTS). Node 24 LTS is recommended." + "nodeIncompatibleTitle": "Versão incompatível do Node.js.", + "nodeIncompatibleFixLabel": "Correção: instale uma versão corrigida do Node.js 22 LTS", + "nodeIncompatibleDesc": "Você está executando o Node.js {version}, que está fora da política de tempo de execução segura suportada pelo OmniRoute. Use uma versão corrigida do Node.js 20.x ou 22.x LTS.", + "nodeIncompatibleHint": "OmniRoute requer Node.js 20.20.2+ (20.x LTS), 22.22.2+ (22.x LTS) ou 24.0.0+ (24.x LTS). O nó 24 LTS é recomendado." }, "landing": { "brandName": "OmniRoute", "navigateHome": "Navegar para a página inicial", "toggleMenu": "Alternar menu", "featuresLink": "Recursos", - "docsLink": "Docs", + "docsLink": "Documentos", "github": "GitHub", "versionLive": "v1.0 já está no ar", "oneEndpoint": "Um Endpoint para", @@ -3338,26 +3336,26 @@ "readyToRoute": "Pronto para rotear! ✓", "configureProvidersNote": "📝 Configure provedores no painel ou use variáveis de ambiente", "dataLocation": "Local dos Dados:", - "dataLocationMacLinux": " macOS/Linux:", - "dataLocationWindows": " Windows:", + "dataLocationMacLinux": "macOS/Linux:", + "dataLocationWindows": "Windows:", "product": "Produto", "dashboardLink": "Painel", - "changelog": "Changelog", + "changelog": "Registro de alterações", "resources": "Recursos", "documentation": "Documentação", "npm": "NPM", - "legal": "Legal", + "legal": "Jurídico", "mitLicense": "Licença MIT", "footerTagline": "O endpoint unificado para geração de IA. Conecte, roteie e gerencie seus provedores de IA com facilidade.", "copyright": "© {year} OmniRoute. Todos os direitos reservados.", - "flowToolClaudeCode": "Claude Code", - "flowToolOpenAICodex": "OpenAI Codex", + "flowToolClaudeCode": "Código Claude", + "flowToolOpenAICodex": "Códice OpenAI", "flowToolCline": "Cline", "flowToolCursor": "Cursor", "flowProviderOpenAI": "OpenAI", - "flowProviderAnthropic": "Anthropic", + "flowProviderAnthropic": "Antrópico", "flowProviderGemini": "Gemini", - "flowProviderGithubCopilot": "GitHub Copilot", + "flowProviderGithubCopilot": "Copiloto GitHub", "interactiveDiagram": "Diagrama interativo visível no desktop", "ctaTitle": "Pronto para simplificar sua infraestrutura de IA?", "ctaDescription": "Junte-se a desenvolvedores que estão simplificando suas integrações de IA com o OmniRoute. Open source e grátis para começar.", @@ -3386,7 +3384,7 @@ "supportsChat": "Suporta endpoints de chat e responses.", "oauthAutoRefresh": "Conexão OAuth com atualização automática de token.", "fullStreaming": "Suporte completo a streaming para todos os modelos.", - "docsLabel": "Docs", + "docsLabel": "Documentos", "docsHeroDescription": "Gateway de IA para LLMs multi-provedor. Um endpoint para OpenAI, Anthropic, Gemini, GitHub Copilot, Claude Code, Cursor e mais de 100 provedores.", "openDashboard": "Abrir Painel", "endpointPage": "Página de Endpoint", @@ -3442,7 +3440,7 @@ "useCaseFallbackText": "Crie modelos combo no painel e mantenha a configuração do cliente estável enquanto os provedores giram internamente.", "useCaseUsageVisibilityTitle": "Visibilidade de uso, custo e debug", "useCaseUsageVisibilityText": "Acompanhe tokens e custo por provedor, conta e chave de API nas abas de Uso e Analytics.", - "clientCherryStudioTitle": "Cherry Studio", + "clientCherryStudioTitle": "Estúdio Cereja", "baseUrlLabel": "URL Base", "chatEndpointLabel": "Endpoint de chat", "modelRecommendationLabel": "Recomendação de modelo: prefixo explícito", @@ -3454,8 +3452,8 @@ "clientCursorBullet1": "Use o prefixo", "clientCursorBullet1Suffix": "para modelos do Cursor.", "clientCursorBullet2": "Conexão OAuth - faça login na página de Provedores.", - "clientClaudeTitle": "Claude Code / Antigravity", - "clientClaudeBullet1Prefix": "Use", + "clientClaudeTitle": "Código Claude / Antigravidade", + "clientClaudeBullet1Prefix": "Usar", "clientClaudeBullet1Middle": "(Claude) ou", "clientClaudeBullet1Suffix": "(Antigravity) como prefixo.", "clientWindsurfTitle": "Windsurf", @@ -3472,12 +3470,12 @@ "clientKimiBullet3": "Use `/v1/responses` quando quiser roteamento nativo estilo Responses para clientes com tools.", "protocolsTitle": "Protocolos: MCP, A2A e ACP", "protocolsDescription": "O OmniRoute expõe MCP, A2A e fluxos orientados a workers ACP além das APIs compatíveis com OpenAI.", - "protocolMcpTitle": "MCP (Model Context Protocol)", + "protocolMcpTitle": "MCP (protocolo de contexto de modelo)", "protocolMcpDesc": "Use MCP via stdio para permitir descoberta e execução de ferramentas OmniRoute com visibilidade de auditoria.", "protocolMcpStep1": "Inicie o transporte MCP com `omniroute --mcp`.", "protocolMcpStep2": "Aponte seu cliente MCP para transporte stdio.", "protocolMcpStep3": "Chame `omniroute_get_health` e `omniroute_list_combos` para validar conectividade.", - "protocolA2aTitle": "A2A (Agent2Agent)", + "protocolA2aTitle": "A2A (Agente2Agente)", "protocolA2aDesc": "Use A2A JSON-RPC para submeter tarefas de forma síncrona ou via SSE streaming.", "protocolA2aStep1": "Leia `/.well-known/agent.json` para descoberta do agente.", "protocolA2aStep2": "Envie `message/send` ou `message/stream` para `POST /a2a`.", @@ -3697,95 +3695,95 @@ } }, "cache": { - "title": "Cache Management", + "title": "Gerenciamento de Cache", "description": "Monitor and manage semantic response cache, hit rates, and token savings.", - "refresh": "Refresh", + "refresh": "Atualizar", "clearAll": "Clear All", - "memoryEntries": "Memory Entries", - "memoryEntriesSub": "In-memory LRU", - "dbEntries": "DB Entries", - "dbEntriesSub": "Persisted (SQLite)", - "cacheHits": "Cache Hits", - "cacheHitsSub": "of {total} total", - "tokensSaved": "Tokens Saved", - "tokensSavedSub": "Estimated from hits", - "hitRate": "Hit Rate", - "performance": "Cache Performance", - "autoRefresh": "Auto-refreshes every {seconds}s", - "hits": "Hits", - "misses": "Misses", + "memoryEntries": "Entradas de memória", + "memoryEntriesSub": "LRU na memória", + "dbEntries": "Entradas do banco de dados", + "dbEntriesSub": "Persistido (SQLite)", + "cacheHits": "Acessos de cache", + "cacheHitsSub": "do total de {total}", + "tokensSaved": "Tokens salvos", + "tokensSavedSub": "Estimado a partir de hits", + "hitRate": "Taxa de acerto", + "performance": "Desempenho do cache", + "autoRefresh": "Atualiza automaticamente a cada {seconds}s", + "hits": "Acessos", + "misses": "Falta", "total": "Total", - "behavior": "Cache Behavior", - "behaviorDeterministic": "Only non-streaming requests with temperature=0 are cached.", - "behaviorBypass": "Bypass with header {header}.", - "behaviorTwoTier": "Two-tier storage: in-memory LRU (fast) + SQLite (persistent across restarts).", - "behaviorTtl": "Default TTL: 30 minutes. Configure via {envVar}.", - "idempotency": "Idempotency Layer", - "activeDedupKeys": "Active Dedup Keys", - "dedupWindow": "Dedup Window", + "behavior": "Comportamento do cache", + "behaviorDeterministic": "Somente solicitações sem streaming com temperatura=0 são armazenadas em cache.", + "behaviorBypass": "Ignorar com cabeçalho {header}.", + "behaviorTwoTier": "Armazenamento em duas camadas: LRU na memória (rápido) + SQLite (persistente nas reinicializações).", + "behaviorTtl": "TTL padrão: 30 minutos. Configurar via {envVar}.", + "idempotency": "Camada de Idempotência", + "activeDedupKeys": "Chaves de eliminação de duplicação ativas", + "dedupWindow": "Janela de eliminação de duplicação", "clearSuccess": "Cache cleared. {count} expired entries removed.", - "clearError": "Failed to clear cache.", - "unavailable": "Cache unavailable", - "unavailableDesc": "Could not fetch cache statistics. Make sure the server is running.", - "promptCache": "Prompt Cache (Provider-Side)", - "cachedRequests": "Cached Requests", - "cacheHitRate": "Cache Hit Rate", + "clearError": "Falha ao limpar o cache.", + "unavailable": "Cache indisponível", + "unavailableDesc": "Não foi possível buscar estatísticas de cache. Certifique-se de que o servidor esteja em execução.", + "promptCache": "Cache de prompt (lado do provedor)", + "cachedRequests": "Solicitações em cache", + "cacheHitRate": "Taxa de acertos do cache", "cachedTokens": "Cached Tokens", "cacheCreationTokens": "Cache Creation Tokens", - "cacheMetrics": "Prompt Cache Metrics", - "withCacheControl": "With Cache Control", + "cacheMetrics": "Métricas de cache de prompt", + "withCacheControl": "Com controle de cache", "cachedTokensRead": "Cached Tokens (Read)", "cacheCreationWrite": "Cache Creation (Write)", - "cacheReuseRatio": "Cache Reuse Ratio", + "cacheReuseRatio": "Taxa de reutilização de cache", "cacheReuseRatioDesc": "Cached tokens / Total input tokens", - "estCostSaved": "Est. Cost Saved", - "requestsShort": "reqs", + "estCostSaved": "Husa. Custo economizado", + "requestsShort": "requisitos", "inputShort": "In", - "cachedShort": "Cached", - "writeShort": "Write", - "resetting": "Resetting...", - "resetMetrics": "Reset Metrics", - "byProvider": "Breakdown by Provider", - "provider": "Provider", - "requests": "Requests", + "cachedShort": "Em cache", + "writeShort": "Escrever", + "resetting": "Redefinindo...", + "resetMetrics": "Redefinir métricas", + "byProvider": "Divisão por provedor", + "provider": "Provedor", + "requests": "Solicitações", "inputTokens": "Input Tokens", "cachedTokensCol": "Cached", "cacheCreation": "Creation", - "trend24h": "Cache Trend (24h)", - "cached": "Cached", - "overview": "Overview", - "entries": "Entries", - "searchEntries": "Search entries...", - "search": "Search", - "loading": "Loading...", - "noEntries": "No cache entries found", - "signature": "Signature", - "model": "Model", - "created": "Created", - "expires": "Expires", - "actions": "Actions", + "trend24h": "Tendência de Cache (24h)", + "cached": "Em cache", + "overview": "Visão geral", + "entries": "Entradas", + "searchEntries": "Pesquisar entradas...", + "search": "Procurar", + "loading": "Carregando...", + "noEntries": "Nenhuma entrada de cache encontrada", + "signature": "Assinatura", + "model": "Modelo", + "created": "Criado", + "expires": "Expira", + "actions": "Ações", "deduplicatedRequests": "Requisições Desduplicadas", "savedCalls": "Chamadas API Poupadas", "totalProcessed": "Total Processado", - "peakCached": "Peak cached", - "entriesLoadError": "Failed to load semantic cache entries.", - "peakCacheRate": "Peak Cache Rate", - "semanticCache": "Semantic Cache", - "busiestHour": "Busiest Hour", - "promptTrendDesc": "Hourly request volume, cache coverage, and cache read volume across the last 24 hours.", - "semanticCacheDisabledDesc": "Semantic cache is disabled. OmniRoute will skip local response reuse until you turn it back on in Settings.", - "activityVolume": "Activity", - "cachedRequests24h": "Cached Requests (24h)", - "cacheRate": "Cache Rate", - "semanticCacheSectionDesc": "OmniRoute's own deterministic response cache. When enabled, repeated non-streaming temperature=0 requests can be served locally without hitting the upstream provider.", - "providerCacheRateDesc": "Each provider exposes total input tokens, cache read tokens, and cache write tokens so you can verify the reuse ratio against raw totals.", - "semanticEntriesDesc": "Persisted semantic cache records currently stored in SQLite. Provider-side prompt cache activity is not listed here.", - "lastUpdated": "Last updated", - "hoursTracked": "hours tracked", - "noPromptCacheData": "No provider-side prompt cache activity has been recorded yet.", - "promptCacheSectionDesc": "Shows provider-side prompt caching activity from usage history so you can see where cache control is active and how much input reuse you are getting.", - "trendHour": "Hour", - "noTrendData": "No prompt cache activity has been recorded over the last 24 hours.", - "cacheRateDesc": "of total requests" + "peakCached": "Pico armazenado em cache", + "entriesLoadError": "Falha ao carregar entradas do cache semântico.", + "peakCacheRate": "Taxa máxima de cache", + "semanticCache": "Cache Semântico", + "busiestHour": "Hora mais movimentada", + "promptTrendDesc": "Volume de solicitações por hora, cobertura de cache e volume de leitura de cache nas últimas 24 horas.", + "semanticCacheDisabledDesc": "O cache semântico está desabilitado. O OmniRoute ignorará a reutilização da resposta local até que você o ative novamente nas Configurações.", + "activityVolume": "Atividade", + "cachedRequests24h": "Solicitações em cache (24h)", + "cacheRate": "Taxa de cache", + "semanticCacheSectionDesc": "Cache de resposta determinística próprio do OmniRoute. Quando ativado, solicitações repetidas de temperatura = 0 sem streaming podem ser atendidas localmente sem atingir o provedor upstream.", + "providerCacheRateDesc": "Cada provedor expõe o total de tokens de entrada, tokens de leitura de cache e tokens de gravação de cache para que você possa verificar a proporção de reutilização em relação aos totais brutos.", + "semanticEntriesDesc": "Registros de cache semântico persistentes atualmente armazenados no SQLite. A atividade de cache de prompt do provedor não está listada aqui.", + "lastUpdated": "Última atualização", + "hoursTracked": "horas monitoradas", + "noPromptCacheData": "Nenhuma atividade de cache de prompt do lado do provedor foi registrada ainda.", + "promptCacheSectionDesc": "Mostra a atividade de cache de prompt do provedor a partir do histórico de uso para que você possa ver onde o controle de cache está ativo e quanta reutilização de entrada você está obtendo.", + "trendHour": "Hora", + "noTrendData": "Nenhuma atividade de cache de prompt foi registrada nas últimas 24 horas.", + "cacheRateDesc": "do total de solicitações" } } diff --git a/src/lib/db/core.ts b/src/lib/db/core.ts index 7e85dcafae..96eaf8b209 100644 --- a/src/lib/db/core.ts +++ b/src/lib/db/core.ts @@ -141,6 +141,7 @@ const SCHEMA_SQL = ` rate_limit_protection INTEGER DEFAULT 0, last_used_at TEXT, "group" TEXT, + max_concurrent INTEGER, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); @@ -441,6 +442,13 @@ function ensureProviderConnectionsColumns(db: SqliteDatabase) { db.exec('ALTER TABLE provider_connections ADD COLUMN "group" TEXT'); console.log('[DB] Added provider_connections."group" column'); } + if (!columnNames.has("max_concurrent")) { + db.exec("ALTER TABLE provider_connections ADD COLUMN max_concurrent INTEGER"); + console.log("[DB] Added provider_connections.max_concurrent column"); + } + db.exec( + "CREATE INDEX IF NOT EXISTS idx_pc_max_concurrent ON provider_connections(provider, max_concurrent)" + ); } catch (error: unknown) { const message = error instanceof Error ? error.message : String(error); console.warn("[DB] Failed to verify provider_connections schema:", message); @@ -1165,6 +1173,12 @@ export function getDbInstance(): SqliteDatabase { "combo_sort_order" ); } + if (hasColumn(db, "provider_connections", "max_concurrent")) { + db.prepare("INSERT OR IGNORE INTO _omniroute_migrations (version, name) VALUES (?, ?)").run( + "029", + "provider_connection_max_concurrent" + ); + } if (hasColumn(db, "call_logs", "request_type")) { db.prepare("INSERT OR IGNORE INTO _omniroute_migrations (version, name) VALUES (?, ?)").run( "007", diff --git a/src/lib/oauth/providers/kimi-coding.ts b/src/lib/oauth/providers/kimi-coding.ts index 2d48abdbca..1e9bd9cb29 100644 --- a/src/lib/oauth/providers/kimi-coding.ts +++ b/src/lib/oauth/providers/kimi-coding.ts @@ -1,13 +1,52 @@ import { KIMI_CODING_CONFIG } from "../constants/oauth"; import { randomUUID } from "crypto"; -import { hostname } from "os"; +import fs from "fs"; +import { arch, hostname, release, type as osType, version as osVersion } from "os"; +import path from "path"; +import { resolveDataDir } from "../../dataPaths"; -// Generate device ID (persistent per installation) -const DEVICE_ID = randomUUID(); -const PLATFORM = "omniroute"; -const VERSION = "2.1.2"; -const DEVICE_NAME = hostname(); -const DEVICE_MODEL = `${process.platform} ${process.arch}`; +const PLATFORM = "kimi_cli"; +const VERSION = process.env.KIMI_CLI_VERSION || "1.36.0"; +const DEVICE_ID_FILE = "kimi-coding-device-id"; + +function sanitizeHeaderValue(value, fallback = "unknown") { + const text = String(value ?? "").trim(); + if (!text) return fallback; + + return text.replace(/[^\x20-\x7e]/g, "").trim() || fallback; +} + +function getDeviceModel() { + return [osType() || process.platform, release(), arch()].filter(Boolean).join(" "); +} + +function generateDeviceId() { + return randomUUID().replace(/-/g, ""); +} + +function getKimiDeviceId() { + const configured = process.env.KIMI_CODING_DEVICE_ID?.trim(); + if (configured) return configured; + + try { + const oauthDir = path.join(resolveDataDir(), "oauth"); + const devicePath = path.join(oauthDir, DEVICE_ID_FILE); + if (fs.existsSync(devicePath)) { + const existing = fs.readFileSync(devicePath, "utf8").trim(); + if (existing) return existing; + } + + fs.mkdirSync(oauthDir, { recursive: true }); + const deviceId = generateDeviceId(); + fs.writeFileSync(devicePath, deviceId, { encoding: "utf8", mode: 0o600 }); + try { + fs.chmodSync(devicePath, 0o600); + } catch {} + return deviceId; + } catch { + return generateDeviceId(); + } +} // Custom headers required by Kimi OAuth function getKimiOAuthHeaders() { @@ -16,9 +55,10 @@ function getKimiOAuthHeaders() { Accept: "application/json", "X-Msh-Platform": PLATFORM, "X-Msh-Version": VERSION, - "X-Msh-Device-Name": DEVICE_NAME, - "X-Msh-Device-Model": DEVICE_MODEL, - "X-Msh-Device-Id": DEVICE_ID, + "X-Msh-Device-Name": sanitizeHeaderValue(hostname()), + "X-Msh-Device-Model": sanitizeHeaderValue(getDeviceModel()), + "X-Msh-Os-Version": sanitizeHeaderValue(osVersion()), + "X-Msh-Device-Id": sanitizeHeaderValue(getKimiDeviceId()), }; } @@ -40,13 +80,12 @@ export const kimiCoding = { } const data = await response.json(); + const verificationUri = data.verification_uri || "https://www.kimi.com/code/authorize_device"; return { device_code: data.device_code, user_code: data.user_code, - verification_uri: data.verification_uri || `https://auth.kimi.com/activate`, - verification_uri_complete: - data.verification_uri_complete || - `https://auth.kimi.com/activate?user_code=${data.user_code}`, + verification_uri: verificationUri, + verification_uri_complete: data.verification_uri_complete || verificationUri, expires_in: data.expires_in, interval: data.interval || 5, }; diff --git a/src/shared/components/OAuthModal.tsx b/src/shared/components/OAuthModal.tsx index 3fb35fbfc8..e6e39cca97 100644 --- a/src/shared/components/OAuthModal.tsx +++ b/src/shared/components/OAuthModal.tsx @@ -42,6 +42,8 @@ export default function OAuthModal({ const [polling, setPolling] = useState(false); const popupRef = useRef(null); const { copied, copy } = useCopyToClipboard(); + const deviceVerificationUrl = + deviceData?.verification_uri_complete || deviceData?.verification_uri || ""; // State for client-only values to avoid hydration mismatch const [isLocalhost, setIsLocalhost] = useState(false); @@ -604,12 +606,12 @@ export default function OAuthModal({
{t("deviceCodeVerificationUrl")}
{deviceData.verification_uri}
+ {deviceVerificationUrl}