diff --git a/docs/cli/commands.md b/docs/cli/commands.md index 82342e0a..983c6e5e 100644 --- a/docs/cli/commands.md +++ b/docs/cli/commands.md @@ -195,6 +195,16 @@ Slash commands provide meta-level control over the CLI itself. - **`/init`** - **Description:** Analyzes the current directory and creates a `QWEN.md` context file by default (or the filename specified by `contextFileName`). If a non-empty file already exists, no changes are made. The command seeds an empty file and prompts the model to populate it with project-specific instructions. +- [**`/language`**](./language.md) + - **Description:** View or change the language setting for both UI and LLM output. + - **Sub-commands:** + - **`ui`**: Set the UI language (zh-CN or en-US) + - **`output`**: Set the LLM output language + - **Usage:** `/language [ui|output] [language]` + - **Examples:** + - `/language ui zh-CN` (set UI language to Simplified Chinese) + - `/language output English` (set LLM output language to English) + ### Custom Commands For a quick start, see the [example](#example-a-pure-function-refactoring-command) below. diff --git a/docs/cli/language.md b/docs/cli/language.md new file mode 100644 index 00000000..7fb1e7f0 --- /dev/null +++ b/docs/cli/language.md @@ -0,0 +1,71 @@ +# Language Command + +The `/language` command allows you to customize the language settings for both the Qwen Code user interface (UI) and the language model's output. This command supports two distinct functionalities: + +1. Setting the UI language for the Qwen Code interface +2. Setting the output language for the language model (LLM) + +## UI Language Settings + +To change the UI language of Qwen Code, use the `ui` subcommand: + +``` +/language ui [zh-CN|en-US] +``` + +### Available UI Languages + +- **zh-CN**: Simplified Chinese (简体中文) +- **en-US**: English + +### Examples + +``` +/language ui zh-CN # Set UI language to Simplified Chinese +/language ui en-US # Set UI language to English +``` + +### UI Language Subcommands + +You can also use direct subcommands for convenience: + +- `/language ui zh-CN` or `/language ui zh` or `/language ui 中文` +- `/language ui en-US` or `/language ui en` or `/language ui english` + +## LLM Output Language Settings + +To set the language for the language model's responses, use the `output` subcommand: + +``` +/language output +``` + +This command generates a language rule file that instructs the LLM to respond in the specified language. The rule file is saved to `~/.qwen/output-language.md`. + +### Examples + +``` +/language output 中文 # Set LLM output language to Chinese +/language output English # Set LLM output language to English +/language output 日本語 # Set LLM output language to Japanese +``` + +## Viewing Current Settings + +When used without arguments, the `/language` command displays the current language settings: + +``` +/language +``` + +This will show: + +- Current UI language +- Current LLM output language (if set) +- Available subcommands + +## Notes + +- UI language changes take effect immediately and reload all command descriptions +- LLM output language settings are persisted in a rule file that is automatically included in the model's context +- To request additional UI language packs, please open an issue on GitHub diff --git a/packages/cli/src/i18n/locales/en.js b/packages/cli/src/i18n/locales/en.js index 3c0fc22f..3f23f6e5 100644 --- a/packages/cli/src/i18n/locales/en.js +++ b/packages/cli/src/i18n/locales/en.js @@ -112,8 +112,39 @@ export default { 'IDE integration is not supported in your current environment. To use this feature, run Qwen Code in one of these supported IDEs: VS Code or VS Code forks.': 'IDE integration is not supported in your current environment. To use this feature, run Qwen Code in one of these supported IDEs: VS Code or VS Code forks.', 'Set up GitHub Actions': 'Set up GitHub Actions', - 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf)': - 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf)', + 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf, Trae)': + 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf, Trae)', + 'Please restart your terminal for the changes to take effect.': + 'Please restart your terminal for the changes to take effect.', + 'Failed to configure terminal: {{error}}': + 'Failed to configure terminal: {{error}}', + 'Could not determine {{terminalName}} config path on Windows: APPDATA environment variable is not set.': + 'Could not determine {{terminalName}} config path on Windows: APPDATA environment variable is not set.', + '{{terminalName}} keybindings.json exists but is not a valid JSON array. Please fix the file manually or delete it to allow automatic configuration.': + '{{terminalName}} keybindings.json exists but is not a valid JSON array. Please fix the file manually or delete it to allow automatic configuration.', + 'File: {{file}}': 'File: {{file}}', + 'Failed to parse {{terminalName}} keybindings.json. The file contains invalid JSON. Please fix the file manually or delete it to allow automatic configuration.': + 'Failed to parse {{terminalName}} keybindings.json. The file contains invalid JSON. Please fix the file manually or delete it to allow automatic configuration.', + 'Error: {{error}}': 'Error: {{error}}', + 'Shift+Enter binding already exists': 'Shift+Enter binding already exists', + 'Ctrl+Enter binding already exists': 'Ctrl+Enter binding already exists', + 'Existing keybindings detected. Will not modify to avoid conflicts.': + 'Existing keybindings detected. Will not modify to avoid conflicts.', + 'Please check and modify manually if needed: {{file}}': + 'Please check and modify manually if needed: {{file}}', + 'Added Shift+Enter and Ctrl+Enter keybindings to {{terminalName}}.': + 'Added Shift+Enter and Ctrl+Enter keybindings to {{terminalName}}.', + 'Modified: {{file}}': 'Modified: {{file}}', + '{{terminalName}} keybindings already configured.': + '{{terminalName}} keybindings already configured.', + 'Failed to configure {{terminalName}}.': + 'Failed to configure {{terminalName}}.', + 'Your terminal is already configured for an optimal experience with multiline input (Shift+Enter and Ctrl+Enter).': + 'Your terminal is already configured for an optimal experience with multiline input (Shift+Enter and Ctrl+Enter).', + 'Could not detect terminal type. Supported terminals: VS Code, Cursor, Windsurf, and Trae.': + 'Could not detect terminal type. Supported terminals: VS Code, Cursor, Windsurf, and Trae.', + 'Terminal "{{terminal}}" is not supported yet.': + 'Terminal "{{terminal}}" is not supported yet.', // ============================================================================ // Commands - Language diff --git a/packages/cli/src/i18n/locales/zh.js b/packages/cli/src/i18n/locales/zh.js index 82783e73..986600cd 100644 --- a/packages/cli/src/i18n/locales/zh.js +++ b/packages/cli/src/i18n/locales/zh.js @@ -106,8 +106,37 @@ export default { 'IDE integration is not supported in your current environment. To use this feature, run Qwen Code in one of these supported IDEs: VS Code or VS Code forks.': '您当前环境不支持 IDE 集成。要使用此功能,请在以下支持的 IDE 之一中运行 Qwen Code:VS Code 或 VS Code 分支版本。', 'Set up GitHub Actions': '设置 GitHub Actions', - 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf)': - '配置终端按键绑定以支持多行输入(VS Code、Cursor、Windsurf)', + 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf, Trae)': + '配置终端按键绑定以支持多行输入(VS Code、Cursor、Windsurf、Trae)', + 'Please restart your terminal for the changes to take effect.': + '请重启终端以使更改生效。', + 'Failed to configure terminal: {{error}}': '配置终端失败:{{error}}', + 'Could not determine {{terminalName}} config path on Windows: APPDATA environment variable is not set.': + '无法确定 {{terminalName}} 在 Windows 上的配置路径:未设置 APPDATA 环境变量。', + '{{terminalName}} keybindings.json exists but is not a valid JSON array. Please fix the file manually or delete it to allow automatic configuration.': + '{{terminalName}} keybindings.json 存在但不是有效的 JSON 数组。请手动修复文件或删除它以允许自动配置。', + 'File: {{file}}': '文件:{{file}}', + 'Failed to parse {{terminalName}} keybindings.json. The file contains invalid JSON. Please fix the file manually or delete it to allow automatic configuration.': + '解析 {{terminalName}} keybindings.json 失败。文件包含无效的 JSON。请手动修复文件或删除它以允许自动配置。', + 'Error: {{error}}': '错误:{{error}}', + 'Shift+Enter binding already exists': 'Shift+Enter 绑定已存在', + 'Ctrl+Enter binding already exists': 'Ctrl+Enter 绑定已存在', + 'Existing keybindings detected. Will not modify to avoid conflicts.': + '检测到现有按键绑定。为避免冲突,不会修改。', + 'Please check and modify manually if needed: {{file}}': + '如有需要,请手动检查并修改:{{file}}', + 'Added Shift+Enter and Ctrl+Enter keybindings to {{terminalName}}.': + '已为 {{terminalName}} 添加 Shift+Enter 和 Ctrl+Enter 按键绑定。', + 'Modified: {{file}}': '已修改:{{file}}', + '{{terminalName}} keybindings already configured.': + '{{terminalName}} 按键绑定已配置。', + 'Failed to configure {{terminalName}}.': '配置 {{terminalName}} 失败。', + 'Your terminal is already configured for an optimal experience with multiline input (Shift+Enter and Ctrl+Enter).': + '您的终端已配置为支持多行输入(Shift+Enter 和 Ctrl+Enter)的最佳体验。', + 'Could not detect terminal type. Supported terminals: VS Code, Cursor, Windsurf, and Trae.': + '无法检测终端类型。支持的终端:VS Code、Cursor、Windsurf 和 Trae。', + 'Terminal "{{terminal}}" is not supported yet.': + '终端 "{{terminal}}" 尚未支持。', // ============================================================================ // Commands - Language diff --git a/packages/cli/src/ui/commands/terminalSetupCommand.ts b/packages/cli/src/ui/commands/terminalSetupCommand.ts index 31b473c7..3fb85446 100644 --- a/packages/cli/src/ui/commands/terminalSetupCommand.ts +++ b/packages/cli/src/ui/commands/terminalSetupCommand.ts @@ -7,6 +7,7 @@ import type { MessageActionReturn, SlashCommand } from './types.js'; import { CommandKind } from './types.js'; import { terminalSetup } from '../utils/terminalSetup.js'; +import { t } from '../../i18n/index.js'; /** * Command to configure terminal keybindings for multiline input support. @@ -16,8 +17,11 @@ import { terminalSetup } from '../utils/terminalSetup.js'; */ export const terminalSetupCommand: SlashCommand = { name: 'terminal-setup', - description: - 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf, Trae)', + get description() { + return t( + 'Configure terminal keybindings for multiline input (VS Code, Cursor, Windsurf, Trae)', + ); + }, kind: CommandKind.BUILT_IN, action: async (): Promise => { @@ -27,7 +31,8 @@ export const terminalSetupCommand: SlashCommand = { let content = result.message; if (result.requiresRestart) { content += - '\n\nPlease restart your terminal for the changes to take effect.'; + '\n\n' + + t('Please restart your terminal for the changes to take effect.'); } return { @@ -38,7 +43,9 @@ export const terminalSetupCommand: SlashCommand = { } catch (error) { return { type: 'message', - content: `Failed to configure terminal: ${error}`, + content: t('Failed to configure terminal: {{error}}', { + error: String(error), + }), messageType: 'error', }; } diff --git a/packages/cli/src/ui/utils/terminalSetup.ts b/packages/cli/src/ui/utils/terminalSetup.ts index af5367f7..d7a7f41e 100644 --- a/packages/cli/src/ui/utils/terminalSetup.ts +++ b/packages/cli/src/ui/utils/terminalSetup.ts @@ -30,6 +30,7 @@ import { exec } from 'node:child_process'; import { promisify } from 'node:util'; import { isKittyProtocolEnabled } from './kittyProtocolDetector.js'; import { VSCODE_SHIFT_ENTER_SEQUENCE } from './platformConstants.js'; +import { t } from '../../i18n/index.js'; const execAsync = promisify(exec); @@ -146,7 +147,10 @@ async function configureVSCodeStyle( if (!configDir) { return { success: false, - message: `Could not determine ${terminalName} config path on Windows: APPDATA environment variable is not set.`, + message: t( + 'Could not determine {{terminalName}} config path on Windows: APPDATA environment variable is not set.', + { terminalName }, + ), }; } @@ -166,9 +170,12 @@ async function configureVSCodeStyle( return { success: false, message: - `${terminalName} keybindings.json exists but is not a valid JSON array. ` + - `Please fix the file manually or delete it to allow automatic configuration.\n` + - `File: ${keybindingsFile}`, + t( + '{{terminalName}} keybindings.json exists but is not a valid JSON array. Please fix the file manually or delete it to allow automatic configuration.', + { terminalName }, + ) + + '\n' + + t('File: {{file}}', { file: keybindingsFile }), }; } keybindings = parsedContent; @@ -176,10 +183,14 @@ async function configureVSCodeStyle( return { success: false, message: - `Failed to parse ${terminalName} keybindings.json. The file contains invalid JSON.\n` + - `Please fix the file manually or delete it to allow automatic configuration.\n` + - `File: ${keybindingsFile}\n` + - `Error: ${parseError}`, + t( + 'Failed to parse {{terminalName}} keybindings.json. The file contains invalid JSON. Please fix the file manually or delete it to allow automatic configuration.', + { terminalName }, + ) + + '\n' + + t('File: {{file}}', { file: keybindingsFile }) + + '\n' + + t('Error: {{error}}', { error: String(parseError) }), }; } } catch { @@ -214,18 +225,23 @@ async function configureVSCodeStyle( if (existingShiftEnter || existingCtrlEnter) { const messages: string[] = []; if (existingShiftEnter) { - messages.push(`- Shift+Enter binding already exists`); + messages.push('- ' + t('Shift+Enter binding already exists')); } if (existingCtrlEnter) { - messages.push(`- Ctrl+Enter binding already exists`); + messages.push('- ' + t('Ctrl+Enter binding already exists')); } return { success: false, message: - `Existing keybindings detected. Will not modify to avoid conflicts.\n` + + t( + 'Existing keybindings detected. Will not modify to avoid conflicts.', + ) + + '\n' + messages.join('\n') + '\n' + - `Please check and modify manually if needed: ${keybindingsFile}`, + t('Please check and modify manually if needed: {{file}}', { + file: keybindingsFile, + }), }; } @@ -263,19 +279,34 @@ async function configureVSCodeStyle( await fs.writeFile(keybindingsFile, JSON.stringify(keybindings, null, 4)); return { success: true, - message: `Added Shift+Enter and Ctrl+Enter keybindings to ${terminalName}.\nModified: ${keybindingsFile}`, + message: + t( + 'Added Shift+Enter and Ctrl+Enter keybindings to {{terminalName}}.', + { + terminalName, + }, + ) + + '\n' + + t('Modified: {{file}}', { file: keybindingsFile }), requiresRestart: true, }; } else { return { success: true, - message: `${terminalName} keybindings already configured.`, + message: t('{{terminalName}} keybindings already configured.', { + terminalName, + }), }; } } catch (error) { return { success: false, - message: `Failed to configure ${terminalName}.\nFile: ${keybindingsFile}\nError: ${error}`, + message: + t('Failed to configure {{terminalName}}.', { terminalName }) + + '\n' + + t('File: {{file}}', { file: keybindingsFile }) + + '\n' + + t('Error: {{error}}', { error: String(error) }), }; } } @@ -322,8 +353,9 @@ export async function terminalSetup(): Promise { if (isKittyProtocolEnabled()) { return { success: true, - message: + message: t( 'Your terminal is already configured for an optimal experience with multiline input (Shift+Enter and Ctrl+Enter).', + ), }; } @@ -332,8 +364,9 @@ export async function terminalSetup(): Promise { if (!terminal) { return { success: false, - message: - 'Could not detect terminal type. Supported terminals: VS Code, Cursor, and Windsurf.', + message: t( + 'Could not detect terminal type. Supported terminals: VS Code, Cursor, Windsurf, and Trae.', + ), }; } @@ -349,7 +382,9 @@ export async function terminalSetup(): Promise { default: return { success: false, - message: `Terminal "${terminal}" is not supported yet.`, + message: t('Terminal "{{terminal}}" is not supported yet.', { + terminal, + }), }; } }