fix(i18n): Correct zh-TW translations to match Traditional Chinese conventions (#4129)

* fix(i18n): Correct zh-TW translations to match Traditional Chinese conventions

Fix ~131 lines of Traditional Chinese (zh-TW) translations that used
Simplified Chinese character forms instead of standard Traditional
Chinese usage.

Changes:
- 文件 → 檔案 (47 occurrences)
- 爲 → 為 (45 occurrences)
- 啓 → 啟 (44 occurrences)
- 曆史 → 歷史 (6 occurrences)
- 鏈接 → 連結 (4 occurrences)
- 菜單 → 選單 (3 occurrences)

* fix(i18n): Replace 服務器 with 伺服器 (15 occurrences)

Align with Traditional Chinese convention where 伺服器 is the standard
term for 'server' in computing contexts.

* fix(i18n): Update zh-TW.js header comment to prevent accidental overwrite

Clarify that the file is the authoritative source and should not be
overwritten with auto-generated output, to prevent future maintainers
from regenerating with raw OpenCC and losing manual corrections.

* fix(i18n): Add zh-TW regression check and maintenance docs

Addresses reviewer feedback on PR #4129 (points 2 and 3):

- scripts/check-i18n.ts: Iterate over parsed zh-TW translation values
  (not raw file content) and report the offending key. Replace the
  earlier substring list with ZH_TW_FORBIDDEN_PATTERNS, which targets
  the three real regression categories: variant Traditional characters
  produced by OpenCC s2t (爲, 啓), Mainland-Chinese vocabulary (服務器,
  菜單, 鏈接), and pure Simplified characters. Excludes 禁用 / 配置 /
  文件 / 打開 to avoid false positives on Taiwan-valid usage.
- scripts/tests/check-i18n.test.ts: Cover the new check, including
  negative cases for Taiwan-valid vocabulary.
- docs/users/features/language.md: Document zh-TW maintenance — the
  vocabulary table, why raw OpenCC s2t output is not acceptable, and
  where the CI-enforced list lives.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(i18n): Address review feedback on zh-TW check (#4129)

- check-i18n.ts: Sort ZH_TW_FORBIDDEN_PATTERNS longest-first and break
  on first match so e.g. `历史` reports the specific bigram instead of
  also firing the bare `历` rule (no duplicate CI errors).
- check-i18n.ts: Add ZH_TW_ALLOWED_EXCEPTIONS escape hatch so a future
  legitimate translation (e.g. 區塊鏈 in a UI string) can opt out by key
  without weakening the global pattern list.
- docs/users/features/language.md: Add a "CI enforced?" column so
  contributors can tell which rows block CI vs. which are review-only
  style guidance. Replace bare `曆` in the table with the `曆史` bigram
  and note that `曆` is correct in calendar terms (日曆, 農曆, 西曆) —
  prevents a future maintainer from globally replacing 曆→歷.
- Tests: Cover the dedup behavior on overlapping patterns.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(i18n): Note word-boundary limitation of zh-TW substring check

Document the known limitation that `includes()`-based pattern matching
does not respect Chinese word boundaries — a bigram like `鏈接` will
false-positive on `區塊鏈接口` (區塊鏈 + 接口). Direct contributors to
`ZH_TW_ALLOWED_EXCEPTIONS` when this happens instead of weakening the
pattern list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
MikeWang0316tw 2026-05-15 15:26:12 +08:00 committed by GitHub
parent 7c2b51d28e
commit 02a65f90c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 370 additions and 147 deletions

View file

@ -145,6 +145,29 @@ User directory takes precedence over built-in translations.
> Contributions are welcome! If youd like to improve built-in translations or add new languages.
> For a concrete example, see [PR #1238: feat(i18n): add Russian language support](https://github.com/QwenLM/qwen-code/pull/1238).
### Maintaining `zh-TW` (Traditional Chinese for Taiwan)
`zh-TW` is **not** an automatic OpenCC s2t conversion of `zh.js` — it is a hand-maintained Taiwan-vocabulary translation. When adding or updating keys, please follow the conventions below.
The "CI enforced?" column indicates whether `npm run check-i18n` will fail the build on a violation. Rows marked **No** are style guidance enforced by review only — typically because the offending form has a legitimate non-UI meaning (`文件` can mean "document", `打開` is colloquially fine in Taiwan).
| Avoid | Use instead | CI enforced? | Reason |
| --------------------- | --------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 文件 (file) | 檔案 | No | Taiwan term for filesystem files (but `文件` can legitimately mean "document") |
| 服務器 / 服务器 | 伺服器 | Yes | Taiwan term for "server" |
| 菜單 / 菜单 | 選單 | Yes | Taiwan term for "menu" |
| 鏈接 / 链接 | 連結 | Yes | Taiwan term for "link" (bare `鏈` is fine — e.g. 區塊鏈) |
| 打開 | 開啟 | No | Taiwan-preferred verb for "open" (UI); `打開` is colloquially common |
| 爲 / 啓 / 曆史 / 鏈接 | 為 / 啟 / 歷史 / 連結 | Yes | Variant Traditional forms from raw OpenCC s2t. Note: `曆` is context-dependent and correct in calendar terms (日曆, 農曆, 西曆); CI only flags the bigram `曆史`, not bare `曆`. |
If you are not a Traditional Chinese speaker and need to bootstrap a value, **do not paste raw OpenCC `s2t` output**: the default s2t profile emits variant Traditional characters (e.g. 爲, 啓) that Taiwan does not use, and never rewrites Mainland-Chinese vocabulary (服務器, 菜單). Prefer `s2twp.json` (Simplified → Taiwan with phrase mapping) as a starting point and then ask a Taiwan-Chinese speaker to review.
The `check-i18n` script (run in CI via `npm run check-i18n`) will fail the build if any of the CI-enforced substrings above end up in a `zh-TW` value. See `scripts/check-i18n.ts → ZH_TW_FORBIDDEN_PATTERNS` for the full list. If a translation legitimately needs to contain a CI-forbidden substring, add its key to `ZH_TW_ALLOWED_EXCEPTIONS` in the same file with a brief justification.
> [!note]
>
> The check uses plain substring matching, which does not understand Chinese word boundaries. A bigram pattern can therefore false-positive across compound-word boundaries — for example, `區塊鏈接口` (= `區塊鏈` + `接口`) contains the substring `鏈接` even though neither word is incorrect. If you hit a surprising CI failure of this kind, add the translation key to `ZH_TW_ALLOWED_EXCEPTIONS` rather than removing the pattern.
### Language Pack Format
```javascript

View file

@ -5,7 +5,9 @@
*/
// Traditional Chinese (zh-TW) translations for Qwen Code CLI
// Auto-generated: structure from en.js, values from zh-TW (manual) or opencc(zh.js s2t)
// Bootstrapped from en.js structure with opencc(zh.js s2t),
// then extensively hand-corrected for Taiwan vocabulary conventions.
// This file is the authoritative source — do not overwrite with auto-generated output.
export default {
'↑ to manage attachments': '↑ 管理附件',
'← → select, Delete to remove, ↓ to exit': '← → 選擇Delete 刪除,↓ 退出',
@ -13,7 +15,7 @@ export default {
'Basics:': '基礎功能:',
'Add context': '添加上下文',
'Use {{symbol}} to specify files for context (e.g., {{example}}) to target specific files or folders.':
'使用 {{symbol}} 指定文件作爲上下文(例如,{{example}}),用於定位特定文件或文件夾',
'使用 {{symbol}} 指定檔案作為上下文(例如,{{example}}),用於定位特定檔案或檔案夾',
'@': '@',
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Shell 模式',
@ -30,18 +32,18 @@ export default {
'Commands:': '命令:',
'shell command': 'shell 命令',
'Model Context Protocol command (from external servers)':
'Model Context Protocol 命令(來自外部器)',
'Model Context Protocol 命令(來自外部服器)',
'Keyboard Shortcuts:': '鍵盤快捷鍵:',
'Toggle this help display': '切換此幫助顯示',
'Toggle shell mode': '切換命令行模式',
'Open command menu': '打開命令單',
'Add file context': '添加文件上下文',
'Open command menu': '打開命令單',
'Add file context': '添加檔案上下文',
'Accept suggestion / Autocomplete': '接受建議 / 自動補全',
'Reverse search history': '反向搜索歷史',
'Press ? again to close': '再次按 ? 關閉',
'for shell mode': '命令行模式',
'for commands': '命令單',
'for file paths': '文件路徑',
'for commands': '命令單',
'for file paths': '檔案路徑',
'to clear input': '清空輸入',
'to cycle approvals': '切換審批模式',
'to quit': '退出',
@ -63,7 +65,7 @@ export default {
'Initializing...': '正在初始化...',
'Connecting to MCP servers... ({{connected}}/{{total}})':
'正在連接到 MCP servers... ({{connected}}/{{total}})',
'Type your message or @path/to/file': '輸入您的消息或 @ 文件路徑',
'Type your message or @path/to/file': '輸入您的消息或 @ 檔案路徑',
'? for shortcuts': '按 ? 查看快捷鍵',
"Press 'i' for INSERT mode and 'Esc' for NORMAL mode.":
"按 'i' 進入插入模式,按 'Esc' 進入普通模式",
@ -91,7 +93,7 @@ export default {
'Memory Usage': '內存使用',
'IDE Client': 'IDE 客戶端',
'Analyzes the project and creates a tailored QWEN.md file.':
'分析項目並創建定製的 QWEN.md 文件',
'分析項目並創建定製的 QWEN.md 檔案',
'List available Qwen Code tools. Usage: /tools [desc]':
'列出可用的 Qwen Code 工具。用法:/tools [desc]',
'List available skills.': '列出可用技能。',
@ -101,7 +103,7 @@ export default {
'查看或更改工具使用的審批模式',
'Invalid approval mode "{{arg}}". Valid modes: {{modes}}':
'無效的審批模式 "{{arg}}"。有效模式:{{modes}}',
'Approval mode set to "{{mode}}"': '審批模式已設置 "{{mode}}"',
'Approval mode set to "{{mode}}"': '審批模式已設置 "{{mode}}"',
'View or change the language setting': '查看或更改語言設置',
'List background tasks (text dump — interactive dialog opens via the footer pill)':
'列出背景任務(文字列表;互動式對話框可透過頁腳中的「背景任務」入口開啟)',
@ -192,7 +194,7 @@ export default {
'Delete Agent': '刪除智能體',
Back: '返回',
'No agent selected': '未選擇智能體',
'File Path: ': '文件路徑: ',
'File Path: ': '檔案路徑: ',
'Tools: ': '工具: ',
'Color: ': '顏色: ',
'Description:': '描述:',
@ -226,7 +228,7 @@ export default {
'Generate with Qwen Code (Recommended)': '使用 Qwen Code 生成(推薦)',
'Manual Creation': '手動創建',
'Describe what this subagent should do and when it should be used. (Be comprehensive for best results)':
'描述此子智能體應該做什麼以及何時使用它。(了獲得最佳效果,請全面描述)',
'描述此子智能體應該做什麼以及何時使用它。(了獲得最佳效果,請全面描述)',
'e.g., Expert code reviewer that reviews code based on best practices...':
'例如:專業的代碼審查員,根據最佳實踐審查代碼...',
'Generating subagent configuration...': '正在生成子智能體配置...',
@ -257,20 +259,20 @@ export default {
'go back': '返回',
'↑↓ to navigate, ': '↑↓ 導航,',
'Enter a clear, unique name for this subagent.':
'此子智能體輸入一個清晰、唯一的名稱。',
'此子智能體輸入一個清晰、唯一的名稱。',
'e.g., Code Reviewer': '例如:代碼審查員',
'Name cannot be empty.': '名稱不能空。',
'Name cannot be empty.': '名稱不能空。',
"Write the system prompt that defines this subagent's behavior. Be comprehensive for best results.":
'編寫定義此子智能體行爲的系統提示。爲了獲得最佳效果,請全面描述。',
'編寫定義此子智能體行為的系統提示。為了獲得最佳效果,請全面描述。',
'e.g., You are an expert code reviewer...':
'例如:您是一位專業的代碼審查員...',
'System prompt cannot be empty.': '系統提示不能空。',
'System prompt cannot be empty.': '系統提示不能空。',
'Describe when and how this subagent should be used.':
'描述何時以及如何使用此子智能體。',
'e.g., Reviews code for best practices and potential bugs.':
'例如:審查代碼以查找最佳實踐和潛在錯誤。',
'Description cannot be empty.': '描述不能空。',
'Failed to launch editor: {{error}}': '動編輯器失敗: {{error}}',
'Description cannot be empty.': '描述不能空。',
'Failed to launch editor: {{error}}': '動編輯器失敗: {{error}}',
'Failed to save and edit subagent: {{error}}':
'保存並編輯子智能體失敗: {{error}}',
'Manage Extensions': '管理擴展',
@ -278,7 +280,7 @@ export default {
'View Extension': '查看擴展',
'Update Extension': '更新擴展',
'Disable Extension': '禁用擴展',
'Enable Extension': '用擴展',
'Enable Extension': '用擴展',
'Uninstall Extension': '卸載擴展',
'Select Scope': '選擇作用域',
'User Scope': '用戶作用域',
@ -297,9 +299,9 @@ export default {
'Name:': '名稱:',
'MCP Servers:': 'MCP Servers',
'Settings:': '設置:',
active: '已用',
active: '已用',
disabled: '已禁用',
enabled: '已用',
enabled: '已用',
'View Details': '查看詳情',
'Update failed:': '更新失敗:',
'Updating {{name}}...': '正在更新 {{name}}...',
@ -307,7 +309,7 @@ export default {
'User (global)': '用戶(全局)',
'Workspace (project-specific)': '工作區(項目特定)',
'Disable "{{name}}" - Select Scope': '禁用 "{{name}}" - 選擇作用域',
'Enable "{{name}}" - Select Scope': '用 "{{name}}" - 選擇作用域',
'Enable "{{name}}" - Select Scope': '用 "{{name}}" - 選擇作用域',
'No extension selected': '未選擇擴展',
'{{count}} extensions installed': '已安裝 {{count}} 個擴展',
"Use '/extensions install' to install your first extension.":
@ -320,11 +322,11 @@ export default {
'View and edit Qwen Code settings': '查看和編輯 Qwen Code 設置',
Settings: '設置',
'To see changes, Qwen Code must be restarted. Press r to exit and apply changes now.':
'要查看更改,必須重 Qwen Code。按 r 退出並立即應用更改。',
'要查看更改,必須重 Qwen Code。按 r 退出並立即應用更改。',
'Vim Mode': 'Vim 模式',
'Attribution: commit': '署名:提交',
'Terminal Bell Notification': '終端響鈴通知',
'Enable Usage Statistics': '用使用統計',
'Enable Usage Statistics': '用使用統計',
Theme: '主題',
'Preferred Editor': '首選編輯器',
'Auto-connect to IDE': '自動連接到 IDE',
@ -339,7 +341,7 @@ export default {
'Show Citations': '顯示引用',
'Custom Witty Phrases': '自定義詼諧短語',
'Show Welcome Back Dialog': '顯示歡迎回來對話框',
'Enable User Feedback': '用用戶反饋',
'Enable User Feedback': '用用戶反饋',
'How is Qwen doing this session? (optional)': 'Qwen 這次表現如何?(可選)',
Bad: '不滿意',
Fine: '還行',
@ -349,15 +351,15 @@ export default {
'Max Session Turns': '最大會話輪次',
'Skip Next Speaker Check': '跳過下一個說話者檢查',
'Skip Loop Detection': '跳過循環檢測',
'Skip Startup Context': '跳過動上下文',
'Enable OpenAI Logging': '用 OpenAI 日誌',
'Skip Startup Context': '跳過動上下文',
'Enable OpenAI Logging': '用 OpenAI 日誌',
'OpenAI Logging Directory': 'OpenAI 日誌目錄',
Timeout: '超時',
'Max Retries': '最大重試次數',
'Load Memory From Include Directories': '從包含目錄加載內存',
'Respect .gitignore': '遵守 .gitignore',
'Respect .qwenignore': '遵守 .qwenignore',
'Enable Recursive File Search': '啓用遞歸文件搜索',
'Enable Recursive File Search': '啟用遞歸檔案搜索',
'Interactive Shell (PTY)': '交互式 Shell (PTY)',
'Show Color': '顯示顏色',
'Auto Accept': '自動接受',
@ -365,7 +367,7 @@ export default {
'Use Builtin Ripgrep': '使用內置 Ripgrep',
'Tool Output Truncation Threshold': '工具輸出截斷閾值',
'Tool Output Truncation Lines': '工具輸出截斷行數',
'Folder Trust': '文件夾信任',
'Folder Trust': '檔案夾信任',
'Tool Schema Compliance': 'Tool Schema 兼容性',
'Auto (detect from system)': '自動(從系統檢測)',
'Auto (detect terminal theme)': '自動(檢測終端主題)',
@ -395,7 +397,7 @@ export default {
'Manage extensions': '管理擴展',
'Manage installed extensions': '管理已安裝的擴展',
'Disable an extension': '禁用擴展',
'Enable an extension': '用擴展',
'Enable an extension': '用擴展',
'Install an extension from a git repo or local path':
'從 Git 倉庫或本地路徑安裝擴展',
'Uninstall an extension': '卸載擴展',
@ -412,7 +414,7 @@ export default {
'Do you want to continue?': '是否繼續?',
'Installing extension "{{name}}".': '正在安裝擴展 "{{name}}"。',
'**Extensions may introduce unexpected behavior. Ensure you have investigated the extension source and trust the author.**':
'**擴展可能會引入意外行。請確保您已調查過擴展源並信任作者。**',
'**擴展可能會引入意外行。請確保您已調查過擴展源並信任作者。**',
'This extension will run the following MCP servers:':
'此擴展將運行以下 MCP servers',
local: '本地',
@ -430,12 +432,12 @@ export default {
'--ref and --auto-update are not applicable for marketplace extensions.':
'--ref 和 --auto-update 不適用於市場擴展。',
'Extension "{{name}}" installed successfully and enabled.':
'擴展 "{{name}}" 安裝成功並已用。',
'擴展 "{{name}}" 安裝成功並已用。',
'The github URL, local path, or marketplace source (marketplace-url:plugin-name) of the extension to install.':
'要安裝的擴展的 GitHub URL、本地路徑或市場源marketplace-url:plugin-name。',
'The git ref to install from.': '要安裝的 Git 引用。',
'Enable auto-update for this extension.': '爲此擴展啓用自動更新。',
'Enable pre-release versions for this extension.': '爲此擴展啓用預發佈版本。',
'Enable auto-update for this extension.': '為此擴展啟用自動更新。',
'Enable pre-release versions for this extension.': '為此擴展啟用預發佈版本。',
'Acknowledge the security risks of installing an extension and skip the confirmation prompt.':
'確認安裝擴展的安全風險並跳過確認提示。',
'The source argument must be provided.': '必須提供來源參數。',
@ -445,15 +447,15 @@ export default {
'The name or source path of the extension to uninstall.':
'要卸載的擴展的名稱或源路徑。',
'Please include the name of the extension to uninstall as a positional argument.':
'請將要卸載的擴展名稱作位置參數。',
'Enables an extension.': '用擴展。',
'The name of the extension to enable.': '要用的擴展名稱。',
'請將要卸載的擴展名稱作位置參數。',
'Enables an extension.': '用擴展。',
'The name of the extension to enable.': '要用的擴展名稱。',
'The scope to enable the extenison in. If not set, will be enabled in all scopes.':
'啓用擴展的作用域。如果未設置,將在所有作用域中啓用。',
'啟用擴展的作用域。如果未設置,將在所有作用域中啟用。',
'Extension "{{name}}" successfully enabled for scope "{{scope}}".':
'擴展 "{{name}}" 已在作用域 "{{scope}}" 中用。',
'擴展 "{{name}}" 已在作用域 "{{scope}}" 中用。',
'Extension "{{name}}" successfully enabled in all scopes.':
'擴展 "{{name}}" 已在所有作用域中用。',
'擴展 "{{name}}" 已在所有作用域中用。',
'Invalid scope: {{scope}}. Please use one of {{scopes}}.':
'無效的作用域:{{scope}}。請使用 {{scopes}} 之一。',
'Disables an extension.': '禁用擴展。',
@ -479,19 +481,19 @@ export default {
'Type:': '類型:',
'Ref:': '引用:',
'Release tag:': '發佈標籤:',
'Enabled (User):': '已用(用戶):',
'Enabled (Workspace):': '已用(工作區):',
'Context files:': '上下文文件',
'Enabled (User):': '已用(用戶):',
'Enabled (Workspace):': '已用(工作區):',
'Context files:': '上下文檔案',
'Skills:': '技能:',
'Agents:': '智能體:',
'MCP servers:': 'MCP servers',
'Link extension failed to install.': '鏈接擴展安裝失敗。',
'Link extension failed to install.': '連結擴展安裝失敗。',
'Extension "{{name}}" linked successfully and enabled.':
'擴展 "{{name}}" 鏈接成功並已啓用。',
'擴展 "{{name}}" 連結成功並已啟用。',
'Links an extension from a local path. Updates made to the local path will always be reflected.':
'從本地路徑鏈接擴展。對本地路徑的更新將始終反映。',
'The name of the extension to link.': '要鏈接的擴展名稱。',
'Set a specific setting for an extension.': '擴展設置特定配置。',
'從本地路徑連結擴展。對本地路徑的更新將始終反映。',
'The name of the extension to link.': '要連結的擴展名稱。',
'Set a specific setting for an extension.': '擴展設置特定配置。',
'Name of the extension to configure.': '要配置的擴展名稱。',
'The setting to configure (name or env var).':
'要配置的設置(名稱或環境變量)。',
@ -522,7 +524,7 @@ export default {
'check status of IDE integration': '檢查 IDE 集成狀態',
'install required IDE companion for {{ideName}}':
'安裝 {{ideName}} 所需的 IDE 配套工具',
'enable IDE integration': '用 IDE 集成',
'enable IDE integration': '用 IDE 集成',
'disable IDE integration': '禁用 IDE 集成',
'IDE integration is not supported in your current environment. To use this feature, run Qwen Code in one of these supported IDEs: VS Code or VS Code forks.':
'您當前環境不支持 IDE 集成。要使用此功能,請在以下支持的 IDE 之一中運行 Qwen CodeVS Code 或 VS Code 分支版本。',
@ -530,30 +532,30 @@ export default {
'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf, Trae)':
'配置終端按鍵綁定以支持多行輸入VS Code、Cursor、Windsurf、Trae',
'Please restart your terminal for the changes to take effect.':
'請重終端以使更改生效。',
'請重終端以使更改生效。',
'Failed to configure terminal: {{error}}': '配置終端失敗:{{error}}',
'Could not determine {{terminalName}} config path on Windows: APPDATA environment variable is not set.':
'無法確定 {{terminalName}} 在 Windows 上的配置路徑:未設置 APPDATA 環境變量。',
'{{terminalName}} keybindings.json exists but is not a valid JSON array. Please fix the file manually or delete it to allow automatic configuration.':
'{{terminalName}} keybindings.json 存在但不是有效的 JSON 數組。請手動修復文件或刪除它以允許自動配置。',
'File: {{file}}': '文件{{file}}',
'{{terminalName}} keybindings.json 存在但不是有效的 JSON 數組。請手動修復檔案或刪除它以允許自動配置。',
'File: {{file}}': '檔案{{file}}',
'Failed to parse {{terminalName}} keybindings.json. The file contains invalid JSON. Please fix the file manually or delete it to allow automatic configuration.':
'解析 {{terminalName}} keybindings.json 失敗。文件包含無效的 JSON。請手動修復文件或刪除它以允許自動配置。',
'解析 {{terminalName}} keybindings.json 失敗。檔案包含無效的 JSON。請手動修復檔案或刪除它以允許自動配置。',
'Error: {{error}}': '錯誤:{{error}}',
'Shift+Enter binding already exists': 'Shift+Enter 綁定已存在',
'Ctrl+Enter binding already exists': 'Ctrl+Enter 綁定已存在',
'Existing keybindings detected. Will not modify to avoid conflicts.':
'檢測到現有按鍵綁定。避免衝突,不會修改。',
'檢測到現有按鍵綁定。避免衝突,不會修改。',
'Please check and modify manually if needed: {{file}}':
'如有需要,請手動檢查並修改:{{file}}',
'Added Shift+Enter and Ctrl+Enter keybindings to {{terminalName}}.':
'已 {{terminalName}} 添加 Shift+Enter 和 Ctrl+Enter 按鍵綁定。',
'已 {{terminalName}} 添加 Shift+Enter 和 Ctrl+Enter 按鍵綁定。',
'Modified: {{file}}': '已修改:{{file}}',
'{{terminalName}} keybindings already configured.':
'{{terminalName}} 按鍵綁定已配置。',
'Failed to configure {{terminalName}}.': '配置 {{terminalName}} 失敗。',
'Your terminal is already configured for an optimal experience with multiline input (Shift+Enter and Ctrl+Enter).':
'您的終端已配置支持多行輸入Shift+Enter 和 Ctrl+Enter的最佳體驗。',
'您的終端已配置支持多行輸入Shift+Enter 和 Ctrl+Enter的最佳體驗。',
'Manage Qwen Code hooks': '管理 Qwen Code Hook',
'List all configured hooks': '列出所有已配置的 Hook',
Hooks: 'Hook',
@ -568,7 +570,7 @@ export default {
'{{count}} hook configured': '{{count}} 個 Hook 已配置',
'{{count}} hooks configured': '{{count}} 個 Hook 已配置',
'This menu is read-only. To add or modify hooks, edit settings.json directly or ask Qwen Code.':
'此菜單爲只讀。要添加或修改 Hook請直接編輯 settings.json 或詢問 Qwen Code。',
'此選單為只讀。要添加或修改 Hook請直接編輯 settings.json 或詢問 Qwen Code。',
'Enter to select · Esc to cancel': 'Enter 選擇 · Esc 取消',
'Exit codes:': '退出碼:',
'Configured hooks:': '已配置的 Hook',
@ -594,7 +596,7 @@ export default {
'Tool operations will proceed without hook validation':
'工具操作將在沒有 Hook 驗證的情況下繼續',
'To re-enable hooks, remove "disableAllHooks" from settings.json or ask Qwen Code.':
'要重新用 Hook請從 settings.json 中刪除 "disableAllHooks" 或詢問 Qwen Code。',
'要重新用 Hook請從 settings.json 中刪除 "disableAllHooks" 或詢問 Qwen Code。',
Project: '項目',
User: '用戶',
Skill: '技能',
@ -613,33 +615,33 @@ export default {
'When a new session is started': '新會話開始時',
'Right before Qwen Code concludes its response': 'Qwen Code 結束響應之前',
'When a subagent (Agent tool call) is started':
'子智能體Agent 工具調用)動時',
'子智能體Agent 工具調用)動時',
'Right before a subagent concludes its response': '子智能體結束響應之前',
'Before conversation compaction': '對話壓縮前',
'When a session is ending': '會話結束時',
'When a permission dialog is displayed': '顯示權限對話框時',
'Input to command is JSON of tool call arguments.':
'命令輸入工具調用參數的 JSON。',
'命令輸入工具調用參數的 JSON。',
'Input to command is JSON with fields "inputs" (tool call arguments) and "response" (tool call response).':
'命令輸入包含 "inputs"(工具調用參數)和 "response"(工具調用響應)字段的 JSON。',
'命令輸入包含 "inputs"(工具調用參數)和 "response"(工具調用響應)字段的 JSON。',
'Input to command is JSON with tool_name, tool_input, tool_use_id, error, error_type, is_interrupt, and is_timeout.':
'命令輸入包含 tool_name、tool_input、tool_use_id、error、error_type、is_interrupt 和 is_timeout 的 JSON。',
'命令輸入包含 tool_name、tool_input、tool_use_id、error、error_type、is_interrupt 和 is_timeout 的 JSON。',
'Input to command is JSON with notification message and type.':
'命令輸入包含通知消息和類型的 JSON。',
'命令輸入包含通知消息和類型的 JSON。',
'Input to command is JSON with original user prompt text.':
'命令輸入包含原始用戶提示文本的 JSON。',
'命令輸入包含原始用戶提示文本的 JSON。',
'Input to command is JSON with session start source.':
'命令輸入爲包含會話啓動來源的 JSON。',
'命令輸入為包含會話啟動來源的 JSON。',
'Input to command is JSON with session end reason.':
'命令輸入包含會話結束原因的 JSON。',
'命令輸入包含會話結束原因的 JSON。',
'Input to command is JSON with agent_id and agent_type.':
'命令輸入包含 agent_id 和 agent_type 的 JSON。',
'命令輸入包含 agent_id 和 agent_type 的 JSON。',
'Input to command is JSON with agent_id, agent_type, and agent_transcript_path.':
'命令輸入包含 agent_id、agent_type 和 agent_transcript_path 的 JSON。',
'命令輸入包含 agent_id、agent_type 和 agent_transcript_path 的 JSON。',
'Input to command is JSON with compaction details.':
'命令輸入包含壓縮詳情的 JSON。',
'命令輸入包含壓縮詳情的 JSON。',
'Input to command is JSON with tool_name, tool_input, and tool_use_id. Output JSON with hookSpecificOutput containing decision to allow or deny.':
'命令輸入包含 tool_name、tool_input 和 tool_use_id 的 JSON。輸出包含 hookSpecificOutput 的 JSON其中包含允許或拒絕的決定。',
'命令輸入包含 tool_name、tool_input 和 tool_use_id 的 JSON。輸出包含 hookSpecificOutput 的 JSON其中包含允許或拒絕的決定。',
'stdout/stderr not shown': 'stdout/stderr 不顯示',
'show stderr to model and continue conversation':
'向模型顯示 stderr 並繼續對話',
@ -658,21 +660,21 @@ export default {
'show stderr to subagent and continue having it run':
'向子智能體顯示 stderr 並繼續運行',
'stdout appended as custom compact instructions':
'stdout 作自定義壓縮指令追加',
'stdout 作自定義壓縮指令追加',
'block compaction': '阻止壓縮',
'show stderr to user only but continue with compaction':
'僅向用戶顯示 stderr 但繼續壓縮',
'use hook decision if provided': '如果提供則使用 Hook 決定',
'Config not loaded.': '配置未加載。',
'Hooks are not enabled. Enable hooks in settings to use this feature.':
'Hook 未啓用。請在設置中啓用 Hook 以使用此功能。',
'Hook 未啟用。請在設置中啟用 Hook 以使用此功能。',
'Export current session message history to a file':
'將當前會話的消息記錄導出到文件',
'Export session to HTML format': '將會話導出爲 HTML 文件',
'Export session to JSON format': '將會話導出爲 JSON 文件',
'將當前會話的消息記錄導出到檔案',
'Export session to HTML format': '將會話導出為 HTML 檔案',
'Export session to JSON format': '將會話導出為 JSON 檔案',
'Export session to JSONL format (one message per line)':
'將會話導出爲 JSONL 文件(每行一條消息)',
'Export session to markdown format': '將會話導出爲 Markdown 文件',
'將會話導出為 JSONL 檔案(每行一條消息)',
'Export session to markdown format': '將會話導出為 Markdown 檔案',
'generate personalized programming insights from your chat history':
'根據你的聊天記錄生成個性化編程洞察',
'Resume a previous session': '恢復先前會話',
@ -681,7 +683,7 @@ export default {
'回應或工具呼叫正在進行時無法分支。請等待其完成或處理待確認的工具呼叫。',
'No conversation to branch.': '沒有可分支的對話。',
'Restore a tool call. This will reset the conversation and file history to the state it was in when the tool call was suggested':
'恢復某次工具調用。這將把對話與文件歷史重置到提出該工具調用建議時的狀態',
'恢復某次工具調用。這將把對話與檔案歷史重置到提出該工具調用建議時的狀態',
'Could not detect terminal type. Supported terminals: VS Code, Cursor, Windsurf, and Trae.':
'無法檢測終端類型。支持的終端VS Code、Cursor、Windsurf 和 Trae。',
'Terminal "{{terminal}}" is not supported yet.':
@ -699,31 +701,31 @@ export default {
'Example: /language output 中文': '示例:/language output 中文',
'Example: /language output English': '示例:/language output English',
'Example: /language output 日本語': '示例:/language output 日本語',
'UI language changed to {{lang}}': 'UI 語言已更改 {{lang}}',
'LLM output language set to {{lang}}': 'LLM 輸出語言已設置 {{lang}}',
'UI language changed to {{lang}}': 'UI 語言已更改 {{lang}}',
'LLM output language set to {{lang}}': 'LLM 輸出語言已設置 {{lang}}',
'Please restart the application for the changes to take effect.':
'請重應用程序以使更改生效。',
'請重應用程序以使更改生效。',
'Failed to generate LLM output language rule file: {{error}}':
'生成 LLM 輸出語言規則文件失敗:{{error}}',
'生成 LLM 輸出語言規則檔案失敗:{{error}}',
'Invalid command. Available subcommands:': '無效的命令。可用的子命令:',
'Available subcommands:': '可用的子命令:',
'To request additional UI language packs, please open an issue on GitHub.':
'如需請求其他 UI 語言包,請在 GitHub 上提交 issue',
'Available options:': '可用選項:',
'Set UI language to {{name}}': '將 UI 語言設置 {{name}}',
'Set UI language to {{name}}': '將 UI 語言設置 {{name}}',
'Tool Approval Mode': '工具審批模式',
'{{mode}} mode': '{{mode}} 模式',
'Analyze only, do not modify files or execute commands':
'僅分析,不修改文件或執行命令',
'僅分析,不修改檔案或執行命令',
'Require approval for file edits or shell commands':
'需要批准文件編輯或 shell 命令',
'Automatically approve file edits': '自動批准文件編輯',
'需要批准檔案編輯或 shell 命令',
'Automatically approve file edits': '自動批准檔案編輯',
'Automatically approve all tools': '自動批准所有工具',
'Workspace approval mode exists and takes priority. User-level change will have no effect.':
'工作區審批模式已存在並具有優先級。用戶級別的更改將無效。',
'Apply To': '應用於',
'Workspace Settings': '工作區設置',
'Open auto-memory folder': '打開自動記憶文件夾',
'Open auto-memory folder': '打開自動記憶檔案夾',
'Auto-memory: {{status}}': '自動記憶:{{status}}',
'Auto-dream: {{status}} · {{lastDream}} · /dream to run':
'自動整理:{{status}} · {{lastDream}} · /dream 立即運行',
@ -735,7 +737,7 @@ export default {
'Usage: /forget <memory text to remove>': '用法:/forget <要刪除的記憶文本>',
'No managed auto-memory entries matched: {{query}}':
'沒有匹配的託管自動記憶條目:{{query}}',
'Consolidate managed auto-memory topic files.': '整理託管自動記憶主題文件',
'Consolidate managed auto-memory topic files.': '整理託管自動記憶主題檔案',
'Open MCP management dialog': '打開 MCP 管理對話框',
'Could not retrieve tool registry.': '無法檢索工具註冊表',
"Successfully authenticated and refreshed tools for '{{name}}'.":
@ -745,10 +747,10 @@ export default {
"Discovered {{count}} tool(s) from '{{name}}'.":
"從 '{{name}}' 發現了 {{count}} 個工具。",
'Authentication complete. Returning to server details...':
'認證完成,正在返回器詳情...',
'認證完成,正在返回服器詳情...',
'Authentication successful.': '認證成功。',
'Manage MCP servers': '管理 MCP servers',
'Server Detail': '器詳情',
'Server Detail': '服器詳情',
Tools: '工具',
'Tool Detail': '工具詳情',
'Loading...': '加載中...',
@ -762,21 +764,21 @@ export default {
'↑↓ 導航 · Enter 確認 · Esc 返回',
'User Settings (global)': '用戶設置(全局)',
'Workspace Settings (project-specific)': '工作區設置(項目級)',
'Disable server:': '禁用器:',
'Disable server:': '禁用服器:',
'Select where to add the server to the exclude list:':
'選擇將器添加到排除列表的位置:',
'選擇將服器添加到排除列表的位置:',
'Press Enter to confirm, Esc to cancel': '按 Enter 確認Esc 取消',
'View tools': '查看工具',
Reconnect: '重新連接',
Enable: '用',
Enable: '用',
Disable: '禁用',
Authenticate: '認證',
'Re-authenticate': '重新認證',
'Clear Authentication': '清空認證',
'Server:': '器:',
'Server:': '服器:',
'Command:': '命令:',
'Working Directory:': '工作目錄:',
'No server selected': '未選擇器',
'No server selected': '未選擇服器',
prompts: '提示詞',
'Error:': '錯誤:',
tool: '工具',
@ -787,8 +789,8 @@ export default {
'User MCPs': '用戶 MCP',
'Project MCPs': '項目 MCP',
'Extension MCPs': '擴展 MCP',
server: '個器',
servers: '個器',
server: '個服器',
servers: '個服器',
'Add MCP servers to your settings to get started.':
'請在設置中添加 MCP servers 以開始使用。',
'Run qwen --debug to see error logs': '運行 qwen --debug 查看錯誤日誌',
@ -798,10 +800,10 @@ export default {
'Press c to copy the authorization URL to your clipboard.':
'按 c 複製授權 URL 到剪貼板。',
'Copy request sent to your terminal. If paste is empty, copy the URL above manually.':
'已向終端發送複製請求;若粘貼空,請手動複製上方 URL。',
'已向終端發送複製請求;若粘貼空,請手動複製上方 URL。',
'Cannot write to terminal — copy the URL above manually.':
'無法寫入終端,請手動複製上方 URL。',
'No tools available for this server.': '此器沒有可用工具。',
'No tools available for this server.': '此服器沒有可用工具。',
destructive: '破壞性',
'read-only': '只讀',
'open-world': '開放世界',
@ -811,7 +813,7 @@ export default {
required: '必填',
Parameters: '參數',
'No tool selected': '未選擇工具',
Server: '器',
Server: '服器',
'{{count}} invalid tools': '{{count}} 個無效工具',
invalid: '無效',
'invalid: {{reason}}': '無效:{{reason}}',
@ -856,24 +858,24 @@ export default {
'Starting a new session and clearing.': '正在開始新會話並清屏。',
'Already compressing, wait for previous request to complete':
'正在壓縮中,請等待上一個請求完成',
'Failed to compress chat history.': '壓縮聊天史失敗',
'Failed to compress chat history: {{error}}': '壓縮聊天史失敗:{{error}}',
'Compressing chat history': '正在壓縮聊天史',
'Failed to compress chat history.': '壓縮聊天史失敗',
'Failed to compress chat history: {{error}}': '壓縮聊天史失敗:{{error}}',
'Compressing chat history': '正在壓縮聊天史',
'Chat history compressed from {{originalTokens}} to {{newTokens}} tokens.':
'聊天史已從 {{originalTokens}} 個 token 壓縮到 {{newTokens}} 個 token。',
'聊天史已從 {{originalTokens}} 個 token 壓縮到 {{newTokens}} 個 token。',
'Compression was not beneficial for this history size.':
'對於此歷史記錄大小,壓縮沒有益處。',
'Chat history compression did not reduce size. This may indicate issues with the compression prompt.':
'聊天史壓縮未能減小大小。這可能表明壓縮提示存在問題。',
'聊天史壓縮未能減小大小。這可能表明壓縮提示存在問題。',
'Could not compress chat history due to a token counting error.':
'由於 token 計數錯誤,無法壓縮聊天史。',
'由於 token 計數錯誤,無法壓縮聊天史。',
'Configuration is not available.': '配置不可用。',
'Please provide at least one path to add.': '請提供至少一個要添加的路徑。',
'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.':
'/directory add 命令在限制性沙箱配置文件中不受支持。請改爲在啓動會話時使用 --include-directories。',
'/directory add 命令在限制性沙箱配置檔案中不受支持。請改為在啟動會話時使用 --include-directories。',
"Error adding '{{path}}': {{error}}": "添加 '{{path}}' 時出錯:{{error}}",
'Successfully added QWEN.md files from the following directories if there are:\n- {{directories}}':
'如果存在,已成功從以下目錄添加 QWEN.md 文件\n- {{directories}}',
'如果存在,已成功從以下目錄添加 QWEN.md 檔案\n- {{directories}}',
'Error refreshing memory: {{error}}': '刷新內存時出錯:{{error}}',
'Successfully added directories:\n- {{directories}}':
'成功添加目錄:\n- {{directories}}',
@ -960,7 +962,7 @@ export default {
'Browser-based authentication with third-party providers (e.g. OpenRouter, ModelScope)':
'基於瀏覽器的第三方提供商認證(例如 OpenRouter、ModelScope',
'Authentication is enforced to be {{enforcedType}}, but you are currently using {{currentType}}.':
'認證方式被強制設置 {{enforcedType}},但您當前使用的是 {{currentType}}',
'認證方式被強制設置 {{enforcedType}},但您當前使用的是 {{currentType}}',
'Qwen OAuth Authentication': 'Qwen OAuth 認證',
'Please visit this URL to authorize:': '請訪問此 URL 進行授權:',
'Waiting for authorization': '等待授權中',
@ -977,9 +979,9 @@ export default {
'Missing API key for OpenAI-compatible auth. Set settings.security.auth.apiKey, or set the {{envKeyHint}} environment variable.':
'缺少 OpenAI 兼容認證的 API Key。請設置 settings.security.auth.apiKey 或設置 {{envKeyHint}} 環境變量。',
'{{envKeyHint}} environment variable not found. Please set it in your .env file or environment variables.':
'未找到 {{envKeyHint}} 環境變量。請在 .env 文件或系統環境變量中進行設置。',
'未找到 {{envKeyHint}} 環境變量。請在 .env 檔案或系統環境變量中進行設置。',
'{{envKeyHint}} environment variable not found (or set settings.security.auth.apiKey). Please set it in your .env file or environment variables.':
'未找到 {{envKeyHint}} 環境變量(或設置 settings.security.auth.apiKey。請在 .env 文件或系統環境變量中進行設置。',
'未找到 {{envKeyHint}} 環境變量(或設置 settings.security.auth.apiKey。請在 .env 檔案或系統環境變量中進行設置。',
'Missing API key for OpenAI-compatible auth. Set the {{envKeyHint}} environment variable.':
'缺少 OpenAI 兼容認證的 API Key。請設置 {{envKeyHint}} 環境變量。',
'Anthropic provider missing required baseUrl in modelProviders[].baseUrl.':
@ -991,7 +993,7 @@ export default {
'Authenticated successfully with {{authType}} credentials.':
'使用 {{authType}} 憑據成功認證。',
'Invalid QWEN_DEFAULT_AUTH_TYPE value: "{{value}}". Valid values are: {{validValues}}':
'無效的 QWEN_DEFAULT_AUTH_TYPE 值:"{{value}}"。有效值{{validValues}}',
'無效的 QWEN_DEFAULT_AUTH_TYPE 值:"{{value}}"。有效值{{validValues}}',
'Select Model': '選擇模型',
'API Key': 'API Key',
'(default)': '(默認)',
@ -1007,7 +1009,7 @@ export default {
'not set': '未設置',
none: '無',
unknown: '未知',
'Manage folder trust settings': '管理文件夾信任設置',
'Manage folder trust settings': '管理檔案夾信任設置',
'Manage permission rules': '管理 permission rules',
Allow: '允許',
Ask: '詢問',
@ -1052,9 +1054,9 @@ export default {
'Add directory…': '添加目錄…',
'Add directory to workspace': '添加工作區目錄',
'Qwen Code can read files in the workspace, and make edits when auto-accept edits is on.':
'Qwen Code 可以讀取工作區中的文件,並在自動接受編輯模式開啓時進行編輯。',
'Qwen Code 可以讀取工作區中的檔案,並在自動接受編輯模式開啟時進行編輯。',
'Qwen Code will be able to read files in this directory and make edits when auto-accept edits is on.':
'Qwen Code 將能夠讀取此目錄中的文件,並在自動接受編輯模式開啓時進行編輯。',
'Qwen Code 將能夠讀取此目錄中的檔案,並在自動接受編輯模式開啟時進行編輯。',
'Enter the path to the directory:': '輸入目錄路徑:',
'Enter directory path…': '輸入目錄路徑…',
'Tab to complete · Enter to add · Esc to cancel':
@ -1069,11 +1071,11 @@ export default {
'This directory is already in the workspace.': '此目錄已在工作區中。',
'Already covered by existing directory: {{dir}}': '已被現有目錄覆蓋:{{dir}}',
'Using:': '已加載: ',
'{{count}} open file': '{{count}} 個打開的文件',
'{{count}} open files': '{{count}} 個打開的文件',
'{{count}} open file': '{{count}} 個打開的檔案',
'{{count}} open files': '{{count}} 個打開的檔案',
'(ctrl+g to view)': '(按 ctrl+g 查看)',
'{{count}} {{name}} file': '{{count}} 個 {{name}} 文件',
'{{count}} {{name}} files': '{{count}} 個 {{name}} 文件',
'{{count}} {{name}} file': '{{count}} 個 {{name}} 檔案',
'{{count}} {{name}} files': '{{count}} 個 {{name}} 檔案',
'{{count}} MCP server': '{{count}} 個 MCP server',
'{{count}} MCP servers': '{{count}} 個 MCP servers',
'{{count}} Blocked': '{{count}} 個已阻止',
@ -1085,13 +1087,13 @@ export default {
'Press ↑ to edit queued messages': '按 ↑ 編輯排隊消息',
'No MCP servers configured.': '未配置 MCP servers',
'⏳ MCP servers are starting up ({{count}} initializing)...':
'⏳ MCP servers 正在動({{count}} 個正在初始化)...',
'⏳ MCP servers 正在動({{count}} 個正在初始化)...',
'Note: First startup may take longer. Tool availability will update automatically.':
'注意:首次動可能需要更長時間。工具可用性將自動更新',
'注意:首次動可能需要更長時間。工具可用性將自動更新',
'Configured MCP servers:': '已配置的 MCP servers',
Ready: '就緒',
'Starting... (first startup may take longer)':
'正在啓動...(首次啓動可能需要更長時間)',
'正在啟動...(首次啟動可能需要更長時間)',
Disconnected: '已斷開連接',
'{{count}} tool': '{{count}} 個工具',
'{{count}} tools': '{{count}} 個工具',
@ -1109,20 +1111,20 @@ export default {
Blocked: '已阻止',
'💡 Tips:': '💡 提示:',
Use: '使用',
'to show server and tool descriptions': '顯示器和工具描述',
'to show server and tool descriptions': '顯示服器和工具描述',
'to show tool parameter schemas': '顯示 tool parameter schemas',
'to hide descriptions': '隱藏描述',
'to authenticate with OAuth-enabled servers':
'使用支持 OAuth 的器進行認證',
'使用支持 OAuth 的服器進行認證',
Press: '按',
'to toggle tool descriptions on/off': '切換工具描述開關',
"Starting OAuth authentication for MCP server '{{name}}'...":
"正在爲 MCP server '{{name}}' 啓動 OAuth 認證...",
"正在為 MCP server '{{name}}' 啟動 OAuth 認證...",
'Tips:': '提示:',
'Use /compress when the conversation gets long to summarize history and free up context.':
'對話變長時用 /compress總結歷史並釋放上下文。',
'Start a fresh idea with /clear or /new; the previous session stays available in history.':
'用 /clear 或 /new 開新思路;之前的會話會保留在歷史記錄中。',
'用 /clear 或 /new 開新思路;之前的會話會保留在歷史記錄中。',
'Use /bug to submit issues to the maintainers when something goes off.':
'遇到問題時,用 /bug 將問題提交給維護者。',
'Switch auth type quickly with /auth.': '用 /auth 快速切換認證方式。',
@ -1141,11 +1143,11 @@ export default {
'Press Ctrl+O to toggle compact mode — hide tool output and thinking for a cleaner view.':
'按 Ctrl+O 切換緊湊模式 ── 隱藏工具輸出和思考過程,界面更簡潔。',
'Add a QWEN.md file to give Qwen Code persistent project context.':
'添加 QWEN.md 文件,爲 Qwen Code 提供持久的項目上下文。',
'添加 QWEN.md 檔案,為 Qwen Code 提供持久的項目上下文。',
'Use /btw to ask a quick side question without disrupting the conversation.':
'用 /btw 快速問一個小問題,不會打斷當前對話。',
'Context is almost full! Run /compress now or start /new to continue.':
'上下文即將用滿!請立即執行 /compress 或使用 /new 開新會話。',
'上下文即將用滿!請立即執行 /compress 或使用 /new 開新會話。',
'Context is getting full. Use /compress to free up space.':
'上下文空間不足,用 /compress 釋放空間。',
'Long conversation? /compress summarizes history to free context.':
@ -1204,21 +1206,21 @@ export default {
'Session start time is unavailable, cannot calculate stats.':
'會話開始時間不可用,無法計算統計信息',
'Command Format Migration': '命令格式遷移',
'Found {{count}} TOML command file:': '發現 {{count}} 個 TOML 命令文件',
'Found {{count}} TOML command files:': '發現 {{count}} 個 TOML 命令文件',
'Found {{count}} TOML command file:': '發現 {{count}} 個 TOML 命令檔案',
'Found {{count}} TOML command files:': '發現 {{count}} 個 TOML 命令檔案',
'Current tasks': '目前任務',
'... and {{count}} more': '... 以及其他 {{count}} 個',
'The TOML format is deprecated. Would you like to migrate them to Markdown format?':
'TOML 格式已棄用。是否將它們遷移到 Markdown 格式?',
'(Backups will be created and original files will be preserved)':
'(將創建備份,原始文件將保留)',
'(將創建備份,原始檔案將保留)',
'Waiting for user confirmation...': '等待用戶確認...',
WITTY_LOADING_PHRASES: [
'正在努力搬磚,請稍候...',
'老闆在身後,快加載啊!',
'頭髮掉光前,一定能加載完...',
'器正在深呼吸,準備放大招...',
'正在向器投餵咖啡...',
'服器正在深呼吸,準備放大招...',
'正在向服器投餵咖啡...',
'正在賦能全鏈路,尋找關鍵抓手...',
'正在降本增效,優化加載路徑...',
'正在打破部門壁壘,沉澱方法論...',
@ -1226,7 +1228,7 @@ export default {
'正在對齊顆粒度,打磨底層邏輯...',
'大力出奇跡,正在強行加載...',
'只要我不寫代碼,代碼就沒有 Bug...',
'正在把 Bug 轉化 Feature...',
'正在把 Bug 轉化 Feature...',
'只要我不尷尬Bug 就追不上我...',
'正在試圖理解去年的自己寫了什麼...',
'正在猿力覺醒中,請耐心等待...',
@ -1243,23 +1245,23 @@ export default {
'Enter sensitive value...': '請輸入敏感值...',
'Press Enter to submit, Escape to cancel': '按 Enter 提交Escape 取消',
'Markdown file already exists: {{filename}}':
'Markdown 文件已存在:{{filename}}',
'Markdown 檔案已存在:{{filename}}',
'TOML Command Format Deprecation Notice': 'TOML 命令格式棄用通知',
'Found {{count}} command file(s) in TOML format:':
'發現 {{count}} 個 TOML 格式的命令文件',
'發現 {{count}} 個 TOML 格式的命令檔案',
'The TOML format for commands is being deprecated in favor of Markdown format.':
'命令的 TOML 格式正在被棄用,推薦使用 Markdown 格式。',
'Markdown format is more readable and easier to edit.':
'Markdown 格式更易讀、更易編輯。',
'You can migrate these files automatically using:':
'您可以使用以下命令自動遷移這些文件',
'Or manually convert each file:': '或手動轉換每個文件',
'您可以使用以下命令自動遷移這些檔案',
'Or manually convert each file:': '或手動轉換每個檔案',
'TOML: prompt = "..." / description = "..."':
'TOMLprompt = "..." / description = "..."',
'Markdown: YAML frontmatter + content': 'MarkdownYAML frontmatter + 內容',
'The migration tool will:': '遷移工具將:',
'Convert TOML files to Markdown': '將 TOML 文件轉換爲 Markdown',
'Create backups of original files': '創建原始文件的備份',
'Convert TOML files to Markdown': '將 TOML 檔案轉換為 Markdown',
'Create backups of original files': '創建原始檔案的備份',
'Preserve all command functionality': '保留所有命令功能',
'TOML format will continue to work for now, but migration is recommended.':
'TOML 格式目前仍可使用,但建議遷移。',
@ -1277,7 +1279,7 @@ export default {
'Press Ctrl+Y to retry': '按 Ctrl+Y 重試。',
'No failed request to retry.': '沒有可重試的失敗請求。',
'to retry last request': '重試上一次請求',
'API key cannot be empty.': 'API Key 不能空。',
'API key cannot be empty.': 'API Key 不能空。',
'Invalid API key. Coding Plan API keys start with "sk-sp-". Please check.':
'無效的 API KeyCoding Plan API Key 均以 "sk-sp-" 開頭,請檢查',
'You can get your Coding Plan API key here':
@ -1285,7 +1287,7 @@ export default {
'You can get your Token Plan API key here':
'您可以在這裏獲取 Token Plan API Key',
'API key is stored in settings.env. You can migrate it to a .env file for better security.':
'API Key 已存儲在 settings.env 中。您可以將其遷移到 .env 文件以獲得更好的安全性。',
'API Key 已存儲在 settings.env 中。您可以將其遷移到 .env 檔案以獲得更好的安全性。',
'New model configurations are available for Alibaba Cloud Coding Plan. Update now?':
'阿里雲百鍊 Coding Plan 有新模型配置可用。是否立即更新?',
'Coding Plan configuration updated successfully. New models are now available.':
@ -1325,7 +1327,7 @@ export default {
'System prompt': '系統提示',
'Built-in tools': '內置工具',
'MCP tools': 'MCP tools',
'Memory files': '記憶文件',
'Memory files': '記憶檔案',
Skills: '技能',
Messages: '消息',
'Run /context detail for per-item breakdown.':
@ -1357,7 +1359,7 @@ export default {
'API key for Coding Plan': 'Coding Plan 的 API Key',
'Show current authentication status': '顯示當前認證狀態',
'Authentication completed successfully.': '認證完成。',
'Starting Qwen OAuth authentication...': '正在動 Qwen OAuth 認證...',
'Starting Qwen OAuth authentication...': '正在動 Qwen OAuth 認證...',
'Successfully authenticated with Qwen OAuth.': '已成功通過 Qwen OAuth 認證。',
'Failed to authenticate with Qwen OAuth: {{error}}':
'Qwen OAuth 認證失敗:{{error}}',
@ -1419,7 +1421,7 @@ export default {
'Exited plan mode. Previous approval mode restored.':
'已退出計劃模式,已恢復之前的審批模式。',
'Enabled plan mode. The agent will analyze and plan without executing tools.':
'用計劃模式。智能體將只分析和規劃,而不執行工具。',
'用計劃模式。智能體將只分析和規劃,而不執行工具。',
'Already in plan mode. Use "/plan exit" to exit plan mode.':
'已處於計劃模式。使用 "/plan exit" 退出計劃模式。',
'Not in plan mode. Use "/plan" to enter plan mode first.':
@ -1487,7 +1489,7 @@ export default {
'Manage AI translation for dynamic slash command descriptions':
'管理動態斜線命令描述的 AI 翻譯',
'Enable AI translation for dynamic slash command descriptions':
'用動態斜線命令描述的 AI 翻譯',
'用動態斜線命令描述的 AI 翻譯',
'Disable AI translation for dynamic slash command descriptions':
'禁用動態斜線命令描述的 AI 翻譯',
'Show AI translation status for dynamic slash command descriptions':
@ -1495,7 +1497,7 @@ export default {
'AI translation for dynamic slash command descriptions is {{status}}.':
'動態斜線命令描述的 AI 翻譯處於{{status}}狀態。',
'AI translation for dynamic slash command descriptions is now enabled.':
'動態斜線命令描述的 AI 翻譯現已用。',
'動態斜線命令描述的 AI 翻譯現已用。',
'AI translation for dynamic slash command descriptions is now disabled.':
'動態斜線命令描述的 AI 翻譯現已禁用。',
'Manage extension settings': '管理擴展設置',

View file

@ -71,6 +71,112 @@ export function shouldWriteUnusedKeysJson(): boolean {
);
}
/**
* Substrings that should not appear in zh-TW (Taiwan Traditional Chinese) values.
*
* Three categories of regressions we want to catch automatically:
* 1. Variant Traditional characters that OpenCC s2t produces by default but
* Taiwan does not use as primary forms (e.g. , ).
* 2. Mainland-Chinese vocabulary whose characters are valid Traditional but
* the word itself is not used in Taiwan (e.g. , , ).
* 3. Pure Simplified Chinese characters that would only appear if OpenCC
* was not run at all (e.g. , , ).
*
* Deliberately excluded to avoid false positives:
* - / / standard in Taiwan.
* - contextual (can legitimately mean "document").
* - colloquially common in Taiwan even if is preferred for UI.
* - Bare valid in etc.; only the bigram is flagged.
*
* Known limitation: matching is plain substring (`includes()`) and does not
* respect Chinese word boundaries. Bigram patterns can therefore false-positive
* across compound-word boundaries e.g. `區塊鏈接口` (= `區塊鏈` + `接口`)
* contains the substring `鏈接` even though neither word is wrong. When this
* happens, add the affected translation key to ZH_TW_ALLOWED_EXCEPTIONS below
* with a brief justification, rather than weakening the pattern list.
*/
const ZH_TW_FORBIDDEN_PATTERNS_RAW: ReadonlyArray<{
pattern: string;
preferred: string;
}> = [
// Variant Traditional characters from OpenCC s2t output
{ pattern: '爲', preferred: '為' },
{ pattern: '啓', preferred: '啟' },
// Mainland-Chinese vocabulary (valid Traditional chars, wrong word for Taiwan)
{ pattern: '曆史', preferred: '歷史' },
{ pattern: '鏈接', preferred: '連結' },
{ pattern: '菜單', preferred: '選單' },
{ pattern: '服務器', preferred: '伺服器' },
// Same Mainland vocabulary written in Simplified form
{ pattern: '菜单', preferred: '選單' },
{ pattern: '服务器', preferred: '伺服器' },
{ pattern: '链接', preferred: '連結' },
{ pattern: '历史', preferred: '歷史' },
// Pure Simplified characters (no ambiguity with valid Traditional usage)
{ pattern: '为', preferred: '為' },
{ pattern: '启', preferred: '啟' },
{ pattern: '历', preferred: '歷' },
{ pattern: '链', preferred: '鏈/連' },
{ pattern: '选', preferred: '選' },
{ pattern: '删', preferred: '刪' },
{ pattern: '扩', preferred: '擴' },
{ pattern: '设', preferred: '設' },
{ pattern: '详', preferred: '詳' },
{ pattern: '认', preferred: '認' },
];
// Sorted longest-first so that more specific patterns (e.g. `历史`) are matched
// before their constituent characters (`历`), avoiding duplicate findings on
// the same translation value.
const ZH_TW_FORBIDDEN_PATTERNS = [...ZH_TW_FORBIDDEN_PATTERNS_RAW].sort(
(a, b) => b.pattern.length - a.pattern.length,
);
/**
* Translation keys whose zh-TW value is allowed to contain an otherwise
* forbidden substring. Use this as an escape hatch when a legitimate
* translation needs a normally-banned character or word add the key here
* with a comment explaining why, instead of weakening the global pattern list.
*
* Example:
* 'Open block explorer for {{address}}': '...區塊鏈瀏覽器...', // 區塊鏈 = blockchain
*/
const ZH_TW_ALLOWED_EXCEPTIONS: ReadonlySet<string> = new Set<string>([
// (empty — no legitimate exceptions today)
]);
/**
* Walk every translation value and report any value containing a forbidden
* substring. Iterating over the parsed dict (rather than the raw file)
* lets us report the offending key, and avoids matching characters inside
* file-level comments or JS syntax.
*
* Only the longest matching pattern per value is reported, to keep CI output
* focused on the most actionable fix.
*/
export function findForbiddenZhTwPatterns(
translations: TranslationDict,
): Array<{ key: string; pattern: string; preferred: string }> {
const findings: Array<{ key: string; pattern: string; preferred: string }> =
[];
for (const [key, value] of Object.entries(translations)) {
if (ZH_TW_ALLOWED_EXCEPTIONS.has(key)) continue;
const candidates = Array.isArray(value) ? value : [value];
for (const candidate of candidates) {
if (typeof candidate !== 'string') continue;
for (const { pattern, preferred } of ZH_TW_FORBIDDEN_PATTERNS) {
if (candidate.includes(pattern)) {
findings.push({ key, pattern, preferred });
break;
}
}
}
}
return findings;
}
async function loadTranslationsFile(
filePath: string,
): Promise<TranslationDict> {
@ -433,6 +539,19 @@ export async function checkI18n(
}
}
// Check zh-TW.js for Taiwan-vocabulary regressions (raw OpenCC output,
// Mainland-Chinese vocabulary, or Simplified characters slipping in).
const zhTWTranslations = localeTranslations.get('zh-TW');
if (zhTWTranslations) {
for (const { key, pattern, preferred } of findForbiddenZhTwPatterns(
zhTWTranslations,
)) {
errors.push(
`Non-Taiwan vocabulary in zh-TW.js at "${key}": "${pattern}" should be "${preferred}"`,
);
}
}
const usedKeys = await extractUsedKeys(sourceDir);
const unusedKeys = findUnusedKeys(enKeys, usedKeys);
const unusedKeysOnlyInLocales =

View file

@ -17,6 +17,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import type { LanguageDefinition } from '../../packages/cli/src/i18n/languages.js';
import {
checkI18n,
findForbiddenZhTwPatterns,
printCheckI18nResult,
shouldWriteUnusedKeysJson,
type CheckI18nOptions,
@ -341,6 +342,84 @@ describe('checkI18n', () => {
expect(result.stats.unusedKeys).toEqual([]);
});
it('flags Mainland-Chinese vocabulary and variant Traditional chars in zh-TW values', async () => {
const { localesDir, sourceDir } = makeFixture();
writeLocale(localesDir, 'en', {
Open: 'Open',
Server: 'Server',
Menu: 'Menu',
Disable: 'Disable',
Config: 'Config',
});
writeLocale(localesDir, 'zh', {
Open: '打开',
Server: '服务器',
Menu: '菜单',
Disable: '禁用',
Config: '配置',
});
writeLocale(localesDir, 'zh-TW', {
// Regressions we expect the check to catch
Open: '啓動', // variant Traditional 啓 (OpenCC s2t artifact)
Server: '服務器', // Mainland vocabulary
Menu: '菜單', // Mainland vocabulary
// Taiwan-standard vocabulary — must NOT be flagged
Disable: '禁用',
Config: '配置',
});
writeSource(
sourceDir,
"t('Open');\nt('Server');\nt('Menu');\nt('Disable');\nt('Config');\n",
);
const result = await checkI18n({
localesDir,
sourceDir,
supportedLanguages: languages('en', 'zh', 'zh-TW'),
mustTranslateKeys: [],
});
expect(result.errors).toContain(
'Non-Taiwan vocabulary in zh-TW.js at "Open": "啓" should be "啟"',
);
expect(result.errors).toContain(
'Non-Taiwan vocabulary in zh-TW.js at "Server": "服務器" should be "伺服器"',
);
expect(result.errors).toContain(
'Non-Taiwan vocabulary in zh-TW.js at "Menu": "菜單" should be "選單"',
);
expect(result.errors).not.toContainEqual(
expect.stringContaining('at "Disable"'),
);
expect(result.errors).not.toContainEqual(
expect.stringContaining('at "Config"'),
);
});
it('returns no findings for clean Taiwan Traditional translations', () => {
const findings = findForbiddenZhTwPatterns({
Open: '開啟',
Server: '伺服器',
Menu: '選單',
Disable: '禁用',
Config: '配置',
Link: '連結',
History: '歷史',
});
expect(findings).toEqual([]);
});
it('reports only the most specific pattern per value (no duplicate findings)', () => {
// `历史` (Simplified) overlaps with the single-char pattern `历`.
// We expect exactly one finding for the longer/more specific pattern.
const findings = findForbiddenZhTwPatterns({
History: '历史',
});
expect(findings).toEqual([
{ key: 'History', pattern: '历史', preferred: '歷史' },
]);
});
it('detects the unused-keys JSON flag from argv or env', () => {
const originalArgv = process.argv;
const originalEnv = process.env['QWEN_CHECK_I18N_WRITE_UNUSED_KEYS'];