Browse Source

feat(i18n): add Traditional Chinese language support & rename 'Chinese' to 'Chinese (Simplified)' (#9887)

Alex Yaroshuk 1 month ago
parent
commit
23daac2170

+ 11 - 3
packages/app/src/context/language.tsx

@@ -5,6 +5,7 @@ import { createSimpleContext } from "@opencode-ai/ui/context"
 import { Persist, persisted } from "@/utils/persist"
 import { dict as en } from "@/i18n/en"
 import { dict as zh } from "@/i18n/zh"
+import { dict as zht } from "@/i18n/zht"
 import { dict as ko } from "@/i18n/ko"
 import { dict as de } from "@/i18n/de"
 import { dict as es } from "@/i18n/es"
@@ -15,6 +16,7 @@ import { dict as pl } from "@/i18n/pl"
 import { dict as ru } from "@/i18n/ru"
 import { dict as uiEn } from "@opencode-ai/ui/i18n/en"
 import { dict as uiZh } from "@opencode-ai/ui/i18n/zh"
+import { dict as uiZht } from "@opencode-ai/ui/i18n/zht"
 import { dict as uiKo } from "@opencode-ai/ui/i18n/ko"
 import { dict as uiDe } from "@opencode-ai/ui/i18n/de"
 import { dict as uiEs } from "@opencode-ai/ui/i18n/es"
@@ -24,12 +26,12 @@ import { dict as uiJa } from "@opencode-ai/ui/i18n/ja"
 import { dict as uiPl } from "@opencode-ai/ui/i18n/pl"
 import { dict as uiRu } from "@opencode-ai/ui/i18n/ru"
 
-export type Locale = "en" | "zh" | "ko" | "de" | "es" | "fr" | "da" | "ja" | "pl" | "ru"
+export type Locale = "en" | "zh" | "zht" | "ko" | "de" | "es" | "fr" | "da" | "ja" | "pl" | "ru"
 
 type RawDictionary = typeof en & typeof uiEn
 type Dictionary = i18n.Flatten<RawDictionary>
 
-const LOCALES: readonly Locale[] = ["en", "zh", "ko", "de", "es", "fr", "da", "ja", "pl", "ru"]
+const LOCALES: readonly Locale[] = ["en", "zh", "zht", "ko", "de", "es", "fr", "da", "ja", "pl", "ru"]
 
 function detectLocale(): Locale {
   if (typeof navigator !== "object") return "en"
@@ -37,7 +39,10 @@ function detectLocale(): Locale {
   const languages = navigator.languages?.length ? navigator.languages : [navigator.language]
   for (const language of languages) {
     if (!language) continue
-    if (language.toLowerCase().startsWith("zh")) return "zh"
+    if (language.toLowerCase().startsWith("zh")) {
+      if (language.toLowerCase().includes("hant")) return "zht"
+      return "zh"
+    }
     if (language.toLowerCase().startsWith("ko")) return "ko"
     if (language.toLowerCase().startsWith("de")) return "de"
     if (language.toLowerCase().startsWith("es")) return "es"
@@ -63,6 +68,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
 
     const locale = createMemo<Locale>(() => {
       if (store.locale === "zh") return "zh"
+      if (store.locale === "zht") return "zht"
       if (store.locale === "ko") return "ko"
       if (store.locale === "de") return "de"
       if (store.locale === "es") return "es"
@@ -84,6 +90,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
     const dict = createMemo<Dictionary>(() => {
       if (locale() === "en") return base
       if (locale() === "zh") return { ...base, ...i18n.flatten({ ...zh, ...uiZh }) }
+      if (locale() === "zht") return { ...base, ...i18n.flatten({ ...zht, ...uiZht }) }
       if (locale() === "de") return { ...base, ...i18n.flatten({ ...de, ...uiDe }) }
       if (locale() === "es") return { ...base, ...i18n.flatten({ ...es, ...uiEs }) }
       if (locale() === "fr") return { ...base, ...i18n.flatten({ ...fr, ...uiFr }) }
@@ -99,6 +106,7 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
     const labelKey: Record<Locale, keyof Dictionary> = {
       en: "language.en",
       zh: "language.zh",
+      zht: "language.zht",
       ko: "language.ko",
       de: "language.de",
       es: "language.es",

+ 2 - 1
packages/app/src/i18n/da.ts

@@ -269,7 +269,8 @@ export const dict = {
   "context.usage.clickToView": "Klik for at se kontekst",
 
   "language.en": "Engelsk",
-  "language.zh": "Kinesisk",
+  "language.zh": "Kinesisk (forenklet)",
+  "language.zht": "Kinesisk (traditionelt)",
   "language.ko": "Koreansk",
   "language.de": "Tysk",
   "language.es": "Spansk",

+ 2 - 1
packages/app/src/i18n/de.ts

@@ -274,7 +274,8 @@ export const dict = {
   "context.usage.clickToView": "Klicken, um Kontext anzuzeigen",
 
   "language.en": "Englisch",
-  "language.zh": "Chinesisch",
+  "language.zh": "Chinesisch (Vereinfacht)",
+  "language.zht": "Chinesisch (Traditionell)",
   "language.ko": "Koreanisch",
   "language.de": "Deutsch",
   "language.es": "Spanisch",

+ 2 - 1
packages/app/src/i18n/en.ts

@@ -286,7 +286,8 @@ export const dict = {
   "context.usage.clickToView": "Click to view context",
 
   "language.en": "English",
-  "language.zh": "Chinese",
+  "language.zh": "Chinese (Simplified)",
+  "language.zht": "Chinese (Traditional)",
   "language.ko": "Korean",
   "language.de": "German",
   "language.es": "Spanish",

+ 2 - 1
packages/app/src/i18n/es.ts

@@ -269,7 +269,8 @@ export const dict = {
   "context.usage.clickToView": "Haz clic para ver contexto",
 
   "language.en": "Inglés",
-  "language.zh": "Chino",
+  "language.zh": "Chino (simplificado)",
+  "language.zht": "Chino (tradicional)",
   "language.ko": "Coreano",
   "language.de": "Alemán",
   "language.es": "Español",

+ 2 - 1
packages/app/src/i18n/fr.ts

@@ -269,7 +269,8 @@ export const dict = {
   "context.usage.clickToView": "Cliquez pour voir le contexte",
 
   "language.en": "Anglais",
-  "language.zh": "Chinois",
+  "language.zh": "Chinois (simplifié)",
+  "language.zht": "Chinois (traditionnel)",
   "language.ko": "Coréen",
   "language.de": "Allemand",
   "language.es": "Espagnol",

+ 2 - 1
packages/app/src/i18n/ja.ts

@@ -267,7 +267,8 @@ export const dict = {
   "context.usage.clickToView": "クリックしてコンテキストを表示",
 
   "language.en": "英語",
-  "language.zh": "中国語",
+  "language.zh": "中国語(簡体字)",
+  "language.zht": "中国語(繁体字)",
   "language.ko": "韓国語",
   "language.de": "ドイツ語",
   "language.es": "スペイン語",

+ 2 - 1
packages/app/src/i18n/ko.ts

@@ -271,7 +271,8 @@ export const dict = {
   "context.usage.clickToView": "컨텍스트를 보려면 클릭",
 
   "language.en": "영어",
-  "language.zh": "중국어",
+  "language.zh": "중국어 (간체)",
+  "language.zht": "중국어 (번체)",
   "language.ko": "한국어",
   "language.de": "독일어",
   "language.es": "스페인어",

+ 2 - 1
packages/app/src/i18n/zh.ts

@@ -267,7 +267,8 @@ export const dict = {
   "context.usage.clickToView": "点击查看上下文",
 
   "language.en": "英语",
-  "language.zh": "中文",
+  "language.zh": "简体中文",
+  "language.zht": "繁体中文",
   "language.ko": "韩语",
   "language.de": "德语",
   "language.es": "西班牙语",

+ 547 - 0
packages/app/src/i18n/zht.ts

@@ -0,0 +1,547 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+  "command.category.suggested": "建議",
+  "command.category.view": "檢視",
+  "command.category.project": "專案",
+  "command.category.provider": "提供者",
+  "command.category.server": "伺服器",
+  "command.category.session": "工作階段",
+  "command.category.theme": "主題",
+  "command.category.language": "語言",
+  "command.category.file": "檔案",
+  "command.category.terminal": "終端機",
+  "command.category.model": "模型",
+  "command.category.mcp": "MCP",
+  "command.category.agent": "代理程式",
+  "command.category.permissions": "權限",
+  "command.category.workspace": "工作區",
+
+  "theme.scheme.system": "系統",
+  "theme.scheme.light": "淺色",
+  "theme.scheme.dark": "深色",
+
+  "command.sidebar.toggle": "切換側邊欄",
+  "command.project.open": "開啟專案",
+  "command.provider.connect": "連接提供者",
+  "command.server.switch": "切換伺服器",
+  "command.session.previous": "上一個工作階段",
+  "command.session.next": "下一個工作階段",
+  "command.session.archive": "封存工作階段",
+
+  "command.palette": "命令面板",
+
+  "command.theme.cycle": "循環主題",
+  "command.theme.set": "使用主題: {{theme}}",
+  "command.theme.scheme.cycle": "循環配色方案",
+  "command.theme.scheme.set": "使用配色方案: {{scheme}}",
+
+  "command.language.cycle": "循環語言",
+  "command.language.set": "使用語言: {{language}}",
+
+  "command.session.new": "新增工作階段",
+  "command.file.open": "開啟檔案",
+  "command.file.open.description": "搜尋檔案和命令",
+  "command.terminal.toggle": "切換終端機",
+  "command.review.toggle": "切換審查",
+  "command.terminal.new": "新增終端機",
+  "command.terminal.new.description": "建立新的終端機標籤頁",
+  "command.steps.toggle": "切換步驟",
+  "command.steps.toggle.description": "顯示或隱藏目前訊息的步驟",
+  "command.message.previous": "上一則訊息",
+  "command.message.previous.description": "跳到上一則使用者訊息",
+  "command.message.next": "下一則訊息",
+  "command.message.next.description": "跳到下一則使用者訊息",
+  "command.model.choose": "選擇模型",
+  "command.model.choose.description": "選擇不同的模型",
+  "command.mcp.toggle": "切換 MCP",
+  "command.mcp.toggle.description": "切換 MCP",
+  "command.agent.cycle": "循環代理程式",
+  "command.agent.cycle.description": "切換到下一個代理程式",
+  "command.agent.cycle.reverse": "反向循環代理程式",
+  "command.agent.cycle.reverse.description": "切換到上一個代理程式",
+  "command.model.variant.cycle": "循環思考強度",
+  "command.model.variant.cycle.description": "切換到下一個強度等級",
+  "command.permissions.autoaccept.enable": "自動接受編輯",
+  "command.permissions.autoaccept.disable": "停止自動接受編輯",
+  "command.session.undo": "復原",
+  "command.session.undo.description": "復原上一則訊息",
+  "command.session.redo": "重做",
+  "command.session.redo.description": "重做上一則復原的訊息",
+  "command.session.compact": "精簡工作階段",
+  "command.session.compact.description": "總結工作階段以減少上下文大小",
+  "command.session.fork": "從訊息分支",
+  "command.session.fork.description": "從先前的訊息建立新工作階段",
+  "command.session.share": "分享工作階段",
+  "command.session.share.description": "分享此工作階段並將連結複製到剪貼簿",
+  "command.session.unshare": "取消分享工作階段",
+  "command.session.unshare.description": "停止分享此工作階段",
+
+  "palette.search.placeholder": "搜尋檔案和命令",
+  "palette.empty": "找不到結果",
+  "palette.group.commands": "命令",
+  "palette.group.files": "檔案",
+
+  "dialog.provider.search.placeholder": "搜尋提供者",
+  "dialog.provider.empty": "找不到提供者",
+  "dialog.provider.group.popular": "熱門",
+  "dialog.provider.group.other": "其他",
+  "dialog.provider.tag.recommended": "推薦",
+  "dialog.provider.anthropic.note": "使用 Claude Pro/Max 或 API 金鑰連線",
+
+  "dialog.model.select.title": "選擇模型",
+  "dialog.model.search.placeholder": "搜尋模型",
+  "dialog.model.empty": "找不到模型",
+  "dialog.model.manage": "管理模型",
+  "dialog.model.manage.description": "自訂模型選擇器中顯示的模型。",
+
+  "dialog.model.unpaid.freeModels.title": "OpenCode 提供的免費模型",
+  "dialog.model.unpaid.addMore.title": "從熱門提供者新增更多模型",
+
+  "dialog.provider.viewAll": "查看全部提供者",
+
+  "provider.connect.title": "連線 {{provider}}",
+  "provider.connect.title.anthropicProMax": "使用 Claude Pro/Max 登入",
+  "provider.connect.selectMethod": "選擇 {{provider}} 的登入方式。",
+  "provider.connect.method.apiKey": "API 金鑰",
+  "provider.connect.status.inProgress": "正在授權...",
+  "provider.connect.status.waiting": "等待授權...",
+  "provider.connect.status.failed": "授權失敗: {{error}}",
+  "provider.connect.apiKey.description":
+    "輸入你的 {{provider}} API 金鑰以連線帳戶,並在 OpenCode 中使用 {{provider}} 模型。",
+  "provider.connect.apiKey.label": "{{provider}} API 金鑰",
+  "provider.connect.apiKey.placeholder": "API 金鑰",
+  "provider.connect.apiKey.required": "API 金鑰為必填",
+  "provider.connect.opencodeZen.line1": "OpenCode Zen 為你提供一組精選的可靠最佳化模型,用於程式碼代理程式。",
+  "provider.connect.opencodeZen.line2": "只需一個 API 金鑰,你就能使用 Claude、GPT、Gemini、GLM 等模型。",
+  "provider.connect.opencodeZen.visit.prefix": "造訪 ",
+  "provider.connect.opencodeZen.visit.link": "opencode.ai/zen",
+  "provider.connect.opencodeZen.visit.suffix": " 取得你的 API 金鑰。",
+  "provider.connect.oauth.code.visit.prefix": "造訪 ",
+  "provider.connect.oauth.code.visit.link": "此連結",
+  "provider.connect.oauth.code.visit.suffix": " 取得授權碼,以連線你的帳戶並在 OpenCode 中使用 {{provider}} 模型。",
+  "provider.connect.oauth.code.label": "{{method}} 授權碼",
+  "provider.connect.oauth.code.placeholder": "授權碼",
+  "provider.connect.oauth.code.required": "授權碼為必填",
+  "provider.connect.oauth.code.invalid": "授權碼無效",
+  "provider.connect.oauth.auto.visit.prefix": "造訪 ",
+  "provider.connect.oauth.auto.visit.link": "此連結",
+  "provider.connect.oauth.auto.visit.suffix":
+    " 並輸入以下程式碼,以連線你的帳戶並在 OpenCode 中使用 {{provider}} 模型。",
+  "provider.connect.oauth.auto.confirmationCode": "確認碼",
+  "provider.connect.toast.connected.title": "{{provider}} 已連線",
+  "provider.connect.toast.connected.description": "現在可以使用 {{provider}} 模型了。",
+
+  "model.tag.free": "免費",
+  "model.tag.latest": "最新",
+
+  "common.search.placeholder": "搜尋",
+  "common.loading": "載入中",
+  "common.cancel": "取消",
+  "common.submit": "提交",
+  "common.save": "儲存",
+  "common.saving": "儲存中...",
+  "common.default": "預設",
+  "common.attachment": "附件",
+
+  "prompt.placeholder.shell": "輸入 shell 命令...",
+  "prompt.placeholder.normal": '隨便問點什麼... "{{example}}"',
+  "prompt.mode.shell": "Shell",
+  "prompt.mode.shell.exit": "按 esc 退出",
+
+  "prompt.example.1": "修復程式碼庫中的一個 TODO",
+  "prompt.example.2": "這個專案的技術堆疊是什麼?",
+  "prompt.example.3": "修復失敗的測試",
+  "prompt.example.4": "解釋驗證是如何運作的",
+  "prompt.example.5": "尋找並修復安全漏洞",
+  "prompt.example.6": "為使用者服務新增單元測試",
+  "prompt.example.7": "重構這個函式,讓它更易讀",
+  "prompt.example.8": "這個錯誤是什麼意思?",
+  "prompt.example.9": "幫我偵錯這個問題",
+  "prompt.example.10": "產生 API 文件",
+  "prompt.example.11": "最佳化資料庫查詢",
+  "prompt.example.12": "新增輸入驗證",
+  "prompt.example.13": "建立一個新的元件用於...",
+  "prompt.example.14": "我該如何部署這個專案?",
+  "prompt.example.15": "審查我的程式碼並給出最佳實務建議",
+  "prompt.example.16": "為這個函式新增錯誤處理",
+  "prompt.example.17": "解釋這個正規表示式",
+  "prompt.example.18": "把它轉換成 TypeScript",
+  "prompt.example.19": "在整個程式碼庫中新增日誌",
+  "prompt.example.20": "哪些相依性已經過期?",
+  "prompt.example.21": "幫我寫一個遷移腳本",
+  "prompt.example.22": "為這個端點實作快取",
+  "prompt.example.23": "給這個清單新增分頁",
+  "prompt.example.24": "建立一個 CLI 命令用於...",
+  "prompt.example.25": "這裡的環境變數是怎麼運作的?",
+
+  "prompt.popover.emptyResults": "沒有符合的結果",
+  "prompt.popover.emptyCommands": "沒有符合的命令",
+  "prompt.dropzone.label": "將圖片或 PDF 拖到這裡",
+  "prompt.slash.badge.custom": "自訂",
+  "prompt.context.active": "作用中",
+  "prompt.context.includeActiveFile": "包含作用中檔案",
+  "prompt.action.attachFile": "附加檔案",
+  "prompt.action.send": "傳送",
+  "prompt.action.stop": "停止",
+
+  "prompt.toast.pasteUnsupported.title": "不支援的貼上",
+  "prompt.toast.pasteUnsupported.description": "這裡只能貼上圖片或 PDF 檔案。",
+  "prompt.toast.modelAgentRequired.title": "請選擇代理程式和模型",
+  "prompt.toast.modelAgentRequired.description": "傳送提示前請先選擇代理程式和模型。",
+  "prompt.toast.worktreeCreateFailed.title": "建立工作樹失敗",
+  "prompt.toast.sessionCreateFailed.title": "建立工作階段失敗",
+  "prompt.toast.shellSendFailed.title": "傳送 shell 命令失敗",
+  "prompt.toast.commandSendFailed.title": "傳送命令失敗",
+  "prompt.toast.promptSendFailed.title": "傳送提示失敗",
+
+  "dialog.mcp.title": "MCP",
+  "dialog.mcp.description": "已啟用 {{enabled}} / {{total}}",
+  "dialog.mcp.empty": "未設定 MCP",
+
+  "mcp.status.connected": "已連線",
+  "mcp.status.failed": "失敗",
+  "mcp.status.needs_auth": "需要授權",
+  "mcp.status.disabled": "已停用",
+
+  "dialog.fork.empty": "沒有可用於分支的訊息",
+
+  "dialog.directory.search.placeholder": "搜尋資料夾",
+  "dialog.directory.empty": "找不到資料夾",
+
+  "dialog.server.title": "伺服器",
+  "dialog.server.description": "切換此應用程式連線的 OpenCode 伺服器。",
+  "dialog.server.search.placeholder": "搜尋伺服器",
+  "dialog.server.empty": "暫無伺服器",
+  "dialog.server.add.title": "新增伺服器",
+  "dialog.server.add.url": "伺服器 URL",
+  "dialog.server.add.placeholder": "http://localhost:4096",
+  "dialog.server.add.error": "無法連線到伺服器",
+  "dialog.server.add.checking": "檢查中...",
+  "dialog.server.add.button": "新增",
+  "dialog.server.default.title": "預設伺服器",
+  "dialog.server.default.description": "應用程式啟動時連線此伺服器,而不是啟動本地伺服器。需要重新啟動。",
+  "dialog.server.default.none": "未選擇伺服器",
+  "dialog.server.default.set": "將目前伺服器設為預設",
+  "dialog.server.default.clear": "清除",
+
+  "dialog.project.edit.title": "編輯專案",
+  "dialog.project.edit.name": "名稱",
+  "dialog.project.edit.icon": "圖示",
+  "dialog.project.edit.icon.alt": "專案圖示",
+  "dialog.project.edit.icon.hint": "點擊或拖曳圖片",
+  "dialog.project.edit.icon.recommended": "建議:128x128px",
+  "dialog.project.edit.color": "顏色",
+
+  "context.breakdown.title": "上下文拆分",
+  "context.breakdown.note": "輸入 token 的大致拆分。「其他」包含工具定義和額外開銷。",
+  "context.breakdown.system": "系統",
+  "context.breakdown.user": "使用者",
+  "context.breakdown.assistant": "助手",
+  "context.breakdown.tool": "工具呼叫",
+  "context.breakdown.other": "其他",
+
+  "context.systemPrompt.title": "系統提示詞",
+  "context.rawMessages.title": "原始訊息",
+
+  "context.stats.session": "工作階段",
+  "context.stats.messages": "訊息數",
+  "context.stats.provider": "提供者",
+  "context.stats.model": "模型",
+  "context.stats.limit": "上下文限制",
+  "context.stats.totalTokens": "總 token",
+  "context.stats.usage": "使用量",
+  "context.stats.inputTokens": "輸入 token",
+  "context.stats.outputTokens": "輸出 token",
+  "context.stats.reasoningTokens": "推理 token",
+  "context.stats.cacheTokens": "快取 token(讀/寫)",
+  "context.stats.userMessages": "使用者訊息",
+  "context.stats.assistantMessages": "助手訊息",
+  "context.stats.totalCost": "總成本",
+  "context.stats.sessionCreated": "建立時間",
+  "context.stats.lastActivity": "最後活動",
+
+  "context.usage.tokens": "Token",
+  "context.usage.usage": "使用量",
+  "context.usage.cost": "成本",
+  "context.usage.clickToView": "點擊查看上下文",
+
+  "language.en": "英語",
+  "language.zh": "簡體中文",
+  "language.zht": "繁體中文",
+  "language.ko": "韓語",
+
+  "toast.language.title": "語言",
+  "toast.language.description": "已切換到 {{language}}",
+
+  "toast.theme.title": "主題已切換",
+  "toast.scheme.title": "配色方案",
+
+  "toast.permissions.autoaccept.on.title": "自動接受編輯",
+  "toast.permissions.autoaccept.on.description": "編輯和寫入權限將自動獲准",
+  "toast.permissions.autoaccept.off.title": "已停止自動接受編輯",
+  "toast.permissions.autoaccept.off.description": "編輯和寫入權限將需要手動批准",
+
+  "toast.model.none.title": "未選擇模型",
+  "toast.model.none.description": "請先連線提供者以總結此工作階段",
+
+  "toast.file.loadFailed.title": "載入檔案失敗",
+
+  "toast.session.share.copyFailed.title": "無法複製連結到剪貼簿",
+  "toast.session.share.success.title": "工作階段已分享",
+  "toast.session.share.success.description": "分享連結已複製到剪貼簿",
+  "toast.session.share.failed.title": "分享工作階段失敗",
+  "toast.session.share.failed.description": "分享工作階段時發生錯誤",
+
+  "toast.session.unshare.success.title": "已取消分享工作階段",
+  "toast.session.unshare.success.description": "工作階段已成功取消分享",
+  "toast.session.unshare.failed.title": "取消分享失敗",
+  "toast.session.unshare.failed.description": "取消分享工作階段時發生錯誤",
+
+  "toast.session.listFailed.title": "無法載入 {{project}} 的工作階段",
+
+  "toast.update.title": "有可用更新",
+  "toast.update.description": "OpenCode 有新版本 ({{version}}) 可安裝。",
+  "toast.update.action.installRestart": "安裝並重新啟動",
+  "toast.update.action.notYet": "稍後",
+
+  "error.page.title": "出了點問題",
+  "error.page.description": "載入應用程式時發生錯誤。",
+  "error.page.details.label": "錯誤詳情",
+  "error.page.action.restart": "重新啟動",
+  "error.page.action.checking": "檢查中...",
+  "error.page.action.checkUpdates": "檢查更新",
+  "error.page.action.updateTo": "更新到 {{version}}",
+  "error.page.report.prefix": "請將此錯誤回報給 OpenCode 團隊",
+  "error.page.report.discord": "在 Discord 上",
+  "error.page.version": "版本: {{version}}",
+
+  "error.dev.rootNotFound": "找不到根元素。你是不是忘了把它新增到 index.html? 或者 id 屬性拼錯了?",
+
+  "error.globalSync.connectFailed": "無法連線到伺服器。是否有伺服器正在 `{{url}}` 執行?",
+
+  "error.chain.unknown": "未知錯誤",
+  "error.chain.causedBy": "原因:",
+  "error.chain.apiError": "API 錯誤",
+  "error.chain.status": "狀態: {{status}}",
+  "error.chain.retryable": "可重試: {{retryable}}",
+  "error.chain.responseBody": "回應內容:\n{{body}}",
+  "error.chain.didYouMean": "你是不是想輸入: {{suggestions}}",
+  "error.chain.modelNotFound": "找不到模型: {{provider}}/{{model}}",
+  "error.chain.checkConfig": "請檢查你的設定 (opencode.json) 中的 provider/model 名稱",
+  "error.chain.mcpFailed": 'MCP 伺服器 "{{name}}" 啟動失敗。注意: OpenCode 暫不支援 MCP 認證。',
+  "error.chain.providerAuthFailed": "提供者認證失敗 ({{provider}}): {{message}}",
+  "error.chain.providerInitFailed": '無法初始化提供者 "{{provider}}"。請檢查憑證和設定。',
+  "error.chain.configJsonInvalid": "設定檔 {{path}} 不是有效的 JSON(C)",
+  "error.chain.configJsonInvalidWithMessage": "設定檔 {{path}} 不是有效的 JSON(C): {{message}}",
+  "error.chain.configDirectoryTypo":
+    '{{path}} 中的目錄 "{{dir}}" 無效。請將目錄重新命名為 "{{suggestion}}" 或移除它。這是一個常見拼寫錯誤。',
+  "error.chain.configFrontmatterError": "無法解析 {{path}} 中的 frontmatter:\n{{message}}",
+  "error.chain.configInvalid": "設定檔 {{path}} 無效",
+  "error.chain.configInvalidWithMessage": "設定檔 {{path}} 無效: {{message}}",
+
+  "notification.permission.title": "需要權限",
+  "notification.permission.description": "{{sessionTitle}}({{projectName}})需要權限",
+  "notification.question.title": "問題",
+  "notification.question.description": "{{sessionTitle}}({{projectName}})有一個問題",
+  "notification.action.goToSession": "前往工作階段",
+
+  "notification.session.responseReady.title": "回覆已就緒",
+  "notification.session.error.title": "工作階段錯誤",
+  "notification.session.error.fallbackDescription": "發生錯誤",
+
+  "home.recentProjects": "最近專案",
+  "home.empty.title": "沒有最近專案",
+  "home.empty.description": "透過開啟本地專案開始使用",
+
+  "session.tab.session": "工作階段",
+  "session.tab.review": "審查",
+  "session.tab.context": "上下文",
+  "session.review.filesChanged": "{{count}} 個檔案變更",
+  "session.review.loadingChanges": "正在載入變更...",
+  "session.review.empty": "此工作階段暫無變更",
+  "session.messages.renderEarlier": "顯示更早的訊息",
+  "session.messages.loadingEarlier": "正在載入更早的訊息...",
+  "session.messages.loadEarlier": "載入更早的訊息",
+  "session.messages.loading": "正在載入訊息...",
+
+  "session.context.addToContext": "將 {{selection}} 新增到上下文",
+
+  "session.new.worktree.main": "主分支",
+  "session.new.worktree.mainWithBranch": "主分支 ({{branch}})",
+  "session.new.worktree.create": "建立新的 worktree",
+  "session.new.lastModified": "最後修改",
+
+  "session.header.search.placeholder": "搜尋 {{project}}",
+
+  "session.share.popover.title": "發佈到網頁",
+  "session.share.popover.description.shared": "此工作階段已在網頁上公開。任何擁有連結的人都可以存取。",
+  "session.share.popover.description.unshared": "在網頁上公開分享此工作階段。任何擁有連結的人都可以存取。",
+  "session.share.action.share": "分享",
+  "session.share.action.publish": "發佈",
+  "session.share.action.publishing": "正在發佈...",
+  "session.share.action.unpublish": "取消發佈",
+  "session.share.action.unpublishing": "正在取消發佈...",
+  "session.share.action.view": "檢視",
+  "session.share.copy.copied": "已複製",
+  "session.share.copy.copyLink": "複製連結",
+
+  "lsp.tooltip.none": "沒有 LSP 伺服器",
+  "lsp.label.connected": "{{count}} LSP",
+
+  "prompt.loading": "正在載入提示...",
+  "terminal.loading": "正在載入終端機...",
+  "terminal.title": "終端機",
+  "terminal.title.numbered": "終端機 {{number}}",
+
+  "common.closeTab": "關閉標籤頁",
+  "common.dismiss": "忽略",
+  "common.requestFailed": "要求失敗",
+  "common.moreOptions": "更多選項",
+  "common.learnMore": "深入了解",
+  "common.rename": "重新命名",
+  "common.reset": "重設",
+  "common.delete": "刪除",
+  "common.close": "關閉",
+  "common.edit": "編輯",
+  "common.loadMore": "載入更多",
+
+  "sidebar.settings": "設定",
+  "sidebar.help": "說明",
+  "sidebar.workspaces.enable": "啟用工作區",
+  "sidebar.workspaces.disable": "停用工作區",
+  "sidebar.gettingStarted.title": "開始使用",
+  "sidebar.gettingStarted.line1": "OpenCode 提供免費模型,你可以立即開始使用。",
+  "sidebar.gettingStarted.line2": "連線任意提供者即可使用更多模型,如 Claude、GPT、Gemini 等。",
+  "sidebar.project.recentSessions": "最近工作階段",
+  "sidebar.project.viewAllSessions": "查看全部工作階段",
+
+  "settings.section.desktop": "桌面",
+  "settings.tab.general": "一般",
+  "settings.tab.shortcuts": "快速鍵",
+
+  "settings.general.section.appearance": "外觀",
+  "settings.general.section.notifications": "系統通知",
+  "settings.general.section.sounds": "音效",
+
+  "settings.general.row.language.title": "語言",
+  "settings.general.row.language.description": "變更 OpenCode 的顯示語言",
+  "settings.general.row.appearance.title": "外觀",
+  "settings.general.row.appearance.description": "自訂 OpenCode 在你的裝置上的外觀",
+  "settings.general.row.theme.title": "主題",
+  "settings.general.row.theme.description": "自訂 OpenCode 的主題。",
+  "settings.general.row.font.title": "字型",
+  "settings.general.row.font.description": "自訂程式碼區塊使用的等寬字型",
+
+  "settings.general.notifications.agent.title": "代理程式",
+  "settings.general.notifications.agent.description": "當代理程式完成或需要注意時顯示系統通知",
+  "settings.general.notifications.permissions.title": "權限",
+  "settings.general.notifications.permissions.description": "當需要權限時顯示系統通知",
+  "settings.general.notifications.errors.title": "錯誤",
+  "settings.general.notifications.errors.description": "發生錯誤時顯示系統通知",
+
+  "settings.general.sounds.agent.title": "代理程式",
+  "settings.general.sounds.agent.description": "當代理程式完成或需要注意時播放聲音",
+  "settings.general.sounds.permissions.title": "權限",
+  "settings.general.sounds.permissions.description": "當需要權限時播放聲音",
+  "settings.general.sounds.errors.title": "錯誤",
+  "settings.general.sounds.errors.description": "發生錯誤時播放聲音",
+
+  "settings.shortcuts.title": "鍵盤快速鍵",
+  "settings.shortcuts.reset.button": "重設為預設值",
+  "settings.shortcuts.reset.toast.title": "快速鍵已重設",
+  "settings.shortcuts.reset.toast.description": "鍵盤快速鍵已重設為預設設定。",
+  "settings.shortcuts.conflict.title": "快速鍵已被占用",
+  "settings.shortcuts.conflict.description": "{{keybind}} 已分配給 {{titles}}。",
+  "settings.shortcuts.unassigned": "未設定",
+  "settings.shortcuts.pressKeys": "按下按鍵",
+  "settings.shortcuts.search.placeholder": "搜尋快速鍵",
+  "settings.shortcuts.search.empty": "找不到快速鍵",
+
+  "settings.shortcuts.group.general": "一般",
+  "settings.shortcuts.group.session": "工作階段",
+  "settings.shortcuts.group.navigation": "導覽",
+  "settings.shortcuts.group.modelAndAgent": "模型與代理程式",
+  "settings.shortcuts.group.terminal": "終端機",
+  "settings.shortcuts.group.prompt": "提示",
+
+  "settings.providers.title": "提供者",
+  "settings.providers.description": "提供者設定將在此處可設定。",
+  "settings.models.title": "模型",
+  "settings.models.description": "模型設定將在此處可設定。",
+  "settings.agents.title": "代理程式",
+  "settings.agents.description": "代理程式設定將在此處可設定。",
+  "settings.commands.title": "命令",
+  "settings.commands.description": "命令設定將在此處可設定。",
+  "settings.mcp.title": "MCP",
+  "settings.mcp.description": "MCP 設定將在此處可設定。",
+
+  "settings.permissions.title": "權限",
+  "settings.permissions.description": "控制伺服器預設可以使用哪些工具。",
+  "settings.permissions.section.tools": "工具",
+  "settings.permissions.toast.updateFailed.title": "更新權限失敗",
+
+  "settings.permissions.action.allow": "允許",
+  "settings.permissions.action.ask": "詢問",
+  "settings.permissions.action.deny": "拒絕",
+
+  "settings.permissions.tool.read.title": "讀取",
+  "settings.permissions.tool.read.description": "讀取檔案(符合檔案路徑)",
+  "settings.permissions.tool.edit.title": "編輯",
+  "settings.permissions.tool.edit.description": "修改檔案,包括編輯、寫入、修補和多重編輯",
+  "settings.permissions.tool.glob.title": "Glob",
+  "settings.permissions.tool.glob.description": "使用 glob 模式符合檔案",
+  "settings.permissions.tool.grep.title": "Grep",
+  "settings.permissions.tool.grep.description": "使用正規表示式搜尋檔案內容",
+  "settings.permissions.tool.list.title": "清單",
+  "settings.permissions.tool.list.description": "列出目錄中的檔案",
+  "settings.permissions.tool.bash.title": "Bash",
+  "settings.permissions.tool.bash.description": "執行 shell 命令",
+  "settings.permissions.tool.task.title": "Task",
+  "settings.permissions.tool.task.description": "啟動子代理程式",
+  "settings.permissions.tool.skill.title": "Skill",
+  "settings.permissions.tool.skill.description": "按名稱載入技能",
+  "settings.permissions.tool.lsp.title": "LSP",
+  "settings.permissions.tool.lsp.description": "執行語言伺服器查詢",
+  "settings.permissions.tool.todoread.title": "讀取待辦",
+  "settings.permissions.tool.todoread.description": "讀取待辦清單",
+  "settings.permissions.tool.todowrite.title": "更新待辦",
+  "settings.permissions.tool.todowrite.description": "更新待辦清單",
+  "settings.permissions.tool.webfetch.title": "Web Fetch",
+  "settings.permissions.tool.webfetch.description": "從 URL 取得內容",
+  "settings.permissions.tool.websearch.title": "Web Search",
+  "settings.permissions.tool.websearch.description": "搜尋網頁",
+  "settings.permissions.tool.codesearch.title": "Code Search",
+  "settings.permissions.tool.codesearch.description": "在網路上搜尋程式碼",
+  "settings.permissions.tool.external_directory.title": "外部目錄",
+  "settings.permissions.tool.external_directory.description": "存取專案目錄之外的檔案",
+  "settings.permissions.tool.doom_loop.title": "Doom Loop",
+  "settings.permissions.tool.doom_loop.description": "偵測具有相同輸入的重複工具呼叫",
+
+  "workspace.new": "新增工作區",
+  "workspace.type.local": "本地",
+  "workspace.type.sandbox": "沙盒",
+  "workspace.create.failed.title": "建立工作區失敗",
+  "workspace.delete.failed.title": "刪除工作區失敗",
+  "workspace.resetting.title": "正在重設工作區",
+  "workspace.resetting.description": "這可能需要一點時間。",
+  "workspace.reset.failed.title": "重設工作區失敗",
+  "workspace.reset.success.title": "工作區已重設",
+  "workspace.reset.success.description": "工作區已與預設分支保持一致。",
+  "workspace.status.checking": "正在檢查未合併的變更...",
+  "workspace.status.error": "無法驗證 git 狀態。",
+  "workspace.status.clean": "未偵測到未合併的變更。",
+  "workspace.status.dirty": "偵測到未合併的變更。",
+  "workspace.delete.title": "刪除工作區",
+  "workspace.delete.confirm": '刪除工作區 "{{name}}"?',
+  "workspace.delete.button": "刪除工作區",
+  "workspace.reset.title": "重設工作區",
+  "workspace.reset.confirm": '重設工作區 "{{name}}"?',
+  "workspace.reset.button": "重設工作區",
+  "workspace.reset.archived.none": "不會封存任何作用中工作階段。",
+  "workspace.reset.archived.one": "將封存 1 個工作階段。",
+  "workspace.reset.archived.many": "將封存 {{count}} 個工作階段。",
+  "workspace.reset.note": "這將把工作區重設為與預設分支一致。",
+} satisfies Partial<Record<Keys, string>>

+ 94 - 0
packages/ui/src/i18n/zht.ts

@@ -0,0 +1,94 @@
+import { dict as en } from "./en"
+
+type Keys = keyof typeof en
+
+export const dict = {
+  "ui.sessionReview.title": "工作階段變更",
+  "ui.sessionReview.diffStyle.unified": "整合",
+  "ui.sessionReview.diffStyle.split": "拆分",
+  "ui.sessionReview.expandAll": "全部展開",
+  "ui.sessionReview.collapseAll": "全部收合",
+
+  "ui.sessionTurn.steps.show": "顯示步驟",
+  "ui.sessionTurn.steps.hide": "隱藏步驟",
+  "ui.sessionTurn.summary.response": "回覆",
+  "ui.sessionTurn.diff.showMore": "顯示更多變更 ({{count}})",
+
+  "ui.sessionTurn.retry.retrying": "重試中",
+  "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒後",
+
+  "ui.sessionTurn.status.delegating": "正在委派工作",
+  "ui.sessionTurn.status.planning": "正在規劃下一步",
+  "ui.sessionTurn.status.gatheringContext": "正在收集上下文",
+  "ui.sessionTurn.status.searchingCodebase": "正在搜尋程式碼庫",
+  "ui.sessionTurn.status.searchingWeb": "正在搜尋網頁",
+  "ui.sessionTurn.status.makingEdits": "正在修改",
+  "ui.sessionTurn.status.runningCommands": "正在執行命令",
+  "ui.sessionTurn.status.thinking": "思考中",
+  "ui.sessionTurn.status.thinkingWithTopic": "思考 - {{topic}}",
+  "ui.sessionTurn.status.gatheringThoughts": "正在整理思緒",
+  "ui.sessionTurn.status.consideringNextSteps": "正在考慮下一步",
+
+  "ui.messagePart.diagnostic.error": "錯誤",
+  "ui.messagePart.title.edit": "編輯",
+  "ui.messagePart.title.write": "寫入",
+  "ui.messagePart.option.typeOwnAnswer": "輸入自己的答案",
+  "ui.messagePart.review.title": "檢查你的答案",
+
+  "ui.list.loading": "載入中",
+  "ui.list.empty": "無結果",
+  "ui.list.emptyWithFilter.prefix": "沒有關於",
+  "ui.list.emptyWithFilter.suffix": "的結果",
+
+  "ui.messageNav.newMessage": "新訊息",
+
+  "ui.textField.copyToClipboard": "複製到剪貼簿",
+  "ui.textField.copied": "已複製",
+
+  "ui.imagePreview.alt": "圖片預覽",
+
+  "ui.tool.read": "讀取",
+  "ui.tool.list": "清單",
+  "ui.tool.glob": "Glob",
+  "ui.tool.grep": "Grep",
+  "ui.tool.webfetch": "Webfetch",
+  "ui.tool.shell": "Shell",
+  "ui.tool.patch": "修補",
+  "ui.tool.todos": "待辦",
+  "ui.tool.todos.read": "讀取待辦",
+  "ui.tool.questions": "問題",
+  "ui.tool.agent": "{{type}} 代理程式",
+
+  "ui.common.file.one": "個檔案",
+  "ui.common.file.other": "個檔案",
+  "ui.common.question.one": "個問題",
+  "ui.common.question.other": "個問題",
+
+  "ui.common.add": "新增",
+  "ui.common.cancel": "取消",
+  "ui.common.confirm": "確認",
+  "ui.common.dismiss": "忽略",
+  "ui.common.next": "下一步",
+  "ui.common.submit": "提交",
+
+  "ui.permission.deny": "拒絕",
+  "ui.permission.allowAlways": "永遠允許",
+  "ui.permission.allowOnce": "允許一次",
+
+  "ui.message.expand": "展開訊息",
+  "ui.message.collapse": "收合訊息",
+  "ui.message.copy": "複製",
+  "ui.message.copied": "已複製",
+  "ui.message.attachment.alt": "附件",
+
+  "ui.patch.action.deleted": "已刪除",
+  "ui.patch.action.created": "已建立",
+  "ui.patch.action.moved": "已移動",
+  "ui.patch.action.patched": "已套用修補",
+
+  "ui.question.subtitle.answered": "{{count}} 已回答",
+  "ui.question.answer.none": "(無答案)",
+  "ui.question.review.notAnswered": "(未回答)",
+  "ui.question.multiHint": "(可多選)",
+  "ui.question.custom.placeholder": "輸入你的答案...",
+} satisfies Partial<Record<Keys, string>>