Skip to content

feat(cli): core built-in i18n coverage#3871

Merged
wenshao merged 12 commits into
QwenLM:mainfrom
shenyankm:sheny/feat-i18n-core
May 10, 2026
Merged

feat(cli): core built-in i18n coverage#3871
wenshao merged 12 commits into
QwenLM:mainfrom
shenyankm:sheny/feat-i18n-core

Conversation

@shenyankm

@shenyankm shenyankm commented May 6, 2026

Copy link
Copy Markdown
Contributor

Refs #3323

Summary

  • What changed: Expanded bundled UI language coverage across supported locales, localized high-visibility built-in slash-command descriptions and UI labels, added optional AI translation with per-language caching for dynamic slash command descriptions from skills/files/extensions/MCP prompts, added /language translate on|off|status|cache, fixed check-i18n so normal validation no longer rewrites the tracked unused-key JSON report, restored Arena agent completion metadata, tightened locale key diagnostics, and hardened JSONL reader cleanup.
  • Why it changed: Non-English UI mode still showed English command descriptions, dynamic commands had no localization path, local i18n validation dirtied the working tree, and review found follow-up risks around Arena result display, locale parity visibility, and JSONL stream cleanup validation.
  • Reviewer focus: Getter-based t() descriptions for built-in commands, locale loading/fallback behavior, DynamicCommandLocalizationService batching/cache/fallback design, /language translate cache routing, the dynamic translation opt-in setting, mustTranslateKeys/check-i18n coverage, Arena result card metadata preservation, JSONL reader cleanup, and custom auth provider labels in the header.

Validation

  • Commands run:
    cd packages/cli && npx vitest run src/ui/commands/arenaCommand.test.ts src/ui/commands/arenaCommand.agentComplete.test.ts src/ui/hooks/slashCommandProcessor.test.ts src/services/DynamicCommandLocalizationService.test.ts src/ui/commands/languageCommand.test.ts src/ui/components/SuggestionsDisplay.test.tsx src/i18n/index.test.ts src/i18n/mustTranslateKeys.test.ts
    cd packages/core && npx vitest run src/utils/jsonl-utils.test.ts
    npm run check-i18n --workspace=packages/cli
    npx eslint scripts/check-i18n.ts packages/cli/src/ui/commands/arenaCommand.agentComplete.test.ts packages/cli/src/ui/hooks/slashCommandProcessor.test.ts packages/core/src/utils/jsonl-utils.ts packages/core/src/utils/jsonl-utils.test.ts --max-warnings 0
    git diff --check
    npm run build
    npm run typecheck
    gh pr checks 3871 --watch
  • Prompts / inputs used: N/A for built-in strings. Dynamic descriptions are translated through generateJson using the configured fast model when general.dynamicCommandTranslation is enabled.
  • Expected result: Required built-in strings are translated for supported non-English UI languages; dynamic command descriptions translate and cache per language when enabled; cache refresh/clear works through /language translate cache; check-i18n passes without modifying tracked files by default; Arena completion cards retain diff/file/approach metadata; JSONL readers release file streams after full and early-stop reads; build, typecheck, and CI pass.
  • Observed result: CLI targeted tests passed: 8 files, 158 tests. Core JSONL tests passed: 1 file, 22 tests. check-i18n passed, reported 1112 total keys, locale coverage from 94.8% to 98.7%, warnings for non-required missing/unused keys, and did not write the JSON report by default. ESLint, git diff --check, npm run build, and npm run typecheck passed on Windows. GitHub CI passed CodeQL, Lint, and Test on macOS, Ubuntu, and Windows for the latest push.
  • Quickest reviewer verification path: Set /language ui zh, open slash-command suggestions, and confirm built-in descriptions are localized. Enable dynamic translation with /language translate on, then use /language translate cache refresh and /language translate cache clear. Run npm run check-i18n --workspace=packages/cli and confirm it does not modify scripts/unused-keys-only-in-locales.json unless --write-unused-locale-keys or QWEN_CHECK_I18N_WRITE_UNUSED_KEYS=1 is used. Run the Arena and JSONL targeted tests above to verify the review follow-ups.
  • Evidence (output, logs, screenshots, video, JSON, before/after, etc.): Local output showed all listed targeted tests passing. The new Arena regression test emits an AGENT_COMPLETE event and asserts diffSummary, modifiedFiles, and approachSummary reach both the UI history item and chat recorder. The new slash-command processor test proves dynamically loaded commands use the localized command list when the setting is enabled. The new JSONL tests capture fs.createReadStream and assert streams are closed after readLines, read, and countLines.

Scope / Risk

  • Main risk or tradeoff: Runtime dynamic translation depends on the configured fast model; failures intentionally fall back to original English descriptions. Translation quality still needs reviewer spot-checking across locales.
  • Not covered / not validated: Full copy review for every bundled locale, packaged/container/sandbox E2E runs, Docker/Podman/Seatbelt runtime validation, and screenshots/video for the TUI flow.
  • Breaking changes / migration notes: No external API break expected. Dynamic command translation is off by default. AuthDisplayType now uses internal identifiers and maps known values for display while preserving custom provider labels. The check-i18n JSON report is no longer written by default; use --write-unused-locale-keys or QWEN_CHECK_I18N_WRITE_UNUSED_KEYS=1 to update it intentionally. zh and zh-TW now keep strict locale key parity while newer locales warn on non-required missing or extra keys.

Testing Matrix

Windows macOS Linux
npm run ⚠️ ⚠️
npx ⚠️ ⚠️
Docker ⚠️ ⚠️ ⚠️
Podman ⚠️ N/A N/A
Seatbelt ⚠️ N/A N/A

Testing matrix notes:

  • Targeted npx tests, npm run check-i18n, targeted ESLint, git diff --check, build, and typecheck were run locally on Windows.
  • GitHub CI passed CodeQL, Lint, and Test on macOS, Ubuntu, and Windows for the latest push; this is CI validation, not manual local macOS/Linux package-runtime testing.
  • Container, Podman, Seatbelt, and local macOS/Linux package-runtime testing were not run manually.

Linked Issues / Bugs

Refs #3323

@shenyankm shenyankm changed the title feat(cli): comprehensive i18n — native locale coverage, cleanup, and dynamic translation feat(cli): core built-in i18n coverage May 6, 2026
shenyankm added a commit to shenyankm/qwen-code that referenced this pull request May 8, 2026
…onsDisplay

Added 22 missing translation keys to all 8 locale files (en, zh, zh-TW, ja, fr, de, pt, ru, ca) covering arena command error messages, usage prompts, and 'Loading suggestions...' text. Fixed i18n/index.test.ts bundled locale fallback test timeout (10s → 20s). Fixes CI test failures in arenaCommand.test.ts, SuggestionsDisplay.test.tsx, and i18n/index.test.ts on PR QwenLM#3871.
@shenyankm shenyankm force-pushed the sheny/feat-i18n-core branch from 32fdae2 to 0f8353b Compare May 8, 2026 04:07
@shenyankm shenyankm force-pushed the sheny/feat-i18n-core branch from b1321ab to 5f471cf Compare May 8, 2026 17:01
@shenyankm shenyankm marked this pull request as ready for review May 8, 2026 17:44

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

This PR adds core built-in i18n coverage with localized slash-command descriptions, AI-powered dynamic translation with per-language caching, and /language translate commands. The i18n architecture is well-designed, and the test coverage for new code is good. Build and PR-related tests pass.

Key findings (detailed in inline comments):

  1. DynamicCommandLocalizationService:113cacheLoaded flag set before async read completes, creating a race condition with concurrent cache operations.
  2. DynamicCommandLocalizationService:143cacheWriteQueue lacks error recovery; first write failure permanently breaks all future cache writes.
  3. DynamicCommandLocalizationService:294 — Batch translation partial results are discarded when a later batch fails, wasting LLM tokens.
  4. languages.ts:112resolveSupportedLanguage prefix matching depends on zh-TW appearing before zh in the array; fragile under reordering.
  5. nonInteractiveCli.test.ts:123 — Type error (TS2345) in mock types after SlashCommand interface changes.

No Critical issues found in the PR's changed files. The more serious findings from the broader codebase analysis (CommitAttributionService singleton isolation, Co-authored-by default-on injection, /branch rollback path) are in files not modified by this PR and should be addressed separately.

— DeepSeek/deepseek-v4-pro via Qwen Code /review

@shenyankm

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review. Addressed all five findings in 398be4a7d:

  1. Fixed the cache load race by adding a shared in-flight cacheLoadPromise; concurrent callers now wait for the same load, and cacheLoaded is only set after load completion.
  2. Added recovery for cacheWriteQueue failures so one failed cache write no longer prevents future writes.
  3. Preserved successful batch translation results when a later batch fails, and persist any successful translations already collected.
  4. Updated resolveSupportedLanguage to prefer the longest locale/code match, so zh-TW no longer depends on array ordering.
  5. Fixed the nonInteractiveCli.test.ts mock typing to match readonly SlashCommand[].

Also added focused regression tests for the cache race, write recovery, partial batch persistence, and zh-TW / zh_TW / zh-TW.UTF-8 language resolution.

@shenyankm shenyankm dismissed a stale review via 2e27122 May 10, 2026 03:02
Comment thread packages/cli/src/ui/components/background-view/BackgroundTasksDialog.tsx Outdated
Comment thread packages/cli/src/ui/components/messages/SummaryMessage.tsx
Comment thread packages/cli/src/ui/commands/languageCommand.ts
@shenyankm shenyankm requested a review from wenshao May 10, 2026 03:16

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

无法映射到 diff 行的问题

[Critical] scripts/check-i18n.ts 进行了重大重写(多语言检查、MUST_TRANSLATE_KEYS 强制校验、严格/宽松 key parity),但 scripts/ 目录下完全没有测试文件。多个分支路径(locale 加载失败、en.js 缺失、严格 vs 宽松 parity、--write-unused-locale-keys 标志等)完全依赖手动验证。建议添加 scripts/tests/check-i18n.test.ts

[Suggestion] BackgroundTasksDialog.tsxDreamDetailBody 组件使用硬编码英文字符串('Dream''Sessions reviewing''Progress''Lock release warning' 等),未通过 t() 国际化。这些 key 在任何 locale 文件中均不存在。请在 en.js 中添加翻译键并使用 t() 调用。

— DeepSeek/deepseek-v4-pro via Qwen Code /review

@wenshao wenshao dismissed a stale review May 10, 2026 06:43

test

@wenshao

wenshao commented May 10, 2026

Copy link
Copy Markdown
Collaborator

抱歉 @shenyankm,刚才两条测试评论("Test comment" 和 "test")是 code review 工具出错导致的误发,并非真实 review 意见,已删除。请忽略它们,给你带来困扰很抱歉。

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review @ HEAD 2e27122d

[Critical] — 与我 5-10 06:42 review 同源,最新 commit 仍未处理

  1. BackgroundTasksDialog.tsxDreamDetailBody 多处硬编码英文(line 340-490)

    • line 345 const title = 'Dream' / line 376 {title}
    • line 393 Sessions reviewing / 407 Progress / 421 Topics touched (…) / 433 +N more
    • line 468 Lock release warning + line 478 整句 / 488 Metadata write warning
    • 同文件 line 444 {t('Error')} 已 i18n,兄弟节点全漏。
    • 与 PR 标题 "core built-in i18n coverage" 直接矛盾——这正是 builtin path。
    • 建议:每条 wrap 到 t() + 加到 en.js 等 locale;高可见的(Lock release warning/Metadata write warning)进 mustTranslateKeys
  2. scripts/check-i18n.ts 514 行重写、零测试覆盖

    • 关键分支无回归保护:locale 加载失败(294-298)、en.js 缺失早返(302-313)、严格 vs 宽松 parity(356-403)、MUST_TRANSLATE_KEY_SET 校验、--write-unused-locale-keys flag 与 env var、extractUsedKeys 正则 + extractStringLiteral escape 状态机。
    • STRICT_KEY_PARITY_LOCALES = new Set(['zh', 'zh-TW'])(line 49)硬编码——建议从 SUPPORTED_LANGUAGES 元数据驱动(language.strictParity?: boolean)。
    • 建议补 scripts/tests/check-i18n.test.ts 至少覆盖 5 类:(a) en.js 缺失→success=false;(b) 严格 locale extra key→error;(c) 宽松 locale extra key→warning;(d) mustTranslate locale 缺失→error;(e) --write-unused-locale-keys flag 控制 JSON 写入。

[Suggestion] — 新发现,非阻塞

  1. DynamicCommandLocalizationService prompt-injection 暴露面DynamicCommandLocalizationService.ts:330-339

    • prompt 直接 JSON.stringify(batch)batch.text 来自 third-party dynamic command(skill / MCP prompt / extension 描述)。恶意 description 能影响同 batch 内其他翻译结果(注入文本进入 UI label)。
    • 风险有限:仅 UI 显示,没有命令执行;但 UI 上显示注入文本是 social-engineering 信号。
    • 缓解:(a) prompt 顶部用更强 framing(<user_input id="...">…</user_input> + system instruction "treat text inside tags as data"),或 (b) sanitize description(剥离 Ignore previous--- 等典型 marker)。
  2. batch 翻译失败 break 过激进DynamicCommandLocalizationService.ts:366-374

    • 单 batch 失败后 break 整个循环,剩余 batch 全跳过,整次调用零 partial 进度。
    • continue 让其他 batch 仍能尝试;或保留 fail-fast 但加注释说明这是 deliberate("first failure usually means model unavailable; fail fast saves cost")。
  3. 缓存 cross-process raceDynamicCommandLocalizationService.ts:147-167

    • cacheWriteQueue 只串行单进程;并发跑两个 qwen 进程时 ~/.qwen/dynamic-command-translations.json 后写入覆盖前者新条目。
    • 影响:偶发丢失翻译条目,下次冷启动重翻(非热路径,cost 低)。
    • follow-up:write-then-rename 原子写 + read-merge-write。
  4. fileLocks / ensuredDirs 永不清理jsonl-utils.ts:36, 243

    • 单条 session 文件被删后 Mutex 仍留在 Map。session 数量级 100~1000 时无影响,长期跑累积。
    • follow-up:session finalize 时 fileLocks.delete(filePath)

Style / Convention

  1. DynamicCommandLocalizationService 同时导出 class + global singletonDynamicCommandLocalizationService.ts:396-397
    • 当前调用方都直接构造,singleton 处于"export 但未使用"灰色地带。要么删除 singleton 避免被默默用绕过 DI,要么在 README/JSDoc 显式标明这是 cache-shared 单例契约。

测试

  • 新代码核心覆盖良好:DynamicCommandLocalizationService.test.tslanguageCommand.test.tsjsonl-utils.test.tsarenaCommand.agentComplete.test.tsslashCommandProcessor.test.tsSuggestionsDisplay.test.tsxi18n/index.test.tsmustTranslateKeys.test.ts,8 文件 158 cases 全 pass ✅。
  • 缺口:scripts/check-i18n.ts(见 #2)。

安全 / 性能

  • dynamic-command-translations.json 写在 Storage.getGlobalQwenDir() ✅。
  • Cache 文件 JSON.parse(raw) as CacheFile 后只校验 versionparsed.entries 直接 for-of 拷贝,损坏 cache 文件最坏只导致 UI 翻译异常,不影响安全。
  • extractUsedKeys / findKeysOnlyInLocales 各 glob 一次同样目录树,可在第一轮顺手 build reverse map 省一遍 — 优先级低(build-time tool)。

放行路径

#1#2 close 后即可 APPROVE:

  • BackgroundTasksDialog.DreamDetailBody 8 处硬编码 wrap 到 t()
  • scripts/tests/check-i18n.test.ts 覆盖上面列的 5 个核心分支。

其余 [Suggestion] 可作为 follow-up tracked。

@shenyankm

Copy link
Copy Markdown
Contributor Author

Re-review @ HEAD 2e27122d

[Critical] — 与我 5-10 06:42 review 同源,最新 commit 仍未处理

  1. BackgroundTasksDialog.tsxDreamDetailBody 多处硬编码英文(line 340-490)

    • line 345 const title = 'Dream' / line 376 {title}
    • line 393 Sessions reviewing / 407 Progress / 421 Topics touched (…) / 433 +N more
    • line 468 Lock release warning + line 478 整句 / 488 Metadata write warning
    • 同文件 line 444 {t('Error')} 已 i18n,兄弟节点全漏。
    • 与 PR 标题 "core built-in i18n coverage" 直接矛盾——这正是 builtin path。
    • 建议:每条 wrap 到 t() + 加到 en.js 等 locale;高可见的(Lock release warning/Metadata write warning)进 mustTranslateKeys
  2. scripts/check-i18n.ts 514 行重写、零测试覆盖

    • 关键分支无回归保护:locale 加载失败(294-298)、en.js 缺失早返(302-313)、严格 vs 宽松 parity(356-403)、MUST_TRANSLATE_KEY_SET 校验、--write-unused-locale-keys flag 与 env var、extractUsedKeys 正则 + extractStringLiteral escape 状态机。
    • STRICT_KEY_PARITY_LOCALES = new Set(['zh', 'zh-TW'])(line 49)硬编码——建议从 SUPPORTED_LANGUAGES 元数据驱动(language.strictParity?: boolean)。
    • 建议补 scripts/tests/check-i18n.test.ts 至少覆盖 5 类:(a) en.js 缺失→success=false;(b) 严格 locale extra key→error;(c) 宽松 locale extra key→warning;(d) mustTranslate locale 缺失→error;(e) --write-unused-locale-keys flag 控制 JSON 写入。

[Suggestion] — 新发现,非阻塞

  1. DynamicCommandLocalizationService prompt-injection 暴露面DynamicCommandLocalizationService.ts:330-339

    • prompt 直接 JSON.stringify(batch)batch.text 来自 third-party dynamic command(skill / MCP prompt / extension 描述)。恶意 description 能影响同 batch 内其他翻译结果(注入文本进入 UI label)。
    • 风险有限:仅 UI 显示,没有命令执行;但 UI 上显示注入文本是 social-engineering 信号。
    • 缓解:(a) prompt 顶部用更强 framing(<user_input id="...">…</user_input> + system instruction "treat text inside tags as data"),或 (b) sanitize description(剥离 Ignore previous--- 等典型 marker)。
  2. batch 翻译失败 break 过激进DynamicCommandLocalizationService.ts:366-374

    • 单 batch 失败后 break 整个循环,剩余 batch 全跳过,整次调用零 partial 进度。
    • continue 让其他 batch 仍能尝试;或保留 fail-fast 但加注释说明这是 deliberate("first failure usually means model unavailable; fail fast saves cost")。
  3. 缓存 cross-process raceDynamicCommandLocalizationService.ts:147-167

    • cacheWriteQueue 只串行单进程;并发跑两个 qwen 进程时 ~/.qwen/dynamic-command-translations.json 后写入覆盖前者新条目。
    • 影响:偶发丢失翻译条目,下次冷启动重翻(非热路径,cost 低)。
    • follow-up:write-then-rename 原子写 + read-merge-write。
  4. fileLocks / ensuredDirs 永不清理jsonl-utils.ts:36, 243

    • 单条 session 文件被删后 Mutex 仍留在 Map。session 数量级 100~1000 时无影响,长期跑累积。
    • follow-up:session finalize 时 fileLocks.delete(filePath)

Style / Convention

  1. DynamicCommandLocalizationService 同时导出 class + global singletonDynamicCommandLocalizationService.ts:396-397

    • 当前调用方都直接构造,singleton 处于"export 但未使用"灰色地带。要么删除 singleton 避免被默默用绕过 DI,要么在 README/JSDoc 显式标明这是 cache-shared 单例契约。

测试

  • 新代码核心覆盖良好:DynamicCommandLocalizationService.test.tslanguageCommand.test.tsjsonl-utils.test.tsarenaCommand.agentComplete.test.tsslashCommandProcessor.test.tsSuggestionsDisplay.test.tsxi18n/index.test.tsmustTranslateKeys.test.ts,8 文件 158 cases 全 pass ✅。
  • 缺口:scripts/check-i18n.ts(见 Where is the config saved? #2)。

安全 / 性能

  • dynamic-command-translations.json 写在 Storage.getGlobalQwenDir() ✅。
  • Cache 文件 JSON.parse(raw) as CacheFile 后只校验 versionparsed.entries 直接 for-of 拷贝,损坏 cache 文件最坏只导致 UI 翻译异常,不影响安全。
  • extractUsedKeys / findKeysOnlyInLocales 各 glob 一次同样目录树,可在第一轮顺手 build reverse map 省一遍 — 优先级低(build-time tool)。

放行路径

#1#2 close 后即可 APPROVE:

  • BackgroundTasksDialog.DreamDetailBody 8 处硬编码 wrap 到 t()
  • scripts/tests/check-i18n.test.ts 覆盖上面列的 5 个核心分支。

其余 [Suggestion] 可作为 follow-up tracked。

感谢您的详细复审!最新提交 707086569 处理了以下问题:

Critical:

  • 第 1 条:DreamDetailBody 国际化:所有硬编码英文字符串已用 t() 包裹,en.js 新增对应 key,并同步 8 种 locale。
  • 第 2 条:check-i18n.ts 测试覆盖:已重构为可测试架构,新增 scripts/tests/check-i18n.test.ts 覆盖 5 类核心路径,strictParity 改为 LanguageDefinition.strictParity 元数据驱动。

Suggestion 中也顺手处理了 3 项:

  • 第 3 条:prompt-injection:翻译 prompt 改为 XML <user_input> 框架,并加入转义和 untrusted source text 指令。
  • 第 4 条:batch 失败 break 过激进:已改为 continue,单 batch 失败不再阻断后续 batch。
  • 第 7 条:singleton 无说明:已添加 JSDoc 说明 process-wide 共享缓存语义。

其余第 5 条和第 6 条将作为 follow-up 跟进。

请重新审查,谢谢!

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ CI 在 Test (macOS/Ubuntu/Windows, Node 22.x) 均失败——可能与 tsc 类型错误有关。

其他需要关注的问题

isTranslationDict 将数组误判为有效翻译字典 (packages/cli/src/i18n/index.ts:48): typeof [] === 'object' 且数组有 numeric keys,导致 export default ['a','b'] 被当作合法翻译字典,所有翻译静默返回 undefined。建议添加 !Array.isArray(value) 检查。

getAvailableCommands 调用者未传 settings 参数 (packages/cli/src/utils/nonInteractiveHelpers.ts:204, packages/cli/src/nonInteractive/control/controllers/systemController.ts:447): 两处调用只传 3 个参数,缺少新增的可选 settings 参数。即使开启 dynamicCommandTranslation,非交互模式下的命令描述也永远不会翻译。建议传入 settings 或添加注释说明。

localizeCommands 缓存命中时仍无条件克隆 (packages/cli/src/services/DynamicCommandLocalizationService.ts:300): 已缓存所有描述时仍克隆全部命令(含递归子命令),可跳过。

— DeepSeek/deepseek-v4-pro via Qwen Code /review

Comment thread scripts/tests/check-i18n.test.ts Outdated
Comment thread scripts/tests/check-i18n.test.ts
Comment thread scripts/tests/check-i18n.test.ts Outdated
Comment thread packages/cli/src/i18n/index.ts Outdated
Comment thread scripts/check-i18n.ts Outdated
@shenyankm

Copy link
Copy Markdown
Contributor Author

⚠️ CI 在 Test (macOS/Ubuntu/Windows, Node 22.x) 均失败——可能与 tsc 类型错误有关。

其他需要关注的问题

isTranslationDict 将数组误判为有效翻译字典 (packages/cli/src/i18n/index.ts:48): typeof [] === 'object' 且数组有 numeric keys,导致 export default ['a','b'] 被当作合法翻译字典,所有翻译静默返回 undefined。建议添加 !Array.isArray(value) 检查。

getAvailableCommands 调用者未传 settings 参数 (packages/cli/src/utils/nonInteractiveHelpers.ts:204, packages/cli/src/nonInteractive/control/controllers/systemController.ts:447): 两处调用只传 3 个参数,缺少新增的可选 settings 参数。即使开启 dynamicCommandTranslation,非交互模式下的命令描述也永远不会翻译。建议传入 settings 或添加注释说明。

localizeCommands 缓存命中时仍无条件克隆 (packages/cli/src/services/DynamicCommandLocalizationService.ts:300): 已缓存所有描述时仍克隆全部命令(含递归子命令),可跳过。

— DeepSeek/deepseek-v4-pro via Qwen Code /review

感谢您的审阅。已针对 pullrequestreview-4259405150 中的所有反馈进行了处理:

  • 修复了 check-i18n.test.ts 中的 TypeScript 问题:移除了 .ts 文件的动态导入,改为常规导入 node:fs API,并将对 process.env 的访问方式切换为方括号表示法。
  • 在运行时 i18n 模块与 check-i18n 模块之间,共享了用于翻译模块导出及字典验证的辅助函数;同时统一了对数组和空对象的拒绝处理逻辑。
  • 针对非交互式路径及系统命令执行路径,透传了 settings 配置对象,从而确保动态命令翻译功能在这些场景下也能正常生效。
  • localizeCommands 函数进行了优化,避免了对未发生变更的命令分支进行不必要的克隆操作。

已在本地通过以下指令完成了验证:

  • npm run test:scripts
  • 针对 CLI 模块的特定 Vitest 测试文件
  • cd packages/cli && npm run typecheck
  • npm run build
  • npm run typecheck
  • npm run check-i18n

@shenyankm shenyankm requested a review from wenshao May 10, 2026 14:12

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review @ HEAD 508b48e94

13:16 review 提到的全部修复已落地:

  • isTranslationDict 重复定义 → 抽到共享 packages/cli/src/i18n/translationDict.ts,加了 !Array.isArray + Object.keys.length > 0scripts/check-i18n.ts 已 import 共享实现。
  • getAvailableCommands caller 缺 settingsnonInteractiveHelpers.ts / systemController.ts 两处已传 settings
  • localizeCommands cache-hit 仍无条件 clone → 改为按需 clone,未变化时返回原对象。
  • scripts/tests/check-i18n.test.ts.ts import / mkdtempSync 类型 / process.env 方括号 → 全部修正。

CI 全绿(CodeQL / Lint / Test macOS / Ubuntu / Windows)。所有 review threads 已 resolved。

10:00 review 提的 #3#7(prompt-injection 边界、batch fail-fast、cross-process race、fileLocks 清理、singleton 风格)作为非阻塞 follow-up 不再阻塞本次合入。

LGTM.

@wenshao wenshao merged commit 9bd5a01 into QwenLM:main May 10, 2026
7 checks passed
@shenyankm shenyankm deleted the sheny/feat-i18n-core branch May 10, 2026 14:49
tanzhenxin added a commit that referenced this pull request May 14, 2026
Removes the runtime LLM-translation path for dynamic slash command
descriptions added in #3871, along with its `general.dynamicCommandTranslation`
setting and the `/language translate` subcommand tree.

Keeps the built-in locale coverage from the same PR untouched. Localization
of dynamic command descriptions should be solved at the source (manifest
fields, not runtime model calls); see #4137 for the proposed alternative.
tanzhenxin added a commit that referenced this pull request May 14, 2026
Follow-up cleanup after the dynamic command translation revert.

CommandService.fromCommands was introduced by #3871 solely to wrap the
LLM-translated command list. With the LLM-translation path gone, it has
no remaining non-test callers — remove it and the matching test mock.

Also drop two assertions in languageCommand.test.ts that checked for the
absence of a top-level /language cache command. They tested a migration
state that never existed in this branch and now pass vacuously.
tanzhenxin added a commit that referenced this pull request May 15, 2026
* refactor(cli): revert dynamic slash command LLM translation (#4137)

Removes the runtime LLM-translation path for dynamic slash command
descriptions added in #3871, along with its `general.dynamicCommandTranslation`
setting and the `/language translate` subcommand tree.

Keeps the built-in locale coverage from the same PR untouched. Localization
of dynamic command descriptions should be solved at the source (manifest
fields, not runtime model calls); see #4137 for the proposed alternative.

* refactor(cli): drop translate prompts from mustTranslateKeys

Follow-up to the dynamic command translation revert: the 7 prompt keys
were stripped from every locale file in the previous commit, but the
allow-list in mustTranslateKeys still demanded them.

* refactor(cli): drop dead CommandService.fromCommands and vacuous tests

Follow-up cleanup after the dynamic command translation revert.

CommandService.fromCommands was introduced by #3871 solely to wrap the
LLM-translated command list. With the LLM-translation path gone, it has
no remaining non-test callers — remove it and the matching test mock.

Also drop two assertions in languageCommand.test.ts that checked for the
absence of a top-level /language cache command. They tested a migration
state that never existed in this branch and now pass vacuously.

* docs: drop /language translate references after revert

Two user-facing docs documented the /language translate subcommands
(status/on/off/cache refresh/clear) that were removed in the dynamic
command translation revert. Strip them so users following the docs
don't hit "Invalid command" errors.

* refactor(cli): drop unused localizeDescription field

The DynamicCommandLocalizationService that read this flag was removed in
the revert, leaving the field with five setters and zero readers. Drop the
field, its JSDoc, and the five `localizeDescription: true` assignments.
Also tidy the now-misleading `modelDescription` JSDoc and the stale
`reloadCommands` comment that referenced the removed feature.

* refactor(cli): drop unused getLanguageNameForTranslationTarget

The only caller was the removed DynamicCommandLocalizationService.
Remove the function from `i18n/languages.ts` and the matching
import + re-export from `i18n/index.ts`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants