语言包
Hermes 内置 17 种 UI 语言(display.language)。该列表是可插拔的:一个语言包就是一个插件(或你 Hermes 主目录中的一个文件夹),用于新增语言或覆盖既有语言的措辞——一次覆盖 Python 侧(CLI 审批提示、网关回复、工具动词、提示)、hermes --tui 界面和桌面应用。
一个包翻译的是静态 UI 文本。agent 的回复、工具输出、日志和斜杠命令名称保持原样;要让 agent 自己用另一种语言回答,请在提示词中说明。
语言从何而来
Hermes 查找一个字符串时,会自上而下依次经过以下各层,取第一个命中:
- 插件语言包——每个声明了
provides_locales的已安装插件(两个包覆盖同一 key 时,后加载者胜出)。 - 你的覆盖层——
<HERMES_HOME>/locales/<lang>.yaml(按 profile:每个 profile 主目录有自己的locales/文件夹)。 - 内置——随 Hermes 分发的
locales/<lang>.yaml文件。 - 同样这三层用于英文,最后才是原始 key。
每一层都可以是部分的:一个包或覆盖层只需包含它要改动的 key。
hermes config set display.language <id> 接受这些层中任一层提供的 id。未知 id 会被拒绝,并列出可用语言:
$ hermes config set display.language pl
✗ display.language 的未知语言 'pl'。可用:en, af, ar, de, es, ...
安装语言包插件(hermes plugins install <包名>),或放入 <HERMES_HOME>/locales/<id>.yaml 以添加。
使用一个包
hermes plugins install https://github.com/teknium1/hermes-lang-pl # 或目录名
hermes config set display.language pl
重启正在运行的网关/TUI,使其加载该包。TUI 和桌面端的语言切换器会以母语名称(endonym)列出内置语言、你的覆盖层语言和每个已安装包。.env 中的 HERMES_LANGUAGE 仍优先于 display.language。
编写一个包
一个包不需要任何 Python 代码。最小布局:
hermes-lang-pl/
plugin.yaml
locales/
pl.yaml # 核心:Python 侧字符串(approval.*, gateway.*, cli.*, display.*, slash.*, tips.*, ...)
pl.tui.yaml # 可选:hermes --tui 字符串
pl.desktop.yaml # 可选:Hermes 桌面端字符串
plugin.yaml:
name: hermes-lang-pl
version: 1.0.0
description: Hermes 波兰语语言包
provides_locales:
- id: pl # 小写 BCP-47 风格标签:pl, pt-br, zh-hant
endonym: Polski # 显示在语言切换器中
rtl: false # 从右向左书写时为 true(翻转桌面端布局)
provides_locales 条目也可以是纯 id(- pl);此时 endonym 默认为该 id。当清单声明了 provides_locales,插件加载器会自动注册每个 locales/<lang>[.tui|.desktop].yaml。
文件与 key
pl.yaml(核心) 镜像内置locales/en.yaml的结构。嵌套 YAML 展开为点分 key(approval.denied、gateway.goal_cleared)。复制en.yaml,翻译值,删掉你不想覆盖的部分。pl.tui.yaml/pl.desktop.yaml镜像 TUI 和桌面应用的英文目录。key 集合导出到 Hermes 仓库的locales/_keys.tui.json和locales/_keys.desktop.json,校验器即据此检查。- YAML 值必须是文本。数字、列表、
true/false或空值都会被拒绝。 - 切勿把 YAML 保留字(
on、off、yes、no)用作 key。
占位符
- 核心(Python)字符串使用与英文完全一致的命名占位符:
"⏳ 正在排空 {count} 个活跃 agent……"。保留英文值中的每个{name};占位符缺失或拼写错误会使 Hermes 对该 key 回退到未翻译字符串。 - TUI 和桌面端条目若其英文值是一个函数(接受参数),则在 YAML 中写成带位置占位符的字符串:
"{0}/{1} 个会话"。
校验
hermes plugins validate ./hermes-lang-pl
校验器会检查:每个声明的 id 都有 locales/<id>.yaml;每个文件可解析且仅含文本(非文本值是错误);并对该界面英文目录中不存在的 key 发出警告(列出它们——无害但不起作用)。.tui.yaml / .desktop.yaml 的检查在对应 _keys.*.json 导出存在时运行。
从 Python 注册(可选)
已有 Python 代码的插件可自行注册目录:
from pathlib import Path
def register(ctx):
here = Path(__file__).parent
ctx.register_locale("pl", here / "locales" / "pl.yaml", endonym="Polski")
ctx.register_locale("pl", {"approval": {"denied": " ✗ Odrzucono"}}) # dict,嵌套或扁平
ctx.register_locale("pl", here / "locales" / "pl.tui.yaml", surface="tui")
ctx.register_locale_dir(here / "locales") # 一次性全部注册
register_locale(lang, source, *, endonym=None, rtl=False, surface="core") 接受 YAML 路径或映射;surface 为 core、tui 或 desktop。插件卸载时注册随之撤销,且绝不改动 display.language。
无需插件的个人覆盖
把一个部分文件放进你的 Hermes 主目录:
# ~/.hermes/locales/en.yaml —— 只放你想改的 key
approval:
denied: " ✗ 不行。"
覆盖层仅作用于该 profile(命名 profile 为 ~/.hermes/profiles/<name>/locales/)。为 Hermes 未内置的语言提供覆盖层文件,也会让该语言变得可选。编辑会在下次启动或下次 display.language 变更时读取。
故障排查
display.language 的未知语言 ……——包未安装或未启用(hermes plugins list),或provides_locales中的 id 与文件名不匹配(pl需要locales/pl.yaml)。- 某个已翻译字符串仍显示英文——该 key 不在英文目录中(运行
hermes plugins validate;会列出未知 key),或占位符集合与英文不一致。 - 语言已列出,但 TUI/桌面端仍是英文——该包没有
.tui.yaml/.desktop.yaml;这些界面会渲染英文加上包所提供的内容。对于 16 种内置语言,TUI 在 Hermes 树中自带locales/<lang>.tui.yaml(桌面端把翻译打包在应用内),因此为这些语言之一制作的包只需包含它想覆盖的 key。