mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
feat: Add i18n support for /settings, /theme
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
import { themeManager } from '../ui/themes/theme-manager.js';
|
||||
import { type LoadedSettings } from '../config/settings.js';
|
||||
import { t } from '../i18n/index.js';
|
||||
|
||||
/**
|
||||
* Validates the configured theme.
|
||||
@@ -15,7 +16,9 @@ import { type LoadedSettings } from '../config/settings.js';
|
||||
export function validateTheme(settings: LoadedSettings): string | null {
|
||||
const effectiveTheme = settings.merged.ui?.theme;
|
||||
if (effectiveTheme && !themeManager.findThemeByName(effectiveTheme)) {
|
||||
return `Theme "${effectiveTheme}" not found.`;
|
||||
return t('Theme "{{themeName}}" not found.', {
|
||||
themeName: effectiveTheme,
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ export default {
|
||||
'@': '@',
|
||||
'@src/myFile.ts': '@src/myFile.ts',
|
||||
'Shell mode': 'Shell mode',
|
||||
'YOLO mode': 'YOLO mode',
|
||||
'plan mode': 'plan mode',
|
||||
'auto-accept edits': 'auto-accept edits',
|
||||
'Accepting edits': 'Accepting edits',
|
||||
'(shift + tab to cycle)': '(shift + tab to cycle)',
|
||||
'Execute shell commands via {{symbol}} (e.g., {{example1}}) or use natural language (e.g., {{example2}}).':
|
||||
'Execute shell commands via {{symbol}} (e.g., {{example1}}) or use natural language (e.g., {{example2}}).',
|
||||
'!': '!',
|
||||
@@ -80,10 +85,23 @@ export default {
|
||||
'Analyzes the project and creates a tailored QWEN.md file.',
|
||||
'list available Qwen Code tools. Usage: /tools [desc]':
|
||||
'list available Qwen Code tools. Usage: /tools [desc]',
|
||||
'Available Qwen Code CLI tools:': 'Available Qwen Code CLI tools:',
|
||||
'No tools available': 'No tools available',
|
||||
'View or change the approval mode for tool usage':
|
||||
'View or change the approval mode for tool usage',
|
||||
'View or change the language setting': 'View or change the language setting',
|
||||
'change the theme': 'change the theme',
|
||||
'Select Theme': 'Select Theme',
|
||||
Preview: 'Preview',
|
||||
'(Use Enter to select, Tab to configure scope)':
|
||||
'(Use Enter to select, Tab to configure scope)',
|
||||
'(Use Enter to apply scope, Tab to select theme)':
|
||||
'(Use Enter to apply scope, Tab to select theme)',
|
||||
'Theme configuration unavailable due to NO_COLOR env variable.':
|
||||
'Theme configuration unavailable due to NO_COLOR env variable.',
|
||||
'Theme "{{themeName}}" not found.': 'Theme "{{themeName}}" not found.',
|
||||
'Theme "{{themeName}}" not found in selected scope.':
|
||||
'Theme "{{themeName}}" not found in selected scope.',
|
||||
'clear the screen and conversation history':
|
||||
'clear the screen and conversation history',
|
||||
'Compresses the context by replacing it with a summary.':
|
||||
@@ -236,6 +254,71 @@ export default {
|
||||
// Commands - General (continued)
|
||||
// ============================================================================
|
||||
'View and edit Qwen Code settings': 'View and edit Qwen Code settings',
|
||||
Settings: 'Settings',
|
||||
'(Use Enter to select{{tabText}})': '(Use Enter to select{{tabText}})',
|
||||
', Tab to change focus': ', Tab to change focus',
|
||||
'To see changes, Qwen Code must be restarted. Press r to exit and apply changes now.':
|
||||
'To see changes, Qwen Code must be restarted. Press r to exit and apply changes now.',
|
||||
// ============================================================================
|
||||
// Settings Labels
|
||||
// ============================================================================
|
||||
'Vim Mode': 'Vim Mode',
|
||||
'Disable Auto Update': 'Disable Auto Update',
|
||||
'Enable Prompt Completion': 'Enable Prompt Completion',
|
||||
'Debug Keystroke Logging': 'Debug Keystroke Logging',
|
||||
Language: 'Language',
|
||||
'Output Format': 'Output Format',
|
||||
'Hide Window Title': 'Hide Window Title',
|
||||
'Show Status in Title': 'Show Status in Title',
|
||||
'Hide Tips': 'Hide Tips',
|
||||
'Hide Banner': 'Hide Banner',
|
||||
'Hide Context Summary': 'Hide Context Summary',
|
||||
'Hide CWD': 'Hide CWD',
|
||||
'Hide Sandbox Status': 'Hide Sandbox Status',
|
||||
'Hide Model Info': 'Hide Model Info',
|
||||
'Hide Footer': 'Hide Footer',
|
||||
'Show Memory Usage': 'Show Memory Usage',
|
||||
'Show Line Numbers': 'Show Line Numbers',
|
||||
'Show Citations': 'Show Citations',
|
||||
'Custom Witty Phrases': 'Custom Witty Phrases',
|
||||
'Enable Welcome Back': 'Enable Welcome Back',
|
||||
'Disable Loading Phrases': 'Disable Loading Phrases',
|
||||
'Screen Reader Mode': 'Screen Reader Mode',
|
||||
'IDE Mode': 'IDE Mode',
|
||||
'Max Session Turns': 'Max Session Turns',
|
||||
'Skip Next Speaker Check': 'Skip Next Speaker Check',
|
||||
'Skip Loop Detection': 'Skip Loop Detection',
|
||||
'Skip Startup Context': 'Skip Startup Context',
|
||||
'Enable OpenAI Logging': 'Enable OpenAI Logging',
|
||||
'OpenAI Logging Directory': 'OpenAI Logging Directory',
|
||||
Timeout: 'Timeout',
|
||||
'Max Retries': 'Max Retries',
|
||||
'Disable Cache Control': 'Disable Cache Control',
|
||||
'Memory Discovery Max Dirs': 'Memory Discovery Max Dirs',
|
||||
'Load Memory From Include Directories':
|
||||
'Load Memory From Include Directories',
|
||||
'Respect .gitignore': 'Respect .gitignore',
|
||||
'Respect .qwenignore': 'Respect .qwenignore',
|
||||
'Enable Recursive File Search': 'Enable Recursive File Search',
|
||||
'Disable Fuzzy Search': 'Disable Fuzzy Search',
|
||||
'Enable Interactive Shell': 'Enable Interactive Shell',
|
||||
'Show Color': 'Show Color',
|
||||
'Auto Accept': 'Auto Accept',
|
||||
'Use Ripgrep': 'Use Ripgrep',
|
||||
'Use Builtin Ripgrep': 'Use Builtin Ripgrep',
|
||||
'Enable Tool Output Truncation': 'Enable Tool Output Truncation',
|
||||
'Tool Output Truncation Threshold': 'Tool Output Truncation Threshold',
|
||||
'Tool Output Truncation Lines': 'Tool Output Truncation Lines',
|
||||
'Folder Trust': 'Folder Trust',
|
||||
'Vision Model Preview': 'Vision Model Preview',
|
||||
// Settings enum options
|
||||
'Auto (detect from system)': 'Auto (detect from system)',
|
||||
Text: 'Text',
|
||||
JSON: 'JSON',
|
||||
Plan: 'Plan',
|
||||
Default: 'Default',
|
||||
'Auto Edit': 'Auto Edit',
|
||||
YOLO: 'YOLO',
|
||||
'toggle vim mode on/off': 'toggle vim mode on/off',
|
||||
'check session stats. Usage: /stats [model|tools]':
|
||||
'check session stats. Usage: /stats [model|tools]',
|
||||
@@ -534,6 +617,33 @@ export default {
|
||||
'Failed to compress chat history.': 'Failed to compress chat history.',
|
||||
'Failed to compress chat history: {{error}}':
|
||||
'Failed to compress chat history: {{error}}',
|
||||
'Compressing chat history': 'Compressing chat history',
|
||||
'Chat history compressed from {{originalTokens}} to {{newTokens}} tokens.':
|
||||
'Chat history compressed from {{originalTokens}} to {{newTokens}} tokens.',
|
||||
'Compression was not beneficial for this history size.':
|
||||
'Compression was not beneficial for this history size.',
|
||||
'Chat history compression did not reduce size. This may indicate issues with the compression prompt.':
|
||||
'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.':
|
||||
'Could not compress chat history due to a token counting error.',
|
||||
'Chat history is already compressed.': 'Chat history is already compressed.',
|
||||
|
||||
// ============================================================================
|
||||
// Commands - Directory
|
||||
// ============================================================================
|
||||
'Configuration is not available.': 'Configuration is not available.',
|
||||
'Please provide at least one path to add.':
|
||||
'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.':
|
||||
'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.',
|
||||
"Error adding '{{path}}': {{error}}": "Error adding '{{path}}': {{error}}",
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}':
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}',
|
||||
'Error refreshing memory: {{error}}': 'Error refreshing memory: {{error}}',
|
||||
'Successfully added directories:\n- {{directories}}':
|
||||
'Successfully added directories:\n- {{directories}}',
|
||||
'Current workspace directories:\n{{directories}}':
|
||||
'Current workspace directories:\n{{directories}}',
|
||||
|
||||
// ============================================================================
|
||||
// Commands - Docs
|
||||
|
||||
@@ -17,6 +17,11 @@ export default {
|
||||
'@': '@',
|
||||
'@src/myFile.ts': '@src/myFile.ts',
|
||||
'Shell mode': 'Shell 模式',
|
||||
'YOLO mode': 'YOLO 模式',
|
||||
'plan mode': '规划模式',
|
||||
'auto-accept edits': '自动接受编辑',
|
||||
'Accepting edits': '接受编辑',
|
||||
'(shift + tab to cycle)': '(shift + tab 切换)',
|
||||
'Execute shell commands via {{symbol}} (e.g., {{example1}}) or use natural language (e.g., {{example2}}).':
|
||||
'通过 {{symbol}} 执行 shell 命令(例如,{{example1}})或使用自然语言(例如,{{example2}})',
|
||||
'!': '!',
|
||||
@@ -79,10 +84,23 @@ export default {
|
||||
'分析项目并创建定制的 QWEN.md 文件',
|
||||
'list available Qwen Code tools. Usage: /tools [desc]':
|
||||
'列出可用的 Qwen Code 工具。用法:/tools [desc]',
|
||||
'Available Qwen Code CLI tools:': '可用的 Qwen Code CLI 工具:',
|
||||
'No tools available': '没有可用工具',
|
||||
'View or change the approval mode for tool usage':
|
||||
'查看或更改工具使用的审批模式',
|
||||
'View or change the language setting': '查看或更改语言设置',
|
||||
'change the theme': '更改主题',
|
||||
'Select Theme': '选择主题',
|
||||
Preview: '预览',
|
||||
'(Use Enter to select, Tab to configure scope)':
|
||||
'(使用 Enter 选择,Tab 配置作用域)',
|
||||
'(Use Enter to apply scope, Tab to select theme)':
|
||||
'(使用 Enter 应用作用域,Tab 选择主题)',
|
||||
'Theme configuration unavailable due to NO_COLOR env variable.':
|
||||
'由于 NO_COLOR 环境变量,主题配置不可用。',
|
||||
'Theme "{{themeName}}" not found.': '未找到主题 "{{themeName}}"。',
|
||||
'Theme "{{themeName}}" not found in selected scope.':
|
||||
'在所选作用域中未找到主题 "{{themeName}}"。',
|
||||
'clear the screen and conversation history': '清屏并清除对话历史',
|
||||
'Compresses the context by replacing it with a summary.':
|
||||
'通过用摘要替换来压缩上下文',
|
||||
@@ -227,6 +245,70 @@ export default {
|
||||
// Commands - General (continued)
|
||||
// ============================================================================
|
||||
'View and edit Qwen Code settings': '查看和编辑 Qwen Code 设置',
|
||||
Settings: '设置',
|
||||
'(Use Enter to select{{tabText}})': '(使用 Enter 选择{{tabText}})',
|
||||
', Tab to change focus': ',Tab 切换焦点',
|
||||
'To see changes, Qwen Code must be restarted. Press r to exit and apply changes now.':
|
||||
'要查看更改,必须重启 Qwen Code。按 r 退出并立即应用更改。',
|
||||
// ============================================================================
|
||||
// Settings Labels
|
||||
// ============================================================================
|
||||
'Vim Mode': 'Vim 模式',
|
||||
'Disable Auto Update': '禁用自动更新',
|
||||
'Enable Prompt Completion': '启用提示补全',
|
||||
'Debug Keystroke Logging': '调试按键记录',
|
||||
Language: '语言',
|
||||
'Output Format': '输出格式',
|
||||
'Hide Window Title': '隐藏窗口标题',
|
||||
'Show Status in Title': '在标题中显示状态',
|
||||
'Hide Tips': '隐藏提示',
|
||||
'Hide Banner': '隐藏横幅',
|
||||
'Hide Context Summary': '隐藏上下文摘要',
|
||||
'Hide CWD': '隐藏当前工作目录',
|
||||
'Hide Sandbox Status': '隐藏沙箱状态',
|
||||
'Hide Model Info': '隐藏模型信息',
|
||||
'Hide Footer': '隐藏页脚',
|
||||
'Show Memory Usage': '显示内存使用',
|
||||
'Show Line Numbers': '显示行号',
|
||||
'Show Citations': '显示引用',
|
||||
'Custom Witty Phrases': '自定义诙谐短语',
|
||||
'Enable Welcome Back': '启用欢迎回来',
|
||||
'Disable Loading Phrases': '禁用加载短语',
|
||||
'Screen Reader Mode': '屏幕阅读器模式',
|
||||
'IDE Mode': 'IDE 模式',
|
||||
'Max Session Turns': '最大会话轮次',
|
||||
'Skip Next Speaker Check': '跳过下一个说话者检查',
|
||||
'Skip Loop Detection': '跳过循环检测',
|
||||
'Skip Startup Context': '跳过启动上下文',
|
||||
'Enable OpenAI Logging': '启用 OpenAI 日志',
|
||||
'OpenAI Logging Directory': 'OpenAI 日志目录',
|
||||
Timeout: '超时',
|
||||
'Max Retries': '最大重试次数',
|
||||
'Disable Cache Control': '禁用缓存控制',
|
||||
'Memory Discovery Max Dirs': '内存发现最大目录数',
|
||||
'Load Memory From Include Directories': '从包含目录加载内存',
|
||||
'Respect .gitignore': '遵守 .gitignore',
|
||||
'Respect .qwenignore': '遵守 .qwenignore',
|
||||
'Enable Recursive File Search': '启用递归文件搜索',
|
||||
'Disable Fuzzy Search': '禁用模糊搜索',
|
||||
'Enable Interactive Shell': '启用交互式 Shell',
|
||||
'Show Color': '显示颜色',
|
||||
'Auto Accept': '自动接受',
|
||||
'Use Ripgrep': '使用 Ripgrep',
|
||||
'Use Builtin Ripgrep': '使用内置 Ripgrep',
|
||||
'Enable Tool Output Truncation': '启用工具输出截断',
|
||||
'Tool Output Truncation Threshold': '工具输出截断阈值',
|
||||
'Tool Output Truncation Lines': '工具输出截断行数',
|
||||
'Folder Trust': '文件夹信任',
|
||||
'Vision Model Preview': '视觉模型预览',
|
||||
// Settings enum options
|
||||
'Auto (detect from system)': '自动(从系统检测)',
|
||||
Text: '文本',
|
||||
JSON: 'JSON',
|
||||
Plan: '规划',
|
||||
Default: '默认',
|
||||
'Auto Edit': '自动编辑',
|
||||
YOLO: 'YOLO',
|
||||
'toggle vim mode on/off': '切换 vim 模式开关',
|
||||
'check session stats. Usage: /stats [model|tools]':
|
||||
'检查会话统计信息。用法:/stats [model|tools]',
|
||||
@@ -336,7 +418,7 @@ export default {
|
||||
'Scope subcommands do not accept additional arguments.':
|
||||
'作用域子命令不接受额外参数',
|
||||
'Plan mode - Analyze only, do not modify files or execute commands':
|
||||
'计划模式 - 仅分析,不修改文件或执行命令',
|
||||
'规划模式 - 仅分析,不修改文件或执行命令',
|
||||
'Default mode - Require approval for file edits or shell commands':
|
||||
'默认模式 - 需要批准文件编辑或 shell 命令',
|
||||
'Auto-edit mode - Automatically approve file edits':
|
||||
@@ -502,6 +584,32 @@ export default {
|
||||
'正在压缩中,请等待上一个请求完成',
|
||||
'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。',
|
||||
'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 计数错误,无法压缩聊天历史。',
|
||||
'Chat history is already compressed.': '聊天历史已经压缩。',
|
||||
|
||||
// ============================================================================
|
||||
// Commands - Directory
|
||||
// ============================================================================
|
||||
'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。',
|
||||
"Error adding '{{path}}': {{error}}": "添加 '{{path}}' 时出错:{{error}}",
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}':
|
||||
'如果存在,已成功从以下目录添加 GEMINI.md 文件:\n- {{directories}}',
|
||||
'Error refreshing memory: {{error}}': '刷新内存时出错:{{error}}',
|
||||
'Successfully added directories:\n- {{directories}}':
|
||||
'成功添加目录:\n- {{directories}}',
|
||||
'Current workspace directories:\n{{directories}}':
|
||||
'当前工作区目录:\n{{directories}}',
|
||||
|
||||
// ============================================================================
|
||||
// Commands - Docs
|
||||
@@ -593,8 +701,8 @@ export default {
|
||||
'(Use Enter to Set Auth)': '(使用 Enter 设置认证)',
|
||||
'Terms of Services and Privacy Notice for Qwen Code':
|
||||
'Qwen Code 的服务条款和隐私声明',
|
||||
'Qwen OAuth': 'Qwen OAuth (推荐)',
|
||||
OpenAI: 'OpenAI (兼容 API)',
|
||||
'Qwen OAuth': 'Qwen OAuth (免费)',
|
||||
OpenAI: 'OpenAI',
|
||||
'Failed to login. Message: {{message}}': '登录失败。消息:{{message}}',
|
||||
'Authentication is enforced to be {{enforcedType}}, but you are currently using {{currentType}}.':
|
||||
'认证方式被强制设置为 {{enforcedType}},但您当前使用的是 {{currentType}}',
|
||||
|
||||
@@ -52,7 +52,7 @@ export const directoryCommand: SlashCommand = {
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Configuration is not available.',
|
||||
text: t('Configuration is not available.'),
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
@@ -69,7 +69,7 @@ export const directoryCommand: SlashCommand = {
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Please provide at least one path to add.',
|
||||
text: t('Please provide at least one path to add.'),
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
@@ -80,8 +80,9 @@ export const directoryCommand: SlashCommand = {
|
||||
return {
|
||||
type: 'message' as const,
|
||||
messageType: 'error' as const,
|
||||
content:
|
||||
content: t(
|
||||
'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.',
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -94,7 +95,12 @@ export const directoryCommand: SlashCommand = {
|
||||
added.push(pathToAdd.trim());
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
errors.push(`Error adding '${pathToAdd.trim()}': ${error.message}`);
|
||||
errors.push(
|
||||
t("Error adding '{{path}}': {{error}}", {
|
||||
path: pathToAdd.trim(),
|
||||
error: error.message,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +129,21 @@ export const directoryCommand: SlashCommand = {
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: `Successfully added GEMINI.md files from the following directories if there are:\n- ${added.join('\n- ')}`,
|
||||
text: t(
|
||||
'Successfully added GEMINI.md files from the following directories if there are:\n- {{directories}}',
|
||||
{
|
||||
directories: added.join('\n- '),
|
||||
},
|
||||
),
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
} catch (error) {
|
||||
errors.push(`Error refreshing memory: ${(error as Error).message}`);
|
||||
errors.push(
|
||||
t('Error refreshing memory: {{error}}', {
|
||||
error: (error as Error).message,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (added.length > 0) {
|
||||
@@ -139,7 +154,9 @@ export const directoryCommand: SlashCommand = {
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: `Successfully added directories:\n- ${added.join('\n- ')}`,
|
||||
text: t('Successfully added directories:\n- {{directories}}', {
|
||||
directories: added.join('\n- '),
|
||||
}),
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
@@ -169,7 +186,7 @@ export const directoryCommand: SlashCommand = {
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.ERROR,
|
||||
text: 'Configuration is not available.',
|
||||
text: t('Configuration is not available.'),
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
@@ -181,7 +198,9 @@ export const directoryCommand: SlashCommand = {
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: `Current workspace directories:\n${directoryList}`,
|
||||
text: t('Current workspace directories:\n{{directories}}', {
|
||||
directories: directoryList,
|
||||
}),
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import type React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
import { ApprovalMode } from '@qwen-code/qwen-code-core';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface AutoAcceptIndicatorProps {
|
||||
approvalMode: ApprovalMode;
|
||||
@@ -23,18 +24,18 @@ export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
|
||||
switch (approvalMode) {
|
||||
case ApprovalMode.PLAN:
|
||||
textColor = theme.status.success;
|
||||
textContent = 'plan mode';
|
||||
subText = ' (shift + tab to cycle)';
|
||||
textContent = t('plan mode');
|
||||
subText = ` ${t('(shift + tab to cycle)')}`;
|
||||
break;
|
||||
case ApprovalMode.AUTO_EDIT:
|
||||
textColor = theme.status.warning;
|
||||
textContent = 'auto-accept edits';
|
||||
subText = ' (shift + tab to cycle)';
|
||||
textContent = t('auto-accept edits');
|
||||
subText = ` ${t('(shift + tab to cycle)')}`;
|
||||
break;
|
||||
case ApprovalMode.YOLO:
|
||||
textColor = theme.status.error;
|
||||
textContent = 'YOLO mode';
|
||||
subText = ' (shift + tab to cycle)';
|
||||
textContent = t('YOLO mode');
|
||||
subText = ` ${t('(shift + tab to cycle)')}`;
|
||||
break;
|
||||
case ApprovalMode.DEFAULT:
|
||||
default:
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
parseInputForHighlighting,
|
||||
buildSegmentsForVisualSlice,
|
||||
} from '../utils/highlight.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
import {
|
||||
clipboardHasImage,
|
||||
saveClipboardImage,
|
||||
@@ -833,13 +834,13 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||
let statusText = '';
|
||||
if (shellModeActive) {
|
||||
statusColor = theme.ui.symbol;
|
||||
statusText = 'Shell mode';
|
||||
statusText = t('Shell mode');
|
||||
} else if (showYoloStyling) {
|
||||
statusColor = theme.status.error;
|
||||
statusText = 'YOLO mode';
|
||||
statusText = t('YOLO mode');
|
||||
} else if (showAutoAcceptStyling) {
|
||||
statusColor = theme.status.warning;
|
||||
statusText = 'Accepting edits';
|
||||
statusText = t('Accepting edits');
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { LoadedSettings, Settings } from '../../config/settings.js';
|
||||
import { SettingScope } from '../../config/settings.js';
|
||||
import { getScopeMessageForSetting } from '../../utils/dialogScopeUtils.js';
|
||||
import { ScopeSelector } from './shared/ScopeSelector.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
import {
|
||||
getDialogSettingKeys,
|
||||
setPendingSettingValue,
|
||||
@@ -124,7 +125,9 @@ export function SettingsDialog({
|
||||
const definition = getSettingDefinition(key);
|
||||
|
||||
return {
|
||||
label: definition?.label || key,
|
||||
label: definition?.label
|
||||
? t(definition.label) || definition.label
|
||||
: key,
|
||||
value: key,
|
||||
type: definition?.type,
|
||||
toggle: () => {
|
||||
@@ -779,7 +782,8 @@ export function SettingsDialog({
|
||||
>
|
||||
<Box flexDirection="column" flexGrow={1}>
|
||||
<Text bold={focusSection === 'settings'} wrap="truncate">
|
||||
{focusSection === 'settings' ? '> ' : ' '}Settings
|
||||
{focusSection === 'settings' ? '> ' : ' '}
|
||||
{t('Settings')}
|
||||
</Text>
|
||||
<Box height={1} />
|
||||
{showScrollUp && <Text color={theme.text.secondary}>▲</Text>}
|
||||
@@ -916,13 +920,15 @@ export function SettingsDialog({
|
||||
|
||||
<Box height={1} />
|
||||
<Text color={theme.text.secondary}>
|
||||
(Use Enter to select
|
||||
{showScopeSelection ? ', Tab to change focus' : ''})
|
||||
{t('(Use Enter to select{{tabText}})', {
|
||||
tabText: showScopeSelection ? t(', Tab to change focus') : '',
|
||||
})}
|
||||
</Text>
|
||||
{showRestartPrompt && (
|
||||
<Text color={theme.status.warning}>
|
||||
To see changes, Qwen Code must be restarted. Press r to exit and
|
||||
apply changes now.
|
||||
{t(
|
||||
'To see changes, Qwen Code must be restarted. Press r to exit and apply changes now.',
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
@@ -17,6 +17,7 @@ import { SettingScope } from '../../config/settings.js';
|
||||
import { getScopeMessageForSetting } from '../../utils/dialogScopeUtils.js';
|
||||
import { useKeypress } from '../hooks/useKeypress.js';
|
||||
import { ScopeSelector } from './shared/ScopeSelector.js';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface ThemeDialogProps {
|
||||
/** Callback function when a theme is selected */
|
||||
@@ -198,7 +199,8 @@ export function ThemeDialog({
|
||||
{/* Left Column: Selection */}
|
||||
<Box flexDirection="column" width="45%" paddingRight={2}>
|
||||
<Text bold={mode === 'theme'} wrap="truncate">
|
||||
{mode === 'theme' ? '> ' : ' '}Select Theme{' '}
|
||||
{mode === 'theme' ? '> ' : ' '}
|
||||
{t('Select Theme')}{' '}
|
||||
<Text color={theme.text.secondary}>
|
||||
{otherScopeModifiedMessage}
|
||||
</Text>
|
||||
@@ -218,7 +220,7 @@ export function ThemeDialog({
|
||||
{/* Right Column: Preview */}
|
||||
<Box flexDirection="column" width="55%" paddingLeft={2}>
|
||||
<Text bold color={theme.text.primary}>
|
||||
Preview
|
||||
{t('Preview')}
|
||||
</Text>
|
||||
{/* Get the Theme object for the highlighted theme, fall back to default if not found */}
|
||||
{(() => {
|
||||
@@ -274,8 +276,9 @@ def fibonacci(n):
|
||||
)}
|
||||
<Box marginTop={1}>
|
||||
<Text color={theme.text.secondary} wrap="truncate">
|
||||
(Use Enter to {mode === 'theme' ? 'select' : 'apply scope'}, Tab to{' '}
|
||||
{mode === 'theme' ? 'configure scope' : 'select theme'})
|
||||
{mode === 'theme'
|
||||
? t('(Use Enter to select, Tab to configure scope)')
|
||||
: t('(Use Enter to apply scope, Tab to select theme)')}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -10,6 +10,7 @@ import Spinner from 'ink-spinner';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { SCREEN_READER_MODEL_PREFIX } from '../../textConstants.js';
|
||||
import { CompressionStatus } from '@qwen-code/qwen-code-core';
|
||||
import { t } from '../../../i18n/index.js';
|
||||
|
||||
export interface CompressionDisplayProps {
|
||||
compression: CompressionProps;
|
||||
@@ -30,24 +31,34 @@ export function CompressionMessage({
|
||||
|
||||
const getCompressionText = () => {
|
||||
if (isPending) {
|
||||
return 'Compressing chat history';
|
||||
return t('Compressing chat history');
|
||||
}
|
||||
|
||||
switch (compressionStatus) {
|
||||
case CompressionStatus.COMPRESSED:
|
||||
return `Chat history compressed from ${originalTokens} to ${newTokens} tokens.`;
|
||||
return t(
|
||||
'Chat history compressed from {{originalTokens}} to {{newTokens}} tokens.',
|
||||
{
|
||||
originalTokens: String(originalTokens),
|
||||
newTokens: String(newTokens),
|
||||
},
|
||||
);
|
||||
case CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT:
|
||||
// For smaller histories (< 50k tokens), compression overhead likely exceeds benefits
|
||||
if (originalTokens < 50000) {
|
||||
return 'Compression was not beneficial for this history size.';
|
||||
return t('Compression was not beneficial for this history size.');
|
||||
}
|
||||
// For larger histories where compression should work but didn't,
|
||||
// this suggests an issue with the compression process itself
|
||||
return 'Chat history compression did not reduce size. This may indicate issues with the compression prompt.';
|
||||
return t(
|
||||
'Chat history compression did not reduce size. This may indicate issues with the compression prompt.',
|
||||
);
|
||||
case CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR:
|
||||
return 'Could not compress chat history due to a token counting error.';
|
||||
return t(
|
||||
'Could not compress chat history due to a token counting error.',
|
||||
);
|
||||
case CompressionStatus.NOOP:
|
||||
return 'Chat history is already compressed.';
|
||||
return t('Chat history is already compressed.');
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Box, Text } from 'ink';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import { type ToolDefinition } from '../../types.js';
|
||||
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
|
||||
import { t } from '../../../i18n/index.js';
|
||||
|
||||
interface ToolsListProps {
|
||||
tools: readonly ToolDefinition[];
|
||||
@@ -23,7 +24,7 @@ export const ToolsList: React.FC<ToolsListProps> = ({
|
||||
}) => (
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Text bold color={theme.text.primary}>
|
||||
Available Qwen Code CLI tools:
|
||||
{t('Available Qwen Code CLI tools:')}
|
||||
</Text>
|
||||
<Box height={1} />
|
||||
{tools.length > 0 ? (
|
||||
@@ -46,7 +47,7 @@ export const ToolsList: React.FC<ToolsListProps> = ({
|
||||
</Box>
|
||||
))
|
||||
) : (
|
||||
<Text color={theme.text.primary}> No tools available</Text>
|
||||
<Text color={theme.text.primary}> {t('No tools available')}</Text>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { themeManager } from '../themes/theme-manager.js';
|
||||
import type { LoadedSettings, SettingScope } from '../../config/settings.js'; // Import LoadedSettings, AppSettings, MergedSetting
|
||||
import { type HistoryItem, MessageType } from '../types.js';
|
||||
import process from 'node:process';
|
||||
import { t } from '../../i18n/index.js';
|
||||
|
||||
interface UseThemeCommandReturn {
|
||||
isThemeDialogOpen: boolean;
|
||||
@@ -34,7 +35,9 @@ export const useThemeCommand = (
|
||||
addItem(
|
||||
{
|
||||
type: MessageType.INFO,
|
||||
text: 'Theme configuration unavailable due to NO_COLOR env variable.',
|
||||
text: t(
|
||||
'Theme configuration unavailable due to NO_COLOR env variable.',
|
||||
),
|
||||
},
|
||||
Date.now(),
|
||||
);
|
||||
@@ -48,7 +51,11 @@ export const useThemeCommand = (
|
||||
if (!themeManager.setActiveTheme(themeName)) {
|
||||
// If theme is not found, open the theme selection dialog and set error message
|
||||
setIsThemeDialogOpen(true);
|
||||
setThemeError(`Theme "${themeName}" not found.`);
|
||||
setThemeError(
|
||||
t('Theme "{{themeName}}" not found.', {
|
||||
themeName: themeName ?? '',
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
setThemeError(null); // Clear any previous theme error on success
|
||||
}
|
||||
@@ -75,7 +82,11 @@ export const useThemeCommand = (
|
||||
const isBuiltIn = themeManager.findThemeByName(themeName);
|
||||
const isCustom = themeName && mergedCustomThemes[themeName];
|
||||
if (!isBuiltIn && !isCustom) {
|
||||
setThemeError(`Theme "${themeName}" not found in selected scope.`);
|
||||
setThemeError(
|
||||
t('Theme "{{themeName}}" not found in selected scope.', {
|
||||
themeName: themeName ?? '',
|
||||
}),
|
||||
);
|
||||
setIsThemeDialogOpen(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
SettingsValue,
|
||||
} from '../config/settingsSchema.js';
|
||||
import { getSettingsSchema } from '../config/settingsSchema.js';
|
||||
import { t } from '../i18n/index.js';
|
||||
|
||||
// The schema is now nested, but many parts of the UI and logic work better
|
||||
// with a flattened structure and dot-notation keys. This section flattens the
|
||||
@@ -446,7 +447,11 @@ export function getDisplayValue(
|
||||
|
||||
if (definition?.type === 'enum' && definition.options) {
|
||||
const option = definition.options?.find((option) => option.value === value);
|
||||
valueString = option?.label ?? `${value}`;
|
||||
if (option?.label) {
|
||||
valueString = t(option.label) || option.label;
|
||||
} else {
|
||||
valueString = `${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if value is different from default OR if it's in modified settings OR if there are pending changes
|
||||
|
||||
Reference in New Issue
Block a user