diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs index 30ebc8c52..8d866ab5f 100644 --- a/src-tauri/src/settings.rs +++ b/src-tauri/src/settings.rs @@ -443,7 +443,7 @@ impl AppSettings { .language .as_ref() .map(|s| s.trim()) - .filter(|s| matches!(*s, "en" | "zh" | "ja")) + .filter(|s| matches!(*s, "en" | "zh" | "zh-TW" | "ja")) .map(|s| s.to_string()); if let Some(sync) = &mut self.webdav_sync { diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 42072312f..71842a5ad 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -47,6 +47,14 @@ impl TrayTexts { quit: "終了", _auto_label: "自動 (フェイルオーバー)", }, + "zh-TW" => Self { + show_main: "開啟主介面", + open_website: "開啟官方網站", + no_providers_label: "(無供應商)", + lightweight_mode: "輕量模式", + quit: "退出", + _auto_label: "自動 (故障轉移)", + }, _ => Self { show_main: "打开主界面", open_website: "打开官方网站", diff --git a/src/components/settings/LanguageSettings.tsx b/src/components/settings/LanguageSettings.tsx index 8ef2cb131..ea733749a 100644 --- a/src/components/settings/LanguageSettings.tsx +++ b/src/components/settings/LanguageSettings.tsx @@ -2,7 +2,7 @@ import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { useTranslation } from "react-i18next"; -type LanguageOption = "zh" | "en" | "ja"; +type LanguageOption = "zh" | "zh-TW" | "en" | "ja"; interface LanguageSettingsProps { value: LanguageOption; @@ -24,6 +24,12 @@ export function LanguageSettings({ value, onChange }: LanguageSettingsProps) { onChange("zh")}> {t("settings.languageOptionChinese")} + onChange("zh-TW")} + > + {t("settings.languageOptionTraditionalChinese")} + onChange("en")}> {t("settings.languageOptionEnglish")} diff --git a/src/components/usage/RequestDetailPanel.tsx b/src/components/usage/RequestDetailPanel.tsx index 6a2c7619f..f39547198 100644 --- a/src/components/usage/RequestDetailPanel.tsx +++ b/src/components/usage/RequestDetailPanel.tsx @@ -22,9 +22,11 @@ export function RequestDetailPanel({ const dateLocale = i18n.language === "zh" ? "zh-CN" - : i18n.language === "ja" - ? "ja-JP" - : "en-US"; + : i18n.language === "zh-TW" + ? "zh-TW" + : i18n.language === "ja" + ? "ja-JP" + : "en-US"; if (isLoading) { return ( diff --git a/src/components/usage/format.ts b/src/components/usage/format.ts index 404f4b056..4c9cc303d 100644 --- a/src/components/usage/format.ts +++ b/src/components/usage/format.ts @@ -31,10 +31,28 @@ export function fmtUsd( return `$${num.toFixed(digits)}`; } +function normalizeLanguageTag(language: string): string { + return language.toLowerCase().replace(/_/g, "-"); +} + +function isTraditionalChineseLanguage(normalizedLanguage: string): boolean { + return ( + normalizedLanguage === "zh-tw" || + normalizedLanguage.startsWith("zh-hant") || + normalizedLanguage.startsWith("zh-hk") || + normalizedLanguage.startsWith("zh-mo") + ); +} + export function getLocaleFromLanguage(language: string): string { if (!language) return "en-US"; - if (language.startsWith("zh")) return "zh-CN"; - if (language.startsWith("ja")) return "ja-JP"; + const normalized = normalizeLanguageTag(language); + if (normalized === "zh") return "zh-CN"; + if (isTraditionalChineseLanguage(normalized)) { + return "zh-TW"; + } + if (normalized.startsWith("zh")) return "zh-CN"; + if (normalized.startsWith("ja")) return "ja-JP"; return "en-US"; } @@ -61,7 +79,13 @@ export function formatTokensShort( ): string { if (!Number.isFinite(value) || value <= 0) return "0"; const decimals = compactDecimals; - if (lang.startsWith("zh") || lang.startsWith("ja")) { + const normalizedLang = normalizeLanguageTag(lang); + if (isTraditionalChineseLanguage(normalizedLang)) { + if (value >= 1e8) return `${(value / 1e8).toFixed(2)} 億`; + if (value >= 1e4) return `${(value / 1e4).toFixed(decimals)} 萬`; + return value.toLocaleString("zh-TW"); + } + if (normalizedLang.startsWith("zh") || normalizedLang.startsWith("ja")) { if (value >= 1e8) return `${(value / 1e8).toFixed(2)} 亿`; if (value >= 1e4) return `${(value / 1e4).toFixed(decimals)} 万`; return value.toLocaleString(); diff --git a/src/hooks/useDragSort.ts b/src/hooks/useDragSort.ts index c7df771b5..4d843f54d 100644 --- a/src/hooks/useDragSort.ts +++ b/src/hooks/useDragSort.ts @@ -18,7 +18,12 @@ export function useDragSort(providers: Record, appId: AppId) { const { t, i18n } = useTranslation(); const sortedProviders = useMemo(() => { - const locale = i18n.language === "zh" ? "zh-CN" : "en-US"; + const locale = + i18n.language === "zh" + ? "zh-CN" + : i18n.language === "zh-TW" + ? "zh-TW" + : "en-US"; return Object.values(providers).sort((a, b) => { if (a.sortIndex !== undefined && b.sortIndex !== undefined) { return a.sortIndex - b.sortIndex; diff --git a/src/hooks/useSettingsForm.ts b/src/hooks/useSettingsForm.ts index df2323c6a..de625ffc1 100644 --- a/src/hooks/useSettingsForm.ts +++ b/src/hooks/useSettingsForm.ts @@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next"; import { useSettingsQuery } from "@/lib/query"; import type { Settings } from "@/types"; -type Language = "zh" | "en" | "ja"; +type Language = "zh" | "zh-TW" | "en" | "ja"; export type SettingsFormState = Omit & { language: Language; @@ -11,8 +11,38 @@ export type SettingsFormState = Omit & { const normalizeLanguage = (lang?: string | null): Language => { if (!lang) return "zh"; - const normalized = lang.toLowerCase(); - return normalized === "en" || normalized === "ja" ? normalized : "zh"; + const normalized = lang.toLowerCase().replace(/_/g, "-"); + + if (normalized === "zh") { + return "zh"; + } + + if ( + normalized === "zh-tw" || + normalized.startsWith("zh-hant") || + normalized.startsWith("zh-hk") || + normalized.startsWith("zh-mo") + ) { + return "zh-TW"; + } + + if (normalized === "en" || normalized === "ja") { + return normalized; + } + + if (normalized.startsWith("zh")) { + return "zh"; + } + + return "zh"; +}; + +const isSupportedLanguage = (lang?: string | null): boolean => { + if (!lang) return false; + const normalized = lang.toLowerCase().replace(/_/g, "-"); + return ( + normalized === "en" || normalized === "ja" || normalized.startsWith("zh") + ); }; const sanitizeDir = (value?: string | null): string | undefined => { @@ -52,8 +82,8 @@ export function useSettingsForm(): UseSettingsFormResult { const readPersistedLanguage = useCallback((): Language => { if (typeof window !== "undefined") { const stored = window.localStorage.getItem("language"); - if (stored === "en" || stored === "zh" || stored === "ja") { - return stored as Language; + if (isSupportedLanguage(stored)) { + return normalizeLanguage(stored); } } return normalizeLanguage(i18n.language); diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 81c55275f..428542bb9 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -4,8 +4,9 @@ import { initReactI18next } from "react-i18next"; import en from "./locales/en.json"; import ja from "./locales/ja.json"; import zh from "./locales/zh.json"; +import zhTW from "./locales/zh-TW.json"; -type Language = "zh" | "en" | "ja"; +type Language = "zh" | "zh-TW" | "en" | "ja"; const DEFAULT_LANGUAGE: Language = "zh"; @@ -13,7 +14,12 @@ const getInitialLanguage = (): Language => { if (typeof window !== "undefined") { try { const stored = window.localStorage.getItem("language"); - if (stored === "zh" || stored === "en" || stored === "ja") { + if ( + stored === "zh" || + stored === "zh-TW" || + stored === "en" || + stored === "ja" + ) { return stored; } } catch (error) { @@ -27,6 +33,19 @@ const getInitialLanguage = (): Language => { navigator.languages?.[0]?.toLowerCase()) : undefined; + if (navigatorLang === "zh") { + return "zh"; + } + + if ( + navigatorLang?.startsWith("zh-tw") || + navigatorLang?.startsWith("zh-hk") || + navigatorLang?.startsWith("zh-mo") || + navigatorLang?.startsWith("zh-hant") + ) { + return "zh-TW"; + } + if (navigatorLang?.startsWith("zh")) { return "zh"; } @@ -52,6 +71,9 @@ const resources = { zh: { translation: zh, }, + "zh-TW": { + translation: zhTW, + }, }; i18n.use(initReactI18next).init({ diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 44467d4a2..97c5e9235 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -542,7 +542,8 @@ } }, "autoReload": "Data refreshed", - "languageOptionChinese": "中文", + "languageOptionChinese": "简体中文", + "languageOptionTraditionalChinese": "繁體中文", "languageOptionEnglish": "English", "languageOptionJapanese": "日本語", "windowBehavior": "Window Behavior", diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 2b1d39d60..093e284c1 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -542,7 +542,8 @@ } }, "autoReload": "データを更新しました", - "languageOptionChinese": "中文", + "languageOptionChinese": "简体中文", + "languageOptionTraditionalChinese": "繁體中文", "languageOptionEnglish": "English", "languageOptionJapanese": "日本語", "windowBehavior": "ウィンドウ動作", diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json new file mode 100644 index 000000000..2fcf1e22c --- /dev/null +++ b/src/i18n/locales/zh-TW.json @@ -0,0 +1,2634 @@ +{ + "app": { + "title": "CC Switch", + "description": "Claude Code / Codex / Gemini CLI 全方位輔助工具" + }, + "common": { + "add": "新增", + "edit": "編輯", + "delete": "刪除", + "save": "儲存", + "saving": "儲存中...", + "cancel": "取消", + "confirm": "確認", + "close": "關閉", + "done": "完成", + "settings": "設定", + "about": "關於", + "version": "版本", + "loading": "載入中...", + "notInstalled": "未安裝", + "success": "成功", + "error": "錯誤", + "unknown": "未知", + "enterValidValue": "請輸入有效的內容", + "clear": "清除", + "toggleTheme": "切換主題", + "format": "格式化", + "formatSuccess": "格式化成功", + "formatError": "格式化失敗:{{error}}", + "copy": "複製", + "view": "檢視", + "back": "返回", + "refresh": "重新整理", + "refreshing": "重新整理中...", + "import": "匯入", + "all": "全部", + "search": "搜尋", + "reset": "重設", + "actions": "操作", + "deleting": "刪除中...", + "auto": "自動", + "enabled": "已啟用", + "notSet": "未設定" + }, + "firstRunNotice": { + "title": "歡迎使用 CC Switch", + "bodyDefault": "CC Switch 可以協助您在 Claude Code / Codex / Gemini CLI 的多個供應商之間一鍵切換。如果您之前已經設定過這些工具,CC Switch 會自動將現有設定儲存為名為 default 的供應商,確保您的設定不會遺失。", + "bodyOfficial": "清單中還預設了「官方 (Official)」供應商,隨時點擊即可切換回官方預設設定。切換前 CC Switch 會自動將目前設定備份回 default,可以放心來回切換。這就是 CC Switch 的運作方式。", + "confirm": "我了解了" + }, + "apiKeyInput": { + "placeholder": "請輸入 API Key", + "show": "顯示 API Key", + "hide": "隱藏 API Key" + }, + "jsonEditor": { + "mustBeObject": "設定必須是 JSON 物件,不能是陣列或其他類型", + "invalidJson": "JSON 格式錯誤" + }, + "commonConfig": { + "guideTitle": "什麼是通用設定片段?", + "guidePurpose": "用來在不同供應商之間共用外掛程式、環境變數等非敏感設定。切換供應商時不會遺失這些設定。", + "guideUsage": "用法:① 點擊「從編輯內容擷取」儲存通用部分 ② 新增供應商時勾選「寫入通用設定」", + "guideReExtract": "如果您新安裝了外掛程式或 Hook,請重新擷取一次通用設定,以便同步至其他供應商。", + "guideReassurance": "請放心:您的原始設定已儲存在預設供應商中,不會遺失。", + "emptyTitle": "尚未建立通用設定片段", + "emptyHint": "點擊下方「從編輯內容擷取」按鈕,從目前設定中擷取可重複使用的部分" + }, + "claudeConfig": { + "configLabel": "Claude Code 設定 (JSON) *", + "writeCommonConfig": "寫入通用設定", + "editCommonConfig": "編輯通用設定", + "editCommonConfigTitle": "編輯通用設定片段", + "commonConfigHint": "該片段會在勾選「寫入通用設定」時合併到 settings.json 中", + "fullSettingsHint": "完整的 Claude Code settings.json 設定內容", + "extractFromCurrent": "從編輯內容擷取", + "extractNoCommonConfig": "目前編輯內容沒有可擷取的通用設定", + "extractFailed": "擷取失敗:{{error}}", + "saveFailed": "儲存失敗:{{error}}", + "hideAttribution": "隱藏 AI 署名", + "enableTeammates": "Teammates 模式", + "enableToolSearch": "啟用 Tool Search", + "effortMax": "最大強度思考", + "disableAutoUpgrade": "停用自動升級" + }, + "header": { + "viewOnGithub": "在 GitHub 上檢視", + "toggleDarkMode": "切換至深色模式", + "toggleLightMode": "切換至淺色模式", + "addProvider": "新增供應商", + "switchToChinese": "切換至中文", + "switchToEnglish": "切換至英文", + "enterEditMode": "進入編輯模式", + "exitEditMode": "退出編輯模式", + "windowMinimize": "最小化視窗", + "windowMaximize": "最大化視窗", + "windowRestore": "還原視窗", + "windowClose": "關閉視窗" + }, + "provider": { + "tabProvider": "供應商", + "tabUniversal": "通用供應商", + "noProviders": "尚未新增任何供應商", + "noProvidersDescription": "如果您已有設定,請點擊「匯入目前設定」,所有資料將安全儲存在 default 供應商中", + "noProvidersDescriptionSnippet": "除 API Key 和請求位址外的資料(如外掛程式設定)會被儲存至通用設定片段,用於在不同供應商之間共用", + "importCurrent": "匯入目前設定", + "importFromClaude": "將 Claude Code 中已有的供應商匯入", + "importCurrentDescription": "將目前正在使用的設定匯入為預設供應商", + "currentlyUsing": "目前使用", + "enable": "啟用", + "inUse": "使用中", + "blockedByProxy": "已攔截", + "editProvider": "編輯供應商", + "editProviderHint": "更新設定後將立即套用至目前供應商。", + "deleteProvider": "刪除供應商", + "addNewProvider": "新增供應商", + "addClaudeProvider": "新增 Claude Code 供應商", + "addCodexProvider": "新增 Codex 供應商", + "addGeminiProvider": "新增 Gemini 供應商", + "addOpenCodeProvider": "新增 OpenCode 供應商", + "addToConfig": "新增", + "removeFromConfig": "移除", + "setAsDefault": "設為預設", + "isDefault": "目前預設", + "inConfig": "已新增", + "addProviderHint": "填寫資訊後即可在清單中快速切換供應商。", + "editClaudeProvider": "編輯 Claude Code 供應商", + "editCodexProvider": "編輯 Codex 供應商", + "configError": "設定錯誤", + "notConfigured": "未設定官網位址", + "applyToClaudePlugin": "套用至 Claude 外掛程式", + "removeFromClaudePlugin": "從 Claude 外掛程式移除", + "dragToReorder": "拖曳以重新排序", + "dragHandle": "拖曳排序", + "searchPlaceholder": "依名稱/備註/網址搜尋供應商...", + "searchAriaLabel": "搜尋供應商", + "searchScopeHint": "根據名稱、備註和官網連結比對結果。", + "searchCloseHint": "按 Esc 關閉", + "searchCloseAriaLabel": "關閉供應商搜尋", + "noSearchResults": "沒有符合搜尋條件的供應商。", + "duplicate": "複製", + "sortUpdateFailed": "排序更新失敗", + "configureUsage": "設定用量查詢", + "officialPartner": "官方合作夥伴", + "managedByHermes": "Hermes 託管", + "managedByHermesHint": "該專案定義於 Hermes 的 providers: dict,請在 Hermes Web UI 中編輯或刪除。", + "openTerminal": "開啟終端機", + "terminalOpened": "終端機已開啟", + "terminalOpenFailed": "開啟終端機失敗", + "name": "供應商名稱", + "namePlaceholder": "例如:Claude 官方", + "websiteUrl": "官網連結", + "notes": "備註", + "notesPlaceholder": "例如:公司專用帳號", + "configJson": "設定 JSON", + "writeCommonConfig": "寫入通用設定", + "editCommonConfigButton": "編輯通用設定", + "configJsonHint": "請填寫完整的 Claude Code 設定", + "editCommonConfigTitle": "編輯通用設定片段", + "editCommonConfigHint": "通用設定片段將合併至所有啟用它的供應商設定中", + "addProvider": "新增供應商", + "sortUpdated": "排序已更新", + "usageSaved": "用量查詢設定已儲存", + "usageSaveFailed": "用量查詢設定儲存失敗", + "geminiConfig": "Gemini 設定", + "geminiConfigHint": "使用 .env 格式設定 Gemini", + "form": { + "gemini": { + "model": "模型", + "oauthTitle": "OAuth 驗證模式", + "oauthHint": "Google 官方使用 OAuth 個人驗證,無需填寫 API Key。首次使用時會自動開啟瀏覽器進行登入。", + "apiKeyPlaceholder": "請輸入 Gemini API Key" + } + } + }, + "claudeCode": { + "needsRouting": "需要路由", + "noRoutingSupport": "不支援路由" + }, + "codex": { + "needsRouting": "需要路由", + "noRoutingSupport": "不支援路由" + }, + "claudeDesktop": { + "officialNotice": "Claude Desktop 官方供應商使用應用程式內建的 1P 登入,無需設定 API Key 和 API 位址。", + "mode": "模型處理方式", + "modeDirect": "直連", + "modeProxy": "需要路由", + "modelMappingToggle": "需要模型對應", + "modelMappingOffHint": "如果您的供應商提供的不是原生 Claude 系列模型,請開啟此開關。", + "modelMappingOnHint": "Claude Desktop 目前對模型 ID 進行了限制,如果您的供應商提供的模型不是 Claude 系列模型,則需要開啟本開關,並在使用過程中保持本地路由開啟。", + "routeMapTitle": "模型對應", + "routeMapHint": "選擇模型角色後,CC Switch 會自動產生 Claude Desktop 相容路由;選單顯示名稱可以填寫 DeepSeek、Kimi 等品牌模型,實際請求模型依右側填寫內容發送。", + "routeModelLabel": "模型角色", + "routeRoleSonnet": "Sonnet", + "routeRoleOpus": "Opus", + "routeRoleHaiku": "Haiku", + "labelOverrideLabel": "選單顯示名稱", + "upstreamModelLabel": "實際請求模型", + "supports1mLabel": "聲明支援 1M", + "supports1mShort": "1M", + "directModelListTitle": "手動指定 Claude Desktop 模型清單(進階,選填)", + "directModelListCollapsedHint": "原生 Claude 模型供應商通常不需填寫,Claude Desktop 會自動讀取 /v1/models。", + "directModelListHint": "僅當供應商的 /v1/models 不可用或沒有回傳 Claude Desktop 可識別的 claude-* 模型名稱時填寫;勾選 1M 會向 Claude Desktop 聲明支援 1M 上下文。", + "directModelInvalid": "直連模型必須使用 claude-* / anthropic/claude-* 模型名稱", + "addModel": "新增模型", + "addRoute": "新增模型", + "routeInvalid": "請選擇模型角色並填寫實際請求模型", + "routesRequired": "至少填寫一個模型對應", + "statusTitle": "Claude Desktop 設定需要檢查", + "statusUnsupported": "目前平台暫不支援 Claude Desktop 3P 設定寫入。", + "statusStaleRawModels": "Claude Desktop profile 中存在非 claude-* 模型名稱,新版 Claude Desktop 可能拒絕載入;重新切換目前供應商可修復。", + "statusMissingRouteMappings": "目前供應商啟用了模型對應,但沒有有效路由;請編輯供應商並補全至少一個模型對應。", + "statusGatewayTokenMissing": "目前本地路由 token 尚未產生;重新切換該供應商會寫入新的本地 token。", + "statusBaseUrlMismatch": "Claude Desktop profile 指向的位址與目前供應商不一致;目前為 {{actual}},應為 {{expected}}。重新切換目前供應商可修復。", + "route": { + "tooltip": { + "active": "Claude Desktop 本地路由已開啟 - {{address}}:{{port}}", + "inactive": "開啟 Claude Desktop 本地路由,用於需要模型對應或格式轉換的供應商。目前設定位址:{{address}}:{{port}}" + } + } + }, + "notifications": { + "providerAdded": "供應商已新增", + "providerSaved": "供應商設定已儲存", + "providerDeleted": "供應商刪除成功", + "switchSuccess": "切換成功!", + "claudeDesktopRestartRequired": "切換成功,重新啟動 Claude Desktop 後生效", + "claudeDesktopProxyRestartRequired": "切換成功,請保持 CC Switch 執行,並重新啟動 Claude Desktop 後生效", + "addToConfigSuccess": "已新增至設定", + "removeFromConfigSuccess": "已從設定移除", + "switchFailedTitle": "切換失敗", + "switchFailed": "切換失敗:{{error}}", + "autoImported": "已從現有設定建立預設供應商", + "addFailed": "新增供應商失敗:{{error}}", + "saveFailed": "儲存失敗:{{error}}", + "saveFailedGeneric": "儲存失敗,請重試", + "appliedToClaudePlugin": "已套用至 Claude 外掛程式", + "removedFromClaudePlugin": "已從 Claude 外掛程式移除", + "syncClaudePluginFailed": "同步 Claude 外掛程式失敗", + "skipClaudeOnboardingFailed": "跳過 Claude Code 初次安裝確認失敗", + "clearClaudeOnboardingSkipFailed": "還原 Claude Code 初次安裝確認失敗", + "updateSuccess": "供應商更新成功", + "updateFailed": "更新供應商失敗:{{error}}", + "deleteSuccess": "供應商已刪除", + "deleteFailed": "刪除供應商失敗:{{error}}", + "settingsSaved": "設定已儲存", + "settingsSaveFailed": "儲存設定失敗:{{error}}", + "proxyRequiredForSwitch": "此供應商 {{reason}},需要路由服務才能正常使用,請先啟動路由", + "proxyReasonCopilot": "使用 GitHub Copilot 作為 Claude 供應商", + "proxyReasonOpenAIChat": "使用 OpenAI Chat API 格式", + "proxyReasonOpenAIResponses": "使用 OpenAI Responses API 格式", + "proxyReasonFullUrl": "開啟了完整 URL 連線模式", + "openAIFormatHint": "此供應商使用 OpenAI 相容格式,需要開啟路由服務才能正常使用", + "copilotProxyHint": "GitHub Copilot 作為 Claude 供應商時始終需要本地路由;路由會根據目前模型自動選擇 Chat Completions 或 Responses。", + "openLinkFailed": "連結開啟失敗", + "openclawModelsRegistered": "模型已註冊至 /model 清單", + "openclawDefaultModelSet": "已設為預設模型", + "openclawDefaultModelSetFailed": "設定預設模型失敗", + "openclawNoModels": "該供應商沒有設定模型", + "backfillWarning": "切換成功,但舊供應商設定回填失敗,您手動修改的設定可能未儲存", + "windowControlFailed": "視窗控制失敗:{{error}}", + "officialBlockedByProxy": "本地路由模式下不能切換至官方供應商,使用路由存取官方 API 可能導致帳號被封鎖", + "proxyOfficialWarning": "目前供應商 {{name}} 是官方供應商,建議切換至第三方供應商後再使用本地路由" + }, + "confirm": { + "deleteProvider": "刪除供應商", + "deleteProviderMessage": "確定要刪除供應商「{{name}}」嗎?此操作無法復原。", + "removeProvider": "移除供應商", + "removeProviderMessage": "確定要從設定中移除供應商「{{name}}」嗎?\n\n移除後該供應商將不再生效,但設定資料會保留在 CC Switch 中,您可以隨時重新新增。", + "proxy": { + "title": "啟用本地路由服務", + "message": "本地路由是一項進階功能,啟用前請確保您已了解其運作原理。\n\n建議先查閱相關文件或諮詢您的供應商,以取得正確的設定方式。", + "confirm": "我已了解,繼續啟用" + }, + "failover": { + "title": "啟用故障轉移功能", + "message": "故障轉移是一項進階功能,啟用前請確保您已了解其運作原理。\n\n建議先在故障轉移佇列中設定好供應商優先順序。", + "confirm": "我已了解,繼續啟用" + }, + "usage": { + "title": "設定用量查詢", + "message": "用量查詢需要設定專用的查詢腳本或 API 參數,請確保您已從供應商處取得相關資訊。\n\n如不確定如何設定,請先查閱供應商文件。", + "confirm": "我已了解,繼續設定" + }, + "streamCheck": { + "title": "模型健康檢測", + "message": "健康檢測透過直接發送 API 請求來測試供應商連線能力,以下情況可能導致檢測失敗:\n\n• 官方供應商(使用 OAuth 登入,無獨立 API Key)\n• 部分中繼服務(會驗證請求是否來自 Claude Code CLI)\n• AWS Bedrock(使用 IAM 簽章驗證)\n\n檢測失敗不代表供應商不可用,僅表示無法透過獨立請求驗證。請以應用程式內的實際情況為準。", + "confirm": "我已了解,繼續檢測" + }, + "autoSync": { + "title": "開啟自動同步", + "message": "開啟自動同步後,每次資料庫變更都會自動上傳至 WebDAV 伺服器。\n\n這可能會產生較高的網路流量消耗,請確保您的網路環境和 WebDAV 服務支援頻繁的資料傳輸。", + "confirm": "我已了解,繼續開啟" + }, + "commonConfig": { + "title": "關於通用設定", + "message": "「通用設定片段」可以在不同供應商之間共用外掛程式、環境變數等設定,避免切換供應商時遺失這些設定。\n\n使用方法:\n① 編輯供應商時點擊「編輯通用設定」→「從編輯內容擷取」\n② 新增供應商時勾選「寫入通用設定」(預設已勾選)\n\n如果您新安裝了外掛程式或 Hook,請重新擷取一次通用設定。", + "confirm": "我了解了" + } + }, + "settings": { + "title": "設定", + "general": "通用", + "tabGeneral": "通用", + "tabAuth": "驗證", + "tabAdvanced": "進階", + "tabProxy": "路由", + "authCenter": { + "title": "OAuth 驗證中心", + "description": "在 Claude Code 中使用您的其他訂閱,請注意合規風險。", + "beta": "Beta", + "copilotDescription": "管理 GitHub Copilot 帳號", + "codexOauthDescription": "管理 ChatGPT 帳號" + }, + "advanced": { + "configDir": { + "title": "設定檔目錄", + "description": "管理 Claude、Codex 和 Gemini 的設定儲存路徑" + }, + "proxy": { + "title": "本地路由", + "description": "控制路由服務開關、查看狀態與連接埠資訊", + "enableFeature": "在主頁面顯示本地路由開關", + "enableFeatureDescription": "開啟後,主頁面頂部將顯示路由和故障轉移開關", + "enableFailoverToggle": "在主頁面顯示故障轉移開關", + "enableFailoverToggleDescription": "開啟後,主頁面頂部將獨立顯示故障轉移開關", + "running": "執行中", + "stopped": "已停止" + }, + "modelTest": { + "title": "模型測試設定", + "description": "設定模型測試使用的預設模型和提示詞" + }, + "failover": { + "title": "自動故障轉移", + "description": "設定故障轉移佇列和斷路器策略" + }, + "pricing": { + "title": "成本定價", + "description": "管理各模型 Token 計費規則" + }, + "globalProxy": { + "title": "全域出站代理伺服器", + "description": "設定 CC Switch 存取外部 API 時使用的代理伺服器" + }, + "data": { + "title": "資料管理", + "description": "匯入和匯出本地設定資料" + }, + "backup": { + "title": "備份與還原", + "description": "管理自動備份,查看和還原資料庫快照" + }, + "cloudSync": { + "title": "雲端同步", + "description": "透過 WebDAV 在多裝置間同步資料" + }, + "rectifier": { + "title": "整流器", + "description": "自動修復 API 請求中的相容性問題", + "enabled": "啟用整流器", + "enabledDescription": "總開關,關閉後所有整流功能將被停用", + "requestGroup": "請求整流", + "responseGroup": "回應整流", + "thinkingSignature": "Thinking 簽章整流", + "thinkingSignatureDescription": "當 Anthropic 類型供應商回傳 thinking 簽章不相容或非法請求等錯誤時,自動移除不相容的 thinking 相關區塊,並對同一供應商重試一次", + "thinkingBudget": "Thinking Budget 整流", + "thinkingBudgetDescription": "當 Anthropic 類型供應商回傳 budget_tokens 限制錯誤(如至少 1024)時,自動將 thinking 規範為 enabled,並將 budget 設為 32000,同時在需要時將 max_tokens 設為 64000,然後重試一次" + }, + "optimizer": { + "title": "Bedrock 請求最佳化工具", + "description": "在請求發送前自動最佳化 Thinking 和 Cache 設定(僅 Bedrock 供應商生效)", + "enabled": "啟用最佳化工具", + "thinkingOptimizer": "Thinking 最佳化", + "thinkingOptimizerDescription": "自動為 Opus/Sonnet 啟用 Adaptive Thinking,為舊模型注入 Extended Thinking", + "cacheInjection": "Cache 注入", + "cacheInjectionDescription": "自動在請求關鍵位置注入 Cache 斷點,減少重複 token 計費", + "cacheTtl": "Cache TTL", + "cacheTtl5m": "5 分鐘", + "cacheTtl1h": "1 小時" + }, + "logConfig": { + "title": "日誌管理", + "description": "控制日誌輸出層級", + "enabled": "啟用日誌", + "enabledDescription": "總開關,關閉後所有日誌將被停用", + "level": "日誌層級", + "levelDescription": "設定輸出的最低日誌層級", + "levels": { + "error": "錯誤", + "warn": "警告", + "info": "資訊", + "debug": "偵錯", + "trace": "追蹤" + }, + "levelHint": "日誌層級說明:", + "levelDesc": { + "error": "僅嚴重錯誤", + "warn": "錯誤 + 警告資訊", + "info": "一般操作資訊(預設)", + "debug": "詳細資訊,包含 SSE 串流與請求/回應詳情", + "trace": "全部日誌,最詳細" + } + } + }, + "language": "介面語言", + "languageHint": "切換後立即預覽介面語言,儲存後永久生效。", + "theme": "外觀主題", + "themeHint": "選擇應用程式的外觀主題,立即生效。", + "themeLight": "淺色", + "themeDark": "深色", + "themeSystem": "跟隨系統", + "importExport": "SQL 匯入匯出", + "importExportHint": "匯入/匯出資料庫 SQL 備份(僅支援匯入由 CC Switch 匯出的備份),便於備份或遷移。", + "exportConfig": "匯出 SQL 備份", + "selectConfigFile": "選擇 SQL 檔案", + "noFileSelected": "尚未選擇設定檔。", + "import": "匯入", + "importing": "匯入中...", + "importSuccess": "匯入成功!", + "importFailed": "匯入失敗", + "syncLiveFailed": "已匯入,但同步至目前供應商失敗,請手動重新選擇一次供應商。", + "importPartialSuccess": "設定已匯入,但同步至目前供應商失敗。", + "importPartialHint": "請手動重新選擇一次供應商以重新整理對應設定。", + "configExported": "設定已匯出至:", + "exportFailed": "匯出失敗", + "selectFileFailed": "請選擇有效的 SQL 備份檔案", + "configCorrupted": "SQL 檔案可能已損壞或格式不正確", + "backupId": "備份 ID", + "backupManager": { + "title": "資料庫備份", + "description": "自動備份的資料庫快照,可用於還原至之前的狀態", + "empty": "暫無備份", + "restore": "還原", + "restoring": "還原中...", + "confirmTitle": "確認還原備份", + "confirmMessage": "還原至此備份將覆寫目前資料庫。還原前會自動建立安全備份。", + "restoreSuccess": "還原成功!安全備份已建立", + "restoreFailed": "還原失敗", + "safetyBackupId": "安全備份 ID", + "intervalLabel": "自動備份間隔", + "retainLabel": "備份保留數量", + "intervalDisabled": "停用", + "intervalHours": "{{hours}} 小時", + "intervalDays": "{{days}} 天", + "rename": "重新命名", + "renameSuccess": "備份重新命名成功", + "renameFailed": "重新命名失敗", + "namePlaceholder": "輸入新名稱", + "createBackup": "立即備份", + "creating": "備份中...", + "createSuccess": "備份建立成功", + "createFailed": "備份建立失敗", + "delete": "刪除", + "deleting": "刪除中...", + "deleteSuccess": "備份已刪除", + "deleteFailed": "刪除失敗", + "deleteConfirmTitle": "確認刪除備份", + "deleteConfirmMessage": "此備份將被永久刪除,此操作無法復原。" + }, + "webdavSync": { + "title": "WebDAV 雲端同步", + "description": "透過 WebDAV 在多裝置間同步資料庫和技能設定。", + "baseUrl": "WebDAV 伺服器位址", + "baseUrlPlaceholder": "https://dav.jianguoyun.com/dav/", + "username": "WebDAV 帳號", + "usernamePlaceholder": "信箱帳號", + "password": "WebDAV 密碼", + "passwordPlaceholder": "應用程式密碼(堅果雲請使用「第三方應用程式密碼」)", + "remoteRoot": "遠端根目錄", + "profile": "同步設定名稱", + "autoSync": "自動同步", + "autoSyncHint": "開啟後每次資料庫變更都會自動上傳至 WebDAV。", + "test": "測試連線", + "testing": "測試中...", + "testSuccess": "連線成功", + "testFailed": "連線失敗:{{error}}", + "save": "儲存設定", + "saving": "儲存中...", + "saveFailed": "儲存設定失敗:{{error}}", + "upload": "上傳至雲端", + "uploading": "上傳中...", + "uploadSuccess": "已上傳至 WebDAV", + "uploadFailed": "上傳失敗:{{error}}", + "autoSyncFailedToast": "自動同步失敗:{{error}}", + "download": "從雲端下載", + "downloading": "下載中...", + "downloadSuccess": "已從 WebDAV 下載並還原", + "downloadFailed": "下載失敗:{{error}}", + "lastSync": "上次同步:{{time}}", + "autoSyncLastErrorTitle": "上次自動同步失敗", + "autoSyncLastErrorHint": "請檢查網路或 WebDAV 設定,系統會在後續變更時繼續自動重試。", + "missingUrl": "請填寫 WebDAV 伺服器位址", + "presets": { + "label": "服務商", + "jianguoyun": "堅果雲", + "jianguoyunHint": "請在堅果雲「安全選項」中產生「第三方應用程式密碼」,不要使用登入密碼。", + "nextcloud": "Nextcloud", + "nextcloudHint": "請將 your-server 替換為您的 Nextcloud 伺服器位址,USERNAME 替換為您的使用者名稱。", + "synology": "Synology NAS", + "synologyHint": "請先在 Synology「套件中心」安裝並啟用 WebDAV Server 套件。", + "custom": "自訂" + }, + "remoteRootDefault": "預設: cc-switch-sync", + "profileDefault": "預設: default", + "saveAndTestSuccess": "設定已儲存,連線正常", + "saveAndTestFailed": "設定已儲存,但連線測試失敗:{{error}}", + "noRemoteData": "雲端沒有找到同步資料", + "incompatibleVersion": "遠端資料版本不相容(協定 v{{protocolVersion}},資料庫 {{dbCompatVersion}}),目前支援協定 v2 / db-v6", + "unsaved": "未儲存", + "saved": "已儲存", + "unsavedChanges": "請先儲存設定", + "saveBeforeSync": "請先儲存設定,再使用上傳/下載。", + "fetchingRemote": "取得遠端資訊...", + "fetchRemoteFailed": "取得遠端資訊失敗,請檢查設定和網路後重試。", + "confirmDownload": { + "title": "從雲端還原", + "deviceName": "上傳裝置", + "createdAt": "上傳時間", + "path": "遠端路徑", + "dbCompat": "資料庫相容層", + "artifacts": "包含內容", + "legacyNotice": "檢測到舊版雲端路徑。還原完成後,下次上傳將寫入新路徑 v2/db-v6。", + "warning": "還原將覆寫本地所有資料和技能設定", + "confirm": "確認還原" + }, + "confirmUpload": { + "title": "上傳至雲端", + "content": "將同步以下內容至 WebDAV 伺服器:", + "dbItem": "資料庫(所有 Provider 設定和資料)", + "skillsItem": "技能包(所有自訂技能)", + "targetPath": "目標路徑", + "existingData": "雲端已有資料", + "deviceName": "上傳裝置", + "createdAt": "上傳時間", + "path": "遠端路徑", + "dbCompat": "資料庫相容層", + "warning": "將覆寫雲端已有的同步資料", + "legacyNotice": "檢測到舊版雲端路徑資料。本次上傳將寫入新路徑 v2/db-v6,不會覆寫舊路徑。", + "confirm": "確認上傳" + } + }, + "autoReload": "資料已重新整理", + "languageOptionChinese": "简体中文", + "languageOptionTraditionalChinese": "繁體中文", + "languageOptionEnglish": "English", + "languageOptionJapanese": "日本語", + "windowBehavior": "視窗行為", + "windowBehaviorHint": "設定視窗最小化與 Claude 外掛程式連動策略。", + "launchOnStartup": "開機自動啟動", + "launchOnStartupDescription": "隨系統啟動自動執行 CC Switch", + "silentStartup": "靜默啟動", + "silentStartupDescription": "程式啟動時不顯示主視窗,僅在系統匣執行", + "autoLaunchFailed": "設定開機自動啟動失敗", + "minimizeToTray": "關閉時最小化至系統匣", + "minimizeToTrayDescription": "勾選後點擊關閉按鈕會隱藏至系統匣,取消則直接退出應用程式。", + "useAppWindowControls": "啟用應用程式等級視窗按鈕", + "useAppWindowControlsDescription": "開啟後使用應用程式自建的最小化、最大化/還原、關閉按鈕;關閉後沿用系統視窗模式。", + "enableClaudePluginIntegration": "套用至 Claude Code 外掛程式", + "enableClaudePluginIntegrationDescription": "開啟後 Vscode Claude Code 外掛程式的供應商將隨本軟體切換", + "skipClaudeOnboarding": "跳過 Claude Code 初次安裝確認", + "skipClaudeOnboardingDescription": "開啟後跳過 Claude Code 初次安裝確認", + "appVisibility": { + "title": "主頁面顯示", + "description": "選擇在主頁面顯示的應用程式", + "claudeDesc": "Anthropic Claude Code CLI", + "codexDesc": "OpenAI Codex CLI", + "geminiDesc": "Google Gemini CLI", + "opencodeDesc": "OpenCode CLI" + }, + "skillStorage": { + "title": "Skills 儲存位置", + "description": "選擇 CC Switch 存放 Skills 主副本的目錄", + "ccSwitch": "CC Switch", + "unified": "~/.agents/skills", + "ccSwitchHint": "技能儲存在 ~/.cc-switch/skills/,由 CC Switch 統一管理並同步至各應用程式。", + "unifiedHint": "技能儲存在 ~/.agents/skills/,遵循 Agent Skills 開放標準。相容的工具(Claude Code、Codex、Gemini CLI 等)可直接發現此目錄中的技能。", + "confirmTitle": "遷移技能儲存位置", + "confirmMessage": "將移動 {{count}} 個技能至新位置,是否繼續?", + "migrationSuccess": "已成功遷移 {{count}} 個技能", + "migrationPartial": "遷移了 {{migrated}} 個技能,{{errors}} 個失敗,請查看日誌" + }, + "skillSync": { + "title": "Skills 同步方式", + "description": "選擇 Skills 的檔案同步策略", + "symlink": "軟連結", + "copy": "檔案複製", + "symlinkHint": "軟連結節省磁碟空間並支援即時同步。注意:Windows 可能需要管理員權限或開啟開發者模式" + }, + "terminal": { + "title": "首選終端機", + "description": "選擇點擊終端機按鈕時使用的終端機應用程式", + "fallbackHint": "如果選擇的終端機不可用,將自動使用系統預設終端機", + "options": { + "macos": { + "terminal": "Terminal.app", + "iterm2": "iTerm2", + "alacritty": "Alacritty", + "kitty": "Kitty", + "ghostty": "Ghostty", + "wezterm": "WezTerm", + "kaku": "Kaku", + "warp": "Warp" + }, + "windows": { + "cmd": "命令提示字元", + "powershell": "PowerShell", + "wt": "Windows Terminal" + }, + "linux": { + "gnomeTerminal": "GNOME Terminal", + "konsole": "Konsole", + "xfce4Terminal": "Xfce4 Terminal", + "alacritty": "Alacritty", + "kitty": "Kitty", + "ghostty": "Ghostty" + } + } + }, + "configDirectoryOverride": "設定目錄覆寫(進階)", + "configDirectoryDescription": "在 WSL 等環境使用 Claude Code 或 Codex 的時候,可手動指定為 WSL 裡的設定目錄,供應商資料與主環境保持一致。", + "appConfigDir": "CC Switch 設定目錄", + "appConfigDirDescription": "自訂 CC Switch 的設定儲存位置(指定至雲端同步資料夾即可雲端同步設定)", + "browsePlaceholderApp": "例如:C:\\Users\\Administrator\\.cc-switch", + "claudeConfigDir": "Claude Code 設定目錄", + "claudeConfigDirDescription": "覆寫 Claude 設定目錄 (settings.json),同時會在同級存放 Claude MCP 的 claude.json。", + "codexConfigDir": "Codex 設定目錄", + "codexConfigDirDescription": "覆寫 Codex 設定目錄。", + "geminiConfigDir": "Gemini 設定目錄", + "geminiConfigDirDescription": "覆寫 Gemini 設定目錄 (.env)。", + "opencodeConfigDir": "OpenCode 設定目錄", + "opencodeConfigDirDescription": "覆寫 OpenCode 設定目錄 (opencode.json)。", + "openclawConfigDir": "OpenClaw 設定目錄", + "openclawConfigDirDescription": "覆寫 OpenClaw 設定目錄 (openclaw.json)。", + "hermesConfigDir": "Hermes 設定目錄", + "hermesConfigDirDescription": "覆寫 Hermes 設定目錄 (config.yaml)。", + "browsePlaceholderClaude": "例如:/home/<您的帳號>/.claude", + "browsePlaceholderCodex": "例如:/home/<您的帳號>/.codex", + "browsePlaceholderGemini": "例如:/home/<您的帳號>/.gemini", + "browsePlaceholderOpencode": "例如:/home/<您的帳號>/.config/opencode", + "browsePlaceholderOpenclaw": "例如:/home/<您的帳號>/.openclaw", + "browsePlaceholderHermes": "例如:/home/<您的帳號>/.hermes", + "browseDirectory": "瀏覽目錄", + "resetDefault": "還原預設目錄(需儲存後生效)", + "checkForUpdates": "檢查更新", + "updateTo": "更新至 v{{version}}", + "updating": "更新中...", + "checking": "檢查中...", + "upToDate": "已是最新", + "aboutHint": "檢視版本資訊與更新狀態。", + "portableMode": "目前為可攜版,更新需手動下載。", + "updateAvailable": "檢測到新版本:{{version}}", + "updateBadge": "有更新可用", + "updateFailed": "更新安裝失敗,已嘗試開啟下載頁面。", + "checkUpdateFailed": "檢查更新失敗,請稍後重試。", + "openReleaseNotesFailed": "開啟更新日誌失敗", + "releaseNotes": "更新日誌", + "viewReleaseNotes": "檢視該版本更新日誌", + "viewCurrentReleaseNotes": "檢視目前版本更新日誌", + "officialWebsite": "官方網站", + "github": "GitHub", + "oneClickInstall": "一鍵安裝", + "oneClickInstallHint": "安裝 Claude Code / Codex / Gemini CLI / OpenCode", + "localEnvCheck": "本地環境檢查", + "envBadge": { + "wsl": "WSL", + "windows": "Win", + "macos": "macOS", + "linux": "Linux" + }, + "wslShell": "Shell", + "wslShellFlag": "標誌", + "installCommandsCopied": "安裝命令已複製", + "installCommandsCopyFailed": "複製失敗,請手動複製。", + "importFailedError": "匯入設定失敗:{{message}}", + "exportFailedError": "匯出設定失敗:", + "restartRequired": "需要重新啟動應用程式", + "restartRequiredMessage": "修改 CC Switch 設定目錄後需要重新啟動應用程式才能生效,是否立即重新啟動?", + "restartNow": "立即重新啟動", + "restartLater": "稍後重新啟動", + "restartFailed": "應用程式重新啟動失敗,請手動關閉後重新開啟。", + "devModeRestartHint": "開發模式下不支援自動重新啟動,請手動重新啟動應用程式。", + "saving": "正在儲存...", + "globalProxy": { + "label": "全域代理伺服器", + "hint": "代理所有請求(API、Skills 下載等)。開啟本地路由時,應用程式的請求也會經過此代理伺服器。留空表示直連。", + "username": "使用者名稱(選填)", + "password": "密碼(選填)", + "test": "測試連線", + "scan": "掃描本地代理伺服器", + "clear": "清除", + "scanFailed": "掃描失敗:{{error}}", + "saved": "代理伺服器設定已儲存", + "saveFailed": "儲存失敗:{{error}}", + "testSuccess": "連線成功!延遲 {{latency}}ms", + "testFailed": "連線失敗:{{error}}", + "pricingDefaultsTitle": "計費預設設定", + "pricingDefaultsDescription": "設定各應用程式的預設倍率與計費模式來源。", + "pricingAppLabel": "應用程式", + "defaultCostMultiplierLabel": "預設倍率", + "defaultCostMultiplierHint": "用於成本計算的倍率,支援小數。", + "pricingModelSourceLabel": "計費模式", + "pricingModelSourceRequest": "請求模型", + "pricingModelSourceResponse": "回傳模型", + "pricingSave": "儲存計費設定", + "pricingSaved": "計費設定已儲存", + "pricingSaveFailed": "儲存計費設定失敗:{{error}}", + "pricingLoadFailed": "載入計費設定失敗:{{error}}", + "defaultCostMultiplierRequired": "預設倍率不能為空", + "defaultCostMultiplierInvalid": "預設倍率格式不正確" + }, + "saveFailedGeneric": "儲存失敗,請重試" + }, + "apps": { + "claude": "Claude", + "claudeCode": "Claude Code", + "claudeDesktop": "Claude Desktop", + "claude-desktop": "Claude Desktop", + "codex": "Codex", + "gemini": "Gemini", + "opencode": "OpenCode", + "openclaw": "OpenClaw", + "hermes": "Hermes" + }, + "sessionManager": { + "title": "工作階段管理", + "subtitle": "管理 Claude Code、Codex、OpenCode、OpenClaw、Hermes 與 Gemini CLI 工作階段紀錄", + "searchPlaceholder": "搜尋對話內容、目錄或 ID", + "searchSessions": "搜尋工作階段", + "providerFilterAll": "全部", + "sessionList": "工作階段清單", + "manageBatchTooltip": "進入批次管理", + "exitBatchModeTooltip": "退出批次管理", + "batchModeHint": "勾選要刪除的工作階段", + "selectForBatch": "選擇工作階段", + "selectedCount": "已選 {{count}} 項", + "selectAllFiltered": "全選目前", + "clearFilteredSelection": "取消全選", + "clearSelection": "清空已選", + "deleteSelected": "批次刪除", + "batchDeleting": "批次刪除中...", + "loadingSessions": "載入工作階段中...", + "noSessions": "未發現工作階段", + "selectSession": "請選擇工作階段檢視詳情", + "noSummary": "暫無摘要", + "lastActive": "最近活躍", + "projectDir": "專案目錄", + "sourcePath": "原始檔案", + "copyResumeCommand": "複製繼續命令", + "resumeCommandCopied": "已複製繼續命令", + "openInTerminal": "在終端機繼續", + "terminalTargetTerminal": "Terminal", + "terminalTargetKitty": "kitty", + "terminalTargetCopy": "僅複製", + "terminalLaunched": "終端機已啟動", + "openFailed": "開啟終端機失敗", + "resumeFallbackCopied": "已複製繼續命令,可手動貼上至終端機", + "copyProjectDir": "複製目錄", + "projectDirCopied": "目錄已複製", + "copySourcePath": "複製原始檔案", + "sourcePathCopied": "原始檔案已複製", + "delete": "刪除工作階段", + "deleting": "刪除中...", + "deleteTooltip": "永久刪除此本地工作階段紀錄", + "deleteConfirmTitle": "刪除工作階段", + "deleteConfirmMessage": "將永久刪除本地工作階段「{{title}}」\nSession ID: {{sessionId}}\n\n此操作不可復原。", + "deleteConfirmAction": "刪除工作階段", + "sessionDeleted": "工作階段已刪除", + "deleteFailed": "刪除工作階段失敗:{{error}}", + "batchDeleteConfirmTitle": "批次刪除工作階段", + "batchDeleteConfirmMessage": "將永久刪除已選取的 {{count}} 個本地工作階段紀錄。\n\n此操作不可復原。", + "batchDeleteConfirmAction": "刪除所選工作階段", + "batchDeleteSuccess": "已刪除 {{count}} 個工作階段", + "batchDeleteFailed": "{{failed}} 個工作階段刪除失敗", + "batchDeleteRequestFailed": "批次刪除失敗,請稍後重試", + "loadingMessages": "載入對話內容中...", + "emptySession": "該工作階段暫無可展示內容", + "clickToCopyPath": "點擊複製路徑", + "tocTitle": "對話目錄", + "justNow": "剛剛", + "minutesAgo": "{{count}} 分鐘前", + "hoursAgo": "{{count}} 小時前", + "daysAgo": "{{count}} 天前", + "roleUser": "使用者", + "roleSystem": "系統", + "roleTool": "工具", + "resume": "繼續工作階段", + "resumeTooltip": "在終端機中繼續此工作階段", + "noResumeCommand": "此工作階段無法繼續", + "copyCommand": "複製命令", + "copyMessage": "複製訊息", + "messageCopied": "已複製訊息內容", + "conversationHistory": "對話紀錄", + "expandContent": "展開完整內容", + "collapseContent": "收起" + }, + "console": { + "providerSwitchReceived": "收到供應商切換事件:", + "setupListenerFailed": "設定供應商切換監聽器失敗:", + "updateProviderFailed": "更新供應商失敗:", + "autoImportFailed": "自動匯入預設設定失敗:", + "openLinkFailed": "開啟連結失敗:", + "getVersionFailed": "取得版本資訊失敗:", + "loadSettingsFailed": "載入設定失敗:", + "getConfigPathFailed": "取得設定路徑失敗:", + "getConfigDirFailed": "取得設定目錄失敗:", + "detectPortableFailed": "檢測可攜模式失敗:", + "saveSettingsFailed": "儲存設定失敗:", + "updateFailed": "更新失敗:", + "checkUpdateFailed": "檢查更新失敗:", + "openConfigFolderFailed": "開啟設定資料夾失敗:", + "selectConfigDirFailed": "選擇設定目錄失敗:", + "getDefaultConfigDirFailed": "取得預設設定目錄失敗:", + "openReleaseNotesFailed": "開啟更新日誌失敗:" + }, + "providerForm": { + "supplierName": "供應商名稱", + "supplierNameRequired": "供應商名稱 *", + "supplierNamePlaceholder": "例如:Anthropic 官方", + "websiteUrl": "官網位址", + "websiteUrlPlaceholder": "https://example.com(選填)", + "apiEndpoint": "請求位址", + "apiEndpointPlaceholder": "https://your-api-endpoint.com", + "codexApiEndpointPlaceholder": "https://your-api-endpoint.com/v1", + "manageAndTest": "管理與測速", + "configContent": "設定內容", + "officialNoApiKey": "官方登入無需填寫 API Key,直接儲存即可", + "codexOfficialNoApiKey": "官方無需填寫 API Key,直接儲存即可", + "codexApiKeyAutoFill": "只需要填這裡,下方 auth.json 會自動填寫", + "apiKeyAutoFill": "只需要填這裡,下方設定會自動填寫", + "cnOfficialApiKeyHint": "只需填寫 API Key,請求位址已預設", + "aggregatorApiKeyHint": "只需填寫 API Key,請求位址已預設", + "thirdPartyApiKeyHint": "只需填寫 API Key,請求位址已預設", + "customApiKeyHint": "自訂設定需手動填寫所有必要欄位", + "omoHint": "OMO 設定管理 Agent 模型指派,相容 oh-my-openagent.jsonc / oh-my-opencode.jsonc", + "officialHint": "官方供應商使用瀏覽器登入,無需設定 API Key", + "getApiKey": "取得 API Key", + "partnerPromotion": { + "packycode": "PackyCode 是 CC Switch 的官方合作夥伴,使用此連結註冊並在儲值時填寫「cc-switch」優惠碼,可以享受 9 折優惠", + "patewayai": "PatewayAI 為 CC Switch 的使用者提供了特別福利,透過此連結註冊可以獲得 3 美元額度。", + "claudeapi": "ClaudeAPI 為 CC Switch 的使用者提供了特別福利,透過此連結註冊可以領取測試額度。", + "claudecn": "ClaudeCN 是一家實體企業營運的企業級 AI 中繼平台,支援企業採購流程,可對公打款、簽約,服務合規有保障。", + "runapi": "RunAPI 為 CC Switch 的使用者提供了特別福利,透過此連結註冊並聯繫客服可領取 ¥14 免費額度。", + "minimax_cn": "MiniMax Coding Plan 特惠,Starter 方案 9.9 元起", + "minimax_en": "MiniMax Coding Plan 黑五特惠,Starter 方案現僅 $2 / 月(2 折優惠!)", + "dmxapi": "Claude Code 專屬模型 3.4 折優惠進行中!", + "cubence": "Cubence 是 CC Switch 的官方合作夥伴,使用此連結註冊並在儲值時填寫「CCSWITCH」優惠碼,每次儲值均可享受 9 折優惠", + "aigocode": "AIGoCode 是 CC Switch 的官方合作夥伴,使用此連結註冊首次儲值時可以獲得 10% 額度獎勵!", + "rightcode": "RightCode 是 CC Switch 的官方合作夥伴,使用此連結註冊每次儲值均可贈送 5% 額外額度!", + "aicodemirror": "AICodeMirror 是 CC Switch 的官方合作夥伴,使用此連結註冊可享受 8 折優惠!", + "aicoding": "AI Coding 為 CC Switch 的使用者提供了特殊優惠,首次儲值可以享受 9 折優惠!", + "crazyrouter": "CrazyRouter 為 CC Switch 的使用者提供了特殊優惠,首次儲值贈送 30% 額外額度!", + "sssaicode": "SSAI Code 為 CC Switch 的使用者提供了特殊優惠,每次儲值贈送額外 $10 額度!", + "siliconflow": "矽基流動是 CC Switch 的官方合作夥伴", + "ucloud": "優雲智算為 CC Switch 的使用者提供了特殊優惠,透過此連結註冊,可以獲得 5 元平台體驗金!", + "micu": "Micu 是 CC Switch 的官方合作夥伴", + "ctok": "官網加入 CTok 社群,訂閱方案。", + "shengsuanyun": "勝算雲為 CC Switch 的使用者提供了特別福利,使用此連結註冊的新使用者可獲 10 元模力及首儲 10% 贈送!", + "lemondata": "Lemon Code 為 CC Switch 的使用者提供了特別優惠。使用此連結註冊可以獲得 1 美元免費額度。", + "doubaoseed": "豆包大模型為 CC Switch 的使用者提供了專屬福利:透過此連結註冊即可取得豆包全系列文本模型 50 萬 tokens 推理額度以及 Seedance 2.0 的 500 萬 tokens 免費額度", + "volcengine_agentplan": "火山方舟 Agent Plan 為 CC Switch 的使用者提供了專屬福利:透過此連結訂閱方舟 AgentPlan,新客戶首月 40 元起。", + "byteplus": "透過此連結註冊即可取得每個模型 50 萬 tokens 的免費推理額度。" + }, + "presets": { + "ucloud": "優雲智算", + "ucloudCoding": "優雲智算 Coding Plan", + "shengsuanyun": "勝算雲", + "openrouter": "OpenRouter", + "deepseek": "DeepSeek", + "together": "Together AI" + }, + "parameterConfig": "參數設定 - {{name}} *", + "mainModel": "主模型 (選填)", + "mainModelPlaceholder": "例如: GLM-4.6", + "fastModel": "快速模型 (選填)", + "fastModelPlaceholder": "例如: GLM-4.5-Air", + "modelHint": "留空將使用供應商的預設模型", + "apiHint": "填寫相容 Claude API 的伺服器端點位址,請勿以斜線結尾", + "apiHintOAI": "填寫相容 OpenAI Chat Completions 的伺服器端點位址,請勿以斜線結尾", + "apiHintGeminiNative": "建議填寫 Gemini Native 的 base URL,例如 https://generativelanguage.googleapis.com 或 https://generativelanguage.googleapis.com/v1beta;代理伺服器會自動補齊 models/*:generateContent", + "codexApiHint": "填寫相容 OpenAI Response 格式的伺服器端點位址", + "fillSupplierName": "請填寫供應商名稱", + "fillConfigContent": "請填寫設定內容", + "fillParameter": "請填寫 {{label}}", + "fillTemplateValue": "請填寫 {{label}}", + "endpointRequired": "非官方供應商請填寫 API 端點", + "apiKeyRequired": "非官方供應商請填寫 API Key", + "softValidation": { + "title": "設定存在以下問題", + "hint": "仍要儲存嗎?儲存後切換此供應商時可能失敗,可以之後再補全。", + "saveAnyway": "仍要儲存" + }, + "configJsonError": "設定 JSON 格式錯誤,請檢查語法", + "authJsonRequired": "auth.json 必須是 JSON 物件", + "authJsonError": "auth.json 格式錯誤,請檢查 JSON 語法", + "fillAuthJson": "請填寫 auth.json 設定", + "fillApiKey": "請填寫 OPENAI_API_KEY", + "visitWebsite": "造訪 {{url}}", + "anthropicModel": "主模型", + "anthropicSmallFastModel": "快速模型", + "apiFormat": "API 格式", + "apiFormatHint": "選擇供應商 API 的輸入格式", + "fullUrlLabel": "完整 URL", + "fullUrlEnabled": "完整 URL 模式", + "fullUrlDisabled": "標記為完整 URL", + "fullUrlHint": "請填寫完整請求 URL,並且必須開啟路由後使用;路由將直接使用此 URL,不拼接路徑", + "fullUrlHintGeminiNative": "Gemini Native 下,完整 URL 模式同時相容兩類位址:1. 官方/標準 Gemini URL,代理伺服器會依模型和串流參數自動標準化;2. 自訂 relay 的完整 URL,代理伺服器會盡量原樣使用,只補齊查詢參數,不再強制附加 models 路徑", + "apiFormatAnthropic": "Anthropic Messages (原生)", + "apiFormatOpenAIChat": "OpenAI Chat Completions (需開啟路由)", + "apiFormatOpenAIResponses": "OpenAI Responses API (需開啟路由)", + "apiFormatGeminiNative": "Gemini Native generateContent (需開啟路由)", + "codexApiFormatResponses": "OpenAI Responses API (原生)", + "codexApiFormatOpenAIChat": "OpenAI Chat Completions (需開啟路由)", + "codexApiFormatHint": "選擇供應商真實支援的 Codex API 格式;設定仍保持 Responses 以相容新版 Codex,Chat Completions 會透過本地路由自動轉換。", + "authField": "驗證欄位", + "authFieldAuthToken": "ANTHROPIC_AUTH_TOKEN(預設)", + "authFieldApiKey": "ANTHROPIC_API_KEY", + "authFieldHint": "選擇寫入設定的驗證環境變數名稱", + "apiHintResponses": "填寫相容 OpenAI Responses API 的伺服器端點位址,請勿以斜線結尾", + "anthropicDefaultHaikuModel": "Haiku 預設模型", + "anthropicDefaultSonnetModel": "Sonnet 預設模型", + "anthropicDefaultOpusModel": "Opus 預設模型", + "modelPlaceholder": "", + "smallModelPlaceholder": "", + "haikuModelPlaceholder": "", + "modelHelper": "選填:指定預設使用的 Claude 模型,留空則使用系統預設。", + "modelMappingLabel": "模型對應", + "modelMappingHint": "顯示名稱只影響 /model 選單;1M 只是提供給 Claude Code 的上下文能力聲明。", + "modelRoleLabel": "模型角色", + "modelRoleSonnet": "Sonnet", + "modelRoleOpus": "Opus", + "modelRoleHaiku": "Haiku", + "modelDisplayNameLabel": "顯示名稱", + "modelDisplayNamePlaceholder": "例如 DeepSeek V4 Pro", + "requestModelLabel": "實際請求模型", + "modelOneMHeader": "聲明支援 1M", + "modelOneMLabel": "1M", + "fallbackModelLabel": "備用模型", + "fallbackModelHint": "僅在 Claude Code 請求沒有明確落到 Sonnet、Opus 或 Haiku 角色時使用;通常可以留空。", + "quickSetModels": "一鍵設定", + "quickSetSuccess": "已將模型名稱套用至所有角色", + "advancedOptionsToggle": "進階選項", + "advancedOptionsHint": "包含 API 格式、驗證欄位、模型對應等設定。大多數場景下保持預設即可。", + "categoryOfficial": "官方", + "categoryCnOfficial": "開源官方", + "categoryAggregation": "聚合服務", + "categoryThirdParty": "第三方", + "fetchModels": "取得模型清單", + "fetchingModels": "正在取得...", + "fetchModelsSuccess": "取得 {{count}} 個模型", + "fetchModelsFailed": "取得模型清單失敗", + "fetchModelsEmpty": "未找到可用模型", + "fetchModelsNeedApiKey": "請先填寫 API Key", + "fetchModelsNeedEndpoint": "請先填寫 API 端點", + "fetchModelsNeedConfig": "請先填寫 API 端點和 API Key", + "fetchModelsAuthFailed": "API Key 無效或無權限", + "fetchModelsNotSupported": "該供應商不支援取得模型清單", + "fetchModelsEndpointNotFound": "未找到可用的模型清單端點,請檢查 Base URL 或確認供應商是否開放該 API", + "fetchModelsTimeout": "請求逾時,請檢查網路連線" + }, + "copilot": { + "authSection": "GitHub Copilot 驗證", + "authStatus": "驗證狀態", + "authenticated": "已驗證: {{username}}", + "notAuthenticated": "未驗證", + "loginWithGitHub": "使用 GitHub 登入", + "loginRequired": "請先登入 GitHub Copilot", + "waitingForAuth": "等待授權中...", + "enterCode": "請在瀏覽器中輸入驗證碼:", + "logout": "登出", + "authSuccess": "GitHub Copilot 驗證成功", + "authFailed": "驗證失敗:{{error}}", + "authTimeout": "驗證逾時,請重試", + "tokenExpired": "Token 已過期,請重新驗證", + "accountCount": "{{count}} 個帳號", + "selectAccount": "選擇帳號", + "selectAccountPlaceholder": "選擇一個 GitHub 帳號", + "useDefaultAccount": "使用預設帳號", + "loggedInAccounts": "已登入帳號", + "defaultAccount": "預設", + "selected": "已選取", + "removeAccount": "移除帳號", + "setAsDefault": "設為預設", + "addAnotherAccount": "新增其他帳號", + "logoutAll": "登出所有帳號", + "retry": "重試", + "copyCode": "複製程式碼", + "migrationFailed": "舊驗證資料遷移失敗:{{error}}", + "loadModelsFailed": "載入 Copilot 模型清單失敗", + "deploymentType": "GitHub 部署類型", + "deploymentGitHubCom": "GitHub.com", + "deploymentEnterprise": "GitHub Enterprise Server", + "enterpriseDomainPlaceholder": "例如:company.ghe.com" + }, + "codexOauth": { + "authStatus": "驗證狀態", + "notAuthenticated": "未驗證", + "loginWithChatGPT": "使用 ChatGPT 登入", + "loginRequired": "請先登入 ChatGPT 帳號", + "waitingForAuth": "等待授權中...", + "enterCode": "請在瀏覽器中輸入以下驗證碼:", + "accountCount": "{{count}} 個帳號", + "selectAccount": "選擇帳號", + "selectAccountPlaceholder": "選擇一個 ChatGPT 帳號", + "useDefaultAccount": "使用預設帳號", + "loggedInAccounts": "已登入帳號", + "defaultAccount": "預設", + "selected": "已選取", + "removeAccount": "移除帳號", + "setAsDefault": "設為預設", + "addAnotherAccount": "新增其他帳號", + "logoutAll": "登出所有帳號", + "retry": "重試", + "copyCode": "複製程式碼", + "fastMode": "FAST 模式", + "fastModeDescription": "發送 service_tier=\"priority\" 換取更低延遲。預設關閉——開啟後會以更高速率消耗 ChatGPT 配額。" + }, + "endpointTest": { + "title": "請求位址管理", + "endpoints": "個端點", + "autoSelect": "自動選擇", + "testSpeed": "測速", + "testing": "測速中", + "addEndpointPlaceholder": "https://api.example.com", + "done": "完成", + "noEndpoints": "暫無端點", + "failed": "失敗", + "enterValidUrl": "請輸入有效的 URL", + "invalidUrlFormat": "URL 格式不正確", + "onlyHttps": "僅支援 HTTP/HTTPS", + "urlExists": "該位址已存在", + "saveFailed": "儲存失敗,請重試", + "loadEndpointsFailed": "載入自訂端點失敗:", + "addEndpointFailed": "新增自訂端點失敗:", + "removeEndpointFailed": "刪除自訂端點失敗:", + "removeFailed": "刪除失敗:{{error}}", + "updateLastUsedFailed": "更新端點使用時間失敗", + "pleaseAddEndpoint": "請先新增端點", + "testUnavailable": "測速功能不可用", + "noResult": "未回傳結果", + "testFailed": "測速失敗:{{error}}", + "empty": "暫無端點" + }, + "providerAdvanced": { + "testConfig": "模型測試設定", + "useCustomConfig": "使用獨立設定", + "testConfigDesc": "為此供應商設定獨立的模型測試參數,不啟用時使用全域設定。", + "testModel": "測試模型", + "testModelPlaceholder": "留空使用全域設定", + "timeoutSecs": "逾時時間(秒)", + "testPrompt": "測試提示詞", + "degradedThreshold": "降級閾值(毫秒)", + "maxRetries": "最大重試次數", + "pricingConfig": "計費設定", + "useCustomPricing": "使用獨立設定", + "pricingConfigDesc": "為此供應商設定獨立的計費參數,不啟用時使用全域預設設定。", + "costMultiplier": "成本倍率", + "costMultiplierPlaceholder": "留空使用全域預設(1)", + "costMultiplierHint": "實際成本 = 基礎成本 × 倍率,支援小數如 1.5", + "pricingModelSourceLabel": "計費模式", + "pricingModelSourceInherit": "繼承全域預設", + "pricingModelSourceRequest": "請求模型", + "pricingModelSourceResponse": "回傳模型", + "pricingModelSourceHint": "選擇依請求模型還是回傳模型進行定價比對" + }, + "codexConfig": { + "authJson": "auth.json (JSON) *", + "authJsonPlaceholder": "{\n \"OPENAI_API_KEY\": \"sk-your-api-key-here\"\n}", + "authJsonHint": "Codex auth.json 設定內容", + "configToml": "config.toml (TOML)", + "configTomlHint": "Codex config.toml 設定內容", + "writeCommonConfig": "寫入通用設定", + "editCommonConfig": "編輯通用設定", + "editCommonConfigTitle": "編輯 Codex 通用設定片段", + "commonConfigHint": "該片段會在勾選「寫入通用設定」時附加到 config.toml 末尾", + "apiUrlLabel": "API 請求位址", + "extractFromCurrent": "從編輯內容擷取", + "extractNoCommonConfig": "目前編輯內容沒有可擷取的通用設定", + "extractFailed": "擷取失敗:{{error}}", + "saveFailed": "儲存失敗:{{error}}", + "modelNameHint": "指定使用的模型,將自動更新到 config.toml 中", + "modelName": "模型名稱", + "modelNamePlaceholder": "例如: gpt-5-codex", + "contextWindow1M": "1M 上下文視窗", + "autoCompactLimit": "壓縮閾值", + "autoCompactLimitHint": "上下文 token 數達到此閾值時自動壓縮歷史" + }, + "geminiConfig": { + "envFile": "環境變數 (.env)", + "envFileHint": "使用 .env 格式設定 Gemini 環境變數", + "configJson": "設定檔 (config.json)", + "configJsonHint": "使用 JSON 格式設定 Gemini 擴充參數(選填)", + "writeCommonConfig": "寫入通用設定", + "editCommonConfig": "編輯通用設定", + "editCommonConfigTitle": "編輯 Gemini 通用設定片段", + "commonConfigHint": "該片段會寫入 Gemini 的 .env(不允許包含 GOOGLE_GEMINI_BASE_URL、GEMINI_API_KEY)", + "extractFromCurrent": "從編輯內容擷取", + "extractNoCommonConfig": "目前編輯內容沒有可擷取的通用設定", + "extractFailed": "擷取失敗:{{error}}", + "saveFailed": "儲存失敗:{{error}}", + "extractedConfigInvalid": "擷取的設定格式錯誤", + "invalidJsonFormat": "通用設定片段格式錯誤(必須是有效的 JSON)", + "commonConfigInvalidKeys": "通用設定片段不能包含 GOOGLE_GEMINI_BASE_URL 或 GEMINI_API_KEY(發現:{{keys}})", + "commonConfigInvalidValues": "通用設定片段的值必須是字串", + "noCommonConfigToApply": "通用設定片段為空或沒有可寫入的內容", + "configMergeFailed": "設定合併失敗:{{error}}", + "configReplaceFailed": "設定替換失敗:{{error}}" + }, + "opencode": { + "npmPackage": "API 格式", + "selectPackage": "選擇 API 格式", + "npmPackageHint": "選擇 AI 服務的 API 格式", + "baseUrl": "Base URL", + "baseUrlHint": "自訂 API 端點位址", + "models": "模型設定", + "modelsHint": "設定可用的模型及其顯示名稱", + "addModel": "新增模型", + "modelId": "模型 ID", + "modelName": "顯示名稱", + "noModels": "暫無模型設定", + "modelsRequired": "請至少新增一個模型設定", + "providerKey": "供應商標識", + "providerKeyPlaceholder": "my-provider", + "providerKeyHint": "設定檔中的唯一識別碼,只能使用小寫字母、數字和連字號", + "providerKeyLockedHint": "該供應商已新增至應用程式設定中,供應商標識不可修改", + "providerKeyRequired": "請填寫供應商標識", + "providerKeyDuplicate": "此標識已被使用,請更換", + "providerKeyInvalid": "標識格式無效,只能使用小寫字母、數字和連字號", + "extraOptions": "額外選項", + "extraOptionsHint": "設定額外的 SDK 選項,如 timeout、setCacheKey 等。值會自動解析類型(數字、布林值等)。", + "addExtraOption": "新增", + "extraOptionKey": "鍵名", + "extraOptionValue": "值", + "extraOptionKeyPlaceholder": "timeout", + "extraOptionValuePlaceholder": "600000", + "noExtraOptions": "暫無額外選項", + "noModelOptions": "模型選項,點擊 + 新增", + "modelExtraFields": "模型屬性", + "noModelExtraFields": "模型屬性 (variants, cost 等),點擊 + 新增", + "modelExtraFieldKeyPlaceholder": "variants", + "sdkOptions": "SDK 選項", + "modelOptionKeyPlaceholder": "provider", + "modelOptionValuePlaceholder": "{\"order\": [\"baseten\"]}" + }, + "providerPreset": { + "label": "預設供應商", + "custom": "自訂設定", + "other": "其他", + "hint": "選擇預設後可繼續調整下方欄位。" + }, + "usage": { + "title": "使用統計", + "subtitle": "查看 AI 模型的使用情況和成本統計", + "today": "24 小時", + "last7days": "7 天", + "last30days": "30 天", + "presetToday": "當天", + "preset1d": "1d", + "preset7d": "7d", + "preset14d": "14d", + "preset30d": "30d", + "totalRequests": "總請求數", + "totalCost": "總成本", + "cost": "成本", + "perMillion": "(每百萬)", + "trends": "使用趨勢", + "rangeToday": "過去 24 小時 (按小時)", + "rangeLast7Days": "過去 7 天", + "rangeLast30Days": "過去 30 天", + "totalTokens": "新產生 Token (Input+Output)", + "cacheTokens": "快取 Token", + "realTotal": "真實消耗 Tokens", + "realTotalHint": "Input + Output + 快取建立 + 快取命中", + "tokensSuffix": "Tokens", + "freshInput": "新增輸入", + "cacheHitRate": "快取命中率", + "requestLogs": "請求日誌", + "providerStats": "Provider 統計", + "modelStats": "模型統計", + "time": "時間", + "provider": "供應商", + "billingModel": "計費模型", + "inputTokens": "輸入", + "outputTokens": "輸出", + "cacheReadTokens": "快取命中", + "cacheCreationTokens": "快取建立", + "timingInfo": "耗時/首字", + "status": "狀態", + "multiplier": "倍率", + "requestModel": "請求模型", + "responseModel": "回傳模型", + "noData": "暫無資料", + "unknownProvider": "未知供應商", + "stream": "串流", + "nonStream": "非串流", + "source": "來源", + "requestsLabel": "次請求", + "costLabel": "總成本", + "appFilter": { + "all": "全部", + "claude": "Claude Code", + "codex": "Codex", + "gemini": "Gemini" + }, + "rawInputLabel": "原始", + "dataSources": "資料來源", + "dataSource": { + "proxy": "路由", + "session_log": "工作階段日誌", + "codex_db": "Codex 資料庫", + "codex_session": "Codex 工作階段日誌", + "gemini_session": "Gemini 工作階段日誌" + }, + "sessionSync": { + "trigger": "同步工作階段日誌", + "import": "匯入工作階段", + "resync": "同步", + "imported": "從工作階段日誌匯入了 {{count}} 筆紀錄", + "upToDate": "工作階段日誌已是最新", + "failed": "工作階段同步失敗" + }, + "totalRecords": "共 {{total}} 筆紀錄", + "goToPage": "跳轉", + "pageInputPlaceholder": "頁碼", + "modelPricing": "模型定價", + "loadPricingError": "載入定價資料失敗", + "modelPricingDesc": "設定各模型的 Token 成本", + "noPricingData": "暫無定價資料。點擊「新增」加入模型定價設定。", + "model": "模型", + "displayName": "顯示名稱", + "inputCost": "輸入成本", + "outputCost": "輸出成本", + "cacheReadCost": "快取命中", + "cacheWriteCost": "快取建立", + "deleteConfirmTitle": "確認刪除", + "deleteConfirmDesc": "確定要刪除此模型定價設定嗎?此操作無法復原。", + "queryFailed": "查詢失敗", + "refreshUsage": "重新整理用量", + "planUsage": "方案用量", + "invalid": "已失效", + "total": "總:", + "used": "已使用:", + "remaining": "剩餘:", + "justNow": "剛剛", + "minutesAgo": "{{count}} 分鐘前", + "hoursAgo": "{{count}} 小時前", + "daysAgo": "{{count}} 天前", + "multiplePlans": "{{count}} 個方案", + "expand": "展開", + "collapse": "收起", + "modelIdPlaceholder": "例如: claude-3-5-sonnet-20241022", + "displayNamePlaceholder": "例如: Claude 3.5 Sonnet", + "appType": "應用程式類型", + "allApps": "全部應用程式", + "statusCode": "狀態碼", + "searchProviderPlaceholder": "搜尋供應商...", + "searchModelPlaceholder": "搜尋模型...", + "timeRange": "時間範圍", + "customRange": "日曆篩選", + "customRangeHint": "支援日期與時間", + "startTime": "開始時間", + "endTime": "結束時間", + "input": "Input", + "output": "Output", + "cacheWrite": "建立", + "cacheWriteNotReported": "OpenAI 協定不區分快取建立,僅上報快取命中", + "cacheWritePartial": "部分協定(如 OpenAI)不上報快取建立,數值可能偏低", + "cacheRead": "命中", + "baseCost": "基礎", + "costMultiplier": "成本倍率", + "withMultiplier": "含倍率", + "requestDetail": "請求詳情", + "requestNotFound": "請求未找到", + "basicInfo": "基本資訊", + "tokenUsage": "Token 使用量", + "cacheCreationCost": "快取寫入成本", + "costBreakdown": "成本明細", + "performance": "效能資訊", + "latency": "延遲", + "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": "設定用量查詢", + "enableUsageQuery": "啟用用量查詢", + "presetTemplate": "預設範本", + "requestUrl": "請求位址", + "requestUrlPlaceholder": "例如:https://api.example.com", + "method": "HTTP 方法", + "templateCustom": "自訂", + "templateGeneral": "通用範本", + "templateNewAPI": "NewAPI", + "templateCopilot": "GitHub Copilot", + "templateTokenPlan": "Token Plan", + "templateBalance": "官方", + "copilotAutoAuth": "自動使用 OAuth 驗證,無需手動設定憑證", + "tokenPlanHint": "自動使用供應商的 API Key 和 Base URL 查詢 Token Plan 額度", + "balanceHint": "自動使用供應商的 API Key 查詢帳號餘額", + "resetDate": "重設日期", + "premiumRequests": "Premium 請求", + "credentialsConfig": "憑證設定", + "credentialsHint": "留空則自動使用供應商設定", + "optional": "選填", + "apiKeyPlaceholder": "留空則使用供應商的 API Key", + "baseUrlPlaceholder": "留空則使用供應商的請求位址", + "baseUrl": "請求位址", + "accessToken": "Access Token(在個人安全設定裡取得)", + "accessTokenPlaceholder": "在「安全設定」裡產生", + "userId": "使用者 ID", + "userIdPlaceholder": "例如:114514", + "defaultPlan": "預設方案", + "queryFailedMessage": "查詢失敗", + "queryScript": "查詢腳本(JavaScript)", + "timeoutSeconds": "逾時時間(秒)", + "headers": "請求標頭", + "body": "請求 Body", + "timeoutHint": "範圍: 2-30 秒", + "timeoutMustBeInteger": "逾時時間必須為整數,小數部分已忽略", + "timeoutCannotBeNegative": "逾時時間不能為負數", + "autoIntervalMinutes": "自動查詢間隔(分鐘,0 表示不自動查詢)", + "autoQueryInterval": "自動查詢間隔(分鐘)", + "autoQueryIntervalHint": "0 表示不自動查詢,建議 5-60 分鐘", + "intervalMustBeInteger": "自動查詢間隔必須為整數,小數部分已忽略", + "intervalCannotBeNegative": "自動查詢間隔不能為負數", + "intervalAdjusted": "自動查詢間隔已調整為 {{value}} 分鐘", + "scriptHelp": "腳本編寫說明:", + "configFormat": "設定格式:", + "commentOptional": "選填", + "commentResponseIsJson": "response 是 API 回傳的 JSON 資料", + "extractorFormat": "extractor 回傳格式(所有欄位均為選填):", + "tips": "💡 提示:", + "testing": "測試中...", + "testScript": "測試腳本", + "format": "格式化", + "saveConfig": "儲存設定", + "scriptEmpty": "腳本設定不能為空", + "mustHaveReturn": "腳本必須包含 return 敘述", + "testSuccess": "測試成功!", + "testFailed": "測試失敗", + "formatSuccess": "格式化成功", + "formatFailed": "格式化失敗", + "supportedVariables": "支援的變數", + "variablesHint": "支援變數: {{apiKey}}, {{baseUrl}} | extractor 函式接收 API 回應的 JSON 物件", + "scriptConfig": "請求設定", + "extractorCode": "提取器程式碼", + "extractorHint": "回傳物件需包含剩餘額度等欄位", + "fieldIsValid": "• isValid: 布林值,方案是否有效", + "fieldInvalidMessage": "• invalidMessage: 字串,失效原因說明(當 isValid 為 false 時顯示)", + "fieldRemaining": "• remaining: 數字,剩餘額度", + "fieldUnit": "• unit: 字串,單位(如 \"USD\")", + "fieldPlanName": "• planName: 字串,方案名稱", + "fieldTotal": "• total: 數字,總額度", + "fieldUsed": "• used: 數字,已用額度", + "fieldExtra": "• extra: 字串,擴充欄位,可自由補充需要展示的文字", + "tip1": "• 變數 {{apiKey}} 和 {{baseUrl}} 會自動替換", + "tip2": "• extractor 函式在沙盒環境中執行,支援 ES2020+ 語法", + "tip3": "• 整個設定必須用 () 包覆,形成物件實字運算式" + }, + "errors": { + "usage_query_failed": "用量查詢失敗", + "configLoadFailedTitle": "設定載入失敗", + "configLoadFailedMessage": "無法讀取設定檔:\n{{path}}\n\n錯誤詳情:\n{{detail}}\n\n請手動檢查 JSON 是否有效,或從同目錄的備份檔案(如 config.json.bak)還原。\n\n應用程式將退出以便您進行修復。" + }, + "presetSelector": { + "title": "選擇設定類型", + "custom": "自訂", + "customDescription": "手動設定供應商,需要填寫完整的設定資訊", + "officialDescription": "官方登入,不需要填寫 API Key", + "presetDescription": "使用預設設定,只需填寫 API Key" + }, + "mcp": { + "title": "MCP 管理", + "import": "匯入", + "importExisting": "匯入已有", + "addMcp": "新增 MCP", + "claudeTitle": "Claude Code MCP 管理", + "codexTitle": "Codex MCP 管理", + "geminiTitle": "Gemini MCP 管理", + "unifiedPanel": { + "title": "MCP 伺服器管理", + "addServer": "新增伺服器", + "editServer": "編輯伺服器", + "deleteServer": "刪除伺服器", + "deleteConfirm": "確定要刪除伺服器 \"{{id}}\" 嗎?此操作無法復原。", + "noServers": "暫無伺服器", + "enabledApps": "啟用的應用程式", + "noImportFound": "未發現需要匯入的 MCP 伺服器。所有伺服器已在 CC Switch 統一管理中。", + "importSuccess": "成功匯入 {{count}} 個 MCP 伺服器", + "apps": { + "claude": "Claude", + "codex": "Codex", + "gemini": "Gemini", + "opencode": "OpenCode", + "openclaw": "OpenClaw", + "hermes": "Hermes" + } + }, + "userLevelPath": "使用者級 MCP 設定路徑", + "serverList": "伺服器清單", + "loading": "載入中...", + "empty": "暫無 MCP 伺服器", + "emptyDescription": "點擊右上角按鈕新增第一個 MCP 伺服器", + "add": "新增 MCP", + "addServer": "新增 MCP", + "editServer": "編輯 MCP", + "addClaudeServer": "新增 Claude Code MCP", + "editClaudeServer": "編輯 Claude Code MCP", + "addCodexServer": "新增 Codex MCP", + "editCodexServer": "編輯 Codex MCP", + "configPath": "設定路徑", + "serverCount": "已設定 {{count}} 個 MCP 伺服器", + "enabledCount": "已啟用 {{count}} 個", + "template": { + "fetch": "快速範本:mcp-fetch" + }, + "form": { + "title": "MCP 標題(唯一)", + "titlePlaceholder": "my-mcp-server", + "name": "顯示名稱", + "namePlaceholder": "例如 @modelcontextprotocol/server-time", + "enabledApps": "啟用至應用程式", + "noAppsWarning": "至少選擇一個應用程式", + "description": "描述", + "descriptionPlaceholder": "選填的描述資訊", + "tags": "標籤(逗號分隔)", + "tagsPlaceholder": "stdio, time, utility", + "homepage": "首頁連結", + "homepagePlaceholder": "https://example.com", + "docs": "文件連結", + "docsPlaceholder": "https://example.com/docs", + "additionalInfo": "附加資訊", + "jsonConfig": "完整的 JSON 設定", + "jsonConfigOrPrefix": "完整的 JSON 設定或者使用", + "tomlConfigOrPrefix": "完整的 TOML 設定或者使用", + "jsonPlaceholder": "{\n \"type\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"mcp-server-fetch\"]\n}", + "tomlConfig": "完整的 TOML 設定", + "tomlPlaceholder": "type = \"stdio\"\ncommand = \"uvx\"\nargs = [\"mcp-server-fetch\"]", + "useWizard": "設定精靈", + "syncOtherSide": "同步至 {{target}}", + "syncOtherSideHint": "勾選後會把目前設定同時寫入 {{target}},若存在同名設定將被覆寫", + "willOverwriteWarning": "將覆寫 {{target}} 中的同名設定" + }, + "wizard": { + "title": "MCP 設定精靈", + "hint": "快速設定 MCP 伺服器,自動產生 JSON 設定", + "type": "類型", + "typeStdio": "stdio", + "typeHttp": "http", + "typeSse": "sse", + "command": "命令", + "commandPlaceholder": "npx 或 uvx", + "args": "參數", + "argsPlaceholder": "arg1\narg2", + "env": "環境變數", + "envPlaceholder": "KEY1=value1\nKEY2=value2", + "url": "URL", + "urlPlaceholder": "https://api.example.com/mcp", + "urlRequired": "請輸入 URL", + "headers": "請求標頭(選填)", + "headersPlaceholder": "Authorization: Bearer your_token_here\nContent-Type: application/json", + "preview": "設定預覽", + "apply": "套用設定" + }, + "id": "標識 (唯一)", + "type": "類型", + "command": "命令", + "validateCommand": "驗證命令", + "args": "參數", + "argsPlaceholder": "例如:mcp-server-fetch --help", + "env": "環境變數 (一行一個,KEY=VALUE)", + "envPlaceholder": "FOO=bar\nHELLO=world", + "reset": "重設", + "msg": { + "saved": "已儲存", + "deleted": "已刪除", + "enabled": "已啟用", + "disabled": "已停用", + "templateAdded": "已新增範本" + }, + "error": { + "idRequired": "請填寫標識", + "idExists": "該標識已存在,請更換", + "jsonInvalid": "JSON 格式錯誤,請檢查", + "tomlInvalid": "TOML 格式錯誤,請檢查", + "commandRequired": "請填寫命令", + "singleServerObjectRequired": "此處只需單個伺服器物件,請不要貼上包含 mcpServers 的整份設定", + "saveFailed": "儲存失敗", + "deleteFailed": "刪除失敗" + }, + "validation": { + "ok": "命令可用", + "fail": "命令不可用" + }, + "confirm": { + "deleteTitle": "刪除 MCP 伺服器", + "deleteMessage": "確定要刪除 MCP 伺服器 \"{{id}}\" 嗎?此操作無法復原。" + }, + "presets": { + "title": "選擇 MCP 類型", + "enable": "啟用", + "enabled": "已啟用", + "installed": "已安裝", + "docs": "文件", + "requiresEnv": "需要環境變數", + "fetch": { + "name": "mcp-server-fetch", + "description": "通用 HTTP 請求工具,支援 GET/POST 等 HTTP 方法,適合快速請求 API / 抓取網頁資料" + }, + "time": { + "name": "@modelcontextprotocol/server-time", + "description": "時間查詢工具,提供目前時間、時區轉換、日期計算等功能" + }, + "memory": { + "name": "@modelcontextprotocol/server-memory", + "description": "知識圖譜記憶系統,支援儲存實體、關係和觀察,讓 AI 記住對話中的重要資訊" + }, + "sequential-thinking": { + "name": "@modelcontextprotocol/server-sequential-thinking", + "description": "順序思考工具,協助 AI 將複雜問題分解為多個步驟,逐步深入思考" + }, + "context7": { + "name": "@upstash/context7-mcp", + "description": "Context7 文件搜尋工具,提供最新的函式庫文件和程式碼範例,設定 key 會有更高限額" + } + } + }, + "prompts": { + "manage": "提示詞", + "title": "{{appName}} 提示詞管理", + "claudeTitle": "Claude 提示詞管理", + "codexTitle": "Codex 提示詞管理", + "add": "新增提示詞", + "edit": "編輯提示詞", + "addTitle": "新增 {{appName}} 提示詞", + "editTitle": "編輯 {{appName}} 提示詞", + "import": "匯入現有", + "count": "共 {{count}} 個提示詞", + "enabled": "已啟用", + "enable": "啟用", + "enabledName": "已啟用:{{name}}", + "noneEnabled": "未啟用任何提示詞", + "currentFile": "目前 {{filename}} 內容", + "empty": "暫無提示詞", + "emptyDescription": "點擊右上角按鈕新增或匯入提示詞", + "loading": "載入中...", + "name": "名稱", + "namePlaceholder": "例如:專案預設提示詞", + "description": "描述", + "descriptionPlaceholder": "選填的描述資訊", + "content": "內容", + "contentPlaceholder": "# {{filename}}\n\n在此輸入提示詞內容...", + "loadFailed": "載入提示詞失敗", + "saveSuccess": "儲存成功", + "saveFailed": "儲存失敗", + "deleteSuccess": "刪除成功", + "deleteFailed": "刪除失敗", + "enableSuccess": "啟用成功", + "enableFailed": "啟用失敗", + "disableSuccess": "停用成功", + "disableFailed": "停用失敗", + "importSuccess": "匯入成功", + "importFailed": "匯入失敗", + "confirm": { + "deleteTitle": "確認刪除", + "deleteMessage": "確定要刪除提示詞 \"{{name}}\" 嗎?" + } + }, + "workspace": { + "title": "Workspace 檔案管理", + "manage": "Workspace", + "files": { + "agents": "Agent 操作指令和規則", + "soul": "Agent 人格和溝通風格", + "user": "使用者檔案和偏好", + "identity": "Agent 名稱和頭像", + "tools": "本地工具文件", + "memory": "長期記憶和決策紀錄", + "heartbeat": "心跳執行清單", + "bootstrap": "首次執行儀式", + "boot": "閘道器重新啟動清單" + }, + "editing": "編輯 {{filename}}", + "saveSuccess": "儲存成功", + "saveFailed": "儲存失敗", + "loadFailed": "讀取失敗", + "openDirectory": "在檔案管理員中開啟", + "dailyMemory": { + "title": "每日記憶", + "sectionTitle": "每日記憶", + "cardTitle": "每日記憶檔案", + "cardDescription": "瀏覽管理每日記憶", + "createToday": "新增記憶", + "empty": "暫無每日記憶檔案", + "loadFailed": "載入每日記憶檔案失敗", + "createFailed": "建立每日記憶檔案失敗", + "deleteSuccess": "每日記憶檔案已刪除", + "deleteFailed": "刪除每日記憶檔案失敗", + "confirmDeleteTitle": "刪除每日記憶", + "confirmDeleteMessage": "確定刪除 {{date}} 的每日記憶嗎?此操作不可復原。", + "searchPlaceholder": "搜尋全文內容...", + "searchScopeHint": "全文搜尋所有每日記憶 ⌘F", + "searchCloseHint": "Esc 關閉", + "noSearchResults": "沒有找到符合的每日記憶。", + "searching": "搜尋中...", + "searchFailed": "搜尋失敗", + "matchCount": "{{count}} 處相符" + } + }, + "openclaw": { + "backupCreated": "已建立備份:{{path}}", + "providerKey": "供應商標識", + "providerKeyPlaceholder": "my-provider", + "providerKeyHint": "設定檔中的唯一識別碼,只能使用小寫字母、數字和連字號", + "providerKeyLockedHint": "該供應商已新增至應用程式設定中,供應商標識不可修改", + "providerKeyRequired": "請填寫供應商標識", + "providerKeyDuplicate": "此標識已被使用,請更換", + "providerKeyInvalid": "標識格式無效,只能使用小寫字母、數字和連字號", + "apiProtocol": "API 協定", + "selectProtocol": "選擇 API 協定", + "apiProtocolHint": "選擇與供應商 API 相容的協定類型。大多數供應商使用 OpenAI Completions 格式。", + "baseUrl": "API 端點", + "baseUrlHint": "供應商的 API 端點位址。", + "models": "模型清單", + "addModel": "新增模型", + "noModels": "暫無模型設定。點擊新增模型來設定可用模型。", + "modelId": "模型 ID", + "modelIdPlaceholder": "claude-3-sonnet", + "modelName": "顯示名稱", + "modelNamePlaceholder": "Claude 3 Sonnet", + "contextWindow": "上下文視窗", + "maxTokens": "最大輸出 Tokens", + "reasoning": "推理模式", + "reasoningOn": "啟用", + "reasoningOff": "關閉", + "inputTypes": "輸入類型", + "inputCost": "輸入價格 ($/M tokens)", + "outputCost": "輸出價格 ($/M tokens)", + "advancedOptions": "進階選項", + "cacheReadCost": "快取讀取價格 ($/M tokens)", + "cacheWriteCost": "快取寫入價格 ($/M tokens)", + "cacheCostHint": "快取價格用於計算 Prompt Caching 的成本。如不使用快取可留空。", + "modelsHint": "設定該供應商支援的模型。模型 ID 用於 API 呼叫,顯示名稱用於介面展示。", + "userAgent": "發送 User-Agent", + "userAgentHint": "部分供應商需要瀏覽器 User-Agent 才能正常存取。", + "env": { + "title": "環境變數", + "description": "管理 openclaw.json 中的環境變數設定(API Key、自訂變數等)", + "editorHint": "以 JSON 形式編輯整個 env 節點。支援 env.vars、env.shellEnv 等巢狀物件。", + "objectRequired": "OpenClaw 的 env 必須是 JSON 物件。", + "invalidJson": "OpenClaw 的 env 必須是合法 JSON。", + "empty": "OpenClaw 的 env 不能為空。空物件請使用 {}。", + "keyPlaceholder": "變數名稱", + "valuePlaceholder": "值", + "add": "新增變數", + "saveSuccess": "環境變數已儲存", + "saveFailed": "儲存環境變數失敗", + "loadFailed": "讀取環境變數失敗", + "duplicateKey": "檢測到重複的變數名稱: {{key}}" + }, + "tools": { + "title": "工具權限", + "description": "管理 openclaw.json 中的工具權限設定(允許/拒絕清單)", + "profile": "權限模式", + "profileMinimal": "最小權限", + "profileCoding": "編碼", + "profileMessaging": "對話", + "profileFull": "完全存取", + "profileUnset": "未設定", + "unsupportedProfileTitle": "檢測到不受支援的工具設定", + "unsupportedProfileDescription": "目前 tools.profile 的值「{{value}}」不在 OpenClaw 支援清單內。在您手動選擇新值之前,它會被保留。", + "unsupportedProfileLabel": "不受支援", + "allowList": "允許清單", + "denyList": "拒絕清單", + "patternPlaceholder": "工具名稱或模式", + "addAllow": "新增允許", + "addDeny": "新增拒絕", + "saveSuccess": "工具權限已儲存", + "saveFailed": "儲存工具權限失敗", + "loadFailed": "讀取工具權限失敗" + }, + "agents": { + "title": "Agents 設定", + "description": "管理 openclaw.json 中的 agents.defaults 設定(預設模型、執行參數等)", + "modelSection": "模型設定", + "primaryModel": "預設模型", + "primaryModelHint": "從已設定供應商的模型中選擇預設模型", + "notSet": "未設定", + "fallbackModels": "備用模型", + "fallbackModelsHint": "當主模型不可用時,依優先順序依次嘗試以下備用模型", + "addFallback": "新增備用模型", + "noModels": "暫無已設定的供應商模型。請先新增 OpenClaw 供應商。", + "notInList": "{{value}} (供應商未設定)", + "runtimeSection": "執行參數", + "workspace": "工作區路徑", + "timeout": "逾時時間(秒)", + "contextTokens": "上下文 Token 數", + "maxConcurrent": "最大並行數", + "legacyTimeoutTitle": "檢測到舊版逾時欄位", + "legacyTimeoutDescription": "目前設定仍在使用 agents.defaults.timeout。儲存本頁面時會遷移為 timeoutSeconds。", + "saveSuccess": "Agents 設定已儲存", + "saveFailed": "儲存 Agents 設定失敗", + "loadFailed": "讀取 Agents 設定失敗" + }, + "health": { + "title": "檢測到 OpenClaw 設定警告", + "invalidToolsProfile": "tools.profile 使用了不受支援的值。OpenClaw 目前只支援 minimal、coding、messaging、full。", + "legacyTimeout": "agents.defaults.timeout 已廢棄。開啟並儲存 Agents 面板即可遷移至 timeoutSeconds。", + "stringifiedEnvVars": "env.vars 應為物件,但目前值看起來像被字串化或已損壞。", + "stringifiedShellEnv": "env.shellEnv 應為物件,但目前值看起來像被字串化或已損壞。", + "parseFailed": "openclaw.json 不是合法 JSON5。請先修復檔案,再透過這裡編輯。" + }, + "primaryModel": "預設模型", + "fallbackModel": "備用模型" + }, + "hermes": { + "form": { + "baseUrl": "API 端點", + "baseUrlHint": "供應商的 API 端點位址。", + "providerKey": "供應商標識", + "providerKeyPlaceholder": "my-provider", + "providerKeyHint": "只能使用小寫字母、數字和連字號。用作 config.yaml 中的供應商名稱。", + "providerKeyLockedHint": "該供應商已新增至 Hermes 設定中,標識不可修改。", + "providerKeyRequired": "供應商標識不能為空", + "providerKeyInvalid": "供應商標識只能包含小寫字母、數字和連字號", + "providerKeyDuplicate": "該供應商標識已存在", + "apiMode": "API 模式", + "apiModeHint": "供應商 API 協定。請根據端點選擇正確的協定。", + "apiModeChatCompletions": "OpenAI Chat Completions", + "apiModeAnthropicMessages": "Anthropic Messages", + "apiModeCodexResponses": "OpenAI Responses", + "apiModeBedrockConverse": "AWS Bedrock Converse", + "baseUrlRequired": "API 端點不能為空", + "baseUrlScheme": "請使用 http:// 或 https:// 開頭的位址", + "baseUrlInvalid": "API 端點不是有效的 URL", + "models": "模型清單", + "addModel": "新增模型", + "noModels": "暫無模型設定。切換至此供應商時將不會更新預設模型。", + "modelId": "模型 ID", + "modelIdPlaceholder": "anthropic/claude-opus-4-7", + "modelName": "顯示名稱", + "modelNamePlaceholder": "Claude Opus 4.7", + "contextLength": "上下文長度", + "advancedOptions": "進階選項", + "modelsHint": "切換至此供應商時,第一個模型會寫入頂層 model.default。", + "primaryModel": "預設模型", + "fallbackModel": "備用模型", + "providerAdvanced": "供應商進階選項", + "rateLimitDelay": "請求間隔(秒)", + "rateLimitDelayHint": "連續請求間的最小間隔秒數(選填)。留空表示無限制。" + }, + "webui": { + "open": "開啟 Hermes Web UI", + "offline": "Hermes Web UI 未啟動,請先執行 `hermes dashboard` 啟動服務。", + "openFailed": "開啟 Hermes Web UI 失敗", + "launchConfirmTitle": "Hermes Dashboard 未啟動", + "launchConfirmMessage": "是否開啟終端機並執行 `hermes dashboard` 啟動服務?\n\n啟動完成後會自動開啟瀏覽器。\n\n若終端機提示找不到 hermes 或缺少 web 相依套件,請先執行:\npip install hermes-agent[web]", + "launchConfirmAction": "開啟終端機並啟動", + "launching": "已在終端機啟動 hermes dashboard", + "launchFailed": "開啟終端機失敗" + }, + "memory": { + "title": "記憶管理", + "agentTab": "Agent 記憶 (MEMORY.md)", + "userTab": "使用者畫像 (USER.md)", + "usage": "已用 {{current}} / {{limit}} 字元", + "overLimit": "已超過上限,Hermes 下次載入時會截斷", + "enableOn": "已啟用", + "enableOff": "已停用", + "disabledHint": "在重新啟用前 Hermes 會跳過此記憶", + "toggleFailed": "切換記憶狀態失敗", + "saveSuccess": "記憶已儲存", + "saveFailed": "儲存記憶失敗", + "loadFailed": "讀取記憶檔案失敗", + "openConfig": "在 Hermes Web UI 調整上限", + "runtimeNote": "變更將在 Hermes 下次啟動或建立新工作階段時生效。" + } + }, + "env": { + "warning": { + "title": "檢測到系統環境變數衝突", + "description": "發現 {{count}} 個環境變數可能會覆寫您的設定" + }, + "actions": { + "expand": "查看詳情", + "collapse": "收起", + "selectAll": "全選", + "clearSelection": "取消選擇", + "deleteSelected": "刪除選取 ({{count}})", + "deleting": "刪除中..." + }, + "field": { + "value": "值", + "source": "來源" + }, + "source": { + "userRegistry": "使用者環境變數 (登錄檔)", + "systemRegistry": "系統環境變數 (登錄檔)", + "systemEnv": "系統環境變數" + }, + "delete": { + "success": "環境變數已成功刪除", + "error": "刪除環境變數失敗" + }, + "backup": { + "location": "備份位置:{{path}}" + }, + "confirm": { + "title": "確認刪除環境變數", + "message": "確定要刪除 {{count}} 個環境變數嗎?", + "backupNotice": "刪除前將自動備份,您可以稍後還原。刪除後需要重新啟動應用程式或終端機才能生效。", + "confirm": "確認刪除" + }, + "error": { + "noSelection": "請選擇要刪除的環境變數" + } + }, + "skills": { + "manage": "Skills", + "title": "Skills 管理", + "description": "從熱門的儲存庫發現並安裝技能,擴充 Claude Code/Codex/Gemini 的能力", + "refresh": "重新整理", + "refreshing": "重新整理中...", + "repoManager": "儲存庫管理", + "count": "共 {{count}} 個技能", + "empty": "暫無可用技能", + "emptyDescription": "新增技能儲存庫以發現可用的技能", + "addRepo": "新增技能儲存庫", + "loading": "載入中...", + "installed": "已安裝", + "install": "安裝", + "installing": "安裝中...", + "uninstall": "解除安裝", + "uninstalling": "解除安裝中...", + "view": "檢視", + "noDescription": "暫無描述", + "loadFailed": "載入失敗", + "installSuccess": "技能 {{name}} 已安裝", + "installFailed": "安裝失敗", + "uninstallSuccess": "技能 {{name}} 已解除安裝", + "uninstallFailed": "解除安裝失敗", + "update": "更新", + "updating": "更新中...", + "updateAvailable": "可更新", + "updateSuccess": "技能 {{name}} 已更新至最新版本", + "updateFailed": "更新失敗", + "checkUpdates": "檢查更新", + "checkingUpdates": "檢查中...", + "noUpdates": "所有技能已是最新版本", + "updatesFound": "發現 {{count}} 個技能有可用更新", + "updateAll": "全部更新 ({{count}})", + "updatingAll": "更新中...", + "updateAllSuccess": "已成功更新 {{count}} 個技能", + "error": { + "skillNotFound": "技能不存在:{{directory}}", + "missingRepoInfo": "缺少儲存庫資訊(owner 或 name)", + "downloadTimeout": "下載儲存庫 {{owner}}/{{name}} 逾時({{timeout}} 秒)", + "downloadTimeoutHint": "請檢查網路連線或稍後重試", + "skillPathNotFound": "儲存庫 {{owner}}/{{name}} 中未找到技能路徑 '{{path}}'", + "skillDirNotFound": "技能目錄不存在:{{path}}", + "directoryConflict": "技能目錄 '{{directory}}' 已被 {{existing_repo}} 佔用,無法從 {{new_repo}} 安裝", + "emptyArchive": "下載的壓縮檔為空", + "downloadFailed": "下載失敗:HTTP {{status}}", + "allBranchesFailed": "所有分支下載失敗,嘗試了:{{branches}}", + "httpError": "HTTP 錯誤 {{status}}", + "http403": "GitHub 存取受限,可能是請求頻率過高", + "http404": "儲存庫或分支不存在,請檢查位址", + "http429": "請求過於頻繁,請等待後重試", + "parseMetadataFailed": "解析技能中繼資料失敗", + "getHomeDirFailed": "無法取得使用者主目錄", + "noSkillsInZip": "ZIP 檔案中未找到技能(需包含 SKILL.md 檔案)", + "networkError": "網路錯誤", + "fsError": "檔案系統錯誤", + "unknownError": "未知錯誤", + "suggestion": { + "checkNetwork": "請檢查網路連線", + "checkProxy": "建議設定 HTTP 代理伺服器", + "retryLater": "請稍後重試", + "checkRepoUrl": "請檢查儲存庫位址和分支名稱", + "checkDiskSpace": "請檢查磁碟空間", + "checkPermission": "請檢查目錄權限", + "uninstallFirst": "請先解除安裝已安裝的同名技能", + "checkZipContent": "請確認 ZIP 檔案包含有效的技能目錄(含 SKILL.md 檔案)" + } + }, + "repo": { + "title": "管理技能儲存庫", + "description": "新增或刪除 GitHub 技能儲存庫來源", + "url": "儲存庫 URL", + "urlPlaceholder": "owner/name 或 https://github.com/owner/name", + "branch": "分支", + "branchPlaceholder": "main", + "path": "技能路徑", + "pathPlaceholder": "skills (選填,留空掃描根目錄)", + "add": "新增儲存庫", + "list": "已新增的儲存庫", + "empty": "暫無儲存庫", + "invalidUrl": "無效的儲存庫 URL 格式", + "addSuccess": "儲存庫 {{owner}}/{{name}} 已新增,識別到 {{count}} 個技能", + "addFailed": "新增失敗", + "removeSuccess": "儲存庫 {{owner}}/{{name}} 已刪除", + "removeFailed": "刪除失敗", + "skillCount": "識別到 {{count}} 個技能" + }, + "search": "搜尋技能", + "searchPlaceholder": "搜尋技能名稱或儲存庫名稱...", + "searchSource": { + "repos": "儲存庫", + "skillssh": "skills.sh" + }, + "skillssh": { + "searchPlaceholder": "搜尋 skills.sh(至少 2 個字元)...", + "installs": "{{count}} 次安裝", + "loadMore": "載入更多", + "loading": "正在搜尋 skills.sh...", + "noResults": "未找到 \"{{query}}\" 相關技能", + "error": "搜尋 skills.sh 失敗", + "poweredBy": "由 skills.sh 提供" + }, + "filter": { + "placeholder": "狀態篩選", + "all": "全部", + "installed": "已安裝", + "uninstalled": "未安裝", + "repo": "儲存庫篩選", + "allRepos": "全部儲存庫" + }, + "noResults": "未找到相符的技能", + "noInstalled": "暫無已安裝的技能", + "noInstalledDescription": "從儲存庫發現並安裝技能,或匯入已有的技能", + "discover": "發現技能", + "import": "匯入已有", + "importDescription": "選擇要匯入至 CC Switch 統一管理的技能", + "importSuccess": "成功匯入 {{count}} 個技能", + "importSelected": "匯入已選 ({{count}})", + "noUnmanagedFound": "未發現需要匯入的技能。所有技能已在 CC Switch 統一管理中。", + "foundIn": "發現於", + "local": "本地", + "uninstallConfirm": "確定要解除安裝技能 \"{{name}}\" 嗎?這將從所有應用程式中移除該技能,並在刪除前自動建立本地備份。", + "uninstallInMainPanel": "請在主面板中解除安裝技能", + "notFound": "未找到技能", + "backup": { + "location": "備份位置:{{path}}" + }, + "restoreFromBackup": { + "button": "從備份中還原", + "title": "從備份中還原", + "description": "選擇一個 Skills 備份,將檔案還原至本地並重新加入目前清單。", + "empty": "暫無可還原的 Skills 備份", + "createdAt": "備份時間", + "path": "備份路徑", + "restore": "還原", + "restoring": "還原中...", + "delete": "刪除", + "deleting": "刪除中...", + "deleteSuccess": "技能備份 {{name}} 已刪除", + "deleteFailed": "刪除技能備份失敗", + "deleteConfirmTitle": "確認刪除備份", + "deleteConfirmMessage": "確定要刪除技能備份 \"{{name}}\" 嗎?此操作無法復原。", + "success": "技能 {{name}} 已從備份還原", + "failed": "從備份還原失敗" + }, + "apps": { + "claude": "Claude", + "codex": "Codex", + "gemini": "Gemini", + "opencode": "OpenCode", + "openclaw": "OpenClaw" + }, + "installFromZip": { + "button": "從 ZIP 安裝", + "installing": "安裝中...", + "successSingle": "技能 {{name}} 已安裝", + "successMultiple": "成功安裝 {{count}} 個技能", + "noSkillsFound": "ZIP 檔案中未找到技能(需包含 SKILL.md 檔案)" + } + }, + "deeplink": { + "confirmImport": "確認匯入供應商設定", + "confirmImportDescription": "以下設定將匯入至 CC Switch", + "importPrompt": "匯入提示詞", + "importPromptDescription": "請確認是否匯入此系統提示詞", + "importMcp": "匯入 MCP Servers", + "importMcpDescription": "請確認是否匯入這些 MCP Servers", + "importSkill": "新增 Skill 儲存庫", + "importSkillDescription": "請確認是否新增此 Skill 儲存庫", + "promptImportSuccess": "提示詞匯入成功", + "promptImportSuccessDescription": "已匯入提示詞:{{name}}", + "mcpImportSuccess": "MCP Servers 匯入成功", + "mcpImportSuccessDescription": "成功匯入 {{count}} 個伺服器", + "mcpPartialSuccess": "部分匯入成功", + "mcpPartialSuccessDescription": "成功:{{success}},失敗:{{failed}}", + "skillImportSuccess": "Skill 儲存庫新增成功", + "skillImportSuccessDescription": "已新增儲存庫:{{repo}}", + "app": "應用程式類型", + "providerName": "供應商名稱", + "homepage": "官網位址", + "endpoint": "API 端點", + "apiKey": "API 金鑰", + "icon": "圖示", + "model": "模型", + "haikuModel": "Haiku 模型", + "sonnetModel": "Sonnet 模型", + "opusModel": "Opus 模型", + "multiModel": "多模態模型", + "notes": "備註", + "import": "匯入", + "importing": "匯入中...", + "warning": "請確認以上資訊準確無誤後再匯入。匯入後可在供應商清單中編輯或刪除。", + "parseError": "深層連結解析失敗", + "importSuccess": "匯入成功", + "importSuccessDescription": "供應商 \"{{name}}\" 已成功匯入", + "importError": "匯入失敗", + "configSource": "設定來源", + "configEmbedded": "內嵌設定", + "configRemote": "遠端設定", + "configDetails": "設定詳情", + "configUrl": "設定檔 URL", + "configMergeError": "合併設定檔失敗", + "primaryEndpoint": "主", + "mcp": { + "title": "批次匯入 MCP Servers", + "targetApps": "目標應用程式", + "serverCount": "MCP Servers ({{count}} 個)", + "enabledWarning": "匯入後將立即寫入所有指定應用程式的設定檔" + }, + "prompt": { + "title": "匯入系統提示詞", + "app": "應用程式", + "name": "名稱", + "description": "描述", + "contentPreview": "內容預覽", + "enabledWarning": "匯入後將立即啟用此提示詞,其他提示詞將被停用" + }, + "skill": { + "title": "新增 Claude Skill 儲存庫", + "repo": "GitHub 儲存庫", + "directory": "目標目錄", + "branch": "分支", + "skillsPath": "Skills 路徑", + "hint": "此操作將新增 Skill 儲存庫至清單。", + "hintDetail": "新增後,您可以在 Skills 管理介面中選擇安裝具體的 Skill。" + }, + "usageScript": "用量查詢", + "usageScriptEnabled": "已啟用", + "usageScriptDisabled": "未啟用", + "usageApiKey": "用量 API Key", + "usageBaseUrl": "用量查詢位址", + "usageAutoInterval": "自動查詢", + "usageAutoIntervalValue": "每 {{minutes}} 分鐘" + }, + "iconPicker": { + "search": "搜尋圖示", + "searchPlaceholder": "輸入圖示名稱...", + "noResults": "未找到相符的圖示", + "category": { + "aiProvider": "AI 服務商", + "cloud": "雲端平台", + "tool": "開發工具", + "other": "其他" + } + }, + "providerIcon": { + "label": "圖示", + "colorLabel": "圖示顏色", + "selectIcon": "選擇圖示", + "preview": "預覽", + "clickToChange": "點擊更換圖示", + "clickToSelect": "點擊選擇圖示", + "color": "圖示顏色" + }, + "migration": { + "success": "設定遷移成功", + "skillsSuccess": "已自動匯入 {{count}} 個技能至統一管理", + "skillsFailed": "自動匯入技能失敗", + "skillsFailedDescription": "請開啟 Skills 頁面點擊「匯入現有」手動匯入(或重新啟動後再試)。" + }, + "agents": { + "title": "Agent" + }, + "modelTest": { + "testProvider": "測試模型" + }, + "health": { + "operational": "正常", + "degraded": "降級", + "failed": "失敗", + "circuitOpen": "斷路", + "consecutiveFailures": "連續失敗 {{count}} 次" + }, + "failover": { + "enabled": "{{app}} 故障轉移已啟用", + "disabled": "{{app}} 故障轉移已關閉", + "toggleFailed": "操作失敗:{{detail}}", + "inQueue": "已加入", + "addQueue": "加入", + "priority": { + "tooltip": "故障轉移優先順序 {{priority}}" + }, + "tooltip": { + "enabled": "{{app}} 故障轉移已啟用\n按佇列優先順序(P1→P2→...)選擇供應商", + "disabled": "啟用 {{app}} 故障轉移\n將立即切換至佇列 P1,並在失敗時自動切換至下一個" + } + }, + "proxy": { + "panel": { + "serviceAddress": "服務位址", + "addressCopied": "位址已複製", + "currentProvider": "目前 Provider:", + "waitingFirstRequest": "目前 Provider:等待首次請求...", + "stoppedTitle": "路由服務已停止", + "stoppedDescription": "使用上方開關即可啟動服務", + "openSettings": "設定路由服務", + "stats": { + "activeConnections": "活躍連線", + "totalRequests": "總請求數", + "successRate": "成功率", + "uptime": "運作時間" + } + }, + "settings": { + "title": "路由服務設定", + "description": "設定本地路由伺服器的監聽位址、連接埠和執行參數,儲存後立即生效。", + "alert": { + "autoApply": "儲存後將自動同步至正在執行的路由服務,無需手動重新啟動。" + }, + "basic": { + "title": "基礎設定", + "description": "設定路由服務監聽的位址與連接埠。" + }, + "advanced": { + "title": "進階參數", + "description": "控制請求的穩定性和日誌紀錄。" + }, + "timeout": { + "title": "逾時設定", + "description": "設定串流和非串流請求的逾時時間。" + }, + "fields": { + "listenAddress": { + "label": "監聽位址", + "placeholder": "127.0.0.1", + "description": "路由伺服器監聽的 IP 位址(推薦 127.0.0.1)" + }, + "listenPort": { + "label": "監聽連接埠", + "placeholder": "15721", + "description": "路由伺服器監聽的連接埠號(1024 ~ 65535)" + }, + "maxRetries": { + "label": "最大重試次數", + "placeholder": "3", + "description": "請求失敗時的重試次數(0 ~ 10)" + }, + "requestTimeout": { + "label": "請求逾時(秒)", + "placeholder": "0(不限)或 300", + "description": "單個請求的最大等待時間(0 表示不限制,或設定 10 ~ 600 秒)" + }, + "enableLogging": { + "label": "啟用日誌紀錄", + "description": "紀錄所有路由請求,便於排查問題" + }, + "streamingFirstByteTimeout": { + "label": "串流首位元組逾時(秒)", + "description": "等待首個資料區塊的最大時間" + }, + "streamingIdleTimeout": { + "label": "串流閒置逾時(秒)", + "description": "資料區塊之間的最大間隔" + }, + "nonStreamingTimeout": { + "label": "非串流逾時(秒)", + "description": "非串流請求的總逾時時間" + } + }, + "validation": { + "addressInvalid": "請輸入有效的 IP 位址", + "portMin": "連接埠必須大於 1024", + "portMax": "連接埠必須小於 65535", + "retryMin": "重試次數不能為負", + "retryMax": "重試次數不能超過 10", + "timeoutNonNegative": "逾時時間不能為負數", + "timeoutMax": "逾時時間最多 600 秒", + "timeoutRange": "請輸入 0 或 10-600 之間的數值", + "streamingTimeoutMin": "逾時時間至少 5 秒", + "streamingTimeoutMax": "逾時時間最多 300 秒" + }, + "actions": { + "save": "儲存設定" + }, + "toast": { + "saved": "路由設定已儲存", + "saveFailed": "儲存失敗:{{error}}" + }, + "invalidPort": "連接埠無效,請輸入 1024-65535 之間的數字", + "invalidAddress": "位址無效,請輸入 IPv4(如 127.0.0.1)、IPv6(如 ::1)或 localhost", + "configSaved": "路由設定已儲存", + "configSaveFailed": "儲存設定失敗", + "restartRequired": "修改位址或連接埠後需要重新啟動路由服務才能生效" + }, + "switchFailed": "切換失敗:{{error}}", + "takeover": { + "hint": "選擇要路由的應用程式,啟用後該應用程式的請求將透過本地路由轉發", + "enabled": "{{app}} 路由已啟用", + "disabled": "{{app}} 路由已關閉", + "failed": "切換路由狀態失敗:{{detail}}", + "tooltip": { + "active": "{{appLabel}} 路由中 - {{address}}:{{port}}\n切換該應用程式供應商為熱切換", + "broken": "{{appLabel}} 路由中,但路由服務未執行", + "inactive": "路由 {{appLabel}} 的請求,讓該應用程式請求走本地路由" + } + }, + "failover": { + "proxyRequired": "需要先啟動路由服務才能設定故障轉移", + "autoSwitch": "自動故障轉移", + "autoSwitchDescription": "開啟後將立即切換至佇列 P1,並在請求失敗時自動切換至佇列中的下一個供應商" + }, + "failoverQueue": { + "title": "故障轉移佇列", + "description": "管理各應用程式的供應商故障轉移順序", + "info": "啟用自動故障轉移後,將按佇列優先順序選擇供應商(P1 優先)。當請求失敗時,系統會按佇列順序依次嘗試下一個供應商。", + "selectProvider": "選擇供應商新增至佇列", + "noAvailableProviders": "沒有可新增的供應商", + "empty": "故障轉移佇列為空。新增供應商以啟用自動故障轉移。", + "orderHint": "佇列順序與首頁供應商清單順序一致,可在首頁拖曳調整順序。", + "dragHint": "拖曳供應商可調整故障轉移順序,序號越小優先順序越高。", + "toggleEnabled": "啟用/停用", + "addSuccess": "已新增至故障轉移佇列", + "addFailed": "新增失敗", + "removeSuccess": "已從故障轉移佇列移除", + "removeFailed": "移除失敗", + "reorderSuccess": "佇列順序已更新", + "reorderFailed": "更新順序失敗", + "toggleFailed": "狀態更新失敗" + }, + "autoFailover": { + "info": "當故障轉移佇列中設定了多個供應商時,系統會在請求失敗時按優先順序依次嘗試。當某個供應商連續失敗達到閾值時,斷路器會打開並在一段時間內跳過該供應商。", + "configSaved": "自動故障轉移設定已儲存", + "configSaveFailed": "儲存失敗", + "validationFailed": "以下欄位超出有效範圍:{{fields}}", + "retrySettings": "重試與逾時設定", + "failureThreshold": "失敗閾值", + "failureThresholdHint": "連續失敗多少次後打開斷路器(建議:3-10)", + "timeout": "恢復等待時間(秒)", + "timeoutHint": "斷路器打開後,等待多久後嘗試恢復(建議:30-120)", + "circuitBreakerSettings": "斷路器設定", + "successThreshold": "恢復成功閾值", + "successThresholdHint": "半開狀態下成功多少次後關閉斷路器", + "errorRate": "錯誤率閾值 (%)", + "errorRateHint": "錯誤率超過此值時打開斷路器", + "minRequests": "最小請求數", + "minRequestsHint": "計算錯誤率前的最小請求數", + "explanationTitle": "運作原理", + "failureThresholdLabel": "失敗閾值", + "failureThresholdExplain": "連續失敗達到此次數時,斷路器打開,該供應商暫時不可用", + "timeoutLabel": "恢復等待時間", + "timeoutExplain": "斷路器打開後,等待此時間後嘗試半開狀態", + "successThresholdLabel": "恢復成功閾值", + "successThresholdExplain": "半開狀態下,成功達到此次數時關閉斷路器,供應商恢復可用", + "errorRateLabel": "錯誤率閾值", + "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": "健康檢測設定已儲存", + "configSaveFailed": "儲存失敗", + "testModels": "測試模型", + "claudeModel": "Claude 模型", + "codexModel": "Codex 模型", + "geminiModel": "Gemini 模型", + "checkParams": "檢查參數", + "timeout": "逾時時間(秒)", + "maxRetries": "最大重試次數", + "degradedThreshold": "降級閾值(毫秒)", + "testPrompt": "檢查提示詞", + "operational": "{{providerName}} 執行正常 ({{responseTimeMs}}ms)", + "degraded": "{{providerName}} 回應較慢 ({{responseTimeMs}}ms)", + "failed": "{{providerName}} 檢查失敗:{{message}}", + "rejected": "{{providerName}} 檢查被拒:{{message}}", + "error": "{{providerName}} 檢查出錯:{{error}}", + "modelNotFound": "{{providerName}} 測試模型 {{model}} 不存在或已下架", + "modelNotFoundHint": "該模型可能已被供應商棄用。請在「模型測試設定」中更新預設測試模型。", + "quotaExceeded": "{{providerName}} Coding Plan 額度已用盡", + "quotaExceededHint": "百度千帆回傳了 Coding Plan 超額錯誤。請等待 5 小時 / 每週 / 每月額度重新整理,或在千帆控制台切換方案。", + "httpHint": { + "400": "供應商拒絕了請求格式。健康檢測的探測格式可能與實際使用不同。", + "401": "API Key 可能無效,或供應商使用 OAuth 等驗證方式。檢查失敗不代表實際不可用。", + "402": "帳號配額或計費問題。", + "403": "供應商拒絕了此請求。部分供應商會驗證用戶端身分,檢查失敗但實際使用可能正常。", + "404": "API 位址不存在,請檢查 Base URL 和 API 路徑。", + "429": "請求頻率過高,請稍後重試。", + "5xx": "供應商內部錯誤,通常是臨時問題。" + } + }, + "proxyConfig": { + "proxyEnabled": "路由總開關", + "appTakeover": "路由啟用", + "perAppConfig": "應用程式設定", + "circuitBreaker": "斷路器設定", + "circuitBreakerSettings": "斷路器設定", + "failureThreshold": "失敗閾值", + "successThreshold": "恢復閾值", + "recoveryTimeout": "恢復等待時間", + "errorRateThreshold": "錯誤率閾值", + "minRequests": "最小請求數", + "timeoutConfig": "逾時設定", + "streamingFirstByte": "串流首位元組逾時", + "streamingIdle": "串流閒置逾時", + "nonStreaming": "非串流逾時" + }, + "circuitBreaker": { + "failureThreshold": "失敗閾值", + "successThreshold": "成功閾值", + "timeoutSeconds": "逾時時間(秒)", + "errorRateThreshold": "錯誤率閾值 (%)", + "minRequests": "最小請求數", + "validationFailed": "以下欄位超出有效範圍:{{fields}}", + "configSaved": "斷路器設定已儲存", + "saveFailed": "儲存失敗", + "loading": "載入中...", + "title": "斷路器設定", + "description": "調整斷路器參數以控制故障檢測和恢復行為", + "failureThresholdHint": "連續失敗多少次後打開斷路器", + "timeoutSecondsHint": "斷路器打開後多久嘗試恢復(半開狀態)", + "successThresholdHint": "半開狀態下成功多少次後關閉斷路器", + "errorRateThresholdHint": "錯誤率超過此值時打開斷路器", + "minRequestsHint": "計算錯誤率前的最小請求數", + "saveConfig": "儲存設定", + "instructionsTitle": "設定說明", + "instructions": { + "failureThreshold": "連續失敗達到此次數時,斷路器打開", + "timeout": "斷路器打開後,等待此時間後嘗試半開", + "successThreshold": "半開狀態下,成功達到此次數時關閉斷路器", + "errorRate": "錯誤率超過此值時,斷路器打開", + "minRequests": "只有請求數達到此值後才計算錯誤率" + } + }, + "universalProvider": { + "duplicate": "複製", + "duplicatedAndSynced": "通用供應商已複製並同步", + "duplicateError": "複製通用供應商失敗", + "title": "通用供應商", + "description": "通用供應商可以同時管理 Claude、Codex 和 Gemini 的設定。修改後會自動同步至所有啟用的應用程式。", + "add": "新增通用供應商", + "edit": "編輯通用供應商", + "empty": "還沒有通用供應商", + "emptyHint": "點擊下方「新增通用供應商」按鈕建立一個", + "selectPreset": "選擇預設類型", + "name": "名稱", + "namePlaceholder": "例如:我的 NewAPI", + "baseUrl": "API 位址", + "apiKey": "API Key", + "websiteUrl": "官網位址", + "websiteUrlPlaceholder": "https://example.com(選填,用於在清單中顯示)", + "notes": "備註", + "notesPlaceholder": "選填:加入備註資訊", + "enabledApps": "啟用的應用程式", + "modelConfig": "模型設定", + "model": "模型", + "sync": "同步至應用程式", + "synced": "已同步至所有應用程式", + "syncError": "同步失敗", + "noAppsEnabled": "未啟用任何應用程式", + "added": "通用供應商已新增", + "addedAndSynced": "通用供應商已新增並同步", + "updated": "通用供應商已更新", + "deleted": "通用供應商已刪除", + "addSuccess": "通用供應商新增成功", + "addFailed": "通用供應商新增失敗", + "hint": "跨應用程式通用設定,自動同步至 Claude/Codex/Gemini", + "manage": "管理", + "loadError": "載入通用供應商失敗", + "saveError": "儲存通用供應商失敗", + "deleteError": "刪除通用供應商失敗", + "deleteConfirmTitle": "刪除通用供應商", + "deleteConfirmDescription": "確定要刪除 \"{{name}}\" 嗎?這將同時刪除它在各應用程式中產生的供應商設定。", + "syncConfirmTitle": "同步通用供應商", + "syncConfirmDescription": "同步 \"{{name}}\" 將會覆寫 Claude、Codex 和 Gemini 中關聯的供應商設定。確定要繼續嗎?", + "syncConfirm": "同步", + "saveAndSync": "儲存並同步", + "savedAndSynced": "已儲存並同步至所有應用程式", + "saveAndSyncError": "儲存並同步失敗", + "configJsonPreview": "設定 JSON 預覽", + "configJsonPreviewHint": "以下是將要同步至各應用程式的設定內容(僅覆寫顯示的欄位,保留其他自訂設定)" + }, + "omo": { + "editProfile": "編輯 OMO 設定", + "newProfile": "新增 OMO 設定", + "profileName": "名稱", + "mainAgents": "主 Agent", + "subAgents": "子 Agent", + "categories": "分類", + "customAgents": "自訂 Agent", + "noCustomAgents": "暫無自訂 Agent", + "otherFields": "其他設定", + "globalConfig": "OMO 全域設定", + "globalConfigShort": "OMO 設定", + "globalConfigSaved": "全域設定已儲存", + "addProfile": "新增 OMO 設定", + "disabledItems": "停用項目設定", + "advanced": "進階設定", + "profileCreated": "OMO 設定已建立", + "profileUpdated": "OMO 設定已更新", + "invalidJson": "其他欄位包含無效 JSON", + "confirmDelete": "刪除設定", + "confirmDeleteMsg": "確定刪除 \"{{name}}\" 嗎?", + "profileDeleted": "設定已刪除", + "imported": "已匯入為 \"{{name}}\"", + "import": "匯入", + "global": "全域", + "empty": "暫無設定。點擊 + 新增或從本地匯入。", + "applied": "已套用", + "apply": "套用", + "enable": "啟用", + "enabled": "啟用中", + "disabled": "OMO 已停用", + "disableFailed": "停用 OMO 失敗:{{error}}", + "selectPlaceholder": "請選擇...", + "clear": "清空", + "clearWrapped": "(清空)", + "defaultWrapped": "(預設)", + "variantPlaceholder": "思考等級", + "selectEnabledModel": "選擇已設定模型", + "selectModel": "選擇已設定模型", + "recommendedHint": "推薦:{{model}}", + "searchModel": "搜尋模型...", + "selectModelFirst": "先選擇模型", + "noEnabledModels": "暫無已設定模型", + "noVariantsForModel": "該模型無思考等級", + "currentValueNotEnabled": "{{value}}(目前值,未設定)", + "currentValueUnavailable": "{{value}}(目前值,不可用)", + "advancedLabel": "進階參數", + "advancedJsonInvalid": "進階參數 JSON 無效", + "advancedJsonHint": "temperature, top_p, budgetTokens, prompt_append, permission 等,留空使用預設值", + "noEnabledModelsWarning": "目前沒有可用的已設定模型,請先設定 OpenCode 模型", + "modelSourcePartialWarning": "部分供應商模型設定無效,已自動跳過。", + "modelSourceFallbackWarning": "讀取 live 供應商狀態失敗,已回退至已設定供應商清單。", + "importLocalReplaceSuccess": "已從本地檔案匯入並覆寫 Agent/Category/Other Fields", + "importLocalFailed": "讀取本地檔案失敗:{{error}}", + "agentKeyPlaceholder": "agent 鍵名", + "categoryKeyPlaceholder": "分類鍵名", + "modelNamePlaceholder": "模型名", + "custom": "自訂", + "customCategories": "自訂分類", + "modelConfiguration": "模型設定", + "fillRecommended": "填入推薦", + "fillRecommendedSuccess": "已填入 {{count}} 個推薦模型", + "fillRecommendedPartial": "已填入 {{filled}} 個推薦模型,{{unmatched}} 個未比對成功", + "fillRecommendedAllSet": "所有槽位已有模型設定", + "fillRecommendedNoMatch": "推薦模型在已設定的供應商中未找到相符項目", + "configSummary": "已設定 {{agents}} 個 Agent,{{categories}} 個 Category · 點擊 ⚙ 展開進階參數", + "enabledModelsCount": "可選已設定模型 {{count}} 個", + "source": "來源:", + "otherFieldsJson": "其他欄位 (JSON)", + "slimOtherFieldsHint": "OMO Slim 的 council、fallback、multiplexer、disabled_mcps、todoContinuation 等頂層設定請寫在這裡。", + "searchOrType": "搜尋或輸入自訂值...", + "noMatches": "無相符項目", + "jsonMustBeObject": "{{field}} 必須是 JSON 物件", + "jsonInvalid": "{{field}} 包含無效 JSON", + "importGlobalSuccess": "已從本地檔案匯入全域設定(未儲存)", + "importGlobalFailed": "讀取本地檔案失敗:{{error}}", + "importLocal": "從本地匯入", + "saveGlobalConfig": "儲存全域設定", + "schemaUrl": "$schema", + "resetDefault": "還原預設", + "sisyphusAgentConfig": "Sisyphus Agent 設定", + "disabledAgents": "Agents", + "disabledAgentsPlaceholder": "停用的 Agents", + "disabledMcps": "MCPs", + "disabledMcpsPlaceholder": "停用的 MCPs", + "disabledHooks": "Hooks", + "disabledHooksPlaceholder": "停用的 Hooks", + "disabledSkills": "Skills", + "disabledSkillsPlaceholder": "停用的 Skills", + "advancedLsp": "LSP 設定", + "advancedExperimental": "實驗性功能", + "advancedBackgroundTask": "背景任務", + "advancedBrowserAutomation": "瀏覽器自動化", + "advancedClaudeCode": "Claude Code", + "agentDesc": { + "sisyphus": "主協調器", + "hephaestus": "自主深度工作者", + "prometheus": "戰略規劃者", + "atlas": "任務管理者", + "oracle": "戰略顧問", + "librarian": "多儲存庫研究員", + "explore": "快速程式碼搜尋", + "multimodalLooker": "媒體分析器", + "metis": "規劃前分析顧問", + "momus": "計畫審查者", + "sisyphusJunior": "委派任務執行器" + }, + "agentTooltip": { + "sisyphus": "主協調器,負責任務規劃、委派與並行執行,使用擴充思考(32k 預算),透過 TODO 驅動工作流程確保任務完成。", + "atlas": "主協調器(持有 TODO 清單),負責執行階段的任務分發與協調,不直接完成所有工作而是委派給專業代理。", + "prometheus": "戰略規劃師,透過訪談模式收集需求並制定詳細工作計畫,僅能在 .sisyphus/ 目錄讀寫 Markdown 檔案,從不直接寫程式碼。", + "hephaestus": "自主深度工作者(「合法工匠」),受 AmpCode 深度模式啟發,目標導向執行,行動前會並行啟動 2-5 個探索 / 圖書管理員代理進行研究。", + "oracle": "架構決策與除錯顧問,唯讀諮詢代理,提供出色的邏輯推理和深度分析,不能寫檔案或委派任務。", + "librarian": "多儲存庫分析與文件檢索專家,深度理解程式碼庫並提供基於證據的答案,擅長尋找官方文件和開源實作範例。", + "explore": "快速程式碼庫探索與上下文 grep 專家,使用輕量級模型進行高速搜尋,是理解程式碼結構的先鋒。", + "multimodalLooker": "視覺內容專家,分析 PDF、圖片、圖表等非文字媒體,提取其中的資訊與洞見。", + "metis": "計畫顧問,在規劃前進行預先分析,識別隱藏意圖、模糊點和 AI 失敗點,防止過度工程化。", + "momus": "計畫審查員,高精度驗證計畫的清晰度、可驗證性和完整性,拒絕並要求修訂直到計畫完美。", + "sisyphusJunior": "類別產生的執行器,由 category 參數自動產生,專注於執行分配的任務且不能再委派,防止無限委派迴圈。" + }, + "categoryDesc": { + "visualEngineering": "視覺 / 前端工程", + "ultrabrain": "超級思考", + "deep": "深度工作", + "artistry": "創意 / 文藝", + "quick": "快速回應", + "unspecifiedLow": "通用低階", + "unspecifiedHigh": "通用高階", + "writing": "寫作" + }, + "categoryTooltip": { + "visualEngineering": "前端與視覺工程類別,專注於 UI/UX 設計、樣式、動畫和介面實作,預設使用 Gemini 3 Pro 模型。", + "ultrabrain": "深度邏輯推理類別,用於需要廣泛分析的複雜架構決策,預設使用 GPT-5.3 Codex 的超高推理變體。", + "deep": "深度自主問題解決類別,目標導向執行,行動前進行徹底研究,適用於需要深度理解的棘手問題。", + "artistry": "高度創意與藝術性任務類別,激發新穎想法和創造性解決方案,預設使用 Gemini 3 Pro 的最大變體。", + "quick": "輕量任務類別,用於單檔案修改、錯別字修復、簡單調整等瑣碎工作,預設使用 Claude Haiku 4.5 快速模型。", + "unspecifiedLow": "未分類低工作量任務類別,適用於不適合其他類別且工作量較小的任務,預設使用 Claude Sonnet 4.5。", + "unspecifiedHigh": "未分類高工作量任務類別,適用於不適合其他類別且工作量較大的任務,預設使用 Claude Opus 4.7 的最大變體。", + "writing": "寫作類別,專注於文件、散文和技術寫作,預設使用 Gemini 3 Flash 快速產生模型。" + }, + "slimAgentDesc": { + "orchestrator": "協調器", + "oracle": "神諭者", + "librarian": "圖書管理員", + "explorer": "探索者", + "designer": "設計師", + "fixer": "修復者", + "council": "議會" + }, + "slimAgentTooltip": { + "orchestrator": "編寫執行程式碼,協調多代理工作流程,召喚專家", + "oracle": "根本原因分析、架構審查、除錯指導(唯讀)", + "librarian": "文件查詢、GitHub 程式碼搜尋(唯讀)", + "explorer": "正規搜尋、AST 模式比對、檔案發現(唯讀)", + "designer": "現代響應式設計、CSS / Tailwind 精通", + "fixer": "程式碼實作、重構、測試、驗證", + "council": "多模型共識代理,並行執行多個唯讀 councillor,再由 master 彙整最終答案。" + } + }, + "openclawConfig": { + "defaultModel": { + "title": "預設模型", + "description": "設定 OpenClaw 的預設主模型和備用模型", + "primary": "主模型", + "primaryPlaceholder": "例如: deepseek/deepseek-chat", + "fallbacks": "備用模型", + "fallbacksPlaceholder": "例如: openrouter/anthropic/claude-sonnet-4.5", + "addFallback": "新增備用模型", + "saved": "預設模型設定已儲存", + "saveFailed": "儲存預設模型失敗" + }, + "modelCatalog": { + "title": "模型目錄", + "description": "設定可用模型的別名和允許清單", + "modelId": "模型 ID", + "modelIdPlaceholder": "例如: deepseek/deepseek-chat", + "alias": "別名", + "aliasPlaceholder": "例如: DeepSeek", + "addEntry": "新增模型", + "removeEntry": "移除", + "saved": "模型目錄已儲存", + "saveFailed": "儲存模型目錄失敗", + "empty": "暫無模型目錄設定", + "emptyHint": "新增模型至目錄以設定別名" + }, + "suggestedDefaults": "套用建議預設設定", + "suggestedDefaultsHint": "使用此預設推薦的預設模型設定" + }, + "subscription": { + "title": "訂閱額度", + "fiveHour": "5 小時", + "sevenDay": "7 天", + "sevenDayOpus": "7 天 (Opus)", + "sevenDaySonnet": "7 天 (Sonnet)", + "geminiPro": "Pro", + "geminiFlash": "Flash", + "geminiFlashLite": "Flash Lite", + "weeklyLimit": "每週", + "copilotPremium": "進階請求", + "utilization": "{{value}}%", + "resetsIn": "{{time}} 後重設", + "extraUsage": "超額用量", + "expired": "工作階段已過期", + "expiredHint": "請執行 {{tool}} 命令重新整理登入", + "queryFailed": "查詢失敗", + "refresh": "重新整理" + } +} diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index afb7a9214..4064af713 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -542,7 +542,8 @@ } }, "autoReload": "数据已刷新", - "languageOptionChinese": "中文", + "languageOptionChinese": "简体中文", + "languageOptionTraditionalChinese": "繁體中文", "languageOptionEnglish": "English", "languageOptionJapanese": "日本語", "windowBehavior": "窗口行为", diff --git a/src/lib/schemas/settings.ts b/src/lib/schemas/settings.ts index 9b42d787e..774d3eced 100644 --- a/src/lib/schemas/settings.ts +++ b/src/lib/schemas/settings.ts @@ -15,7 +15,7 @@ export const settingsSchema = z.object({ skipClaudeOnboarding: z.boolean().optional(), launchOnStartup: z.boolean().optional(), enableLocalProxy: z.boolean().optional(), - language: z.enum(["en", "zh", "ja"]).optional(), + language: z.enum(["en", "zh", "zh-TW", "ja"]).optional(), // 设备级目录覆盖 claudeConfigDir: directorySchema.nullable().optional(), diff --git a/src/types.ts b/src/types.ts index 0891f1ecc..9b943beca 100644 --- a/src/types.ts +++ b/src/types.ts @@ -342,7 +342,7 @@ export interface Settings { // User has confirmed the common config first-run notice commonConfigConfirmed?: boolean; // 首选语言(可选,默认中文) - language?: "en" | "zh" | "ja"; + language?: "en" | "zh" | "zh-TW" | "ja"; // 主页面显示的应用(默认全部显示) visibleApps?: VisibleApps; diff --git a/tests/components/usageFormat.test.ts b/tests/components/usageFormat.test.ts new file mode 100644 index 000000000..fd3c695b7 --- /dev/null +++ b/tests/components/usageFormat.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from "vitest"; +import { + formatTokensShort, + getLocaleFromLanguage, +} from "@/components/usage/format"; + +describe("usage format helpers", () => { + it("formats Traditional Chinese token units with Traditional characters", () => { + expect(formatTokensShort(12_345, "zh-TW")).toBe("1.2 萬"); + expect(formatTokensShort(123_456_789, "zh-Hant", 2)).toBe("1.23 億"); + }); + + it("resolves Traditional Chinese locale aliases", () => { + expect(getLocaleFromLanguage("zh_TW")).toBe("zh-TW"); + expect(getLocaleFromLanguage("zh-HK")).toBe("zh-TW"); + }); +}); diff --git a/tests/hooks/useSettingsForm.test.tsx b/tests/hooks/useSettingsForm.test.tsx index f6dbd96b1..741d96a37 100644 --- a/tests/hooks/useSettingsForm.test.tsx +++ b/tests/hooks/useSettingsForm.test.tsx @@ -81,6 +81,29 @@ describe("useSettingsForm Hook", () => { expect(changeLanguageSpy).toHaveBeenCalledWith("ja"); }); + it("should support traditional chinese language preference aliases", async () => { + useSettingsQueryMock.mockReturnValue({ + data: { + showInTray: true, + minimizeToTrayOnClose: true, + enableClaudePluginIntegration: false, + claudeConfigDir: "/Users/demo", + codexConfigDir: null, + language: "zh-Hant", + }, + isLoading: false, + }); + + const { result } = renderHook(() => useSettingsForm()); + + await waitFor(() => { + expect(result.current.settings?.language).toBe("zh-TW"); + }); + + expect(result.current.initialLanguage).toBe("zh-TW"); + expect(changeLanguageSpy).toHaveBeenCalledWith("zh-TW"); + }); + it("should prioritize reading language from local storage in readPersistedLanguage", () => { useSettingsQueryMock.mockReturnValue({ data: null,