feat(i18n): Add Internationalization Support for UI and LLM Output (#1058)

This commit is contained in:
pomelo
2025-11-21 15:44:37 +08:00
committed by GitHub
parent 640f30655d
commit 48b77541c3
98 changed files with 4740 additions and 636 deletions

View File

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

View File

@@ -15,6 +15,7 @@ import { theme } from '../../../semantic-colors.js';
import { shouldShowColor, getColorForDisplay } from '../utils.js';
import { useLaunchEditor } from '../../../hooks/useLaunchEditor.js';
import { useKeypress } from '../../../hooks/useKeypress.js';
import { t } from '../../../../i18n/index.js';
/**
* Step 6: Final confirmation and actions.
@@ -62,15 +63,24 @@ export function CreationSummary({
if (conflictLevel === targetLevel) {
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') {
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 {
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
if (state.generatedDescription.length > 300) {
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) {
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();
} catch (error) {
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>
<Text bold color={theme.status.success}>
Subagent Created Successfully!
{t('✅ Subagent Created Successfully!')}
</Text>
</Box>
<Box>
<Text>
Subagent &quot;{state.generatedName}&quot; has been saved to{' '}
{state.location} level.
{t('Subagent "{{name}}" has been saved to {{level}} level.', {
name: state.generatedName,
level: state.location,
})}
</Text>
</Box>
</Box>
@@ -232,35 +250,35 @@ export function CreationSummary({
<Box flexDirection="column" gap={1}>
<Box flexDirection="column">
<Box>
<Text color={theme.text.primary}>Name: </Text>
<Text color={theme.text.primary}>{t('Name: ')}</Text>
<Text color={getColorForDisplay(state.color)}>
{state.generatedName}
</Text>
</Box>
<Box>
<Text color={theme.text.primary}>Location: </Text>
<Text color={theme.text.primary}>{t('Location: ')}</Text>
<Text>
{state.location === 'project'
? 'Project Level (.qwen/agents/)'
: 'User Level (~/.qwen/agents/)'}
? t('Project Level (.qwen/agents/)')
: t('User Level (~/.qwen/agents/)')}
</Text>
</Box>
<Box>
<Text color={theme.text.primary}>Tools: </Text>
<Text color={theme.text.primary}>{t('Tools: ')}</Text>
<Text>{toolsDisplay}</Text>
</Box>
{shouldShowColor(state.color) && (
<Box>
<Text color={theme.text.primary}>Color: </Text>
<Text color={theme.text.primary}>{t('Color: ')}</Text>
<Text color={getColorForDisplay(state.color)}>{state.color}</Text>
</Box>
)}
<Box marginTop={1}>
<Text color={theme.text.primary}>Description:</Text>
<Text color={theme.text.primary}>{t('Description:')}</Text>
</Box>
<Box padding={1} paddingBottom={0}>
<Text wrap="wrap">
@@ -269,7 +287,7 @@ export function CreationSummary({
</Box>
<Box marginTop={1}>
<Text color={theme.text.primary}>System Prompt:</Text>
<Text color={theme.text.primary}>{t('System Prompt:')}</Text>
</Box>
<Box padding={1} paddingBottom={0}>
<Text wrap="wrap">
@@ -281,7 +299,7 @@ export function CreationSummary({
{saveError && (
<Box flexDirection="column">
<Text bold color={theme.status.error}>
Error saving subagent:
{t('❌ Error saving subagent:')}
</Text>
<Box flexDirection="column" padding={1} paddingBottom={0}>
<Text color={theme.status.error} wrap="wrap">
@@ -294,7 +312,7 @@ export function CreationSummary({
{warnings.length > 0 && (
<Box flexDirection="column">
<Text bold color={theme.status.warning}>
Warnings:
{t('Warnings:')}
</Text>
<Box flexDirection="column" padding={1} paddingBottom={0}>
{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 { theme } from '../../../semantic-colors.js';
import { TextInput } from '../../shared/TextInput.js';
import { t } from '../../../../i18n/index.js';
/**
* Step 3: Description input with LLM generation.
@@ -103,7 +104,9 @@ export function DescriptionInput({
dispatch({
type: 'SET_VALIDATION_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,
});
const placeholder =
'e.g., Expert code reviewer that reviews code based on best practices...';
const placeholder = t(
'e.g., Expert code reviewer that reviews code based on best practices...',
);
return (
<Box flexDirection="column" gap={1}>
<Box>
<Text color={theme.text.secondary}>
Describe what this subagent should do and when it should be used. (Be
comprehensive for best results)
{t(
'Describe what this subagent should do and when it should be used. (Be comprehensive for best results)',
)}
</Text>
</Box>
@@ -153,7 +158,7 @@ export function DescriptionInput({
<Spinner />
</Box>
<Text color={theme.text.accent}>
Generating subagent configuration...
{t('Generating subagent configuration...')}
</Text>
</Box>
) : (

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,6 +11,7 @@ import { MANAGEMENT_STEPS } from '../types.js';
import { theme } from '../../../semantic-colors.js';
import { useLaunchEditor } from '../../../hooks/useLaunchEditor.js';
import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import { t } from '../../../../i18n/index.js';
interface EditOption {
id: string;
@@ -20,15 +21,21 @@ interface EditOption {
const editOptions: EditOption[] = [
{
id: 'editor',
label: 'Open in editor',
get label() {
return t('Open in editor');
},
},
{
id: 'tools',
label: 'Edit tools',
get label() {
return t('Edit tools');
},
},
{
id: 'color',
label: 'Edit color',
get label() {
return t('Edit color');
},
},
];
@@ -65,7 +72,9 @@ export function EditOptionsStep({
await launchEditor(selectedAgent?.filePath);
} catch (err) {
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') {
@@ -98,7 +107,7 @@ export function EditOptionsStep({
{error && (
<Box flexDirection="column">
<Text bold color={theme.status.error}>
Error:
{t('❌ Error:')}
</Text>
<Box flexDirection="column" padding={1} paddingBottom={0}>
<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 { useKeypress } from '../../../hooks/useKeypress.js';
import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import { t } from '../../../../i18n/index.js';
interface NavigationState {
currentBlock: 'project' | 'user' | 'builtin';
@@ -205,9 +206,9 @@ export const AgentSelectionStep = ({
if (availableAgents.length === 0) {
return (
<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}>
Use &apos;/agents create&apos; to create your first subagent.
{t("Use '/agents create' to create your first subagent.")}
</Text>
</Box>
);
@@ -237,7 +238,7 @@ export const AgentSelectionStep = ({
{agent.isBuiltin && (
<Text color={isSelected ? theme.text.accent : theme.text.secondary}>
{' '}
(built-in)
{t('(built-in)')}
</Text>
)}
{agent.level === 'user' && projectNames.has(agent.name) && (
@@ -245,7 +246,7 @@ export const AgentSelectionStep = ({
color={isSelected ? theme.status.warning : theme.text.secondary}
>
{' '}
(overridden by project level agent)
{t('(overridden by project level agent)')}
</Text>
)}
</Text>
@@ -265,7 +266,9 @@ export const AgentSelectionStep = ({
{projectAgents.length > 0 && (
<Box flexDirection="column" marginBottom={1}>
<Text color={theme.text.primary} bold>
Project Level ({projectAgents[0].filePath.replace(/\/[^/]+$/, '')})
{t('Project Level ({{path}})', {
path: projectAgents[0].filePath.replace(/\/[^/]+$/, ''),
})}
</Text>
<Box marginTop={1} flexDirection="column">
{projectAgents.map((agent, index) => {
@@ -285,7 +288,9 @@ export const AgentSelectionStep = ({
marginBottom={builtinAgents.length > 0 ? 1 : 0}
>
<Text color={theme.text.primary} bold>
User Level ({userAgents[0].filePath.replace(/\/[^/]+$/, '')})
{t('User Level ({{path}})', {
path: userAgents[0].filePath.replace(/\/[^/]+$/, ''),
})}
</Text>
<Box marginTop={1} flexDirection="column">
{userAgents.map((agent, index) => {
@@ -302,7 +307,7 @@ export const AgentSelectionStep = ({
{builtinAgents.length > 0 && (
<Box flexDirection="column">
<Text color={theme.text.primary} bold>
Built-in Agents
{t('Built-in Agents')}
</Text>
<Box marginTop={1} flexDirection="column">
{builtinAgents.map((agent, index) => {
@@ -321,7 +326,9 @@ export const AgentSelectionStep = ({
builtinAgents.length > 0) && (
<Box marginTop={1}>
<Text color={theme.text.secondary}>
Using: {enabledAgentsCount} agents
{t('Using: {{count}} agents', {
count: enabledAgentsCount.toString(),
})}
</Text>
</Box>
)}

View File

@@ -8,6 +8,7 @@ import { Box, Text } from 'ink';
import { theme } from '../../../semantic-colors.js';
import { shouldShowColor, getColorForDisplay } from '../utils.js';
import { type SubagentConfig } from '@qwen-code/qwen-code-core';
import { t } from '../../../../i18n/index.js';
interface AgentViewerStepProps {
selectedAgent: SubagentConfig | null;
@@ -17,7 +18,7 @@ export const AgentViewerStep = ({ selectedAgent }: AgentViewerStepProps) => {
if (!selectedAgent) {
return (
<Box>
<Text color={theme.status.error}>No agent selected</Text>
<Text color={theme.status.error}>{t('No agent selected')}</Text>
</Box>
);
}
@@ -30,31 +31,31 @@ export const AgentViewerStep = ({ selectedAgent }: AgentViewerStepProps) => {
<Box flexDirection="column" gap={1}>
<Box flexDirection="column">
<Box>
<Text color={theme.text.primary}>File Path: </Text>
<Text color={theme.text.primary}>{t('File Path: ')}</Text>
<Text>{agent.filePath}</Text>
</Box>
<Box>
<Text color={theme.text.primary}>Tools: </Text>
<Text color={theme.text.primary}>{t('Tools: ')}</Text>
<Text>{toolsDisplay}</Text>
</Box>
{shouldShowColor(agent.color) && (
<Box>
<Text color={theme.text.primary}>Color: </Text>
<Text color={theme.text.primary}>{t('Color: ')}</Text>
<Text color={getColorForDisplay(agent.color)}>{agent.color}</Text>
</Box>
)}
<Box marginTop={1}>
<Text color={theme.text.primary}>Description:</Text>
<Text color={theme.text.primary}>{t('Description:')}</Text>
</Box>
<Box padding={1} paddingBottom={0}>
<Text wrap="wrap">{agent.description}</Text>
</Box>
<Box marginTop={1}>
<Text color={theme.text.primary}>System Prompt:</Text>
<Text color={theme.text.primary}>{t('System Prompt:')}</Text>
</Box>
<Box padding={1} paddingBottom={0}>
<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 type { SubagentConfig, Config } from '@qwen-code/qwen-code-core';
import { useKeypress } from '../../../hooks/useKeypress.js';
import { t } from '../../../../i18n/index.js';
interface AgentsManagerDialogProps {
onClose: () => void;
@@ -143,21 +144,21 @@ export function AgentsManagerDialog({
const getStepHeaderText = () => {
switch (currentStep) {
case MANAGEMENT_STEPS.AGENT_SELECTION:
return 'Agents';
return t('Agents');
case MANAGEMENT_STEPS.ACTION_SELECTION:
return 'Choose Action';
return t('Choose Action');
case MANAGEMENT_STEPS.AGENT_VIEWER:
return selectedAgent?.name;
case MANAGEMENT_STEPS.EDIT_OPTIONS:
return `Edit ${selectedAgent?.name}`;
return t('Edit {{name}}', { name: selectedAgent?.name || '' });
case MANAGEMENT_STEPS.EDIT_TOOLS:
return `Edit Tools: ${selectedAgent?.name}`;
return t('Edit Tools: {{name}}', { name: selectedAgent?.name || '' });
case MANAGEMENT_STEPS.EDIT_COLOR:
return `Edit Color: ${selectedAgent?.name}`;
return t('Edit Color: {{name}}', { name: selectedAgent?.name || '' });
case MANAGEMENT_STEPS.DELETE_CONFIRMATION:
return `Delete ${selectedAgent?.name}`;
return t('Delete {{name}}', { name: selectedAgent?.name || '' });
default:
return 'Unknown Step';
return t('Unknown Step');
}
};
@@ -183,20 +184,20 @@ export function AgentsManagerDialog({
const getNavigationInstructions = () => {
if (currentStep === MANAGEMENT_STEPS.AGENT_SELECTION) {
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) {
return 'Esc to go back';
return t('Esc to go back');
}
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 (
@@ -295,7 +296,9 @@ export function AgentsManagerDialog({
default:
return (
<Box>
<Text color={theme.status.error}>Invalid step: {currentStep}</Text>
<Text color={theme.status.error}>
{t('Invalid step: {{step}}', { step: currentStep })}
</Text>
</Box>
);
}