fix: comprehensive i18n audit - add 69 missing keys and fix hardcoded Chinese

- Add 69 missing translation keys to zh/en/ja (usage, proxy, sessionManager,
  deeplink, codexConfig, openclaw, circuitBreaker, streamCheck, etc.)
- Replace 15 hardcoded Chinese strings in CircuitBreakerConfigPanel with t() calls
- Fix ColorPicker component to use i18n for default label
- Add i18n interpolation params to ProxyToggle tooltip translations
- All three language files synchronized at 1838 keys
This commit is contained in:
Jason
2026-03-08 20:41:44 +08:00
parent 7dbceeafe6
commit c54515742f
6 changed files with 416 additions and 74 deletions

View File

@@ -2,6 +2,7 @@ import React from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
import { useTranslation } from "react-i18next";
interface ColorPickerProps {
value?: string;
@@ -28,12 +29,14 @@ const DEFAULT_PRESETS = [
export const ColorPicker: React.FC<ColorPickerProps> = ({
value = "#4285F4",
onValueChange,
label = "图标颜色",
label,
presets = DEFAULT_PRESETS,
}) => {
const { t } = useTranslation();
const displayLabel = label ?? t("providerIcon.color", "图标颜色");
return (
<div className="space-y-3">
<Label>{label}</Label>
<Label>{displayLabel}</Label>
{/* 颜色预设 */}
<div className="grid grid-cols-6 gap-2">

View File

@@ -146,15 +146,24 @@ export function CircuitBreakerConfigPanel() {
};
if (isLoading) {
return <div className="text-sm text-muted-foreground">...</div>;
return (
<div className="text-sm text-muted-foreground">
{t("circuitBreaker.loading", "加载中...")}
</div>
);
}
return (
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold"></h3>
<h3 className="text-lg font-semibold">
{t("circuitBreaker.title", "熔断器配置")}
</h3>
<p className="text-sm text-muted-foreground mt-1">
{t(
"circuitBreaker.description",
"调整熔断器参数以控制故障检测和恢复行为",
)}
</p>
</div>
@@ -163,7 +172,9 @@ export function CircuitBreakerConfigPanel() {
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* 失败阈值 */}
<div className="space-y-2">
<Label htmlFor="failureThreshold"></Label>
<Label htmlFor="failureThreshold">
{t("circuitBreaker.failureThreshold", "失败阈值")}
</Label>
<Input
id="failureThreshold"
type="number"
@@ -175,13 +186,18 @@ export function CircuitBreakerConfigPanel() {
}
/>
<p className="text-xs text-muted-foreground">
{t(
"circuitBreaker.failureThresholdHint",
"连续失败多少次后打开熔断器",
)}
</p>
</div>
{/* 超时时间 */}
<div className="space-y-2">
<Label htmlFor="timeoutSeconds"></Label>
<Label htmlFor="timeoutSeconds">
{t("circuitBreaker.timeoutSeconds", "超时时间(秒)")}
</Label>
<Input
id="timeoutSeconds"
type="number"
@@ -193,13 +209,18 @@ export function CircuitBreakerConfigPanel() {
}
/>
<p className="text-xs text-muted-foreground">
{t(
"circuitBreaker.timeoutSecondsHint",
"熔断器打开后多久尝试恢复(半开状态)",
)}
</p>
</div>
{/* 成功阈值 */}
<div className="space-y-2">
<Label htmlFor="successThreshold"></Label>
<Label htmlFor="successThreshold">
{t("circuitBreaker.successThreshold", "成功阈值")}
</Label>
<Input
id="successThreshold"
type="number"
@@ -211,13 +232,18 @@ export function CircuitBreakerConfigPanel() {
}
/>
<p className="text-xs text-muted-foreground">
{t(
"circuitBreaker.successThresholdHint",
"半开状态下成功多少次后关闭熔断器",
)}
</p>
</div>
{/* 错误率阈值 */}
<div className="space-y-2">
<Label htmlFor="errorRateThreshold"> (%)</Label>
<Label htmlFor="errorRateThreshold">
{t("circuitBreaker.errorRateThreshold", "错误率阈值 (%)")}
</Label>
<Input
id="errorRateThreshold"
type="number"
@@ -230,13 +256,18 @@ export function CircuitBreakerConfigPanel() {
}
/>
<p className="text-xs text-muted-foreground">
{t(
"circuitBreaker.errorRateThresholdHint",
"错误率超过此值时打开熔断器",
)}
</p>
</div>
{/* 最小请求数 */}
<div className="space-y-2">
<Label htmlFor="minRequests"></Label>
<Label htmlFor="minRequests">
{t("circuitBreaker.minRequests", "最小请求数")}
</Label>
<Input
id="minRequests"
type="number"
@@ -248,42 +279,75 @@ export function CircuitBreakerConfigPanel() {
}
/>
<p className="text-xs text-muted-foreground">
{t("circuitBreaker.minRequestsHint", "计算错误率前的最小请求数")}
</p>
</div>
</div>
<div className="flex gap-3">
<Button onClick={handleSave} disabled={updateConfig.isPending}>
{updateConfig.isPending ? "保存中..." : "保存配置"}
{updateConfig.isPending
? t("common.saving", "保存中...")
: t("circuitBreaker.saveConfig", "保存配置")}
</Button>
<Button
variant="outline"
onClick={handleReset}
disabled={updateConfig.isPending}
>
{t("common.reset", "重置")}
</Button>
</div>
{/* 说明信息 */}
<div className="p-4 bg-muted/50 rounded-lg space-y-2 text-sm">
<h4 className="font-medium"></h4>
<h4 className="font-medium">
{t("circuitBreaker.instructionsTitle", "配置说明")}
</h4>
<ul className="space-y-1 text-muted-foreground">
<li>
<strong></strong>
{" "}
<strong>{t("circuitBreaker.failureThreshold", "失败阈值")}</strong>
{t(
"circuitBreaker.instructions.failureThreshold",
"连续失败达到此次数时,熔断器打开",
)}
</li>
<li>
<strong></strong>
<strong>{t("circuitBreaker.timeoutSeconds", "超时时间")}</strong>
{t(
"circuitBreaker.instructions.timeout",
"熔断器打开后,等待此时间后尝试半开",
)}
</li>
<li>
<strong></strong>
{" "}
<strong>{t("circuitBreaker.successThreshold", "成功阈值")}</strong>
{t(
"circuitBreaker.instructions.successThreshold",
"半开状态下,成功达到此次数时关闭熔断器",
)}
</li>
<li>
<strong></strong>
{" "}
<strong>
{t("circuitBreaker.errorRateThreshold", "错误率阈值")}
</strong>
{t(
"circuitBreaker.instructions.errorRate",
"错误率超过此值时,熔断器打开",
)}
</li>
<li>
<strong></strong>
<strong>{t("circuitBreaker.minRequests", "最小请求数")}</strong>
{t(
"circuitBreaker.instructions.minRequests",
"只有请求数达到此值后才计算错误率",
)}
</li>
</ul>
</div>

View File

@@ -44,12 +44,17 @@ export function ProxyToggle({ className, activeApp }: ProxyToggleProps) {
const tooltipText = takeoverEnabled
? isRunning
? t("proxy.takeover.tooltip.active", {
appLabel,
address: status?.address,
port: status?.port,
defaultValue: `${appLabel} 已接管 - ${status?.address}:${status?.port}\n切换该应用供应商为热切换`,
})
: t("proxy.takeover.tooltip.broken", {
appLabel,
defaultValue: `${appLabel} 已接管,但代理服务未运行`,
})
: t("proxy.takeover.tooltip.inactive", {
appLabel,
defaultValue: `接管 ${appLabel} 的 Live 配置,让该应用请求走本地代理`,
});

View File

@@ -38,7 +38,9 @@
"reset": "Reset",
"actions": "Actions",
"deleting": "Deleting...",
"auto": "Auto"
"auto": "Auto",
"enabled": "Enabled",
"notSet": "Not Set"
},
"apiKeyInput": {
"placeholder": "Enter API Key",
@@ -579,7 +581,8 @@
"pricingLoadFailed": "Failed to load pricing defaults: {{error}}",
"defaultCostMultiplierRequired": "Default multiplier is required",
"defaultCostMultiplierInvalid": "Invalid multiplier format"
}
},
"saveFailedGeneric": "Save failed, please try again"
},
"apps": {
"claude": "Claude",
@@ -633,7 +636,14 @@
"daysAgo": "{{count}} days ago",
"roleUser": "User",
"roleSystem": "System",
"roleTool": "Tool"
"roleTool": "Tool",
"resume": "Resume Session",
"resumeTooltip": "Resume this session in terminal",
"noResumeCommand": "This session cannot be resumed",
"copyCommand": "Copy Command",
"copyMessage": "Copy Message",
"messageCopied": "Message copied",
"conversationHistory": "Conversation History"
},
"console": {
"providerSwitchReceived": "Received provider switch event:",
@@ -755,7 +765,8 @@
"pleaseAddEndpoint": "Please add an endpoint first",
"testUnavailable": "Speed test unavailable",
"noResult": "No result returned",
"testFailed": "Speed test failed: {{error}}"
"testFailed": "Speed test failed: {{error}}",
"empty": "No endpoints"
},
"providerAdvanced": {
"testConfig": "Model Test Config",
@@ -799,7 +810,9 @@
"extractNoCommonConfig": "No common config available to extract from editor",
"extractFailed": "Extract failed: {{error}}",
"saveFailed": "Save failed: {{error}}",
"modelNameHint": "Specify the model to use, will be auto-updated in config.toml"
"modelNameHint": "Specify the model to use, will be auto-updated in config.toml",
"modelName": "Model Name",
"modelNamePlaceholder": "e.g., gpt-5-codex"
},
"geminiConfig": {
"envFile": "Environment Variables (.env)",
@@ -944,7 +957,28 @@
"costBreakdown": "Cost Breakdown",
"performance": "Performance",
"latency": "Latency",
"errorMessage": "Error Message"
"errorMessage": "Error Message",
"requests": "Requests",
"tokens": "Tokens",
"avgCost": "Average Cost",
"avgLatency": "Average Latency",
"successRate": "Success Rate",
"requestId": "Request ID",
"never": "Never",
"modelId": "Model ID",
"modelIdRequired": "Model ID is required",
"inputCostPerMillion": "Input Cost (per million tokens, USD)",
"outputCostPerMillion": "Output Cost (per million tokens, USD)",
"invalidPrice": "Price must be non-negative",
"invalidTimeRange": "Please select complete start/end time",
"invalidTimeRangeOrder": "Start time cannot be later than end time",
"timeRangeTooLarge": "Time range is too large, please narrow it down",
"addPricing": "Add Pricing",
"editPricing": "Edit Pricing",
"pricingAdded": "Pricing added",
"pricingUpdated": "Pricing updated",
"cacheReadCostPerMillion": "Cache Read Cost (per million tokens, USD)",
"cacheCreationCostPerMillion": "Cache Write Cost (per million tokens, USD)"
},
"usageScript": {
"title": "Configure Usage Query",
@@ -1367,7 +1401,9 @@
"stringifiedEnvVars": "env.vars should be an object, but the current value looks stringified or malformed.",
"stringifiedShellEnv": "env.shellEnv should be an object, but the current value looks stringified or malformed.",
"parseFailed": "openclaw.json could not be parsed as valid JSON5. Fix the file before editing it here."
}
},
"primaryModel": "Primary Model",
"fallbackModel": "Fallback Model"
},
"env": {
"warning": {
@@ -1587,7 +1623,14 @@
"skillsPath": "Skills Path",
"hint": "This will add the Skill repository to the list.",
"hintDetail": "After adding, you can install specific Skills from the Skills management page."
}
},
"usageScript": "Usage Query",
"usageScriptEnabled": "Enabled",
"usageScriptDisabled": "Disabled",
"usageApiKey": "Usage API Key",
"usageBaseUrl": "Usage Query URL",
"usageAutoInterval": "Auto Query",
"usageAutoIntervalValue": "Every {{minutes}} minutes"
},
"iconPicker": {
"search": "Search Icons",
@@ -1606,7 +1649,8 @@
"selectIcon": "Select Icon",
"preview": "Preview",
"clickToChange": "Click to change icon",
"clickToSelect": "Click to select icon"
"clickToSelect": "Click to select icon",
"color": "Icon Color"
},
"migration": {
"success": "Configuration migrated successfully",
@@ -1743,7 +1787,12 @@
"hint": "Select apps to take over — once enabled, requests from that app will be routed through the local proxy",
"enabled": "{{app}} takeover enabled",
"disabled": "{{app}} takeover disabled",
"failed": "Failed to toggle takeover"
"failed": "Failed to toggle takeover",
"tooltip": {
"active": "{{appLabel}} is intercepting - {{address}}:{{port}}\nSwitch provider for hot switching",
"broken": "{{appLabel}} is intercepting, but proxy service is not running",
"inactive": "Intercept {{appLabel}}'s live config to route requests through local proxy"
}
},
"failover": {
"proxyRequired": "Proxy service must be started to configure failover",
@@ -1793,8 +1842,28 @@
"successThresholdLabel": "Recovery Success Threshold",
"successThresholdExplain": "In half-open state, close circuit breaker after this many successes, making provider available again",
"errorRateLabel": "Error Rate Threshold",
"errorRateExplain": "Open circuit breaker when error rate exceeds this value, even if failure threshold not reached"
}
"errorRateExplain": "Open circuit breaker when error rate exceeds this value, even if failure threshold not reached",
"maxRetries": "Max Retries",
"timeoutSettings": "Timeout Settings",
"streamingFirstByte": "Streaming First Byte Timeout",
"streamingIdle": "Streaming Idle Timeout",
"nonStreaming": "Non-Streaming Timeout",
"maxRetriesHint": "Number of retries on request failure (0-10)",
"streamingFirstByteHint": "Max time to wait for first data chunk, range 1-120s, default 60s",
"streamingIdleHint": "Max interval between data chunks, range 60-600s, 0 to disable (prevents mid-stream stalls)",
"nonStreamingHint": "Total timeout for non-streaming requests, range 60-1200s, default 600s (10 min)"
},
"logging": {
"enabled": "Logging enabled",
"disabled": "Logging disabled",
"failed": "Failed to toggle logging"
},
"server": {
"started": "Proxy service started - {{address}}:{{port}}",
"startFailed": "Failed to start proxy service: {{detail}}"
},
"stoppedWithRestore": "Proxy service stopped, all takeover configs restored",
"stopWithRestoreFailed": "Stop failed: {{detail}}"
},
"streamCheck": {
"configSaved": "Health check config saved",
@@ -1807,7 +1876,11 @@
"timeout": "Timeout (seconds)",
"maxRetries": "Max Retries",
"degradedThreshold": "Degraded Threshold (ms)",
"testPrompt": "Test Prompt"
"testPrompt": "Test Prompt",
"operational": "{{providerName}} is operational ({{responseTimeMs}}ms)",
"degraded": "{{providerName}} is slow ({{responseTimeMs}}ms)",
"failed": "{{providerName}} check failed: {{message}}",
"error": "{{providerName}} check error: {{error}}"
},
"proxyConfig": {
"proxyEnabled": "Proxy Enabled",
@@ -1829,11 +1902,28 @@
"failureThreshold": "Failure Threshold",
"successThreshold": "Success Threshold",
"timeoutSeconds": "Timeout (seconds)",
"errorRateThreshold": "Error Rate Threshold",
"minRequests": "Min Requests",
"errorRateThreshold": "Error Rate Threshold (%)",
"minRequests": "Minimum Requests",
"validationFailed": "The following fields are out of valid range: {{fields}}",
"configSaved": "Circuit breaker config saved",
"saveFailed": "Failed to save"
"configSaved": "Circuit breaker configuration saved",
"saveFailed": "Save failed",
"loading": "Loading...",
"title": "Circuit Breaker Configuration",
"description": "Adjust circuit breaker parameters to control fault detection and recovery behavior",
"failureThresholdHint": "How many consecutive failures trigger the circuit breaker",
"timeoutSecondsHint": "How long to wait before attempting recovery (half-open state)",
"successThresholdHint": "How many successes in half-open state to close the circuit breaker",
"errorRateThresholdHint": "Open circuit breaker when error rate exceeds this value",
"minRequestsHint": "Minimum requests before calculating error rate",
"saveConfig": "Save Configuration",
"instructionsTitle": "Configuration Instructions",
"instructions": {
"failureThreshold": "Circuit breaker opens when consecutive failures reach this count",
"timeout": "After circuit breaker opens, wait this time before attempting half-open",
"successThreshold": "In half-open state, close circuit breaker when successes reach this count",
"errorRate": "Circuit breaker opens when error rate exceeds this value",
"minRequests": "Error rate is only calculated after request count reaches this value"
}
},
"universalProvider": {
"title": "Universal Provider",

View File

@@ -38,7 +38,9 @@
"reset": "リセット",
"actions": "操作",
"deleting": "削除中...",
"auto": "自動"
"auto": "自動",
"enabled": "有効",
"notSet": "未設定"
},
"apiKeyInput": {
"placeholder": "API Key を入力",
@@ -579,7 +581,8 @@
"pricingLoadFailed": "課金設定の読み込みに失敗しました: {{error}}",
"defaultCostMultiplierRequired": "デフォルト倍率は必須です",
"defaultCostMultiplierInvalid": "デフォルト倍率の形式が正しくありません"
}
},
"saveFailedGeneric": "保存に失敗しました。もう一度お試しください"
},
"apps": {
"claude": "Claude",
@@ -633,7 +636,14 @@
"daysAgo": "{{count}}日前",
"roleUser": "ユーザー",
"roleSystem": "システム",
"roleTool": "ツール"
"roleTool": "ツール",
"resume": "セッションを再開",
"resumeTooltip": "ターミナルでこのセッションを再開",
"noResumeCommand": "このセッションは再開できません",
"copyCommand": "コマンドをコピー",
"copyMessage": "メッセージをコピー",
"messageCopied": "メッセージがコピーされました",
"conversationHistory": "会話履歴"
},
"console": {
"providerSwitchReceived": "プロバイダー切り替えイベントを受信:",
@@ -755,7 +765,8 @@
"pleaseAddEndpoint": "まずエンドポイントを追加してください",
"testUnavailable": "速度テストを実行できません",
"noResult": "結果がありません",
"testFailed": "速度テストに失敗しました: {{error}}"
"testFailed": "速度テストに失敗しました: {{error}}",
"empty": "エンドポイントがありません"
},
"providerAdvanced": {
"testConfig": "モデルテスト設定",
@@ -799,7 +810,9 @@
"extractNoCommonConfig": "編集内容から抽出できる共通設定がありません",
"extractFailed": "抽出に失敗しました: {{error}}",
"saveFailed": "保存に失敗しました: {{error}}",
"modelNameHint": "使用するモデルを指定します。config.toml に自動更新されます"
"modelNameHint": "使用するモデルを指定します。config.toml に自動更新されます",
"modelName": "モデル名",
"modelNamePlaceholder": "例: gpt-5-codex"
},
"geminiConfig": {
"envFile": "環境変数 (.env)",
@@ -944,7 +957,28 @@
"costBreakdown": "コスト明細",
"performance": "パフォーマンス",
"latency": "レイテンシー",
"errorMessage": "エラーメッセージ"
"errorMessage": "エラーメッセージ",
"requests": "リクエスト数",
"tokens": "トークン",
"avgCost": "平均コスト",
"avgLatency": "平均レイテンシ",
"successRate": "成功率",
"requestId": "リクエスト ID",
"never": "なし",
"modelId": "モデル ID",
"modelIdRequired": "モデル ID は必須です",
"inputCostPerMillion": "入力コスト100万トークンあたり、USD",
"outputCostPerMillion": "出力コスト100万トークンあたり、USD",
"invalidPrice": "価格は負でない数値である必要があります",
"invalidTimeRange": "開始/終了時刻を完全に選択してください",
"invalidTimeRangeOrder": "開始時刻は終了時刻より前である必要があります",
"timeRangeTooLarge": "時間範囲が大きすぎます。範囲を縮小してください",
"addPricing": "価格設定を追加",
"editPricing": "価格設定を編集",
"pricingAdded": "価格設定が追加されました",
"pricingUpdated": "価格設定が更新されました",
"cacheReadCostPerMillion": "キャッシュ読み取りコスト100万トークンあたり、USD",
"cacheCreationCostPerMillion": "キャッシュ書き込みコスト100万トークンあたり、USD"
},
"usageScript": {
"title": "利用状況を設定",
@@ -1367,7 +1401,9 @@
"stringifiedEnvVars": "env.vars はオブジェクトである必要がありますが、現在の値は文字列化または破損しているようです。",
"stringifiedShellEnv": "env.shellEnv はオブジェクトである必要がありますが、現在の値は文字列化または破損しているようです。",
"parseFailed": "openclaw.json を有効な JSON5 として解析できませんでした。ここで編集する前にファイルを修正してください。"
}
},
"primaryModel": "プライマリモデル",
"fallbackModel": "フォールバックモデル"
},
"env": {
"warning": {
@@ -1587,7 +1623,14 @@
"skillsPath": "スキルパス",
"hint": "この操作でスキルリポジトリが一覧に追加されます。",
"hintDetail": "追加後、スキル管理ページから個別のスキルをインストールできます。"
}
},
"usageScript": "使用量クエリ",
"usageScriptEnabled": "有効",
"usageScriptDisabled": "無効",
"usageApiKey": "使用量 API キー",
"usageBaseUrl": "使用量クエリ URL",
"usageAutoInterval": "自動クエリ",
"usageAutoIntervalValue": "{{minutes}} 分ごと"
},
"iconPicker": {
"search": "アイコンを検索",
@@ -1606,7 +1649,8 @@
"selectIcon": "アイコンを選択",
"preview": "プレビュー",
"clickToChange": "クリックでアイコンを変更",
"clickToSelect": "クリックでアイコンを選択"
"clickToSelect": "クリックでアイコンを選択",
"color": "アイコンカラー"
},
"migration": {
"success": "設定の移行が完了しました",
@@ -1743,7 +1787,12 @@
"hint": "テイクオーバーするアプリを選択します。有効にすると、そのアプリのリクエストはローカルプロキシ経由で転送されます",
"enabled": "{{app}} テイクオーバー有効",
"disabled": "{{app}} テイクオーバー無効",
"failed": "テイクオーバーの切り替えに失敗しました"
"failed": "テイクオーバーの切り替えに失敗しました",
"tooltip": {
"active": "{{appLabel}} がインターセプト中 - {{address}}:{{port}}\nホットスイッチングのためプロバイダを切り替え",
"broken": "{{appLabel}} がインターセプト中ですが、プロキシサービスが実行されていません",
"inactive": "{{appLabel}} のライブ設定をインターセプトしてリクエストをローカルプロキシ経由でルーティング"
}
},
"failover": {
"proxyRequired": "フェイルオーバーを設定するには、プロキシサービスを先に起動する必要があります",
@@ -1793,8 +1842,28 @@
"successThresholdLabel": "回復成功しきい値",
"successThresholdExplain": "半開状態でこの回数成功するとサーキットブレーカーが閉じ、プロバイダーが再び利用可能になります",
"errorRateLabel": "エラー率しきい値",
"errorRateExplain": "失敗しきい値に達していなくても、エラー率がこの値を超えるとサーキットブレーカーが開きます"
}
"errorRateExplain": "失敗しきい値に達していなくても、エラー率がこの値を超えるとサーキットブレーカーが開きます",
"maxRetries": "最大リトライ回数",
"timeoutSettings": "タイムアウト設定",
"streamingFirstByte": "ストリーミング最初のバイトタイムアウト",
"streamingIdle": "ストリーミングアイドルタイムアウト",
"nonStreaming": "非ストリーミングタイムアウト",
"maxRetriesHint": "リクエスト失敗時のリトライ回数0-10",
"streamingFirstByteHint": "最初のデータチャンクを待つ最大時間、範囲 1-120 秒、デフォルト 60 秒",
"streamingIdleHint": "データチャンク間の最大間隔、範囲 60-600 秒、0 で無効化(途中停止を防止)",
"nonStreamingHint": "非ストリーミングリクエストの合計タイムアウト、範囲 60-1200 秒、デフォルト 600 秒10 分)"
},
"logging": {
"enabled": "ログ記録が有効になりました",
"disabled": "ログ記録が無効になりました",
"failed": "ログ状態の切り替えに失敗しました"
},
"server": {
"started": "プロキシサービスが開始されました - {{address}}:{{port}}",
"startFailed": "プロキシサービスの開始に失敗しました: {{detail}}"
},
"stoppedWithRestore": "プロキシサービスが停止し、すべてのテイクオーバー設定が復元されました",
"stopWithRestoreFailed": "停止に失敗しました: {{detail}}"
},
"streamCheck": {
"configSaved": "ヘルスチェック設定を保存しました",
@@ -1807,7 +1876,11 @@
"timeout": "タイムアウト(秒)",
"maxRetries": "最大リトライ回数",
"degradedThreshold": "劣化しきい値(ミリ秒)",
"testPrompt": "テストプロンプト"
"testPrompt": "テストプロンプト",
"operational": "{{providerName}} は正常に動作しています ({{responseTimeMs}}ms)",
"degraded": "{{providerName}} の応答が遅いです ({{responseTimeMs}}ms)",
"failed": "{{providerName}} のチェックに失敗しました: {{message}}",
"error": "{{providerName}} のチェックでエラーが発生しました: {{error}}"
},
"proxyConfig": {
"proxyEnabled": "プロキシ有効",
@@ -1826,14 +1899,31 @@
"nonStreaming": "非ストリーミングタイムアウト"
},
"circuitBreaker": {
"failureThreshold": "失敗しきい値",
"successThreshold": "成功しきい値",
"failureThreshold": "失敗値",
"successThreshold": "成功値",
"timeoutSeconds": "タイムアウト(秒)",
"errorRateThreshold": "エラー率しきい値",
"errorRateThreshold": "エラー率閾値 (%)",
"minRequests": "最小リクエスト数",
"validationFailed": "以下のフィールドが有効範囲外です: {{fields}}",
"configSaved": "サーキットブレーカー設定保存ました",
"saveFailed": "保存に失敗しました"
"configSaved": "サーキットブレーカー設定保存されました",
"saveFailed": "保存に失敗しました",
"loading": "読み込み中...",
"title": "サーキットブレーカー設定",
"description": "サーキットブレーカーパラメータを調整して、障害検出と復旧動作を制御します",
"failureThresholdHint": "連続失敗後にサーキットブレーカーを開く回数",
"timeoutSecondsHint": "サーキットブレーカーを開いた後、復旧を試みるまでの時間(半開状態)",
"successThresholdHint": "半開状態で成功してサーキットブレーカーを閉じる回数",
"errorRateThresholdHint": "エラー率がこの値を超えるとサーキットブレーカーを開く",
"minRequestsHint": "エラー率を計算する前の最小リクエスト数",
"saveConfig": "設定を保存",
"instructionsTitle": "設定説明",
"instructions": {
"failureThreshold": "連続失敗がこの回数に達するとサーキットブレーカーが開く",
"timeout": "サーキットブレーカーを開いた後、この時間待機してから半開を試みる",
"successThreshold": "半開状態で成功がこの回数に達するとサーキットブレーカーを閉じる",
"errorRate": "エラー率がこの値を超えるとサーキットブレーカーが開く",
"minRequests": "リクエスト数がこの値に達した後にのみエラー率が計算される"
}
},
"universalProvider": {
"title": "統合プロバイダー",

View File

@@ -38,7 +38,9 @@
"reset": "重置",
"actions": "操作",
"deleting": "删除中...",
"auto": "自动"
"auto": "自动",
"enabled": "已开启",
"notSet": "未设置"
},
"apiKeyInput": {
"placeholder": "请输入API Key",
@@ -579,7 +581,8 @@
"pricingLoadFailed": "加载计费配置失败:{{error}}",
"defaultCostMultiplierRequired": "默认倍率不能为空",
"defaultCostMultiplierInvalid": "默认倍率格式不正确"
}
},
"saveFailedGeneric": "保存失败,请重试"
},
"apps": {
"claude": "Claude",
@@ -633,7 +636,14 @@
"daysAgo": "{{count}} 天前",
"roleUser": "用户",
"roleSystem": "系统",
"roleTool": "工具"
"roleTool": "工具",
"resume": "恢复会话",
"resumeTooltip": "在终端中恢复此会话",
"noResumeCommand": "此会话无法恢复",
"copyCommand": "复制命令",
"copyMessage": "复制消息",
"messageCopied": "已复制消息内容",
"conversationHistory": "对话记录"
},
"console": {
"providerSwitchReceived": "收到供应商切换事件:",
@@ -755,7 +765,8 @@
"pleaseAddEndpoint": "请先添加端点",
"testUnavailable": "测速功能不可用",
"noResult": "未返回结果",
"testFailed": "测速失败: {{error}}"
"testFailed": "测速失败: {{error}}",
"empty": "暂无端点"
},
"providerAdvanced": {
"testConfig": "模型测试配置",
@@ -799,7 +810,9 @@
"extractNoCommonConfig": "当前编辑内容没有可提取的通用配置",
"extractFailed": "提取失败: {{error}}",
"saveFailed": "保存失败: {{error}}",
"modelNameHint": "指定使用的模型,将自动更新到 config.toml 中"
"modelNameHint": "指定使用的模型,将自动更新到 config.toml 中",
"modelName": "模型名称",
"modelNamePlaceholder": "例如: gpt-5-codex"
},
"geminiConfig": {
"envFile": "环境变量 (.env)",
@@ -944,7 +957,28 @@
"costBreakdown": "成本明细",
"performance": "性能信息",
"latency": "延迟",
"errorMessage": "错误信息"
"errorMessage": "错误信息",
"requests": "请求数",
"tokens": "Tokens",
"avgCost": "平均成本",
"avgLatency": "平均延迟",
"successRate": "成功率",
"requestId": "请求 ID",
"never": "从不",
"modelId": "模型 ID",
"modelIdRequired": "模型 ID 不能为空",
"inputCostPerMillion": "输入成本 (每百万 tokens, USD)",
"outputCostPerMillion": "输出成本 (每百万 tokens, USD)",
"invalidPrice": "价格必须为非负数",
"invalidTimeRange": "请选择完整的开始/结束时间",
"invalidTimeRangeOrder": "开始时间不能晚于结束时间",
"timeRangeTooLarge": "时间范围过大,请缩小范围",
"addPricing": "新增定价",
"editPricing": "编辑定价",
"pricingAdded": "定价已添加",
"pricingUpdated": "定价已更新",
"cacheReadCostPerMillion": "缓存读取成本 (每百万 tokens, USD)",
"cacheCreationCostPerMillion": "缓存写入成本 (每百万 tokens, USD)"
},
"usageScript": {
"title": "配置用量查询",
@@ -1367,7 +1401,9 @@
"stringifiedEnvVars": "env.vars 应为对象,但当前值看起来像被字符串化或已损坏。",
"stringifiedShellEnv": "env.shellEnv 应为对象,但当前值看起来像被字符串化或已损坏。",
"parseFailed": "openclaw.json 不是合法 JSON5。请先修复文件再通过这里编辑。"
}
},
"primaryModel": "默认模型",
"fallbackModel": "回退模型"
},
"env": {
"warning": {
@@ -1587,7 +1623,14 @@
"skillsPath": "Skills 路径",
"hint": "此操作将添加 Skill 仓库到列表。",
"hintDetail": "添加后,您可以在 Skills 管理界面中选择安装具体的 Skill。"
}
},
"usageScript": "用量查询",
"usageScriptEnabled": "已启用",
"usageScriptDisabled": "未启用",
"usageApiKey": "用量 API Key",
"usageBaseUrl": "用量查询地址",
"usageAutoInterval": "自动查询",
"usageAutoIntervalValue": "每 {{minutes}} 分钟"
},
"iconPicker": {
"search": "搜索图标",
@@ -1606,7 +1649,8 @@
"selectIcon": "选择图标",
"preview": "预览",
"clickToChange": "点击更换图标",
"clickToSelect": "点击选择图标"
"clickToSelect": "点击选择图标",
"color": "图标颜色"
},
"migration": {
"success": "配置迁移成功",
@@ -1743,7 +1787,12 @@
"hint": "选择要接管的应用,启用后该应用的请求将通过本地代理转发",
"enabled": "{{app}} 接管已启用",
"disabled": "{{app}} 接管已关闭",
"failed": "切换接管状态失败"
"failed": "切换接管状态失败",
"tooltip": {
"active": "{{appLabel}} 已接管 - {{address}}:{{port}}\n切换该应用供应商为热切换",
"broken": "{{appLabel}} 已接管,但代理服务未运行",
"inactive": "接管 {{appLabel}} 的 Live 配置,让该应用请求走本地代理"
}
},
"failover": {
"proxyRequired": "需要先启动代理服务才能配置故障转移",
@@ -1793,8 +1842,28 @@
"successThresholdLabel": "恢复成功阈值",
"successThresholdExplain": "半开状态下,成功达到此次数时关闭熔断器,供应商恢复可用",
"errorRateLabel": "错误率阈值",
"errorRateExplain": "错误率超过此值时,即使未达到失败阈值也会打开熔断器"
}
"errorRateExplain": "错误率超过此值时,即使未达到失败阈值也会打开熔断器",
"maxRetries": "最大重试次数",
"timeoutSettings": "超时配置",
"streamingFirstByte": "流式首字节超时",
"streamingIdle": "流式静默超时",
"nonStreaming": "非流式超时",
"maxRetriesHint": "请求失败时的重试次数0-10",
"streamingFirstByteHint": "等待首个数据块的最大时间,范围 1-120 秒,默认 60 秒",
"streamingIdleHint": "数据块之间的最大间隔,范围 60-600 秒,填 0 禁用(防止中途卡住)",
"nonStreamingHint": "非流式请求的总超时时间,范围 60-1200 秒,默认 600 秒10 分钟)"
},
"logging": {
"enabled": "日志记录已启用",
"disabled": "日志记录已关闭",
"failed": "切换日志状态失败"
},
"server": {
"started": "代理服务已启动 - {{address}}:{{port}}",
"startFailed": "启动代理服务失败: {{detail}}"
},
"stoppedWithRestore": "代理服务已关闭,已恢复所有接管配置",
"stopWithRestoreFailed": "停止失败: {{detail}}"
},
"streamCheck": {
"configSaved": "健康检查配置已保存",
@@ -1807,7 +1876,11 @@
"timeout": "超时时间(秒)",
"maxRetries": "最大重试次数",
"degradedThreshold": "降级阈值(毫秒)",
"testPrompt": "检查提示词"
"testPrompt": "检查提示词",
"operational": "{{providerName}} 运行正常 ({{responseTimeMs}}ms)",
"degraded": "{{providerName}} 响应较慢 ({{responseTimeMs}}ms)",
"failed": "{{providerName}} 检查失败: {{message}}",
"error": "{{providerName}} 检查出错: {{error}}"
},
"proxyConfig": {
"proxyEnabled": "代理总开关",
@@ -1828,12 +1901,29 @@
"circuitBreaker": {
"failureThreshold": "失败阈值",
"successThreshold": "成功阈值",
"timeoutSeconds": "超时时间",
"errorRateThreshold": "错误率阈值",
"timeoutSeconds": "超时时间(秒)",
"errorRateThreshold": "错误率阈值 (%)",
"minRequests": "最小请求数",
"validationFailed": "以下字段超出有效范围: {{fields}}",
"configSaved": "熔断器配置已保存",
"saveFailed": "保存失败"
"saveFailed": "保存失败",
"loading": "加载中...",
"title": "熔断器配置",
"description": "调整熔断器参数以控制故障检测和恢复行为",
"failureThresholdHint": "连续失败多少次后打开熔断器",
"timeoutSecondsHint": "熔断器打开后多久尝试恢复(半开状态)",
"successThresholdHint": "半开状态下成功多少次后关闭熔断器",
"errorRateThresholdHint": "错误率超过此值时打开熔断器",
"minRequestsHint": "计算错误率前的最小请求数",
"saveConfig": "保存配置",
"instructionsTitle": "配置说明",
"instructions": {
"failureThreshold": "连续失败达到此次数时,熔断器打开",
"timeout": "熔断器打开后,等待此时间后尝试半开",
"successThreshold": "半开状态下,成功达到此次数时关闭熔断器",
"errorRate": "错误率超过此值时,熔断器打开",
"minRequests": "只有请求数达到此值后才计算错误率"
}
},
"universalProvider": {
"title": "统一供应商",