hermes-agent/locales/zh.yaml
Teknium c39168453d
feat(i18n): localize all gateway commands + web dashboard, add 8 new locales (16 total) (#22914)
* feat(i18n): localize /model command output

Reported by @tianma8888: when Chinese users run /model, the labels
("Provider:", "Context:", "_session only_", etc.) are still English.
This routes the static prose through the existing i18n catalog so it
follows display.language / HERMES_LANGUAGE.

Changes:
- locales/{en,zh,ja,de,es,fr,tr,uk}.yaml: add 17 keys under
  gateway.model.* covering switched/provider/context/max_output/cost/
  capabilities/prompt_caching/warning/saved_global/session_only_hint/
  current_label/current_tag/more_models_suffix/usage_*.
- gateway/run.py _handle_model_command: replace hardcoded f-strings in
  the picker callback, the text-list fallback, and the direct-switch
  confirmation block with t("gateway.model.<key>", ...).

What stays English:
- model IDs, provider slugs, capability strings, cost figures, and the
  "[Note: model was just switched...]" prepended to the model's next
  prompt (LLM-facing, not user-facing).
- The two slightly-different session-only hints unify on a single key
  with the em-dash phrasing.

Validation: tests/agent/test_i18n.py 27/27 passing (parity contract
holds), tests/gateway/ -k 'model or i18n' 74/74 passing.

* feat(i18n): localize all gateway slash command outputs

Expands the i18n catalog from 7 strings to 234 keys across 35 gateway
slash command handlers, so non-English users see localized output for
\`/profile\`, \`/status\`, \`/help\`, \`/personality\`, \`/voice\`, \`/reset\`,
\`/agents\`, \`/restart\`, \`/commands\`, \`/goal\`, \`/retry\`, \`/undo\`,
\`/sethome\`, \`/title\`, \`/yolo\`, \`/background\`, \`/approve\`, \`/deny\`,
\`/insights\`, \`/debug\`, \`/rollback\`, \`/reasoning\`, \`/fast\`,
\`/verbose\`, \`/footer\`, \`/compress\`, \`/topic\`, \`/kanban\`,
\`/resume\`, \`/branch\`, \`/usage\`, \`/reload-mcp\`, \`/reload-skills\`,
\`/update\`, \`/stop\` (plus the \`/model\` block already added in the
previous commit).

Reported by @tianma8888 — Chinese users want command output prose in
their language, not just the labels we already had.

Translations are hand-written for all 8 supported locales (en, zh, ja,
de, es, fr, tr, uk), matching each catalog's existing style: full-width
punctuation in zh, em-dashes in zh/ja/uk, French spaced colons,
German noun capitalization, etc.

What stays English (unchanged):
- Identifiers/values: model IDs, file paths, profile names, session IDs,
  command flag names like --global, URLs, config keys.
- Backtick code spans: \`/foo\`, \`config.yaml\`.
- Log messages (logger.info/warning/error).
- LLM-facing system notes prepended to next prompt (e.g. [Note: model
  was just switched...]).
- Strings produced by external modules (gateway_help_lines,
  format_gateway, manual_compression_feedback) — those have their
  own surfaces.

New shared keys for cross-handler boilerplate:
- gateway.shared.session_db_unavailable (5 call sites: branch, title,
  resume, topic, _disable_telegram_topic_mode_for_chat)
- gateway.shared.session_not_found (1 site)
- gateway.shared.warn_passthrough (2 sites in /title's f"⚠️ {e}" pattern)

YAML gotcha fixed: \`yolo.on\` and \`yolo.off\` were originally written
unquoted, which YAML 1.1 parses as boolean True/False keys. Renamed to
\`yolo.enabled\` / \`yolo.disabled\` for both safety and clarity.

Test fix: tests/agent/test_i18n.py::test_t_missing_key_in_non_english_falls_back_to_english
now resets the catalog cache on teardown, so the fake "foo: English Foo"
locale doesn't poison the module-level cache for subsequent tests in
the same xdist worker. (Without this, every gateway slash command test
that shares a worker with the i18n suite would see the fake catalog.)

Validation:
- tests/agent/test_i18n.py: 27/27 (parity contract — every key in every
  locale, matching placeholder tokens).
- tests/gateway/: 5077 passed, 0 failed (full gateway suite).
- 180 t() call sites added across 35 handlers; 1872 catalog entries
  total (234 keys × 8 locales).

* feat(i18n): add 8 new locales — af, ko, it, ga, zh-hant, pt, ru, hu

Expands the static-message catalog from 8 → 16 languages, each with full
270-key parity against the English source-of-truth.  Every locale now
covers the same surface PR #22914 added: approval prompts plus all 35
gateway slash command outputs.

New locales:
- af  Afrikaans      (community ask in #21961 by @GodsBoy; PRs #21962, #21970)
- ko  Korean         (PRs #20297 by @tmdgusya, #22285 by @project820)
- it  Italian        (PR #20371 by @leprincep35700)
- ga  Irish/Gaeilge  (PR #20962 by @ryanmcc09-dot)
- zh-hant Traditional Chinese (PRs #20523 by @jackey8616, #13140 by @anomixer)
- pt  Portuguese     (PRs #20443 by @pedroborges, #15737 by @carloshenriquecarniatto, #22063 by @Magaav)
- ru  Russian        (PR #22770 by @DrMaks22)
- hu  Hungarian      (PR #22336 by @lunasec007)

Each locale uses native-quality translations matching the existing tone
and conventions of the older 8 locales:
- zh-hant uses 繁體 characters with TW/HK technical vocabulary (軟體
  not 软件, 連線 not 连接, 設定 not 设置, 訊息 not 消息, 工作階段 not 会话, 程式
  not 程序, 預設 not 默认, 伺服器 not 服务器), full-width punctuation 「:()」.
- ko uses formal 합니다체 (습니다/합니다) register throughout.
- pt uses European Portuguese as baseline with neutral PT/BR vocabulary
  where possible.
- ga uses standard An Caighdeán Oifigiúil; English loanwords retained
  for tech terms without good Irish equivalents (gateway, API, JSON).
- All preserve {placeholder} tokens, backtick code spans, slash commands,
  brand names (Hermes, MCP, TTS, YOLO, OpenAI, Telegram, etc.), and emoji.

Aliases added in agent/i18n.py:
- af-za, Afrikaans → af
- ko-kr, Korean, 한국어 → ko
- it-it, italiano → it
- ga-ie, Irish, Gaeilge → ga
- zh-tw, zh-hk, zh-mo, traditional-chinese → zh-hant (note: zh-tw used to
  alias to zh; now aliases to its own zh-hant catalog)
- zh-cn, zh-hans, zh-sg → zh (unchanged from before)
- pt-pt, pt-br, brazilian, portuguese → pt
- ru-ru, Russian, русский → ru
- hu-hu, Magyar → hu

The zh-tw alias re-routing is intentional: previously typing 'zh-TW' got
the Simplified Chinese catalog (wrong vocabulary for Taiwan/HK users).
Now those users get the proper Traditional Chinese catalog.

Validation:
- tests/agent/test_i18n.py: 43/43 (parity contract holds for all 16
  languages × 270 keys = 4320 catalog entries, with matching placeholder
  tokens).
- E2E alias resolution verified for all 19 alias inputs (Afrikaans, ko-KR,
  한국어, italiano, Gaeilge, zh-TW, zh-HK, traditional-chinese, pt-BR,
  brazilian, Magyar, etc.).
- tests/gateway/: 5198 passed (3 pre-existing TTS routing failures
  unrelated to i18n).

Credit to all contributors whose PRs surfaced these language requests.
Their original PRs may now be closed as superseded with credit.

* feat(dashboard-i18n): add 14 web dashboard locales matching the static catalog

Brings the React dashboard (web/src/) up to the same 16-language
coverage the static catalog already has after the previous commits in
this PR. The Translations interface is TypeScript-typed, so every new
locale must provide every key — tsc -b is the parity guard.

Languages added (each is a complete 429-line locale file):
- af  Afrikaans
- ja  Japanese        (PR #22513 by @snuffxxx surfaced this)
- de  German          (PR #21749 by @mag1art)
- es  Spanish         (PR #21749)
- fr  French          (PRs #21749, #10310 by @foXaCe)
- tr  Turkish
- uk  Ukrainian
- ko  Korean          (PRs #21749, #18894 by @ovstng, #22285 by @project820)
- it  Italian
- ga  Irish (Gaeilge)
- zh-hant Traditional Chinese (PR #13140 by @anomixer)
- pt  Portuguese      (PRs #22063 by @Magaav, #22182 by @wesleysimplicio, #15737 by @carloshenriquecarniatto)
- ru  Russian         (PRs #21749, #22770 by @DrMaks22)
- hu  Hungarian       (PR #22336 by @lunasec007)

Each translation covers all 15 namespaces with full key parity vs en.ts,
preserves every {placeholder} token verbatim, keeps identifiers
untranslated (brand names, file paths, cron expressions, code spans),
translates the language.switchTo tooltip into the target language, and
matches existing tone conventions (zh-hant uses TW/HK vocab; ja uses
formal desu/masu; ko uses formal seumnida register; ga uses An
Caighdean Oifigiuil with English loanwords for tech vocab without good
Irish equivalents).

Plumbing:
- web/src/i18n/types.ts: Locale union expanded to all 16 codes.
- web/src/i18n/context.tsx: imports all 16 catalogs; exports
  LOCALE_META (endonym + flag per locale); isLocale() type guard.
- web/src/i18n/index.ts: re-export LOCALE_META.
- web/src/components/LanguageSwitcher.tsx: replaced two-state EN-ZH
  toggle with a click-to-open dropdown listing all 16 languages.

Note: zh-hant.ts exports zhHant (camelCase) since hyphen is invalid in
a JS identifier; the canonical 'zh-hant' string keys it in TRANSLATIONS.

Validation:
- npx tsc -b: 0 errors. Every locale satisfies Translations.
- npm run build (tsc + vite production): green, 2062 modules.
- Each locale file is exactly 429 lines.

Out of scope: plugin dashboards (kanban/achievements ship as prebuilt
bundles with no source in repo); Docusaurus docs (separate surface);
TUI (no i18n yet).

* feat(plugin-i18n): localize achievements + kanban plugin dashboards across all 16 locales

Brings the two shipped plugin dashboards (hermes-achievements, kanban)
under the same i18n umbrella as the core dashboard PR #22914 just
established.  Both bundles now read user-facing strings from the host's
i18n catalog via SDK.useI18n() instead of hardcoded English.

## Approach

Plugin dashboards ship as prebuilt IIFE bundles in
plugins/<name>/dashboard/dist/index.js — no build step, no source in
repo (upstream-authored, vendored as compiled JS).  Earlier contributor
PRs (#22594, #22595, #18747) tried direct edits but didn't actually
wire the bundles to read translations.

This change does the wiring properly:

1.  Each bundle gets a useI18n shim at IIFE scope:
        const useI18n = SDK.useI18n
          || function () { return { t: { kanban: null }, locale: "en" }; };
    Older host SDKs without useI18n still load the bundle and render
    English fallbacks.

2.  A small tx(t, path, fallback, vars) helper resolves dotted keys
    under the plugin's namespace (t.kanban.* or t.achievements.*) and
    interpolates {placeholder} tokens.

3.  Every React component starts with const { t } = useI18n() and
    each user-visible string is wrapped in tx(t, "key", "English fallback").
    Helpers called outside React components (window.prompt callers,
    constants used during init) take t as a parameter.

4.  Top-level constants that were English dictionaries (COLUMN_LABEL,
    COLUMN_HELP, DESTRUCTIVE_TRANSITIONS, DIAGNOSTIC_EVENT_LABELS in
    kanban) become getColumnLabel(t, status)-style functions backed by
    FALLBACK_* dictionaries.

## Translations added

Two new top-level namespaces added to the dashboard's TypeScript-typed
Translations interface:

- achievements: ~70 keys covering the hero, scan banner, achievement
  card, share dialog, stats, filters, and empty states.
- kanban: ~145 keys covering the board, columns (with nested
  columnLabels and columnHelp sub-dicts), card detail panel,
  bulk-actions toolbar, dependency editor, board switcher, and
  diagnostic callouts.

Each key is provided across all 16 supported locales:
en, zh, zh-hant, ja, de, es, fr, tr, uk, af, ko, it, ga, pt, ru, hu.

Total new translation entries: ~3,440 (215 keys × 16 locales).

## What stays English (deliberate)

- API paths, CSS class names, data-* attributes, JSON keys, regex
  strings, URLs, file paths (~/.hermes/kanban.db, boards/_archived/).
- State identifier strings used as lookup keys (triage / todo / ready /
  running / blocked / done / archived) — labels translate, key strings
  don't.
- The PNG share-card text rendered to canvas in the achievements
  ShareDialog (HERMES AGENT watermark, UNLOCKED stamp, tier names) —
  these become part of a globally-shared image and stay English.
- localStorage keys (hermes.kanban.selectedBoard).
- Brand names (Kanban, Hermes, WebSocket, Nous Research).

## Contributor credit

PR #22594 by @02356abc and PR #22595 by @02356abc supplied the
en + zh kanban namespace skeleton (145 keys); used as the en source-
of-truth in this commit and translated to the other 14 locales.

PR #18747 by @laolaoshiren first surfaced the achievements
localization request.

## Validation

- npx tsc -b: 0 errors. All 16 locale .ts files satisfy the
  Translations type with full key parity.
- npm run build (tsc + vite production build): green, 2062 modules,
  1.56MB JS / 95KB CSS, ~2.5s build.
- node --check on both plugin bundles: parse cleanly.
- 126 tx() call sites in kanban, 46 in achievements.

## Out of scope

- TUI (ui-tui/) has no i18n infrastructure yet.
- Docusaurus docs (website/i18n/) — already had zh-Hans; expanding
  is a separate translation workstream (Thai / Korean / Hindi PRs).
2026-05-10 07:14:14 -07:00

350 lines
22 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# Hermes 静态消息目录 -- 中文(简体)
# See locales/en.yaml for the source of truth; keep keys in sync.
approval:
dangerous_header: "⚠️ 危险命令: {description}"
choose_long: " [o]仅此一次 | [s]本次会话 | [a]永久允许 | [d]拒绝"
choose_short: " [o]仅此一次 | [s]本次会话 | [d]拒绝"
prompt_long: " 选择 [o/s/a/D]: "
prompt_short: " 选择 [o/s/D]: "
timeout: " ⏱ 超时 — 已拒绝命令"
allowed_once: " ✓ 本次允许"
allowed_session: " ✓ 本次会话内允许"
allowed_always: " ✓ 已加入永久允许列表"
denied: " ✗ 已拒绝"
cancelled: " ✗ 已取消"
blocklist_message: "此命令位于无条件拦截列表中,无法被批准。"
gateway:
approval_expired: "⚠️ 批准已过期(代理不再等待)。请让代理重试。"
draining: "⏳ 正在等待 {count} 个活跃代理结束后重启..."
goal_cleared: "✓ 目标已清除。"
no_active_goal: "当前没有活跃的目标。"
config_read_failed: "⚠️ 无法读取 config.yaml{error}"
config_save_failed: "⚠️ 无法保存配置:{error}"
model:
error_prefix: "错误:{error}"
switched: "已切换模型为 `{model}`"
provider_label: "提供方:{provider}"
context_label: "上下文:{tokens} tokens"
max_output_label: "最大输出:{tokens} tokens"
cost_label: "费用:{cost}"
capabilities_label: "能力:{capabilities}"
prompt_caching_enabled: "提示词缓存:已启用"
warning_prefix: "警告:{warning}"
saved_global: "已保存到 config.yaml`--global`"
session_only_hint: "_仅本次会话有效 — 添加 `--global` 可永久保存_"
current_label: "当前:`{model}`{provider}"
current_tag: "(当前)"
more_models_suffix: "(还有 {count} 个)"
usage_switch_model: "`/model <name>` — 切换模型"
usage_switch_provider: "`/model <name> --provider <slug>` — 切换提供方"
usage_persist: "`/model <name> --global` — 永久保存"
agents:
header: "🤖 **活跃代理与任务**"
active_agents: "**活跃代理:** {count}"
this_chat: " · 当前聊天"
more: "... 还有 {count} 个"
running_processes: "**运行中的后台进程:** {count}"
async_jobs: "**网关异步任务:** {count}"
none: "没有活跃的代理或运行中的任务。"
state_starting: "启动中"
state_running: "运行中"
approve:
no_pending: "没有待批准的命令。"
once_singular: "✅ 命令已批准。代理正在恢复…"
once_plural: "✅ 命令已批准({count} 条命令)。代理正在恢复…"
session_singular: "✅ 命令已批准(本次会话内允许该模式)。代理正在恢复…"
session_plural: "✅ 命令已批准(本次会话内允许该模式)({count} 条命令)。代理正在恢复…"
always_singular: "✅ 命令已批准(永久允许该模式)。代理正在恢复…"
always_plural: "✅ 命令已批准(永久允许该模式)({count} 条命令)。代理正在恢复…"
background:
usage: "用法:/background <提示>\n示例/background 总结今天 HN 上热门的故事\n\n在独立会话中运行该提示。你可以继续聊天 — 结果完成后将在此显示。"
started: "🔄 后台任务已启动:「{preview}」\n任务 ID{task_id}\n你可以继续聊天 — 完成后结果将在此显示。"
branch:
db_unavailable: "会话数据库不可用。"
no_conversation: "没有可分支的对话 — 请先发送一条消息。"
create_failed: "创建分支失败:{error}"
switch_failed: "分支已创建,但无法切换到它。"
branched_one: "⑂ 已分支到 **{title}**(已复制 {count} 条消息)\n原始`{parent}`\n分支`{new}`\n使用 `/resume` 切换回原始会话。"
branched_many: "⑂ 已分支到 **{title}**(已复制 {count} 条消息)\n原始`{parent}`\n分支`{new}`\n使用 `/resume` 切换回原始会话。"
commands:
usage: "用法:`/commands [page]`"
skill_header: "⚡ **技能命令**"
default_desc: "技能命令"
none: "没有可用的命令。"
header: "📚 **命令**(共 {total} 个,第 {page}/{total_pages} 页)"
nav_prev: "`/commands {page}` ← 上一页"
nav_next: "下一页 → `/commands {page}`"
out_of_range: "_请求的第 {requested} 页超出范围,显示第 {page} 页。_"
compress:
not_enough: "对话内容不足,无法压缩(至少需要 4 条消息)。"
no_provider: "未配置提供方 — 无法压缩。"
nothing_to_do: "暂无可压缩内容(对话记录仍全部为受保护上下文)。"
focus_line: "聚焦:\"{topic}\""
summary_failed: "⚠️ 摘要生成失败({error})。{count} 条历史消息已被移除并替换为占位符;之前的上下文已无法恢复。建议检查 auxiliary.compression 模型配置。"
aux_failed: " 配置的压缩模型 `{model}` 失败({error})。已使用主模型恢复 — 上下文完好 — 但您可能想检查 config.yaml 中的 `auxiliary.compression.model`。"
failed: "压缩失败:{error}"
debug:
upload_failed: "✗ 无法上传调试报告:{error}"
header: "**调试报告已上传:**"
auto_delete: "⏱ 粘贴内容将在 6 小时后自动删除。"
full_logs_hint: "如需上传完整日志,请在 CLI 中使用 `hermes debug share`。"
share_hint: "请将这些链接分享给 Hermes 团队以获得支持。"
deny:
stale: "❌ 命令已拒绝(批准已过期)。"
no_pending: "没有待拒绝的命令。"
denied_singular: "❌ 命令已拒绝。"
denied_plural: "❌ 命令已拒绝({count} 条命令)。"
fast:
not_supported: "⚡ /fast 仅适用于支持优先处理Priority Processing的 OpenAI 模型。"
status: "⚡ 优先处理\n\n当前模式`{mode}`\n\n_用法_ `/fast <normal|fast|status>`"
unknown_arg: "⚠️ 未知参数:`{arg}`\n\n**有效选项:** normal、fast、status"
saved: "⚡ ✓ 优先处理:**{label}**(已保存到配置)\n_下一条消息生效_"
session_only: "⚡ ✓ 优先处理:**{label}**(仅本次会话)"
label_fast: "FAST"
label_normal: "NORMAL"
status_fast: "fast"
status_normal: "normal"
footer:
status: "📎 运行时页脚:**{state}**\n字段`{fields}`\n平台`{platform}`"
usage: "用法:`/footer [on|off|status]`"
saved: "📎 运行时页脚:**{state}**{example}\n_已全局保存 — 下一条消息生效_"
example_line: "\n示例`{preview}`"
state_on: "ON"
state_off: "OFF"
goal:
unavailable: "此会话不支持目标功能。"
no_goal_set: "未设置目标。"
paused: "⏸ 目标已暂停:{goal}"
no_resume: "没有可恢复的目标。"
resumed: "▶ 目标已恢复:{goal}\n发送任意消息继续或等待 — 我会在下一轮继续推进。"
invalid: "无效目标:{error}"
set: "⊙ 目标已设置({budget} 轮预算):{goal}\n我将持续工作直到目标完成、你暂停/清除它,或预算耗尽。\n控制命令/goal status · /goal pause · /goal resume · /goal clear"
help:
header: "📖 **Hermes 命令**\n"
skill_header: "\n⚡ **技能命令**{count} 个活跃):"
more_use_commands: "\n... 还有 {count} 个。使用 `/commands` 查看完整分页列表。"
insights:
invalid_days: "无效的 --days 值:{value}"
error: "生成洞察时出错:{error}"
kanban:
error_prefix: "⚠ kanban 错误:{error}"
subscribed_suffix: "(已订阅 — 当 {task_id} 完成或被阻塞时将通知您)"
truncated_suffix: "…(已截断;如需完整输出请在终端运行 `hermes kanban …`"
no_output: "(无输出)"
personality:
none_configured: "`{path}/config.yaml` 中未配置人格设定"
header: "🎭 **可用人格**\n"
none_option: "• `none` — (不应用人格覆盖)"
item: "• `{name}` — {preview}"
usage: "\n用法`/personality <name>`"
save_failed: "⚠️ 保存人格变更失败:{error}"
cleared: "🎭 已清除人格 — 使用基础代理行为。\n_在下一条消息时生效_"
set_to: "🎭 人格已设置为 **{name}**\n_在下一条消息时生效_"
unknown: "未知人格:`{name}`\n\n可用{available}"
profile:
header: "👤 **配置文件:** `{profile}`"
home: "📂 **主目录:** `{home}`"
reasoning:
level_default: "medium默认"
level_disabled: "none已禁用"
scope_session: "会话覆盖"
scope_global: "全局配置"
status: "🧠 **推理设置**\n\n**强度:** `{level}`\n**作用域:** {scope}\n**显示:** {display}\n\n_用法_ `/reasoning <none|minimal|low|medium|high|xhigh|reset|show|hide> [--global]`"
display_on: "开 ✓"
display_off: "关"
display_set_on: "🧠 ✓ 推理显示:**开启**\n在 **{platform}** 上每次响应前将显示模型的思考过程。"
display_set_off: "🧠 ✓ **{platform}** 上的推理显示:**关闭**"
reset_global_unsupported: "⚠️ 不支持 `/reasoning reset --global`。请使用 `/reasoning <level> --global` 修改全局默认值。"
reset_done: "🧠 ✓ 已清除本会话的推理覆盖;回退到全局配置。"
unknown_arg: "⚠️ 未知参数:`{arg}`\n\n**有效级别:** none, minimal, low, medium, high, xhigh\n**显示:** show, hide\n**持久化:** 添加 `--global` 以跨会话保存"
set_global: "🧠 ✓ 推理强度已设置为 `{effort}`(已保存到配置)\n_下一条消息生效_"
set_global_save_failed: "🧠 ✓ 推理强度已设置为 `{effort}`(仅本会话 — 配置保存失败)\n_下一条消息生效_"
set_session: "🧠 ✓ 推理强度已设置为 `{effort}`(仅本会话 — 添加 `--global` 以持久化)\n_下一条消息生效_"
reload_mcp:
cancelled: "🟡 已取消 /reload-mcp。MCP 工具未更改。"
always_followup: " 后续 `/reload-mcp` 调用将不再确认。可在 `config.yaml` 中将 `approvals.mcp_reload_confirm: true` 重新启用。"
confirm_prompt: "⚠️ **确认 /reload-mcp**\n\n重新加载 MCP 服务器会为本会话重建工具集,并**使提供方提示词缓存失效** — 下一条消息将重新发送完整输入令牌。在长上下文或高推理模型上,这可能开销较大。\n\n请选择\n• **批准一次** — 立即重新加载\n• **始终批准** — 立即重新加载并永久静默此提示\n• **取消** — 保持 MCP 工具不变\n\n_文本备用回复 `/approve`、`/always` 或 `/cancel`。_"
header: "🔄 **MCP 服务器已重新加载**\n"
reconnected: "♻️ 已重新连接:{names}"
added: " 已添加:{names}"
removed: " 已移除:{names}"
none_connected: "没有连接的 MCP 服务器。"
tools_available: "\n🔧 来自 {servers} 个服务器的 {tools} 个工具可用"
failed: "❌ MCP 重新加载失败:{error}"
reload_skills:
header: "🔄 **技能已重新加载**\n"
no_new: "未检测到新技能。"
total: "\n📚 {count} 个技能可用"
added_header: " **新增技能:**"
removed_header: " **移除技能:**"
item_with_desc: " - {name}{desc}"
item_no_desc: " - {name}"
failed: "❌ 技能重新加载失败:{error}"
reset:
header_default: "✨ 会话已重置!重新开始。"
header_new: "✨ 新会话已启动!"
header_titled: "✨ 新会话已启动:{title}"
title_rejected: "\n⚠ 标题被拒绝:{error}"
title_error_untitled: "\n⚠ {error} — 会话以未命名方式启动。"
title_empty_untitled: "\n⚠ 清理后标题为空 — 会话以未命名方式启动。"
tip: "\n✦ 提示:{tip}"
restart:
in_progress: "⏳ 网关重启已在进行中……"
restarting: "♻ 正在重启网关。如果 60 秒内没有收到通知,请在控制台运行 `hermes gateway restart` 重启。"
resume:
db_unavailable: "会话数据库不可用。"
no_named_sessions: "未找到已命名的会话。\n使用 `/title 我的会话` 为当前会话命名,然后用 `/resume 我的会话` 返回。"
list_header: "📋 **已命名会话**\n"
list_item: "• **{title}**{preview_part}"
list_preview_suffix: " — _{preview}_"
list_footer: "\n用法`/resume <会话名称>`"
list_failed: "无法列出会话:{error}"
not_found: "未找到匹配 '**{name}**' 的会话。\n使用不带参数的 `/resume` 查看可用会话。"
already_on: "📌 已在会话 **{name}** 上。"
switch_failed: "切换会话失败。"
resumed_one: "↻ 已恢复会话 **{title}**{count} 条消息)。对话已还原。"
resumed_many: "↻ 已恢复会话 **{title}**{count} 条消息)。对话已还原。"
resumed_no_count: "↻ 已恢复会话 **{title}**。对话已还原。"
retry:
no_previous: "没有可重试的上一条消息。"
rollback:
not_enabled: "检查点未启用。\n请在 config.yaml 中启用:\n```\ncheckpoints:\n enabled: true\n```"
none_found: "未找到 {cwd} 的检查点"
invalid_number: "无效的检查点编号。请使用 1-{max}。"
restored: "✅ 已恢复到检查点 {hash}{reason}\n已自动保存回滚前的快照。"
restore_failed: "❌ {error}"
set_home:
save_failed: "无法保存主频道:{error}"
success: "✅ 主频道已设置为 **{name}**ID{chat_id})。\n定时任务和跨平台消息将发送到此处。"
status:
header: "📊 **Hermes 网关状态**"
session_id: "**会话 ID** `{session_id}`"
title: "**标题:** {title}"
created: "**创建时间:** {timestamp}"
last_activity: "**最近活动:** {timestamp}"
tokens: "**Token 数:** {tokens}"
agent_running: "**代理运行中:** {state}"
state_yes: "是 ⚡"
state_no: "否"
queued: "**排队的后续:** {count}"
platforms: "**已连接平台:** {platforms}"
stop:
stopped_pending: "⚡ 已停止。代理尚未启动 — 你可以继续此会话。"
stopped: "⚡ 已停止。你可以继续此会话。"
no_active: "没有可停止的活跃任务。"
title:
db_unavailable: "会话数据库不可用。"
warn_prefix: "⚠️ {error}"
empty_after_clean: "⚠️ 清理后标题为空。请使用可打印字符。"
set_to: "✏️ 已设置会话标题:**{title}**"
not_found: "未在数据库中找到该会话。"
current_with_title: "📌 会话:`{session_id}`\n标题**{title}**"
current_no_title: "📌 会话:`{session_id}`\n尚未设置标题。用法`/title 我的会话名称`"
topic:
not_telegram_dm: "/topic 命令仅在 Telegram 私聊中可用。"
no_session_db: "会话数据库不可用。"
unauthorized: "您无权在此 bot 上使用 /topic。"
restore_needs_topic: "若要恢复会话,请先创建或打开一个 Telegram topic然后在该 topic 中发送 /topic <session-id>。要创建新 topic请打开 All Messages 并在其中发送任意消息。"
topics_disabled: "此 bot 尚未启用 Telegram topics。\n\n启用方法\n1. 打开 @BotFather。\n2. 选择您的 bot。\n3. 打开 Bot Settings → Threads Settings。\n4. 开启 Threaded Mode并确保允许用户创建新线程。\n\n然后再次发送 /topic。"
topics_user_disallowed: "Telegram topics 已启用,但不允许用户创建 topics。\n\n打开 @BotFather → 选择您的 bot → Bot Settings → Threads Settings然后关闭 'Disallow users to create new threads'。\n\n然后再次发送 /topic。"
enable_failed: "启用 Telegram topic 模式失败:{error}"
bound_status: "此 topic 已关联到:\n会话{label}\nID{session_id}\n\n使用 /new 将此 topic 替换为新会话。\n如需并行工作请打开 All Messages 并在其中发送消息以创建另一个 topic。"
thread_ready: "Telegram 多会话 topics 已启用。\n\n此 topic 将作为独立的 Hermes 会话使用。使用 /new 替换此 topic 的当前会话。如需并行工作,请打开 All Messages 并在其中发送消息以创建另一个 topic。"
untitled_session: "未命名会话"
undo:
nothing: "没有可撤销的内容。"
removed: "↩️ 已撤销 {count} 条消息。\n已移除「{preview}」"
update:
platform_not_messaging: "✗ /update 仅在消息平台可用。请在终端运行 `hermes update`。"
not_git_repo: "✗ 不是 git 仓库 — 无法更新。"
hermes_cmd_not_found: "✗ 无法找到 `hermes` 命令。Hermes 正在运行,但更新命令无法在 PATH 上或通过当前 Python 解释器找到可执行文件。请尝试在终端中手动运行 `hermes update`。"
start_failed: "✗ 启动更新失败:{error}"
starting: "⚕ 正在启动 Hermes 更新…… 进度将在此处显示。"
usage:
rate_limits: "⏱️ **速率限制:** {state}"
header_session: "📊 **会话令牌使用情况**"
label_model: "模型:`{model}`"
label_input_tokens: "输入令牌:{count}"
label_cache_read: "缓存读取令牌:{count}"
label_cache_write: "缓存写入令牌:{count}"
label_output_tokens: "输出令牌:{count}"
label_total: "总计:{count}"
label_api_calls: "API 调用次数:{count}"
label_cost: "费用:{prefix}${amount}"
label_cost_included: "费用:已包含"
label_context: "上下文:{used} / {total}{pct}%"
label_compressions: "压缩次数:{count}"
header_session_info: "📊 **会话信息**"
label_messages: "消息数:{count}"
label_estimated_context: "估计上下文:~{count} 个令牌"
detailed_after_first: "_首次代理响应后可查看详细使用情况_"
no_data: "此会话暂无使用数据。"
verbose:
not_enabled: "`/verbose` 命令未在消息平台启用。\n\n请在 `config.yaml` 中启用:\n```yaml\ndisplay:\n tool_progress_command: true\n```"
mode_off: "⚙️ 工具进度:**OFF** — 不显示任何工具活动。"
mode_new: "⚙️ 工具进度:**NEW** — 工具变化时显示(预览长度:`display.tool_preview_length`,默认 40。"
mode_all: "⚙️ 工具进度:**ALL** — 显示每次工具调用(预览长度:`display.tool_preview_length`,默认 40。"
mode_verbose: "⚙️ 工具进度:**VERBOSE** — 显示每次工具调用及完整参数。"
saved_suffix: "_已为 **{platform}** 保存 — 下一条消息生效_"
save_failed: "_无法保存到配置{error}_"
voice:
enabled_voice_only: "语音模式已启用。\n当你发送语音消息时我会用语音回复。\n使用 /voice tts 让所有消息都收到语音回复。"
disabled_text: "语音模式已禁用。仅文本回复。"
tts_enabled: "自动 TTS 已启用。\n所有回复都将包含一条语音消息。"
status_mode: "语音模式:{label}"
status_channel: "语音频道:#{channel}"
status_participants: "参与人数:{count}"
status_member: " - {name}{status}"
speaking: "(正在说话)"
enabled_short: "语音模式已启用。"
disabled_short: "语音模式已禁用。"
label_off: "关闭(仅文本)"
label_voice_only: "开启(仅对语音消息进行语音回复)"
label_all: "TTS对所有消息进行语音回复"
yolo:
disabled: "⚠️ 本会话 YOLO 模式 **已关闭** — 危险命令将需要批准。"
enabled: "⚡ 本会话 YOLO 模式 **已开启** — 所有命令自动批准。请谨慎使用。"
shared:
session_db_unavailable: "会话数据库不可用。"
session_db_unavailable_prefix: "会话数据库不可用"
session_not_found: "数据库中未找到该会话。"
warn_passthrough: "⚠️ {error}"