From 50c815fa500576747f8bb330e08119eeb8035a6a Mon Sep 17 00:00:00 2001
From: han <2992336417@qq.com>
Date: Thu, 9 Jul 2026 18:52:31 +0800
Subject: [PATCH 1/6] fix(cli): localize approval mode UI labels
---
packages/cli/src/i18n/locales/en.js | 2 ++
packages/cli/src/i18n/locales/zh-TW.js | 4 ++-
packages/cli/src/i18n/locales/zh.js | 4 ++-
.../components/AutoAcceptIndicator.test.tsx | 6 +++--
.../src/ui/components/AutoAcceptIndicator.tsx | 2 +-
.../ui/hooks/useAutoAcceptIndicator.test.ts | 25 ++++++++++++++++++-
.../src/ui/hooks/useAutoAcceptIndicator.ts | 11 ++++----
.../src/ui/utils/approvalModeDisplay.test.ts | 16 ++++--------
.../cli/src/ui/utils/approvalModeDisplay.ts | 8 +++++-
9 files changed, 55 insertions(+), 23 deletions(-)
diff --git a/packages/cli/src/i18n/locales/en.js b/packages/cli/src/i18n/locales/en.js
index 120c9870c8a..ef29e404cd7 100644
--- a/packages/cli/src/i18n/locales/en.js
+++ b/packages/cli/src/i18n/locales/en.js
@@ -233,6 +233,8 @@ export default {
'Shell mode': 'Shell mode',
'YOLO mode': 'YOLO mode',
'Auto mode': 'Auto mode',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
'plan mode': 'plan mode',
'auto-accept edits': 'auto-accept edits',
'Accepting edits': 'Accepting edits',
diff --git a/packages/cli/src/i18n/locales/zh-TW.js b/packages/cli/src/i18n/locales/zh-TW.js
index 52b499fad50..fbf2e59ea1d 100644
--- a/packages/cli/src/i18n/locales/zh-TW.js
+++ b/packages/cli/src/i18n/locales/zh-TW.js
@@ -219,7 +219,9 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
- 'Auto mode': 'Auto 模式',
+ 'Auto mode': '自動模式',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ '已啟用自動模式。\n LLM 分類器會評估每次工具呼叫 - 安全操作將自動批准,\n 有風險的操作將被阻止。退出:Shift+Tab 或 /approval-mode default。',
'plan mode': '規劃模式',
'auto-accept edits': '自動接受編輯',
'Accepting edits': '接受編輯',
diff --git a/packages/cli/src/i18n/locales/zh.js b/packages/cli/src/i18n/locales/zh.js
index 87289f76853..8d423660568 100644
--- a/packages/cli/src/i18n/locales/zh.js
+++ b/packages/cli/src/i18n/locales/zh.js
@@ -223,7 +223,9 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
- 'Auto mode': 'Auto 模式',
+ 'Auto mode': '自动模式',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ '已启用自动模式。\n LLM 分类器会评估每次工具调用 - 安全操作将自动批准,\n 有风险的操作将被阻止。退出:Shift+Tab 或 /approval-mode default。',
'plan mode': '规划模式',
'auto-accept edits': '自动接受编辑',
'Accepting edits': '接受编辑',
diff --git a/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx b/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
index e9f58f49ad7..7bbf523a3ee 100644
--- a/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
+++ b/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
@@ -33,11 +33,13 @@ describe('', () => {
expect(lastFrame()).toContain('auto-accept edits');
});
- it('renders AUTO mode indicator', () => {
+ it('renders AUTO mode indicator with the localized label', () => {
const { lastFrame } = render(
,
);
- expect(lastFrame()).toContain('auto mode (classifier-evaluated)');
+ const frame = lastFrame()!;
+ expect(frame).toContain('Auto mode');
+ expect(frame).not.toContain('auto mode (classifier-evaluated)');
});
it('renders YOLO mode indicator', () => {
diff --git a/packages/cli/src/ui/components/AutoAcceptIndicator.tsx b/packages/cli/src/ui/components/AutoAcceptIndicator.tsx
index caa9234c177..6b1a851c59d 100644
--- a/packages/cli/src/ui/components/AutoAcceptIndicator.tsx
+++ b/packages/cli/src/ui/components/AutoAcceptIndicator.tsx
@@ -37,7 +37,7 @@ export const AutoAcceptIndicator: React.FC = ({
subText = cycleText;
break;
case ApprovalMode.AUTO:
- textContent = t('auto mode (classifier-evaluated)');
+ textContent = t('Auto mode');
subText = cycleText;
break;
case ApprovalMode.YOLO:
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
index 30d34677179..9d5056b7447 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
@@ -14,7 +14,10 @@ import {
type Mock,
} from 'vitest';
import { renderHook, act } from '@testing-library/react';
-import { useAutoAcceptIndicator } from './useAutoAcceptIndicator.js';
+import {
+ emitAutoModeEntryNotices,
+ useAutoAcceptIndicator,
+} from './useAutoAcceptIndicator.js';
import { Config, ApprovalMode } from '@qwen-code/qwen-code-core';
import type { Config as ActualConfigType } from '@qwen-code/qwen-code-core';
@@ -494,6 +497,26 @@ describe('useAutoAcceptIndicator', () => {
);
});
+ it('should emit the localizable AUTO mode entry notice', () => {
+ const mockAddItem = vi.fn();
+
+ emitAutoModeEntryNotices({
+ config: mockConfigInstance as unknown as ActualConfigType,
+ addItem: mockAddItem,
+ });
+
+ expect(mockAddItem).toHaveBeenCalledWith(
+ {
+ type: MessageType.INFO,
+ text:
+ 'Auto mode enabled.\n' +
+ ' An LLM classifier evaluates each tool call - safe actions auto-approve,\n' +
+ ' risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
+ },
+ expect.any(Number),
+ );
+ });
+
it('should not cycle approval mode on Windows when shouldBlockTab returns true', () => {
const originalPlatform = process.platform;
Object.defineProperty(process, 'platform', {
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
index 7e2e5b3bb95..3e56429d8fa 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
@@ -14,11 +14,12 @@ import { useKeypress } from './useKeypress.js';
import type { HistoryItemWithoutId } from '../types.js';
import { MessageType } from '../types.js';
import { type LoadedSettings, SettingScope } from '../../config/settings.js';
+import { t } from '../../i18n/index.js';
-const AUTO_MODE_FIRST_TIME_MESSAGE =
- 'Auto mode enabled.\n' +
- ' An LLM classifier evaluates each tool call — safe actions auto-approve,\n' +
- ' risky ones are blocked. Exit: Shift+Tab or /approval-mode default.';
+const getAutoModeFirstTimeMessage = () =>
+ t(
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
+ );
export interface UseAutoAcceptIndicatorArgs {
config: Config;
@@ -145,7 +146,7 @@ export function emitAutoModeEntryNotices(opts: {
const acknowledged = settings?.merged.ui?.autoModeAcknowledged === true;
if (!acknowledged) {
addItem(
- { type: MessageType.INFO, text: AUTO_MODE_FIRST_TIME_MESSAGE },
+ { type: MessageType.INFO, text: getAutoModeFirstTimeMessage() },
now,
);
if (settings) {
diff --git a/packages/cli/src/ui/utils/approvalModeDisplay.test.ts b/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
index 52436927dfd..d740a0f166c 100644
--- a/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
+++ b/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
@@ -13,20 +13,14 @@ import {
describe('approval mode display', () => {
describe('formatApprovalModeName', () => {
- it('formats yolo as uppercase', () => {
- expect(formatApprovalModeName(ApprovalMode.YOLO)).toBe('YOLO');
- });
-
- it('formats default mode as a friendly name', () => {
+ it('formats all modes as friendly names', () => {
+ expect(formatApprovalModeName(ApprovalMode.PLAN)).toBe('plan mode');
expect(formatApprovalModeName(ApprovalMode.DEFAULT)).toBe(
'Ask permissions',
);
- });
-
- it('falls back to the raw mode value for modes without a custom name', () => {
- expect(formatApprovalModeName(ApprovalMode.PLAN)).toBe('plan');
- expect(formatApprovalModeName(ApprovalMode.AUTO_EDIT)).toBe('auto-edit');
- expect(formatApprovalModeName(ApprovalMode.AUTO)).toBe('auto');
+ expect(formatApprovalModeName(ApprovalMode.AUTO_EDIT)).toBe('Auto Edit');
+ expect(formatApprovalModeName(ApprovalMode.AUTO)).toBe('Auto mode');
+ expect(formatApprovalModeName(ApprovalMode.YOLO)).toBe('YOLO');
});
});
diff --git a/packages/cli/src/ui/utils/approvalModeDisplay.ts b/packages/cli/src/ui/utils/approvalModeDisplay.ts
index 7c61dfe8f7f..336dd68638e 100644
--- a/packages/cli/src/ui/utils/approvalModeDisplay.ts
+++ b/packages/cli/src/ui/utils/approvalModeDisplay.ts
@@ -9,10 +9,16 @@ import { t } from '../../i18n/index.js';
export function formatApprovalModeName(mode: ApprovalMode): string {
switch (mode) {
+ case ApprovalMode.PLAN:
+ return t('plan mode');
case ApprovalMode.DEFAULT:
return t('Ask permissions');
+ case ApprovalMode.AUTO_EDIT:
+ return t('Auto Edit');
+ case ApprovalMode.AUTO:
+ return t('Auto mode');
case ApprovalMode.YOLO:
- return 'YOLO';
+ return t('YOLO');
default:
return mode;
}
From e4a525656edce4ebcd33b00edf320490a73879ff Mon Sep 17 00:00:00 2001
From: han <2992336417@qq.com>
Date: Thu, 9 Jul 2026 20:48:54 +0800
Subject: [PATCH 2/6] fix(cli): address approval mode i18n review
---
packages/cli/src/i18n/locales/ca.js | 2 ++
packages/cli/src/i18n/locales/de.js | 2 ++
packages/cli/src/i18n/locales/en.js | 4 +--
packages/cli/src/i18n/locales/fr.js | 2 ++
packages/cli/src/i18n/locales/ja.js | 2 ++
packages/cli/src/i18n/locales/pt.js | 2 ++
packages/cli/src/i18n/locales/ru.js | 2 ++
packages/cli/src/i18n/locales/zh-TW.js | 4 +--
packages/cli/src/i18n/locales/zh.js | 4 +--
packages/cli/src/i18n/mustTranslateKeys.ts | 1 +
.../ui/hooks/useAutoAcceptIndicator.test.ts | 28 ++++++++++++++++++-
.../src/ui/hooks/useAutoAcceptIndicator.ts | 8 +++---
.../src/ui/utils/approvalModeDisplay.test.ts | 22 +++++++++++++--
.../cli/src/ui/utils/approvalModeDisplay.ts | 4 +--
14 files changed, 72 insertions(+), 15 deletions(-)
diff --git a/packages/cli/src/i18n/locales/ca.js b/packages/cli/src/i18n/locales/ca.js
index cc1b6f53259..80c6d7738da 100644
--- a/packages/cli/src/i18n/locales/ca.js
+++ b/packages/cli/src/i18n/locales/ca.js
@@ -23,6 +23,8 @@ export default {
'Shell mode': 'Mode shell',
'YOLO mode': 'Mode YOLO',
'Auto mode': 'Mode auto',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ "Mode auto activat.\n Un classificador LLM avalua cada crida d'eina — les accions segures s'aproven automàticament,\n les arriscades es bloquegen. Sortiu: Shift+Tab o /approval-mode default.",
'plan mode': 'mode de planificació',
'auto-accept edits': 'acceptació automàtica de canvis',
'Accepting edits': 'Acceptant canvis',
diff --git a/packages/cli/src/i18n/locales/de.js b/packages/cli/src/i18n/locales/de.js
index 137c8ed96ca..65b8e0a02a8 100644
--- a/packages/cli/src/i18n/locales/de.js
+++ b/packages/cli/src/i18n/locales/de.js
@@ -25,6 +25,8 @@ export default {
'Shell mode': 'Shell-Modus',
'YOLO mode': 'YOLO-Modus',
'Auto mode': 'Auto-Modus',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'Auto-Modus aktiviert.\n Ein LLM-Klassifikator bewertet jeden Tool-Aufruf — sichere Aktionen werden automatisch genehmigt,\n riskante werden blockiert. Beenden: Shift+Tab oder /approval-mode default.',
'plan mode': 'Planungsmodus',
'auto-accept edits': 'Änderungen automatisch akzeptieren',
'Accepting edits': 'Änderungen werden akzeptiert',
diff --git a/packages/cli/src/i18n/locales/en.js b/packages/cli/src/i18n/locales/en.js
index ef29e404cd7..4b5630d2ace 100644
--- a/packages/cli/src/i18n/locales/en.js
+++ b/packages/cli/src/i18n/locales/en.js
@@ -233,8 +233,8 @@ export default {
'Shell mode': 'Shell mode',
'YOLO mode': 'YOLO mode',
'Auto mode': 'Auto mode',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
'plan mode': 'plan mode',
'auto-accept edits': 'auto-accept edits',
'Accepting edits': 'Accepting edits',
diff --git a/packages/cli/src/i18n/locales/fr.js b/packages/cli/src/i18n/locales/fr.js
index 564eea679b1..b9defad82b7 100644
--- a/packages/cli/src/i18n/locales/fr.js
+++ b/packages/cli/src/i18n/locales/fr.js
@@ -23,6 +23,8 @@ export default {
'Shell mode': 'Mode shell',
'YOLO mode': 'Mode YOLO',
'Auto mode': 'Mode auto',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ "Mode auto activé.\n Un classificateur LLM évalue chaque appel d'outil — les actions sûres sont approuvées automatiquement,\n les actions risquées sont bloquées. Quitter : Shift+Tab ou /approval-mode default.",
'plan mode': 'mode plan',
'auto-accept edits': 'acceptation automatique des modifications',
'Accepting edits': 'Acceptation des modifications',
diff --git a/packages/cli/src/i18n/locales/ja.js b/packages/cli/src/i18n/locales/ja.js
index aa6b9c38201..bdc9384f4ac 100644
--- a/packages/cli/src/i18n/locales/ja.js
+++ b/packages/cli/src/i18n/locales/ja.js
@@ -19,6 +19,8 @@ export default {
'Shell mode': 'シェルモード',
'YOLO mode': 'YOLOモード',
'Auto mode': 'Autoモード',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ '自動モードが有効です。\n LLM 分類器が各ツール呼び出しを評価します — 安全な操作は自動承認され、\n 危険な操作はブロックされます。終了: Shift+Tab または /approval-mode default。',
'plan mode': 'プランモード',
'auto-accept edits': '編集を自動承認',
'Accepting edits': '編集を承認中',
diff --git a/packages/cli/src/i18n/locales/pt.js b/packages/cli/src/i18n/locales/pt.js
index b1bd2d7593f..1913100f5af 100644
--- a/packages/cli/src/i18n/locales/pt.js
+++ b/packages/cli/src/i18n/locales/pt.js
@@ -19,6 +19,8 @@ export default {
'Shell mode': 'Modo shell',
'YOLO mode': 'Modo YOLO',
'Auto mode': 'Modo auto',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'Modo auto ativado.\n Um classificador LLM avalia cada chamada de ferramenta — ações seguras são aprovadas automaticamente,\n ações arriscadas são bloqueadas. Sair: Shift+Tab ou /approval-mode default.',
'plan mode': 'modo planejamento',
'auto-accept edits': 'aceitar edições automaticamente',
'Accepting edits': 'Aceitando edições',
diff --git a/packages/cli/src/i18n/locales/ru.js b/packages/cli/src/i18n/locales/ru.js
index acfe059665d..afae3ca5528 100644
--- a/packages/cli/src/i18n/locales/ru.js
+++ b/packages/cli/src/i18n/locales/ru.js
@@ -25,6 +25,8 @@ export default {
'Shell mode': 'Режим терминала',
'YOLO mode': 'Режим YOLO',
'Auto mode': 'Автоматический режим',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'Автоматический режим включен.\n LLM-классификатор оценивает каждый вызов инструмента — безопасные действия утверждаются автоматически,\n рискованные блокируются. Выход: Shift+Tab или /approval-mode default.',
'plan mode': 'Режим планирования',
'auto-accept edits': 'Режим принятия правок',
'Accepting edits': 'Принятие правок',
diff --git a/packages/cli/src/i18n/locales/zh-TW.js b/packages/cli/src/i18n/locales/zh-TW.js
index fbf2e59ea1d..9da6aa55bad 100644
--- a/packages/cli/src/i18n/locales/zh-TW.js
+++ b/packages/cli/src/i18n/locales/zh-TW.js
@@ -220,8 +220,8 @@ export default {
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
'Auto mode': '自動模式',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
- '已啟用自動模式。\n LLM 分類器會評估每次工具呼叫 - 安全操作將自動批准,\n 有風險的操作將被阻止。退出:Shift+Tab 或 /approval-mode default。',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ '已啟用自動模式。\n LLM 分類器會評估每次工具呼叫 — 安全操作將自動批准,\n 有風險的操作將被阻止。退出:Shift+Tab 或 /approval-mode default。',
'plan mode': '規劃模式',
'auto-accept edits': '自動接受編輯',
'Accepting edits': '接受編輯',
diff --git a/packages/cli/src/i18n/locales/zh.js b/packages/cli/src/i18n/locales/zh.js
index 8d423660568..ed53e1fa5c0 100644
--- a/packages/cli/src/i18n/locales/zh.js
+++ b/packages/cli/src/i18n/locales/zh.js
@@ -224,8 +224,8 @@ export default {
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
'Auto mode': '自动模式',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
- '已启用自动模式。\n LLM 分类器会评估每次工具调用 - 安全操作将自动批准,\n 有风险的操作将被阻止。退出:Shift+Tab 或 /approval-mode default。',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ '已启用自动模式。\n LLM 分类器会评估每次工具调用 — 安全操作将自动批准,\n 有风险的操作将被阻止。退出:Shift+Tab 或 /approval-mode default。',
'plan mode': '规划模式',
'auto-accept edits': '自动接受编辑',
'Accepting edits': '接受编辑',
diff --git a/packages/cli/src/i18n/mustTranslateKeys.ts b/packages/cli/src/i18n/mustTranslateKeys.ts
index cfb6b7538cf..ebb9cbc3018 100644
--- a/packages/cli/src/i18n/mustTranslateKeys.ts
+++ b/packages/cli/src/i18n/mustTranslateKeys.ts
@@ -94,6 +94,7 @@ export const MUST_TRANSLATE_KEYS = [
'? for shortcuts',
'Invalid approval mode "{{arg}}". Valid modes: {{modes}}',
'Approval mode set to "{{mode}}"',
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
"Set up Qwen Code's status line UI",
'Cached (included in Input): {{tokens}}',
'By source:',
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
index 9d5056b7447..e0eda8da394 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
@@ -24,6 +24,7 @@ import type { Config as ActualConfigType } from '@qwen-code/qwen-code-core';
import type { Key } from './useKeypress.js';
import { useKeypress } from './useKeypress.js';
import { MessageType } from '../types.js';
+import { setLanguageAsync } from '../../i18n/index.js';
vi.mock('./useKeypress.js');
@@ -510,13 +511,38 @@ describe('useAutoAcceptIndicator', () => {
type: MessageType.INFO,
text:
'Auto mode enabled.\n' +
- ' An LLM classifier evaluates each tool call - safe actions auto-approve,\n' +
+ ' An LLM classifier evaluates each tool call — safe actions auto-approve,\n' +
' risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
},
expect.any(Number),
);
});
+ it('should emit the AUTO mode entry notice with the active locale', async () => {
+ await setLanguageAsync('zh');
+ try {
+ const mockAddItem = vi.fn();
+
+ emitAutoModeEntryNotices({
+ config: mockConfigInstance as unknown as ActualConfigType,
+ addItem: mockAddItem,
+ });
+
+ expect(mockAddItem).toHaveBeenCalledWith(
+ {
+ type: MessageType.INFO,
+ text:
+ '已启用自动模式。\n' +
+ ' LLM 分类器会评估每次工具调用 — 安全操作将自动批准,\n' +
+ ' 有风险的操作将被阻止。退出:Shift+Tab 或 /approval-mode default。',
+ },
+ expect.any(Number),
+ );
+ } finally {
+ await setLanguageAsync('en');
+ }
+ });
+
it('should not cycle approval mode on Windows when shouldBlockTab returns true', () => {
const originalPlatform = process.platform;
Object.defineProperty(process, 'platform', {
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
index 3e56429d8fa..922e9f6660d 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
@@ -16,10 +16,10 @@ import { MessageType } from '../types.js';
import { type LoadedSettings, SettingScope } from '../../config/settings.js';
import { t } from '../../i18n/index.js';
-const getAutoModeFirstTimeMessage = () =>
- t(
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call - safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
- );
+const AUTO_MODE_FIRST_TIME_MESSAGE_KEY =
+ 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.';
+
+const getAutoModeFirstTimeMessage = () => t(AUTO_MODE_FIRST_TIME_MESSAGE_KEY);
export interface UseAutoAcceptIndicatorArgs {
config: Config;
diff --git a/packages/cli/src/ui/utils/approvalModeDisplay.test.ts b/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
index d740a0f166c..2369f5d0251 100644
--- a/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
+++ b/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
@@ -10,6 +10,7 @@ import {
formatApprovalModeDescription,
formatApprovalModeName,
} from './approvalModeDisplay.js';
+import { setLanguageAsync } from '../../i18n/index.js';
describe('approval mode display', () => {
describe('formatApprovalModeName', () => {
@@ -18,9 +19,26 @@ describe('approval mode display', () => {
expect(formatApprovalModeName(ApprovalMode.DEFAULT)).toBe(
'Ask permissions',
);
- expect(formatApprovalModeName(ApprovalMode.AUTO_EDIT)).toBe('Auto Edit');
+ expect(formatApprovalModeName(ApprovalMode.AUTO_EDIT)).toBe(
+ 'auto-accept edits',
+ );
expect(formatApprovalModeName(ApprovalMode.AUTO)).toBe('Auto mode');
- expect(formatApprovalModeName(ApprovalMode.YOLO)).toBe('YOLO');
+ expect(formatApprovalModeName(ApprovalMode.YOLO)).toBe('YOLO mode');
+ });
+
+ it('formats mode names with the active locale', async () => {
+ await setLanguageAsync('zh');
+ try {
+ expect(formatApprovalModeName(ApprovalMode.PLAN)).toBe('规划模式');
+ expect(formatApprovalModeName(ApprovalMode.DEFAULT)).toBe('请求授权');
+ expect(formatApprovalModeName(ApprovalMode.AUTO_EDIT)).toBe(
+ '自动接受编辑',
+ );
+ expect(formatApprovalModeName(ApprovalMode.AUTO)).toBe('自动模式');
+ expect(formatApprovalModeName(ApprovalMode.YOLO)).toBe('YOLO 模式');
+ } finally {
+ await setLanguageAsync('en');
+ }
});
});
diff --git a/packages/cli/src/ui/utils/approvalModeDisplay.ts b/packages/cli/src/ui/utils/approvalModeDisplay.ts
index 336dd68638e..08255166d76 100644
--- a/packages/cli/src/ui/utils/approvalModeDisplay.ts
+++ b/packages/cli/src/ui/utils/approvalModeDisplay.ts
@@ -14,11 +14,11 @@ export function formatApprovalModeName(mode: ApprovalMode): string {
case ApprovalMode.DEFAULT:
return t('Ask permissions');
case ApprovalMode.AUTO_EDIT:
- return t('Auto Edit');
+ return t('auto-accept edits');
case ApprovalMode.AUTO:
return t('Auto mode');
case ApprovalMode.YOLO:
- return t('YOLO');
+ return t('YOLO mode');
default:
return mode;
}
From cb3e52d7ec5f065c83c28d3595f230e7632bd74f Mon Sep 17 00:00:00 2001
From: han <2992336417@qq.com>
Date: Thu, 9 Jul 2026 22:14:54 +0800
Subject: [PATCH 3/6] fix(cli): stabilize approval mode i18n key
---
packages/cli/src/i18n/locales/ca.js | 2 +-
packages/cli/src/i18n/locales/de.js | 2 +-
packages/cli/src/i18n/locales/en.js | 2 +-
packages/cli/src/i18n/locales/fr.js | 2 +-
packages/cli/src/i18n/locales/ja.js | 2 +-
packages/cli/src/i18n/locales/pt.js | 2 +-
packages/cli/src/i18n/locales/ru.js | 2 +-
packages/cli/src/i18n/locales/zh-TW.js | 2 +-
packages/cli/src/i18n/locales/zh.js | 2 +-
packages/cli/src/i18n/mustTranslateKeys.ts | 2 +-
packages/cli/src/ui/commands/approvalModeCommand.test.ts | 2 +-
packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts | 3 ++-
packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts | 5 +++--
scripts/check-i18n.ts | 7 ++++++-
14 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/packages/cli/src/i18n/locales/ca.js b/packages/cli/src/i18n/locales/ca.js
index 80c6d7738da..3040d562960 100644
--- a/packages/cli/src/i18n/locales/ca.js
+++ b/packages/cli/src/i18n/locales/ca.js
@@ -23,7 +23,7 @@ export default {
'Shell mode': 'Mode shell',
'YOLO mode': 'Mode YOLO',
'Auto mode': 'Mode auto',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
"Mode auto activat.\n Un classificador LLM avalua cada crida d'eina — les accions segures s'aproven automàticament,\n les arriscades es bloquegen. Sortiu: Shift+Tab o /approval-mode default.",
'plan mode': 'mode de planificació',
'auto-accept edits': 'acceptació automàtica de canvis',
diff --git a/packages/cli/src/i18n/locales/de.js b/packages/cli/src/i18n/locales/de.js
index 65b8e0a02a8..3bde41ca9c2 100644
--- a/packages/cli/src/i18n/locales/de.js
+++ b/packages/cli/src/i18n/locales/de.js
@@ -25,7 +25,7 @@ export default {
'Shell mode': 'Shell-Modus',
'YOLO mode': 'YOLO-Modus',
'Auto mode': 'Auto-Modus',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
'Auto-Modus aktiviert.\n Ein LLM-Klassifikator bewertet jeden Tool-Aufruf — sichere Aktionen werden automatisch genehmigt,\n riskante werden blockiert. Beenden: Shift+Tab oder /approval-mode default.',
'plan mode': 'Planungsmodus',
'auto-accept edits': 'Änderungen automatisch akzeptieren',
diff --git a/packages/cli/src/i18n/locales/en.js b/packages/cli/src/i18n/locales/en.js
index 4b5630d2ace..a65760898c5 100644
--- a/packages/cli/src/i18n/locales/en.js
+++ b/packages/cli/src/i18n/locales/en.js
@@ -233,7 +233,7 @@ export default {
'Shell mode': 'Shell mode',
'YOLO mode': 'YOLO mode',
'Auto mode': 'Auto mode',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
'plan mode': 'plan mode',
'auto-accept edits': 'auto-accept edits',
diff --git a/packages/cli/src/i18n/locales/fr.js b/packages/cli/src/i18n/locales/fr.js
index b9defad82b7..56c42e0ad0e 100644
--- a/packages/cli/src/i18n/locales/fr.js
+++ b/packages/cli/src/i18n/locales/fr.js
@@ -23,7 +23,7 @@ export default {
'Shell mode': 'Mode shell',
'YOLO mode': 'Mode YOLO',
'Auto mode': 'Mode auto',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
"Mode auto activé.\n Un classificateur LLM évalue chaque appel d'outil — les actions sûres sont approuvées automatiquement,\n les actions risquées sont bloquées. Quitter : Shift+Tab ou /approval-mode default.",
'plan mode': 'mode plan',
'auto-accept edits': 'acceptation automatique des modifications',
diff --git a/packages/cli/src/i18n/locales/ja.js b/packages/cli/src/i18n/locales/ja.js
index bdc9384f4ac..f6c3fb0141e 100644
--- a/packages/cli/src/i18n/locales/ja.js
+++ b/packages/cli/src/i18n/locales/ja.js
@@ -19,7 +19,7 @@ export default {
'Shell mode': 'シェルモード',
'YOLO mode': 'YOLOモード',
'Auto mode': 'Autoモード',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
'自動モードが有効です。\n LLM 分類器が各ツール呼び出しを評価します — 安全な操作は自動承認され、\n 危険な操作はブロックされます。終了: Shift+Tab または /approval-mode default。',
'plan mode': 'プランモード',
'auto-accept edits': '編集を自動承認',
diff --git a/packages/cli/src/i18n/locales/pt.js b/packages/cli/src/i18n/locales/pt.js
index 1913100f5af..561578f2df2 100644
--- a/packages/cli/src/i18n/locales/pt.js
+++ b/packages/cli/src/i18n/locales/pt.js
@@ -19,7 +19,7 @@ export default {
'Shell mode': 'Modo shell',
'YOLO mode': 'Modo YOLO',
'Auto mode': 'Modo auto',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
'Modo auto ativado.\n Um classificador LLM avalia cada chamada de ferramenta — ações seguras são aprovadas automaticamente,\n ações arriscadas são bloqueadas. Sair: Shift+Tab ou /approval-mode default.',
'plan mode': 'modo planejamento',
'auto-accept edits': 'aceitar edições automaticamente',
diff --git a/packages/cli/src/i18n/locales/ru.js b/packages/cli/src/i18n/locales/ru.js
index afae3ca5528..430f2fe4b7d 100644
--- a/packages/cli/src/i18n/locales/ru.js
+++ b/packages/cli/src/i18n/locales/ru.js
@@ -25,7 +25,7 @@ export default {
'Shell mode': 'Режим терминала',
'YOLO mode': 'Режим YOLO',
'Auto mode': 'Автоматический режим',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
'Автоматический режим включен.\n LLM-классификатор оценивает каждый вызов инструмента — безопасные действия утверждаются автоматически,\n рискованные блокируются. Выход: Shift+Tab или /approval-mode default.',
'plan mode': 'Режим планирования',
'auto-accept edits': 'Режим принятия правок',
diff --git a/packages/cli/src/i18n/locales/zh-TW.js b/packages/cli/src/i18n/locales/zh-TW.js
index 9da6aa55bad..5bc963e8fc4 100644
--- a/packages/cli/src/i18n/locales/zh-TW.js
+++ b/packages/cli/src/i18n/locales/zh-TW.js
@@ -220,7 +220,7 @@ export default {
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
'Auto mode': '自動模式',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
'已啟用自動模式。\n LLM 分類器會評估每次工具呼叫 — 安全操作將自動批准,\n 有風險的操作將被阻止。退出:Shift+Tab 或 /approval-mode default。',
'plan mode': '規劃模式',
'auto-accept edits': '自動接受編輯',
diff --git a/packages/cli/src/i18n/locales/zh.js b/packages/cli/src/i18n/locales/zh.js
index ed53e1fa5c0..a338b40074a 100644
--- a/packages/cli/src/i18n/locales/zh.js
+++ b/packages/cli/src/i18n/locales/zh.js
@@ -224,7 +224,7 @@ export default {
'Shell mode': 'Shell 模式',
'YOLO mode': 'YOLO 模式',
'Auto mode': '自动模式',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.':
+ 'auto_mode.entry_notice':
'已启用自动模式。\n LLM 分类器会评估每次工具调用 — 安全操作将自动批准,\n 有风险的操作将被阻止。退出:Shift+Tab 或 /approval-mode default。',
'plan mode': '规划模式',
'auto-accept edits': '自动接受编辑',
diff --git a/packages/cli/src/i18n/mustTranslateKeys.ts b/packages/cli/src/i18n/mustTranslateKeys.ts
index ebb9cbc3018..71fde07627c 100644
--- a/packages/cli/src/i18n/mustTranslateKeys.ts
+++ b/packages/cli/src/i18n/mustTranslateKeys.ts
@@ -94,7 +94,7 @@ export const MUST_TRANSLATE_KEYS = [
'? for shortcuts',
'Invalid approval mode "{{arg}}". Valid modes: {{modes}}',
'Approval mode set to "{{mode}}"',
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
+ 'auto_mode.entry_notice',
"Set up Qwen Code's status line UI",
'Cached (included in Input): {{tokens}}',
'By source:',
diff --git a/packages/cli/src/ui/commands/approvalModeCommand.test.ts b/packages/cli/src/ui/commands/approvalModeCommand.test.ts
index 77fbe2b4d93..ebe78d6f053 100644
--- a/packages/cli/src/ui/commands/approvalModeCommand.test.ts
+++ b/packages/cli/src/ui/commands/approvalModeCommand.test.ts
@@ -91,7 +91,7 @@ describe('approvalModeCommand', () => {
expect(result.type).toBe('message');
expect(result.messageType).toBe('info');
- expect(result.content).toContain('auto-edit');
+ expect(result.content).toContain('auto-accept edits');
expect(mockSetApprovalMode).toHaveBeenCalledWith('auto-edit');
});
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
index e0eda8da394..5de0a3c73d6 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
@@ -498,7 +498,8 @@ describe('useAutoAcceptIndicator', () => {
);
});
- it('should emit the localizable AUTO mode entry notice', () => {
+ it('should emit the localizable AUTO mode entry notice', async () => {
+ await setLanguageAsync('en');
const mockAddItem = vi.fn();
emitAutoModeEntryNotices({
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
index 922e9f6660d..9b86b922b37 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
@@ -16,8 +16,7 @@ import { MessageType } from '../types.js';
import { type LoadedSettings, SettingScope } from '../../config/settings.js';
import { t } from '../../i18n/index.js';
-const AUTO_MODE_FIRST_TIME_MESSAGE_KEY =
- 'Auto mode enabled.\n An LLM classifier evaluates each tool call — safe actions auto-approve,\n risky ones are blocked. Exit: Shift+Tab or /approval-mode default.';
+const AUTO_MODE_FIRST_TIME_MESSAGE_KEY = 'auto_mode.entry_notice';
const getAutoModeFirstTimeMessage = () => t(AUTO_MODE_FIRST_TIME_MESSAGE_KEY);
@@ -166,6 +165,8 @@ export function emitAutoModeEntryNotices(opts: {
stripped &&
(stripped.persistent.length > 0 || stripped.session.length > 0)
) {
+ // Intentionally untranslated operational notice: rule text is copied from
+ // user/session allow-rule configuration and may contain command syntax.
const lines = [
'ℹ Auto mode temporarily disabled these allow rules',
' (they would bypass the classifier):',
diff --git a/scripts/check-i18n.ts b/scripts/check-i18n.ts
index eb9109e6ecb..719bb5f4074 100644
--- a/scripts/check-i18n.ts
+++ b/scripts/check-i18n.ts
@@ -63,6 +63,11 @@ export interface PrintCheckI18nOptions {
const __dirname = dirname(fileURLToPath(import.meta.url));
const WRITE_UNUSED_KEYS_FLAG = '--write-unused-locale-keys';
const WRITE_UNUSED_KEYS_ENV = 'QWEN_CHECK_I18N_WRITE_UNUSED_KEYS';
+const EN_SEMANTIC_KEY_EXCEPTIONS: ReadonlySet = new Set([
+ // Multi-line copy is intentionally keyed by a stable identifier so wording
+ // changes do not silently break locale lookup.
+ 'auto_mode.entry_notice',
+]);
export function shouldWriteUnusedKeysJson(): boolean {
return (
@@ -288,7 +293,7 @@ function checkKeyValueConsistency(enTranslations: TranslationDict): string[] {
continue;
}
- if (key !== value) {
+ if (key !== value && !EN_SEMANTIC_KEY_EXCEPTIONS.has(key)) {
errors.push(`Key-value mismatch in en.js: "${key}" !== "${value}"`);
}
}
From 999fef33ac34fdc27d5bdf8e04112b2b7c646a1a Mon Sep 17 00:00:00 2001
From: han <2992336417@qq.com>
Date: Fri, 10 Jul 2026 09:35:37 +0800
Subject: [PATCH 4/6] test(cli): cover approval mode i18n follow-up
---
.../ui/hooks/useAutoAcceptIndicator.test.ts | 53 +++++++++++++++++++
scripts/check-i18n.ts | 9 ++++
scripts/tests/check-i18n.test.ts | 30 +++++++++++
3 files changed, 92 insertions(+)
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
index 5de0a3c73d6..99d1695eef4 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
@@ -25,6 +25,7 @@ import type { Key } from './useKeypress.js';
import { useKeypress } from './useKeypress.js';
import { MessageType } from '../types.js';
import { setLanguageAsync } from '../../i18n/index.js';
+import { SettingScope, type LoadedSettings } from '../../config/settings.js';
vi.mock('./useKeypress.js');
@@ -59,6 +60,13 @@ interface MockConfigInstanceShape {
type UseKeypressHandler = (key: Key) => void;
+function createMockSettings(autoModeAcknowledged: boolean): LoadedSettings {
+ return {
+ merged: { ui: { autoModeAcknowledged } },
+ setValue: vi.fn(),
+ } as unknown as LoadedSettings;
+}
+
describe('useAutoAcceptIndicator', () => {
let mockConfigInstance: MockConfigInstanceShape;
let capturedUseKeypressHandler: UseKeypressHandler;
@@ -519,6 +527,51 @@ describe('useAutoAcceptIndicator', () => {
);
});
+ it('should persist acknowledgement after emitting the AUTO mode entry notice', async () => {
+ await setLanguageAsync('en');
+ const mockAddItem = vi.fn();
+ const mockSettings = createMockSettings(false);
+
+ emitAutoModeEntryNotices({
+ config: mockConfigInstance as unknown as ActualConfigType,
+ settings: mockSettings,
+ addItem: mockAddItem,
+ });
+
+ expect(mockAddItem).toHaveBeenCalledWith(
+ expect.objectContaining({
+ type: MessageType.INFO,
+ text: expect.stringContaining('Auto mode enabled.'),
+ }),
+ expect.any(Number),
+ );
+ expect(mockSettings.setValue).toHaveBeenCalledWith(
+ SettingScope.User,
+ 'ui.autoModeAcknowledged',
+ true,
+ );
+ });
+
+ it('should skip the AUTO mode entry notice after acknowledgement', async () => {
+ await setLanguageAsync('en');
+ const mockAddItem = vi.fn();
+ const mockSettings = createMockSettings(true);
+
+ emitAutoModeEntryNotices({
+ config: mockConfigInstance as unknown as ActualConfigType,
+ settings: mockSettings,
+ addItem: mockAddItem,
+ });
+
+ expect(mockAddItem).not.toHaveBeenCalledWith(
+ expect.objectContaining({
+ text: expect.stringContaining('Auto mode enabled.'),
+ }),
+ expect.any(Number),
+ );
+ expect(mockSettings.setValue).not.toHaveBeenCalled();
+ });
+
it('should emit the AUTO mode entry notice with the active locale', async () => {
await setLanguageAsync('zh');
try {
diff --git a/scripts/check-i18n.ts b/scripts/check-i18n.ts
index 719bb5f4074..d597c813be4 100644
--- a/scripts/check-i18n.ts
+++ b/scripts/check-i18n.ts
@@ -419,6 +419,15 @@ export async function checkI18n(
.map((language) => language.code),
);
+ const builtinMustTranslateKeySet = new Set(MUST_TRANSLATE_KEYS);
+ for (const key of EN_SEMANTIC_KEY_EXCEPTIONS) {
+ if (!builtinMustTranslateKeySet.has(key)) {
+ errors.push(
+ `English semantic key exception must be listed in MUST_TRANSLATE_KEYS: "${key}"`,
+ );
+ }
+ }
+
const localeDefinitions = supportedLanguages.map((language) => ({
code: language.code,
id: language.id,
diff --git a/scripts/tests/check-i18n.test.ts b/scripts/tests/check-i18n.test.ts
index 4069f265ef9..d6e7eda144f 100644
--- a/scripts/tests/check-i18n.test.ts
+++ b/scripts/tests/check-i18n.test.ts
@@ -274,6 +274,36 @@ describe('checkI18n', () => {
);
});
+ it('allows the AUTO mode entry notice semantic key in en.js while preserving mismatch errors', async () => {
+ const { localesDir, sourceDir } = makeFixture();
+ writeLocale(localesDir, 'en', {
+ 'auto_mode.entry_notice': 'Auto mode enabled.',
+ OrdinaryMismatch: 'Different English copy',
+ });
+ writeLocale(localesDir, 'fr', {
+ 'auto_mode.entry_notice': 'Mode auto activé.',
+ OrdinaryMismatch: 'Texte français',
+ });
+ writeSource(
+ sourceDir,
+ "t('auto_mode.entry_notice');\nt('OrdinaryMismatch');\n",
+ );
+
+ const result = await checkI18n({
+ localesDir,
+ sourceDir,
+ supportedLanguages: languages('en', 'fr'),
+ mustTranslateKeys: ['auto_mode.entry_notice'],
+ });
+
+ expect(result.errors).not.toContain(
+ 'Key-value mismatch in en.js: "auto_mode.entry_notice" !== "Auto mode enabled."',
+ );
+ expect(result.errors).toContain(
+ 'Key-value mismatch in en.js: "OrdinaryMismatch" !== "Different English copy"',
+ );
+ });
+
it('writes unused locale-only keys only when requested', async () => {
const { root, localesDir, sourceDir } = makeFixture();
writeLocale(localesDir, 'en', {
From e31130a2977f7a23a91ae99a700fa79e5d5d2762 Mon Sep 17 00:00:00 2001
From: han <2992336417@qq.com>
Date: Fri, 10 Jul 2026 14:52:16 +0800
Subject: [PATCH 5/6] test(cli): cover localized auto indicator
---
.../src/ui/components/AutoAcceptIndicator.test.tsx | 13 +++++++++++++
packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts | 13 +++++++++++--
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx b/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
index 7bbf523a3ee..e486bb353a7 100644
--- a/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
+++ b/packages/cli/src/ui/components/AutoAcceptIndicator.test.tsx
@@ -8,6 +8,7 @@ import { render } from 'ink-testing-library';
import { describe, it, expect } from 'vitest';
import { AutoAcceptIndicator } from './AutoAcceptIndicator.js';
import { ApprovalMode } from '@qwen-code/qwen-code-core';
+import { setLanguageAsync } from '../../i18n/index.js';
describe('', () => {
it('renders DEFAULT mode with pause badge and Ask permissions text', () => {
@@ -42,6 +43,18 @@ describe('', () => {
expect(frame).not.toContain('auto mode (classifier-evaluated)');
});
+ it('renders AUTO mode indicator with the active Chinese locale', async () => {
+ await setLanguageAsync('zh');
+ try {
+ const { lastFrame } = render(
+ ,
+ );
+ expect(lastFrame()).toContain('自动模式');
+ } finally {
+ await setLanguageAsync('en');
+ }
+ });
+
it('renders YOLO mode indicator', () => {
const { lastFrame } = render(
,
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
index 9b86b922b37..2d67d309f3d 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
@@ -17,8 +17,17 @@ import { type LoadedSettings, SettingScope } from '../../config/settings.js';
import { t } from '../../i18n/index.js';
const AUTO_MODE_FIRST_TIME_MESSAGE_KEY = 'auto_mode.entry_notice';
-
-const getAutoModeFirstTimeMessage = () => t(AUTO_MODE_FIRST_TIME_MESSAGE_KEY);
+const AUTO_MODE_FIRST_TIME_MESSAGE_FALLBACK =
+ 'Auto mode enabled.\n' +
+ ' An LLM classifier evaluates each tool call - safe actions auto-approve,\n' +
+ ' risky ones are blocked. Exit: Shift+Tab or /approval-mode default.';
+
+const getAutoModeFirstTimeMessage = () => {
+ const message = t(AUTO_MODE_FIRST_TIME_MESSAGE_KEY);
+ return message === AUTO_MODE_FIRST_TIME_MESSAGE_KEY
+ ? AUTO_MODE_FIRST_TIME_MESSAGE_FALLBACK
+ : message;
+};
export interface UseAutoAcceptIndicatorArgs {
config: Config;
From 4f95c9eb5cb1257c69950bd3d9b672bb7673bffd Mon Sep 17 00:00:00 2001
From: han <2992336417@qq.com>
Date: Fri, 10 Jul 2026 20:30:36 +0800
Subject: [PATCH 6/6] test(cli): address approval i18n suggestions
---
packages/cli/src/i18n/locales/ja.js | 2 +-
.../ui/hooks/useAutoAcceptIndicator.test.ts | 31 ++++++++++++++++++-
.../src/ui/hooks/useAutoAcceptIndicator.ts | 2 +-
.../src/ui/utils/approvalModeDisplay.test.ts | 23 ++++++++++++++
4 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/packages/cli/src/i18n/locales/ja.js b/packages/cli/src/i18n/locales/ja.js
index f6c3fb0141e..a775dcc788f 100644
--- a/packages/cli/src/i18n/locales/ja.js
+++ b/packages/cli/src/i18n/locales/ja.js
@@ -18,7 +18,7 @@ export default {
'@src/myFile.ts': '@src/myFile.ts',
'Shell mode': 'シェルモード',
'YOLO mode': 'YOLOモード',
- 'Auto mode': 'Autoモード',
+ 'Auto mode': '自動モード',
'auto_mode.entry_notice':
'自動モードが有効です。\n LLM 分類器が各ツール呼び出しを評価します — 安全な操作は自動承認され、\n 危険な操作はブロックされます。終了: Shift+Tab または /approval-mode default。',
'plan mode': 'プランモード',
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
index 99d1695eef4..56aa6436ffa 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.test.ts
@@ -24,7 +24,7 @@ import type { Config as ActualConfigType } from '@qwen-code/qwen-code-core';
import type { Key } from './useKeypress.js';
import { useKeypress } from './useKeypress.js';
import { MessageType } from '../types.js';
-import { setLanguageAsync } from '../../i18n/index.js';
+import { setLanguage, setLanguageAsync } from '../../i18n/index.js';
import { SettingScope, type LoadedSettings } from '../../config/settings.js';
vi.mock('./useKeypress.js');
@@ -527,6 +527,35 @@ describe('useAutoAcceptIndicator', () => {
);
});
+ it('should fall back to readable English when the entry notice key is not loaded', async () => {
+ const stderrWrite = vi
+ .spyOn(process.stderr, 'write')
+ .mockImplementation(() => true);
+ setLanguage('ca');
+ try {
+ const mockAddItem = vi.fn();
+
+ emitAutoModeEntryNotices({
+ config: mockConfigInstance as unknown as ActualConfigType,
+ addItem: mockAddItem,
+ });
+
+ expect(mockAddItem).toHaveBeenCalledWith(
+ {
+ type: MessageType.INFO,
+ text:
+ 'Auto mode enabled.\n' +
+ ' An LLM classifier evaluates each tool call — safe actions auto-approve,\n' +
+ ' risky ones are blocked. Exit: Shift+Tab or /approval-mode default.',
+ },
+ expect.any(Number),
+ );
+ } finally {
+ stderrWrite.mockRestore();
+ await setLanguageAsync('en');
+ }
+ });
+
it('should persist acknowledgement after emitting the AUTO mode entry notice', async () => {
await setLanguageAsync('en');
const mockAddItem = vi.fn();
diff --git a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
index 2d67d309f3d..4a681fd7e01 100644
--- a/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
+++ b/packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts
@@ -19,7 +19,7 @@ import { t } from '../../i18n/index.js';
const AUTO_MODE_FIRST_TIME_MESSAGE_KEY = 'auto_mode.entry_notice';
const AUTO_MODE_FIRST_TIME_MESSAGE_FALLBACK =
'Auto mode enabled.\n' +
- ' An LLM classifier evaluates each tool call - safe actions auto-approve,\n' +
+ ' An LLM classifier evaluates each tool call — safe actions auto-approve,\n' +
' risky ones are blocked. Exit: Shift+Tab or /approval-mode default.';
const getAutoModeFirstTimeMessage = () => {
diff --git a/packages/cli/src/ui/utils/approvalModeDisplay.test.ts b/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
index 2369f5d0251..fd3819f0a00 100644
--- a/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
+++ b/packages/cli/src/ui/utils/approvalModeDisplay.test.ts
@@ -63,5 +63,28 @@ describe('approval mode display', () => {
'Automatically approve all tools',
);
});
+
+ it('formats descriptions with the active locale', async () => {
+ await setLanguageAsync('zh');
+ try {
+ expect(formatApprovalModeDescription(ApprovalMode.PLAN)).toBe(
+ '仅分析,不修改文件或执行命令',
+ );
+ expect(formatApprovalModeDescription(ApprovalMode.DEFAULT)).toBe(
+ '需要批准文件编辑或 shell 命令',
+ );
+ expect(formatApprovalModeDescription(ApprovalMode.AUTO_EDIT)).toBe(
+ '自动批准文件编辑',
+ );
+ expect(formatApprovalModeDescription(ApprovalMode.AUTO)).toBe(
+ '使用分类器自动批准安全的工具调用',
+ );
+ expect(formatApprovalModeDescription(ApprovalMode.YOLO)).toBe(
+ '自动批准所有工具',
+ );
+ } finally {
+ await setLanguageAsync('en');
+ }
+ });
});
});