diff --git a/app/src/components/AppUpdatePrompt.tsx b/app/src/components/AppUpdatePrompt.tsx index 9aacbb805..2af06cdfd 100644 --- a/app/src/components/AppUpdatePrompt.tsx +++ b/app/src/components/AppUpdatePrompt.tsx @@ -108,7 +108,7 @@ const AppUpdatePrompt = (props: AppUpdatePromptProps) => { )} diff --git a/app/src/components/BootCheckGate/BootCheckGate.tsx b/app/src/components/BootCheckGate/BootCheckGate.tsx index 4df60a84a..d2c4d3fc7 100644 --- a/app/src/components/BootCheckGate/BootCheckGate.tsx +++ b/app/src/components/BootCheckGate/BootCheckGate.tsx @@ -315,7 +315,8 @@ function ModePicker({ onConfirm }: PickerProps) { /> {tokenError &&

{tokenError}

}

- {t('bootCheck.storedLocally')} Authorization: Bearer … on every RPC. + {t('bootCheck.storedLocally')} Authorization: Bearer …{' '} + {t('bootCheck.rpcAuthSuffix')}

diff --git a/app/src/components/LocalAIDownloadSnackbar.tsx b/app/src/components/LocalAIDownloadSnackbar.tsx index d9e9ee3af..1dabfa0ca 100644 --- a/app/src/components/LocalAIDownloadSnackbar.tsx +++ b/app/src/components/LocalAIDownloadSnackbar.tsx @@ -119,7 +119,7 @@ const LocalAIDownloadSnackbar = () => { )} {!onApplySuggestedEnv && (

- Re-install with these values to apply them. + {t('mcp.configAssistant.reinstallHint')}

)} @@ -143,7 +148,7 @@ const ConfigAssistantPanel = ({ {sending && (
- Thinking... + {t('mcp.configAssistant.thinking')}
)} @@ -165,7 +170,7 @@ const ConfigAssistantPanel = ({ onChange={e => setInput(e.target.value)} onKeyDown={handleKeyDown} disabled={sending} - placeholder="Ask a question (Enter to send, Shift+Enter for newline)" + placeholder={t('mcp.configAssistant.inputPlaceholder')} className="flex-1 rounded-lg border border-stone-200 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm text-stone-800 dark:text-neutral-100 placeholder:text-stone-400 dark:placeholder:text-neutral-500 focus:outline-none focus:ring-2 focus:ring-primary-500/40 disabled:opacity-50 resize-none" /> diff --git a/app/src/components/channels/mcp/InstallDialog.tsx b/app/src/components/channels/mcp/InstallDialog.tsx index c242c3028..f0a54fd5a 100644 --- a/app/src/components/channels/mcp/InstallDialog.tsx +++ b/app/src/components/channels/mcp/InstallDialog.tsx @@ -7,6 +7,7 @@ import debug from 'debug'; import { useCallback, useEffect, useRef, useState } from 'react'; +import { useT } from '../../../lib/i18n/I18nContext'; import { mcpClientsApi } from '../../../services/api/mcpClientsApi'; import type { InstalledServer, SmitheryServerDetail } from './types'; @@ -20,6 +21,7 @@ interface InstallDialogProps { } const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: InstallDialogProps) => { + const { t } = useT(); const [detail, setDetail] = useState(null); const [loadingDetail, setLoadingDetail] = useState(true); const [detailError, setDetailError] = useState(null); @@ -61,7 +63,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta }) .catch(err => { if (latestQualifiedNameRef.current !== requestedName) return; - const msg = err instanceof Error ? err.message : 'Failed to load server details'; + const msg = err instanceof Error ? err.message : t('mcp.install.failedDetail'); log('detail error: %s', msg); setDetailError(msg); }) @@ -70,7 +72,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta setLoadingDetail(false); } }); - }, [qualifiedName, prefillEnv]); + }, [qualifiedName, prefillEnv, t]); const toggleShowEnv = useCallback((key: string) => { setShowEnv(prev => ({ ...prev, [key]: !prev[key] })); @@ -86,7 +88,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta // Validate required keys are filled. for (const key of detail.required_env_keys ?? []) { if (!envValues[key]?.trim()) { - setInstallError(`"${key}" is required`); + setInstallError(t('mcp.install.missingRequired').replace('{key}', key)); return; } } @@ -97,7 +99,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta try { parsedConfig = JSON.parse(configJson.trim()); } catch { - setInstallError('Config JSON is not valid JSON'); + setInstallError(t('mcp.install.invalidJson')); return; } } @@ -115,18 +117,18 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta log('install success server_id=%s', server.server_id); onSuccess(server); } catch (err) { - const msg = err instanceof Error ? err.message : 'Install failed'; + const msg = err instanceof Error ? err.message : t('mcp.install.failedInstall'); log('install error: %s', msg); setInstallError(msg); } finally { setInstalling(false); } - }, [detail, envValues, configJson, qualifiedName, onSuccess]); + }, [detail, envValues, configJson, qualifiedName, onSuccess, t]); if (loadingDetail) { return (
- Loading server details... + {t('mcp.install.loadingDetail')}
); } @@ -141,7 +143,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta type="button" onClick={onCancel} className="text-sm text-stone-500 dark:text-neutral-400 hover:underline"> - Go back + {t('mcp.install.back')} ); @@ -166,7 +168,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta )}

- Install {detail.display_name} + {t('mcp.install.title').replace('{name}', detail.display_name)}

{detail.description && (

@@ -180,7 +182,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta {(detail.required_env_keys ?? []).length > 0 && (

- Required environment variables + {t('mcp.install.requiredEnv')}

{detail.required_env_keys!.map(key => (
@@ -195,7 +197,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta type={showEnv[key] ? 'text' : 'password'} value={envValues[key] ?? ''} onChange={e => handleEnvChange(key, e.target.value)} - placeholder={`Enter ${key}`} + placeholder={t('mcp.install.enterValue').replace('{key}', key)} disabled={installing} className="flex-1 rounded-lg border border-stone-200 dark:border-neutral-700 bg-white dark:bg-neutral-900 px-3 py-1.5 text-sm text-stone-800 dark:text-neutral-100 placeholder:text-stone-400 dark:placeholder:text-neutral-500 focus:outline-none focus:ring-2 focus:ring-primary-500/40 disabled:opacity-50" /> @@ -204,7 +206,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta onClick={() => toggleShowEnv(key)} disabled={installing} className="shrink-0 rounded-lg border border-stone-200 dark:border-neutral-700 px-2 py-1 text-xs text-stone-500 dark:text-neutral-400 hover:border-stone-300 dark:hover:border-neutral-600 disabled:opacity-50"> - {showEnv[key] ? 'Hide' : 'Show'} + {showEnv[key] ? t('mcp.install.hide') : t('mcp.install.show')}
@@ -217,7 +219,7 @@ const InstallDialog = ({ qualifiedName, prefillEnv, onSuccess, onCancel }: Insta