mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-22 03:03:56 +00:00
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:
parent
7c2b51d28e
commit
02a65f90c4
4 changed files with 370 additions and 147 deletions
|
|
@ -145,6 +145,29 @@ User directory takes precedence over built-in translations.
|
|||
> Contributions are welcome! If you’d 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
|
||||
|
|
|
|||
|
|
@ -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 Code:VS 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 = "..."':
|
||||
'TOML:prompt = "..." / description = "..."',
|
||||
'Markdown: YAML frontmatter + content': 'Markdown:YAML 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 Key,Coding 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': '管理擴展設置',
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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'];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue