hermes-agent-features/web/src/i18n/zh-hant.ts
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

697 lines
25 KiB
TypeScript
Raw 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 type { Translations } from "./types";
export const zhHant: Translations = {
common: {
save: "儲存",
saving: "儲存中...",
cancel: "取消",
close: "關閉",
confirm: "確認",
delete: "刪除",
refresh: "重新整理",
retry: "重試",
search: "搜尋...",
loading: "載入中...",
create: "建立",
creating: "建立中...",
set: "設定",
replace: "取代",
clear: "清除",
live: "線上",
off: "離線",
enabled: "已啟用",
disabled: "已停用",
active: "使用中",
inactive: "未啟用",
unknown: "未知",
untitled: "未命名",
none: "無",
form: "表單",
noResults: "無結果",
of: "/",
page: "頁",
msgs: "訊息",
tools: "工具",
match: "符合",
other: "其他",
configured: "已設定",
removed: "已移除",
failedToToggle: "切換失敗",
failedToRemove: "移除失敗",
failedToReveal: "顯示失敗",
collapse: "收合",
expand: "展開",
general: "一般",
messaging: "訊息平台",
pluginLoadFailed:
"無法載入此外掛的指令碼。請檢查網路請求dashboard-plugins/…)以及伺服器上的外掛路徑。",
pluginNotRegistered:
"外掛指令碼未呼叫 register(),或執行時發生錯誤。請開啟瀏覽器主控台查看詳細資訊。",
},
app: {
brand: "Hermes Agent",
brandShort: "HA",
closeNavigation: "關閉導覽",
closeModelTools: "關閉模型與工具",
footer: {
org: "Nous Research",
},
activeSessionsLabel: "使用中工作階段:",
gatewayStatusLabel: "閘道狀態:",
gatewayStrip: {
failed: "啟動失敗",
off: "關閉",
running: "執行中",
starting: "啟動中",
stopped: "已停止",
},
nav: {
analytics: "分析",
chat: "對話",
config: "設定",
cron: "排程任務",
documentation: "文件",
keys: "金鑰",
logs: "日誌",
models: "模型",
profiles: "多代理設定檔",
plugins: "外掛管理",
sessions: "工作階段",
skills: "技能",
},
modelToolsSheetSubtitle: "與工具",
modelToolsSheetTitle: "模型",
navigation: "導覽",
openDocumentation: "在新分頁開啟文件",
openNavigation: "開啟導覽",
pluginNavSection: "外掛",
sessionsActiveCount: "{count} 個使用中",
statusOverview: "狀態總覽",
system: "系統",
webUi: "管理面板",
},
status: {
actionFailed: "動作失敗",
actionFinished: "已完成",
actions: "動作",
agent: "代理",
activeSessions: "使用中工作階段",
connected: "已連線",
connectedPlatforms: "已連線平台",
disconnected: "已中斷連線",
error: "錯誤",
failed: "失敗",
gateway: "閘道",
gatewayFailedToStart: "閘道啟動失敗",
lastUpdate: "最後更新",
noneRunning: "無",
notRunning: "未執行",
pid: "PID",
platformDisconnected: "已中斷",
platformError: "錯誤",
recentSessions: "近期工作階段",
restartGateway: "重新啟動閘道",
restartingGateway: "正在重新啟動閘道…",
running: "執行中",
runningRemote: "執行中(遠端)",
startFailed: "啟動失敗",
starting: "啟動中",
startedInBackground: "已於背景啟動 — 請查看日誌以取得進度",
stopped: "已停止",
updateHermes: "更新 Hermes",
updatingHermes: "正在更新 Hermes…",
waitingForOutput: "等待輸出…",
},
sessions: {
title: "工作階段",
searchPlaceholder: "搜尋訊息內容...",
noSessions: "尚無工作階段",
noMatch: "沒有符合的工作階段",
startConversation: "開始對話後將顯示於此",
noMessages: "尚無訊息",
untitledSession: "未命名工作階段",
deleteSession: "刪除工作階段",
confirmDeleteTitle: "刪除工作階段?",
confirmDeleteMessage:
"此操作將永久移除對話及其所有訊息,無法復原。",
sessionDeleted: "工作階段已刪除",
failedToDelete: "刪除工作階段失敗",
resumeInChat: "在對話中繼續",
previousPage: "上一頁",
nextPage: "下一頁",
roles: {
user: "使用者",
assistant: "助理",
system: "系統",
tool: "工具",
},
},
analytics: {
period: "時間範圍:",
totalTokens: "Token 總數",
totalSessions: "工作階段總數",
apiCalls: "API 呼叫",
dailyTokenUsage: "每日 Token 用量",
dailyBreakdown: "每日明細",
perModelBreakdown: "各模型用量明細",
topSkills: "常用技能",
skill: "技能",
loads: "代理載入",
edits: "代理管理",
lastUsed: "最近使用",
input: "輸入",
output: "輸出",
total: "總計",
noUsageData: "此時間範圍內無使用資料",
startSession: "開始工作階段後將於此處顯示分析資料",
date: "日期",
model: "模型",
tokens: "Token",
perDayAvg: "/日 平均",
acrossModels: "共 {count} 個模型",
inOut: "輸入 {input} / 輸出 {output}",
},
models: {
modelsUsed: "使用模型數",
estimatedCost: "預估費用",
tokens: "Token",
sessions: "工作階段",
avgPerSession: "平均/工作階段",
apiCalls: "API 呼叫",
toolCalls: "工具呼叫",
noModelsData: "此時間範圍內無模型使用資料",
startSession: "開始工作階段後將於此處顯示模型資料",
},
logs: {
title: "日誌",
autoRefresh: "自動重新整理",
file: "檔案",
level: "層級",
component: "元件",
lines: "行數",
noLogLines: "找不到日誌記錄",
},
cron: {
confirmDeleteMessage:
"將從排程移除此任務,此操作無法復原。",
confirmDeleteTitle: "刪除排程任務?",
newJob: "新增排程任務",
nameOptional: "名稱(選填)",
namePlaceholder: "例如:每日摘要",
prompt: "提示詞",
promptPlaceholder: "代理每次執行時應做什麼?",
schedule: "排程cron 運算式)",
schedulePlaceholder: "0 9 * * *",
deliverTo: "傳送至",
scheduledJobs: "已排程任務",
noJobs: "尚未設定排程任務。請於上方建立。",
last: "上次",
next: "下次",
pause: "暫停",
resume: "繼續",
triggerNow: "立即觸發",
delivery: {
local: "本機",
telegram: "Telegram",
discord: "Discord",
slack: "Slack",
email: "Email",
},
},
profiles: {
newProfile: "新增設定檔",
name: "名稱",
namePlaceholder: "例如coder、writer 等",
nameRequired: "名稱為必填",
nameRule:
"僅允許小寫字母、數字、底線及連字號;首字必須為字母或數字;最多 64 個字元。",
invalidName: "設定檔名稱無效",
cloneFromDefault: "從預設設定檔複製設定",
allProfiles: "設定檔",
noProfiles: "找不到設定檔。",
defaultBadge: "預設",
hasEnv: "env",
model: "模型",
skills: "技能",
rename: "重新命名",
editSoul: "編輯 SOUL.md",
soulSection: "SOUL.md人格 / 系統提示詞)",
soulPlaceholder: "# 此代理應如何運作…",
saveSoul: "儲存 SOUL",
soulSaved: "SOUL.md 已儲存",
openInTerminal: "複製 CLI 指令",
commandCopied: "已複製到剪貼簿",
copyFailed: "複製失敗",
confirmDeleteTitle: "刪除設定檔?",
confirmDeleteMessage:
"將永久刪除設定檔「{name}」 — 包括設定、金鑰、記憶、工作階段、技能、排程任務。無法復原。",
created: "已建立",
deleted: "已刪除",
renamed: "已重新命名",
},
pluginsPage: {
contextEngineLabel: "上下文引擎",
dashboardSlots: "面板插槽",
disableRuntime: "停用",
enableAfterInstall: "安裝後啟用",
enableRuntime: "啟用",
forceReinstall: "強制重新安裝(先刪除既有資料夾)",
headline:
"探索、安裝、啟用並更新 Hermes 外掛(對齊 `hermes plugins` CLI。",
identifierLabel: "Git 網址或 owner/repo",
inactive: "未啟用",
installBtn: "從 Git 安裝",
installHeading: "從 GitHub / Git URL 安裝",
installHint: "可使用 owner/repo 簡寫或完整的 https:// 或 git@ 複製網址。",
memoryProviderLabel: "記憶提供者",
missingEnvWarn: "請先在「金鑰」頁面設定下列項目,外掛才能執行:",
noDashboardTab: "無儀表板分頁",
openTab: "開啟",
orphanHeading: "僅儀表板擴充功能(無對應的 agent plugin.yaml",
pluginListHeading: "已安裝的外掛",
providerDefaults: "內建 / 預設",
providersHeading: "執行階段提供者外掛",
providersHint:
"會寫入 config.yamlmemory.provider留空為內建與 context.engine。下一個工作階段生效。",
refreshDashboard: "重新掃描儀表板擴充功能",
removeConfirm: "從 ~/.hermes/plugins/ 移除此外掛?",
removeHint: "僅可移除位於 ~/.hermes/plugins 下使用者安裝的外掛。",
rescanHeading: "SPA 外掛註冊表",
rescanHint: "在磁碟新增檔案後重新掃描,使儀表板側邊欄載入新的 manifest。",
runtimeHeading: "閘道執行階段YAML 外掛)",
saveProviders: "儲存提供者設定",
savedProviders: "提供者設定已儲存。",
sourceBadge: "來源",
authRequired: "需要驗證",
authRequiredHint: "執行此指令以完成驗證:",
updateGit: "Git pull",
versionBadge: "版本",
showInSidebar: "顯示於側邊欄",
hideFromSidebar: "從側邊欄隱藏",
},
skills: {
title: "技能",
searchPlaceholder: "搜尋技能與工具集...",
enabledOf: "已啟用 {enabled}/{total}",
all: "全部",
categories: "分類",
filters: "篩選",
noSkills: "找不到技能。技能由 ~/.hermes/skills/ 載入",
noSkillsMatch: "沒有符合搜尋或篩選條件的技能。",
skillCount: "{count} 個技能",
resultCount: "{count} 個結果",
noDescription: "無可用描述。",
toolsets: "工具集",
toolsetLabel: "{name} 工具集",
noToolsetsMatch: "沒有符合搜尋條件的工具集。",
setupNeeded: "需要設定",
disabledForCli: "CLI 已停用",
more: "還有 {count} 個",
},
config: {
configPath: "~/.hermes/config.yaml",
filters: "篩選",
sections: "分類",
exportConfig: "匯出設定為 JSON",
importConfig: "從 JSON 匯入設定",
resetDefaults: "重設為預設值",
resetScopeTooltip: "將{scope}重設為預設值",
confirmResetScope: "要將{scope}的所有設定重設為預設值嗎?此操作只更新表單,在按下「儲存」前不會寫入 config.yaml。",
resetScopeToast: "{scope}已重設為預設值 — 請檢視並儲存以套用",
rawYaml: "原始 YAML 設定",
searchResults: "搜尋結果",
fields: "個欄位",
noFieldsMatch: '沒有符合「{query}」的欄位',
configSaved: "設定已儲存",
yamlConfigSaved: "YAML 設定已儲存",
failedToSave: "儲存失敗",
failedToSaveYaml: "YAML 儲存失敗",
failedToLoadRaw: "載入原始設定失敗",
configImported: "設定已匯入 — 請檢視後儲存",
invalidJson: "無效的 JSON 檔案",
categories: {
general: "一般",
agent: "代理",
terminal: "終端機",
display: "顯示",
delegation: "委派",
memory: "記憶",
compression: "壓縮",
security: "安全性",
browser: "瀏覽器",
voice: "語音",
tts: "文字轉語音",
stt: "語音轉文字",
logging: "日誌",
discord: "Discord",
auxiliary: "輔助",
},
},
env: {
changesNote: "變更會立即儲存到磁碟。使用中的工作階段將自動取得新金鑰。",
confirmClearMessage:
"此變數已儲存的值將從 .env 檔案中移除。無法從介面復原。",
confirmClearTitle: "清除此金鑰?",
description: "管理儲存於下列位置的 API 金鑰與密鑰",
hideAdvanced: "隱藏進階選項",
showAdvanced: "顯示進階選項",
llmProviders: "LLM 提供者",
providersConfigured: "已設定 {configured}/{total} 個提供者",
getKey: "取得金鑰",
notConfigured: "{count} 個未設定",
notSet: "未設定",
keysCount: "{count} 個金鑰",
enterValue: "輸入值...",
replaceCurrentValue: "取代目前值({preview}",
showValue: "顯示實際值",
hideValue: "隱藏值",
},
oauth: {
title: "提供者登入OAuth",
providerLogins: "提供者登入OAuth",
description: "已連線 {connected}/{total} 個 OAuth 提供者。登入流程目前透過 CLI 執行;請點擊「複製指令」並貼到終端機完成設定。",
connected: "已連線",
expired: "已過期",
notConnected: "未連線。請在終端機執行 {command}。",
runInTerminal: "於終端機。",
noProviders: "未偵測到支援 OAuth 的提供者。",
login: "登入",
disconnect: "中斷連線",
managedExternally: "由外部管理",
copied: "已複製 ✓",
cli: "CLI",
copyCliCommand: "複製 CLI 指令(外部 / 備援用)",
connect: "連線",
sessionExpires: "工作階段將於 {time} 後過期",
initiatingLogin: "正在啟動登入流程…",
exchangingCode: "正在交換權杖…",
connectedClosing: "已連線!正在關閉…",
loginFailed: "登入失敗。",
sessionExpired: "工作階段已過期。請點擊「重試」開始新的登入。",
reOpenAuth: "重新開啟授權頁面",
reOpenVerification: "重新開啟驗證頁面",
submitCode: "提交代碼",
pasteCode: "貼上授權代碼(包含 #state 後綴亦可)",
waitingAuth: "等待您於瀏覽器中完成授權…",
enterCodePrompt: "已開啟新分頁。如有提示,請輸入此代碼:",
pkceStep1: "已於新分頁開啟 claude.ai。請登入並點擊「Authorize」。",
pkceStep2: "複製授權後顯示的授權代碼。",
pkceStep3: "將其貼到下方並提交。",
flowLabels: {
pkce: "瀏覽器登入PKCE",
device_code: "裝置代碼",
external: "外部 CLI",
},
expiresIn: "{time}後過期",
},
language: {
switchTo: "切換為英文",
},
theme: {
title: "主題",
switchTheme: "切換主題",
},
achievements: {
hero: {
kicker: "Agentic Gamerscore",
title: "Hermes Achievements",
subtitle:
"從真實工作階段歷史中獲得的 Hermes 可收集徽章。已知尚未達成的成就會顯示為「已發現」;秘密成就在首次出現相符行為之前保持隱藏。",
scan_subtitle:
"正在掃描 Hermes 工作階段歷史。在歷史紀錄較多時,首次掃描可能需要 510 秒。",
},
actions: {
rescan: "重新掃描",
},
stats: {
unlocked: "已解鎖",
unlocked_hint: "獲得的徽章",
discovered: "已發現",
discovered_hint: "已知,但尚未獲得",
secrets: "秘密",
secrets_hint: "在首次訊號出現前保持隱藏",
highest_tier: "最高等級",
highest_tier_hint: "Copper → Silver → Gold → Diamond → Olympian",
latest: "最新",
latest_hint_empty: "多多執行 Hermes",
none_yet: "尚無",
},
state: {
unlocked: "已解鎖",
discovered: "已發現",
secret: "秘密",
},
tier: {
target: "目標 {tier}",
hidden: "隱藏",
complete: "已完成",
objective: "目標",
},
progress: {
hidden: "隱藏",
},
scan: {
building_headline: "正在建立成就檔案…",
building_detail:
"正在讀取工作階段、工具呼叫、模型中繼資料以及解鎖狀態。",
starting_headline: "正在開始成就掃描…",
progress_detail:
"已掃描 {scanned} / {total} 個工作階段 · {pct}%。隨著更多歷史串入,徽章會陸續解鎖。",
idle_detail:
"正在讀取工作階段、工具呼叫、模型中繼資料以及解鎖狀態。徽章解鎖後會顯示在這裡。",
},
guide: {
tiers_header: "等級",
secret_header: "秘密成就",
secret_body:
"秘密成就會隱藏其確切觸發條件。一旦 Hermes 偵測到相關訊號,卡片便會變為「已發現」並顯示其需求。",
scan_status_header: "掃描狀態",
scan_status_body:
"Hermes 正在對本機歷史進行一次掃描,之後卡片會自動出現。即使需要幾秒鐘,也並未卡住。",
what_scanned_header: "掃描內容",
what_scanned_body:
"工作階段、工具呼叫、模型中繼資料、錯誤、成就以及本機解鎖狀態。",
},
card: {
share_title: "分享此成就",
share_label: "分享 {name}",
share_text: "分享",
how_to_reveal: "如何揭示",
what_counts: "計入條件",
evidence_label: "證據",
evidence_session_fallback: "工作階段",
no_evidence: "尚無證據",
},
latest: {
header: "最近解鎖",
},
empty: {
no_secrets_header: "本次掃描已沒有隱藏的秘密。",
no_secrets_body:
"提示:秘密通常源自異常失敗或進階使用者的行為模式 —— 連接埠衝突、權限阻擋、缺少環境變數、YAML 錯誤、Docker 衝突、回復或檢查點的使用、快取命中,或在大量紅色錯誤後做出的小小修正。",
},
filters: {
all_categories: "全部",
visibility_all: "全部",
visibility_unlocked: "已解鎖",
visibility_discovered: "已發現",
visibility_secret: "秘密",
},
share: {
dialog_label: "分享成就",
header: "分享:{name}",
close: "關閉",
rendering: "繪製中…",
card_alt: "{name} 分享卡片",
error_generic: "發生錯誤。",
x_title: "在 X 中開啟預先填寫的貼文",
x_button: "在 X 上分享",
copy_title: "複製圖片以貼上到你的貼文",
copy_button: "複製圖片",
copied: "已複製 ✓",
download_button: "下載 PNG",
hint:
"「在 X 上分享」會在新分頁中開啟預先填寫的貼文。若想附上 1200×630 的徽章,請先點擊「複製圖片」—— X 允許你直接貼到推文編輯器中。「下載 PNG」會將檔案儲存下來可在任何地方使用。",
clipboard_unsupported:
"此瀏覽器不支援剪貼簿圖片複製 —— 請改用「下載」。",
tweet_text: "Just unlocked {tier_part}\"{name}\" in Hermes Agent ☤",
},
},
kanban: {
loading: "正在載入看板…",
loadFailed: "載入看板失敗:",
loadFailedHint:
"後端會在首次讀取時自動建立 kanban.db。如果問題持續請檢查儀表板日誌。",
board: "看板",
newBoard: "+ 新增看板",
newBoardTitle: "新增看板",
newBoardDescription:
"看板可將不相關的工作流分開——每個專案、程式碼庫或網域一個看板。一個看板上的工作者不會看到另一個看板的任務。",
slug: "識別碼",
slugHint: "— 小寫字母、連字號,例如 atm10-server",
displayName: "顯示名稱",
displayNameHint: "(選填)",
description: "描述",
descriptionHint: "(選填)",
icon: "圖示",
iconHint: "(單一字元或表情符號)",
switchAfterCreate: "建立後切換到此看板",
cancel: "取消",
creating: "建立中…",
createBoard: "建立看板",
search: "搜尋",
filterCards: "篩選卡片…",
tenant: "租戶",
allTenants: "全部租戶",
assignee: "負責人",
allProfiles: "全部設定檔",
showArchived: "顯示已封存",
lanesByProfile: "依設定檔分組",
nudgeDispatcher: "觸發排程器",
refresh: "重新整理",
selected: "已選取",
complete: "完成",
archive: "封存",
apply: "套用",
clear: "清除",
createTask: "在此欄建立任務",
noTasks: "— 沒有任務 —",
unassigned: "未指派",
untitled: "(無標題)",
loadingDetail: "載入中…",
addComment: "新增留言…(按 Enter 送出)",
comment: "留言",
status: "狀態",
workspace: "工作區",
skills: "技能",
createdBy: "建立者",
result: "結果",
comments: "留言",
events: "事件",
runHistory: "執行紀錄",
workerLog: "工作者日誌",
loadingLog: "正在載入日誌…",
noWorkerLog:
"— 尚無工作者日誌(任務尚未啟動或日誌已被輪替)—",
noDescription: "— 沒有描述 —",
noComments: "— 沒有留言 —",
edit: "編輯",
save: "儲存",
dependencies: "相依項目",
parents: "上層任務:",
children: "下層任務:",
none: "無",
addParent: "— 新增上層任務 —",
addChild: "— 新增下層任務 —",
removeDependency: "移除相依項目",
block: "封鎖",
unblock: "解除封鎖",
notifyHomeChannels: "通知主要頻道",
diagnostics: "診斷",
hide: "隱藏",
show: "顯示",
attention: "注意",
tasksNeedAttention: "個任務需要關注",
taskNeedsAttention: "1 個任務需要關注",
diagnostic: "診斷",
open: "開啟",
close: "關閉 (Esc)",
reassignTo: "重新指派給:",
copied: "已複製",
copyCommand: "複製指令到剪貼簿",
reclaim: "收回",
reassign: "重新指派",
renderingError: "看板分頁發生繪製錯誤",
reloadView: "重新載入檢視",
wsAuthFailed:
"WebSocket 驗證失敗 — 請重新載入頁面以更新工作階段權杖。",
markDone: "將 {n} 個任務標記為完成?",
markArchived: "封存 {n} 個任務?",
warning: "警告",
phantomIds: "幽靈 ID",
active: "進行中",
ended: "已結束",
noProfile: "(無設定檔)",
showAllAttempts: "顯示所有嘗試",
sendingUpdates: "正在傳送更新到",
sendNotifications: "傳送完成 / 封鎖 / 放棄通知到",
archiveBoardConfirm:
"封存看板「{name}」?看板將會移至 boards/_archived/,以便日後復原。此看板上的任務將不再出現在 UI 中的任何位置。",
archiveBoardTitle: "封存此看板",
boardSwitcherHint: "看板可將不相關的工作流分開",
taskCreatedWarning: "任務已建立,但:",
moveFailed: "移動失敗:",
bulkFailed: "批次操作:",
completionBlockedHallucination: "⚠ 完成被封鎖 — 幽靈卡片 ID",
suspectedHallucinatedReferences: "⚠ 文字內容引用了幽靈卡片 ID",
pickProfileFirst: "請先選擇一個設定檔。",
unblockedMessage: "已解除封鎖 {id}。任務已準備好進入下一輪排程。",
unblockFailed: "解除封鎖失敗:",
reclaimedMessage: "已收回 {id}。任務已回到就緒狀態。",
reclaimFailed: "收回失敗:",
reassignedMessage: "已將 {id} 重新指派給 {profile}。",
reassignFailed: "重新指派失敗:",
selectForBulk: "選取以進行批次操作",
clickToEdit: "點擊以編輯",
clickToEditAssignee: "點擊以編輯負責人",
emptyAssignee: "(留空 = 取消指派)",
columnLabels: {
triage: "待分類",
todo: "待辦",
ready: "就緒",
running: "進行中",
blocked: "已封鎖",
done: "已完成",
archived: "已封存",
},
columnHelp: {
triage: "原始想法 — 規格制定者將完善規格",
todo: "等待相依項目或尚未指派",
ready: "已指派,等待排程器輪詢",
running: "已被工作者領取 — 執行中",
blocked: "工作者請求人工輸入",
done: "已完成",
archived: "已封存",
},
confirmDone:
"將此任務標記為完成?工作者的領取將被釋放,下層相依任務將變為就緒。",
confirmArchive:
"封存此任務?它將從預設看板檢視中消失。",
confirmBlocked:
"將此任務標記為已封鎖?工作者的領取將被釋放。",
completionSummary:
"{label} 的完成摘要。這將作為任務結果儲存。",
completionSummaryRequired:
"在將任務標記為完成之前,必須提供完成摘要。",
triagePlaceholder: "粗略的想法 — AI 將完善規格…",
taskTitlePlaceholder: "新任務標題…",
specifier: "規格制定者",
assigneePlaceholder: "負責人",
priority: "優先順序",
skillsPlaceholder:
"技能選填以逗號分隔translation、github-code-review",
noParent: "— 無上層任務 —",
workspacePathDir: "工作區路徑(必填,例如 ~/projects/my-app",
workspacePathOptional:
"工作區路徑(選填,留空則依負責人推導)",
logTruncated: "(顯示最後 100 KB — 完整日誌位於 ",
logAt: "",
},
};