mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 15:52:52 +03:00
feat(i18n): migrate Providers page (1110 lines, 30+ strings)
- ProvidersPage: section headers, test buttons, compatible provider modals - Expanded providers namespace from 16 to 73 keys in en.json and pt-BR.json - Coverage: OAuth/Free/API Key/Compatible sections, batch test, modals
This commit is contained in:
@@ -23,6 +23,7 @@ import Link from "next/link";
|
||||
import { getErrorCode, getRelativeTime } from "@/shared/utils";
|
||||
import { useNotificationStore } from "@/store/notificationStore";
|
||||
import ModelAvailabilityBadge from "./components/ModelAvailabilityBadge";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
// Shared helper function to avoid code duplication between ProviderCard and ApiKeyProviderCard
|
||||
function getStatusDisplay(connected, error, errorCode) {
|
||||
@@ -97,6 +98,8 @@ export default function ProvidersPage() {
|
||||
const [testingMode, setTestingMode] = useState(null);
|
||||
const [testResults, setTestResults] = useState(null);
|
||||
const notify = useNotificationStore();
|
||||
const t = useTranslations("providers");
|
||||
const tc = useTranslations("common");
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
@@ -194,12 +197,12 @@ export default function ProvidersPage() {
|
||||
setTestResults(data);
|
||||
if (data.summary) {
|
||||
const { passed, failed, total } = data.summary;
|
||||
if (failed === 0) notify.success(`All ${total} tests passed`);
|
||||
else notify.warning(`${passed}/${total} passed, ${failed} failed`);
|
||||
if (failed === 0) notify.success(t("allTestsPassed", { total }));
|
||||
else notify.warning(t("testSummary", { passed, failed, total }));
|
||||
}
|
||||
} catch (error) {
|
||||
setTestResults({ error: "Test request failed" });
|
||||
notify.error("Provider test failed");
|
||||
setTestResults({ error: t("providerTestFailed") });
|
||||
notify.error(t("providerTestFailed"));
|
||||
} finally {
|
||||
setTestingMode(null);
|
||||
}
|
||||
@@ -239,7 +242,8 @@ export default function ProvidersPage() {
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||
OAuth Providers <span className="size-2.5 rounded-full bg-blue-500" title="OAuth" />
|
||||
{t("oauthProviders")}{" "}
|
||||
<span className="size-2.5 rounded-full bg-blue-500" title="OAuth" />
|
||||
</h2>
|
||||
<div className="flex items-center gap-2">
|
||||
<ModelAvailabilityBadge />
|
||||
@@ -251,13 +255,13 @@ export default function ProvidersPage() {
|
||||
? "bg-primary/20 border-primary/40 text-primary animate-pulse"
|
||||
: "bg-bg-subtle border-border text-text-muted hover:text-text-primary hover:border-primary/40"
|
||||
}`}
|
||||
title="Test all OAuth connections"
|
||||
aria-label="Test all OAuth connections"
|
||||
title={t("testAllOAuth")}
|
||||
aria-label={t("testAllOAuth")}
|
||||
>
|
||||
<span className="material-symbols-outlined text-[14px]">
|
||||
{testingMode === "oauth" ? "sync" : "play_arrow"}
|
||||
</span>
|
||||
{testingMode === "oauth" ? "Testing..." : "Test All"}
|
||||
{testingMode === "oauth" ? t("testing") : t("testAll")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -279,7 +283,8 @@ export default function ProvidersPage() {
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||
Free Providers <span className="size-2.5 rounded-full bg-green-500" title="Free" />
|
||||
{t("freeProviders")}{" "}
|
||||
<span className="size-2.5 rounded-full bg-green-500" title="Free" />
|
||||
</h2>
|
||||
<button
|
||||
onClick={() => handleBatchTest("free")}
|
||||
@@ -289,13 +294,13 @@ export default function ProvidersPage() {
|
||||
? "bg-primary/20 border-primary/40 text-primary animate-pulse"
|
||||
: "bg-bg-subtle border-border text-text-muted hover:text-text-primary hover:border-primary/40"
|
||||
}`}
|
||||
title="Test all Free connections"
|
||||
aria-label="Test all Free provider connections"
|
||||
title={t("testAllFree")}
|
||||
aria-label={t("testAllFree")}
|
||||
>
|
||||
<span className="material-symbols-outlined text-[14px]">
|
||||
{testingMode === "free" ? "sync" : "play_arrow"}
|
||||
</span>
|
||||
{testingMode === "free" ? "Testing..." : "Test All"}
|
||||
{testingMode === "free" ? t("testing") : t("testAll")}
|
||||
</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
@@ -316,7 +321,7 @@ export default function ProvidersPage() {
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||
API Key Providers{" "}
|
||||
{t("apiKeyProviders")}{" "}
|
||||
<span className="size-2.5 rounded-full bg-amber-500" title="API Key" />
|
||||
</h2>
|
||||
<button
|
||||
@@ -327,13 +332,13 @@ export default function ProvidersPage() {
|
||||
? "bg-primary/20 border-primary/40 text-primary animate-pulse"
|
||||
: "bg-bg-subtle border-border text-text-muted hover:text-text-primary hover:border-primary/40"
|
||||
}`}
|
||||
title="Test all API Key connections"
|
||||
aria-label="Test all API Key connections"
|
||||
title={t("testAllApiKey")}
|
||||
aria-label={t("testAllApiKey")}
|
||||
>
|
||||
<span className="material-symbols-outlined text-[14px]">
|
||||
{testingMode === "apikey" ? "sync" : "play_arrow"}
|
||||
</span>
|
||||
{testingMode === "apikey" ? "Testing..." : "Test All"}
|
||||
{testingMode === "apikey" ? t("testing") : t("testAll")}
|
||||
</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
@@ -354,7 +359,7 @@ export default function ProvidersPage() {
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold flex items-center gap-2">
|
||||
API Key Compatible Providers{" "}
|
||||
{t("compatibleProviders")}{" "}
|
||||
<span className="size-2.5 rounded-full bg-orange-500" title="Compatible" />
|
||||
</h2>
|
||||
<div className="flex gap-2">
|
||||
@@ -367,16 +372,16 @@ export default function ProvidersPage() {
|
||||
? "bg-primary/20 border-primary/40 text-primary animate-pulse"
|
||||
: "bg-bg-subtle border-border text-text-muted hover:text-text-primary hover:border-primary/40"
|
||||
}`}
|
||||
title="Test all Compatible connections"
|
||||
title={t("testAllCompatible")}
|
||||
>
|
||||
<span className="material-symbols-outlined text-[14px]">
|
||||
{testingMode === "compatible" ? "sync" : "play_arrow"}
|
||||
</span>
|
||||
{testingMode === "compatible" ? "Testing..." : "Test All"}
|
||||
{testingMode === "compatible" ? t("testing") : t("testAll")}
|
||||
</button>
|
||||
)}
|
||||
<Button size="sm" icon="add" onClick={() => setShowAddAnthropicCompatibleModal(true)}>
|
||||
Add Anthropic Compatible
|
||||
{t("addAnthropicCompatible")}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
@@ -385,7 +390,7 @@ export default function ProvidersPage() {
|
||||
onClick={() => setShowAddCompatibleModal(true)}
|
||||
className="!bg-white !text-black hover:!bg-gray-100"
|
||||
>
|
||||
Add OpenAI Compatible
|
||||
{t("addOpenAICompatible")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -394,10 +399,8 @@ export default function ProvidersPage() {
|
||||
<span className="material-symbols-outlined text-[32px] text-text-muted mb-2">
|
||||
extension
|
||||
</span>
|
||||
<p className="text-text-muted text-sm">No compatible providers added yet</p>
|
||||
<p className="text-text-muted text-xs mt-1">
|
||||
Use the buttons above to add OpenAI or Anthropic compatible endpoints
|
||||
</p>
|
||||
<p className="text-text-muted text-sm">{t("noCompatibleYet")}</p>
|
||||
<p className="text-text-muted text-xs mt-1">{t("compatibleHint")}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
||||
@@ -442,7 +445,7 @@ export default function ProvidersPage() {
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="sticky top-0 z-10 flex items-center justify-between px-5 py-3 border-b border-border bg-bg-primary/95 backdrop-blur-sm rounded-t-xl">
|
||||
<h3 className="font-semibold">Test Results</h3>
|
||||
<h3 className="font-semibold">{t("testResults")}</h3>
|
||||
<button
|
||||
onClick={() => setTestResults(null)}
|
||||
className="p-1 rounded-lg hover:bg-bg-subtle text-text-muted hover:text-text-primary transition-colors"
|
||||
|
||||
@@ -498,7 +498,73 @@
|
||||
"testFailed": "Connection failed",
|
||||
"available": "Available",
|
||||
"unavailable": "Unavailable",
|
||||
"unknown": "Unknown"
|
||||
"unknown": "Unknown",
|
||||
"oauthProviders": "OAuth Providers",
|
||||
"freeProviders": "Free Providers",
|
||||
"apiKeyProviders": "API Key Providers",
|
||||
"compatibleProviders": "API Key Compatible Providers",
|
||||
"testAll": "Test All",
|
||||
"testAllOAuth": "Test all OAuth connections",
|
||||
"testAllFree": "Test all Free connections",
|
||||
"testAllApiKey": "Test all API Key connections",
|
||||
"testAllCompatible": "Test all Compatible connections",
|
||||
"connected": "{count} Connected",
|
||||
"errorCount": "{count} Error ({code})",
|
||||
"errorCountNoCode": "{count} Error",
|
||||
"noConnections": "No connections",
|
||||
"disabled": "Disabled",
|
||||
"enableProvider": "Enable provider",
|
||||
"disableProvider": "Disable provider",
|
||||
"testResults": "Test Results",
|
||||
"noCompatibleYet": "No compatible providers added yet",
|
||||
"compatibleHint": "Use the buttons above to add OpenAI or Anthropic compatible endpoints",
|
||||
"addOpenAICompatible": "Add OpenAI Compatible",
|
||||
"addAnthropicCompatible": "Add Anthropic Compatible",
|
||||
"addNewProvider": "Add New Provider",
|
||||
"backToProviders": "Back to Providers",
|
||||
"configureNewProvider": "Configure a new AI provider to use with your applications.",
|
||||
"selectProvider": "Select a provider",
|
||||
"selectedProvider": "Selected provider",
|
||||
"authMethod": "Authentication Method",
|
||||
"apiKeyRequired": "API Key is required",
|
||||
"selectProviderRequired": "Please select a provider",
|
||||
"enterApiKey": "Enter your API key",
|
||||
"apiKeySecure": "Your API key will be encrypted and stored securely.",
|
||||
"oauth2Connect": "Connect with OAuth2",
|
||||
"oauth2Desc": "Connect your account using OAuth2 authentication.",
|
||||
"displayName": "Display Name",
|
||||
"displayNamePlaceholder": "e.g., Production API, Dev Environment",
|
||||
"displayNameHint": "Optional. A friendly name to identify this configuration.",
|
||||
"active": "Active",
|
||||
"activeDescription": "Enable this provider for use in your applications",
|
||||
"createProvider": "Create Provider",
|
||||
"failedCreate": "Failed to create provider",
|
||||
"errorOccurred": "An error occurred. Please try again.",
|
||||
"modelStatus": "Model Status",
|
||||
"allModelsOperational": "All models operational",
|
||||
"modelsWithIssues": "{count} model(s) with issues",
|
||||
"allModelsNormal": "All models are responding normally.",
|
||||
"cooldownCleared": "Cooldown cleared for {model}",
|
||||
"failedClearCooldown": "Failed to clear cooldown",
|
||||
"loadingAvailability": "Loading model availability...",
|
||||
"clearCooldown": "Clear",
|
||||
"clearing": "Clearing...",
|
||||
"providerTestFailed": "Provider test failed",
|
||||
"allTestsPassed": "All {total} tests passed",
|
||||
"testSummary": "{passed}/{total} passed, {failed} failed",
|
||||
"nameLabel": "Name",
|
||||
"prefixLabel": "Prefix",
|
||||
"baseUrlLabel": "Base URL",
|
||||
"apiTypeLabel": "API Type",
|
||||
"prefixHint": "Required. Unique prefix for model names.",
|
||||
"nameHint": "Required. A friendly label for this node.",
|
||||
"baseUrlHint": "Required. \u2003Provider API base URL.",
|
||||
"validateConnection": "Validate Connection",
|
||||
"validating": "Validating...",
|
||||
"connectionValid": "Connection is valid!",
|
||||
"connectionFailed": "Connection failed. Check URL and key.",
|
||||
"testKeyLabel": "Test API Key",
|
||||
"testKeyPlaceholder": "sk-... (for validation only)"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Settings",
|
||||
|
||||
@@ -498,7 +498,73 @@
|
||||
"testFailed": "Falha na conexão",
|
||||
"available": "Disponível",
|
||||
"unavailable": "Indisponível",
|
||||
"unknown": "Desconhecido"
|
||||
"unknown": "Desconhecido",
|
||||
"oauthProviders": "Provedores OAuth",
|
||||
"freeProviders": "Provedores Gratuitos",
|
||||
"apiKeyProviders": "Provedores por Chave de API",
|
||||
"compatibleProviders": "Provedores Compatíveis por Chave de API",
|
||||
"testAll": "Testar Todos",
|
||||
"testAllOAuth": "Testar todas as conexões OAuth",
|
||||
"testAllFree": "Testar todas as conexões gratuitas",
|
||||
"testAllApiKey": "Testar todas as conexões por chave de API",
|
||||
"testAllCompatible": "Testar todas as conexões compatíveis",
|
||||
"connected": "{count} Conectado(s)",
|
||||
"errorCount": "{count} Erro ({code})",
|
||||
"errorCountNoCode": "{count} Erro",
|
||||
"noConnections": "Sem conexões",
|
||||
"disabled": "Desativado",
|
||||
"enableProvider": "Ativar provedor",
|
||||
"disableProvider": "Desativar provedor",
|
||||
"testResults": "Resultados do Teste",
|
||||
"noCompatibleYet": "Nenhum provedor compatível adicionado",
|
||||
"compatibleHint": "Use os botões acima para adicionar endpoints compatíveis com OpenAI ou Anthropic",
|
||||
"addOpenAICompatible": "Adicionar Compatível OpenAI",
|
||||
"addAnthropicCompatible": "Adicionar Compatível Anthropic",
|
||||
"addNewProvider": "Adicionar Novo Provedor",
|
||||
"backToProviders": "Voltar para Provedores",
|
||||
"configureNewProvider": "Configure um novo provedor de IA para usar com suas aplicações.",
|
||||
"selectProvider": "Selecione um provedor",
|
||||
"selectedProvider": "Provedor selecionado",
|
||||
"authMethod": "Método de Autenticação",
|
||||
"apiKeyRequired": "Chave de API é obrigatória",
|
||||
"selectProviderRequired": "Selecione um provedor",
|
||||
"enterApiKey": "Digite sua chave de API",
|
||||
"apiKeySecure": "Sua chave de API será criptografada e armazenada com segurança.",
|
||||
"oauth2Connect": "Conectar com OAuth2",
|
||||
"oauth2Desc": "Conecte sua conta usando autenticação OAuth2.",
|
||||
"displayName": "Nome de Exibição",
|
||||
"displayNamePlaceholder": "ex.: API de Produção, Ambiente Dev",
|
||||
"displayNameHint": "Opcional. Um nome amigável para identificar esta configuração.",
|
||||
"active": "Ativo",
|
||||
"activeDescription": "Habilitar este provedor para uso em suas aplicações",
|
||||
"createProvider": "Criar Provedor",
|
||||
"failedCreate": "Falha ao criar provedor",
|
||||
"errorOccurred": "Ocorreu um erro. Tente novamente.",
|
||||
"modelStatus": "Status dos Modelos",
|
||||
"allModelsOperational": "Todos os modelos operacionais",
|
||||
"modelsWithIssues": "{count} modelo(s) com problemas",
|
||||
"allModelsNormal": "Todos os modelos estão respondendo normalmente.",
|
||||
"cooldownCleared": "Cooldown limpo para {model}",
|
||||
"failedClearCooldown": "Falha ao limpar cooldown",
|
||||
"loadingAvailability": "Carregando disponibilidade dos modelos...",
|
||||
"clearCooldown": "Limpar",
|
||||
"clearing": "Limpando...",
|
||||
"providerTestFailed": "Teste de provedor falhou",
|
||||
"allTestsPassed": "Todos os {total} testes passaram",
|
||||
"testSummary": "{passed}/{total} passaram, {failed} falharam",
|
||||
"nameLabel": "Nome",
|
||||
"prefixLabel": "Prefixo",
|
||||
"baseUrlLabel": "URL Base",
|
||||
"apiTypeLabel": "Tipo de API",
|
||||
"prefixHint": "Obrigatório. Prefixo único para nomes de modelos.",
|
||||
"nameHint": "Obrigatório. Um rótulo amigável para este nó.",
|
||||
"baseUrlHint": "Obrigatório. URL base da API do provedor.",
|
||||
"validateConnection": "Validar Conexão",
|
||||
"validating": "Validando...",
|
||||
"connectionValid": "Conexão válida!",
|
||||
"connectionFailed": "Falha na conexão. Verifique URL e chave.",
|
||||
"testKeyLabel": "Chave de API de Teste",
|
||||
"testKeyPlaceholder": "sk-... (apenas para validação)"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Configurações",
|
||||
|
||||
Reference in New Issue
Block a user