feat: add i18n for /agents command

This commit is contained in:
pomelo-nwu
2025-11-18 12:02:36 +08:00
parent 47083e810a
commit 805a919f69
16 changed files with 499 additions and 120 deletions

View File

@@ -95,12 +95,146 @@ export default {
'Show quit confirmation dialog': 'Show quit confirmation dialog', 'Show quit confirmation dialog': 'Show quit confirmation dialog',
'Copy the last result or code snippet to clipboard': 'Copy the last result or code snippet to clipboard':
'Copy the last result or code snippet to clipboard', 'Copy the last result or code snippet to clipboard',
// ============================================================================
// Commands - Agents
// ============================================================================
'Manage subagents for specialized task delegation.': 'Manage subagents for specialized task delegation.':
'Manage subagents for specialized task delegation.', 'Manage subagents for specialized task delegation.',
'Manage existing subagents (view, edit, delete).': 'Manage existing subagents (view, edit, delete).':
'Manage existing subagents (view, edit, delete).', 'Manage existing subagents (view, edit, delete).',
'Create a new subagent with guided setup.': 'Create a new subagent with guided setup.':
'Create a new subagent with guided setup.', 'Create a new subagent with guided setup.',
// ============================================================================
// Agents - Management Dialog
// ============================================================================
Agents: 'Agents',
'Choose Action': 'Choose Action',
'Edit {{name}}': 'Edit {{name}}',
'Edit Tools: {{name}}': 'Edit Tools: {{name}}',
'Edit Color: {{name}}': 'Edit Color: {{name}}',
'Delete {{name}}': 'Delete {{name}}',
'Unknown Step': 'Unknown Step',
'Esc to close': 'Esc to close',
'Enter to select, ↑↓ to navigate, Esc to close':
'Enter to select, ↑↓ to navigate, Esc to close',
'Esc to go back': 'Esc to go back',
'Enter to confirm, Esc to cancel': 'Enter to confirm, Esc to cancel',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter to select, ↑↓ to navigate, Esc to go back',
'Invalid step: {{step}}': 'Invalid step: {{step}}',
'No subagents found.': 'No subagents found.',
"Use '/agents create' to create your first subagent.":
"Use '/agents create' to create your first subagent.",
'(built-in)': '(built-in)',
'(overridden by project level agent)': '(overridden by project level agent)',
'Project Level ({{path}})': 'Project Level ({{path}})',
'User Level ({{path}})': 'User Level ({{path}})',
'Built-in Agents': 'Built-in Agents',
'Using: {{count}} agents': 'Using: {{count}} agents',
'View Agent': 'View Agent',
'Edit Agent': 'Edit Agent',
'Delete Agent': 'Delete Agent',
Back: 'Back',
'No agent selected': 'No agent selected',
'File Path: ': 'File Path: ',
'Tools: ': 'Tools: ',
'Color: ': 'Color: ',
'Description:': 'Description:',
'System Prompt:': 'System Prompt:',
'Open in editor': 'Open in editor',
'Edit tools': 'Edit tools',
'Edit color': 'Edit color',
'❌ Error:': '❌ Error:',
'Are you sure you want to delete agent "{{name}}"?':
'Are you sure you want to delete agent "{{name}}"?',
// ============================================================================
// Agents - Creation Wizard
// ============================================================================
'Project Level (.qwen/agents/)': 'Project Level (.qwen/agents/)',
'User Level (~/.qwen/agents/)': 'User Level (~/.qwen/agents/)',
'✅ Subagent Created Successfully!': '✅ Subagent Created Successfully!',
'Subagent "{{name}}" has been saved to {{level}} level.':
'Subagent "{{name}}" has been saved to {{level}} level.',
'Name: ': 'Name: ',
'Location: ': 'Location: ',
'❌ Error saving subagent:': '❌ Error saving subagent:',
'Warnings:': 'Warnings:',
'Name "{{name}}" already exists at {{level}} level - will overwrite existing subagent':
'Name "{{name}}" already exists at {{level}} level - will overwrite existing subagent',
'Name "{{name}}" exists at user level - project level will take precedence':
'Name "{{name}}" exists at user level - project level will take precedence',
'Name "{{name}}" exists at project level - existing subagent will take precedence':
'Name "{{name}}" exists at project level - existing subagent will take precedence',
'Description is over {{length}} characters':
'Description is over {{length}} characters',
'System prompt is over {{length}} characters':
'System prompt is over {{length}} characters',
// Agents - Creation Wizard Steps
'Step {{n}}: Choose Location': 'Step {{n}}: Choose Location',
'Step {{n}}: Choose Generation Method':
'Step {{n}}: Choose Generation Method',
'Generate with Qwen Code (Recommended)':
'Generate with Qwen Code (Recommended)',
'Manual Creation': 'Manual Creation',
'Describe what this subagent should do and when it should be used. (Be comprehensive for best results)':
'Describe what this subagent should do and when it should be used. (Be comprehensive for best results)',
'e.g., Expert code reviewer that reviews code based on best practices...':
'e.g., Expert code reviewer that reviews code based on best practices...',
'Generating subagent configuration...':
'Generating subagent configuration...',
'Failed to generate subagent: {{error}}':
'Failed to generate subagent: {{error}}',
'Step {{n}}: Describe Your Subagent': 'Step {{n}}: Describe Your Subagent',
'Step {{n}}: Enter Subagent Name': 'Step {{n}}: Enter Subagent Name',
'Step {{n}}: Enter System Prompt': 'Step {{n}}: Enter System Prompt',
'Step {{n}}: Enter Description': 'Step {{n}}: Enter Description',
// Agents - Tool Selection
'Step {{n}}: Select Tools': 'Step {{n}}: Select Tools',
'All Tools (Default)': 'All Tools (Default)',
'All Tools': 'All Tools',
'Read-only Tools': 'Read-only Tools',
'Read & Edit Tools': 'Read & Edit Tools',
'Read & Edit & Execution Tools': 'Read & Edit & Execution Tools',
'All tools selected, including MCP tools':
'All tools selected, including MCP tools',
'Selected tools:': 'Selected tools:',
'Read-only tools:': 'Read-only tools:',
'Edit tools:': 'Edit tools:',
'Execution tools:': 'Execution tools:',
'Step {{n}}: Choose Background Color': 'Step {{n}}: Choose Background Color',
'Step {{n}}: Confirm and Save': 'Step {{n}}: Confirm and Save',
// Agents - Navigation & Instructions
'Esc to cancel': 'Esc to cancel',
'Press Enter to save, e to save and edit, Esc to go back':
'Press Enter to save, e to save and edit, Esc to go back',
'Press Enter to continue, {{navigation}}Esc to {{action}}':
'Press Enter to continue, {{navigation}}Esc to {{action}}',
cancel: 'cancel',
'go back': 'go back',
'↑↓ to navigate, ': '↑↓ to navigate, ',
'Enter a clear, unique name for this subagent.':
'Enter a clear, unique name for this subagent.',
'e.g., Code Reviewer': 'e.g., Code Reviewer',
'Name cannot be empty.': 'Name cannot be empty.',
"Write the system prompt that defines this subagent's behavior. Be comprehensive for best results.":
"Write the system prompt that defines this subagent's behavior. Be comprehensive for best results.",
'e.g., You are an expert code reviewer...':
'e.g., You are an expert code reviewer...',
'System prompt cannot be empty.': 'System prompt cannot be empty.',
'Describe when and how this subagent should be used.':
'Describe when and how this subagent should be used.',
'e.g., Reviews code for best practices and potential bugs.':
'e.g., Reviews code for best practices and potential bugs.',
'Description cannot be empty.': 'Description cannot be empty.',
'Failed to launch editor: {{error}}': 'Failed to launch editor: {{error}}',
'Failed to save and edit subagent: {{error}}':
'Failed to save and edit subagent: {{error}}',
// ============================================================================
// Commands - General (continued)
// ============================================================================
'View and edit Qwen Code settings': 'View and edit Qwen Code settings', 'View and edit Qwen Code settings': 'View and edit Qwen Code settings',
'toggle vim mode on/off': 'toggle vim mode on/off', 'toggle vim mode on/off': 'toggle vim mode on/off',
'check session stats. Usage: /stats [model|tools]': 'check session stats. Usage: /stats [model|tools]':
@@ -247,6 +381,9 @@ export default {
'Workspace approval mode exists and takes priority. User-level change will have no effect.', 'Workspace approval mode exists and takes priority. User-level change will have no effect.',
'(Use Enter to select, Tab to change focus)': '(Use Enter to select, Tab to change focus)':
'(Use Enter to select, Tab to change focus)', '(Use Enter to select, Tab to change focus)',
'Apply To': 'Apply To',
'User Settings': 'User Settings',
'Workspace Settings': 'Workspace Settings',
// ============================================================================ // ============================================================================
// Commands - Memory // Commands - Memory

View File

@@ -93,11 +93,139 @@ export default {
'Show quit confirmation dialog': '显示退出确认对话框', 'Show quit confirmation dialog': '显示退出确认对话框',
'Copy the last result or code snippet to clipboard': 'Copy the last result or code snippet to clipboard':
'将最后的结果或代码片段复制到剪贴板', '将最后的结果或代码片段复制到剪贴板',
// ============================================================================
// Commands - Agents
// ============================================================================
'Manage subagents for specialized task delegation.': 'Manage subagents for specialized task delegation.':
'管理用于专门任务委派的子代理', '管理用于专门任务委派的子代理',
'Manage existing subagents (view, edit, delete).': 'Manage existing subagents (view, edit, delete).':
'管理现有子代理(查看、编辑、删除)', '管理现有子代理(查看、编辑、删除)',
'Create a new subagent with guided setup.': '通过引导式设置创建新的子代理', 'Create a new subagent with guided setup.': '通过引导式设置创建新的子代理',
// ============================================================================
// Agents - Management Dialog
// ============================================================================
Agents: '代理',
'Choose Action': '选择操作',
'Edit {{name}}': '编辑 {{name}}',
'Edit Tools: {{name}}': '编辑工具: {{name}}',
'Edit Color: {{name}}': '编辑颜色: {{name}}',
'Delete {{name}}': '删除 {{name}}',
'Unknown Step': '未知步骤',
'Esc to close': '按 Esc 关闭',
'Enter to select, ↑↓ to navigate, Esc to close':
'Enter 选择,↑↓ 导航Esc 关闭',
'Esc to go back': '按 Esc 返回',
'Enter to confirm, Esc to cancel': 'Enter 确认Esc 取消',
'Enter to select, ↑↓ to navigate, Esc to go back':
'Enter 选择,↑↓ 导航Esc 返回',
'Invalid step: {{step}}': '无效步骤: {{step}}',
'No subagents found.': '未找到子代理。',
"Use '/agents create' to create your first subagent.":
"使用 '/agents create' 创建您的第一个子代理。",
'(built-in)': '(内置)',
'(overridden by project level agent)': '(已被项目级代理覆盖)',
'Project Level ({{path}})': '项目级 ({{path}})',
'User Level ({{path}})': '用户级 ({{path}})',
'Built-in Agents': '内置代理',
'Using: {{count}} agents': '使用中: {{count}} 个代理',
'View Agent': '查看代理',
'Edit Agent': '编辑代理',
'Delete Agent': '删除代理',
Back: '返回',
'No agent selected': '未选择代理',
'File Path: ': '文件路径: ',
'Tools: ': '工具: ',
'Color: ': '颜色: ',
'Description:': '描述:',
'System Prompt:': '系统提示:',
'Open in editor': '在编辑器中打开',
'Edit tools': '编辑工具',
'Edit color': '编辑颜色',
'❌ Error:': '❌ 错误:',
'Are you sure you want to delete agent "{{name}}"?':
'您确定要删除代理 "{{name}}" 吗?',
// ============================================================================
// Agents - Creation Wizard
// ============================================================================
'Project Level (.qwen/agents/)': '项目级 (.qwen/agents/)',
'User Level (~/.qwen/agents/)': '用户级 (~/.qwen/agents/)',
'✅ Subagent Created Successfully!': '✅ 子代理创建成功!',
'Subagent "{{name}}" has been saved to {{level}} level.':
'子代理 "{{name}}" 已保存到 {{level}} 级别。',
'Name: ': '名称: ',
'Location: ': '位置: ',
'❌ Error saving subagent:': '❌ 保存子代理时出错:',
'Warnings:': '警告:',
'Name "{{name}}" already exists at {{level}} level - will overwrite existing subagent':
'名称 "{{name}}" 在 {{level}} 级别已存在 - 将覆盖现有子代理',
'Name "{{name}}" exists at user level - project level will take precedence':
'名称 "{{name}}" 在用户级别存在 - 项目级别将优先',
'Name "{{name}}" exists at project level - existing subagent will take precedence':
'名称 "{{name}}" 在项目级别存在 - 现有子代理将优先',
'Description is over {{length}} characters': '描述超过 {{length}} 个字符',
'System prompt is over {{length}} characters':
'系统提示超过 {{length}} 个字符',
// Agents - Creation Wizard Steps
'Step {{n}}: Choose Location': '步骤 {{n}}: 选择位置',
'Step {{n}}: Choose Generation Method': '步骤 {{n}}: 选择生成方式',
'Generate with Qwen Code (Recommended)': '使用 Qwen Code 生成(推荐)',
'Manual Creation': '手动创建',
'Describe what this subagent should do and when it should be used. (Be comprehensive for best results)':
'描述此子代理应该做什么以及何时使用它。(为了获得最佳效果,请全面描述)',
'e.g., Expert code reviewer that reviews code based on best practices...':
'例如:专业的代码审查员,根据最佳实践审查代码...',
'Generating subagent configuration...': '正在生成子代理配置...',
'Failed to generate subagent: {{error}}': '生成子代理失败: {{error}}',
'Step {{n}}: Describe Your Subagent': '步骤 {{n}}: 描述您的子代理',
'Step {{n}}: Enter Subagent Name': '步骤 {{n}}: 输入子代理名称',
'Step {{n}}: Enter System Prompt': '步骤 {{n}}: 输入系统提示',
'Step {{n}}: Enter Description': '步骤 {{n}}: 输入描述',
// Agents - Tool Selection
'Step {{n}}: Select Tools': '步骤 {{n}}: 选择工具',
'All Tools (Default)': '所有工具(默认)',
'All Tools': '所有工具',
'Read-only Tools': '只读工具',
'Read & Edit Tools': '读取和编辑工具',
'Read & Edit & Execution Tools': '读取、编辑和执行工具',
'All tools selected, including MCP tools': '已选择所有工具,包括 MCP 工具',
'Selected tools:': '已选择的工具:',
'Read-only tools:': '只读工具:',
'Edit tools:': '编辑工具:',
'Execution tools:': '执行工具:',
'Step {{n}}: Choose Background Color': '步骤 {{n}}: 选择背景颜色',
'Step {{n}}: Confirm and Save': '步骤 {{n}}: 确认并保存',
// Agents - Navigation & Instructions
'Esc to cancel': '按 Esc 取消',
'Press Enter to save, e to save and edit, Esc to go back':
'按 Enter 保存e 保存并编辑Esc 返回',
'Press Enter to continue, {{navigation}}Esc to {{action}}':
'按 Enter 继续,{{navigation}}Esc {{action}}',
cancel: '取消',
'go back': '返回',
'↑↓ to navigate, ': '↑↓ 导航,',
'Enter a clear, unique name for this subagent.':
'为此子代理输入一个清晰、唯一的名称。',
'e.g., Code Reviewer': '例如:代码审查员',
'Name cannot be empty.': '名称不能为空。',
"Write the system prompt that defines this subagent's behavior. Be comprehensive for best results.":
'编写定义此子代理行为的系统提示。为了获得最佳效果,请全面描述。',
'e.g., You are an expert code reviewer...':
'例如:您是一位专业的代码审查员...',
'System prompt cannot be empty.': '系统提示不能为空。',
'Describe when and how this subagent should be used.':
'描述何时以及如何使用此子代理。',
'e.g., Reviews code for best practices and potential bugs.':
'例如:审查代码以查找最佳实践和潜在错误。',
'Description cannot be empty.': '描述不能为空。',
'Failed to launch editor: {{error}}': '启动编辑器失败: {{error}}',
'Failed to save and edit subagent: {{error}}':
'保存并编辑子代理失败: {{error}}',
// ============================================================================
// Commands - General (continued)
// ============================================================================
'View and edit Qwen Code settings': '查看和编辑 Qwen Code 设置', 'View and edit Qwen Code settings': '查看和编辑 Qwen Code 设置',
'toggle vim mode on/off': '切换 vim 模式开关', 'toggle vim mode on/off': '切换 vim 模式开关',
'check session stats. Usage: /stats [model|tools]': 'check session stats. Usage: /stats [model|tools]':
@@ -232,6 +360,9 @@ export default {
'工作区审批模式已存在并具有优先级。用户级别的更改将无效。', '工作区审批模式已存在并具有优先级。用户级别的更改将无效。',
'(Use Enter to select, Tab to change focus)': '(Use Enter to select, Tab to change focus)':
'(使用 Enter 选择Tab 切换焦点)', '(使用 Enter 选择Tab 切换焦点)',
'Apply To': '应用于',
'User Settings': '用户设置',
'Workspace Settings': '工作区设置',
// ============================================================================ // ============================================================================
// Commands - Memory // Commands - Memory
@@ -454,7 +585,7 @@ export default {
// ============================================================================ // ============================================================================
'Get started': '开始使用', 'Get started': '开始使用',
'How would you like to authenticate for this project?': 'How would you like to authenticate for this project?':
'您如何为此项目进行证?', '您希望如何为此项目进行身份验证?',
'OpenAI API key is required to use OpenAI authentication.': 'OpenAI API key is required to use OpenAI authentication.':
'使用 OpenAI 认证需要 OpenAI API 密钥', '使用 OpenAI 认证需要 OpenAI API 密钥',
'You must select an auth method to proceed. Press Ctrl+C again to exit.': 'You must select an auth method to proceed. Press Ctrl+C again to exit.':
@@ -462,8 +593,8 @@ export default {
'(Use Enter to Set Auth)': '(使用 Enter 设置认证)', '(Use Enter to Set Auth)': '(使用 Enter 设置认证)',
'Terms of Services and Privacy Notice for Qwen Code': 'Terms of Services and Privacy Notice for Qwen Code':
'Qwen Code 的服务条款和隐私声明', 'Qwen Code 的服务条款和隐私声明',
'Qwen OAuth': 'Qwen OAuth', 'Qwen OAuth': 'Qwen OAuth (推荐)',
OpenAI: 'OpenAI', OpenAI: 'OpenAI (兼容 API)',
'Failed to login. Message: {{message}}': '登录失败。消息:{{message}}', 'Failed to login. Message: {{message}}': '登录失败。消息:{{message}}',
'Authentication is enforced to be {{enforcedType}}, but you are currently using {{currentType}}.': 'Authentication is enforced to be {{enforcedType}}, but you are currently using {{currentType}}.':
'认证方式被强制设置为 {{enforcedType}},但您当前使用的是 {{currentType}}', '认证方式被强制设置为 {{enforcedType}},但您当前使用的是 {{currentType}}',

View File

@@ -19,6 +19,7 @@ import { SettingScope } from '../../config/settings.js';
import type { EditorType } from '@qwen-code/qwen-code-core'; import type { EditorType } from '@qwen-code/qwen-code-core';
import { isEditorAvailable } from '@qwen-code/qwen-code-core'; import { isEditorAvailable } from '@qwen-code/qwen-code-core';
import { useKeypress } from '../hooks/useKeypress.js'; import { useKeypress } from '../hooks/useKeypress.js';
import { t } from '../../i18n/index.js';
interface EditorDialogProps { interface EditorDialogProps {
onSelect: (editorType: EditorType | undefined, scope: SettingScope) => void; onSelect: (editorType: EditorType | undefined, scope: SettingScope) => void;
@@ -66,12 +67,16 @@ export function EditorSettingsDialog({
const scopeItems = [ const scopeItems = [
{ {
label: 'User Settings', get label() {
return t('User Settings');
},
value: SettingScope.User, value: SettingScope.User,
key: SettingScope.User, key: SettingScope.User,
}, },
{ {
label: 'Workspace Settings', get label() {
return t('Workspace Settings');
},
value: SettingScope.Workspace, value: SettingScope.Workspace,
key: SettingScope.Workspace, key: SettingScope.Workspace,
}, },
@@ -145,7 +150,8 @@ export function EditorSettingsDialog({
<Box marginTop={1} flexDirection="column"> <Box marginTop={1} flexDirection="column">
<Text bold={focusedSection === 'scope'}> <Text bold={focusedSection === 'scope'}>
{focusedSection === 'scope' ? '> ' : ' '}Apply To {focusedSection === 'scope' ? '> ' : ' '}
{t('Apply To')}
</Text> </Text>
<RadioButtonSelect <RadioButtonSelect
items={scopeItems} items={scopeItems}

View File

@@ -9,6 +9,7 @@ import { Box, Text } from 'ink';
import type { SettingScope } from '../../../config/settings.js'; import type { SettingScope } from '../../../config/settings.js';
import { getScopeItems } from '../../../utils/dialogScopeUtils.js'; import { getScopeItems } from '../../../utils/dialogScopeUtils.js';
import { RadioButtonSelect } from './RadioButtonSelect.js'; import { RadioButtonSelect } from './RadioButtonSelect.js';
import { t } from '../../../i18n/index.js';
interface ScopeSelectorProps { interface ScopeSelectorProps {
/** Callback function when a scope is selected */ /** Callback function when a scope is selected */
@@ -29,6 +30,7 @@ export function ScopeSelector({
}: ScopeSelectorProps): React.JSX.Element { }: ScopeSelectorProps): React.JSX.Element {
const scopeItems = getScopeItems().map((item) => ({ const scopeItems = getScopeItems().map((item) => ({
...item, ...item,
label: t(item.label),
key: item.value, key: item.value,
})); }));
@@ -40,7 +42,8 @@ export function ScopeSelector({
return ( return (
<Box flexDirection="column"> <Box flexDirection="column">
<Text bold={isFocused} wrap="truncate"> <Text bold={isFocused} wrap="truncate">
{isFocused ? '> ' : ' '}Apply To {isFocused ? '> ' : ' '}
{t('Apply To')}
</Text> </Text>
<RadioButtonSelect <RadioButtonSelect
items={scopeItems} items={scopeItems}

View File

@@ -20,6 +20,7 @@ import type { Config } from '@qwen-code/qwen-code-core';
import { theme } from '../../../semantic-colors.js'; import { theme } from '../../../semantic-colors.js';
import { TextEntryStep } from './TextEntryStep.js'; import { TextEntryStep } from './TextEntryStep.js';
import { useKeypress } from '../../../hooks/useKeypress.js'; import { useKeypress } from '../../../hooks/useKeypress.js';
import { t } from '../../../../i18n/index.js';
interface AgentCreationWizardProps { interface AgentCreationWizardProps {
onClose: () => void; onClose: () => void;
@@ -90,25 +91,25 @@ export function AgentCreationWizard({
const n = state.currentStep; const n = state.currentStep;
switch (kind) { switch (kind) {
case 'LOCATION': case 'LOCATION':
return `Step ${n}: Choose Location`; return t('Step {{n}}: Choose Location', { n: n.toString() });
case 'GEN_METHOD': case 'GEN_METHOD':
return `Step ${n}: Choose Generation Method`; return t('Step {{n}}: Choose Generation Method', { n: n.toString() });
case 'LLM_DESC': case 'LLM_DESC':
return `Step ${n}: Describe Your Subagent`; return t('Step {{n}}: Describe Your Subagent', { n: n.toString() });
case 'MANUAL_NAME': case 'MANUAL_NAME':
return `Step ${n}: Enter Subagent Name`; return t('Step {{n}}: Enter Subagent Name', { n: n.toString() });
case 'MANUAL_PROMPT': case 'MANUAL_PROMPT':
return `Step ${n}: Enter System Prompt`; return t('Step {{n}}: Enter System Prompt', { n: n.toString() });
case 'MANUAL_DESC': case 'MANUAL_DESC':
return `Step ${n}: Enter Description`; return t('Step {{n}}: Enter Description', { n: n.toString() });
case 'TOOLS': case 'TOOLS':
return `Step ${n}: Select Tools`; return t('Step {{n}}: Select Tools', { n: n.toString() });
case 'COLOR': case 'COLOR':
return `Step ${n}: Choose Background Color`; return t('Step {{n}}: Choose Background Color', { n: n.toString() });
case 'FINAL': case 'FINAL':
return `Step ${n}: Confirm and Save`; return t('Step {{n}}: Confirm and Save', { n: n.toString() });
default: default:
return 'Unknown Step'; return t('Unknown Step');
} }
}; };
@@ -163,11 +164,11 @@ export function AgentCreationWizard({
// Special case: During generation in description input step, only show cancel option // Special case: During generation in description input step, only show cancel option
const kind = getStepKind(state.generationMethod, state.currentStep); const kind = getStepKind(state.generationMethod, state.currentStep);
if (kind === 'LLM_DESC' && state.isGenerating) { if (kind === 'LLM_DESC' && state.isGenerating) {
return 'Esc to cancel'; return t('Esc to cancel');
} }
if (getStepKind(state.generationMethod, state.currentStep) === 'FINAL') { if (getStepKind(state.generationMethod, state.currentStep) === 'FINAL') {
return 'Press Enter to save, e to save and edit, Esc to go back'; return t('Press Enter to save, e to save and edit, Esc to go back');
} }
// Steps that have ↑↓ navigation (RadioButtonSelect components) // Steps that have ↑↓ navigation (RadioButtonSelect components)
@@ -177,14 +178,17 @@ export function AgentCreationWizard({
kindForNav === 'GEN_METHOD' || kindForNav === 'GEN_METHOD' ||
kindForNav === 'TOOLS' || kindForNav === 'TOOLS' ||
kindForNav === 'COLOR'; kindForNav === 'COLOR';
const navigationPart = hasNavigation ? '↑↓ to navigate, ' : ''; const navigationPart = hasNavigation ? t('↑↓ to navigate, ') : '';
const escAction = const escAction =
state.currentStep === WIZARD_STEPS.LOCATION_SELECTION state.currentStep === WIZARD_STEPS.LOCATION_SELECTION
? 'cancel' ? t('cancel')
: 'go back'; : t('go back');
return `Press Enter to continue, ${navigationPart}Esc to ${escAction}`; return t('Press Enter to continue, {{navigation}}Esc to {{action}}', {
navigation: navigationPart,
action: escAction,
});
}; };
return ( return (
@@ -210,16 +214,16 @@ export function AgentCreationWizard({
state={state} state={state}
dispatch={dispatch} dispatch={dispatch}
onNext={handleNext} onNext={handleNext}
description="Enter a clear, unique name for this subagent." description={t('Enter a clear, unique name for this subagent.')}
placeholder="e.g., Code Reviewer" placeholder={t('e.g., Code Reviewer')}
height={1} height={1}
initialText={state.generatedName} initialText={state.generatedName}
onChange={(t) => { onChange={(text) => {
const value = t; // keep raw, trim later when validating const value = text; // keep raw, trim later when validating
dispatch({ type: 'SET_GENERATED_NAME', name: value }); dispatch({ type: 'SET_GENERATED_NAME', name: value });
}} }}
validate={(t) => validate={(text) =>
t.trim().length === 0 ? 'Name cannot be empty.' : null text.trim().length === 0 ? t('Name cannot be empty.') : null
} }
/> />
); );
@@ -230,18 +234,22 @@ export function AgentCreationWizard({
state={state} state={state}
dispatch={dispatch} dispatch={dispatch}
onNext={handleNext} onNext={handleNext}
description="Write the system prompt that defines this subagent's behavior. Be comprehensive for best results." description={t(
placeholder="e.g., You are an expert code reviewer..." "Write the system prompt that defines this subagent's behavior. Be comprehensive for best results.",
)}
placeholder={t('e.g., You are an expert code reviewer...')}
height={10} height={10}
initialText={state.generatedSystemPrompt} initialText={state.generatedSystemPrompt}
onChange={(t) => { onChange={(text) => {
dispatch({ dispatch({
type: 'SET_GENERATED_SYSTEM_PROMPT', type: 'SET_GENERATED_SYSTEM_PROMPT',
systemPrompt: t, systemPrompt: text,
}); });
}} }}
validate={(t) => validate={(text) =>
t.trim().length === 0 ? 'System prompt cannot be empty.' : null text.trim().length === 0
? t('System prompt cannot be empty.')
: null
} }
/> />
); );
@@ -252,15 +260,24 @@ export function AgentCreationWizard({
state={state} state={state}
dispatch={dispatch} dispatch={dispatch}
onNext={handleNext} onNext={handleNext}
description="Describe when and how this subagent should be used." description={t(
placeholder="e.g., Reviews code for best practices and potential bugs." 'Describe when and how this subagent should be used.',
)}
placeholder={t(
'e.g., Reviews code for best practices and potential bugs.',
)}
height={6} height={6}
initialText={state.generatedDescription} initialText={state.generatedDescription}
onChange={(t) => { onChange={(text) => {
dispatch({ type: 'SET_GENERATED_DESCRIPTION', description: t }); dispatch({
type: 'SET_GENERATED_DESCRIPTION',
description: text,
});
}} }}
validate={(t) => validate={(text) =>
t.trim().length === 0 ? 'Description cannot be empty.' : null text.trim().length === 0
? t('Description cannot be empty.')
: null
} }
/> />
); );
@@ -292,7 +309,9 @@ export function AgentCreationWizard({
return ( return (
<Box> <Box>
<Text color={theme.status.error}> <Text color={theme.status.error}>
Invalid step: {state.currentStep} {t('Invalid step: {{step}}', {
step: state.currentStep.toString(),
})}
</Text> </Text>
</Box> </Box>
); );

View File

@@ -15,6 +15,7 @@ import { theme } from '../../../semantic-colors.js';
import { shouldShowColor, getColorForDisplay } from '../utils.js'; import { shouldShowColor, getColorForDisplay } from '../utils.js';
import { useLaunchEditor } from '../../../hooks/useLaunchEditor.js'; import { useLaunchEditor } from '../../../hooks/useLaunchEditor.js';
import { useKeypress } from '../../../hooks/useKeypress.js'; import { useKeypress } from '../../../hooks/useKeypress.js';
import { t } from '../../../../i18n/index.js';
/** /**
* Step 6: Final confirmation and actions. * Step 6: Final confirmation and actions.
@@ -62,15 +63,24 @@ export function CreationSummary({
if (conflictLevel === targetLevel) { if (conflictLevel === targetLevel) {
allWarnings.push( allWarnings.push(
`Name "${state.generatedName}" already exists at ${conflictLevel} level - will overwrite existing subagent`, t(
'Name "{{name}}" already exists at {{level}} level - will overwrite existing subagent',
{ name: state.generatedName, level: conflictLevel },
),
); );
} else if (targetLevel === 'project') { } else if (targetLevel === 'project') {
allWarnings.push( allWarnings.push(
`Name "${state.generatedName}" exists at user level - project level will take precedence`, t(
'Name "{{name}}" exists at user level - project level will take precedence',
{ name: state.generatedName },
),
); );
} else { } else {
allWarnings.push( allWarnings.push(
`Name "${state.generatedName}" exists at project level - existing subagent will take precedence`, t(
'Name "{{name}}" exists at project level - existing subagent will take precedence',
{ name: state.generatedName },
),
); );
} }
} }
@@ -83,12 +93,16 @@ export function CreationSummary({
// Check length warnings // Check length warnings
if (state.generatedDescription.length > 300) { if (state.generatedDescription.length > 300) {
allWarnings.push( allWarnings.push(
`Description is over ${state.generatedDescription.length} characters`, t('Description is over {{length}} characters', {
length: state.generatedDescription.length.toString(),
}),
); );
} }
if (state.generatedSystemPrompt.length > 10000) { if (state.generatedSystemPrompt.length > 10000) {
allWarnings.push( allWarnings.push(
`System prompt is over ${state.generatedSystemPrompt.length} characters`, t('System prompt is over {{length}} characters', {
length: state.generatedSystemPrompt.length.toString(),
}),
); );
} }
@@ -181,7 +195,9 @@ export function CreationSummary({
showSuccessAndClose(); showSuccessAndClose();
} catch (error) { } catch (error) {
setSaveError( setSaveError(
`Failed to save and edit subagent: ${error instanceof Error ? error.message : 'Unknown error'}`, t('Failed to save and edit subagent: {{error}}', {
error: error instanceof Error ? error.message : 'Unknown error',
}),
); );
} }
}, [ }, [
@@ -215,13 +231,15 @@ export function CreationSummary({
<Box flexDirection="column" gap={1}> <Box flexDirection="column" gap={1}>
<Box> <Box>
<Text bold color={theme.status.success}> <Text bold color={theme.status.success}>
Subagent Created Successfully! {t('✅ Subagent Created Successfully!')}
</Text> </Text>
</Box> </Box>
<Box> <Box>
<Text> <Text>
Subagent &quot;{state.generatedName}&quot; has been saved to{' '} {t('Subagent "{{name}}" has been saved to {{level}} level.', {
{state.location} level. name: state.generatedName,
level: state.location,
})}
</Text> </Text>
</Box> </Box>
</Box> </Box>
@@ -232,35 +250,35 @@ export function CreationSummary({
<Box flexDirection="column" gap={1}> <Box flexDirection="column" gap={1}>
<Box flexDirection="column"> <Box flexDirection="column">
<Box> <Box>
<Text color={theme.text.primary}>Name: </Text> <Text color={theme.text.primary}>{t('Name: ')}</Text>
<Text color={getColorForDisplay(state.color)}> <Text color={getColorForDisplay(state.color)}>
{state.generatedName} {state.generatedName}
</Text> </Text>
</Box> </Box>
<Box> <Box>
<Text color={theme.text.primary}>Location: </Text> <Text color={theme.text.primary}>{t('Location: ')}</Text>
<Text> <Text>
{state.location === 'project' {state.location === 'project'
? 'Project Level (.qwen/agents/)' ? t('Project Level (.qwen/agents/)')
: 'User Level (~/.qwen/agents/)'} : t('User Level (~/.qwen/agents/)')}
</Text> </Text>
</Box> </Box>
<Box> <Box>
<Text color={theme.text.primary}>Tools: </Text> <Text color={theme.text.primary}>{t('Tools: ')}</Text>
<Text>{toolsDisplay}</Text> <Text>{toolsDisplay}</Text>
</Box> </Box>
{shouldShowColor(state.color) && ( {shouldShowColor(state.color) && (
<Box> <Box>
<Text color={theme.text.primary}>Color: </Text> <Text color={theme.text.primary}>{t('Color: ')}</Text>
<Text color={getColorForDisplay(state.color)}>{state.color}</Text> <Text color={getColorForDisplay(state.color)}>{state.color}</Text>
</Box> </Box>
)} )}
<Box marginTop={1}> <Box marginTop={1}>
<Text color={theme.text.primary}>Description:</Text> <Text color={theme.text.primary}>{t('Description:')}</Text>
</Box> </Box>
<Box padding={1} paddingBottom={0}> <Box padding={1} paddingBottom={0}>
<Text wrap="wrap"> <Text wrap="wrap">
@@ -269,7 +287,7 @@ export function CreationSummary({
</Box> </Box>
<Box marginTop={1}> <Box marginTop={1}>
<Text color={theme.text.primary}>System Prompt:</Text> <Text color={theme.text.primary}>{t('System Prompt:')}</Text>
</Box> </Box>
<Box padding={1} paddingBottom={0}> <Box padding={1} paddingBottom={0}>
<Text wrap="wrap"> <Text wrap="wrap">
@@ -281,7 +299,7 @@ export function CreationSummary({
{saveError && ( {saveError && (
<Box flexDirection="column"> <Box flexDirection="column">
<Text bold color={theme.status.error}> <Text bold color={theme.status.error}>
Error saving subagent: {t('❌ Error saving subagent:')}
</Text> </Text>
<Box flexDirection="column" padding={1} paddingBottom={0}> <Box flexDirection="column" padding={1} paddingBottom={0}>
<Text color={theme.status.error} wrap="wrap"> <Text color={theme.status.error} wrap="wrap">
@@ -294,7 +312,7 @@ export function CreationSummary({
{warnings.length > 0 && ( {warnings.length > 0 && (
<Box flexDirection="column"> <Box flexDirection="column">
<Text bold color={theme.status.warning}> <Text bold color={theme.status.warning}>
Warnings: {t('Warnings:')}
</Text> </Text>
<Box flexDirection="column" padding={1} paddingBottom={0}> <Box flexDirection="column" padding={1} paddingBottom={0}>
{warnings.map((warning, index) => ( {warnings.map((warning, index) => (

View File

@@ -14,6 +14,7 @@ import { useKeypress, type Key } from '../../../hooks/useKeypress.js';
import { keyMatchers, Command } from '../../../keyMatchers.js'; import { keyMatchers, Command } from '../../../keyMatchers.js';
import { theme } from '../../../semantic-colors.js'; import { theme } from '../../../semantic-colors.js';
import { TextInput } from '../../shared/TextInput.js'; import { TextInput } from '../../shared/TextInput.js';
import { t } from '../../../../i18n/index.js';
/** /**
* Step 3: Description input with LLM generation. * Step 3: Description input with LLM generation.
@@ -103,7 +104,9 @@ export function DescriptionInput({
dispatch({ dispatch({
type: 'SET_VALIDATION_ERRORS', type: 'SET_VALIDATION_ERRORS',
errors: [ errors: [
`Failed to generate subagent: ${error instanceof Error ? error.message : 'Unknown error'}`, t('Failed to generate subagent: {{error}}', {
error: error instanceof Error ? error.message : 'Unknown error',
}),
], ],
}); });
} }
@@ -135,15 +138,17 @@ export function DescriptionInput({
isActive: state.isGenerating, isActive: state.isGenerating,
}); });
const placeholder = const placeholder = t(
'e.g., Expert code reviewer that reviews code based on best practices...'; 'e.g., Expert code reviewer that reviews code based on best practices...',
);
return ( return (
<Box flexDirection="column" gap={1}> <Box flexDirection="column" gap={1}>
<Box> <Box>
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
Describe what this subagent should do and when it should be used. (Be {t(
comprehensive for best results) 'Describe what this subagent should do and when it should be used. (Be comprehensive for best results)',
)}
</Text> </Text>
</Box> </Box>
@@ -153,7 +158,7 @@ export function DescriptionInput({
<Spinner /> <Spinner />
</Box> </Box>
<Text color={theme.text.accent}> <Text color={theme.text.accent}>
Generating subagent configuration... {t('Generating subagent configuration...')}
</Text> </Text>
</Box> </Box>
) : ( ) : (

View File

@@ -7,6 +7,7 @@
import { Box } from 'ink'; import { Box } from 'ink';
import { RadioButtonSelect } from '../../shared/RadioButtonSelect.js'; import { RadioButtonSelect } from '../../shared/RadioButtonSelect.js';
import type { WizardStepProps } from '../types.js'; import type { WizardStepProps } from '../types.js';
import { t } from '../../../../i18n/index.js';
interface GenerationOption { interface GenerationOption {
label: string; label: string;
@@ -15,11 +16,15 @@ interface GenerationOption {
const generationOptions: GenerationOption[] = [ const generationOptions: GenerationOption[] = [
{ {
label: 'Generate with Qwen Code (Recommended)', get label() {
return t('Generate with Qwen Code (Recommended)');
},
value: 'qwen', value: 'qwen',
}, },
{ {
label: 'Manual Creation', get label() {
return t('Manual Creation');
},
value: 'manual', value: 'manual',
}, },
]; ];

View File

@@ -7,6 +7,7 @@
import { Box } from 'ink'; import { Box } from 'ink';
import { RadioButtonSelect } from '../../shared/RadioButtonSelect.js'; import { RadioButtonSelect } from '../../shared/RadioButtonSelect.js';
import type { WizardStepProps } from '../types.js'; import type { WizardStepProps } from '../types.js';
import { t } from '../../../../i18n/index.js';
interface LocationOption { interface LocationOption {
label: string; label: string;
@@ -15,11 +16,15 @@ interface LocationOption {
const locationOptions: LocationOption[] = [ const locationOptions: LocationOption[] = [
{ {
label: 'Project Level (.qwen/agents/)', get label() {
return t('Project Level (.qwen/agents/)');
},
value: 'project', value: 'project',
}, },
{ {
label: 'User Level (~/.qwen/agents/)', get label() {
return t('User Level (~/.qwen/agents/)');
},
value: 'user', value: 'user',
}, },
]; ];

View File

@@ -10,6 +10,7 @@ import { RadioButtonSelect } from '../../shared/RadioButtonSelect.js';
import type { ToolCategory } from '../types.js'; import type { ToolCategory } from '../types.js';
import { Kind, type Config } from '@qwen-code/qwen-code-core'; import { Kind, type Config } from '@qwen-code/qwen-code-core';
import { theme } from '../../../semantic-colors.js'; import { theme } from '../../../semantic-colors.js';
import { t } from '../../../../i18n/index.js';
interface ToolOption { interface ToolOption {
label: string; label: string;
@@ -45,7 +46,7 @@ export function ToolSelector({
toolCategories: [ toolCategories: [
{ {
id: 'all', id: 'all',
name: 'All Tools (Default)', name: t('All Tools (Default)'),
tools: [], tools: [],
}, },
], ],
@@ -89,22 +90,22 @@ export function ToolSelector({
const toolCategories = [ const toolCategories = [
{ {
id: 'all', id: 'all',
name: 'All Tools', name: t('All Tools'),
tools: [], tools: [],
}, },
{ {
id: 'read', id: 'read',
name: 'Read-only Tools', name: t('Read-only Tools'),
tools: readTools, tools: readTools,
}, },
{ {
id: 'edit', id: 'edit',
name: 'Read & Edit Tools', name: t('Read & Edit Tools'),
tools: [...readTools, ...editTools], tools: [...readTools, ...editTools],
}, },
{ {
id: 'execute', id: 'execute',
name: 'Read & Edit & Execution Tools', name: t('Read & Edit & Execution Tools'),
tools: [...readTools, ...editTools, ...executeTools], tools: [...readTools, ...editTools, ...executeTools],
}, },
].filter((category) => category.id === 'all' || category.tools.length > 0); ].filter((category) => category.id === 'all' || category.tools.length > 0);
@@ -202,11 +203,11 @@ export function ToolSelector({
<Box flexDirection="column"> <Box flexDirection="column">
{currentCategory.id === 'all' ? ( {currentCategory.id === 'all' ? (
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
All tools selected, including MCP tools {t('All tools selected, including MCP tools')}
</Text> </Text>
) : currentCategory.tools.length > 0 ? ( ) : currentCategory.tools.length > 0 ? (
<> <>
<Text color={theme.text.secondary}>Selected tools:</Text> <Text color={theme.text.secondary}>{t('Selected tools:')}</Text>
<Box flexDirection="column" marginLeft={2}> <Box flexDirection="column" marginLeft={2}>
{(() => { {(() => {
// Filter the already categorized tools to show only those in current category // Filter the already categorized tools to show only those in current category
@@ -224,17 +225,19 @@ export function ToolSelector({
<> <>
{categoryReadTools.length > 0 && ( {categoryReadTools.length > 0 && (
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
Read-only tools: {categoryReadTools.join(', ')} {t('Read-only tools:')}{' '}
{categoryReadTools.join(', ')}
</Text> </Text>
)} )}
{categoryEditTools.length > 0 && ( {categoryEditTools.length > 0 && (
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
Edit tools: {categoryEditTools.join(', ')} {t('Edit tools:')} {categoryEditTools.join(', ')}
</Text> </Text>
)} )}
{categoryExecuteTools.length > 0 && ( {categoryExecuteTools.length > 0 && (
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
Execution tools: {categoryExecuteTools.join(', ')} {t('Execution tools:')}{' '}
{categoryExecuteTools.join(', ')}
</Text> </Text>
)} )}
</> </>

View File

@@ -9,6 +9,7 @@ import { Box } from 'ink';
import { RadioButtonSelect } from '../../shared/RadioButtonSelect.js'; import { RadioButtonSelect } from '../../shared/RadioButtonSelect.js';
import { MANAGEMENT_STEPS } from '../types.js'; import { MANAGEMENT_STEPS } from '../types.js';
import { type SubagentConfig } from '@qwen-code/qwen-code-core'; import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import { t } from '../../../../i18n/index.js';
interface ActionSelectionStepProps { interface ActionSelectionStepProps {
selectedAgent: SubagentConfig | null; selectedAgent: SubagentConfig | null;
@@ -27,10 +28,34 @@ export const ActionSelectionStep = ({
// Filter actions based on whether the agent is built-in // Filter actions based on whether the agent is built-in
const allActions = [ const allActions = [
{ key: 'view', label: 'View Agent', value: 'view' as const }, {
{ key: 'edit', label: 'Edit Agent', value: 'edit' as const }, key: 'view',
{ key: 'delete', label: 'Delete Agent', value: 'delete' as const }, get label() {
{ key: 'back', label: 'Back', value: 'back' as const }, return t('View Agent');
},
value: 'view' as const,
},
{
key: 'edit',
get label() {
return t('Edit Agent');
},
value: 'edit' as const,
},
{
key: 'delete',
get label() {
return t('Delete Agent');
},
value: 'delete' as const,
},
{
key: 'back',
get label() {
return t('Back');
},
value: 'back' as const,
},
]; ];
const actions = selectedAgent?.isBuiltin const actions = selectedAgent?.isBuiltin

View File

@@ -9,6 +9,7 @@ import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import type { StepNavigationProps } from '../types.js'; import type { StepNavigationProps } from '../types.js';
import { theme } from '../../../semantic-colors.js'; import { theme } from '../../../semantic-colors.js';
import { useKeypress } from '../../../hooks/useKeypress.js'; import { useKeypress } from '../../../hooks/useKeypress.js';
import { t } from '../../../../i18n/index.js';
interface AgentDeleteStepProps extends StepNavigationProps { interface AgentDeleteStepProps extends StepNavigationProps {
selectedAgent: SubagentConfig | null; selectedAgent: SubagentConfig | null;
@@ -41,7 +42,7 @@ export function AgentDeleteStep({
if (!selectedAgent) { if (!selectedAgent) {
return ( return (
<Box> <Box>
<Text color={theme.status.error}>No agent selected</Text> <Text color={theme.status.error}>{t('No agent selected')}</Text>
</Box> </Box>
); );
} }
@@ -49,8 +50,9 @@ export function AgentDeleteStep({
return ( return (
<Box flexDirection="column" gap={1}> <Box flexDirection="column" gap={1}>
<Text color={theme.status.error}> <Text color={theme.status.error}>
Are you sure you want to delete agent &ldquo;{selectedAgent.name} {t('Are you sure you want to delete agent "{{name}}"?', {
&rdquo;? name: selectedAgent.name,
})}
</Text> </Text>
</Box> </Box>
); );

View File

@@ -11,6 +11,7 @@ import { MANAGEMENT_STEPS } from '../types.js';
import { theme } from '../../../semantic-colors.js'; import { theme } from '../../../semantic-colors.js';
import { useLaunchEditor } from '../../../hooks/useLaunchEditor.js'; import { useLaunchEditor } from '../../../hooks/useLaunchEditor.js';
import { type SubagentConfig } from '@qwen-code/qwen-code-core'; import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import { t } from '../../../../i18n/index.js';
interface EditOption { interface EditOption {
id: string; id: string;
@@ -20,15 +21,21 @@ interface EditOption {
const editOptions: EditOption[] = [ const editOptions: EditOption[] = [
{ {
id: 'editor', id: 'editor',
label: 'Open in editor', get label() {
return t('Open in editor');
},
}, },
{ {
id: 'tools', id: 'tools',
label: 'Edit tools', get label() {
return t('Edit tools');
},
}, },
{ {
id: 'color', id: 'color',
label: 'Edit color', get label() {
return t('Edit color');
},
}, },
]; ];
@@ -65,7 +72,9 @@ export function EditOptionsStep({
await launchEditor(selectedAgent?.filePath); await launchEditor(selectedAgent?.filePath);
} catch (err) { } catch (err) {
setError( setError(
`Failed to launch editor: ${err instanceof Error ? err.message : 'Unknown error'}`, t('Failed to launch editor: {{error}}', {
error: err instanceof Error ? err.message : 'Unknown error',
}),
); );
} }
} else if (selectedValue === 'tools') { } else if (selectedValue === 'tools') {
@@ -98,7 +107,7 @@ export function EditOptionsStep({
{error && ( {error && (
<Box flexDirection="column"> <Box flexDirection="column">
<Text bold color={theme.status.error}> <Text bold color={theme.status.error}>
Error: {t('❌ Error:')}
</Text> </Text>
<Box flexDirection="column" padding={1} paddingBottom={0}> <Box flexDirection="column" padding={1} paddingBottom={0}>
<Text color={theme.status.error} wrap="wrap"> <Text color={theme.status.error} wrap="wrap">

View File

@@ -9,6 +9,7 @@ import { Box, Text } from 'ink';
import { theme } from '../../../semantic-colors.js'; import { theme } from '../../../semantic-colors.js';
import { useKeypress } from '../../../hooks/useKeypress.js'; import { useKeypress } from '../../../hooks/useKeypress.js';
import { type SubagentConfig } from '@qwen-code/qwen-code-core'; import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import { t } from '../../../../i18n/index.js';
interface NavigationState { interface NavigationState {
currentBlock: 'project' | 'user' | 'builtin'; currentBlock: 'project' | 'user' | 'builtin';
@@ -205,9 +206,9 @@ export const AgentSelectionStep = ({
if (availableAgents.length === 0) { if (availableAgents.length === 0) {
return ( return (
<Box flexDirection="column"> <Box flexDirection="column">
<Text color={theme.text.secondary}>No subagents found.</Text> <Text color={theme.text.secondary}>{t('No subagents found.')}</Text>
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
Use &apos;/agents create&apos; to create your first subagent. {t("Use '/agents create' to create your first subagent.")}
</Text> </Text>
</Box> </Box>
); );
@@ -237,7 +238,7 @@ export const AgentSelectionStep = ({
{agent.isBuiltin && ( {agent.isBuiltin && (
<Text color={isSelected ? theme.text.accent : theme.text.secondary}> <Text color={isSelected ? theme.text.accent : theme.text.secondary}>
{' '} {' '}
(built-in) {t('(built-in)')}
</Text> </Text>
)} )}
{agent.level === 'user' && projectNames.has(agent.name) && ( {agent.level === 'user' && projectNames.has(agent.name) && (
@@ -245,7 +246,7 @@ export const AgentSelectionStep = ({
color={isSelected ? theme.status.warning : theme.text.secondary} color={isSelected ? theme.status.warning : theme.text.secondary}
> >
{' '} {' '}
(overridden by project level agent) {t('(overridden by project level agent)')}
</Text> </Text>
)} )}
</Text> </Text>
@@ -265,7 +266,9 @@ export const AgentSelectionStep = ({
{projectAgents.length > 0 && ( {projectAgents.length > 0 && (
<Box flexDirection="column" marginBottom={1}> <Box flexDirection="column" marginBottom={1}>
<Text color={theme.text.primary} bold> <Text color={theme.text.primary} bold>
Project Level ({projectAgents[0].filePath.replace(/\/[^/]+$/, '')}) {t('Project Level ({{path}})', {
path: projectAgents[0].filePath.replace(/\/[^/]+$/, ''),
})}
</Text> </Text>
<Box marginTop={1} flexDirection="column"> <Box marginTop={1} flexDirection="column">
{projectAgents.map((agent, index) => { {projectAgents.map((agent, index) => {
@@ -285,7 +288,9 @@ export const AgentSelectionStep = ({
marginBottom={builtinAgents.length > 0 ? 1 : 0} marginBottom={builtinAgents.length > 0 ? 1 : 0}
> >
<Text color={theme.text.primary} bold> <Text color={theme.text.primary} bold>
User Level ({userAgents[0].filePath.replace(/\/[^/]+$/, '')}) {t('User Level ({{path}})', {
path: userAgents[0].filePath.replace(/\/[^/]+$/, ''),
})}
</Text> </Text>
<Box marginTop={1} flexDirection="column"> <Box marginTop={1} flexDirection="column">
{userAgents.map((agent, index) => { {userAgents.map((agent, index) => {
@@ -302,7 +307,7 @@ export const AgentSelectionStep = ({
{builtinAgents.length > 0 && ( {builtinAgents.length > 0 && (
<Box flexDirection="column"> <Box flexDirection="column">
<Text color={theme.text.primary} bold> <Text color={theme.text.primary} bold>
Built-in Agents {t('Built-in Agents')}
</Text> </Text>
<Box marginTop={1} flexDirection="column"> <Box marginTop={1} flexDirection="column">
{builtinAgents.map((agent, index) => { {builtinAgents.map((agent, index) => {
@@ -321,7 +326,9 @@ export const AgentSelectionStep = ({
builtinAgents.length > 0) && ( builtinAgents.length > 0) && (
<Box marginTop={1}> <Box marginTop={1}>
<Text color={theme.text.secondary}> <Text color={theme.text.secondary}>
Using: {enabledAgentsCount} agents {t('Using: {{count}} agents', {
count: enabledAgentsCount.toString(),
})}
</Text> </Text>
</Box> </Box>
)} )}

View File

@@ -8,6 +8,7 @@ import { Box, Text } from 'ink';
import { theme } from '../../../semantic-colors.js'; import { theme } from '../../../semantic-colors.js';
import { shouldShowColor, getColorForDisplay } from '../utils.js'; import { shouldShowColor, getColorForDisplay } from '../utils.js';
import { type SubagentConfig } from '@qwen-code/qwen-code-core'; import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import { t } from '../../../../i18n/index.js';
interface AgentViewerStepProps { interface AgentViewerStepProps {
selectedAgent: SubagentConfig | null; selectedAgent: SubagentConfig | null;
@@ -17,7 +18,7 @@ export const AgentViewerStep = ({ selectedAgent }: AgentViewerStepProps) => {
if (!selectedAgent) { if (!selectedAgent) {
return ( return (
<Box> <Box>
<Text color={theme.status.error}>No agent selected</Text> <Text color={theme.status.error}>{t('No agent selected')}</Text>
</Box> </Box>
); );
} }
@@ -30,31 +31,31 @@ export const AgentViewerStep = ({ selectedAgent }: AgentViewerStepProps) => {
<Box flexDirection="column" gap={1}> <Box flexDirection="column" gap={1}>
<Box flexDirection="column"> <Box flexDirection="column">
<Box> <Box>
<Text color={theme.text.primary}>File Path: </Text> <Text color={theme.text.primary}>{t('File Path: ')}</Text>
<Text>{agent.filePath}</Text> <Text>{agent.filePath}</Text>
</Box> </Box>
<Box> <Box>
<Text color={theme.text.primary}>Tools: </Text> <Text color={theme.text.primary}>{t('Tools: ')}</Text>
<Text>{toolsDisplay}</Text> <Text>{toolsDisplay}</Text>
</Box> </Box>
{shouldShowColor(agent.color) && ( {shouldShowColor(agent.color) && (
<Box> <Box>
<Text color={theme.text.primary}>Color: </Text> <Text color={theme.text.primary}>{t('Color: ')}</Text>
<Text color={getColorForDisplay(agent.color)}>{agent.color}</Text> <Text color={getColorForDisplay(agent.color)}>{agent.color}</Text>
</Box> </Box>
)} )}
<Box marginTop={1}> <Box marginTop={1}>
<Text color={theme.text.primary}>Description:</Text> <Text color={theme.text.primary}>{t('Description:')}</Text>
</Box> </Box>
<Box padding={1} paddingBottom={0}> <Box padding={1} paddingBottom={0}>
<Text wrap="wrap">{agent.description}</Text> <Text wrap="wrap">{agent.description}</Text>
</Box> </Box>
<Box marginTop={1}> <Box marginTop={1}>
<Text color={theme.text.primary}>System Prompt:</Text> <Text color={theme.text.primary}>{t('System Prompt:')}</Text>
</Box> </Box>
<Box padding={1} paddingBottom={0}> <Box padding={1} paddingBottom={0}>
<Text wrap="wrap">{agent.systemPrompt}</Text> <Text wrap="wrap">{agent.systemPrompt}</Text>

View File

@@ -18,6 +18,7 @@ import { theme } from '../../../semantic-colors.js';
import { getColorForDisplay, shouldShowColor } from '../utils.js'; import { getColorForDisplay, shouldShowColor } from '../utils.js';
import type { SubagentConfig, Config } from '@qwen-code/qwen-code-core'; import type { SubagentConfig, Config } from '@qwen-code/qwen-code-core';
import { useKeypress } from '../../../hooks/useKeypress.js'; import { useKeypress } from '../../../hooks/useKeypress.js';
import { t } from '../../../../i18n/index.js';
interface AgentsManagerDialogProps { interface AgentsManagerDialogProps {
onClose: () => void; onClose: () => void;
@@ -143,21 +144,21 @@ export function AgentsManagerDialog({
const getStepHeaderText = () => { const getStepHeaderText = () => {
switch (currentStep) { switch (currentStep) {
case MANAGEMENT_STEPS.AGENT_SELECTION: case MANAGEMENT_STEPS.AGENT_SELECTION:
return 'Agents'; return t('Agents');
case MANAGEMENT_STEPS.ACTION_SELECTION: case MANAGEMENT_STEPS.ACTION_SELECTION:
return 'Choose Action'; return t('Choose Action');
case MANAGEMENT_STEPS.AGENT_VIEWER: case MANAGEMENT_STEPS.AGENT_VIEWER:
return selectedAgent?.name; return selectedAgent?.name;
case MANAGEMENT_STEPS.EDIT_OPTIONS: case MANAGEMENT_STEPS.EDIT_OPTIONS:
return `Edit ${selectedAgent?.name}`; return t('Edit {{name}}', { name: selectedAgent?.name || '' });
case MANAGEMENT_STEPS.EDIT_TOOLS: case MANAGEMENT_STEPS.EDIT_TOOLS:
return `Edit Tools: ${selectedAgent?.name}`; return t('Edit Tools: {{name}}', { name: selectedAgent?.name || '' });
case MANAGEMENT_STEPS.EDIT_COLOR: case MANAGEMENT_STEPS.EDIT_COLOR:
return `Edit Color: ${selectedAgent?.name}`; return t('Edit Color: {{name}}', { name: selectedAgent?.name || '' });
case MANAGEMENT_STEPS.DELETE_CONFIRMATION: case MANAGEMENT_STEPS.DELETE_CONFIRMATION:
return `Delete ${selectedAgent?.name}`; return t('Delete {{name}}', { name: selectedAgent?.name || '' });
default: default:
return 'Unknown Step'; return t('Unknown Step');
} }
}; };
@@ -183,20 +184,20 @@ export function AgentsManagerDialog({
const getNavigationInstructions = () => { const getNavigationInstructions = () => {
if (currentStep === MANAGEMENT_STEPS.AGENT_SELECTION) { if (currentStep === MANAGEMENT_STEPS.AGENT_SELECTION) {
if (availableAgents.length === 0) { if (availableAgents.length === 0) {
return 'Esc to close'; return t('Esc to close');
} }
return 'Enter to select, ↑↓ to navigate, Esc to close'; return t('Enter to select, ↑↓ to navigate, Esc to close');
} }
if (currentStep === MANAGEMENT_STEPS.AGENT_VIEWER) { if (currentStep === MANAGEMENT_STEPS.AGENT_VIEWER) {
return 'Esc to go back'; return t('Esc to go back');
} }
if (currentStep === MANAGEMENT_STEPS.DELETE_CONFIRMATION) { if (currentStep === MANAGEMENT_STEPS.DELETE_CONFIRMATION) {
return 'Enter to confirm, Esc to cancel'; return t('Enter to confirm, Esc to cancel');
} }
return 'Enter to select, ↑↓ to navigate, Esc to go back'; return t('Enter to select, ↑↓ to navigate, Esc to go back');
}; };
return ( return (
@@ -295,7 +296,9 @@ export function AgentsManagerDialog({
default: default:
return ( return (
<Box> <Box>
<Text color={theme.status.error}>Invalid step: {currentStep}</Text> <Text color={theme.status.error}>
{t('Invalid step: {{step}}', { step: currentStep })}
</Text>
</Box> </Box>
); );
} }