mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
fix(kanban): i18n wake messages — address review feedback on #54872
Addresses @tonydwb's review on PR #54872 (12:05 UTC, 2026-06-29): > the hardcoded Chinese text in the wake messages (lines 118-128 of > the diff) should be replaced with English or internationalized. > The rest of the codebase uses English for user-facing messages, > and hardcoded Chinese will confuse non-Chinese users. Consider > using a constants dict or the existing i18n infrastructure. Used the existing i18n infrastructure (agent/i18n.py::t()) — the same surface gateway/run.py and slash_commands.py already use for static user-facing strings. ## Changes - gateway/kanban_watchers.py: import `t` from agent.i18n; replace the hardcoded Chinese strings in the synthetic wake-up message with t("gateway.kanban.wake.*") lookups. Behavior unchanged for zh users (zh catalog preserves the original Chinese phrasing). - locales/en.yaml: new `gateway.kanban.wake.*` baseline keys (English): completed / gave_up / crashed / timed_out / blocked / status_default / status_joiner / message (with {task_id} {status} {title} {assignee} {board} placeholders). - locales/zh.yaml: Chinese translation of the new keys, preserving the exact wording the original code used (so existing zh users see no visible change). - locales/{zh-hant,ja,de,es,fr,tr,uk,af,ko,it,ga,pt,ru,hu}.yaml: added the same key set with English fallback values. The i18n invariant test (tests/agent/test_i18n.py::test_catalog_keys_match_english) requires every catalog to carry the same key set as en.yaml; native translations can land incrementally without breaking users (the loader falls back to en.yaml per-key when a translation is missing, but the key must still exist). ## Verification - scripts/run_tests.sh tests/agent/test_i18n.py tests/gateway/test_kanban_watchers_mixin.py tests/gateway/test_kanban_notifier.py tests/gateway/test_kanban_notifier_watcher_dispatch_gate.py → 60 passed, 0 failed (i18n catalog parity + placeholders parity + existing kanban notifier behavior). - Manual: with HERMES_LANGUAGE=en, t("gateway.kanban.wake.completed") returns "completed"; with HERMES_LANGUAGE=zh, returns "已完成"; with HERMES_LANGUAGE=ja (translation pending), falls back to "completed" per-key.
This commit is contained in:
parent
c69643026a
commit
3545d74915
17 changed files with 159 additions and 11 deletions
|
|
@ -18,6 +18,8 @@ import time
|
|||
from pathlib import Path
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
from agent.i18n import t
|
||||
|
||||
# Match the logger run.py uses (logging.getLogger(__name__) where __name__ ==
|
||||
# "gateway.run") so extracted log records keep their original logger name.
|
||||
logger = logging.getLogger("gateway.run")
|
||||
|
|
@ -486,17 +488,19 @@ class GatewayKanbanWatchersMixin:
|
|||
_title = (task.title if task else sub["task_id"])[:120]
|
||||
_assignee = task.assignee if task else ""
|
||||
_parts = []
|
||||
if "completed" in _wake_kinds: _parts.append("已完成")
|
||||
if "gave_up" in _wake_kinds: _parts.append("已放弃(重试次数耗尽)")
|
||||
if "crashed" in _wake_kinds: _parts.append("崩溃(worker 异常退出),dispatcher 将重试")
|
||||
if "timed_out" in _wake_kinds: _parts.append("超时,dispatcher 将重试")
|
||||
if "blocked" in _wake_kinds: _parts.append("被阻塞,需要处理")
|
||||
_status = ",".join(_parts) or "状态变化"
|
||||
_synth = (
|
||||
f"[kanban] 任务 {sub['task_id']} {_status}。\n"
|
||||
f"标题: {_title}\n执行者: @{_assignee}\n"
|
||||
f"看板: {board_slug}\n\n"
|
||||
f"请检查结果或决定下一步动作。"
|
||||
if "completed" in _wake_kinds: _parts.append(t("gateway.kanban.wake.completed"))
|
||||
if "gave_up" in _wake_kinds: _parts.append(t("gateway.kanban.wake.gave_up"))
|
||||
if "crashed" in _wake_kinds: _parts.append(t("gateway.kanban.wake.crashed"))
|
||||
if "timed_out" in _wake_kinds: _parts.append(t("gateway.kanban.wake.timed_out"))
|
||||
if "blocked" in _wake_kinds: _parts.append(t("gateway.kanban.wake.blocked"))
|
||||
_status = t("gateway.kanban.wake.status_joiner").join(_parts) or t("gateway.kanban.wake.status_default")
|
||||
_synth = t(
|
||||
"gateway.kanban.wake.message",
|
||||
task_id=sub["task_id"],
|
||||
status=_status,
|
||||
title=_title,
|
||||
assignee=_assignee,
|
||||
board=board_slug,
|
||||
)
|
||||
from gateway.session import SessionSource
|
||||
from gateway.platforms.base import MessageEvent, MessageType
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(ingeteken — jy sal in kennis gestel word wanneer {task_id} voltooi of vasval)"
|
||||
truncated_suffix: "… (afgekap; gebruik `hermes kanban …` in jou terminale vir volle uitvoer)"
|
||||
no_output: "(geen uitvoer)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "Geen persoonlikhede opgestel in `{path}/config.yaml` nie"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(abonniert — Sie werden benachrichtigt, wenn {task_id} abgeschlossen oder blockiert wird)"
|
||||
truncated_suffix: "… (gekürzt; verwenden Sie `hermes kanban …` im Terminal für die vollständige Ausgabe)"
|
||||
no_output: "(keine Ausgabe)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "Keine Persönlichkeiten in `{path}/config.yaml` konfiguriert"
|
||||
|
|
|
|||
|
|
@ -164,6 +164,15 @@ gateway:
|
|||
subscribed_suffix: "(subscribed — you'll be notified when {task_id} completes or blocks)"
|
||||
truncated_suffix: "… (truncated; use `hermes kanban …` in your terminal for full output)"
|
||||
no_output: "(no output)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "No personalities configured in `{path}/config.yaml`"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(suscrito — recibirás una notificación cuando {task_id} termine o se bloquee)"
|
||||
truncated_suffix: "… (truncado; usa `hermes kanban …` en tu terminal para la salida completa)"
|
||||
no_output: "(sin salida)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "No hay personalidades configuradas en `{path}/config.yaml`"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(abonné — vous serez notifié lorsque {task_id} se terminera ou sera bloqué)"
|
||||
truncated_suffix: "… (tronqué ; utilisez `hermes kanban …` dans votre terminal pour la sortie complète)"
|
||||
no_output: "(aucune sortie)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "Aucune personnalité configurée dans `{path}/config.yaml`"
|
||||
|
|
|
|||
|
|
@ -153,6 +153,15 @@ gateway:
|
|||
subscribed_suffix: "(síntiúsaithe — cuirfear in iúl duit nuair a chríochnóidh nó a stopfaidh {task_id})"
|
||||
truncated_suffix: "… (giorraithe; úsáid `hermes kanban …` i do theirminéal le haghaidh aschur iomláin)"
|
||||
no_output: "(gan aschur)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "Níl aon phearsantachtaí cumraithe in `{path}/config.yaml`"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(feliratkozva — értesítést kapsz, ha a {task_id} befejeződik vagy elakad)"
|
||||
truncated_suffix: "… (csonkítva; használd a `hermes kanban …` parancsot a terminálban a teljes kimenethez)"
|
||||
no_output: "(nincs kimenet)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "Nincs személyiség beállítva itt: `{path}/config.yaml`"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(iscritto — riceverai notifica quando {task_id} verrà completato o si bloccherà)"
|
||||
truncated_suffix: "… (troncato; usa `hermes kanban …` nel terminale per l'output completo)"
|
||||
no_output: "(nessun output)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "Nessuna personalità configurata in `{path}/config.yaml`"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(購読しました — {task_id} が完了またはブロックされたときに通知されます)"
|
||||
truncated_suffix: "… (切り詰めました; 完全な出力にはターミナルで `hermes kanban …` を使用してください)"
|
||||
no_output: "(出力なし)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "`{path}/config.yaml` に人格が設定されていません"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(구독 중 — {task_id}이(가) 완료되거나 차단되면 알림을 받습니다)"
|
||||
truncated_suffix: "… (잘림; 전체 출력을 보려면 터미널에서 `hermes kanban …`을 사용하세요)"
|
||||
no_output: "(출력 없음)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "`{path}/config.yaml`에 구성된 성격이 없습니다"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(subscrito — receberás uma notificação quando {task_id} terminar ou bloquear)"
|
||||
truncated_suffix: "… (truncado; usa `hermes kanban …` no teu terminal para a saída completa)"
|
||||
no_output: "(sem saída)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "Nenhuma personalidade configurada em `{path}/config.yaml`"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(подписка оформлена — вы получите уведомление, когда {task_id} завершится или будет заблокирован)"
|
||||
truncated_suffix: "… (сокращено; используйте `hermes kanban …` в терминале для полного вывода)"
|
||||
no_output: "(нет вывода)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "В `{path}/config.yaml` не настроено ни одной личности"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(abone olundu — {task_id} tamamlandığında veya engellendiğinde bildirim alacaksınız)"
|
||||
truncated_suffix: "… (kısaltıldı; tam çıktı için terminalinizde `hermes kanban …` komutunu kullanın)"
|
||||
no_output: "(çıktı yok)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "`{path}/config.yaml` içinde yapılandırılmış kişilik yok"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(підписано — ви отримаєте сповіщення, коли {task_id} завершиться або буде заблоковано)"
|
||||
truncated_suffix: "… (скорочено; використовуйте `hermes kanban …` у терміналі для повного виводу)"
|
||||
no_output: "(немає виводу)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "У `{path}/config.yaml` не налаштовано жодної особистості"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(已訂閱 — 當 {task_id} 完成或被封鎖時將通知您)"
|
||||
truncated_suffix: "…(已截斷;如需完整輸出請在終端機執行 `hermes kanban …`)"
|
||||
no_output: "(無輸出)"
|
||||
wake:
|
||||
completed: "completed"
|
||||
gave_up: "gave up (retries exhausted)"
|
||||
crashed: "crashed (worker exited); dispatcher will retry"
|
||||
timed_out: "timed out; dispatcher will retry"
|
||||
blocked: "blocked; needs attention"
|
||||
status_default: "status changed"
|
||||
status_joiner: ", "
|
||||
message: "[kanban] Task {task_id} {status}.\nTitle: {title}\nAssignee: @{assignee}\nBoard: {board}\n\nCheck the result or decide the next step."
|
||||
|
||||
personality:
|
||||
none_configured: "`{path}/config.yaml` 中未設定人格"
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ gateway:
|
|||
subscribed_suffix: "(已订阅 — 当 {task_id} 完成或被阻塞时将通知您)"
|
||||
truncated_suffix: "…(已截断;如需完整输出请在终端运行 `hermes kanban …`)"
|
||||
no_output: "(无输出)"
|
||||
wake:
|
||||
completed: "已完成"
|
||||
gave_up: "已放弃(重试次数耗尽)"
|
||||
crashed: "崩溃(worker 异常退出),dispatcher 将重试"
|
||||
timed_out: "超时,dispatcher 将重试"
|
||||
blocked: "被阻塞,需要处理"
|
||||
status_default: "状态变化"
|
||||
status_joiner: ","
|
||||
message: "[kanban] 任务 {task_id} {status}。\n标题: {title}\n执行者: @{assignee}\n看板: {board}\n\n请检查结果或决定下一步动作。"
|
||||
|
||||
personality:
|
||||
none_configured: "`{path}/config.yaml` 中未配置人格设定"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue