qwen-code/packages/web-shell/client/i18n.tsx
Shaojin Wen ac2f371c44
feat(scheduled-tasks): add isolated run mode via create_sub_session tool (#6535)
* feat(scheduled-tasks): add isolated run mode via create_sub_session tool

Introduce a new `create_sub_session` tool (daemon-only) that spawns a
fresh top-level sub-session with its own clean context and transcript.
Wire it into the cron scheduler as an `isolated` run mode so each
scheduled fire dispatches its prompt into a fresh sub-session instead
of accumulating in one shared transcript.

- Add `create_sub_session` tool with `first-turn` and `sent` completion modes
- Add `SubSessionLauncher` in cli/serve with concurrency cap, timeout, and truncation
- Extend ACP bridge `extMethod` dispatch for child→daemon sub-session requests
- Add `runMode` field (`shared`|`isolated`) to DurableCronTask, CronJob, and API types
- Add run-mode radio picker to ScheduledTasksDialog UI
- Fix AuthMessage hardcoded placeholder to use i18n key

* fix(scheduled-tasks): dispatch isolated fires daemon-side, not via the model

An `isolated` fire was relayed through the model: the fired prompt was
wrapped with an instruction to call `create_sub_session`. That tool's
default permission is `'ask'`, so under `ApprovalMode.DEFAULT` an
unattended fire reached `client.requestPermission`, found no SSE
subscriber, and was cancelled by the daemon's 5-minute permission
timeout. The task never ran, and the cancel was booked as a successful
run — the headline use case of a scheduled task was broken.

Route isolated fires straight to the daemon instead: the cron `onFire`
handler in `Session` calls the sub-session spawner directly, with no
model relay and no tool-permission gate. The prompt was already approved
when the task was created; laundering it back through the model only
re-opened that gate. `create_sub_session` keeps `'ask'` for
model-initiated calls, and the attended "Run now" button keeps its relay
(a user is present to answer the prompt).

Also fix orphan-session cleanup in the launcher. `closeSession` was
guarded only by `.catch()`, which covers an async rejection but not a
synchronous throw; because the call sits inside the launcher's own
`catch (err)` block, a sync throw escaped and replaced the real launch
error. Guard both shapes.

Tests:
- Cover isolated routing: dispatch, in-session fallback with no spawner,
  missed one-shot, dispatch failure (dropped, never run inline), and
  shared mode.
- Cover the orphan close, including a `closeSession` that throws.
- Replace the sent-mode concurrency test, which only asserted the slot
  was eventually released (moving the release to the drain's *start*
  kept it green) with one that asserts the slot is HELD while the drain
  runs, plus one that asserts it is released at `turn_complete`.

* fix(scheduled-tasks): honor the caller's AbortSignal and harden the spawn boundary

Four findings from review, all in the model-initiated `create_sub_session`
path (the scheduled `isolated` dispatch reaches none of them).

`execute()` took no parameters, so it silently dropped the parent turn's
`AbortSignal`. `Session.ts` awaits `invocation.execute(signal)` without
racing the abort itself, so cancelling a turn with a `first-turn`
sub-session in flight pinned the caller's tool loop until the daemon's
5-minute ceiling. Accept the signal and return as soon as it fires.

The sub-session is deliberately NOT cancelled and deliberately KEEPS its
concurrency slot: `sendPrompt` has no abort seam, so the sub-session runs
on. Releasing its slot on cancel — as the review suggested — would let the
caller over-admit against sub-sessions that are still consuming a bridge
session and model quota.

`handleCreateSubSession` trusted the child-supplied `callerSessionId`
verbatim, and that id keys the launcher's per-caller concurrency bucket: a
fabricated id starts a fresh bucket at zero (cap evasion) and a victim's id
burns their slots (DoS). Validate it with the connection's existing
`ownsSession` seam.

Every daemon session wires a spawner, sub-sessions included, and each gets
its own cap-sized bucket — so one prompt could fan out 5ⁿ sub-sessions until
`maxSessions` ran dry. Gate nesting at one level: the launcher remembers the
sessions it spawned and refuses to spawn from them. With `callerSessionId`
now authenticated, the gate cannot be sidestepped.

Cap the prompt at 100,000 chars (matching the scheduled-task REST route) and
the display name at 200, both at the bridge trust boundary and, for the
prompt, in the tool's own validation so the model gets an actionable error.

Not changed: `create_sub_session` stays in `PermissionManager.CORE_TOOLS`.
Membership there SUBJECTS a tool to the `coreTools` allowlist; it does not
exempt it. Removing it — as the review suggested — is what would let the
tool bypass a user's allowlist, the way `agent` and `send_message` do today.

* fix(core): do not spawn a sub-session for an already-cancelled turn

`raceCancellation(spawner({…}), signal)` evaluated the spawner as an
argument, so the spawn started before the abort was ever checked. A turn
cancelled before `execute()` ran still created a sub-session on the daemon
— and it kept a concurrency slot — while the tool reported itself
cancelled.

Take a thunk instead, so the pre-abort check happens before any daemon work
is started. Track whether the spawn actually began, and say so: "cancelled
before it started, no sub-session was created" is a different fact from
"a sub-session may already have been created and is not cancelled".

Regression test asserts the spawner is never called for a pre-aborted
signal; it fails against the eager-argument form.

* fix(serve): require callerSessionId and stop misreporting an early stream close

Two findings from review.

`awaitFirstTurn`'s `'incomplete'` stopReason was unreachable. The cleanup
`finally` calls `ac.abort()` unconditionally to tear the subscription down,
so by the time the stopReason ternary read `ac.signal.aborted` it was always
true. An event stream that closed before the turn finished (bridge teardown,
WS drop) was reported as a 5-minute wall-clock `'timeout'` — indistinguishable
from a real one. Track the timer firing in its own flag.

`callerSessionId` was validated only when present. Omitting it handed the
launcher `undefined`, which minted an `anon:<uuid>` bucket — a fresh
concurrency bucket per call, so no cap — and skipped the depth-1 nesting gate
(`info.callerSessionId !== undefined && …`). Authenticating the id closed
forgery but not omission. It is now required at the bridge boundary, and
required in `CreateSubSessionInfo`, so the launcher's anonymous fallback and
the gate's presence check are both gone. Every real caller has a session id —
the tool only ever runs inside a session's turn.

* fix(serve): surface dropped fires and drain timeouts; bound sub-sessions per workspace

Three findings from review.

A dropped `isolated` scheduled fire left no trace. `debugLogger.warn` writes
nothing unless a debug log session is active, and the scheduler persists the
fire as a run before dispatch — so a nightly task could fail forever while its
history claimed it ran. It now also writes to stderr, which the daemon forwards
from the child.

A sent-mode drain that hit its 30-minute ceiling was equally silent: the catch
saw `drainAc.signal.aborted` and skipped logging, the `finally` freed the
concurrency slot, and the sub-session — which the abort does not cancel — kept
burning a bridge session and model quota. The timer now records its own firing
(the controller cannot: `finally` aborts it on every exit path) and the timeout
is written to stderr. The drain ceiling is injectable for tests, mirroring
`firstTurnTimeoutMs`.

The per-caller concurrency cap trusts `callerSessionId`, and the bridge can only
authenticate that id as "a session on this channel". Every session of a
workspace shares one child process, so nothing at the transport can prove which
of them issued the call — and a per-session secret would be readable by the
whole process anyway. Rather than pretend otherwise, add a workspace-wide
ceiling on concurrent sub-sessions that holds no matter which bucket a launch is
charged to.
2026-07-09 12:02:39 +00:00

3509 lines
167 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
createContext,
useContext,
useMemo,
type PropsWithChildren,
} from 'react';
export const WEB_SHELL_LANGUAGES = ['en', 'zh-CN'] as const;
export type WebShellLanguage = (typeof WEB_SHELL_LANGUAGES)[number];
type MessageValue =
| string
| ((vars?: Record<string, string | number>) => string);
type Messages = Record<string, MessageValue>;
const EN: Messages = {
'about.auth': 'Auth',
'about.baseUrl': 'Base URL',
'about.fastModel': 'Fast Model',
'about.memoryUsage': 'Memory Usage',
'about.model': 'Model',
'about.noProxy': 'no proxy',
'about.noSandbox': 'no sandbox',
'about.platform': 'OS',
'about.proxy': 'Proxy',
'about.qwenCode': 'Qwen Code',
'about.runtime': 'Runtime',
'about.sandbox': 'Sandbox',
'about.sessionId': 'Session ID',
'about.title': 'Status',
'agent.back': 'Back',
'agent.builtInBadge': '(built-in)',
'agent.action.delete': 'Delete Agent',
'agent.action.edit': 'Edit Agent',
'agent.action.view': 'View Agent',
'agent.chooseAction': (v) => `Choose action for ${v?.name ?? ''}`,
'agent.chooseActionTitle': 'Choose Action',
'agent.colorLabel': 'Color: ',
'agent.colorUpdated': (v) => `Updated color for ${v?.name ?? ''}`,
'agent.create': 'Create a new subagent',
'agent.create.button': 'Create Agent',
'agent.create.confirm': 'Confirm and Save',
'agent.create.desc': 'Create a new subagent',
'agent.create.descPlaceholder': 'What does this agent do?',
'agent.create.describeAgent': 'Describe Your Subagent',
'agent.create.description': 'Description',
'agent.create.editAgain': 'Edit',
'agent.create.enterDescription': 'Enter Description',
'agent.create.enterName': 'Enter Subagent Name',
'agent.create.enterPrompt': 'Enter System Prompt',
'agent.create.generateFailed': (v) =>
`Failed to generate subagent: ${v?.error ?? 'Unknown error'}`,
'agent.create.generatingConfig': 'Generating subagent configuration...',
'agent.create.loading': 'Creating...',
'agent.create.location': 'Choose Location',
'agent.create.method': 'Choose Generation Method',
'agent.create.method.manual': 'Manual Creation',
'agent.create.method.qwen': 'Generate with Qwen Code',
'agent.create.method.qwen.recommended':
'Generate with Qwen Code (Recommended)',
'agent.create.method.qwen.desc':
'LLM generates name, prompt, and description',
'agent.create.name': 'Name',
'agent.create.namePlaceholder': 'my-agent',
'agent.create.nameHelp': 'Enter a clear, unique name for this subagent.',
'agent.create.project': 'Project',
'agent.create.project.cli': 'Project-level (.qwen/agents/)',
'agent.create.project.desc': 'Create a project-level subagent',
'agent.create.prompt': 'System prompt',
'agent.create.promptPlaceholder': 'You are a specialized agent that...',
'agent.create.promptPlaceholder.cli':
'e.g., You are an expert code reviewer...',
'agent.create.promptHelp':
"Write the system prompt that defines this subagent's behavior. Be comprehensive for best results.",
'agent.create.preview': 'Preview',
'agent.create.qwenHint':
'Describe what this subagent should do and when it should be used. (Be comprehensive for best results)',
'agent.create.qwenPlaceholder':
'> e.g., Expert code reviewer that reviews code based on best practices...',
'agent.create.required': 'Name, description, and system prompt are required.',
'agent.create.save': 'Save Agent',
'agent.create.scope': 'Choose where to save the subagent',
'agent.create.manualDescHelp':
'Describe when and how this subagent should be used.',
'agent.create.manualDescPlaceholder':
'e.g., Reviews code for best practices and potential bugs.',
'agent.create.toolsSelection': 'Select Tools',
'agent.create.tools.all': 'All Tools',
'agent.create.tools.allDefault': 'All Tools (Default)',
'agent.create.tools.allInfo': 'All tools selected, including MCP tools',
'agent.create.tools.allInfoFallback':
'All tools selected, including MCP tools',
'agent.create.tools.editLabel': '• Edit tools:',
'agent.create.tools.executionLabel': '• Execution tools:',
'agent.create.tools.none': '(none)',
'agent.create.tools.readEdit': 'Read & Edit Tools',
'agent.create.tools.readEditExecute': 'Read & Edit & Execution Tools',
'agent.create.tools.readOnlyLabel': '• Read-only tools:',
'agent.create.tools.readOnly': 'Read-only Tools',
'agent.create.tools.selected': 'Selected tools:',
'agent.create.user': 'User',
'agent.create.user.cli': 'User-level (~/.qwen/agents/)',
'agent.create.user.desc': 'Create a user-level subagent',
'agent.createFirstHint':
"Use '/agents create' to create your first subagent.",
'agent.created': (v) => `Created ${v?.name ?? ''}`,
'agent.delete': 'Delete',
'agent.delete.confirm': (v) =>
`Are you sure you want to delete "${v?.name ?? ''}"?`,
'agent.delete.loading': 'Deleting...',
'agent.delete.no': 'No',
'agent.delete.title': (v) => `Delete ${v?.name ?? ''}`,
'agent.delete.yes': 'Yes, delete',
'agent.deleted': (v) => `Deleted ${v?.name ?? ''}`,
'agent.edit': 'Edit',
'agent.edit.color': 'Edit Color',
'agent.edit.tools': 'Edit Tools',
'agent.editColorTitle': (v) => `Edit Color: ${v?.name ?? ''}`,
'agent.editTitle': (v) => `Edit ${v?.name ?? ''}`,
'agent.empty': 'No subagents found.',
'agent.footer.back': 'Esc to go back',
'agent.footer.cliBack': 'Enter to select, ↑↓ to navigate, Esc to go back',
'agent.footer.cliSelect': 'Enter to select, ↑↓ to navigate, Esc to close',
'agent.footer.close': 'Esc to close',
'agent.footer.deleteConfirm': 'Enter to confirm, Esc to cancel',
'agent.footer.enterNext': 'Press Enter to continue, Esc to go back',
'agent.footer.generating': 'Esc to cancel',
'agent.footer.createLocation':
'Press Enter to continue, ↑↓ to navigate, Esc to cancel',
'agent.footer.createContinue':
'Press Enter to continue, ↑↓ to navigate, Esc to go back',
'agent.footer.final':
'Press Enter to save, e to save and edit, Esc to go back',
'agent.footer.nav': '↑↓ navigate · Enter select · Esc back',
'agent.footer.navBack': '↑↓ navigate · Enter select · Esc back',
'agent.footer.navSelect': '↑↓ navigate · Enter select · Esc close',
'agent.footer.viewerBack': 'Esc to go back',
'agent.filePathLabel': 'File Path: ',
'agent.label': 'Agent',
'agent.location': 'Location',
'agent.level.builtin': 'Built-in',
'agent.level.extension': 'Extension',
'agent.level.project': 'Project',
'agent.level.user': 'User',
'agent.manage': 'Manage',
'agent.manage.desc': 'Manage existing subagents',
'agent.modelLabel': 'Model: ',
'agent.overriddenBadge': '(overridden by project level agent)',
'agent.readonly': 'This agent is read-only.',
'agent.select': 'Select an agent.',
'agent.selectAction': 'Select an action',
'agent.descriptionLabel': 'Description:',
'agent.systemPromptLabel': 'System Prompt:',
'agent.step': (v) => `Step ${v?.n ?? ''}`,
'agent.tools': 'Tools',
'agent.toolsLabel': 'Tools: ',
'agent.toolsUpdated': (v) => `Updated tools for ${v?.name ?? ''}`,
'agent.usingCount': (v) => `Using: ${v?.count ?? 0} agents`,
'agent.view': 'View',
'agents.closed': 'Agents panel closed.',
'agents.title': 'Agents',
'subagent.result': 'Result',
'subagent.tools': (v) => `Tools (${v?.count ?? 0})`,
'subagent.toolsCount': (v) => `${v?.count ?? 0} tools`,
'subagent.toggleStream': 'Toggle agent stream details',
'subagent.pending': 'pending',
'subagent.running': 'running',
'timeline.parallelAgents': 'Parallel agents',
'timeline.thinking': 'Thinking',
'timeline.assistantUpdate': 'Assistant update',
'timeline.toolCalls': (v) =>
`${v?.count ?? 0} tool call${v?.count === 1 ? '' : 's'}`,
'timeline.planUpdate': 'Plan update',
'timeline.statusUpdate': 'Status update',
'timeline.userTurn': 'User turn',
'timeline.planDetail': 'plan update',
'timeline.parallelAgentsDetail': (v) =>
`${v?.count ?? 0} parallel agent${v?.count === 1 ? '' : 's'}`,
'timeline.noActivity': 'No activity',
'timeline.sessionTimeline': 'Session timeline',
'timeline.turnPrefix': (v) => `Turn ${v?.index ?? 0}`,
'timeline.currentTurn': 'Current turn',
'timeline.kind.thought': 'thinking',
'timeline.kind.commentary': 'assistant update',
'timeline.kind.tool': 'tool calls',
'timeline.kind.agents': 'parallel agents',
'timeline.kind.plan': 'plan update',
'timeline.kind.status': 'status update',
'timeline.kind.none': 'turn',
'common.copy': 'Copy',
'common.na': 'N/A',
'common.server': 'Server',
'common.agent': 'Agent',
'common.auto': 'auto',
'common.runtime': 'Runtime',
'common.failedToLoad': 'Failed to load',
'auth.notSet': '(not set)',
'auth.apiKeyPlaceholder': 'sk-...',
'auth.modelsPlaceholder': 'model-id-1, model-id-2',
'model.usingModel': (v) =>
`Using ${v?.isRuntime ? 'runtime ' : ''}model: ${v?.modelId ?? ''}`,
'mermaid.label': 'mermaid',
'mermaid.errorLabel': 'mermaid (error)',
'user.uploadedImage': (v) => `User uploaded image ${v?.index ?? 1}`,
'voice.noSpeech': 'No speech detected.',
'voice.stopDictation': 'Stop dictation',
'voice.transcribing': 'Transcribing…',
'voice.starting': 'Starting…',
'voice.errorRetry': (v) =>
`Voice error — click to retry${v?.message ? `: ${v.message}` : ''}`,
'voice.noSpeechRetry': 'No speech detected — click to retry',
'voice.startDictation': 'Start voice dictation',
'voice.error': 'Voice error',
'resume.failedToLoad': 'Failed to load sessions',
'toast.dismiss': 'Dismiss notification',
'toast.dismissShort': 'Dismiss',
'insight.ready': 'Insight report generated successfully!',
'request.cancelled': 'Request cancelled.',
'approval.execQuestion': (v) => `Allow execution of: '${v?.tool ?? ''}'?`,
'approval.changeQuestion': 'Apply this change?',
'approval.launchAgentQuestion': 'Launch this agent?',
'approval.option.allowOnce': 'Yes, allow once',
'approval.option.rejectOnce': 'Reject',
'approval.option.allowAllEdits': 'Allow All Edits',
'approval.option.allowAlwaysProject': 'Always allow in this project',
'approval.option.allowAlwaysUser': 'Always allow for this user',
'approval.option.allowAlwaysServer': 'Always allow for this server',
'approval.option.allowAlwaysTool': 'Always allow for this tool',
'assistant.branch': 'Branch',
'assistant.copy': 'Copy',
'at.category.extensions': 'Extensions',
'at.category.extensions.description': 'Reference active extensions',
'at.category.files': 'Files',
'at.category.files.description': 'Reference workspace files',
'at.category.mcpResources': 'MCP resources',
'at.category.mcpResources.description': 'Reference MCP server resources',
'at.menu': 'Reference menu',
'common.back': 'back',
'common.cancel': 'cancel',
'common.close': 'close',
'common.fullscreen': 'Fullscreen',
'common.exitFullscreen': 'Exit fullscreen',
'common.continue': 'continue',
'common.current': 'current',
'common.disabled': 'disabled',
'common.enabled': 'enabled',
'common.enterSelect': 'Enter to select',
'common.invalid': 'invalid',
'common.loading': 'Loading...',
'common.save': 'save',
'common.navigate': '↑↓ to navigate',
'common.next': 'next',
'common.noResults': 'No results',
'common.previous': 'previous',
'common.refresh': 'refresh',
'common.search': 'Search',
'common.valid': 'valid',
'common.clients': (v) => `${v?.count ?? 0} clients`,
'agent.count': (v) => `${v?.count ?? 0} agents`,
'askUser.submit': 'Submit',
'askUser.ignore': 'Ignore',
'askUser.multiHint': 'multiple choice',
'askUser.progress': (v) => `${v?.current ?? 0}/${v?.total ?? 0} questions`,
'askUser.selectAnswer': 'Select an answer',
'askUser.typePlaceholder': 'Type something...',
'copy.failedFallback': 'Failed to copy to the clipboard',
'copy.inlineLatexMissing':
'No matching inline LaTeX expression found in the last AI output.',
'copy.latexMissing': 'No matching LaTeX block found in the last AI output.',
'copy.noOutput': 'No output in history',
'copy.noText': 'Last AI output contains no text to copy.',
'copy.codeMissing': 'No matching code block found in the last AI output.',
'copy.outputCopied': 'Last output copied to the clipboard',
'copy.toClipboard': (v) =>
`${v?.label ?? 'Selection'} copied to the clipboard`,
'code.copy': 'Copy',
'code.copied': 'Copied!',
'echartsChart.defaultTitle': 'Chart Loading',
'echartsChart.noData': 'No data',
'echartsChart.tableNotice': (v) => {
const omittedRows = Number(v?.omittedRows ?? 0);
const omittedColumns = Number(v?.omittedColumns ?? 0);
if (omittedRows > 0 && omittedColumns > 0) {
return `Showing ${v?.visibleRows ?? 0} of ${v?.totalRows ?? 0} rows and ${v?.visibleColumns ?? 0} of ${v?.totalColumns ?? 0} columns`;
}
if (omittedColumns > 0) {
return `Showing ${v?.visibleColumns ?? 0} of ${v?.totalColumns ?? 0} columns`;
}
return `Showing ${v?.visibleRows ?? 0} of ${v?.totalRows ?? 0} rows`;
},
'echartsChart.rendering': 'Rendering chart',
'echartsChart.runtimeUnavailable': 'Chart runtime is unavailable.',
'echartsChart.renderFailed': 'Chart render failed.',
'echartsChart.viewMode': 'View mode',
'echartsChart.showChart': 'Show chart',
'echartsChart.showData': 'Show data',
'echartsChart.chart': 'Chart',
'echartsChart.data': 'Data',
'markdownTable.blank': '(blank)',
'markdownTable.column': (v) => `Column ${v?.index ?? ''}`,
'markdownTable.rows': (v) => {
const count = Number(v?.count ?? 0);
return `${count} row${count === 1 ? '' : 's'}`;
},
'markdownTable.rowsFiltered': (v) =>
`${v?.visible ?? 0}/${v?.total ?? 0} rows`,
'markdownTable.hint': 'Click headers to sort, open filters from ▾.',
'markdownTable.filtersActive': (v) => {
const count = Number(v?.count ?? 0);
return `${count} filter${count === 1 ? '' : 's'}`;
},
'markdownTable.cellsSelected': (v) => {
const count = Number(v?.count ?? 0);
return `${count} cell${count === 1 ? '' : 's'} selected`;
},
'markdownTable.copyTsv': 'Copy TSV',
'markdownTable.copyVisible': 'Quick copy',
'markdownTable.freezeFirstColumn': 'Freeze first column',
'markdownTable.unfreezeFirstColumn': 'Unfreeze first column',
'markdownTable.hideColumn': 'Hide column',
'markdownTable.showHiddenColumns': (v) => {
const count = Number(v?.count ?? 0);
return `Show ${count} hidden column${count === 1 ? '' : 's'}`;
},
'markdownTable.moveColumn': (v) => `Move ${v?.column ?? ''}`,
'markdownTable.resizeColumn': (v) => `Resize ${v?.column ?? ''}`,
'markdownTable.rowDetails': 'Details',
'markdownTable.rowDetailsAria': (v) =>
`View details for row ${v?.index ?? ''}`,
'markdownTable.closeRowDetailsAria': (v) =>
`Hide details for row ${v?.index ?? ''}`,
'markdownTable.detailsHeader': 'Row details',
'markdownTable.actions': 'Actions',
'markdownTable.sortByColumn': (v) => `Sort by ${v?.column ?? ''}`,
'markdownTable.sortByColumnAsc': (v) =>
`Sort by ${v?.column ?? ''}, ascending`,
'markdownTable.sortByColumnDesc': (v) =>
`Sort by ${v?.column ?? ''}, descending`,
'markdownTable.filterColumn': (v) => `Filter ${v?.column ?? ''}`,
'markdownTable.empty': 'This table has no data.',
'markdownTable.emptyFiltered': 'No rows match the filters.',
'markdownTable.sort.asc': 'Sort ascending',
'markdownTable.sort.desc': 'Sort descending',
'markdownTable.sort.clear': 'Clear sort',
'markdownTable.filter.searchPlaceholder': 'Search filter values',
'markdownTable.filter.searchAria': (v) => `Search ${v?.column ?? ''}`,
'markdownTable.filter.selectVisible': 'Select current results',
'markdownTable.filter.optionLimit': (v) =>
`Showing first ${v?.count ?? 0} items. Search to narrow results.`,
'markdownTable.filter.noOptions': 'No matches',
'markdownTable.filter.custom': 'Custom filter',
'markdownTable.filter.numberAria': (v) =>
`Number filter for ${v?.column ?? ''}`,
'markdownTable.filter.textAria': (v) => `Text filter for ${v?.column ?? ''}`,
'markdownTable.filter.numberPlaceholder': 'Value',
'markdownTable.filter.toPlaceholder': 'To',
'markdownTable.filter.textPlaceholder': 'Enter filter condition',
'markdownTable.filter.reset': 'Reset',
'markdownTable.filter.cancel': 'Cancel',
'markdownTable.filter.confirm': 'Confirm',
'markdownTable.filter.text.contains': 'Contains',
'markdownTable.filter.text.equals': 'Equals',
'markdownTable.filter.text.notEquals': 'Does not equal',
'markdownTable.filter.text.startsWith': 'Starts with',
'markdownTable.filter.text.endsWith': 'Ends with',
'markdownTable.filter.number.gt': 'Greater than',
'markdownTable.filter.number.gte': 'Greater than or equal to',
'markdownTable.filter.number.lt': 'Less than',
'markdownTable.filter.number.lte': 'Less than or equal to',
'markdownTable.filter.number.between': 'Between',
'mermaid.rendering': 'Rendering diagram...',
'mermaid.viewCode': '</>',
'mermaid.viewDiagram': '⊞',
'contextUsage.active': 'active',
'contextUsage.autocompactBuffer': 'Autocompact buffer',
'contextUsage.bodyLoaded': 'body loaded',
'contextUsage.builtinTools': 'Built-in tools',
'contextUsage.contextWindow': 'Context window',
'contextUsage.detailHint': 'Run /context detail for per-item breakdown.',
'contextUsage.estimatedOverhead': 'Estimated pre-conversation overhead',
'contextUsage.free': 'Free',
'contextUsage.memoryFiles': 'Memory files',
'contextUsage.messages': 'Messages',
'contextUsage.mcpTools': 'MCP tools',
'contextUsage.model': 'Model',
'contextUsage.noSession':
'No active session yet. Send your first message before viewing context usage.',
'contextUsage.noApiResponse':
'No API response yet. Send a message to see actual usage.',
'contextUsage.overLimit':
'Context exceeds limit! Use /compress or /clear to reduce.',
'contextUsage.skills': 'Skills',
'contextUsage.systemPrompt': 'System prompt',
'contextUsage.title': 'Context Usage',
'contextUsage.tokens': 'tokens',
'contextUsage.usageByCategory': 'Usage by category',
'contextUsage.used': 'Used',
'daemon.title': 'Daemon Status',
'daemon.details.loading': 'Loading diagnostics...',
'daemon.details.failed': 'Failed to load diagnostics.',
'daemon.refresh': 'Refresh',
'daemon.loading': 'Loading daemon status...',
'daemon.loadFailed': 'Failed to load daemon status',
'daemon.updatedAt': (v) => `Updated ${v?.time ?? ''}`,
'daemon.none': 'none',
'daemon.level.ok': 'OK',
'daemon.level.warning': 'Warning',
'daemon.level.error': 'Error',
'daemon.level.unavailable': 'Unavailable',
'daemon.issues.title': 'Issues',
'daemon.overview.title': 'Daemon',
'daemon.overview.version': 'Version',
'daemon.overview.pid': 'PID',
'daemon.overview.mode': 'Mode',
'daemon.overview.uptime': 'Uptime',
'daemon.overview.workspace': 'Workspace',
'daemon.runtime.title': 'Runtime',
'daemon.runtime.activeSessions': 'Active sessions',
'daemon.runtime.activePrompts': 'Active prompts',
'daemon.runtime.idle': 'Idle for',
'daemon.runtime.noActivity': 'no activity yet',
'daemon.runtime.pendingPermissions': 'Pending permissions',
'daemon.runtime.permissionPolicy': 'Permission policy',
'daemon.runtime.channel': 'ACP channel',
'daemon.runtime.channelLive': 'live',
'daemon.runtime.channelDown': 'down',
'daemon.runtime.startingUp': 'Runtime is starting...',
'daemon.runtime.startFailed': 'Runtime failed to start',
'daemon.runtime.channelWorker': 'Channel worker',
'daemon.runtime.channelWorkerRestarts': 'Worker restarts',
'daemon.runtime.memory': 'Memory (RSS / heap)',
'daemon.transport.title': 'Transport',
'daemon.transport.restSse': 'REST SSE streams',
'daemon.transport.acpDisabled': 'ACP transport disabled',
'daemon.transport.acpConnections': 'ACP connections',
'daemon.transport.acpStreams': 'ACP streams (session/SSE/WS)',
'daemon.transport.pendingRequests': 'Pending client requests',
'daemon.transport.rateLimitRejected': 'Rate-limit rejects',
'daemon.security.title': 'Security',
'daemon.security.token': 'Bearer token',
'daemon.security.requireAuth': 'Require auth',
'daemon.security.loopback': 'Loopback bind',
'daemon.security.allowOrigin': 'Allowed origins',
'daemon.security.shell': 'Session shell commands',
'daemon.security.configured': 'configured',
'daemon.security.notConfigured': 'not configured',
'daemon.limits.title': 'Limits',
'daemon.limits.unlimited': 'unlimited',
'daemon.limits.maxSessions': 'Max sessions',
'daemon.limits.maxPendingPrompts': 'Max pending prompts / session',
'daemon.limits.maxConnections': 'Max listener connections',
'daemon.limits.eventRing': 'Event ring size',
'daemon.limits.promptDeadline': 'Prompt deadline',
'daemon.limits.sessionIdle': 'Session idle timeout',
'daemon.capabilities.title': 'Capabilities',
'daemon.capabilities.titleCount': (v) => `Capabilities (${v?.count ?? 0})`,
'daemon.full.sessions.title': 'Sessions',
'daemon.full.sessions.empty': 'No active sessions',
'daemon.full.session.pendingPrompts': (v) =>
`${v?.count ?? 0} pending prompts`,
'daemon.full.session.pendingPermissions': (v) =>
`${v?.count ?? 0} pending permissions`,
'daemon.full.session.prompting': 'prompting',
'daemon.full.workspace.title': 'Workspace Diagnostics',
'daemon.full.workspace.empty': 'No workspace diagnostics reported',
'daemon.full.auth.title': 'Auth',
'daemon.full.auth.providers': 'Device-flow providers',
'daemon.full.auth.pending': 'Pending device flows',
'daemon.full.acp.title': 'ACP connections',
'daemon.tab.overview': 'Overview',
'daemon.tab.usage': 'Usage',
'daemon.tab.metrics': 'Metrics',
'daemon.tab.diagnostics': 'Diagnostics',
'daemon.charts.title': 'Metrics',
'daemon.charts.empty':
'Collecting metrics… charts appear after the first sample.',
'daemon.charts.concurrency': 'Concurrency',
'daemon.charts.activePrompts': 'Active tasks',
'daemon.charts.activeSessions': 'Sessions',
'daemon.charts.requests': 'Requests',
'daemon.charts.reqTotal': 'Total',
'daemon.charts.reqErrors': 'Errors',
'daemon.charts.apiLatency': 'API latency',
'daemon.charts.promptLatency': 'Prompt latency',
'daemon.charts.queueWait': 'Queue wait',
'daemon.charts.promptDuration': 'Duration',
'daemon.charts.eventLoop': 'Event-loop lag',
'daemon.charts.eventLoopLag': 'Lag p99',
'daemon.charts.queuedPrompts': 'Queued',
'daemon.charts.reqRejected': 'Rejected',
'daemon.charts.llmLatency': 'LLM API latency',
'daemon.charts.cpu': 'CPU',
'daemon.charts.pipe': 'IPC pipe',
'daemon.charts.pipeIn': 'In',
'daemon.charts.pipeOut': 'Out',
'daemon.charts.connections': 'Connections',
'daemon.charts.cpuDaemon': 'Daemon',
'daemon.charts.cpuChild': 'Child',
'daemon.charts.rssDaemon': 'Daemon RSS',
'daemon.charts.rssChild': 'Child RSS',
'daemon.charts.memory': 'Memory',
'daemon.charts.heap': 'Heap',
'daemon.charts.tokens': 'Token burn',
'daemon.charts.tokensIn': 'Input',
'daemon.charts.tokensOut': 'Output',
'daemon.charts.peak': 'peak',
'daemon.usage.today': 'Today',
'daemon.usage.period7d': '7D',
'daemon.usage.period30d': '30D',
'daemon.usage.rangeWeek': 'Last 7 days',
'daemon.usage.rangeMonth': 'Last 30 days',
'daemon.usage.rangeGroup': 'Summary period',
'daemon.usage.tokensConsumed': 'tokens consumed',
'daemon.usage.sessions': 'Sessions',
'daemon.usage.requests': 'Requests',
'daemon.usage.tools': 'Tools',
'daemon.usage.changes': 'Changes',
'daemon.usage.breakdownTitle': 'Token Breakdown',
'daemon.usage.inputTokens': 'Input tokens',
'daemon.usage.inputHint': 'request + cache read',
'daemon.usage.outputTokens': 'Output tokens',
'daemon.usage.outputHint': 'response + reasoning',
'daemon.usage.cacheRead': 'Cache read',
'daemon.usage.cacheHint': 'cache read share',
'daemon.usage.heatmapTitle': 'Token Heatmap',
'daemon.usage.heatmapSub': (v) =>
`recent ${v?.months ?? 12} months · daily aggregated tokens`,
'daemon.usage.low': 'Low',
'daemon.usage.high': 'High',
'daemon.usage.dowMon': 'Mon',
'daemon.usage.dowWed': 'Wed',
'daemon.usage.dowFri': 'Fri',
'daemon.usage.empty': 'No token usage recorded yet.',
'daemon.usage.loading': 'Loading usage…',
'daemon.usage.failed': 'Failed to load usage',
'daemon.usage.cellTokens': (v) =>
`${v?.date ?? ''} · Tokens: ${v?.tokens ?? '0'} · Cache: ${v?.cache ?? 0}%`,
'daemon.usage.rangeWordToday': 'Today',
'daemon.usage.rangeWordWeek': '7 days',
'daemon.usage.rangeWordMonth': '30 days',
'daemon.usage.modelShareTitle': 'model share',
'daemon.usage.modelShareSub': 'token share · light green shows cache read',
'daemon.usage.modelMeta': (v) =>
`${v?.tokens ?? '0'} tokens · cache ${v?.cache ?? 0}%`,
'daemon.usage.skillTitle': 'skill calls',
'daemon.usage.skillSub': 'skill name / count',
'daemon.usage.skillName': 'Skill name',
'daemon.usage.skillCount': 'Count',
'daemon.usage.dailyTokensTitle': 'tokens',
'daemon.usage.dailyTokensSub': 'daily token totals',
'daemon.usage.dailySessionsTitle': 'sessions',
'daemon.usage.dailySessionsSub': 'active session counts per day',
'delete.cannotCurrent': 'Cannot delete the current active session.',
'delete.action': 'Delete',
'delete.deleted': 'Session deleted.',
'delete.deletedCount': (v) => `${v?.count ?? 0} session(s) deleted.`,
'delete.deleting': 'Deleting...',
'delete.failed': (v) =>
`Failed to delete session.${v?.reason ? ` ${v.reason}` : ''}`,
'delete.footer': '↑↓ navigate · Space select · Enter delete · Esc cancel',
'delete.noMatch': (v) => `No session matching "${v?.query ?? ''}"`,
'delete.none': 'No sessions to delete',
'delete.allFailed': (v) =>
`Failed to delete ${v?.count ?? 0} session(s): ${v?.reason ?? 'unknown error'}`,
'delete.nonRemoved': 'No sessions were deleted.',
'delete.notFound': 'Session not found — it may have been deleted already.',
'delete.partialFail': (v) =>
`${v?.removed ?? 0} deleted, ${v?.failed ?? 0} failed: ${v?.detail ?? 'unknown error'}`,
'delete.matches': (v) => `${v?.count ?? 0} matches`,
'delete.pressSearch': 'Press / to search; Space to select; Enter to delete',
'delete.selected': (v) => `${v?.count ?? 0} selected`,
'delete.title': 'Delete Session',
'time.justNow': 'just now',
'time.minutesAgo': (v) => `${v?.count ?? 0} min ago`,
'time.hoursAgo': (v) => `${v?.count ?? 0}h ago`,
'time.daysAgo': (v) => `${v?.count ?? 0}d ago`,
'dialog.footer.close': 'Esc to close',
'dialog.footer.confirmCancel': 'Enter to confirm · Esc to cancel',
'release.cannotCurrent': 'Cannot release the current active session.',
'release.action': 'Release',
'release.released': 'Session released successfully.',
'release.failed': (v) =>
`Failed to release session.${v?.reason ? ` ${v.reason}` : ''}`,
'release.footer': '↑↓ to navigate · Enter to release · Esc to cancel',
'release.inactive': 'Only active live sessions can be released.',
'release.inactiveBadge': 'inactive',
'release.noMatch': (v) => `No session matching "${v?.query ?? ''}"`,
'release.matches': (v) => `${v?.count ?? 0} matches`,
'release.none': 'No live sessions to release',
'release.pressSearch':
'Press / to search; Enter releases the selected live session',
'release.releasing': 'Releasing...',
'release.title': 'Release Session',
'dialog.footer.menu': 'Esc to menu',
'dialog.footer.mcpServers':
'↑↓ to navigate · Enter details · r refresh · Esc close',
'dialog.footer.mcpSelect': '↑↓ to navigate · Enter select · Esc back',
'dialog.footer.modelFast':
'↑↓ to navigate · / to search · c for custom · Enter to set fast model · Esc to cancel',
'dialog.footer.navSelectCancel':
'↑↓ to navigate · Enter to select · Esc to cancel',
'dialog.footer.navSelectClose':
'↑↓ to navigate · Enter to select · Esc to close',
'dialog.footer.navSelectMenu':
'↑↓ to navigate · Enter to select · Esc to menu',
'dialog.footer.navOpenClose': '↑↓ to navigate · Enter to open · Esc to close',
'dialog.footer.navOpenMenu': '↑↓ to navigate · Enter to open · Esc to menu',
'dialog.footer.back': 'Esc to go back',
'dialog.footer.backClose': 'Esc to close',
'dialog.footer.saveClose':
'↑↓ switch fields · ⌘/Ctrl+Enter to save · Esc to close',
'dialog.footer.saveMenu':
'↑↓ switch fields · ⌘/Ctrl+Enter to save · Esc to menu',
'dialog.footer.search': 'Type to search · Enter to commit · Esc to clear',
'dialog.footer.select': 'Enter to select',
'editor.escClearHint': 'Press Esc again to clear',
'editor.hintCommands': 'commands',
'editor.hintFiles': 'Files',
'editor.hintNext': 'next',
'editor.hintPrev': 'previous',
'editor.hintSearch': 'search',
'editor.noHistory': 'No matching history',
'editor.placeholder': 'Type a message or @ file path',
'editor.shellPlaceholder': 'Enter terminal command',
'editor.send': 'Send message',
'editor.connectionDisconnected':
'Connection interrupted. Please try again after it reconnects.',
'editor.sessionLoading': 'Session is still loading. Try again in a moment.',
'editor.processing': 'Processing. New messages will be queued.',
'editor.searchHint': 'ctrl+r next · tab accept · enter send · esc cancel',
'editor.searchLabel': 'reverse-i-search:',
'editor.searchPlaceholder': 'type to search...',
'quickActions.open': 'more actions',
'quickActions.title': 'more actions',
'quickActions.mcp': 'MCP',
'quickActions.context': 'Context',
'quickActions.status': 'Status',
'quickActions.stats': 'Session',
'quickActions.memory': 'Memory',
'quickActions.extensions': 'Extensions',
'quickActions.skills': 'Skills',
'quickActions.tools': 'Tools',
'quickActions.agents': 'Agents',
'quickActions.help': 'Help',
'quickActions.theme': 'Set theme',
'quickActions.auth': 'Auth',
'quickActions.settings': 'Settings',
'quickActions.new': 'New session',
'quickActions.resume': 'Switch session',
'quickActions.delete': 'Delete session',
'quickActions.branch': 'Copy session',
'quickActions.rewind': 'Rewind session',
'quickActions.historyQuestion': 'Question history',
'quickActions.recap': 'Generate recap',
'quickActions.copy': 'Copy output',
'quickActions.shellMode': 'Shell mode',
'quickActions.exitShellMode': 'Exit Shell',
'quickActions.setGoal': 'Set goal',
'session.missing': 'Current session does not exist',
'session.new': 'New session',
// Scheduled tasks page
'scheduledTasks.title': 'Scheduled Tasks',
'scheduledTasks.subtitle':
'Run tasks automatically on a schedule, or trigger them manually anytime.',
'scheduledTasks.loading': 'Loading…',
'scheduledTasks.count': (v) =>
`${v?.count ?? 0} task${Number(v?.count ?? 0) === 1 ? '' : 's'}`,
'scheduledTasks.refresh': 'Refresh',
'scheduledTasks.new': 'New scheduled task',
'scheduledTasks.createViaChat': 'Create via chat',
'scheduledTasks.chatStarter':
'Help me set up a recurring scheduled task (keep it long-term). What I want: ',
'scheduledTasks.name': 'Name',
'scheduledTasks.namePlaceholder': 'Optional — defaults to the prompt',
'scheduledTasks.prompt': 'Prompt',
'scheduledTasks.promptPlaceholder': 'What should this task do?',
'scheduledTasks.frequency': 'Frequency',
'scheduledTasks.freq.daily': 'Daily',
'scheduledTasks.freq.weekdays': 'Weekdays',
'scheduledTasks.freq.weekly': 'Weekly',
'scheduledTasks.freq.hourly': 'Hourly',
'scheduledTasks.freq.minutes': 'Every N minutes',
'scheduledTasks.freq.custom': 'Custom (cron)',
'scheduledTasks.time': 'Time',
'scheduledTasks.weekday': 'Weekday',
'scheduledTasks.interval': 'Minutes',
'scheduledTasks.cron': 'Cron expression',
'scheduledTasks.weekdayNames': 'Sun,Mon,Tue,Wed,Thu,Fri,Sat',
'scheduledTasks.human.daily': (v) => `Daily at ${v?.time ?? ''}`,
'scheduledTasks.human.weekdays': (v) => `Weekdays at ${v?.time ?? ''}`,
'scheduledTasks.human.weekly': (v) =>
`Every ${v?.day ?? ''} at ${v?.time ?? ''}`,
'scheduledTasks.human.hourly': (v) => `Hourly at :${v?.min ?? '00'}`,
'scheduledTasks.human.everyMinutes': (v) => `Every ${v?.n ?? ''} minutes`,
'scheduledTasks.never': 'Never run',
'scheduledTasks.repeats': 'Repeats',
'scheduledTasks.runsOnce': 'Runs once',
'scheduledTasks.lastFired': (v) => `Last run: ${v?.when ?? ''}`,
'scheduledTasks.runNow': 'Run now',
'scheduledTasks.enable': 'Enable',
'scheduledTasks.disable': 'Disable',
'scheduledTasks.delete': 'Delete',
'scheduledTasks.deleteConfirm': (v) =>
`Delete scheduled task "${v?.name ?? ''}"?`,
'scheduledTasks.empty': 'No scheduled tasks yet. Create one to get started.',
'scheduledTasks.create': 'Create',
'scheduledTasks.creating': 'Creating…',
'scheduledTasks.cancel': 'Cancel',
'scheduledTasks.error.invalidSchedule': 'Invalid schedule',
'scheduledTasks.error.emptyPrompt': 'Prompt is required',
'scheduledTasks.error.toggleFailed': 'Failed to update task',
'scheduledTasks.error.deleteFailed': 'Failed to delete task',
'scheduledTasks.edit': 'Edit',
'scheduledTasks.editTitle': 'Edit scheduled task',
'scheduledTasks.save': 'Save',
'scheduledTasks.saving': 'Saving…',
'scheduledTasks.runHistory': (v) => `Run history (${v?.count ?? 0})`,
'scheduledTasks.viewHistory': (v) => `View conversation (${v?.count ?? 0})`,
'scheduledTasks.viewHistoryEmpty': 'View conversation',
'scheduledTasks.viewHistoryHint': "Open the task's session to see its runs",
'scheduledTasks.runKind.catchUp': 'late',
'scheduledTasks.runKind.manual': 'manual',
'scheduledTasks.error.runFailed': 'Failed to record the run',
'scheduledTasks.error.oneShotConsumedButFailed':
'The task was deleted but the prompt could not be delivered — it never ran. Recreate it to try again.',
'scheduledTasks.dueNow': 'Due now',
'scheduledTasks.nextRunTooltip': (v) => `Next run: ${v?.when ?? ''}`,
'scheduledTasks.dur.d': 'd',
'scheduledTasks.dur.h': 'h',
'scheduledTasks.dur.m': 'm',
'scheduledTasks.dur.s': 's',
'scheduledTasks.runMode': 'Run mode',
'scheduledTasks.runMode.shared': 'Shared session',
'scheduledTasks.runMode.isolated': 'Isolated (fresh session per run)',
'scheduledTasks.runMode.shared.hint':
'Runs accumulate in one session transcript.',
'scheduledTasks.runMode.isolated.hint':
'Each run gets a clean session context.',
'sidebar.label': 'Workspace sidebar',
'sidebar.toggleMenu': 'Toggle menu',
'sidebar.newChat': 'New chat',
'sidebar.project': 'Project',
'sidebar.projectFallback': 'Project',
'sidebar.sessionsOverview': 'Session Overview',
'sidebar.splitView': 'Split View',
'sidebar.settings': 'Settings',
'sidebar.daemonStatus': 'Daemon Status',
'sidebar.scheduledTasks': 'Scheduled Tasks',
'sidebar.collapse': 'Collapse',
'sidebar.expand': 'Expand',
'sidebar.collapseProject': 'Collapse project',
'sidebar.expandProject': 'Expand project',
'sidebar.search': 'Search sessions',
'sidebar.searchPlaceholder': 'Search sessions',
'sidebar.searchEmpty': 'No matching sessions.',
'sidebar.rename': 'Rename',
'sidebar.renameCurrentOnly': 'Only the current session can be renamed',
'sidebar.export': 'Export conversation record',
'sidebar.exportFailed': 'Failed to export session',
'sidebar.delete': 'Delete',
'sidebar.archive': 'Archive',
'sidebar.unarchive': 'Restore',
'sidebar.moreActions': 'More actions',
'sidebar.archiveCurrentDisabled': 'The current session cannot be archived',
'sidebar.archivedTitle': 'Archived',
'sidebar.archivedEmpty': 'No archived sessions.',
'sidebar.archiveFailed': 'Failed to archive session',
'sidebar.unarchiveFailed': 'Failed to restore session',
'sidebar.loadingSessions': 'Loading sessions...',
'sidebar.loadFailed': 'Failed to load sessions. Click to retry.',
'sidebar.renameFailed': 'Failed to rename session',
'sidebar.deleteFailed': 'Failed to delete session',
'sidebar.newSessionFailed': 'Failed to create a new chat',
'sidebar.switchFailed': 'Failed to switch session',
'sidebar.currentDeleteDisabled': 'Current session cannot be deleted',
'sidebar.deleteConfirmDescription': (v) =>
`Delete "${v?.name ?? ''}"? This cannot be undone.`,
'sidebar.clients': (v) => `${v?.count ?? 0} client(s)`,
'sidebar.running': 'Running',
'sidebar.completedUnread': 'Finished',
'sidebar.pin': 'Pin',
'sidebar.unpin': 'Unpin',
'sidebar.sessionGroup': 'Group',
'sidebar.groupFilter': 'Session group',
'sidebar.groupAll': 'All',
'sidebar.groupPinned': 'Pinned',
'sidebar.groupUngrouped': 'Ungrouped',
'sidebar.groupRecent': 'Recent',
'sidebar.groupCreate': 'Create group',
'sidebar.groupRename': 'Rename group',
'sidebar.groupDelete': 'Delete group',
'sidebar.groupColor': 'Group color',
'sidebar.groupNamePrompt': 'Group name',
'sidebar.groupDeleteConfirm': (v) => `Delete group "${v?.name ?? ''}"?`,
'sidebar.groupsLoadFailed': 'Failed to load session groups',
'sidebar.groupCreateFailed': 'Failed to create group',
'sidebar.groupAssignFailedAfterCreate':
'Group created, but failed to move session into it',
'sidebar.groupUpdateFailed': 'Failed to update group',
'sidebar.groupDeleteFailed': 'Failed to delete group',
'sidebar.organizationFailed': 'Failed to update session organization',
'sidebar.groupColor.red': 'Red',
'sidebar.groupColor.orange': 'Orange',
'sidebar.groupColor.yellow': 'Yellow',
'sidebar.groupColor.green': 'Green',
'sidebar.groupColor.blue': 'Blue',
'sidebar.groupColor.purple': 'Purple',
'quickKeys.cursor': 'Move cursor',
'quickKeys.escape': 'Cancel run',
'quickKeys.history': 'History',
'quickKeys.retry': 'Retry failed',
'quickKeys.searchHistory': 'Search history',
'quickKeys.tab': 'Accept completion',
'error.unsupportedTheme':
'Unsupported theme. Use /theme light or /theme dark.',
'queue.delete': 'Delete',
'queue.edit': 'Edit',
'queue.insert': 'Insert',
'queue.cleared': 'Queue cleared.',
'queue.deleteTip': 'Remove from queue',
'queue.editTip': 'Remove from queue and edit again',
'queue.insertTip':
'Insert this message into the current session; it takes effect on the next model call.',
'queue.inserted': 'Inserted. It takes effect on the next model call.',
'queue.insertCommandDisabled':
"Commands can't be inserted into the running turn; they run after it finishes.",
'queue.submitting': 'Submitting...',
'queue.editing': 'Editing...',
'queue.removing': 'Updating...',
'queue.submittingDisabled': 'Submitting queued message...',
'queue.commandBlocked':
"Slash commands can't be queued while a turn is running.",
'queue.shellBlocked':
"Shell commands can't be queued while a turn is running.",
'queue.queueFailed': 'Failed to queue message',
'queue.insertFailed': 'Failed to insert queued message',
'queue.deleteFailed': 'Failed to move message out of queue',
'queue.editFailed': 'Failed to edit queued message',
'queue.footer':
'Press ↑ to edit the latest queued message · Esc to clear queue',
'queue.imageCount': (v) => `(+${v?.count ?? 0} images)`,
'queue.more': (v) => `... (+${v?.count ?? 0} more)`,
'midTurn.inserted': (v) => `Inserted message: ${v?.message ?? ''}`,
'help.builtIn': 'Built-in commands',
'help.commandCount': (v) => `${v?.count ?? 0} commands`,
'help.commandMeta.builtIn': 'built-in',
'help.commandMeta.custom': 'custom',
'help.commandMeta.subcommands': (v) => `${v?.count ?? 0} subcommands`,
'help.commandsIntro': 'Browse built-in commands:',
'help.customGroup': 'Custom, skills, plugins, MCP',
'help.customIntro': 'Browse custom, skill, plugin, and MCP commands:',
'help.empty': 'No commands are currently available.',
'help.emptyCustom': 'No custom commands are currently available.',
'help.footer':
'Tab/Shift+Tab to switch tabs · ↑/↓ or PgUp/PgDn to scroll · Esc to close',
'help.intro':
'Qwen Code understands your codebase, makes edits with your permission, and executes commands right from your terminal.',
'help.section.shortcuts': 'Shortcuts',
'help.search': 'Search commands',
'help.shortcut.addContext': 'Add files or folders as context',
'help.shortcut.altWords': 'Jump through words',
'help.shortcut.clear': 'Clear the screen',
'help.shortcut.commandMenu': 'Open command menu',
'help.shortcut.completion': 'Accept completion or switch help tabs',
'help.shortcut.history': 'Cycle prompt history or scroll lists',
'help.shortcut.searchHistory': 'Search prompt history',
'help.shortcut.newline': 'Insert a newline',
'help.shortcut.pasteImages': 'Paste images',
'help.shortcut.shell': 'Run shell commands',
'help.shortcut.togglePanel': 'Toggle this panel',
'help.shortcut.retry': 'Retry last request',
'help.shortcut.compact': 'Toggle compact mode',
'retry.hint': 'Press Ctrl+Y to retry or click to retry',
'retry.none': 'No failed request to retry.',
'branch.failed': 'Failed to branch session.',
'branch.success': (v) =>
`Copied session. New session name: "${v?.name ?? ''}". Switched to the new session.`,
'fork.empty': 'Please provide a directive. Usage: /fork <directive>',
'fork.failed': (v) => `Failed to launch fork: ${v?.reason ?? ''}`,
'fork.notStarted': 'Background agent was not launched.',
'fork.started': (v) =>
`Started background agent: "${v?.name ?? ''}". Track it in background tasks.`,
'command.hidden': 'This command is not available.',
'help.shortcut.approvals': 'Cycle approval modes',
'help.shortcut.cancel': 'Close dialogs or cancel operation',
'bug.failed': 'Failed to load system info for bug report.',
'bug.popupBlocked': 'Popup blocked — please allow popups and try again.',
'bug.submitted': 'Bug report opened in a new tab.',
'clear.blocked': 'Cannot clear while streaming — cancel first (Esc).',
'error.unknown': 'Unknown error',
'error.modelStreamInterrupted':
'Model response stream was interrupted. Please retry.',
'shell.command': 'Shell Command',
'compact.enabled': 'Compact mode enabled',
'compact.disabled': 'Compact mode disabled',
'compact.hint': 'Press Ctrl+O to show full tool output',
'compact.saveFailed': 'Failed to save compact mode',
'help.subcommands': 'subcommands',
'help.tab.commands': 'Built-in commands',
'help.tab.custom': 'custom-commands',
'help.tab.general': 'shortcuts',
'help.title': 'Help',
'slash.category.custom': 'Custom commands',
'slash.category.skill': 'Skill commands',
'slash.category.system': 'System commands',
'language.changed': (v) => `UI language changed to ${v?.language ?? ''}`,
'language.current': (v) => `Current UI language: ${v?.language ?? ''}`,
'language.invalid': 'Invalid language. Available: en, zh-CN',
'language.options': 'Available options:',
'language.set': 'Set UI language',
'language.usage': 'Usage: /language ui [en|zh-CN]',
'localCommand.noSession':
'No active session yet. Send your first message before using this command.',
'local.agents': 'Manage subagents',
'local.bug': 'Submit a bug report',
'local.compress': 'Compress the context into a summary',
'local.compressFast': 'Fast context compression without AI',
'local.config': 'Get or set any setting by dot-path key',
'local.diff': 'Show working-tree change stats versus HEAD',
'local.directory': 'Manage workspace directories',
'local.docs': 'Open the full Qwen Code documentation',
'local.doctor': 'Run installation and environment diagnostics',
'local.dream': 'Consolidate managed auto-memory topic files',
'local.effort': 'Set reasoning effort for capable models',
'local.export': 'Export the current session history to a file',
'local.forget': 'Remove matching entries from managed auto-memory',
'local.hooks': 'Manage Qwen Code hooks',
'local.importConfig': 'Import MCP servers from Claude configs',
'local.init': 'Analyze the project and create a QWEN.md file',
'local.insight': 'Generate programming insights from chat history',
'local.lsp': 'Show LSP server status',
'local.remember': 'Save a durable memory to the memory system',
'local.summary': 'Generate a project summary file',
'local.workflows': 'List active and completed workflow runs',
'skilldesc.batch': 'Run batch operations across many files in parallel',
'skilldesc.dataviz': 'Design guidance for charts and data visualizations',
'skilldesc.extensionCreator':
'Create, test, and customize Qwen Code extensions',
'skilldesc.loop': 'Run a prompt on a schedule or self-paced wakeups',
'skilldesc.newApp': 'Workflow for building a new app from scratch',
'skilldesc.qcHelper': 'Answer questions about using Qwen Code',
'skilldesc.review': 'Review changed code for bugs, security, and quality',
'skilldesc.simplify': 'Clean up recent changes for reuse and simplicity',
'skilldesc.stuck': 'Diagnose frozen or slow Qwen Code sessions',
'skilldesc.agentReproduceAlign':
'Align a ported Codex/Claude Code feature with the original',
'skilldesc.agentReproduceFeature':
'Reproduce an existing Codex/Claude Code feature',
'skilldesc.autofix':
'Implement approved issues or address PR review feedback',
'skilldesc.bugfix': 'Fix a bug from a GitHub issue, reproduce-first',
'skilldesc.codegraph': 'Analyze the codebase via graph and vector index',
'skilldesc.createIssue': 'Draft and submit a GitHub issue from an idea',
'skilldesc.desktopPet': 'Create a pixel-art desktop pet for Qwen Code',
'skilldesc.docsAuditAndRefresh':
'Audit and refresh docs/ against the codebase',
'skilldesc.docsUpdateFromDiff': 'Update official docs from local git diff',
'skilldesc.e2eTesting': 'Run end-to-end tests of the Qwen Code CLI',
'skilldesc.featDev': 'End-to-end workflow for a non-trivial feature',
'skilldesc.memoryLeakDebug': 'Diagnose CLI memory leaks via heap snapshots',
'skilldesc.openworkDesktopSync':
'Sync packages/desktop with openwork commit-by-commit',
'skilldesc.preparePr': 'Prepare a GitHub PR title and body from the branch',
'skilldesc.qwenCodeClaw': 'Use Qwen Code as a code-understanding agent',
'skilldesc.structuredDebugging':
'Hypothesis-driven methodology for hard bugs',
'skilldesc.terminalCapture': 'Automate terminal UI screenshot testing',
'skilldesc.tmuxRealUserTesting': 'Real-user testing with tmux, saving logs',
'skilldesc.triage': 'Triage and review Qwen Code issues and PRs',
'local.approvalMode': 'Change approval mode',
'local.auth': 'Connect an LLM provider',
'auth.title': 'Connect a Provider',
'auth.step.group': 'Type',
'auth.step.provider': 'Provider',
'auth.step.protocol': 'Protocol',
'auth.step.baseUrl': 'Base URL',
'auth.step.apiKey': 'API Key',
'auth.step.models': 'Model IDs',
'auth.step.advanced': 'Advanced Config',
'auth.protocol.openai': 'OpenAI-compatible',
'auth.protocol.openaiDesc': 'Standard OpenAI API format (most common)',
'auth.protocol.anthropic': 'Anthropic-compatible',
'auth.protocol.anthropicDesc': 'Anthropic Messages API format',
'auth.protocol.gemini': 'Gemini-compatible',
'auth.protocol.geminiDesc': 'Google Gemini API format',
'auth.apiKeyRequired': 'API key cannot be empty.',
'auth.baseUrlInvalid': 'Base URL must start with http:// or https://.',
'auth.baseUrlPrompt': 'Enter the API endpoint for this protocol.',
'auth.baseUrlRequired': 'Base URL cannot be empty.',
'auth.documentation': 'Documentation',
'auth.modelsRequired': 'Model IDs cannot be empty.',
'auth.review': 'Review',
'auth.reviewText': 'The following JSON will be saved to settings.json:',
'auth.save': 'Save',
'auth.saving': 'Saving...',
'auth.termsTitle': 'Terms of Services and Privacy Notice',
'auth.continue': 'Continue',
'auth.modelsPrompt': (v) =>
`Enter model IDs separated by commas. Examples: ${v?.modelIds ?? ''}`,
'auth.advanced.prompt': 'Optional: configure advanced generation settings.',
'auth.advanced.thinking': 'Enable thinking',
'auth.advanced.thinkingDesc':
'Allows the model to perform extended reasoning before responding.',
'auth.advanced.modality': 'Enable modality',
'auth.advanced.modalityDesc':
'Enables multimodal input capabilities (image, video, etc.).',
'auth.advanced.modalityImage': 'Image',
'auth.advanced.modalityVideo': 'Video',
'auth.advanced.modalityAudio': 'Audio',
'auth.advanced.modalityPdf': 'PDF',
'auth.advanced.contextWindow': 'Context window',
'auth.advanced.contextDesc':
'Max input tokens (leave empty to auto-detect from model name).',
'auth.advanced.contextPlaceholder': 'Context window (optional)',
'local.btw':
'Ask a quick side question without affecting the main conversation. Usage: /btw <your question>',
'btw.empty': 'Please provide a question. Usage: /btw <your question>',
'btw.emptyAnswer': 'No response received.',
'btw.failed': 'Failed to answer btw question',
'btw.answering': '+ Answering...',
'btw.shortcuts.pending': 'Press Escape, Ctrl+C, or Ctrl+D to cancel',
'btw.shortcuts.done': 'Press Space, Enter, or Escape to dismiss',
'local.clear':
'Start a new session with empty context; previous session stays on disk (resumable with /resume)',
'local.context':
'Show context window usage breakdown. Use "/context detail" for per-item breakdown.',
'local.copy': 'Copy last output or snippet',
'local.delete': 'Delete a session permanently',
'local.release': 'Release a live session',
'local.rewind': 'Rewind the current conversation',
'local.branch': 'Fork the current conversation into a new session',
'local.fork': 'Start a background agent from this conversation',
'local.help': 'Show help and commands',
'local.language': 'Change UI language',
'local.mcp': 'Manage MCP servers',
'local.memory': 'Manage memory',
'local.model': 'Switch model or set fast model',
'local.new': 'Start a new conversation',
'local.plan': 'Enter Plan mode',
'local.goal': 'Set a goal and keep working until it is met',
'local.recap': 'Generate a session recap',
'recap.label': 'Recap',
'recap.loading': 'Generating recap...',
'recap.empty': 'Not enough conversation context for a recap yet.',
'recap.failed': 'Failed to generate recap',
'rewind.action': 'Rewind',
'rewind.confirm': 'Confirm rewind',
'rewind.empty': 'No rewind snapshots are available for this session.',
'rewind.failed': (v) => `Failed to rewind session: ${v?.reason ?? ''}`,
'rewind.loading': 'Loading rewind snapshots...',
'rewind.promptFallback': (v) => `Prompt ${v?.id ?? ''}`,
'rewind.rewinding': 'Rewinding...',
'rewind.subtitle': 'Only the conversation is rewound. Files are not changed.',
'rewind.title': 'Rewind Conversation',
'rewind.turn': (v) => `Prompt ${v?.turn ?? 0}`,
'local.rename': 'Rename current session',
'rename.empty':
'Please enter a session name, for example /rename project debugging, or use /rename --auto.',
'rename.success': (v) => `Session renamed to ${v?.name ?? ''}`,
'local.reset': 'Reset current conversation',
'local.resume': 'Resume a previous session',
'local.skills': 'View available skills',
'local.stats': 'Show session statistics',
'local.tasks': 'View background tasks',
'local.status': 'Show version info',
'local.theme': 'Change theme',
'local.settings': 'View and edit settings',
'local.schedule': 'Manage scheduled tasks',
'local.extensions':
'Manage extensions. Usage: /extensions manage|install <source>',
'extensions.label': 'extension',
'extensions.action.failed': (v) =>
`Extension action failed${
v?.name ? ` for "${v.name}"` : v?.source ? ` from "${v.source}"` : ''
}: ${v?.error ?? 'Unknown error'}`,
'extensions.commands.refreshFailed': 'Failed to refresh extension commands.',
'extensions.install.failed': (v) =>
`Failed to install extension${
v?.source ? ` from "${v.source}"` : ''
}: ${v?.error ?? 'Unknown error'}`,
'extensions.manage.agents': 'Agents:',
'extensions.manage.checkingUpdates': 'Checking for updates...',
'extensions.manage.commands': 'Commands:',
'extensions.manage.contextFiles': 'Context files:',
'extensions.manage.count': (v) => `${v?.count ?? 0} extensions installed`,
'extensions.manage.detailsTitle': 'Extension Details',
'extensions.manage.disable': 'Disable Extension',
'extensions.manage.disabled': (v) =>
`Extension "${v?.name ?? 'extension'}" disabled.`,
'extensions.manage.empty': 'No extensions installed.',
'extensions.manage.enable': 'Enable Extension',
'extensions.manage.enabled': (v) =>
`Extension "${v?.name ?? 'extension'}" enabled.`,
'extensions.manage.footer.back': 'Esc to go back',
'extensions.manage.footer.confirm': 'Enter confirm · Esc cancel',
'extensions.manage.footer.list':
'↑↓ to navigate · Enter select · r refresh · Esc close',
'extensions.manage.footer.select': '↑↓ to navigate · Enter select · Esc back',
'extensions.manage.loading': 'Loading extensions...',
'extensions.manage.mcpServers': 'MCP servers:',
'extensions.manage.name': 'Name:',
'extensions.manage.notUpdatable': 'not updatable',
'extensions.manage.path': 'Path:',
'extensions.manage.queued': (v) =>
`Extension action queued for "${v?.name ?? 'extension'}".`,
'extensions.manage.refreshed': (v) =>
`Extensions refreshed in ${v?.refreshed ?? 0} session(s), ${v?.failed ?? 0} failed.`,
'extensions.manage.settings': 'Settings:',
'extensions.manage.skills': 'Skills:',
'extensions.manage.source': 'Source:',
'extensions.manage.status': 'Status:',
'extensions.manage.status.disabled': 'disabled',
'extensions.manage.status.enabled': 'enabled',
'extensions.manage.title': 'Manage Extensions',
'extensions.manage.unknownUpdate': 'unknown',
'extensions.manage.uninstalled': (v) =>
`Extension "${v?.name ?? 'extension'}" uninstalled.`,
'extensions.manage.uninstallAction': 'Uninstall Extension',
'extensions.manage.uninstallConfirm': (v) =>
`Uninstall extension "${v?.name ?? 'extension'}"?`,
'extensions.manage.upToDate': 'up to date',
'extensions.manage.update': 'Update Extension',
'extensions.manage.updateAvailable': 'update available',
'extensions.manage.updateError': 'update check failed',
'extensions.manage.updated': (v) =>
`Extension "${v?.name ?? 'extension'}" updated.`,
'extensions.manage.updatedWithVersion': (v) =>
`Extension "${v?.name ?? 'extension'}" updated to v${v?.version ?? ''}.`,
'extensions.manage.version': 'Version:',
'extensions.manage.viewDetails': 'View Details',
'extensions.install.installed': (v) =>
`Extension "${v?.name ?? 'extension'}" installed.`,
'extensions.install.installedWithVersion': (v) =>
`Extension "${v?.name ?? 'extension'}" v${v?.version ?? ''} installed.`,
'extensions.install.missingOptionValue': (v) =>
`Missing value for ${v?.option ?? 'option'}`,
'extensions.install.requestFailed': 'Failed to install extension',
'extensions.install.started': (v) =>
`Installing extension from "${v?.source ?? ''}"...`,
'extensions.install.unknownOption': (v) =>
`Unknown option ${v?.option ?? ''}`,
'extensions.install.usage': 'Usage: /extensions manage|install <source>',
'extensions.install.waitForSession':
'Wait for the session to connect before installing an extension.',
'local.tools': 'List available tools. Usage: /tools [desc]',
'loadWarning.commands':
'Failed to load command list; slash commands may be incomplete.',
'loadWarning.context':
'Failed to load session context; current mode may be inaccurate.',
'loadWarning.models':
'Failed to load model list; some model details may be unavailable.',
'mcp.action.auth': 'Authenticate',
'mcp.action.authHint': 'Not exposed by daemon yet',
'mcp.action.authMessage':
'Daemon serve does not expose MCP authentication yet.',
'mcp.action.clearAuth': 'Clear Authentication',
'mcp.action.disable': 'Disable',
'mcp.action.done': (v) => `${v?.action ?? 'Action'} complete.`,
'mcp.action.enable': 'Enable',
'mcp.action.enableMessage':
'Daemon serve does not expose MCP enable/disable yet.',
'mcp.action.failed': (v) => `Failed: ${v?.error ?? ''}`,
'mcp.action.running': (v) => `${v?.action ?? 'Action'}...`,
'mcp.action.reauth': 'Re-authenticate',
'mcp.annotation.destructive': 'destructive',
'mcp.annotation.idempotent': 'idempotent',
'mcp.annotation.openWorld': 'open-world',
'mcp.annotation.readOnly': 'read-only',
'mcp.annotations': 'Annotations',
'mcp.oauth.server': 'Server',
'mcp.oauth.starting': (v) =>
`Starting OAuth authentication for MCP server '${v?.name ?? ''}'...`,
'mcp.oauth.title': 'OAuth Authentication',
'mcp.clientBudget': (v) =>
`${v?.count ?? 0}/${v?.budget ?? 0} clients · ${v?.mode ?? 'off'}`,
'mcp.command': 'Command',
'mcp.description': 'Description:',
'mcp.action.reconnect': 'Reconnect',
'mcp.action.restart': 'Restart',
'mcp.action.tools': 'View tools',
'mcp.action.toolsHint': 'Enter to inspect',
'mcp.empty': 'No MCP servers configured.',
'mcp.emptyTools': 'No tools discovered.',
'mcp.expand': 'Expand MCP server',
'mcp.collapse': 'Collapse MCP server',
'mcp.inputSchema': 'Input schema',
'mcp.loadingStatus': 'Loading MCP status...',
'mcp.loadingTools': 'Loading tools...',
'mcp.name': 'Name',
'mcp.noDescription': 'No description',
'mcp.noSchema': 'No input schema.',
'mcp.serverTool': 'Server tool',
'mcp.servers': (v) => `${v?.count ?? 0} servers`,
'mcp.configuredServers': 'Configured MCP servers:',
'mcp.fromExtension': (v) => `(from ${v?.name ?? ''})`,
'mcp.extensionMcp': 'Extension MCP',
'mcp.invalidReason': (v) => `invalid: ${v?.reason ?? ''}`,
'mcp.invalidReasonLabel': 'Reason:',
'mcp.invalidToolHelp':
'Tools must have both name and description to be used by the LLM.',
'mcp.invalidToolWarning': 'Warning: This tool cannot be called by the LLM',
'mcp.manageServers': 'Manage MCP servers',
'mcp.parameters': 'Parameters:',
'mcp.required': ' required',
'mcp.resources': 'Resources',
'mcp.resourcesUnavailable': 'Resource details unavailable.',
'mcp.resourceCount': (v) =>
`${v?.count ?? 0} ${v?.count === 1 ? 'resource' : 'resources'}`,
'mcp.promptCount': (v) =>
`${v?.count ?? 0} ${v?.count === 1 ? 'prompt' : 'prompts'}`,
'mcp.resource.uriLabel': 'URI:',
'mcp.resource.nameLabel': 'Name:',
'mcp.resource.mimeTypeLabel': 'MIME Type:',
'mcp.resource.sizeLabel': 'Size:',
'mcp.resource.bytes': (v) =>
`${v?.count ?? 0} ${v?.count === 1 ? 'byte' : 'bytes'}`,
'mcp.scrollPosition': (v) => `${v?.current ?? 0}/${v?.total ?? 0}`,
'mcp.shortcut.back': 'Esc to back',
'mcp.shortcut.close': 'Esc to close',
'mcp.shortcut.selectBack': '↑↓ to navigate · Enter to select · Esc to back',
'mcp.shortcut.selectClose': '↑↓ to navigate · Enter to select · Esc to close',
'mcp.settings': 'Settings',
'mcp.extension': (v) => `Extension: ${v?.name ?? ''}`,
'mcp.starting': (v) =>
`⏳ MCP servers are starting up (${v?.count ?? 0} initializing)...`,
'mcp.startingNote':
'Note: First startup may take longer. Tool availability will update automatically.',
'mcp.restartSkipped': (v) => `Skipped ${v?.name ?? ''}: ${v?.reason ?? ''}`,
'mcp.restarted': (v) => `Restarted ${v?.name ?? ''} in ${v?.duration ?? 0}ms`,
'mcp.restartEntries': (v) =>
`Restarted ${v?.restarted ?? 0}/${v?.total ?? 0} ${v?.name ?? ''} entries${v?.failedReasons ? ` (failed: ${v.failedReasons})` : ''}`,
'mcp.source': 'Source',
'mcp.source.extension': 'Extension',
'mcp.source.project': 'Workspace Settings',
'mcp.source.user': 'User Settings',
'mcp.status': 'Status',
'mcp.status.blocked': 'Blocked',
'mcp.status.connected': 'connected',
'mcp.status.connecting': 'connecting',
'mcp.status.disconnected': 'disconnected',
'mcp.status.disconnectedTitle': 'Disconnected',
'mcp.status.disabled': 'disabled',
'mcp.status.ready': 'Ready',
'mcp.status.starting': 'Starting... (first startup may take longer)',
'mcp.status.unknown': 'unknown',
'mcp.tipDesc': 'to show server and tool descriptions',
'mcp.tipNodesc': 'to hide descriptions',
'mcp.tipSchema': 'to show tool parameter schemas',
'mcp.tips': '💡 Tips:',
'mcp.toolCount': (v) => `${v?.count ?? 0} tool`,
'mcp.toolsCount': (v) => `${v?.count ?? 0} tools`,
'mcp.toolsLabel': 'Tools:',
'mcp.title': 'MCP Servers',
'mcp.toolDetail': 'Tool Detail',
'mcp.tools': 'Tools',
'mcp.toolsForServer': (v) => `Tools for ${v?.name ?? 'Server'}`,
'mcp.transport': 'Transport',
'mcp.use': 'Use',
'mcp.userMcp': 'User MCP',
'mcp.workingDirectory': 'Working Directory',
'goal.aborted': 'Goal aborted',
'goal.achieved': 'Goal achieved',
'goal.check': 'Goal check',
'goal.cleared': 'Goal cleared',
'goal.failed': 'Goal could not be achieved',
'goal.judge': 'Judge',
'goal.label': 'Goal',
'goal.lastCheck': 'Last check',
'goal.notYetMet': 'not yet met',
'goal.set': 'Goal set',
'goal.statusActive': '/goal active',
'goal.turn': (v) => `${v?.count ?? 0} turn`,
'goal.turnLabel': (v) => `turn ${v?.count ?? 0}`,
'goal.turns': (v) => `${v?.count ?? 0} turns`,
'memory.add': 'Add',
'memory.add.desc': 'Write a durable memory',
'memory.autoDream': (v) =>
`Auto-dream: ${v?.status ?? 'unknown'} · ${v?.lastDream ?? 'never'} · /dream to run`,
'memory.autoDreamUnsupported':
'Auto-dream settings are not available from web-shell yet.',
'memory.autoFolder': 'Open auto-memory folder',
'memory.autoMemory': (v) => `Auto-memory: ${v?.status ?? 'unknown'}`,
'memory.autoMemoryUnsupported':
'Auto-memory settings are not available from web-shell yet.',
'memory.autoSkill': (v) => `Auto-skill: ${v?.status ?? 'unknown'}`,
'memory.autoSkillUnsupported':
'Auto-skill settings are not available from web-shell yet.',
'memory.chooseScope': 'Choose where to save the memory',
'memory.closed': 'Memory panel closed.',
'memory.contentEmpty': 'Memory content is empty.',
'memory.file': 'Memory file',
'memory.fileOpen': 'Memory file opened.',
'memory.fileTruncated': 'Memory file opened. Content is truncated.',
'memory.files': 'Memory Files',
'memory.footer': 'Enter to confirm · Esc to cancel',
'memory.footer.back': 'Esc to go back',
'memory.global': 'User',
'memory.global.desc': 'Saved to the global user memory file',
'memory.globalReadUnsupported':
'Global memory is outside the bound workspace, so the current daemon file-read API cannot open its content.',
'memory.loading': 'Loading memory...',
'memory.loadingFile': 'Loading memory file...',
'memory.lastDream': '5 hours ago',
'memory.menu': 'Memory',
'memory.never': 'never',
'memory.noFiles': 'No memory files found.',
'memory.on': 'on',
'memory.openFolderUnsupported':
'Opening the auto-memory folder is not available from web-shell yet.',
'memory.placeholder': (v) => `Write ${v?.scope ?? 'memory'} content...`,
'memory.project': 'Project',
'memory.project.desc': 'Saved to this workspace memory file',
'memory.refresh': 'Refresh',
'memory.refresh.desc': 'Reload memory file information',
'memory.refreshed': 'Memory refreshed.',
'memory.save': 'Save Memory',
'memory.savedIn': (v) => `Saved in ${v?.path ?? ''}`,
'memory.saved': (v) =>
`${v?.scope ?? 'Memory'} saved: ${v?.bytes ?? 0} bytes -> ${v?.path ?? ''}`,
'memory.saving': 'Saving...',
'memory.show': 'Show',
'memory.show.desc': 'Show configured memory files',
'memory.status': 'Workspace and user memory files',
'memory.unknown': 'unknown',
'memory.write': 'Write memory content',
'mode.auto': 'Classifier Approval',
'mode.auto.desc':
'Uses a classifier to approve safe tool calls and block or ask for risky ones',
'mode.auto.notice':
'Auto mode enabled. An LLM classifier evaluates each tool call and auto-approves safe actions, blocks risky ones. To exit: Shift+Tab or /approval-mode default.',
'mode.footer': '(Use Enter to select, Esc to cancel)',
'mode.name.plan': 'plan',
'mode.name.default': 'default',
'mode.name.auto-edit': 'auto-edit',
'mode.name.auto': 'auto',
'mode.name.yolo': 'yolo',
'mode.label.plan': 'Plan',
'mode.label.default': 'Ask Approval',
'mode.label.auto-edit': 'Auto Edit',
'mode.label.auto': 'Classifier Approval',
'mode.label.yolo': 'Full Access',
'mode.listLabel.plan': 'Plan (plan)',
'mode.listLabel.default': 'Ask Approval (default)',
'mode.listLabel.auto-edit': 'Auto Edit (auto-edit)',
'mode.listLabel.auto': 'Classifier Approval (auto)',
'mode.listLabel.yolo': 'Full Access (yolo)',
'mode.desc.plan': 'Analyze only, do not modify files or execute commands',
'mode.desc.default':
'Ask before running commands, editing files, or accessing external resources',
'mode.desc.auto-edit':
'Automatically approve file edits and ask before command execution or other sensitive actions',
'mode.desc.auto':
'Evaluate tool risk automatically, run safe actions, and confirm risky ones',
'mode.desc.yolo': 'Automatically approve all tool calls in trusted contexts',
'mode.select': 'Approval Mode',
'mode.autoApproved': ((v) =>
v?.tool
? `Auto-approved: ${v.tool}`
: 'Pending tool call auto-approved by mode switch.') as MessageValue,
'mode.auto-edit': 'Auto-accept edits',
'mode.auto-edit.desc': 'Automatically approve file read/write operations',
'mode.default': 'Default mode',
'mode.default.desc': 'Ask before each tool call',
'mode.plan': 'Plan mode',
'mode.plan.desc': 'Analyze and plan without running tools',
'mode.unknown': 'unknown mode',
'mode.yolo': 'YOLO mode',
'mode.yolo.desc': 'Automatically approve all operations',
'plan.title': 'Plan',
'model.contextWindow': 'Context Window',
'model.contextWindow.unknown': '(unknown)',
'model.current': (v) => `current: ${v?.model ?? 'unknown'}`,
'model.modality': 'Modality',
'model.modality.text': 'text',
'model.modality.textOnly': 'text-only',
'model.modality.image': 'image',
'model.modality.pdf': 'pdf',
'model.modality.audio': 'audio',
'model.modality.video': 'video',
'model.baseUrl': 'Base URL',
'model.apiKey': 'API Key',
'model.default': '(default)',
'model.notSet': '(not set)',
'model.footer': 'Enter select, ↑↓ navigate, Esc close',
'model.searchHint': 'Press / to search',
'model.fastHint': 'for suggestions and side tasks',
'model.noMatch': (v) => `No model matching "${v?.query ?? ''}"`,
'model.none': 'No models available',
'model.select': 'Select Model',
'model.setFast': 'Set Fast Model',
'model.setVoice': 'Set Voice Model',
'model.setVision': 'Set Vision Model',
'model.switch': 'Switch Model',
'model.unknown': 'unknown',
'resume.current': 'current',
'resume.activePrompt': 'active prompt',
'resume.filter': 'Filter',
'resume.noMatch': (v) => `No session matching "${v?.query ?? ''}"`,
'resume.none': 'No sessions to resume',
'resume.pressSearch': 'Press / to search',
'resume.search': 'Search',
'resume.title': 'Resume Session',
'parallelAgents.title': 'Parallel agents',
'parallelAgents.done': (v) => `${v?.done ?? 0}/${v?.total ?? 0} done`,
'skills.available': 'Available skills:',
'skills.none': 'No skills are currently available.',
'skills.empty': 'No skills available.',
'skills.footer': (v) =>
v?.name
? `Use /skills ${v.name} to invoke · r to refresh · Esc to close`
: 'r to refresh · Esc to close',
'skills.invocable': (v) => `${v?.enabled ?? 0}/${v?.total ?? 0} invocable`,
'skills.loading': 'Loading skills...',
'skills.run': 'Run skill',
'skills.status.disabled': 'disabled',
'skills.title': 'Skills',
'stats.accepted': 'Accepted:',
'stats.agreementRate': 'Overall Agreement Rate:',
'stats.api': 'API',
'stats.apiTime': 'API Time',
'stats.avgDuration': 'Avg Duration',
'stats.avgLatency': 'Avg Latency',
'stats.cached': 'Cached',
'stats.cacheDesc':
'of input tokens were served from the cache, reducing costs.',
'stats.calls': 'Calls',
'stats.codeChanges': 'Code Changes',
'stats.decisionSummary': 'User Decision Summary',
'stats.duration': 'Duration',
'stats.errors': 'Errors',
'stats.inputTokens': 'Input Tokens',
'stats.metric': 'Metric',
'stats.modelStats': 'Model Stats',
'stats.modelTip': 'Tip: For a full token breakdown, run /stats model.',
'stats.modelUsage': 'Model Usage',
'stats.modified': 'Modified:',
'stats.noApiCalls': 'No API calls have been made in this session.',
'stats.noToolCalls': 'No tool calls have been made in this session.',
'stats.outputTokens': 'Output Tokens',
'stats.overview': 'Session Overview',
'stats.performance': 'Performance',
'stats.prompts': 'Prompts',
'stats.rejected': 'Rejected:',
'stats.reqs': 'Reqs',
'stats.requests': 'Requests',
'stats.savingsHighlight': 'Savings Highlight:',
'stats.successRate': 'Success Rate',
'stats.thoughts': 'Thoughts',
'stats.title': 'Session Stats',
'stats.tokens': 'Tokens',
'stats.toolCalls': 'Tool Calls',
'stats.toolName': 'Tool Name',
'stats.toolStats': 'Tool Stats',
'stats.toolTime': 'Tool Time',
'stats.total': 'Total',
'stats.totalReviewed': 'Total Reviewed Suggestions:',
'status.contextUsed': (v) => `${v?.pct ?? '0.0'}% context used`,
'status.disconnected': 'Disconnected',
'status.modeHint': '(shift + tab or click to switch)',
'status.shortcuts': '? for shortcuts',
'stream.cancel': 'esc to cancel',
'stream.cancelArmed': 'Press Esc again to stop',
'stream.tokens': (v) => `${v?.count ?? 0} tokens`,
'theme.current': (v) => `current: ${v?.theme ?? ''}`,
'theme.auto': 'Auto',
'theme.dark': 'Dark',
'theme.dark.desc': 'Terminal-style dark skin.',
'theme.light': 'Light',
'theme.light.desc': 'Terminal-style light skin.',
'theme.title': 'Theme',
'todo.allDone': 'All tasks completed',
'todo.collapse': 'Collapse task list',
'todo.completedAbove': (v) => `${v?.count ?? 0} completed`,
'todo.detail.api': 'API',
'todo.detail.cached': 'Cached',
'todo.detail.end': 'End',
'todo.detail.hide': 'Hide task detail',
'todo.detail.input': 'Input',
'todo.detail.noResources':
"Token & time usage wasn't captured for this task.",
'todo.detail.output': 'Output',
'todo.detail.sectionSpent': 'Time spent',
'todo.detail.sectionTime': 'Time',
'todo.detail.sectionTokens': 'Tokens',
'todo.detail.show': 'Show task detail',
'todo.detail.start': 'Start',
'todo.detail.tool': 'Tool',
'todo.expand': 'Expand task list',
'todo.more': (v) => `... ${v?.count ?? 0} more`,
'todo.moreAbove': (v) => `... ${v?.count ?? 0} earlier`,
'todo.showLess': 'Show less',
'todo.stepProgress': (v) => `Step ${v?.current ?? 0} / ${v?.total ?? 0}`,
'todo.stepFraction': (v) => `${v?.current ?? 0} / ${v?.total ?? 0}`,
'todo.title': 'Current tasks',
'chat.scrollToBottom': 'Scroll to bottom',
'userMessage.showMore': 'Show more',
'userMessage.showLess': 'Collapse',
'turn.processed': 'Processed',
'turn.processing': 'Processing',
'turn.collapse': 'Collapse steps',
'turn.expand': 'Expand steps',
'turn.cached': 'cached',
'turn.executionSteps': (v) => {
const n = v?.count ?? 0;
return `${n} step${n === 1 ? '' : 's'}`;
},
'turn.toolCalls': (v) => {
const n = v?.count ?? 0;
return `${n} tool call${n === 1 ? '' : 's'}`;
},
'turn.thinkingCount': (v) => {
const n = v?.count ?? 0;
return `${n} thought${n === 1 ? '' : 's'}`;
},
'turn.stopped': 'You cancelled this request',
'message.renderError': 'This message could not be displayed.',
'tasks.title': 'Background tasks',
'tasks.empty': 'No tasks currently running',
'tasks.refreshStale': 'Task status may be stale; reconnecting...',
'tasks.cancelFailed': 'Failed to cancel task',
'tasks.alreadyStopped': 'Task already stopped',
'tasks.moreAbove': (v) => `^ ${v?.count ?? 0} more above`,
'tasks.moreBelow': (v) => `v ${v?.count ?? 0} more below`,
'tasks.running': 'Running',
'tasks.completed': 'Completed',
'tasks.failed': 'Failed',
'tasks.cancelled': 'Stopped',
'tasks.paused': 'Paused',
'tasks.kind.shell': 'Shell',
'tasks.kind.monitor': 'Monitor',
'tasks.action.stop': 'Stop',
'tasks.action.abandon': 'Abandon',
'tasks.action.confirmStop': 'Confirm stop',
'tasks.action.confirmAbandon': 'Confirm abandon',
'tasks.action.confirmHint': 'This will end the blocking turn.',
'tasks.pill.agent': (v) => `${v?.count ?? 0} local agent`,
'tasks.pill.agents': (v) => `${v?.count ?? 0} local agents`,
'tasks.pill.agentPaused': (v) => `${v?.count ?? 0} local agent paused`,
'tasks.pill.agentsPaused': (v) => `${v?.count ?? 0} local agents paused`,
'tasks.pill.done': (v) => `${v?.count ?? 0} task done`,
'tasks.pill.doneMany': (v) => `${v?.count ?? 0} tasks done`,
'tasks.pill.monitor': (v) => `${v?.count ?? 0} monitor`,
'tasks.pill.monitors': (v) => `${v?.count ?? 0} monitors`,
'tasks.pill.shell': (v) => `${v?.count ?? 0} shell`,
'tasks.pill.shells': (v) => `${v?.count ?? 0} shells`,
'tasks.confirmStop': 'x again to confirm stop · ends the blocking turn',
'tasks.shortcut.select': '↑/↓ select',
'tasks.shortcut.view': 'Enter view',
'tasks.shortcut.stop': 'x stop',
'tasks.shortcut.abandon': 'x abandon',
'tasks.shortcut.listClose': '←/Esc close',
'tasks.shortcut.detailBack': '← go back',
'tasks.shortcut.detailClose': 'Esc/Enter/Space close',
'tasks.shortcut.close': 'Esc close',
'tasks.shortcut.cancelConfirm': 'Esc cancel',
'tasks.detail.workingDir': 'Working dir',
'tasks.detail.outputFile': 'Output file',
'tasks.detail.command': 'Command',
'tasks.detail.events': (v) => `${v?.count ?? 0} events`,
'tasks.detail.exit': (v) => `exit ${v?.exitCode ?? ''}`,
'tasks.detail.dropped': (v) => `${v?.count ?? 0} dropped`,
'tasks.detail.error': 'Error',
'tasks.detail.stoppedBecause': 'Stopped because',
'tasks.detail.resumeBlocked': 'Resume blocked',
'tasks.detail.progress': 'Progress',
'tasks.detail.prompt': 'Prompt',
'tasks.detail.type': 'Type',
'tasks.detail.runtime': 'Time',
'tasks.detail.tokenCount': 'Tokens',
'tasks.detail.toolCallCount': 'Tool calls',
'tasks.detail.tokens': (v) => `${v?.count ?? 0} tokens`,
'tasks.detail.toolCalls': (v) => `${v?.count ?? 0} tool calls`,
'tasks.detail.nesting': 'Nesting',
'tasks.detail.nestingValue': (v) =>
`Level ${v?.level ?? '?'} · from ${v?.parent ?? '?'}`,
'tasks.detail.nestingLevel': (v) => `Level ${v?.level ?? '?'}`,
'tasks.row.from': (v) => `from ${v?.parent ?? '?'}`,
'tasks.row.nested': 'nested',
'tips.items':
'Type / to see all available commands.|Use @ to reference file paths.|Press Esc to cancel an in-flight request.|Use Shift+Enter for a newline.|Press ↑↓ to browse message history.',
'tools.available': 'Available tools:',
'tools.none': 'No tools available.',
'tools.empty': 'No built-in tools available. Open a session first.',
'tools.footer': (v) =>
v?.name
? `${v?.details ? 'Enter/Space for details · ' : ''}t to toggle ${v.name} · r to refresh · Esc to close`
: 'r to refresh · Esc to close',
'tools.details.hide': 'Hide details',
'tools.details.show': 'Show details',
'tools.loading': 'Loading tools...',
'tools.status.disabled': 'disabled',
'tools.status.enabled': 'enabled',
'tools.summary': (v) => `${v?.enabled ?? 0}/${v?.total ?? 0} enabled`,
'tools.title': 'Tools',
'tools.update.disable': 'Disable',
'tools.update.enable': 'Enable',
'tools.updating': 'Updating...',
'tool.collapse': '▲ Collapse',
'tool.expand': 'Expand',
'tool.collapseHint': 'Collapse',
'tool.status.failed': 'Failed',
'toolGroup.moreKinds': (v) => ` +${v?.count ?? 0}`,
'toolGroup.summary': (v) =>
`Ran ${v?.count ?? 0} tool${v?.count === 1 ? '' : 's'}`,
'toolGroup.summary.editedFiles': (v) =>
`Edited ${v?.count ?? 0} file${v?.count === 1 ? '' : 's'}`,
'toolGroup.summary.ranCommands': (v) =>
`Ran ${v?.count ?? 0} command${v?.count === 1 ? '' : 's'}`,
'toolGroup.summary.readFiles': (v) =>
`Read ${v?.count ?? 0} file${v?.count === 1 ? '' : 's'}`,
'toolGroup.summary.searched': (v) =>
`Searched ${v?.count ?? 0} time${v?.count === 1 ? '' : 's'}`,
'toolGroup.summary.updatedTodos': (v) =>
`Updated task list${v?.count === 1 ? '' : ` ${v?.count ?? 0} times`}`,
'toolGroup.summary.askedUser': 'Asked user',
'toolGroup.summary.otherTools': (v) =>
`Called ${v?.count ?? 0} other tool${v?.count === 1 ? '' : 's'}`,
'toolGroup.running': (v) =>
`Running ${v?.name ?? 'tool'}${v?.duration ? ` ${v.duration}` : ''}${
Number(v?.count ?? 0) > 1 ? ` · ${v?.count ?? 0} tools` : ''
}`,
'toolGroup.runningPrefix': 'Running',
'thinking.expand': 'Expand thinking',
'thinking.collapse': 'Collapse thinking',
'thinking.running': (v) => `Thinking${v?.duration ? ` ${v.duration}` : ''}`,
'thinking.done': (v) =>
v?.duration ? `Thought for ${v.duration}` : 'Done thinking',
'sessionsOverview.count': (v) => `${v?.count ?? 0} sessions`,
'sessionsOverview.current': 'Current',
'sessionsOverview.empty': 'No sessions yet',
'sessionsOverview.loadFailed': 'Failed to load sessions',
'sessionsOverview.loading': 'Loading sessions…',
'sessionsOverview.openElsewhere': 'Currently open in another window',
'sessionsOverview.openInSplit': 'Open in split',
'sessionsOverview.openInSplitHint':
'Show the selected sessions side by side in this window',
'sessionsOverview.openInTab': 'Open in new tab',
'sessionsOverview.openInTabHint':
'Open the selected sessions as a split view in a new browser tab',
'sessionsOverview.popupBlocked':
'Pop-up blocked. Allow pop-ups for this site to open sessions in new tabs.',
'sessionsOverview.refresh': 'Refresh',
'sessionsOverview.selectAll': 'Select all',
'sessionsOverview.splitCap': (v) =>
`Only the first ${v?.max ?? 6} selected sessions will open in the split.`,
'sessionsOverview.selectSession': (v) => `Select ${v?.name ?? ''}`,
'sessionsOverview.status.idle': 'Idle',
'sessionsOverview.status.needsApproval': 'Needs approval',
'sessionsOverview.status.running': 'Running',
'sessionsOverview.title': 'Session Overview',
'splitView.title': 'Split View',
'splitView.count': (v) => `${v?.count ?? 0} panes`,
'splitView.addPane': 'Add session',
'splitView.closePane': 'Close pane',
'splitView.paneError': 'This session pane hit an error',
'splitView.paneConnectionError': 'Connection lost',
'splitView.outerApprovalPending':
'Your main session is waiting for approval.',
'splitView.goToApproval': 'Go to it',
'splitView.empty': 'No sessions in the split. Add one to get started.',
'splitView.composerPlaceholder': 'Message this session…',
'settings.title': 'Settings',
'settings.loading': 'Loading settings...',
'settings.empty': 'No settings available.',
'settings.footer':
'↑↓ Navigate Enter Toggle Tab Scope r Reload ESC Close',
'settings.footer.edit': 'Enter Save ESC Cancel',
'settings.footer.theme': '↑↓ Navigate Enter Select ESC Back',
'settings.scope.user': 'User',
'settings.scope.workspace': 'Workspace',
'settings.value.on': 'ON',
'settings.value.off': 'OFF',
'settings.action.edit': 'Edit',
'settings.action.save': 'Save',
'settings.modifiedIn': (v) => `(Modified in ${v?.scope ?? ''})`,
'settings.alsoModifiedIn': (v) => `(Also modified in ${v?.scope ?? ''})`,
'settings.invalidNumber': 'Invalid number',
'settings.readOnly': 'User-scope settings are read-only in daemon mode.',
'settings.requiresRestart': 'This change requires a restart to take effect.',
'settings.corrupted': (v) =>
`Settings file was corrupted${v?.recovered === 'true' ? ' (recovered from backup)' : ''}`,
'settings.label.ui.chatWidth': 'Chat width',
'settings.description.ui.chatWidth':
'Frontend-only chat content width. Stored in this browser.',
'settings.option.ui.chatWidth.1000': 'Regular',
'settings.option.ui.chatWidth.wide': 'Ultra wide',
'settings.label.visionModel': 'Vision Model',
'settings.description.visionModel':
'Image-capable model used as the vision bridge. Leave empty to auto-select.',
'welcome.changeModel': '(/model to change)',
'welcome.defaultModel': 'unknown model',
'welcome.modeHint': 'Shift+Tab or /approval-mode',
'welcome.prompt': 'What would you like to do?',
'welcome.titlePrefix': 'Welcome to',
'welcome.tipLabel': 'Tips:',
};
const ZH: Messages = {
...EN,
// Tool display names (chat-stream badge labels). Keyed by `toolName.<wire>`;
// a wire name with no entry here falls back to the English display name via
// `localizeToolDisplayName`. Proper tool names / acronyms stay in English
// (Agent, Grep, Glob, LSP); a product name (e.g. `Notebook`) stays verbatim.
'toolName.edit': '编辑',
'toolName.write_file': '写入文件',
'toolName.read_file': '读取文件',
'toolName.grep': '搜索内容',
'toolName.grep_search': '搜索内容',
'toolName.glob': 'Glob',
'toolName.run_shell_command': '运行命令',
'toolName.todo_write': '任务清单',
'toolName.save_memory': '保存记忆',
'toolName.agent': 'Agent',
'toolName.skill': '查看技能',
'toolName.enter_plan_mode': '进入计划模式',
'toolName.exit_plan_mode': '退出计划模式',
'toolName.web_fetch': '网络搜索',
'toolName.webfetch': '网络搜索',
'toolName.fetch': '网络搜索',
'toolName.web_search': '网络搜索',
'toolName.list_directory': '列出文件',
'toolName.lsp': 'LSP',
'toolName.ask_user_question': '询问用户',
'toolName.cron_create': '创建定时任务',
'toolName.cron_list': '定时任务列表',
'toolName.cron_delete': '删除定时任务',
'toolName.task_create': '创建任务',
'toolName.task_update': '更新任务',
'toolName.task_list': '任务列表',
'toolName.task_stop': '停止任务',
'toolName.team_create': '创建团队',
'toolName.team_delete': '删除团队',
'toolName.send_message': '发送消息',
'toolName.structured_output': '结构化输出',
'toolName.monitor': '监控',
'toolName.notebook_edit': '编辑 Notebook',
'toolName.tool_search': '工具搜索',
'toolName.enter_worktree': '进入 Worktree',
'toolName.exit_worktree': '退出 Worktree',
'toolName.workflow': '工作流',
// web-shell-only wire aliases (see TOOL_DISPLAY_NAMES in toolFormatting.ts)
'toolName.bash': '运行命令',
'toolName.shell': 'Shell 命令',
'toolName.read': '读取文件',
'toolName.readfile': '读取文件',
'toolName.write': '写入文件',
'toolName.writefile': '写入文件',
'toolName.search': '搜索内容',
'toolName.todowrite': '任务清单',
'toolName.savememory': '保存记忆',
'toolName.askuserquestion': '询问用户',
'toolName.toolsearch': '工具搜索',
'about.auth': '认证',
'about.baseUrl': 'Base URL',
'about.fastModel': '快速模型',
'about.memoryUsage': '内存使用',
'about.model': '模型',
'about.noProxy': 'no proxy',
'about.noSandbox': 'no sandbox',
'about.platform': '操作系统',
'about.proxy': '代理',
'about.qwenCode': 'Qwen Code',
'about.runtime': '运行环境',
'about.sandbox': '沙箱',
'about.sessionId': '会话 ID',
'about.title': '状态',
'agent.back': '返回',
'agent.builtInBadge': '(内置)',
'agent.action.delete': '删除智能体',
'agent.action.edit': '编辑智能体',
'agent.action.view': '查看智能体',
'agent.chooseAction': (v) => `选择操作:${v?.name ?? ''}`,
'agent.chooseActionTitle': '选择操作',
'agent.colorLabel': '颜色:',
'agent.colorUpdated': (v) => `已更新 ${v?.name ?? ''} 的颜色`,
'agent.create': '创建新的智能体',
'agent.create.button': '创建智能体',
'agent.create.confirm': '确认并保存',
'agent.create.desc': '创建新的智能体',
'agent.create.descPlaceholder': '这个智能体做什么?',
'agent.create.describeAgent': '描述您的子智能体',
'agent.create.description': '描述',
'agent.create.editAgain': '编辑',
'agent.create.enterDescription': '输入描述',
'agent.create.enterName': '输入子智能体名称',
'agent.create.enterPrompt': '输入系统提示词',
'agent.create.generateFailed': (v) =>
`生成子智能体失败:${v?.error ?? '未知错误'}`,
'agent.create.generatingConfig': '正在生成子智能体配置...',
'agent.create.loading': '创建中...',
'agent.create.location': '选择位置',
'agent.create.method': '选择生成方式',
'agent.create.method.manual': '手动创建',
'agent.create.method.qwen': '使用 Qwen Code 生成',
'agent.create.method.qwen.recommended': '使用 Qwen Code 生成(推荐)',
'agent.create.method.qwen.desc': 'LLM 生成名称、提示词和描述',
'agent.create.name': '名称',
'agent.create.namePlaceholder': 'my-agent',
'agent.create.nameHelp': '输入此子智能体清晰且唯一的名称。',
'agent.create.project': '项目',
'agent.create.project.cli': '项目级 (.qwen/agents/)',
'agent.create.project.desc': '创建项目级智能体',
'agent.create.prompt': '系统提示词',
'agent.create.promptPlaceholder': '你是一个专门的智能体...',
'agent.create.promptPlaceholder.cli': '例如:你是一名专业的代码审查员...',
'agent.create.promptHelp':
'编写定义此子智能体行为的系统提示词。为了获得最佳效果,请全面描述。',
'agent.create.preview': '预览',
'agent.create.qwenHint':
'描述此子智能体应该做什么以及何时使用它。(为了获得最佳效果,请全面描述)',
'agent.create.qwenPlaceholder':
'> 例如:专业的代码审查员,根据最佳实践审查代码...',
'agent.create.required': '名称、描述和系统提示词均为必填项。',
'agent.create.save': '保存智能体',
'agent.create.scope': '选择智能体的保存位置',
'agent.create.manualDescHelp': '描述此子智能体应该在何时以及如何使用。',
'agent.create.manualDescPlaceholder':
'例如:根据最佳实践和潜在 bug 审查代码。',
'agent.create.toolsSelection': '选择工具',
'agent.create.tools.all': '所有工具',
'agent.create.tools.allDefault': '所有工具(默认)',
'agent.create.tools.allInfo': '已选择所有工具,包括 MCP 工具',
'agent.create.tools.allInfoFallback': '已选择所有工具,包括 MCP 工具',
'agent.create.tools.editLabel': '• 编辑工具:',
'agent.create.tools.executionLabel': '• 执行工具:',
'agent.create.tools.none': '(无)',
'agent.create.tools.readEdit': '读取和编辑工具',
'agent.create.tools.readEditExecute': '读取、编辑和执行工具',
'agent.create.tools.readOnlyLabel': '• 只读工具:',
'agent.create.tools.readOnly': '只读工具',
'agent.create.tools.selected': '已选择的工具:',
'agent.create.user': '用户',
'agent.create.user.cli': '用户级 (~/.qwen/agents/)',
'agent.create.user.desc': '创建用户级智能体',
'agent.createFirstHint': "使用 '/agents create' 创建第一个智能体。",
'agent.created': (v) => `已创建 ${v?.name ?? ''}`,
'agent.delete': '删除',
'agent.delete.confirm': (v) => `确定要删除 "${v?.name ?? ''}" 吗?`,
'agent.delete.loading': '删除中...',
'agent.delete.no': '否',
'agent.delete.title': (v) => `删除 ${v?.name ?? ''}`,
'agent.delete.yes': '是,删除',
'agent.deleted': (v) => `已删除 ${v?.name ?? ''}`,
'agent.edit': '编辑',
'agent.edit.color': '编辑颜色',
'agent.edit.tools': '编辑工具',
'agent.editColorTitle': (v) => `编辑颜色:${v?.name ?? ''}`,
'agent.editTitle': (v) => `编辑 ${v?.name ?? ''}`,
'agent.empty': '未找到智能体。',
'agent.footer.back': 'Esc 返回',
'agent.footer.cliBack': 'Enter 选择 · ↑↓ 导航 · Esc 返回',
'agent.footer.cliSelect': 'Enter 选择 · ↑↓ 导航 · Esc 关闭',
'agent.footer.close': 'Esc 关闭',
'agent.footer.deleteConfirm': 'Enter 确认Esc 取消',
'agent.footer.enterNext': '按 Enter 继续Esc 返回',
'agent.footer.generating': 'Esc 取消',
'agent.footer.createLocation': '按 Enter 继续,↑↓ 导航Esc 取消',
'agent.footer.createContinue': '按 Enter 继续,↑↓ 导航Esc 返回',
'agent.footer.final': '按 Enter 保存e 保存并编辑Esc 返回',
'agent.footer.nav': '↑↓ 导航 · Enter 选择 · Esc 返回',
'agent.footer.navBack': '↑↓ 导航 · Enter 选择 · Esc 返回',
'agent.footer.navSelect': '↑↓ 导航 · Enter 选择 · Esc 关闭',
'agent.footer.viewerBack': 'Esc 返回',
'agent.filePathLabel': '文件路径:',
'agent.label': '智能体',
'agent.location': '位置',
'agent.level.builtin': '内置',
'agent.level.extension': '扩展',
'agent.level.project': '项目',
'agent.level.user': '用户',
'agent.manage': '管理',
'agent.manage.desc': '管理已有智能体',
'agent.modelLabel': '模型:',
'agent.overriddenBadge': '(已被项目级智能体覆盖)',
'agent.readonly': '该智能体是只读的。',
'agent.select': '请选择一个智能体。',
'agent.selectAction': '选择操作',
'agent.descriptionLabel': '描述:',
'agent.systemPromptLabel': '系统提示词:',
'agent.step': (v) => `步骤 ${v?.n ?? ''}`,
'agent.tools': '工具',
'agent.toolsLabel': '工具:',
'agent.toolsUpdated': (v) => `已更新 ${v?.name ?? ''} 的工具`,
'agent.usingCount': (v) => `使用中:${v?.count ?? 0} 个智能体`,
'agent.view': '查看',
'agents.closed': '智能体面板已关闭。',
'agents.title': '智能体',
'subagent.result': '结果',
'subagent.tools': (v) => `工具 (${v?.count ?? 0})`,
'subagent.toolsCount': (v) => `${v?.count ?? 0} 个工具`,
'subagent.toggleStream': '展开/收起子智能体详情',
'subagent.pending': '等待中',
'subagent.running': '运行中',
'timeline.parallelAgents': '并行智能体',
'timeline.thinking': '思考',
'timeline.assistantUpdate': '助手更新',
'timeline.toolCalls': (v) => `${v?.count ?? 0} 个工具调用`,
'timeline.planUpdate': '计划更新',
'timeline.statusUpdate': '状态更新',
'timeline.userTurn': '用户轮次',
'timeline.planDetail': '计划更新',
'timeline.parallelAgentsDetail': (v) => `${v?.count ?? 0} 个并行智能体`,
'timeline.noActivity': '无活动',
'timeline.sessionTimeline': '会话时间线',
'timeline.turnPrefix': (v) => `${v?.index ?? 0}`,
'timeline.currentTurn': '当前轮次',
'timeline.kind.thought': '思考',
'timeline.kind.commentary': '助手更新',
'timeline.kind.tool': '工具调用',
'timeline.kind.agents': '并行智能体',
'timeline.kind.plan': '计划更新',
'timeline.kind.status': '状态更新',
'timeline.kind.none': '轮次',
'common.copy': '复制',
'common.na': '不适用',
'common.server': '服务器',
'common.agent': '智能体',
'common.auto': '自动',
'common.runtime': '运行时',
'common.failedToLoad': '加载失败',
'auth.notSet': '(未设置)',
'auth.apiKeyPlaceholder': 'sk-...',
'auth.modelsPlaceholder': '模型ID-1, 模型ID-2',
'model.usingModel': (v) =>
`正在使用${v?.isRuntime ? '运行时' : ''}模型:${v?.modelId ?? ''}`,
'mermaid.label': 'mermaid',
'mermaid.errorLabel': 'mermaid错误',
'user.uploadedImage': (v) => `用户上传的图片 ${v?.index ?? 1}`,
'voice.noSpeech': '未检测到语音。',
'voice.stopDictation': '停止语音输入',
'voice.transcribing': '正在转录…',
'voice.starting': '正在启动…',
'voice.errorRetry': (v) =>
`语音错误 — 点击重试${v?.message ? `${v.message}` : ''}`,
'voice.noSpeechRetry': '未检测到语音 — 点击重试',
'voice.startDictation': '开始语音输入',
'voice.error': '语音错误',
'resume.failedToLoad': '加载会话失败',
'toast.dismiss': '关闭通知',
'toast.dismissShort': '关闭',
'insight.ready': 'Insight 报告已生成!',
'request.cancelled': '请求已取消。',
'approval.execQuestion': (v) => `允许执行:'${v?.tool ?? ''}'`,
'approval.changeQuestion': '是否继续?',
'approval.launchAgentQuestion': '启动这个 agent',
'approval.option.allowOnce': '是,允许一次',
'approval.option.rejectOnce': '拒绝',
'approval.option.allowAllEdits': '允许所有编辑',
'approval.option.allowAlwaysProject': '项目内始终允许',
'approval.option.allowAlwaysUser': '对此用户始终允许',
'approval.option.allowAlwaysServer': '对此服务始终允许',
'approval.option.allowAlwaysTool': '对此工具始终允许',
'assistant.branch': '分叉',
'assistant.copy': '复制',
'at.category.extensions': '扩展',
'at.category.extensions.description': '引用已启用扩展',
'at.category.files': '文件',
'at.category.files.description': '引用工作区文件',
'at.category.mcpResources': 'MCP 资源',
'at.category.mcpResources.description': '引用 MCP server 资源',
'at.menu': '引用菜单',
'common.back': '返回',
'common.cancel': '取消',
'common.close': '关闭',
'common.fullscreen': '全屏',
'common.exitFullscreen': '退出全屏',
'common.continue': '继续',
'common.current': '当前',
'common.disabled': '已禁用',
'common.enabled': '已启用',
'common.enterSelect': '回车选择',
'common.invalid': '无效',
'common.loading': '加载中...',
'common.save': '保存',
'common.navigate': '↑↓ 导航',
'common.next': '下一步',
'common.noResults': '无结果',
'common.previous': '上一步',
'common.refresh': '刷新',
'common.search': '搜索',
'common.valid': '有效',
'common.clients': (v) => `${v?.count ?? 0} 个客户端`,
'agent.count': (v) => `${v?.count ?? 0} 个智能体`,
'askUser.submit': '提交',
'askUser.ignore': '忽略',
'askUser.multiHint': '可多选',
'askUser.progress': (v) => `${v?.current ?? 0}/${v?.total ?? 0} 个问题`,
'askUser.selectAnswer': '选择一个答案',
'askUser.typePlaceholder': '输入内容...',
'copy.failedFallback': '复制到剪贴板失败',
'copy.inlineLatexMissing': '最后一条 AI 输出中没有匹配的行内 LaTeX 表达式。',
'copy.latexMissing': '最后一条 AI 输出中没有匹配的 LaTeX 块。',
'copy.noOutput': '历史记录中没有可复制的输出',
'copy.noText': '最后一条 AI 输出没有可复制的文本。',
'copy.codeMissing': '最后一条 AI 输出中没有匹配的代码块。',
'copy.outputCopied': '已复制最后一条输出到剪贴板',
'copy.toClipboard': (v) => `${v?.label ?? '内容'} 已复制到剪贴板`,
'code.copy': '复制',
'code.copied': '已复制!',
'echartsChart.defaultTitle': '图表加载中',
'echartsChart.noData': '暂无数据',
'echartsChart.tableNotice': (v) => {
const omittedRows = Number(v?.omittedRows ?? 0);
const omittedColumns = Number(v?.omittedColumns ?? 0);
if (omittedRows > 0 && omittedColumns > 0) {
return `显示 ${v?.visibleRows ?? 0}/${v?.totalRows ?? 0} 行,${v?.visibleColumns ?? 0}/${v?.totalColumns ?? 0}`;
}
if (omittedColumns > 0) {
return `显示 ${v?.visibleColumns ?? 0}/${v?.totalColumns ?? 0}`;
}
return `显示 ${v?.visibleRows ?? 0}/${v?.totalRows ?? 0}`;
},
'echartsChart.rendering': '正在渲染图表',
'echartsChart.runtimeUnavailable': '图表运行时不可用。',
'echartsChart.renderFailed': '图表渲染失败。',
'echartsChart.viewMode': '视图模式',
'echartsChart.showChart': '显示图表',
'echartsChart.showData': '显示数据',
'echartsChart.chart': '图表',
'echartsChart.data': '数据',
'markdownTable.blank': '(空白)',
'markdownTable.column': (v) => `${v?.index ?? ''}`,
'markdownTable.rows': (v) => `${v?.count ?? 0}`,
'markdownTable.rowsFiltered': (v) => `${v?.visible ?? 0}/${v?.total ?? 0}`,
'markdownTable.hint': '点击表头排序,点击 ▾ 打开筛选。',
'markdownTable.filtersActive': (v) => `${v?.count ?? 0} 个筛选`,
'markdownTable.cellsSelected': (v) => `${v?.count ?? 0} 个单元格已选中`,
'markdownTable.copyTsv': '复制 TSV',
'markdownTable.copyVisible': '快捷复制',
'markdownTable.freezeFirstColumn': '冻结首列',
'markdownTable.unfreezeFirstColumn': '取消冻结首列',
'markdownTable.hideColumn': '隐藏列',
'markdownTable.showHiddenColumns': (v) => `显示 ${v?.count ?? 0} 个隐藏列`,
'markdownTable.moveColumn': (v) => `移动 ${v?.column ?? ''}`,
'markdownTable.resizeColumn': (v) => `调整 ${v?.column ?? ''} 列宽`,
'markdownTable.rowDetails': '详情',
'markdownTable.rowDetailsAria': (v) => `查看第 ${v?.index ?? ''} 行详情`,
'markdownTable.closeRowDetailsAria': (v) => `收起第 ${v?.index ?? ''} 行详情`,
'markdownTable.detailsHeader': '单行详情',
'markdownTable.actions': '操作',
'markdownTable.sortByColumn': (v) => `${v?.column ?? ''} 排序`,
'markdownTable.sortByColumnAsc': (v) => `${v?.column ?? ''} 已升序排序`,
'markdownTable.sortByColumnDesc': (v) => `${v?.column ?? ''} 已降序排序`,
'markdownTable.filterColumn': (v) => `筛选 ${v?.column ?? ''}`,
'markdownTable.empty': '此表格没有数据。',
'markdownTable.emptyFiltered': '没有符合筛选条件的行。',
'markdownTable.sort.asc': '升序排序',
'markdownTable.sort.desc': '降序排序',
'markdownTable.sort.clear': '清除排序',
'markdownTable.filter.searchPlaceholder': '搜索筛选值',
'markdownTable.filter.searchAria': (v) => `搜索 ${v?.column ?? ''}`,
'markdownTable.filter.selectVisible': '全选当前结果',
'markdownTable.filter.optionLimit': (v) =>
`已显示前 ${v?.count ?? 0} 项,请搜索缩小范围`,
'markdownTable.filter.noOptions': '没有匹配项',
'markdownTable.filter.custom': '自定义筛选',
'markdownTable.filter.numberAria': (v) => `数字筛选 ${v?.column ?? ''}`,
'markdownTable.filter.textAria': (v) => `文本筛选 ${v?.column ?? ''}`,
'markdownTable.filter.numberPlaceholder': '数值',
'markdownTable.filter.toPlaceholder': '到',
'markdownTable.filter.textPlaceholder': '输入筛选条件',
'markdownTable.filter.reset': '重置',
'markdownTable.filter.cancel': '取消',
'markdownTable.filter.confirm': '确认',
'markdownTable.filter.text.contains': '包含',
'markdownTable.filter.text.equals': '等于',
'markdownTable.filter.text.notEquals': '不等于',
'markdownTable.filter.text.startsWith': '开头是',
'markdownTable.filter.text.endsWith': '结尾是',
'markdownTable.filter.number.gt': '大于',
'markdownTable.filter.number.gte': '大于等于',
'markdownTable.filter.number.lt': '小于',
'markdownTable.filter.number.lte': '小于等于',
'markdownTable.filter.number.between': '区间',
'mermaid.rendering': '正在渲染图表...',
'mermaid.viewCode': '</>',
'mermaid.viewDiagram': '⊞',
'contextUsage.active': '已激活',
'contextUsage.autocompactBuffer': '自动压缩缓冲区',
'contextUsage.bodyLoaded': '已加载正文',
'contextUsage.builtinTools': '内置工具',
'contextUsage.contextWindow': '上下文窗口',
'contextUsage.detailHint': '运行 /context detail 查看逐项明细。',
'contextUsage.estimatedOverhead': '预估的对话前开销',
'contextUsage.free': '空闲',
'contextUsage.memoryFiles': 'Memory 文件',
'contextUsage.messages': '消息',
'contextUsage.mcpTools': 'MCP 工具',
'contextUsage.model': '模型',
'contextUsage.noSession':
'当前还没有会话。请先发送第一条消息,再查看上下文使用情况。',
'contextUsage.noApiResponse':
'尚无 API 响应。发送一条消息后可查看实际使用量。',
'contextUsage.overLimit':
'上下文已超过限制!请使用 /compress 或 /clear 减少占用。',
'contextUsage.skills': 'Skills',
'contextUsage.systemPrompt': '系统提示词',
'contextUsage.title': '上下文使用情况',
'contextUsage.tokens': 'tokens',
'contextUsage.usageByCategory': '按类别统计',
'contextUsage.used': '已用',
'daemon.title': 'Daemon 状态',
'daemon.details.loading': '正在加载诊断信息...',
'daemon.details.failed': '诊断信息加载失败。',
'daemon.refresh': '刷新',
'daemon.loading': '正在加载 Daemon 状态...',
'daemon.loadFailed': '加载 Daemon 状态失败',
'daemon.updatedAt': (v) => `更新于 ${v?.time ?? ''}`,
'daemon.none': '无',
'daemon.level.ok': '正常',
'daemon.level.warning': '警告',
'daemon.level.error': '错误',
'daemon.level.unavailable': '不可用',
'daemon.issues.title': '问题',
'daemon.overview.title': 'Daemon',
'daemon.overview.version': '版本',
'daemon.overview.pid': 'PID',
'daemon.overview.mode': '模式',
'daemon.overview.uptime': '运行时长',
'daemon.overview.workspace': '工作区',
'daemon.runtime.title': '运行时',
'daemon.runtime.activeSessions': '活跃会话',
'daemon.runtime.activePrompts': '执行中的 prompt',
'daemon.runtime.idle': '空闲时长',
'daemon.runtime.noActivity': '暂无活动',
'daemon.runtime.pendingPermissions': '待审批权限',
'daemon.runtime.permissionPolicy': '权限策略',
'daemon.runtime.channel': 'ACP 通道',
'daemon.runtime.channelLive': '在线',
'daemon.runtime.channelDown': '离线',
'daemon.runtime.startingUp': '运行时启动中...',
'daemon.runtime.startFailed': '运行时启动失败',
'daemon.runtime.channelWorker': '通道 Worker',
'daemon.runtime.channelWorkerRestarts': 'Worker 重启次数',
'daemon.runtime.memory': '内存 (RSS / 堆)',
'daemon.transport.title': '传输',
'daemon.transport.restSse': 'REST SSE 流',
'daemon.transport.acpDisabled': 'ACP 传输未启用',
'daemon.transport.acpConnections': 'ACP 连接',
'daemon.transport.acpStreams': 'ACP 流 (会话/SSE/WS)',
'daemon.transport.pendingRequests': '待处理客户端请求',
'daemon.transport.rateLimitRejected': '限流拒绝数',
'daemon.security.title': '安全',
'daemon.security.token': 'Bearer 令牌',
'daemon.security.requireAuth': '强制鉴权',
'daemon.security.loopback': '回环绑定',
'daemon.security.allowOrigin': '允许来源',
'daemon.security.shell': '会话 Shell 命令',
'daemon.security.configured': '已配置',
'daemon.security.notConfigured': '未配置',
'daemon.limits.title': '限制',
'daemon.limits.unlimited': '无限制',
'daemon.limits.maxSessions': '最大会话数',
'daemon.limits.maxPendingPrompts': '每会话最大待处理 prompt 数',
'daemon.limits.maxConnections': '最大监听连接数',
'daemon.limits.eventRing': '事件环大小',
'daemon.limits.promptDeadline': 'Prompt 截止时间',
'daemon.limits.sessionIdle': '会话空闲超时',
'daemon.capabilities.title': '能力',
'daemon.capabilities.titleCount': (v) => `能力 (${v?.count ?? 0})`,
'daemon.full.sessions.title': '会话',
'daemon.full.sessions.empty': '无活跃会话',
'daemon.full.session.pendingPrompts': (v) =>
`${v?.count ?? 0} 个待处理 prompt`,
'daemon.full.session.pendingPermissions': (v) =>
`${v?.count ?? 0} 个待审批权限`,
'daemon.full.session.prompting': '执行中',
'daemon.full.workspace.title': '工作区诊断',
'daemon.full.workspace.empty': '未上报工作区诊断',
'daemon.full.auth.title': '认证',
'daemon.full.auth.providers': '设备码登录提供方',
'daemon.full.auth.pending': '进行中的设备码登录',
'daemon.full.acp.title': 'ACP 连接',
'daemon.tab.overview': '概览',
'daemon.tab.usage': '用量',
'daemon.tab.metrics': '指标',
'daemon.tab.diagnostics': '诊断',
'daemon.charts.title': '指标图表',
'daemon.charts.empty': '正在采集指标…首次采样后显示图表。',
'daemon.charts.concurrency': '并发',
'daemon.charts.activePrompts': '执行中任务',
'daemon.charts.activeSessions': '会话',
'daemon.charts.requests': '请求数',
'daemon.charts.reqTotal': '总数',
'daemon.charts.reqErrors': '错误',
'daemon.charts.apiLatency': 'API 耗时',
'daemon.charts.promptLatency': 'Prompt 延迟',
'daemon.charts.queueWait': '排队等待',
'daemon.charts.promptDuration': '端到端',
'daemon.charts.eventLoop': '事件循环延迟',
'daemon.charts.eventLoopLag': '延迟 p99',
'daemon.charts.queuedPrompts': '排队中',
'daemon.charts.reqRejected': '限流拒绝',
'daemon.charts.llmLatency': 'LLM 耗时',
'daemon.charts.cpu': 'CPU',
'daemon.charts.pipe': 'IPC 管道',
'daemon.charts.pipeIn': '接收',
'daemon.charts.pipeOut': '发送',
'daemon.charts.connections': '连接数',
'daemon.charts.cpuDaemon': 'Daemon',
'daemon.charts.cpuChild': '子进程',
'daemon.charts.rssDaemon': 'Daemon RSS',
'daemon.charts.rssChild': '子进程 RSS',
'daemon.charts.memory': '内存',
'daemon.charts.heap': '堆',
'daemon.charts.tokens': 'Token 消耗',
'daemon.charts.tokensIn': '输入',
'daemon.charts.tokensOut': '输出',
'daemon.charts.peak': '峰值',
'daemon.usage.today': '今日',
'daemon.usage.period7d': '7天',
'daemon.usage.period30d': '30天',
'daemon.usage.rangeWeek': '近 7 天',
'daemon.usage.rangeMonth': '近 30 天',
'daemon.usage.rangeGroup': '统计周期',
'daemon.usage.tokensConsumed': 'tokens 消耗',
'daemon.usage.sessions': '会话',
'daemon.usage.requests': '请求',
'daemon.usage.tools': '工具',
'daemon.usage.changes': '改动',
'daemon.usage.breakdownTitle': 'Token 拆分',
'daemon.usage.inputTokens': '输入 tokens',
'daemon.usage.inputHint': '请求 + 缓存读取',
'daemon.usage.outputTokens': '输出 tokens',
'daemon.usage.outputHint': '响应 + 推理',
'daemon.usage.cacheRead': '缓存读取',
'daemon.usage.cacheHint': '缓存读取占比',
'daemon.usage.heatmapTitle': 'Token 热力图',
'daemon.usage.heatmapSub': (v) =>
`最近 ${v?.months ?? 12} 个月 · 每日 token 汇总`,
'daemon.usage.low': '少',
'daemon.usage.high': '多',
'daemon.usage.dowMon': '一',
'daemon.usage.dowWed': '三',
'daemon.usage.dowFri': '五',
'daemon.usage.empty': '暂无 token 使用记录。',
'daemon.usage.loading': '加载用量中…',
'daemon.usage.failed': '加载用量失败',
'daemon.usage.cellTokens': (v) =>
`${v?.date ?? ''} · Tokens: ${v?.tokens ?? '0'} · Cache: ${v?.cache ?? 0}%`,
'daemon.usage.rangeWordToday': '今日',
'daemon.usage.rangeWordWeek': '7 天',
'daemon.usage.rangeWordMonth': '30 天',
'daemon.usage.modelShareTitle': '模型份额',
'daemon.usage.modelShareSub': 'token 份额 · 浅绿表示缓存读取',
'daemon.usage.modelMeta': (v) =>
`${v?.tokens ?? '0'} tokens · 缓存 ${v?.cache ?? 0}%`,
'daemon.usage.skillTitle': '技能调用',
'daemon.usage.skillSub': '技能名 / 次数',
'daemon.usage.skillName': '技能名',
'daemon.usage.skillCount': '次数',
'daemon.usage.dailyTokensTitle': 'Tokens',
'daemon.usage.dailyTokensSub': '每日 token 总量',
'daemon.usage.dailySessionsTitle': '会话',
'daemon.usage.dailySessionsSub': '每日活跃会话数',
'delete.cannotCurrent': '无法删除当前活动会话。',
'delete.action': '删除',
'delete.deleted': '会话已删除。',
'delete.deletedCount': (v) => `已删除 ${v?.count ?? 0} 个会话。`,
'delete.deleting': '删除中...',
'delete.failed': (v) => `删除会话失败。${v?.reason ? ` ${v.reason}` : ''}`,
'delete.footer': '↑↓ 导航 · Space 选择 · Enter 删除 · Esc 取消',
'delete.noMatch': (v) => `没有匹配 "${v?.query ?? ''}" 的会话`,
'delete.none': '没有可删除的会话',
'delete.allFailed': (v) =>
`删除 ${v?.count ?? 0} 个会话失败: ${v?.reason ?? '未知错误'}`,
'delete.nonRemoved': '没有会话被删除。',
'delete.notFound': '会话未找到,可能已被删除。',
'delete.partialFail': (v) =>
`已删除 ${v?.removed ?? 0} 个,${v?.failed ?? 0} 个失败: ${v?.detail ?? '未知错误'}`,
'delete.matches': (v) => `${v?.count ?? 0} 个匹配`,
'delete.pressSearch': '按 / 搜索Space 选择Enter 删除',
'delete.selected': (v) => `已选 ${v?.count ?? 0}`,
'delete.title': '删除会话',
'time.justNow': '刚刚',
'time.minutesAgo': (v) => `${v?.count ?? 0} 分钟前`,
'time.hoursAgo': (v) => `${v?.count ?? 0} 小时前`,
'time.daysAgo': (v) => `${v?.count ?? 0} 天前`,
'dialog.footer.close': 'Esc 关闭',
'dialog.footer.confirmCancel': 'Enter 确认 · Esc 取消',
'release.cannotCurrent': '不能释放当前活动会话。',
'release.action': '释放',
'release.released': '会话已释放。',
'release.failed': (v) => `释放会话失败。${v?.reason ? ` ${v.reason}` : ''}`,
'release.footer': '↑↓ 导航 · Enter 释放 · Esc 取消',
'release.inactive': '只有活跃的 live session 才能释放。',
'release.inactiveBadge': '非活跃',
'release.noMatch': (v) => `没有匹配 "${v?.query ?? ''}" 的会话`,
'release.matches': (v) => `${v?.count ?? 0} 个匹配`,
'release.none': '没有可释放的 live session',
'release.pressSearch': '按 / 搜索Enter 释放选中的 live session',
'release.releasing': '释放中...',
'release.title': '释放会话',
'dialog.footer.menu': 'Esc 返回菜单',
'dialog.footer.mcpServers': '↑↓ 导航 · Enter 查看详情 · r 刷新 · Esc 关闭',
'dialog.footer.mcpSelect': '↑↓ 导航 · Enter 选择 · Esc 返回',
'dialog.footer.modelFast':
'↑↓ 导航 · / 搜索 · c 自定义 · Enter 设置 fast model · Esc 取消',
'dialog.footer.navSelectCancel': '↑↓ 导航 · Enter 选择 · Esc 取消',
'dialog.footer.navSelectClose': '↑↓ 导航 · Enter 选择 · Esc 关闭',
'dialog.footer.navSelectMenu': '↑↓ 导航 · Enter 选择 · Esc 返回菜单',
'dialog.footer.navOpenClose': '↑↓ 导航 · Enter 打开 · Esc 关闭',
'dialog.footer.navOpenMenu': '↑↓ 导航 · Enter 打开 · Esc 返回菜单',
'dialog.footer.back': 'Esc 返回',
'dialog.footer.backClose': 'Esc 关闭',
'dialog.footer.saveClose': '↑↓ 切换输入框 · ⌘/Ctrl+Enter 保存 · Esc 关闭',
'dialog.footer.saveMenu': '↑↓ 切换输入框 · ⌘/Ctrl+Enter 保存 · Esc 返回菜单',
'dialog.footer.search': '输入搜索 · Enter 确认 · Esc 清空',
'dialog.footer.select': 'Enter 选择',
'editor.escClearHint': '再按一次 Esc 清空',
'editor.hintCommands': '命令',
'editor.hintFiles': '文件',
'editor.hintNext': '下一条',
'editor.hintPrev': '上一条',
'editor.hintSearch': '搜索',
'editor.noHistory': '没有匹配的历史记录',
'editor.placeholder': '输入消息或 @ 文件路径',
'editor.shellPlaceholder': '请输入终端命令',
'editor.send': '发送消息',
'editor.connectionDisconnected': '连接已中断,请在恢复后重试。',
'editor.sessionLoading': '会话正在加载,请稍后再发送。',
'editor.processing': '处理中。新消息会进入队列。',
'editor.searchHint': 'ctrl+r 下一条 · tab 采纳 · enter 发送 · esc 取消',
'editor.searchLabel': '历史搜索:',
'editor.searchPlaceholder': '输入以搜索…',
'quickActions.open': '更多操作',
'quickActions.title': '更多操作',
'quickActions.mcp': 'MCP',
'quickActions.context': '上下文',
'quickActions.status': '运行状态',
'quickActions.stats': '会话统计',
'quickActions.memory': '记忆管理',
'quickActions.extensions': '扩展',
'quickActions.skills': '技能详情',
'quickActions.tools': '工具详情',
'quickActions.agents': '智能体',
'quickActions.help': '帮助',
'quickActions.theme': '设置主题',
'quickActions.auth': '认证',
'quickActions.settings': '设置',
'quickActions.new': '新建会话',
'quickActions.resume': '切换会话',
'quickActions.delete': '删除会话',
'quickActions.branch': '复制会话',
'quickActions.rewind': '回退会话',
'quickActions.historyQuestion': '历史提问',
'quickActions.recap': '生成摘要',
'quickActions.copy': '复制输出',
'quickActions.shellMode': 'Shell模式',
'quickActions.exitShellMode': '退出Shell',
'quickActions.setGoal': '设置目标',
'session.missing': '当前会话不存在',
'session.new': '新建会话',
// 定时任务页面
'scheduledTasks.title': '定时任务',
'scheduledTasks.subtitle': '按计划自动执行任务,也可随时手动触发。',
'scheduledTasks.loading': '加载中…',
'scheduledTasks.count': (v) => `${v?.count ?? 0} 个任务`,
'scheduledTasks.refresh': '刷新',
'scheduledTasks.new': '新建定时任务',
'scheduledTasks.createViaChat': '通过聊天创建',
'scheduledTasks.chatStarter': '帮我创建一个长期保留的定时任务,我想:',
'scheduledTasks.name': '名称',
'scheduledTasks.namePlaceholder': '可选 —— 默认取提示词',
'scheduledTasks.prompt': '提示词',
'scheduledTasks.promptPlaceholder': '这个任务要做什么?',
'scheduledTasks.frequency': '频率',
'scheduledTasks.freq.daily': '每天',
'scheduledTasks.freq.weekdays': '工作日',
'scheduledTasks.freq.weekly': '每周',
'scheduledTasks.freq.hourly': '每小时',
'scheduledTasks.freq.minutes': '每 N 分钟',
'scheduledTasks.freq.custom': '自定义cron',
'scheduledTasks.time': '时间',
'scheduledTasks.weekday': '星期',
'scheduledTasks.interval': '分钟',
'scheduledTasks.cron': 'Cron 表达式',
'scheduledTasks.weekdayNames': '周日,周一,周二,周三,周四,周五,周六',
'scheduledTasks.human.daily': (v) => `每天 ${v?.time ?? ''}`,
'scheduledTasks.human.weekdays': (v) => `工作日 ${v?.time ?? ''}`,
'scheduledTasks.human.weekly': (v) => `${v?.day ?? ''} ${v?.time ?? ''}`,
'scheduledTasks.human.hourly': (v) => `每小时 第 ${v?.min ?? '00'}`,
'scheduledTasks.human.everyMinutes': (v) => `${v?.n ?? ''} 分钟`,
'scheduledTasks.never': '尚未运行',
'scheduledTasks.repeats': '重复',
'scheduledTasks.runsOnce': '仅一次',
'scheduledTasks.lastFired': (v) => `上次运行:${v?.when ?? ''}`,
'scheduledTasks.runNow': '立即运行',
'scheduledTasks.enable': '启用',
'scheduledTasks.disable': '停用',
'scheduledTasks.delete': '删除',
'scheduledTasks.deleteConfirm': (v) =>
`确定删除定时任务「${v?.name ?? ''}」?`,
'scheduledTasks.empty': '还没有定时任务,创建一个开始吧。',
'scheduledTasks.create': '创建',
'scheduledTasks.creating': '创建中…',
'scheduledTasks.cancel': '取消',
'scheduledTasks.error.invalidSchedule': '计划无效',
'scheduledTasks.error.emptyPrompt': '提示词不能为空',
'scheduledTasks.error.toggleFailed': '更新任务失败',
'scheduledTasks.error.deleteFailed': '删除任务失败',
'scheduledTasks.edit': '编辑',
'scheduledTasks.editTitle': '编辑定时任务',
'scheduledTasks.save': '保存',
'scheduledTasks.saving': '保存中…',
'scheduledTasks.runHistory': (v) => `运行记录(${v?.count ?? 0}`,
'scheduledTasks.viewHistory': (v) => `查看对话(${v?.count ?? 0}`,
'scheduledTasks.viewHistoryEmpty': '查看对话',
'scheduledTasks.viewHistoryHint': '打开该任务的会话查看运行详情',
'scheduledTasks.runKind.catchUp': '补跑',
'scheduledTasks.runKind.manual': '手动',
'scheduledTasks.error.runFailed': '记录运行失败',
'scheduledTasks.error.oneShotConsumedButFailed':
'任务已删除,但提示词未能送达——它没有运行。请重新创建后重试。',
'scheduledTasks.dueNow': '即将运行',
'scheduledTasks.nextRunTooltip': (v) => `下次运行:${v?.when ?? ''}`,
'scheduledTasks.dur.d': '天',
'scheduledTasks.dur.h': '小时',
'scheduledTasks.dur.m': '分',
'scheduledTasks.dur.s': '秒',
'scheduledTasks.runMode': '运行模式',
'scheduledTasks.runMode.shared': '共享会话',
'scheduledTasks.runMode.isolated': '隔离(每次运行新建会话)',
'scheduledTasks.runMode.shared.hint': '所有运行记录累积在同一个会话中。',
'scheduledTasks.runMode.isolated.hint': '每次运行获得独立的会话上下文。',
'sidebar.label': '工作区侧边栏',
'sidebar.toggleMenu': '切换菜单',
'sidebar.newChat': '新对话',
'sidebar.project': '项目',
'sidebar.projectFallback': '项目',
'sidebar.sessionsOverview': '会话总览',
'sidebar.splitView': '分屏',
'sidebar.settings': '设置',
'sidebar.daemonStatus': 'Daemon 状态',
'sidebar.scheduledTasks': '定时任务',
'sidebar.collapse': '收起',
'sidebar.expand': '展开',
'sidebar.collapseProject': '收起项目',
'sidebar.expandProject': '展开项目',
'sidebar.search': '搜索会话',
'sidebar.searchPlaceholder': '搜索会话',
'sidebar.searchEmpty': '没有匹配的会话。',
'sidebar.rename': '重命名',
'sidebar.renameCurrentOnly': '暂仅支持重命名当前会话',
'sidebar.export': '导出对话记录',
'sidebar.exportFailed': '导出会话失败',
'sidebar.delete': '删除',
'sidebar.archive': '归档',
'sidebar.unarchive': '恢复',
'sidebar.moreActions': '更多操作',
'sidebar.archiveCurrentDisabled': '不能归档当前会话',
'sidebar.archivedTitle': '已归档',
'sidebar.archivedEmpty': '没有已归档的会话。',
'sidebar.archiveFailed': '归档会话失败',
'sidebar.unarchiveFailed': '恢复会话失败',
'sidebar.loadingSessions': '正在加载会话...',
'sidebar.loadFailed': '会话加载失败,点击重试。',
'sidebar.renameFailed': '重命名会话失败',
'sidebar.deleteFailed': '删除会话失败',
'sidebar.newSessionFailed': '创建新对话失败',
'sidebar.switchFailed': '切换会话失败',
'sidebar.currentDeleteDisabled': '不能删除当前会话',
'sidebar.deleteConfirmDescription': (v) =>
`确定删除“${v?.name ?? ''}”吗?删除后不可恢复。`,
'sidebar.clients': (v) => `${v?.count ?? 0} 个客户端`,
'sidebar.running': '运行中',
'sidebar.completedUnread': '刚完成',
'sidebar.pin': '置顶',
'sidebar.unpin': '取消置顶',
'sidebar.sessionGroup': '分组',
'sidebar.groupFilter': '会话分组',
'sidebar.groupAll': '全部',
'sidebar.groupPinned': '已置顶',
'sidebar.groupUngrouped': '未分组',
'sidebar.groupRecent': '最近',
'sidebar.groupCreate': '新建分组',
'sidebar.groupRename': '重命名分组',
'sidebar.groupDelete': '删除分组',
'sidebar.groupColor': '分组颜色',
'sidebar.groupNamePrompt': '分组名称',
'sidebar.groupDeleteConfirm': (v) => `确定删除分组“${v?.name ?? ''}”吗?`,
'sidebar.groupsLoadFailed': '加载会话分组失败',
'sidebar.groupCreateFailed': '创建分组失败',
'sidebar.groupAssignFailedAfterCreate': '分组已创建,但移动会话失败',
'sidebar.groupUpdateFailed': '更新分组失败',
'sidebar.groupDeleteFailed': '删除分组失败',
'sidebar.organizationFailed': '更新会话组织失败',
'sidebar.groupColor.red': '红色',
'sidebar.groupColor.orange': '橙色',
'sidebar.groupColor.yellow': '黄色',
'sidebar.groupColor.green': '绿色',
'sidebar.groupColor.blue': '蓝色',
'sidebar.groupColor.purple': '紫色',
'quickKeys.cursor': '移动光标',
'quickKeys.escape': '取消运行',
'quickKeys.history': '切换历史',
'quickKeys.retry': '重试失败请求',
'quickKeys.searchHistory': '搜索历史',
'quickKeys.tab': '接受补全',
'error.unsupportedTheme':
'不支持该主题。请使用 /theme light 或 /theme dark。',
'queue.delete': '删除',
'queue.edit': '编辑',
'queue.insert': '插入',
'queue.cleared': '队列已清空。',
'queue.deleteTip': '移出队列',
'queue.editTip': '移出队列并将内容放回输入框',
'queue.insertTip': '将信息插入当前会话,下次模型调用生效。',
'queue.inserted': '已插入,下次模型调用生效。',
'queue.insertCommandDisabled': '命令无法插入当前回合。',
'queue.submitting': '提交中...',
'queue.editing': '编辑中...',
'queue.removing': '处理中...',
'queue.submittingDisabled': '排队消息正在提交中...',
'queue.commandBlocked': '当前回合运行时Slash 命令不能进入排队。',
'queue.shellBlocked': '当前回合运行时Shell 命令不能进入排队。',
'queue.queueFailed': '排队消息失败',
'queue.insertFailed': '插入排队消息失败',
'queue.deleteFailed': '移出队列失败',
'queue.editFailed': '编辑排队消息失败',
'queue.footer': '按 ↑ 编辑最后一条排队消息 · Esc 清空队列',
'queue.imageCount': (v) => `+${v?.count ?? 0} 张图片)`,
'queue.more': (v) => `...(还有 ${v?.count ?? 0} 条)`,
'midTurn.inserted': (v) => `已插入消息:${v?.message ?? ''}`,
'help.builtIn': '内置命令',
'help.commandCount': (v) => `${v?.count ?? 0} 个命令`,
'help.commandMeta.builtIn': '内置',
'help.commandMeta.custom': '自定义',
'help.commandMeta.subcommands': (v) => `${v?.count ?? 0} 个子命令`,
'help.commandsIntro': '浏览内置命令:',
'help.customGroup': '自定义、skills、plugins、MCP',
'help.customIntro': '浏览自定义、skill、plugin 和 MCP 命令:',
'help.empty': '当前没有可用命令。',
'help.emptyCustom': '当前没有可用的自定义命令。',
'help.footer': 'Tab/Shift+Tab 切换标签 · ↑/↓ 或 PgUp/PgDn 滚动 · Esc 关闭',
'help.intro':
'Qwen Code 可以理解代码库,在你的许可下修改文件,并直接执行命令。',
'help.section.shortcuts': '快捷键',
'help.search': '搜索命令',
'help.shortcut.addContext': '添加文件或目录作为上下文',
'help.shortcut.altWords': '按词跳转',
'help.shortcut.clear': '清屏',
'help.shortcut.commandMenu': '打开命令菜单',
'help.shortcut.completion': '接受补全或切换帮助标签',
'help.shortcut.history': '切换历史 prompt 或滚动列表',
'help.shortcut.searchHistory': '搜索历史 prompt',
'help.shortcut.newline': '插入换行',
'help.shortcut.pasteImages': '粘贴图片',
'help.shortcut.shell': '运行 shell 命令',
'help.shortcut.togglePanel': '切换此面板',
'help.shortcut.retry': '重试上次请求',
'help.shortcut.compact': '切换紧凑模式',
'retry.hint': '按 Ctrl+Y 重试或点击重试',
'retry.none': '没有可重试的失败请求。',
'branch.failed': '分支会话失败。',
'branch.success': (v) =>
`已复制会话,新会话名称为: "${v?.name ?? ''}",当前已切换到新的会话。`,
'fork.empty': '请提供任务指令。用法:/fork <指令>',
'fork.failed': (v) => `启动后台智能体失败:${v?.reason ?? ''}`,
'fork.notStarted': '后台智能体未启动。',
'fork.started': (v) =>
`已启动后台智能体:"${v?.name ?? ''}",可在后台任务中查看。`,
'command.hidden': '该命令不可用。',
'help.shortcut.approvals': '切换审批模式',
'help.shortcut.cancel': '关闭弹窗或取消操作',
'bug.failed': '加载系统信息失败,无法提交 Bug 报告。',
'bug.popupBlocked': '弹窗被拦截,请允许弹窗后重试。',
'bug.submitted': 'Bug 报告已在新标签页中打开。',
'clear.blocked': '流式输出中无法清屏 — 先按 Esc 取消。',
'error.unknown': '未知错误',
'error.modelStreamInterrupted': '模型响应流已中断,请重试。',
'shell.command': 'Shell 命令',
'compact.enabled': '紧凑模式已开启',
'compact.disabled': '紧凑模式已关闭',
'compact.hint': '按 Ctrl+O 显示完整工具输出',
'compact.saveFailed': '保存紧凑模式失败',
'help.subcommands': '子命令',
'help.tab.commands': '内置命令',
'help.tab.custom': '自定义命令',
'help.tab.general': '快捷键',
'help.title': '帮助',
'slash.category.custom': '自定义',
'slash.category.skill': 'Skill',
'slash.category.system': '系统',
'language.changed': (v) => `UI 语言已切换为 ${v?.language ?? ''}`,
'language.current': (v) => `当前 UI 语言:${v?.language ?? ''}`,
'language.invalid': '语言无效。可用值en, zh-CN',
'language.options': '可用选项:',
'language.set': '设置 UI 语言',
'language.usage': '用法:/language ui [en|zh-CN]',
'localCommand.noSession':
'当前还没有会话。请先发送第一条消息,再使用这个命令。',
'local.agents': '管理智能体',
'local.bug': '提交错误报告',
'local.compress': '将上下文压缩为摘要',
'local.compressFast': '无需 AI 的快速上下文压缩',
'local.config': '通过点分路径键获取或设置配置项',
'local.diff': '显示工作区相对 HEAD 的改动统计',
'local.directory': '管理工作区目录',
'local.docs': '打开完整的 Qwen Code 文档',
'local.doctor': '运行安装和环境诊断',
'local.dream': '整合托管的自动记忆主题文件',
'local.effort': '设置推理模型的思考强度',
'local.export': '将当前会话历史导出到文件',
'local.forget': '从托管的自动记忆中移除匹配的条目',
'local.hooks': '管理 Qwen Code 钩子',
'local.importConfig': '从 Claude 配置导入 MCP 服务器',
'local.init': '分析项目并创建 QWEN.md 文件',
'local.insight': '根据聊天历史生成编程洞察',
'local.lsp': '显示 LSP 服务器状态',
'local.remember': '将持久记忆保存到记忆系统',
'local.summary': '生成项目摘要文件',
'local.workflows': '列出进行中和已完成的工作流运行',
'skilldesc.batch': '并行批量处理多个文件',
'skilldesc.dataviz': '图表与数据可视化设计指南',
'skilldesc.extensionCreator': '创建、测试和定制 Qwen Code 扩展',
'skilldesc.loop': '按计划或自定节奏循环运行提示词',
'skilldesc.newApp': '从零构建新应用的工作流',
'skilldesc.qcHelper': '解答 Qwen Code 使用相关问题',
'skilldesc.review': '审查代码变更的正确性、安全、质量与性能',
'skilldesc.simplify': '清理近期代码变更(复用与精简)',
'skilldesc.stuck': '诊断卡死或缓慢的 Qwen Code 会话',
'skilldesc.agentReproduceAlign':
'将已移植的 Codex/Claude Code 功能与原版对齐',
'skilldesc.agentReproduceFeature': '复现 Codex/Claude Code 的现有功能',
'skilldesc.autofix': '实现已批准的 issue 或处理 PR 审查反馈',
'skilldesc.bugfix': '按先复现流程修复 GitHub issue 中的 bug',
'skilldesc.codegraph': '通过图数据库和向量索引分析代码库',
'skilldesc.createIssue': '根据想法或 bug 描述起草并提交 GitHub issue',
'skilldesc.desktopPet': '为 Qwen Code 创建像素风桌面宠物',
'skilldesc.docsAuditAndRefresh': '对照代码库审计并刷新 docs/ 文档',
'skilldesc.docsUpdateFromDiff': '按本地 git diff 更新官方文档',
'skilldesc.e2eTesting': '运行 Qwen Code CLI 的端到端测试',
'skilldesc.featDev': '实现非平凡功能的端到端工作流',
'skilldesc.memoryLeakDebug': '用堆快照诊断 CLI 内存泄漏',
'skilldesc.openworkDesktopSync': '将 packages/desktop 与 openwork 逐提交同步',
'skilldesc.preparePr': '从当前分支准备 GitHub PR 标题和正文',
'skilldesc.qwenCodeClaw': '将 Qwen Code 用作代码理解智能体',
'skilldesc.structuredDebugging': '假设驱动的疑难 bug 调试方法',
'skilldesc.terminalCapture': '自动化终端 UI 截图测试',
'skilldesc.tmuxRealUserTesting': '用 tmux 做真实用户测试并保存日志',
'skilldesc.triage': '把关和审查 Qwen Code 的 issue 与 PR',
'local.approvalMode': '切换审批模式',
'local.auth': '连接 LLM provider',
'auth.title': '连接 Provider',
'auth.step.group': '类型',
'auth.step.provider': '供应商',
'auth.step.protocol': '协议',
'auth.step.baseUrl': 'Base URL',
'auth.step.apiKey': 'API Key',
'auth.step.models': '模型 ID',
'auth.step.advanced': '高级配置',
'auth.protocol.openai': 'OpenAI 兼容',
'auth.protocol.openaiDesc': '标准 OpenAI API 格式(最常用)',
'auth.protocol.anthropic': 'Anthropic 兼容',
'auth.protocol.anthropicDesc': 'Anthropic Messages API 格式',
'auth.protocol.gemini': 'Gemini 兼容',
'auth.protocol.geminiDesc': 'Google Gemini API 格式',
'auth.apiKeyRequired': 'API key 不能为空。',
'auth.baseUrlInvalid': 'Base URL 必须以 http:// 或 https:// 开头。',
'auth.baseUrlPrompt': '输入此协议的 API endpoint。',
'auth.baseUrlRequired': 'Base URL 不能为空。',
'auth.documentation': '文档',
'auth.modelsRequired': '模型 ID 不能为空。',
'auth.review': '确认',
'auth.reviewText': '以下 JSON 将保存到 settings.json',
'auth.save': '保存',
'auth.saving': '正在保存...',
'auth.termsTitle': '服务条款和隐私声明',
'auth.continue': '继续',
'auth.modelsPrompt': (v) =>
`输入以逗号分隔的模型 ID。例如${v?.modelIds ?? ''}`,
'auth.advanced.prompt': '可选:配置高级生成设置。',
'auth.advanced.thinking': '启用 thinking',
'auth.advanced.thinkingDesc': '允许模型在回复前进行扩展推理。',
'auth.advanced.modality': '启用多模态',
'auth.advanced.modalityDesc': '启用图片、视频等多模态输入能力。',
'auth.advanced.modalityImage': '图片',
'auth.advanced.modalityVideo': '视频',
'auth.advanced.modalityAudio': '音频',
'auth.advanced.modalityPdf': 'PDF',
'auth.advanced.contextWindow': '上下文窗口',
'auth.advanced.contextDesc':
'最大输入 token 数(留空则根据模型名称自动检测)。',
'auth.advanced.contextPlaceholder': '上下文窗口(可选)',
'local.btw': '快速问一个不影响主对话的侧边问题。用法:/btw <your question>',
'btw.empty': '请提供一个问题。用法:/btw <你的问题>',
'btw.emptyAnswer': '未收到回答。',
'btw.failed': '回答 btw 问题失败',
'btw.answering': '+ 正在回答...',
'btw.shortcuts.pending': '按 Escape、Ctrl+C 或 Ctrl+D 取消',
'btw.shortcuts.done': '按 Space、Enter 或 Escape 关闭',
'local.clear':
'以空上下文开始新会话;之前的会话会保留在磁盘上(可用 /resume 恢复)',
'local.context':
'显示上下文窗口使用情况明细。使用 "/context detail" 查看逐项明细',
'local.copy': '复制最后输出或代码片段',
'local.delete': '永久删除会话',
'local.release': '释放 live session',
'local.rewind': '回退当前会话',
'local.branch': '将当前对话分叉到新会话',
'local.fork': '基于当前对话启动后台智能体',
'local.help': '查看帮助和可用命令',
'local.language': '切换 UI 语言',
'local.mcp': '管理 MCP servers',
'local.memory': '管理 memory',
'local.model': '切换模型或设置 fast model',
'local.new': '开始新对话',
'local.plan': '进入 Plan 模式',
'local.goal': '设置目标并持续工作直到完成',
'local.recap': '生成会话摘要',
'recap.label': '回顾',
'recap.loading': '正在生成摘要...',
'recap.empty': '对话内容还不够,暂时无法生成摘要。',
'recap.failed': '生成摘要失败',
'rewind.action': '回退',
'rewind.confirm': '确认回退',
'rewind.empty': '当前会话没有可回退的快照。',
'rewind.failed': (v) => `回退会话失败:${v?.reason ?? ''}`,
'rewind.loading': '正在加载可回退的 prompt...',
'rewind.promptFallback': (v) => `Prompt ${v?.id ?? ''}`,
'rewind.rewinding': '回退中...',
'rewind.subtitle': '仅回退会话,不涉及文件。',
'rewind.title': '回退会话',
'rewind.turn': (v) => `${v?.turn ?? 0} 个 prompt`,
'local.rename': '重命名当前会话',
'rename.empty':
'请输入会话名称,例如 /rename 项目调试,或使用 /rename --auto。',
'rename.success': (v) => `会话已重命名为 ${v?.name ?? ''}`,
'local.reset': '重置当前对话',
'local.resume': '恢复历史会话',
'local.skills': '查看可用 skills',
'local.stats': '查看会话统计',
'local.tasks': '查看后台任务',
'local.status': '查看版本信息',
'local.theme': '切换主题',
'local.settings': '查看和编辑设置',
'local.schedule': '管理定时任务',
'local.extensions': '管理扩展。用法: /extensions manage|install <source>',
'extensions.label': '扩展',
'extensions.action.failed': (v) =>
`扩展操作失败${v?.name ? `${v.name}` : v?.source ? `${v.source}` : ''}${
v?.error ?? '未知错误'
}`,
'extensions.commands.refreshFailed': '刷新扩展命令失败。',
'extensions.install.failed': (v) =>
`安装扩展失败${v?.source ? `${v.source}` : ''}${
v?.error ?? '未知错误'
}`,
'extensions.manage.agents': '智能体:',
'extensions.manage.checkingUpdates': '正在检查更新...',
'extensions.manage.commands': '命令:',
'extensions.manage.contextFiles': '上下文文件:',
'extensions.manage.count': (v) => `已安装 ${v?.count ?? 0} 个扩展`,
'extensions.manage.detailsTitle': '扩展详情',
'extensions.manage.disable': '禁用扩展',
'extensions.manage.disabled': (v) => `扩展 "${v?.name ?? '扩展'}" 已禁用。`,
'extensions.manage.empty': '未安装扩展。',
'extensions.manage.enable': '启用扩展',
'extensions.manage.enabled': (v) => `扩展 "${v?.name ?? '扩展'}" 已启用。`,
'extensions.manage.footer.back': 'Esc 返回',
'extensions.manage.footer.confirm': 'Enter 确认 · Esc 取消',
'extensions.manage.footer.list': '↑↓ 导航 · Enter 选择 · r 刷新 · Esc 关闭',
'extensions.manage.footer.select': '↑↓ 导航 · Enter 选择 · Esc 返回',
'extensions.manage.loading': '正在加载扩展...',
'extensions.manage.mcpServers': 'MCP servers',
'extensions.manage.name': '名称:',
'extensions.manage.notUpdatable': '不可更新',
'extensions.manage.path': '路径:',
'extensions.manage.queued': (v) =>
`扩展 "${v?.name ?? '扩展'}" 的操作已提交。`,
'extensions.manage.refreshed': (v) =>
`已刷新 ${v?.refreshed ?? 0} 个 session${v?.failed ?? 0} 个失败。`,
'extensions.manage.settings': '设置:',
'extensions.manage.skills': 'Skills',
'extensions.manage.source': '来源:',
'extensions.manage.status': '状态:',
'extensions.manage.status.disabled': '已禁用',
'extensions.manage.status.enabled': '已启用',
'extensions.manage.title': '管理扩展',
'extensions.manage.unknownUpdate': '未知',
'extensions.manage.uninstalled': (v) =>
`扩展 "${v?.name ?? '扩展'}" 已卸载。`,
'extensions.manage.uninstallAction': '卸载扩展',
'extensions.manage.uninstallConfirm': (v) =>
`确定卸载扩展 "${v?.name ?? '扩展'}"`,
'extensions.manage.upToDate': '已是最新',
'extensions.manage.update': '更新扩展',
'extensions.manage.updateAvailable': '有可用更新',
'extensions.manage.updateError': '检查更新失败',
'extensions.manage.updated': (v) => `扩展 "${v?.name ?? '扩展'}" 已更新。`,
'extensions.manage.updatedWithVersion': (v) =>
`扩展 "${v?.name ?? '扩展'}" 已更新到 v${v?.version ?? ''}`,
'extensions.manage.version': '版本:',
'extensions.manage.viewDetails': '查看详情',
'extensions.install.installed': (v) => `扩展 "${v?.name ?? '扩展'}" 已安装。`,
'extensions.install.installedWithVersion': (v) =>
`扩展 "${v?.name ?? '扩展'}" v${v?.version ?? ''} 已安装。`,
'extensions.install.missingOptionValue': (v) =>
`${v?.option ?? '选项'} 缺少值`,
'extensions.install.requestFailed': '安装扩展失败',
'extensions.install.started': (v) =>
`正在从 "${v?.source ?? ''}" 安装扩展...`,
'extensions.install.unknownOption': (v) => `未知选项 ${v?.option ?? ''}`,
'extensions.install.usage': '用法: /extensions manage|install <source>',
'extensions.install.waitForSession': '等待会话连接后再安装扩展。',
'local.tools': '列出可用工具。用法: /tools [desc]',
'loadWarning.commands': '命令列表加载失败,斜杠命令可能不完整。',
'loadWarning.context': '会话上下文加载失败,当前模式可能不准确。',
'loadWarning.models': '模型列表加载失败,部分模型详情可能不可用。',
'mcp.action.auth': '认证',
'mcp.action.authHint': 'daemon 尚未暴露',
'mcp.action.authMessage': 'daemon serve 尚未暴露 MCP 认证能力。',
'mcp.action.clearAuth': '清空认证',
'mcp.action.disable': '禁用',
'mcp.action.done': (v) => `${v?.action ?? '操作'}完成。`,
'mcp.action.enable': '启用',
'mcp.action.enableMessage': 'daemon serve 尚未暴露 MCP 启用/禁用能力。',
'mcp.action.failed': (v) => `失败:${v?.error ?? ''}`,
'mcp.action.running': (v) => `${v?.action ?? '操作'}中...`,
'mcp.action.reauth': '重新认证',
'mcp.annotation.destructive': '破坏性',
'mcp.annotation.idempotent': '幂等',
'mcp.annotation.openWorld': '开放世界',
'mcp.annotation.readOnly': '只读',
'mcp.annotations': '注解',
'mcp.oauth.server': '服务器',
'mcp.oauth.starting': (v) =>
`正在为 MCP server '${v?.name ?? ''}' 启动 OAuth 认证...`,
'mcp.oauth.title': 'OAuth 认证',
'mcp.clientBudget': (v) =>
`${v?.count ?? 0}/${v?.budget ?? 0} 个客户端 · ${v?.mode ?? 'off'}`,
'mcp.command': '命令',
'mcp.description': '描述:',
'mcp.action.reconnect': '重新连接',
'mcp.action.restart': '重启',
'mcp.action.tools': '查看工具',
'mcp.action.toolsHint': 'Enter 查看',
'mcp.empty': '未配置 MCP 服务器。',
'mcp.emptyTools': '没有发现工具。',
'mcp.expand': '展开 MCP server',
'mcp.collapse': '收起 MCP server',
'mcp.inputSchema': '输入 schema',
'mcp.loadingStatus': '正在加载 MCP 状态...',
'mcp.loadingTools': '正在加载工具...',
'mcp.name': '名称',
'mcp.noDescription': '没有描述',
'mcp.noSchema': '没有输入 schema。',
'mcp.serverTool': '服务器工具',
'mcp.servers': (v) => `${v?.count ?? 0} 个服务器`,
'mcp.configuredServers': '已配置的 MCP 服务器:',
'mcp.fromExtension': (v) => `(来自 ${v?.name ?? ''}`,
'mcp.extensionMcp': '扩展 MCP',
'mcp.invalidReason': (v) => `无效:${v?.reason ?? ''}`,
'mcp.invalidReasonLabel': '原因:',
'mcp.invalidToolHelp':
'工具必须同时包含 name 和 description 才能被 LLM 使用。',
'mcp.invalidToolWarning': '警告:这个工具不能被 LLM 调用',
'mcp.manageServers': '管理 MCP servers',
'mcp.parameters': '参数:',
'mcp.required': ' 必填',
'mcp.resources': '资源',
'mcp.resourcesUnavailable': '无法加载资源详情。',
'mcp.resourceCount': (v) => `${v?.count ?? 0} 个资源`,
'mcp.promptCount': (v) => `${v?.count ?? 0} 个提示词`,
'mcp.resource.uriLabel': 'URI',
'mcp.resource.nameLabel': '名称:',
'mcp.resource.mimeTypeLabel': 'MIME 类型:',
'mcp.resource.sizeLabel': '大小:',
'mcp.resource.bytes': (v) => `${v?.count ?? 0} 字节`,
'mcp.scrollPosition': (v) => `${v?.current ?? 0}/${v?.total ?? 0}`,
'mcp.shortcut.back': 'Esc 返回',
'mcp.shortcut.close': 'Esc 关闭',
'mcp.shortcut.selectBack': '↑↓ 导航 · Enter 选择 · Esc 返回',
'mcp.shortcut.selectClose': '↑↓ 导航 · Enter 选择 · Esc 关闭',
'mcp.settings': '设置',
'mcp.extension': (v) => `扩展:${v?.name ?? ''}`,
'mcp.starting': (v) =>
`⏳ MCP 服务器正在启动(${v?.count ?? 0} 个初始化中)...`,
'mcp.startingNote': '注意:首次启动可能需要更长时间。工具可用性会自动更新。',
'mcp.restartSkipped': (v) => `已跳过 ${v?.name ?? ''}${v?.reason ?? ''}`,
'mcp.restarted': (v) => `已重启 ${v?.name ?? ''},耗时 ${v?.duration ?? 0}ms`,
'mcp.restartEntries': (v) =>
`已重启 ${v?.name ?? ''}${v?.restarted ?? 0}/${v?.total ?? 0} 个条目${v?.failedReasons ? `(失败:${v.failedReasons}` : ''}`,
'mcp.source': '来源',
'mcp.source.extension': '扩展',
'mcp.source.project': '工作区设置',
'mcp.source.user': '用户设置',
'mcp.status': '状态',
'mcp.status.blocked': '已阻止',
'mcp.status.connected': '已连接',
'mcp.status.connecting': '连接中',
'mcp.status.disconnected': '未连接',
'mcp.status.disconnectedTitle': '已断开',
'mcp.status.disabled': '已禁用',
'mcp.status.ready': '就绪',
'mcp.status.starting': '启动中...(首次启动可能需要更长时间)',
'mcp.status.unknown': '未知',
'mcp.tipDesc': '显示 server 和工具描述',
'mcp.tipNodesc': '隐藏描述',
'mcp.tipSchema': '显示工具参数 schema',
'mcp.tips': '💡 提示:',
'mcp.toolCount': (v) => `${v?.count ?? 0} 个工具`,
'mcp.toolsCount': (v) => `${v?.count ?? 0} 个工具`,
'mcp.toolsLabel': '工具:',
'mcp.title': 'MCP 服务器',
'mcp.toolDetail': '工具详情',
'mcp.tools': '工具',
'mcp.toolsForServer': (v) => `${v?.name ?? 'Server'} 的工具`,
'mcp.transport': '传输',
'mcp.use': '使用',
'mcp.userMcp': '用户 MCP',
'mcp.workingDirectory': '工作目录',
'goal.aborted': '目标已中止',
'goal.achieved': '目标已达成',
'goal.check': '目标检查',
'goal.cleared': '目标已清除',
'goal.failed': '目标未能达成',
'goal.judge': '判断',
'goal.label': '目标',
'goal.lastCheck': '上次检查',
'goal.notYetMet': '尚未满足',
'goal.set': '目标已设置',
'goal.statusActive': '/goal 运行中',
'goal.turn': (v) => `${v?.count ?? 0}`,
'goal.turnLabel': (v) => `${v?.count ?? 0}`,
'goal.turns': (v) => `${v?.count ?? 0}`,
'memory.add': '添加',
'memory.add.desc': '写入一条持久 memory',
'memory.autoDream': (v) =>
`自动整理:${v?.status ?? '未知'} · ${v?.lastDream ?? '从未'} · /dream 立即运行`,
'memory.autoDreamUnsupported': 'web-shell 暂不支持修改自动整理设置。',
'memory.autoFolder': '打开自动记忆文件夹',
'memory.autoMemory': (v) => `自动记忆:${v?.status ?? '未知'}`,
'memory.autoMemoryUnsupported': 'web-shell 暂不支持修改自动记忆设置。',
'memory.autoSkill': (v) => `自动技能:${v?.status ?? '未知'}`,
'memory.autoSkillUnsupported': 'web-shell 暂不支持修改自动技能设置。',
'memory.chooseScope': '选择 memory 的保存位置',
'memory.closed': 'Memory 面板已关闭。',
'memory.contentEmpty': 'Memory 内容为空。',
'memory.file': 'Memory 文件',
'memory.fileOpen': 'Memory 文件已打开。',
'memory.fileTruncated': 'Memory 文件已打开,内容已截断。',
'memory.files': 'Memory 文件',
'memory.footer': 'Enter 确认 · Esc 取消',
'memory.footer.back': 'Esc 返回',
'memory.global': '用户级',
'memory.global.desc': '保存到全局用户 memory 文件',
'memory.globalReadUnsupported':
'全局 memory 位于当前 workspace 之外,当前 daemon 文件读取接口不能打开它的内容。',
'memory.loading': '正在加载 memory...',
'memory.loadingFile': '正在加载 memory 文件...',
'memory.lastDream': '5 hours ago',
'memory.menu': 'Memory',
'memory.never': '从未',
'memory.noFiles': '未找到 memory 文件。',
'memory.on': '开',
'memory.openFolderUnsupported': 'web-shell 暂不支持打开自动记忆文件夹。',
'memory.placeholder': (v) => `写入${v?.scope ?? 'memory'}内容...`,
'memory.project': '项目级',
'memory.project.desc': '保存到当前 workspace memory 文件',
'memory.refresh': '刷新',
'memory.refresh.desc': '重新加载 memory 文件信息',
'memory.refreshed': 'Memory 已刷新。',
'memory.save': '保存 Memory',
'memory.savedIn': (v) => `Saved in ${v?.path ?? ''}`,
'memory.saved': (v) =>
`${v?.scope ?? 'Memory'} 已保存:${v?.bytes ?? 0} 字节 -> ${v?.path ?? ''}`,
'memory.saving': '保存中...',
'memory.show': '查看',
'memory.show.desc': '查看已配置的 memory 文件',
'memory.status': 'Workspace 和用户 memory 文件',
'memory.unknown': '未知',
'memory.write': '写入 memory 内容',
'mode.auto': '智能审批',
'mode.auto.desc':
'使用分类器评估工具调用,安全操作自动批准,风险操作阻止或请求确认',
'mode.auto.notice':
'Auto 模式已启用。LLM 分类器会评估每个工具调用自动批准安全操作拦截危险操作。退出方式Shift+Tab 或 /approval-mode default。',
'mode.footer': '(Enter 选择Esc 取消)',
'mode.name.plan': 'plan',
'mode.name.default': 'default',
'mode.name.auto-edit': 'auto-edit',
'mode.name.auto': 'auto',
'mode.name.yolo': 'yolo',
'mode.label.plan': '计划',
'mode.label.default': '请求批准',
'mode.label.auto-edit': '自动编辑',
'mode.label.auto': '智能审批',
'mode.label.yolo': '完全访问权限',
'mode.listLabel.plan': '计划plan',
'mode.listLabel.default': '请求批准default',
'mode.listLabel.auto-edit': '自动编辑auto-edit',
'mode.listLabel.auto': '智能审批auto',
'mode.listLabel.yolo': '完全访问权限yolo',
'mode.desc.plan': '仅分析,不修改文件或执行命令',
'mode.desc.default': '执行命令、编辑文件或访问外部资源前请求确认',
'mode.desc.auto-edit': '自动批准文件编辑,命令执行等敏感操作仍会询问',
'mode.desc.auto': '自动评估工具风险,安全操作直接执行,风险操作再确认',
'mode.desc.yolo': '自动批准所有工具调用,适合可信任务环境',
'mode.select': '审批模式',
'mode.autoApproved': ((v) =>
v?.tool
? `已自动批准:${v.tool}`
: '切换模式后自动批准了待处理的工具调用。') as MessageValue,
'mode.auto-edit': '自动编辑',
'mode.auto-edit.desc': '自动批准文件读写操作',
'mode.default': '默认模式',
'mode.default.desc': '每次工具调用都需要确认',
'mode.plan': 'Plan 模式',
'mode.plan.desc': '仅分析和规划,不执行工具',
'mode.unknown': '未知模式',
'mode.yolo': 'YOLO 模式',
'mode.yolo.desc': '自动批准所有操作',
'plan.title': '计划',
'model.contextWindow': '上下文窗口',
'model.contextWindow.unknown': '(未知)',
'model.current': (v) => `当前:${v?.model ?? '未知'}`,
'model.modality': '模态',
'model.modality.text': '文本',
'model.modality.textOnly': '仅文本',
'model.modality.image': '图片',
'model.modality.pdf': 'PDF',
'model.modality.audio': '音频',
'model.modality.video': '视频',
'model.baseUrl': 'Base URL',
'model.apiKey': 'API Key',
'model.default': '(默认)',
'model.notSet': '(未设置)',
'model.footer': 'Enter 选择,↑↓ 导航Esc 关闭',
'model.searchHint': '按 / 搜索',
'model.fastHint': '用于建议和旁路任务',
'model.noMatch': (v) => `没有匹配 "${v?.query ?? ''}" 的模型`,
'model.none': '没有可用模型',
'model.select': '选择模型',
'model.setFast': '设置 Fast Model',
'model.setVoice': '设置语音模型',
'model.setVision': '设置视觉模型',
'model.switch': '切换模型',
'model.unknown': '未知',
'resume.current': '当前',
'resume.activePrompt': '正在运行',
'resume.filter': '筛选',
'resume.noMatch': (v) => `没有匹配 "${v?.query ?? ''}" 的会话`,
'resume.none': '没有可恢复的会话',
'resume.pressSearch': '按 / 搜索',
'resume.search': '搜索',
'resume.title': '恢复会话',
'parallelAgents.title': '并行智能体',
'parallelAgents.done': (v) => `${v?.done ?? 0}/${v?.total ?? 0} 完成`,
'skills.available': '可用 skills:',
'skills.none': '当前没有可用 skill。',
'skills.empty': '没有可用 skill。',
'skills.footer': (v) =>
v?.name
? `使用 /skills ${v.name} 调用 · r 刷新 · Esc 关闭`
: 'r 刷新 · Esc 关闭',
'skills.invocable': (v) => `${v?.enabled ?? 0}/${v?.total ?? 0} 可调用`,
'skills.loading': '正在加载 skills...',
'skills.run': '运行 skill',
'skills.status.disabled': '已禁用',
'skills.title': 'Skills',
'stats.accepted': '已接受:',
'stats.agreementRate': '总体同意率:',
'stats.api': 'API',
'stats.apiTime': 'API 耗时',
'stats.avgDuration': '平均耗时',
'stats.avgLatency': '平均延迟',
'stats.cached': '缓存',
'stats.cacheDesc': '的输入 Token 来自缓存,降低了成本。',
'stats.calls': '调用次数',
'stats.codeChanges': '代码变更',
'stats.decisionSummary': '用户决策摘要',
'stats.duration': '时长',
'stats.errors': '错误数',
'stats.inputTokens': '输入 Token',
'stats.metric': '指标',
'stats.modelStats': '模型统计(技术细节)',
'stats.modelTip': '提示:运行 /stats model 查看完整 Token 明细。',
'stats.modelUsage': '模型使用',
'stats.modified': '已修改:',
'stats.noApiCalls': '本次会话暂无 API 调用。',
'stats.noToolCalls': '本次会话暂无工具调用。',
'stats.outputTokens': '输出 Token',
'stats.overview': '会话概览',
'stats.performance': '性能',
'stats.prompts': '对话轮次',
'stats.rejected': '已拒绝:',
'stats.reqs': '请求',
'stats.requests': '请求数',
'stats.savingsHighlight': '节省亮点:',
'stats.successRate': '成功率',
'stats.thoughts': '思考',
'stats.title': '会话统计',
'stats.tokens': 'Token',
'stats.toolCalls': '工具调用',
'stats.toolName': '工具名称',
'stats.toolStats': '工具统计(技术细节)',
'stats.toolTime': '工具耗时',
'stats.total': '总计',
'stats.totalReviewed': '已审核建议总数:',
'status.contextUsed': (v) => `上下文已用 ${v?.pct ?? '0.0'}%`,
'status.disconnected': '断开连接',
'status.modeHint': '(shift + tab 或点击切换)',
'status.shortcuts': '? 查看快捷键',
'stream.cancel': 'esc 取消',
'stream.cancelArmed': '再按一次 Esc 停止',
'stream.tokens': (v) => `${v?.count ?? 0} tokens`,
'theme.current': (v) => `当前:${v?.theme ?? ''}`,
'theme.auto': '自动',
'theme.dark': '暗色',
'theme.dark.desc': '仿终端暗色皮肤。',
'theme.light': '亮色',
'theme.light.desc': '仿终端亮色皮肤。',
'theme.title': '主题',
'todo.allDone': '任务已全部完成',
'todo.collapse': '折叠任务列表',
'todo.completedAbove': (v) => `✓ 已完成 ${v?.count ?? 0}`,
'todo.detail.api': 'API',
'todo.detail.cached': '缓存',
'todo.detail.end': '结束',
'todo.detail.hide': '收起任务明细',
'todo.detail.input': '输入',
'todo.detail.noResources': '未采集到该任务的 Token 与耗时明细。',
'todo.detail.output': '输出',
'todo.detail.sectionSpent': '耗时',
'todo.detail.sectionTime': '时间',
'todo.detail.sectionTokens': 'Token',
'todo.detail.show': '查看任务明细',
'todo.detail.start': '开始',
'todo.detail.tool': '工具',
'todo.expand': '展开任务列表',
'todo.more': (v) => `... 还有 ${v?.count ?? 0}`,
'todo.moreAbove': (v) => `... 前面还有 ${v?.count ?? 0}`,
'todo.showLess': '收起',
'todo.stepProgress': (v) => `${v?.current ?? 0} / ${v?.total ?? 0}`,
'todo.stepFraction': (v) => `${v?.current ?? 0} / ${v?.total ?? 0}`,
'todo.title': '当前任务',
'chat.scrollToBottom': '回到底部',
'userMessage.showMore': '显示更多',
'userMessage.showLess': '收起',
'turn.processed': '已处理',
'turn.processing': '处理中',
'turn.collapse': '折叠步骤',
'turn.expand': '展开步骤',
'turn.cached': '缓存',
'turn.executionSteps': (v) => `${v?.count ?? 0}`,
'turn.toolCalls': (v) => `工具 ${v?.count ?? 0}`,
'turn.thinkingCount': (v) => `思考 ${v?.count ?? 0}`,
'turn.stopped': '你已取消请求',
'message.renderError': '此消息无法显示。',
'tasks.title': '后台任务',
'tasks.empty': '当前没有运行中的任务',
'tasks.refreshStale': '任务状态可能已过期,正在重连...',
'tasks.cancelFailed': '取消任务失败',
'tasks.alreadyStopped': '任务已停止',
'tasks.moreAbove': (v) => `^ 上方还有 ${v?.count ?? 0}`,
'tasks.moreBelow': (v) => `v 下方还有 ${v?.count ?? 0}`,
'tasks.running': '运行中',
'tasks.completed': '已完成',
'tasks.failed': '失败',
'tasks.cancelled': '已停止',
'tasks.paused': '已暂停',
'tasks.kind.shell': 'Shell',
'tasks.kind.monitor': '监控',
'tasks.action.stop': '停止',
'tasks.action.abandon': '放弃',
'tasks.action.confirmStop': '确认停止',
'tasks.action.confirmAbandon': '确认放弃',
'tasks.action.confirmHint': '这会终结当前阻塞轮次。',
'tasks.pill.agent': (v) => `${v?.count ?? 0} 个本地智能体`,
'tasks.pill.agents': (v) => `${v?.count ?? 0} 个本地智能体`,
'tasks.pill.agentPaused': (v) => `${v?.count ?? 0} 个本地智能体已暂停`,
'tasks.pill.agentsPaused': (v) => `${v?.count ?? 0} 个本地智能体已暂停`,
'tasks.pill.done': (v) => `${v?.count ?? 0} 个任务完成`,
'tasks.pill.doneMany': (v) => `${v?.count ?? 0} 个任务完成`,
'tasks.pill.monitor': (v) => `${v?.count ?? 0} 个监控`,
'tasks.pill.monitors': (v) => `${v?.count ?? 0} 个监控`,
'tasks.pill.shell': (v) => `${v?.count ?? 0} 个 shell`,
'tasks.pill.shells': (v) => `${v?.count ?? 0} 个 shell`,
'tasks.confirmStop': '再按 x 确认停止 · 会终结当前阻塞轮次',
'tasks.shortcut.select': '↑/↓ 选择',
'tasks.shortcut.view': 'Enter 查看',
'tasks.shortcut.stop': 'x 停止',
'tasks.shortcut.abandon': 'x 放弃',
'tasks.shortcut.listClose': '←/Esc 关闭',
'tasks.shortcut.detailBack': '← 返回',
'tasks.shortcut.detailClose': 'Esc/Enter/Space 关闭',
'tasks.shortcut.close': 'Esc 关闭',
'tasks.shortcut.cancelConfirm': 'Esc 取消',
'tasks.detail.workingDir': '工作目录',
'tasks.detail.outputFile': '输出文件',
'tasks.detail.command': '命令',
'tasks.detail.events': (v) => `${v?.count ?? 0} 个事件`,
'tasks.detail.exit': (v) => `退出码 ${v?.exitCode ?? ''}`,
'tasks.detail.dropped': (v) => `${v?.count ?? 0} 个已丢弃`,
'tasks.detail.error': '错误',
'tasks.detail.stoppedBecause': '停止原因',
'tasks.detail.resumeBlocked': '恢复被阻止',
'tasks.detail.progress': '执行进度',
'tasks.detail.prompt': '提示词',
'tasks.detail.type': '类型',
'tasks.detail.runtime': '时间',
'tasks.detail.tokenCount': 'Tokens',
'tasks.detail.toolCallCount': '工具数量',
'tasks.detail.tokens': (v) => `${v?.count ?? 0} tokens`,
'tasks.detail.toolCalls': (v) => `${v?.count ?? 0} 次工具调用`,
'tasks.detail.nesting': '嵌套',
'tasks.detail.nestingValue': (v) =>
`${v?.level ?? '?'} 层 · 来自 ${v?.parent ?? '?'}`,
'tasks.detail.nestingLevel': (v) => `${v?.level ?? '?'}`,
'tasks.row.from': (v) => `来自 ${v?.parent ?? '?'}`,
'tasks.row.nested': '嵌套',
'tips.items':
'输入 / 查看所有可用命令。|使用 @ 引用文件路径。|按 Esc 取消正在进行的请求。|使用 Shift+Enter 换行。|按 ↑↓ 浏览历史消息。',
'tools.available': '可用工具:',
'tools.none': '没有可用工具。',
'tools.empty': '没有可用的内置工具。请先打开一个会话。',
'tools.footer': (v) =>
v?.name
? `${v?.details ? 'Enter/Space 查看详情 · ' : ''}t 切换 ${v.name} · r 刷新 · Esc 关闭`
: 'r 刷新 · Esc 关闭',
'tools.details.hide': '收起详情',
'tools.details.show': '展开详情',
'tools.loading': '正在加载工具...',
'tools.status.disabled': '已禁用',
'tools.status.enabled': '已启用',
'tools.summary': (v) => `${v?.enabled ?? 0}/${v?.total ?? 0} 已启用`,
'tools.title': '工具',
'tools.update.disable': '禁用',
'tools.update.enable': '启用',
'tools.updating': '更新中...',
'tool.collapse': '▲ 收起',
'tool.expand': '展开',
'tool.collapseHint': '收起',
'tool.status.failed': '执行失败',
'toolGroup.moreKinds': (v) => ` +${v?.count ?? 0}`,
'toolGroup.summary': (v) => `调用了 ${v?.count ?? 0} 个工具`,
'toolGroup.summary.editedFiles': (v) => `已编辑 ${v?.count ?? 0} 个文件`,
'toolGroup.summary.ranCommands': (v) => `已运行 ${v?.count ?? 0} 条命令`,
'toolGroup.summary.readFiles': (v) => `已读取 ${v?.count ?? 0} 个文件`,
'toolGroup.summary.searched': (v) => `已搜索 ${v?.count ?? 0}`,
'toolGroup.summary.updatedTodos': (v) =>
Number(v?.count ?? 0) > 1
? `已更新任务清单 ${v?.count ?? 0}`
: '已更新任务清单',
'toolGroup.summary.askedUser': '已询问用户',
'toolGroup.summary.otherTools': (v) => `调用了 ${v?.count ?? 0} 个工具`,
'toolGroup.running': (v) =>
`正在执行 ${v?.name ?? '工具'}${v?.duration ? ` ${v.duration}` : ''}${
Number(v?.count ?? 0) > 1 ? ` · 共 ${v?.count ?? 0} 个工具` : ''
}`,
'toolGroup.runningPrefix': '正在执行',
'thinking.expand': '展开思考',
'thinking.collapse': '收起思考',
'thinking.running': (v) => `正在思考${v?.duration ? ` ${v.duration}` : ''}`,
'thinking.done': (v) => (v?.duration ? `已思考 ${v.duration}` : '思考完成'),
'welcome.changeModel': '(/model 切换)',
'welcome.defaultModel': '未知模型',
'sessionsOverview.count': (v) => `${v?.count ?? 0} 个会话`,
'sessionsOverview.current': '当前',
'sessionsOverview.empty': '暂无会话',
'sessionsOverview.loadFailed': '加载会话失败',
'sessionsOverview.loading': '正在加载会话…',
'sessionsOverview.openElsewhere': '已在其他窗口打开',
'sessionsOverview.openInSplit': '打开到分屏',
'sessionsOverview.openInSplitHint': '在本窗口内并排显示选中的会话',
'sessionsOverview.openInTab': '在新标签页打开',
'sessionsOverview.openInTabHint': '在新标签页中以分屏并排打开选中的会话',
'sessionsOverview.popupBlocked':
'弹出窗口被拦截。请允许本站弹窗,以便在新标签页中打开会话。',
'sessionsOverview.refresh': '刷新',
'sessionsOverview.selectAll': '全选',
'sessionsOverview.splitCap': (v) =>
`只有前 ${v?.max ?? 6} 个选中的会话会进入分屏。`,
'sessionsOverview.selectSession': (v) => `选择 ${v?.name ?? ''}`,
'sessionsOverview.status.idle': '空闲',
'sessionsOverview.status.needsApproval': '待审批',
'sessionsOverview.status.running': '运行中',
'sessionsOverview.title': '会话总览',
'splitView.title': '分屏',
'splitView.count': (v) => `${v?.count ?? 0} 个窗格`,
'splitView.addPane': '添加会话',
'splitView.closePane': '关闭窗格',
'splitView.paneError': '此会话窗格出错',
'splitView.paneConnectionError': '连接已断开',
'splitView.outerApprovalPending': '主会话正在等待审批。',
'splitView.goToApproval': '前往处理',
'splitView.empty': '分屏中还没有会话,添加一个开始。',
'splitView.composerPlaceholder': '给这个会话发消息…',
'settings.title': '设置',
'settings.loading': '正在加载设置...',
'settings.empty': '暂无可用设置。',
'settings.footer': '↑↓ 导航 Enter 切换 Tab 切换作用域 r 刷新 ESC 关闭',
'settings.footer.edit': 'Enter 保存 ESC 取消',
'settings.footer.theme': '↑↓ 导航 Enter 选择 ESC 返回',
'settings.scope.user': '用户',
'settings.scope.workspace': '工作区',
'settings.value.on': '开',
'settings.value.off': '关',
'settings.action.edit': '编辑',
'settings.action.save': '保存',
'settings.modifiedIn': (v) => `(已在${v?.scope ?? ''}中修改)`,
'settings.alsoModifiedIn': (v) => `(同时在${v?.scope ?? ''}中修改)`,
'settings.invalidNumber': '无效数字',
'settings.readOnly': 'User 级别设置在 daemon 模式下为只读。',
'settings.requiresRestart': '此更改需要重启后才能生效。',
'settings.corrupted': (v) =>
`设置文件已损坏${v?.recovered === 'true' ? '(已从备份恢复)' : ''}`,
'settings.label.ui.chatWidth': '屏宽',
'settings.description.ui.chatWidth':
'纯前端的聊天内容宽度设置,保存在当前浏览器中。',
'settings.option.ui.chatWidth.1000': '常规',
'settings.option.ui.chatWidth.wide': '超宽',
'settings.category.General': '通用',
'settings.category.UI': '界面',
'settings.category.Privacy': '隐私',
'settings.category.Model': '模型',
'settings.category.Context': '上下文',
'settings.category.Tools': '工具',
'settings.category.Daemon': '守护进程',
'settings.category.Experimental': '实验性',
'settings.category.Advanced': '高级',
'settings.label.general.enableAutoUpdate': '启用自动更新',
'settings.description.general.enableAutoUpdate': '启动时自动检查并安装更新。',
'settings.label.general.showSessionRecap': '显示会话回顾',
'settings.description.general.showSessionRecap':
'离开终端一段时间后返回时,自动显示一行“上次停在这里”的回顾。默认关闭。也可以随时使用 /recap 手动触发。',
'settings.label.general.sessionRecapAwayThresholdMinutes':
'会话回顾离开阈值(分钟)',
'settings.description.general.sessionRecapAwayThresholdMinutes':
'终端失焦多少分钟后,下一次重新聚焦时触发自动回顾。默认与 Claude Code 一致为 5 分钟;如果只是短暂切换窗口,可以调高。',
'settings.label.general.cleanupPeriodDays': '清理周期(天)',
'settings.description.general.cleanupPeriodDays':
'~/.qwen/file-history/ 中用于 /rewind 的会话备份保留天数。后台清理最多每天运行一次。设为 0 表示最小保留(约 1 小时),仍会保护最近一小时触碰过的会话和当前活动会话。',
'settings.label.general.gitCoAuthor.commit': '归因commit',
'settings.description.general.gitCoAuthor.commit':
'通过 Qwen Code 创建 commit 时,添加 Co-authored-by trailer并写入逐文件 AI 归因 git note。关闭后两者都会跳过。',
'settings.label.general.gitCoAuthor.pr': '归因PR',
'settings.description.general.gitCoAuthor.pr':
'运行 gh pr create 时,在 PR 描述中追加 Qwen Code 归因行。',
'settings.label.general.language': '语言:界面',
'settings.description.general.language':
'用户界面的语言。使用 auto 可根据系统设置自动检测;也可以在 ~/.qwen/locales/ 中放置 JS 语言文件来使用自定义语言代码。',
'settings.label.general.dynamicCommandTranslation': '语言:动态命令翻译',
'settings.description.general.dynamicCommandTranslation':
'为动态 slash command 描述启用 AI 翻译。关闭后动态命令使用原始描述,也不会触发翻译模型调用。',
'settings.label.general.preventSystemSleep': '运行时防止系统睡眠',
'settings.description.general.preventSystemSleep':
'当 Qwen Code 正在流式生成模型回复或执行工具时防止系统睡眠。空闲输入状态和权限确认状态不会阻止睡眠。',
'settings.label.ui.theme': '主题',
'settings.description.ui.theme': '界面的颜色主题。',
'settings.label.ui.hideTips': '隐藏提示',
'settings.description.ui.hideTips': '隐藏界面中的帮助提示。',
'settings.label.ui.enableWelcomeBack': '显示欢迎回来对话框',
'settings.description.ui.enableWelcomeBack':
'回到有历史会话的项目时显示欢迎回来对话框。选择“开始新的聊天会话”后,在项目摘要变化前不会再次显示。',
'settings.label.ui.enableUserFeedback': '启用用户反馈',
'settings.description.ui.enableUserFeedback':
'对话结束后显示可选反馈对话框,帮助改进 Qwen 表现。',
'settings.label.ui.enableFollowupSuggestions': '启用后续建议',
'settings.description.ui.enableFollowupSuggestions':
'任务完成后显示上下文相关的后续建议。按 Tab 或右方向键接受,按 Enter 接受并提交。',
'settings.label.ui.compactMode': '紧凑模式',
'settings.description.ui.compactMode':
'隐藏工具输出和思考内容,显示更简洁的视图(可用 Ctrl+O 切换)。',
'settings.label.ui.compactInline': '紧凑内联',
'settings.description.ui.compactInline':
'在每个分组内紧凑显示工具内容,而不是跨分组合并。需要先启用紧凑模式。',
'settings.label.ui.shellOutputMaxLines': 'Shell 输出最大行数',
'settings.description.ui.shellOutputMaxLines':
'内联显示的 shell 输出最大行数。设为 0 可取消限制并显示完整输出;隐藏行数仍会通过 +N lines 指示器展示。',
'settings.label.privacy.usageStatisticsEnabled': '启用使用统计',
'settings.description.privacy.usageStatisticsEnabled': '启用使用统计收集。',
'settings.label.fastModel': '快速模型',
'settings.description.fastModel':
'用于生成提示建议和推测执行的模型。留空则使用主模型。较小/更快的模型(例如 qwen3-coder-flash可以降低延迟和成本。',
'settings.label.visionModel': '视觉模型',
'settings.description.visionModel':
'用于视觉桥接的图像能力模型。留空则自动选择。',
'settings.label.context.fileFiltering.respectGitIgnore': '遵守 .gitignore',
'settings.description.context.fileFiltering.respectGitIgnore':
'搜索时遵守 .gitignore 文件。',
'settings.label.context.fileFiltering.respectQwenIgnore': '遵守 .qwenignore',
'settings.description.context.fileFiltering.respectQwenIgnore':
'搜索时遵守 .qwenignore 文件。',
'settings.label.context.fileFiltering.enableFuzzySearch': '启用模糊搜索',
'settings.description.context.fileFiltering.enableFuzzySearch':
'搜索文件时启用模糊搜索。',
'settings.label.tools.toolSearch.enabled': '启用 ToolSearch',
'settings.description.tools.toolSearch.enabled':
'启用后MCP 工具会通过 ToolSearch 按需加载,以减少提示词大小。对于依赖前缀 KV 缓存的模型(如 DeepSeek可关闭此项来保持提示词前缀稳定并提高缓存命中率。',
'settings.label.tools.shell.enableInteractiveShell': '交互式 ShellPTY',
'settings.description.tools.shell.enableInteractiveShell':
'使用 node-pty 提供交互式 shell 体验。PTY 不可用时回退到 child_process。',
'settings.label.tools.computerUse.enabled': '启用 Computer Use',
'settings.description.tools.computerUse.enabled':
'启用后(默认),会注册 9 个 computer_use__* 延迟内置工具。',
'settings.label.policy.permissionStrategy': '权限协调策略',
'settings.description.policy.permissionStrategy':
'多个客户端连接时权限请求的决策方式。first-responder 表示任意客户端先响应者生效designated 表示仅提示发起方决策consensus 表示需要 N-of-M 投票同意local-only 表示只有 loopback 客户端可决策。需要重启 daemon 后生效。',
'settings.option.policy.permissionStrategy.first-responder': '先响应者',
'settings.option.policy.permissionStrategy.designated': '指定发起方',
'settings.option.policy.permissionStrategy.consensus': '共识法定人数',
'settings.option.policy.permissionStrategy.local-only': '仅本机',
'settings.label.experimental.enableCronTools': '启用 Cron/Loop 工具',
'settings.description.experimental.enableCronTools':
'启用会话内 cron/loop 工具(实验性)。启用后,模型可以用 cron_create、cron_list 和 cron_delete 创建周期性提示。也可通过 QWEN_CODE_ENABLE_CRON=1 环境变量启用。',
'settings.label.experimental.emitToolUseSummaries': '工具使用摘要',
'settings.description.experimental.emitToolUseSummaries':
'每个工具批次完成后生成一个简短的 LLM 标签。紧凑模式下会替代通用的 Tool × N 标题;完整模式下显示为工具组下方的弱化 ● <label> 行。需要配置快速模型。',
'settings.label.agents.arena.preserveArtifacts': '保留 Arena 产物',
'settings.description.agents.arena.preserveArtifacts':
'启用后Arena worktree 和会话状态文件会在会话结束或主智能体退出后保留。',
'welcome.modeHint': 'Shift+Tab 或 /approval-mode',
'welcome.prompt': '你想构建什么?',
'welcome.titlePrefix': '欢迎使用',
'welcome.tipLabel': '提示:',
};
const MESSAGES: Record<WebShellLanguage, Messages> = {
en: EN,
'zh-CN': ZH,
};
const LANGUAGE_LABELS: Record<WebShellLanguage, string> = {
en: 'English [en]',
'zh-CN': '中文 [zh-CN]',
};
const Context = createContext<{
language: WebShellLanguage;
t: (key: string, vars?: Record<string, string | number>) => string;
}>({
language: 'en',
t: (key) => key,
});
export function normalizeLanguage(
value: string | undefined | null,
): WebShellLanguage {
const normalized = value?.trim().toLowerCase();
if (!normalized) return 'en';
if (normalized === 'zh' || normalized === 'zh-cn' || normalized === 'zh_cn') {
return 'zh-CN';
}
return 'en';
}
export function languageSettingToWebShellLanguage(
value: unknown,
): WebShellLanguage | undefined {
if (typeof value !== 'string') return undefined;
const normalized = value.trim().toLowerCase().replace(/_/g, '-');
if (!normalized) return undefined;
if (normalized === 'auto') {
return normalizeLanguage(
typeof navigator !== 'undefined' ? navigator.language : undefined,
);
}
if (
normalized === 'zh' ||
normalized === 'zh-cn' ||
normalized === 'chinese' ||
normalized === '中文'
) {
return 'zh-CN';
}
if (
normalized === 'en' ||
normalized === 'en-us' ||
normalized === 'english'
) {
return 'en';
}
return undefined;
}
export function languageLabel(language: WebShellLanguage): string {
return LANGUAGE_LABELS[language];
}
export function getTranslator(language: WebShellLanguage) {
const messages = MESSAGES[language];
return (key: string, vars?: Record<string, string | number>) => {
const message = messages[key] ?? EN[key] ?? key;
return typeof message === 'function' ? message(vars) : message;
};
}
export function I18nProvider({
language,
children,
}: PropsWithChildren<{ language: WebShellLanguage }>) {
const value = useMemo(() => {
return {
language,
t: getTranslator(language),
};
}, [language]);
return <Context.Provider value={value}>{children}</Context.Provider>;
}
export function useI18n() {
return useContext(Context);
}