add multi-language for hooks ui

This commit is contained in:
DennisYu07 2026-03-24 14:49:16 +08:00
parent b08154dbee
commit 7a53185dbf
11 changed files with 844 additions and 171 deletions

View file

@ -6,144 +6,182 @@
import { HooksConfigSource, HookEventName } from '@qwen-code/qwen-code-core';
import type { HookExitCode, HookEventDisplayInfo } from './types.js';
import { t } from '../../../i18n/index.js';
/**
* Exit code descriptions for different hook types
*/
export const HOOK_EXIT_CODES: Record<string, HookExitCode[]> = {
[HookEventName.Stop]: [
{ code: 0, description: 'stdout/stderr not shown' },
{ code: 2, description: 'show stderr to model and continue conversation' },
{ code: 'Other', description: 'show stderr to user only' },
],
[HookEventName.PreToolUse]: [
{ code: 0, description: 'stdout/stderr not shown' },
{ code: 2, description: 'show stderr to model and block tool call' },
{
code: 'Other',
description: 'show stderr to user only but continue with tool call',
},
],
[HookEventName.PostToolUse]: [
{ code: 0, description: 'stdout shown in transcript mode (ctrl+o)' },
{ code: 2, description: 'show stderr to model immediately' },
{ code: 'Other', description: 'show stderr to user only' },
],
[HookEventName.PostToolUseFailure]: [
{ code: 0, description: 'stdout shown in transcript mode (ctrl+o)' },
{ code: 2, description: 'show stderr to model immediately' },
{ code: 'Other', description: 'show stderr to user only' },
],
[HookEventName.Notification]: [
{ code: 0, description: 'stdout/stderr not shown' },
{ code: 'Other', description: 'show stderr to user only' },
],
[HookEventName.UserPromptSubmit]: [
{ code: 0, description: 'stdout shown to model' },
{
code: 2,
description:
'block processing, erase original prompt, and show stderr to user only',
},
{ code: 'Other', description: 'show stderr to user only' },
],
[HookEventName.SessionStart]: [
{ code: 0, description: 'stdout shown to model' },
{
code: 'Other',
description: 'show stderr to user only (blocking errors ignored)',
},
],
[HookEventName.SessionEnd]: [
{ code: 0, description: 'command completes successfully' },
{ code: 'Other', description: 'show stderr to user only' },
],
[HookEventName.SubagentStart]: [
{ code: 0, description: 'stdout shown to subagent' },
{
code: 'Other',
description: 'show stderr to user only (blocking errors ignored)',
},
],
[HookEventName.SubagentStop]: [
{ code: 0, description: 'stdout/stderr not shown' },
{
code: 2,
description: 'show stderr to subagent and continue having it run',
},
{ code: 'Other', description: 'show stderr to user only' },
],
[HookEventName.PreCompact]: [
{ code: 0, description: 'stdout appended as custom compact instructions' },
{ code: 2, description: 'block compaction' },
{
code: 'Other',
description: 'show stderr to user only but continue with compaction',
},
],
[HookEventName.PermissionRequest]: [
{ code: 0, description: 'use hook decision if provided' },
{ code: 'Other', description: 'show stderr to user only' },
],
};
export function getHookExitCodes(eventName: string): HookExitCode[] {
const exitCodesMap: Record<string, HookExitCode[]> = {
[HookEventName.Stop]: [
{ code: 0, description: t('stdout/stderr not shown') },
{
code: 2,
description: t('show stderr to model and continue conversation'),
},
{ code: 'Other', description: t('show stderr to user only') },
],
[HookEventName.PreToolUse]: [
{ code: 0, description: t('stdout/stderr not shown') },
{ code: 2, description: t('show stderr to model and block tool call') },
{
code: 'Other',
description: t('show stderr to user only but continue with tool call'),
},
],
[HookEventName.PostToolUse]: [
{ code: 0, description: t('stdout shown in transcript mode (ctrl+o)') },
{ code: 2, description: t('show stderr to model immediately') },
{ code: 'Other', description: t('show stderr to user only') },
],
[HookEventName.PostToolUseFailure]: [
{ code: 0, description: t('stdout shown in transcript mode (ctrl+o)') },
{ code: 2, description: t('show stderr to model immediately') },
{ code: 'Other', description: t('show stderr to user only') },
],
[HookEventName.Notification]: [
{ code: 0, description: t('stdout/stderr not shown') },
{ code: 'Other', description: t('show stderr to user only') },
],
[HookEventName.UserPromptSubmit]: [
{ code: 0, description: t('stdout shown to model') },
{
code: 2,
description: t(
'block processing, erase original prompt, and show stderr to user only',
),
},
{ code: 'Other', description: t('show stderr to user only') },
],
[HookEventName.SessionStart]: [
{ code: 0, description: t('stdout shown to model') },
{
code: 'Other',
description: t('show stderr to user only (blocking errors ignored)'),
},
],
[HookEventName.SessionEnd]: [
{ code: 0, description: t('command completes successfully') },
{ code: 'Other', description: t('show stderr to user only') },
],
[HookEventName.SubagentStart]: [
{ code: 0, description: t('stdout shown to subagent') },
{
code: 'Other',
description: t('show stderr to user only (blocking errors ignored)'),
},
],
[HookEventName.SubagentStop]: [
{ code: 0, description: t('stdout/stderr not shown') },
{
code: 2,
description: t('show stderr to subagent and continue having it run'),
},
{ code: 'Other', description: t('show stderr to user only') },
],
[HookEventName.PreCompact]: [
{
code: 0,
description: t('stdout appended as custom compact instructions'),
},
{ code: 2, description: t('block compaction') },
{
code: 'Other',
description: t('show stderr to user only but continue with compaction'),
},
],
[HookEventName.PermissionRequest]: [
{ code: 0, description: t('use hook decision if provided') },
{ code: 'Other', description: t('show stderr to user only') },
],
};
return exitCodesMap[eventName] || [];
}
/**
* Short one-line description for hooks list view
*/
export const HOOK_SHORT_DESCRIPTIONS: Record<string, string> = {
[HookEventName.PreToolUse]: 'Before tool execution',
[HookEventName.PostToolUse]: 'After tool execution',
[HookEventName.PostToolUseFailure]: 'After tool execution fails',
[HookEventName.Notification]: 'When notifications are sent',
[HookEventName.UserPromptSubmit]: 'When the user submits a prompt',
[HookEventName.SessionStart]: 'When a new session is started',
[HookEventName.Stop]: 'Right before Qwen Code concludes its response',
[HookEventName.SubagentStart]: 'When a subagent (Agent tool call) is started',
[HookEventName.SubagentStop]:
'Right before a subagent concludes its response',
[HookEventName.PreCompact]: 'Before conversation compaction',
[HookEventName.SessionEnd]: 'When a session is ending',
[HookEventName.PermissionRequest]: 'When a permission dialog is displayed',
};
export function getHookShortDescription(eventName: string): string {
const descriptions: Record<string, string> = {
[HookEventName.PreToolUse]: t('Before tool execution'),
[HookEventName.PostToolUse]: t('After tool execution'),
[HookEventName.PostToolUseFailure]: t('After tool execution fails'),
[HookEventName.Notification]: t('When notifications are sent'),
[HookEventName.UserPromptSubmit]: t('When the user submits a prompt'),
[HookEventName.SessionStart]: t('When a new session is started'),
[HookEventName.Stop]: t('Right before Qwen Code concludes its response'),
[HookEventName.SubagentStart]: t(
'When a subagent (Agent tool call) is started',
),
[HookEventName.SubagentStop]: t(
'Right before a subagent concludes its response',
),
[HookEventName.PreCompact]: t('Before conversation compaction'),
[HookEventName.SessionEnd]: t('When a session is ending'),
[HookEventName.PermissionRequest]: t(
'When a permission dialog is displayed',
),
};
return descriptions[eventName] || '';
}
/**
* Detailed description for each hook event type (shown in detail view)
*/
export const HOOK_DESCRIPTIONS: Record<string, string> = {
[HookEventName.Stop]: '',
[HookEventName.PreToolUse]:
'Input to command is JSON of tool call arguments.',
[HookEventName.PostToolUse]:
'Input to command is JSON with fields "inputs" (tool call arguments) and "response" (tool call response).',
[HookEventName.PostToolUseFailure]:
'Input to command is JSON with tool_name, tool_input, tool_use_id, error, error_type, is_interrupt, and is_timeout.',
[HookEventName.Notification]:
'Input to command is JSON with notification message and type.',
[HookEventName.UserPromptSubmit]:
'Input to command is JSON with original user prompt text.',
[HookEventName.SessionStart]:
'Input to command is JSON with session start source.',
[HookEventName.SessionEnd]:
'Input to command is JSON with session end reason.',
[HookEventName.SubagentStart]:
'Input to command is JSON with agent_id and agent_type.',
[HookEventName.SubagentStop]:
'Input to command is JSON with agent_id, agent_type, and agent_transcript_path.',
[HookEventName.PreCompact]:
'Input to command is JSON with compaction details.',
[HookEventName.PermissionRequest]:
'Input to command is JSON with tool_name, tool_input, and tool_use_id. Output JSON with hookSpecificOutput containing decision to allow or deny.',
};
export function getHookDescription(eventName: string): string {
const descriptions: Record<string, string> = {
[HookEventName.Stop]: '',
[HookEventName.PreToolUse]: t(
'Input to command is JSON of tool call arguments.',
),
[HookEventName.PostToolUse]: t(
'Input to command is JSON with fields "inputs" (tool call arguments) and "response" (tool call response).',
),
[HookEventName.PostToolUseFailure]: t(
'Input to command is JSON with tool_name, tool_input, tool_use_id, error, error_type, is_interrupt, and is_timeout.',
),
[HookEventName.Notification]: t(
'Input to command is JSON with notification message and type.',
),
[HookEventName.UserPromptSubmit]: t(
'Input to command is JSON with original user prompt text.',
),
[HookEventName.SessionStart]: t(
'Input to command is JSON with session start source.',
),
[HookEventName.SessionEnd]: t(
'Input to command is JSON with session end reason.',
),
[HookEventName.SubagentStart]: t(
'Input to command is JSON with agent_id and agent_type.',
),
[HookEventName.SubagentStop]: t(
'Input to command is JSON with agent_id, agent_type, and agent_transcript_path.',
),
[HookEventName.PreCompact]: t(
'Input to command is JSON with compaction details.',
),
[HookEventName.PermissionRequest]: t(
'Input to command is JSON with tool_name, tool_input, and tool_use_id. Output JSON with hookSpecificOutput containing decision to allow or deny.',
),
};
return descriptions[eventName] || '';
}
/**
* Source display mapping
* Source display mapping (translated)
*/
export const SOURCE_DISPLAY_MAP: Record<HooksConfigSource, string> = {
[HooksConfigSource.Project]: 'Local Settings',
[HooksConfigSource.User]: 'User Settings',
[HooksConfigSource.System]: 'System Settings',
[HooksConfigSource.Extensions]: 'Extensions',
};
export function getTranslatedSourceDisplayMap(): Record<
HooksConfigSource,
string
> {
return {
[HooksConfigSource.Project]: t('Local Settings'),
[HooksConfigSource.User]: t('User Settings'),
[HooksConfigSource.System]: t('System Settings'),
[HooksConfigSource.Extensions]: t('Extensions'),
};
}
/**
* List of hook events to display in the UI
@ -171,9 +209,9 @@ export function createEmptyHookEventInfo(
): HookEventDisplayInfo {
return {
event: eventName,
shortDescription: HOOK_SHORT_DESCRIPTIONS[eventName] || '',
description: HOOK_DESCRIPTIONS[eventName] || '',
exitCodes: HOOK_EXIT_CODES[eventName] || [],
shortDescription: getHookShortDescription(eventName),
description: getHookDescription(eventName),
exitCodes: getHookExitCodes(eventName),
configs: [],
};
}