diff --git a/CHANGELOG.md b/CHANGELOG.md index 092cde30..8edf09e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ ## [Unreleased] +## [v0.51.217] — 2026-06-02 — Release GK (stage-p2f — decode and complete zh-Hant locale strings) + +### Changed +- Decoded the `zh-Hant` (Traditional Chinese) locale block from `\u`-escaped sequences to literal Chinese text and backfilled missing keys so `zh-Hant` now has full coverage of the English key set. Makes future locale review readable and prevents newer UI keys from falling back to English for Traditional Chinese users. Locale-only — no runtime behavior change (#3414, @PeterDaveHello). + +### Fixed +- Added the missing `provider_mismatch_warning` string to the French (`fr`) locale. It was absent entirely; the gap was masked by a stale duplicate of the same key in the `zh-Hant` block that #3414 removed, so all locales now carry the key. + ## [v0.51.216] — 2026-06-02 — Release GJ (stage-p2e — fix consecutive-user-turn rejection on strict chat templates) ### Fixed diff --git a/static/i18n.js b/static/i18n.js index 00a7f33a..2ef123c4 100644 --- a/static/i18n.js +++ b/static/i18n.js @@ -9031,39 +9031,60 @@ const LOCALES = { // Traditional Chinese (zh-Hant) 'zh-Hant': { + + offline_title: '連線中斷', + offline_browser_detail: '瀏覽器回報此裝置目前離線。', + offline_network_detail: 'Hermes 目前無法從這個瀏覽器連上。', + offline_autorefresh: 'Hermes 重新連線後,系統會自動重新整理此頁面。', + offline_check_now: '立即檢查', + offline_checking: '正在檢查…', + offline_stream_waiting: '連線中斷。等待重新整理…', _lang: 'zh-Hant', - _label: '\u7e41\u9ad4\u4e2d\u6587', + _label: '繁體中文', _speech: 'zh-TW', // boot.js - cancelling: '\u6b63\u5728\u53d6\u6d88...', - cancel_failed: '\u53d6\u6d88\u5931\u6557\uff1a', - mic_denied: '\u9ea6\u514b\u98a8\u8a2a\u554f\u88ab\u62d2\u7d75\uff0c\u8acb\u6aa2\u67e5\u700f\u89bd\u5668\u6b0a\u9650\u3002', - mic_no_speech: '\u6c92\u6709\u6aa2\u6e2c\u5230\u8a71\u97f3\uff0c\u8acb\u518d\u5617\u4e00\u6b21\u3002', - mic_network: '\u8a71\u97f3\u8b58\u5225\u76ee\u524d\u4e0d\u53ef\u7528\u3002', - mic_error: '\u8a71\u97f3\u8f38\u5165\u51fa\u932f\uff1a', - session_imported: '\u6703\u8a71\u5df2\u5c0e\u5165', - import_failed: '\u5c0e\u5165\u5931\u6557\uff1a', - import_invalid_json: 'JSON \u7121\u6548', - image_pasted: '\u5df2\u7c98\u8cbc\u5716\u7247\uff1a', + cancelling: '正在取消……', + cancel_failed: '取消失敗:', + mic_denied: '麥克風存取遭拒。請檢查瀏覽器權限。', + mic_no_speech: '未偵測到語音。請再試一次。', + mic_network: '語音辨識無法使用。', + mic_error: '語音輸入錯誤:', + // Composer voice buttons (#1488 — distinct labels for dictation vs voice mode) + voice_dictate: '聽寫', + voice_dictate_active: '停止聽寫', + voice_recording_active: '停止錄音', + voice_mode_toggle: '語音模式', + voice_mode_toggle_active: '離開語音模式', + // Turn-based voice mode (#1333) + voice_listening: '正在聆聽…', + voice_speaking: '正在說話…', + voice_thinking: '正在思考…', + voice_error: '此瀏覽器不支援語音功能', + voice_mode_active: '語音模式已開啟', + voice_mode_off: '語音模式已關閉', + session_imported: '已匯入對話', + import_failed: '匯入失敗:', + import_invalid_json: '無效的 JSON', + image_pasted: '已貼上圖片:', // messages.js - edit_message: '\u7de8\u8f2f\u8a0a\u606f', - regenerate: '\u91cd\u65b0\u751f\u6210\u56de\u8986', - copy: '\u8907\u88fd', - copied: '\u5df2\u8907\u88fd', - copy_failed: '\u8907\u88fd\u5931\u6557', + edit_message: '編輯訊息', + regenerate: '重新產生回覆', + copy: '複製', + copied: '已複製!', + copy_failed: '複製失敗', selected_text_reply: '用所選內容回覆', - selected_text_reply_title: '將所選聊天文字作為引用上下文附加', + selected_text_reply_title: '將所選聊天文字附加為引用脈絡', selected_text_reply_appended: '已將所選文字加入輸入框', diff_loading: '載入 diff', diff_error: '無法載入 patch 檔案', - diff_too_large: 'Patch 檔案過大,無法內聯顯示', + diff_too_large: 'Patch 檔案太大,無法直接顯示', tree_view: '樹狀', raw_view: '原始', parse_failed_note: '解析失敗', - you: '\u4f60', + you: '你', mcp_servers_title: 'MCP 伺服器', - mcp_servers_desc: '管理 config.yaml 中設定的 MCP 伺服器。', + mcp_servers_desc: '檢視 config.yaml 中設定的 MCP 伺服器。', mcp_no_servers: '未設定 MCP 伺服器。', mcp_add_server: '+ 新增伺服器', mcp_field_name: '伺服器名稱', @@ -9084,216 +9105,374 @@ const LOCALES = { mcp_deleted: 'MCP 伺服器已刪除。', mcp_delete_failed: '刪除 MCP 伺服器失敗。', mcp_load_failed: '載入 MCP 伺服器失敗。', - mcp_restart_hint: 'Server changes are read-only here for now. Edit config.yaml and restart Hermes for changes to take effect.', - mcp_toggle_followup: 'Enable/disable controls are intentionally deferred until MCP reload semantics are explicit.', - mcp_status_active: 'Active', - mcp_status_configured: 'Configured', - mcp_status_disabled: 'Disabled', - mcp_status_invalid_config: 'Invalid config', - mcp_status_unknown: 'Unknown', - mcp_tool_count: '{0} tools', - mcp_enabled_yes: 'Enabled', - mcp_enabled_no: 'Disabled', - mcp_enable_server: 'Enable this MCP server', - mcp_disable_server: 'Disable this MCP server', - mcp_enabled_toast: (name) => `MCP server "${name}" enabled.`, - mcp_disabled_toast: (name) => `MCP server "${name}" disabled.`, - mcp_toggle_failed: 'Failed to update MCP server.', - mcp_tools_title: 'MCP Tools', - mcp_tools_desc: 'Search known tools across active MCP servers.', - mcp_tools_search_placeholder: 'Search tools by name, server, or description…', - mcp_tools_no_tools: 'No MCP tools are available from the active runtime inventory.', - mcp_tools_no_matches: 'No MCP tools match your search.', - mcp_tools_load_failed: 'Failed to load MCP tools.', - mcp_tools_schema_empty: 'No schema parameters.', - mcp_tools_runtime_note: 'Tool inventory only uses already-known active MCP runtime data; the WebUI does not start or probe servers.', - mcp_tools_summary_no_matches: (query,total) => `No MCP tools matching “${query}” (${total} total MCP tools).`, - mcp_tools_summary_none: 'No MCP tools to show.', - mcp_tools_summary_matching: (query) => ` matching “${query}”`, - mcp_tools_summary_total_note: (total) => ` (${total} total MCP tools)`, - mcp_tools_summary_showing: (start,end,filtered,searchNote,totalNote,page,pages) => `Showing ${start}-${end} of ${filtered} MCP tools${searchNote}${totalNote}. Page ${page} of ${pages}.`, - mcp_tools_page_size_prefix: 'Show', - mcp_tools_page_size_suffix: 'per page', - mcp_tools_per_page_aria: 'MCP tools per page', - mcp_tools_inactive_configured_servers: (servers) => `Configured but inactive in this WebUI runtime: ${servers}.`, - mcp_tools_pagination_label: 'MCP tools pagination', - mcp_tools_previous_page: '‹ Prev', - mcp_tools_previous_page_aria: 'Previous MCP tools page', - mcp_tools_next_page: 'Next ›', - mcp_tools_next_page_aria: 'Next MCP tools page', - thinking: '\u601d\u8003\u904e\u7a0b', - expand_all: '\u5168\u90e8\u5c55\u958b', - collapse_all: '\u5168\u90e8\u6298\u758a', - edit_failed: '\u7de8\u8f2f\u5931\u6557\uff1a', - regen_failed: '\u91cd\u65b0\u751f\u6210\u5931\u6557\uff1a', - reconnect_active: '\u56de\u8986\u4ecd\u5728\u751f\u6210\u4e2d\uff0c\u6e96\u5099\u597d\u5f8c\u8981\u91cd\u65b0\u52a0\u8f09\u55ce\uff1f', - reconnect_finished: '\u4f60\u96e2\u958b\u6642\u6709\u56de\u8986\u6b63\u5728\u751f\u6210\uff0c\u8a0a\u606f\u5167\u5bb9\u53ef\u80fd\u5df2\u7d93\u66f4\u65b0\u3002', + mcp_restart_hint: '伺服器變更目前在此為唯讀。請編輯 config.yaml 並重新啟動 Hermes,讓變更生效。', + mcp_toggle_followup: '啟用/停用控制項會等到 MCP 重新載入語意明確後再加入。', + mcp_status_active: '作用中', + mcp_status_configured: '已設定', + mcp_status_disabled: '已停用', + mcp_status_invalid_config: '設定無效', + mcp_status_unknown: '未知', + mcp_tool_count: '{0} 個工具', + mcp_enabled_yes: '已啟用', + mcp_enabled_no: '已停用', + mcp_enable_server: '啟用此 MCP 伺服器', + mcp_disable_server: '停用此 MCP 伺服器', + mcp_enabled_toast: (name) => `MCP 伺服器「${name}」已啟用。`, + mcp_disabled_toast: (name) => `MCP 伺服器「${name}」已停用。`, + mcp_toggle_failed: '更新 MCP 伺服器失敗。', + mcp_tools_title: 'MCP 工具', + mcp_tools_desc: '搜尋作用中 MCP 伺服器中的已知工具。', + mcp_tools_search_placeholder: '依名稱、伺服器或描述搜尋工具…', + mcp_tools_no_tools: '作用中 runtime inventory 沒有可用的 MCP 工具。', + mcp_tools_no_matches: '沒有符合搜尋條件的 MCP 工具。', + mcp_tools_load_failed: '載入 MCP 工具失敗。', + mcp_tools_schema_empty: '沒有 schema 參數。', + mcp_tools_runtime_note: '工具清單只使用已知且作用中的 MCP runtime 資料;WebUI 不會啟動或探測伺服器。', + mcp_tools_summary_no_matches: (query,total) => `沒有符合「${query}」的 MCP 工具(共 ${total} 個 MCP 工具)。`, + mcp_tools_summary_none: '沒有可顯示的 MCP 工具。', + mcp_tools_summary_matching: (query) => `,符合「${query}」`, + mcp_tools_summary_total_note: (total) => `(共 ${total} 個 MCP 工具)`, + mcp_tools_summary_showing: (start,end,filtered,searchNote,totalNote,page,pages) => `顯示第 ${start}-${end} 個,共 ${filtered} 個 MCP 工具${searchNote}${totalNote}。第 ${page} / ${pages} 頁。`, + mcp_tools_page_size_prefix: '每頁顯示', + mcp_tools_page_size_suffix: '筆', + mcp_tools_per_page_aria: '每頁 MCP 工具數量', + mcp_tools_inactive_configured_servers: (servers) => `已設定但未在此 WebUI runtime 中作用:${servers}。`, + mcp_tools_pagination_label: 'MCP 工具分頁', + mcp_tools_previous_page: '‹ 上一頁', + mcp_tools_previous_page_aria: '上一頁 MCP 工具', + mcp_tools_next_page: '下一頁 ›', + mcp_tools_next_page_aria: '下一頁 MCP 工具', + // PDF preview (#480) + pdf_loading: '正在載入 PDF {0}…', + pdf_too_large: 'PDF 太大,無法直接預覽', + pdf_no_pages: 'PDF 沒有頁面', + pdf_error: 'PDF 預覽轉譯失敗', + pdf_download: '下載 PDF', + // HTML sandbox preview (#482) + html_loading: '正在載入 HTML 預覽…', + html_too_large: 'HTML 太大,無法直接預覽', + html_error: 'HTML 預覽轉譯失敗', + html_open_full: '開啟完整頁面', + html_sandbox_label: 'HTML 預覽(沙盒)', + thinking: '思考中', + expand_all: '全部展開', + collapse_all: '全部收合', + edit_failed: '編輯失敗:', + regen_failed: '重新產生失敗:', + reconnect_active: '回覆仍在產生中。完成後要重新載入嗎?', + reconnect_finished: '離開時仍有回覆正在處理。訊息可能已經更新。', // approval card - approval_heading: '\u9700\u8981\u5be9\u6838', - approval_desc_prefix: '\u6aa2\u6e2c\u5230\u5371\u96aa\u547d\u4ee4', - approval_btn_once: '\u5141\u8a31\u4e00\u6b21', - approval_btn_once_title: '\u5141\u8a31\u57f7\u884c\u6b64\u547d\u4ee4\u4e00\u6b21\uff08Enter\uff09', - approval_btn_session: '\u672c\u6b21\u5141\u8a31', - approval_btn_session_title: '\u672c\u6b21\u6703\u8a71\u671f\u9593\u5141\u8a31', - approval_btn_always: '始終允許', - approval_btn_always_title: '始終允許此命令模式', - approval_btn_deny: '\u62d2\u7d55', - approval_btn_deny_title: '\u62d2\u7edd — \u4e0d\u57f7\u884c\u6b64\u547d\u4ee4', - approval_responding: '\u8655\u7406\u4e2d\u2026', - clarify_heading: '\u9700\u8981\u91d0\u6e05', - clarify_hint: '\u8acb\u9078\u64c7\u4e00\u500b\u9078\u9805\uff0c\u6216\u5728\u4e0b\u65b9\u8f38\u5165\u4f60\u81ea\u5df1\u7684\u56de\u7b54\u3002', - clarify_other: '\u5176\u4ed6', - clarify_send: '\u9001\u51fa', - clarify_input_placeholder: '\u8f38\u5165\u4f60\u7684\u56de\u7b54\u2026', - clarify_responding: '\u8655\u7406\u4e2d\u2026', - untitled: '\u672a\u547d\u540d', - n_messages: (n) => `${n} \u689d\u8a0a\u606f`, - load_older_messages: '↑ 向上捲動或點擊以載入較早的訊息', + approval_heading: '需要核准', + approval_desc_prefix: '偵測到危險命令', + approval_btn_once: '允許一次', + approval_btn_once_title: '允許這一道命令(Enter)', + approval_btn_session: '允許本次對話', + approval_btn_session_title: '允許本次對話工作階段', + approval_btn_always: '一律允許', + approval_btn_always_title: '一律允許這個命令模式', + approval_btn_deny: '拒絕', + approval_btn_deny_title: '拒絕,不要執行這道命令', + approval_responding: '正在回應……', + clarify_heading: '需要釐清', + clarify_hint: '請選擇一個選項,或在下方輸入回答。', + clarify_other: '其他', + clarify_send: '送出', + clarify_input_placeholder: '輸入回答…', + clarify_responding: '處理中…', + session_attention_approval: (n) => n === 1 ? '核准' : `${n} 項核准`, + session_attention_clarify: (n) => n === 1 ? '問題' : `${n} 個問題`, + session_attention_generic: (n) => n === 1 ? '待處理' : `${n} 個事項`, + session_attention_approval_title: '等待權限決定', + session_attention_clarify_title: '等待回覆', + session_attention_generic_title: '等待使用者操作', + n_messages: (n) => `${n} 則訊息`, + load_older_messages: '↑ 向上捲動或點選以載入較早的訊息', session_jump_start: '開頭', - session_jump_start_label: '跳至會話開頭', + session_jump_start_label: '跳至對話開頭', session_jump_end: '結尾', - session_jump_end_label: '跳至會話結尾', + session_jump_end_label: '跳至對話結尾', jump_to_question: '回到問題', jump_to_question_label: '跳至這則回答對應的問題', - model_unavailable: '\uff08\u4e0d\u53ef\u7528\uff09', - model_unavailable_title: '\u6b64\u6a21\u578b\u5df2\u7d93\u4e0d\u5728\u7576\u524d provider \u5217\u8868\u4e2d', - provider_mismatch_warning: (m,p)=>`\"${m}\" \u53ef\u80fd\u7121\u6cd5\u5728\u7576\u524d\u914d\u7f6e\u7684\u63d0\u4f9b\u8005 (${p}) \u4e0b\u904b\u4f5c\u3002\u5c1a\u9001\uff0c\u6216\u5728\u7d42\u7aef\u57f7\u884c \`hermes model\` \u5207\u63db\u3002`, - provider_mismatch_label: '\u63d0\u4f9b\u8005\u4e0d\u76f8\u7b26', + queued_label: '回應後傳送', + queued_count: (n) => n === 1 ? '1 已排隊' : `${n} 已排隊`, + queued_cancel: '取消排隊訊息', + model_unavailable: '(無法使用)', + model_unavailable_title: '這個模型已不在目前的供應商清單中', + provider_mismatch_warning: (m,p)=>`「${m}」可能無法搭配已設定的供應商(${p})使用。仍要送出,或在終端機執行 \`hermes model\` 來切換。`, + provider_mismatch_label: '供應商不相符', gateway_auth_label: 'Gateway 驗證失敗', - model_not_found_label: '\u672a\u627e\u5230\u6a21\u578b', + model_not_found_label: '未找到模型', + model_custom_label: '自訂模型 ID', + model_custom_placeholder: '例如 openai/gpt-5.4', + model_search_placeholder: '搜尋模型…', + model_search_no_results: '找不到模型', + model_group_configured: '已設定', + ws_search_placeholder: '搜尋工作區…', + ws_no_results: '找不到工作區', + workspace_new_worktree_conversation: '在 worktree 中新增對話', + workspace_new_worktree_conversation_meta: '為此工作區建立隔離的 git worktree。', + workspace_worktree_created: '已建立 worktree 對話', + workspace_worktree_failed: '建立 worktree 失敗:', + session_worktree_badge: 'Worktree', + model_scope_advisory: '從下一則訊息起適用於此對話。', + model_scope_toast: '從下一則訊息起適用於此對話。', // commands.js - cmd_help: '\u67e5\u770b\u53ef\u7528\u547d\u4ee4', - cmd_clear: '\u6e05\u7a7a\u7576\u524d\u5c0d\u8a71\u8a0a\u606f', - cmd_compress: '\u624b\u52d5\u58d3\u7e2e\u5c0d\u8a71\u4e0a\u4e0b\u6587\uff08\u7528\u6cd5\uff1a/compress [\u4e3b\u984c]\uff09', - ctx_compress_hint: '\u58d3\u7e2e\u4e0a\u4e0b\u6587\u4ee5\u91cb\u653e\u7a7a\u9593 →', - ctx_compress_action: '\u26a0 \u7acb\u5373\u58d3\u7e2e\u4ee5\u91cb\u653e\u4e0a\u4e0b\u6587', - cmd_compact_alias: '\u820a\u5225\u540d\uff1a/compress', - cmd_model: '\u5207\u63db\u6a21\u578b\uff08\u4f8b\u5982 /model gpt-4o\uff09', - cmd_workspace: '\u6309\u540d\u7a31\u5207\u63db\u5de5\u4f5c\u5340', - cmd_terminal: '\u6253\u958b\u5de5\u4f5c\u5340 Terminal', - cmd_new: '\u65b0\u5efa\u804a\u5929\u6703\u8a71', - cmd_usage: '\u5207\u63db token \u7528\u91cf\u986f\u793a', - cmd_theme: '\u5207\u63db\u5916\u89c0\uff08\u4e3b\u984c\uff1asystem/dark/light\uff0c\u76ae\u819a\uff1adefault/ares/mono/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast\uff09', - cmd_personality: '\u5207\u63db Agent \u4eba\u8a2d', - cmd_skills: '\u5217\u51fa\u53ef\u7528\u7684 Hermes \u6280\u80fd', - available_commands: '\u53ef\u7528\u547d\u4ee4\uff1a', - type_slash: '\u8f38\u5165 / \u53ef\u67e5\u770b\u547d\u4ee4', - conversation_cleared: '\u5c0d\u8a71\u5df2\u6e05\u7a7a', - command_label: '\u547d\u4ee4', - context_compaction_label: '\u4e0a\u4e0b\u6587\u58d3\u7e2e', - preserved_task_list_label: '\u4fdd\u7559\u7684\u4efb\u52d9\u6e05\u55ae', - reference_only_label: '\u50c5\u4f9b\u53c3\u8003', - model_usage: '\u7528\u6cd5\uff1a/model ', - no_model_match: '\u6c92\u6709\u5339\u914d\u201c', - switched_to: '\u5df2\u5207\u63db\u5230 ', - workspace_usage: '\u7528\u6cd5\uff1a/workspace ', - no_workspace_match: '\u6c92\u6709\u5339\u914d\u201c', - switched_workspace: '\u5df2\u5207\u63db\u5de5\u4f5c\u5340\uff1a', - workspace_switch_failed: '\u5de5\u4f5c\u5340\u5207\u63db\u5931\u6557\uff1a', - new_session: '\u5df2\u65b0\u5efa\u6703\u8a71', + cmd_clear: '清除對話訊息', + cmd_help: '列出可用命令', + cmd_compress: '手動壓縮對話脈絡(用法:/compress [主題])', + ctx_compress_hint: '壓縮脈絡以釋放空間 →', + ctx_compress_action: '⚠ 立即壓縮以釋放脈絡', + cmd_compact_alias: '舊別名:/compress', + cmd_model: '切換模型(例如 /model gpt-4o)', + cmd_workspace: '依名稱切換工作區', + cmd_terminal: '開啟工作區 Terminal', + cmd_new: '開始新的聊天對話', + cmd_usage: '開啟或關閉 token 用量顯示', + cmd_theme: '切換外觀(主題:system/dark/light,skin:default/ares/mono/slate/poseidon/sisyphus/charizard/sienna/catppuccin/nous/geist-contrast)', + cmd_personality: '切換 Agent 角色', + cmd_skills: '列出可用的 Hermes 技能', + available_commands: '可用命令:', + type_slash: '輸入 / 檢視命令', + conversation_cleared: '已清除對話', + command_label: '命令', + context_compaction_label: '脈絡壓縮', + retrieval_context_label: '已索引的脈絡', + retrieval_context_preview: '較早的訊息已儲存,可透過脈絡工具擷取', + preserved_task_list_label: '保留的任務清單', + reference_only_label: '僅供參考', + model_usage: '用法:/model ', + no_model_match: '沒有符合的模型:', + switched_to: '已切換到 ', + workspace_usage: '用法:/workspace ', + no_workspace_match: '沒有符合的工作區:', + switched_workspace: '已切換至工作區:', + workspace_switch_failed: '工作區切換失敗:', + new_session: '已建立新對話', new_session_creating: '正在建立新對話…', - compressing: '\u6b63\u5728\u8981\u6c42\u58d3\u7e2e\u4e0a\u4e0b\u6587...', - compress_running_label: '\u58d3\u7e2e\u4e2d', - compress_complete_label: '\u58d3\u7e2e\u5b8c\u6210', - auto_compress_label: '\u81ea\u52d5\u58d3\u7e2e', - compress_failed_label: '\u58d3\u7e2e\u5931\u6557', - focus_label: '\u4e3b\u984c', - token_usage_on: 'Token \u7528\u91cf\u986f\u793a\u5df2\u958b\u555f', - token_usage_off: 'Token \u7528\u91cf\u986f\u793a\u5df2\u95dc\u9589', + compressing: '正在要求壓縮脈絡……', + compress_running_label: '壓縮中', + compress_complete_label: '壓縮完成', + auto_compress_label: '自動壓縮', + compress_failed_label: '壓縮失敗', + focus_label: '主題', + token_usage_on: 'Token 用量顯示已開啟', + token_usage_off: 'Token 用量顯示已關閉', usage_cache_hit_detail: '快取:{0}% 命中(讀取 {1} / 寫入 {2})', usage_cached_percent: '{0}% 已快取', - theme_usage: '\u7528\u6cd5\uff1a/theme ', - theme_set: '\u4e3b\u984c\uff1a', - no_active_session: '\u7576\u524d\u6c92\u6709\u6d3b\u52d5\u6703\u8a71', + theme_usage: '用法:/theme ', + theme_set: '主題:', + no_active_session: '沒有使用中的對話', + cmd_queue: '將訊息加入下一輪的佇列', + cmd_goal: '設定或檢視持久目標', + goal_evaluating_progress: '正在評估目標進度…', + goal_working_toward: '正在朝目標執行…', + goal_continuing_toast: '正在繼續目標…', + goal_status_none: '沒有使用中的目標。請使用 /goal 設定。', + goal_status_active: (turns, max_turns, goal) => `⊙ 目標(進行中,${turns}/${max_turns} 回合):${goal}`, + goal_status_paused: (turns, max_turns, reason, goal) => `⏸ 目標(已暫停,${turns}/${max_turns}${reason ? `,${reason}` : ''}):${goal}`, + goal_status_done: (turns, max_turns, goal) => `✓ 目標完成(${turns}/${max_turns}):${goal}`, + goal_set: (turns, goal) => `⊙ 已設定目標(${turns} 回合預算):${goal}`, + goal_paused: (goal) => `⏸ 目標已暫停:${goal}`, + goal_resumed: (goal) => `▶ 目標已恢復:${goal}`, + goal_cleared: '目標已清除。', + goal_no_goal: '沒有使用中的目標。', + goal_achieved: (reason) => `✓ 目標已達成:${reason}`, + goal_paused_budget_exhausted: (turns, max_turns) => `⏸ 目標已暫停,已使用 ${turns}/${max_turns} 回合。使用 /goal resume 繼續,或使用 /goal clear 停止。`, + goal_continuing: (turns, max_turns, reason) => `↻ 繼續目標(${turns}/${max_turns}):${reason}`, + cmd_interrupt: '取消目前回合並傳送新訊息', + cmd_steer: '在回合進行中注入修正,不中斷 Agent', + cmd_queue_no_msg: '用法:/queue <訊息>', + cmd_queue_not_busy: '沒有活動任務 — 直接傳送即可', + cmd_queue_confirm: '訊息已加入佇列', + cmd_interrupt_no_msg: '用法:/interrupt <訊息>', + cmd_interrupt_confirm: '已中斷,正在傳送新訊息', + cmd_steer_no_msg: '用法:/steer <訊息>', + cmd_steer_fallback: 'Steer 不可用 — 已加入下一輪佇列', + cmd_steer_delivered: 'Steer 已送達,Agent 會在下一個工具結果中看到', + steer_leftover_queued: 'Steer 已加入下一輪佇列', + busy_steer_fallback: 'Steer 不可用 — 已加入下一輪佇列', + busy_interrupt_confirm: '已中斷,正在傳送新訊息', + settings_label_busy_input_mode: '忙碌輸入模式', + settings_desc_busy_input_mode: '控制 Agent 執行時送出訊息的行為。佇列會等待;中斷會取消並重新開始;Steer 會中途注入修正且不中斷(Agent 或串流無法使用時會退回佇列)。', + settings_label_fade_text_effect: '文字淡入效果', + settings_desc_fade_text_effect: '在助理回覆時讓新串流輸出的詞語淡入顯示。類似 OpenWebUI;為獲得最佳效能預設關閉。', + settings_busy_input_mode_queue: '加入佇列', + settings_busy_input_mode_interrupt: '中斷目前回合', + settings_busy_input_mode_steer: 'Steer(中途修正)', + slash_skill_badge: '技能', + slash_skill_desc: '叫用此技能', + cmd_stop: '停止目前回應', + cmd_title: '取得或設定對話標題', + cmd_retry: '重新送出上一則訊息', + cmd_undo: '移除上一組問答', + cmd_btw: '提出旁支問題(暫時)', + cmd_btw_usage: '/btw — 使用對話脈絡提出旁支問題', + cmd_background: '在背景執行提示詞', + cmd_background_usage: '/background — 平行執行,不阻塞目前工作', + cmd_branch: '將此對話分支成新的對話', + cmd_branch_usage: '/branch [name] — 分支對話(可選擇命名)', + branch_forked: '已分支成新的對話', + branch_failed: '分支失敗:', + fork_from_here: '從這裡分支', + forked_from: '分支來源', + subagent_children: '子 Agent 對話', + btw_asking: '正在詢問旁支問題…', + btw_label: '旁支問題,不會寫入記錄', + btw_done: '旁支問題已回答', + btw_no_answer: '未收到回答。', + btw_failed: '旁支問題失敗:', + bg_running: '正在背景執行…', + bg_complete: '背景任務已完成', + bg_label: '背景結果:', + bg_no_answer: '(沒有回答)', + bg_failed: '背景任務失敗:', + undo_exchange: '復原上一組問答', + cmd_status: '顯示對話資訊', + cmd_voice: '切換麥克風輸入', + stream_stopped: '回應已停止。', + no_active_task: '沒有可停止的使用中任務。', + cancel_unavailable: '無法取消。', + retry_failed: '重試失敗:', + undo_failed: '復原失敗:', + undid_n_messages: '已移除', + undid_messages_suffix: '則訊息。', + status_heading: '對話狀態', + status_session_id: '對話 ID', + status_title: '標題', + status_model: '模型', + status_provider: '供應商', + status_workspace: '工作區', + status_personality: '角色', + status_messages: '訊息', + status_agent_running: 'Agent 執行中', + status_profile: '個人資料', + status_hermes_home: 'Hermes 主目錄', + status_started: '開始時間', + status_updated: '已更新', + status_tokens: 'Token', + status_ephemeral: '暫時快照,未儲存到對話記錄。', + status_no_tokens: '未使用 Token', + status_unknown: '未知', + status_yes: '是', + status_no: '否', + status_load_failed: '載入狀態失敗:', + title_current: '目前標題', + title_change_hint: '使用 `/title ` 重新命名。', + title_set: '標題已設定為', + cmd_webui_only_session: '此命令無法用於從 CLI 匯入的對話。', + cmd_voice_use_mic: '請點選輸入框中的麥克風按鈕。', + usage_heading: 'Token 用量', + usage_default_model: '預設', + usage_unknown: '未知', + usage_input_tokens: '輸入 Token', + usage_output_tokens: '輸出 Token', + usage_total: 'Token 總計', + usage_estimated_cost: '估計成本', + usage_settings_tip: '注意:成本估計僅供參考。', + usage_load_failed: '載入用量失敗:', + usage_personality_none: '無', + // Session toolsets (#493) + session_toolsets: '對話工具集', + session_toolsets_desc: '限制此對話可用的工具(留空即使用全域設定)', + session_toolsets_global: '全域(預設)', + session_toolsets_custom: '自訂', + session_toolsets_placeholder: 'tool1, tool2, …', + session_toolsets_apply: '套用', + session_toolsets_clear: '清除(使用全域)', + session_toolsets_applied: '工具集已更新', + session_toolsets_cleared: '工具集已清除,改用全域設定', + session_toolsets_failed: '更新工具集失敗:', + untitled: '未命名', + no_personalities: '找不到角色(可新增至 ~/.hermes/personalities/)', + available_personalities: '可用角色:', + personality_switch_hint: '\n\n使用 `/personality ` 切換,或使用 `/personality none` 清除。', + personalities_load_failed: '載入角色失敗', + personality_cleared: '已清除角色', + personality_set: '角色:', + failed_colon: '失敗:', + // ui.js + no_workspace: '沒有工作區', + terminal_open_title: '開啟工作區 Terminal', + terminal_no_workspace_title: '請先選擇工作區再開啟 Terminal', + terminal_title: 'Terminal', + terminal_clear: '清空', + terminal_copy_output: '複製輸出', + terminal_restart: '重新啟動', + terminal_collapse: '收合', + terminal_expand: '展開', + terminal_close: '關閉', + terminal_input_placeholder: '輸入命令……', + terminal_start_failed: 'Terminal 啟動失敗:', + terminal_input_failed: 'Terminal 輸入失敗:', + terminal_copy_failed: '複製失敗:', + terminal_error: 'Terminal 錯誤', workspace_empty_no_path: '未選擇工作區。請在 設定 → 工作區 中設定工作區以瀏覽檔案。', workspace_empty_dir: '此工作區為空。', workspace_show_hidden_files: '顯示隱藏檔案', - workspace_show_hidden_files_desc: 'Include .DS_Store, .git, node_modules, and other hidden / system files in the file tree.', - workspace_hidden_files_visible: 'hidden visible', - workspace_hidden_files_visible_title: 'Hidden files are visible — click for options', - workspace_options: 'Workspace options', - no_personalities: '\u6c92\u6709\u627e\u5230\u4eba\u8a2d\uff08\u53ef\u6dfb\u52a0\u5230 ~/.hermes/personalities/\uff09', - available_personalities: '\u53ef\u7528\u4eba\u8a2d\uff1a', - personality_switch_hint: '\n\n\u4f7f\u7528 `/personality ` \u5207\u63db\uff0c\u6216\u7528 `/personality none` \u6e05\u7a7a\u3002', - personalities_load_failed: '\u52a0\u8f7d\u4eba\u8a2d\u5931\u6557', - personality_cleared: '\u4eba\u8a2d\u5df2\u6e05\u7a7a', - personality_set: '\u7576\u524d\u4eba\u8a2d\uff1a', - failed_colon: '\u5931\u6557\uff1a', - // ui.js - no_workspace: '\u672a\u9078\u64c7\u5de5\u4f5c\u5340', - terminal_open_title: '\u6253\u958b\u5de5\u4f5c\u5340 Terminal', - terminal_no_workspace_title: '\u8acb\u5148\u9078\u64c7\u5de5\u4f5c\u5340\u518d\u6253\u958b Terminal', - terminal_title: 'Terminal', - terminal_clear: '\u6e05\u7a7a', - terminal_copy_output: '\u8907\u88fd\u8f38\u51fa', - terminal_restart: '\u91cd\u555f', - terminal_collapse: '\u6536\u5408', - terminal_expand: '\u5c55\u958b', - terminal_close: '\u95dc\u9589', - terminal_input_placeholder: '\u8f38\u5165\u547d\u4ee4...', - terminal_start_failed: 'Terminal \u555f\u52d5\u5931\u6557\uff1a', - terminal_input_failed: 'Terminal \u8f38\u5165\u5931\u6557\uff1a', - terminal_copy_failed: '\u8907\u88fd\u5931\u6557\uff1a', - terminal_error: 'Terminal \u932f\u8aa4', + workspace_show_hidden_files_desc: '在檔案樹中包含 .DS_Store、.git、node_modules 與其他隱藏/系統檔案。', + workspace_hidden_files_visible: '顯示隱藏檔', + workspace_hidden_files_visible_title: '隱藏檔已顯示,點選可檢視選項', + workspace_options: '工作區選項', // workspace.js - unsaved_confirm: '\u9810\u89bd\u5340\u6709\u672a\u5132\u5b58\u4fee\u6539\uff0c\u8981\u653e\u68c4\u66f4\u6539\u5e76\u7e7c\u7e8c\u8df3\u8ee2\u55ce\uff1f', - save: '\u5132\u5b58', - edit: '\u7de8\u8f2f', - save_title: '\u5132\u5b58\u4fee\u6539', - edit_title: '\u7de8\u8f2f\u6b64\u6587\u4ef6', - saved: '\u5df2\u5132\u5b58', - save_failed: '\u5132\u5b58\u5931\u6557\uff1a', - image_load_failed: '\u5716\u7247\u52a0\u8f09\u5931\u6557', - file_open_failed: '\u7121\u6cd5\u6253\u958b\u6587\u4ef6', - downloading: (name) => `\u6b63\u5728\u4e0b\u8f09 ${name}...`, - double_click_rename: '\u96d9\u64ca\u91cd\u547d\u540d', - session_rename_failed_no_row: 'Could not start rename — row not found.', - renamed_to: '\u5df2\u91cd\u547d\u540d\u70ba ', - rename_failed: '\u91cd\u547d\u540d\u5931\u6557\uff1a', - delete_title: '\u522a\u9664', - delete_confirm: (name) => `\u8981\u522a\u9664 ${name} \u55ce\uff1f`, - delete_dir_confirm: (name) => `刪除資料夾 "${name}" 及其所有內容?`, + unsaved_confirm: '預覽中有未儲存的變更。要捨棄並前往其他位置嗎?', + save: '儲存', + edit: '編輯', + save_title: '儲存變更', + edit_title: '編輯這個檔案', + saved: '已儲存', + save_failed: '儲存失敗:', + image_load_failed: '無法載入圖片', + file_open_failed: '無法開啟檔案', + downloading: (name) => `正在下載 ${name}…`, + double_click_rename: '按兩下即可重新命名', + session_rename_failed_no_row: '無法開始重新命名,找不到資料列。', + renamed_to: '已重新命名為 ', + rename_failed: '重新命名失敗:', + delete_title: '刪除', + delete_confirm: (name) => `要刪除 ${name} 嗎?`, + delete_dir_confirm: (name) => `刪除資料夾「${name}」及其所有內容?`, rename_title: '重新命名', - rename_prompt: '新名稱:', - deleted: '\u5df2\u522a\u9664 ', - delete_failed: '\u522a\u9664\u5931\u6557\uff1a', - reveal_in_finder: '\u5728\u6a94\u6848\u7ba1\u7406\u54e1\u4e2d\u986f\u793a', - reveal_failed: '\u986f\u793a\u5931\u6557\uff1a', - copy_file_path: '\u8907\u88fd\u6a94\u6848\u8def\u5f91', - open_in_vscode: '在VS Code中開啟', - open_in_vscode_failed: '在VS Code中開啟失敗:', - download_folder: 'Download Folder', // TODO: translate - path_copied: '\u6a94\u6848\u8def\u5f91\u5df2\u8907\u88fd\u5230\u526a\u8cbc\u7c3f', - path_copy_failed: '\u8907\u88fd\u8def\u5f91\u5931\u6557\uff1a', - session_rename: '\u91cd\u65b0\u547d\u540d\u5c0d\u8a71', - session_rename_desc: '\u7de8\u8f2f\u6b64\u5c0d\u8a71\u7684\u6a19\u984c', - session_title_regenerate: '\u91cd\u65b0\u751f\u6210\u6a19\u984c', - session_title_regenerate_desc: '\u8b93 Hermes \u6839\u64da\u5c0d\u8a71\u751f\u6210\u65b0\u7684\u6a19\u984c', - session_title_regenerating: '\u6b63\u5728\u91cd\u65b0\u751f\u6210\u6a19\u984c\u2026', - session_title_regenerated: (title) => `\u6a19\u984c\u5df2\u91cd\u65b0\u751f\u6210\uff1a${title}`, - session_title_regenerate_failed: '\u91cd\u65b0\u751f\u6210\u6a19\u984c\u5931\u6557\uff1a', + rename_prompt: '新名稱:', + deleted: '已刪除 ', + delete_failed: '刪除失敗:', + reveal_in_finder: '在檔案管理員中顯示', + reveal_failed: '顯示失敗:', + copy_file_path: '複製檔案路徑', + open_in_vscode: '在 VS Code 中開啟', + open_in_vscode_failed: '在 VS Code 中開啟失敗:', + download_folder: '下載資料夾', + path_copied: '檔案路徑已複製到剪貼簿', + path_copy_failed: '複製路徑失敗:', + session_rename: '重新命名對話', + session_rename_desc: '編輯此對話的標題', + session_title_regenerate: '重新產生標題', + session_title_regenerate_desc: '請 Hermes 依對話產生新的標題', + session_title_regenerating: '正在重新產生標題…', + session_title_regenerated: (title) => `標題已重新產生:${title}`, + session_title_regenerate_failed: '重新產生標題失敗:', session_copy_link: '複製對話連結', session_copy_link_desc: '複製此對話的直接連結', session_link_copied: '對話連結已複製到剪貼簿', session_link_copy_failed: '無法複製對話連結:', - new_file_prompt: '\u65b0\u6587\u4ef6\u540d\uff08\u4f8b\u5982 notes.md\uff09\uff1a', - created: '\u5df2\u5275\u5efa ', - create_failed: '\u5275\u5efa\u5931\u6557\uff1a', - new_folder_prompt: '\u65b0\u6587\u4ef6\u593e\u540d\u7a31\uff1a', - folder_created: '\u5df2\u5275\u5efa\u6587\u4ef6\u593e ', - folder_create_failed: '\u5275\u5efa\u6587\u4ef6\u593e\u5931\u6557\uff1a', - workspace_auto_create_folder: '\u8cc7\u6599\u593e\u4e0d\u5b58\u5728\u6642\u5247\u5efa\u7acb', - folder_add_as_space_btn: '\u65b0\u589e\u70ba\u5de5\u4f5c\u5340', - folder_add_as_space_msg: '\u662f\u5426\u5c07\u6b64\u8cc7\u6599\u593e\u65b0\u589e\u70ba\u5de5\u4f5c\u5340\uff1f', - folder_add_as_space_title: '\u65b0\u589e\u70ba\u5de5\u4f5c\u5340\uff1f', - remove_title: '\u79fb\u9664', - empty_dir: '(空)', + new_file_prompt: '新檔案名稱(例如 notes.md):', + created: '已建立 ', + create_failed: '建立失敗:', + new_folder_prompt: '新資料夾名稱:', + folder_created: '已建立資料夾 ', + folder_create_failed: '建立資料夾失敗:', + workspace_auto_create_folder: '資料夾不存在時自動建立', + folder_add_as_space_btn: '新增為空間', + folder_add_as_space_msg: '要將此資料夾新增為工作區清單中的新空間嗎?', + folder_add_as_space_title: '要新增為空間嗎?', + remove_title: '移除', + empty_dir: '(空)', upload_failed: '上傳失敗:', upload_too_large: (maxMb, fileMb) => `檔案過大(${fileMb} MB)。最大上傳大小為 ${maxMb} MB。`, - uploading: '上传中…', - uploaded: '已上传', - all_uploads_failed: (n) => `${n} 個檔案全部上傳失敗`, + uploading: '上傳中…', + uploaded: '已上傳', + all_uploads_failed: (n) => `全部 ${n} 個上傳都失敗`, + archive_extracted: (n, c) => `從 ${c} 個壓縮包中解壓縮了 ${n} 個檔案`, session_pin: '釘選對話', session_unpin: '取消釘選', session_pin_desc: '將此對話置頂', @@ -9303,23 +9482,23 @@ const LOCALES = { session_move_project_desc_has: '變更此對話的專案', session_move_project_desc_none: '為此對話指定專案', session_archive: '封存對話', - session_hide_external: '從列表中隱藏', + session_hide_external: '從清單中隱藏', session_restore: '還原對話', session_archive_desc: '隱藏此對話,直到開啟顯示封存', session_archive_worktree_desc: '隱藏此對話;保留磁碟上的 worktree', - session_hide_external_desc: '從 WebUI 列表中隱藏此匯入的對話,不刪除原始歷史記錄。', + session_hide_external_desc: '從 WebUI 清單中隱藏此匯入的對話,不刪除原始歷史記錄。', session_restore_desc: '將此對話移回主清單', session_archived: '對話已封存', session_archived_worktree: '對話已封存。Worktree 仍保留在磁碟上。', - session_hidden: '已從列表中隱藏對話', + session_hidden: '已從清單中隱藏對話', session_restored: '對話已還原', session_archive_failed: '封存失敗:', session_duplicate: '複製對話', session_duplicate_desc: '建立一個相同工作區與模型的副本', session_duplicated: '對話已複製', session_duplicate_failed: '複製失敗:', - session_stop_response: 'Stop response', - session_stop_response_desc: 'Cancel the running response for this conversation', + session_stop_response: '停止回應', + session_stop_response_desc: '取消此對話中正在執行的回應', session_delete: '刪除對話', session_delete_desc: '永久移除這個對話', session_delete_confirm: '刪除此對話?', @@ -9340,20 +9519,20 @@ const LOCALES = { session_worktree_remove_unsafe_blocked: '請先處理本機變更或未推送提交,再刪除此 worktree。', session_worktree_remove_dirty_warning: '⚠️ 此 worktree 有未提交的變更,將被永久刪除。', session_worktree_remove_untracked_warning: (count) => `${count} 個未追蹤檔案將被永久刪除。`, - session_worktree_remove_ahead_warning: (ahead) => `${ahead} 個未推送的提交將丟失。`, + session_worktree_remove_ahead_warning: (ahead) => `${ahead} 個未推送的提交會遺失。`, session_select_mode: '選取', - session_select_mode_desc: '選取會話以批次管理', + session_select_mode_desc: '選取對話以批次管理', session_select_all: '全選', session_deselect_all: '取消全選', session_selected_count: '已選 {0} 個', session_batch_archive: '封存', session_batch_delete: '刪除', session_batch_move: '移至專案', - session_batch_delete_confirm: '刪除 {0} 個會話?', - session_batch_archive_confirm: '封存 {0} 個會話?', - session_batch_delete_worktree_confirm: '刪除 {0} 個會話?其中 {1} 個 worktree 會話會把 worktree 目錄保留在磁碟上。', - session_batch_archive_worktree_confirm: '封存 {0} 個會話?其中 {1} 個 worktree 會話會把 worktree 目錄保留在磁碟上。', - session_no_selection: '未選取任何會話', + session_batch_delete_confirm: '要刪除 {0} 個對話嗎?', + session_batch_archive_confirm: '要封存 {0} 個對話嗎?', + session_batch_delete_worktree_confirm: '要刪除 {0} 個對話嗎?其中 {1} 個 worktree 對話會把 worktree 目錄保留在磁碟上。', + session_batch_archive_worktree_confirm: '要封存 {0} 個對話嗎?其中 {1} 個 worktree 對話會把 worktree 目錄保留在磁碟上。', + session_no_selection: '未選取任何對話', // settings panel settings_heading_title: '控制中心', settings_heading_subtitle: '偏好設定、對話工具與系統控制。', @@ -9363,25 +9542,25 @@ const LOCALES = { settings_section_preferences_title: '偏好設定', settings_section_preferences_meta: 'Hermes Web UI 的預設值與介面行為。', settings_section_system_title: '系統', - settings_section_system_meta: '實例版本與存取控制。', + settings_section_system_meta: '執行個體版本與存取控制。', settings_check_now: '立即檢查', - settings_checking: '檢查中\u2026', - settings_up_to_date: '已是最新 \u2713', + settings_checking: '檢查中…', + settings_up_to_date: '已是最新 ✓', settings_updates_available: '有 {count} 個更新可用', - settings_updates_disabled: '更新檢查已禁用', + settings_updates_disabled: '更新檢查已停用', settings_update_check_failed: '更新檢查失敗', - settings_label_workspace_panel_open: '預設保持工作區面板開啓', - settings_desc_workspace_panel_open: '啟用後,工作區/檔案瀏覽器面板會在每次新會話時自動開啓。您仍可隨時手動關閉。', - settings_label_session_jump_buttons: '顯示會話跳轉按鈕', - settings_desc_session_jump_buttons: '閱讀較長會話歷史時顯示浮動的開頭與結尾按鈕。', + settings_label_workspace_panel_open: '預設保持工作區面板開啟', + settings_desc_workspace_panel_open: '啟用後,工作區/檔案瀏覽器面板會在每次新對話時自動開啟。仍可隨時手動關閉。', + settings_label_session_jump_buttons: '顯示對話跳轉按鈕', + settings_desc_session_jump_buttons: '閱讀較長對話記錄時,顯示浮動的開頭與結尾按鈕。', settings_label_session_endless_scroll: '向上捲動時載入較早訊息', settings_desc_session_endless_scroll: '啟用後,向上捲動時會自動載入較早訊息。停用時請使用載入較早訊息按鈕。', settings_label_tab_visibility: '側邊欄標籤', - settings_desc_tab_visibility: '選擇在側邊欄和導航列中顯示哪些標籤。聊天和設定始終可見。', - open_in_browser: '在瀏覽器中開啓', + settings_desc_tab_visibility: '選擇在側邊欄和導覽列中顯示哪些標籤。聊天和設定始終可見。', + open_in_browser: '在瀏覽器中開啟', settings_dropdown_conversation: '對話', settings_dropdown_appearance: '外觀', settings_dropdown_preferences: '偏好設定', @@ -9393,99 +9572,94 @@ const LOCALES = { settings_tab_plugins: '外掛', settings_plugins_title: '外掛', plugins_enable_toggle: '啟用', - settings_plugins_meta: '檢視已安裝的 Hermes 外掛及其註冊的生命週期鉤子。此面板為唯讀。', + settings_plugins_meta: '檢視已安裝的 Hermes 外掛及其註冊的生命週期掛鉤。此面板為唯讀。', settings_plugins_empty: '目前沒有可見的 Hermes 外掛。透過 Hermes CLI/設定檔安裝或啟用外掛後即可在此檢視。', plugins_unnamed: '未命名外掛', plugins_no_description: '未提供描述。', - plugins_no_hooks: '未註冊生命週期鉤子', - plugins_registered_hooks: '已註冊的鉤子', + plugins_no_hooks: '未註冊生命週期掛鉤', + plugins_registered_hooks: '已註冊的掛鉤', plugins_enabled: '已啟用', plugins_disabled: '已停用', plugins_active_provider: '啟用中(提供者)', - plugins_provider_no_hooks: '提供者外掛 — 無代理可見鉤子', + plugins_provider_no_hooks: '供應商外掛,沒有 Agent 可見的掛鉤', plugins_load_failed: '載入外掛失敗:', settings_tab_system: '系統', - settings_title: '\u8a2d\u5b9a', - settings_save_btn: '\u5132\u5b58\u8a2d\u5b9a', - settings_label_model: '\u9ed8\u8a8d\u6a21\u578b', - settings_desc_model: '\u7528\u65bc\u65b0\u6703\u8a71\u3002\u73fe\u6709\u6703\u8a71\u6703\u4fdd\u7559\u5404\u81ea\u9078\u5b9a\u7684\u6a21\u578b\u3002', - settings_label_auxiliary_models: '\u8f14\u52a9\u6a21\u578b', - settings_desc_auxiliary_models: '\u8996\u89ba\u5206\u6790\u3001\u4e0a\u4e0b\u6587\u58d3\u7e2e\u3001\u6a19\u984c\u7522\u751f\u7b49\u8f14\u52a9\u4efb\u52d9\u7684\u8def\u7531\u3002\u300c\u81ea\u52d5\u300d\u8868\u793a\u4f7f\u7528\u4e3b\u804a\u5929\u6a21\u578b\u3002', - settings_btn_reset_aux_models: '\u5168\u90e8\u91cd\u7f6e\u70ba\u81ea\u52d5', - settings_btn_apply_aux_models: '\u61c9\u7528\u8b8a\u66f4', - settings_aux_provider_auto: '\u4f7f\u7528\u4e3b\u6a21\u578b', - settings_aux_model_auto: '\u81ea\u52d5\uff08\u4f7f\u7528\u63d0\u4f9b\u5546\u9810\u8a2d\uff09', - settings_aux_model_custom: '\u81ea\u8a02\u6a21\u578b\u2026', - settings_aux_model_custom_prompt: '\u8f38\u5165\u6a21\u578b ID\uff1a', - settings_aux_loading: '\u6b63\u5728\u8f09\u5165\u8f14\u52a9\u6a21\u578b\u2026', - settings_aux_load_failed: '\u7121\u6cd5\u8f09\u5165\u8f14\u52a9\u6a21\u578b\u8a2d\u5b9a\uff0c\u8acb\u78ba\u4fdd Agent API \u53ef\u7528\u3002', - settings_aux_reset_confirm_title: '\u91cd\u7f6e\u8f14\u52a9\u6a21\u578b\uff1f', - settings_aux_reset_confirm_msg: '\u9019\u5c07\u628a\u6240\u6709\u8f14\u52a9\u4efb\u52d9\u8a2d\u5b9a\u70ba\u81ea\u52d5\uff08\u4f7f\u7528\u4e3b\u6a21\u578b\uff09\u3002', - settings_aux_reset_done: '\u8f14\u52a9\u6a21\u578b\u5df2\u91cd\u7f6e\u70ba\u81ea\u52d5', - settings_aux_save_failed: '\u8f14\u52a9\u6a21\u578b\u5132\u5b58\u5931\u6557', - settings_aux_saved: '\u8f14\u52a9\u6a21\u578b\u5df2\u66f4\u65b0', - settings_aux_no_changes: '\u6c92\u6709\u9700\u8981\u61c9\u7528\u7684\u8b8a\u66f4', - settings_label_send_key: '\u767c\u9001\u5feb\u6377\u9375', - settings_label_theme: '\u4e3b\u984c', + settings_title: '設定', + settings_save_btn: '儲存設定', + settings_label_model: '預設模型', + settings_desc_model: '用於新對話。現有對話會保留各自選定的模型。', + settings_label_auxiliary_models: '輔助模型', + settings_desc_auxiliary_models: '視覺分析、脈絡壓縮、標題產生等輔助任務的路由。「自動」表示使用主要聊天模型。', + settings_btn_reset_aux_models: '全部重置為自動', + settings_btn_apply_aux_models: '應用變更', + settings_aux_provider_auto: '使用主模型', + settings_aux_model_auto: '自動(使用供應商預設值)', + settings_aux_model_custom: '自訂模型…', + settings_aux_model_custom_prompt: '輸入模型 ID:', + settings_aux_loading: '正在載入輔助模型…', + settings_aux_load_failed: '無法載入輔助模型設定,請確保 Agent API 可用。', + settings_aux_reset_confirm_title: '重置輔助模型?', + settings_aux_reset_confirm_msg: '這將把所有輔助任務設定為自動(使用主模型)。', + settings_aux_reset_done: '輔助模型已重置為自動', + settings_aux_save_failed: '輔助模型儲存失敗', + settings_aux_saved: '輔助模型已更新', + settings_aux_no_changes: '沒有需要應用的變更', + settings_label_send_key: '送出按鍵', + settings_label_theme: '主題', settings_label_skin: '佈景', - settings_label_font_size: '\u5b57\u9ad4\u5927\u5c0f', - font_size_small: '\u5c0f', - font_size_default: '\u9810\u8a2d', - font_size_large: '\u5927', - font_size_xlarge: '\u8d85\u5927', - settings_autosave_saving: '\u5132\u5b58\u4e2d…', - settings_autosave_saved: '\u5df2\u5132\u5b58', - settings_autosave_failed: '\u5132\u5b58\u5931\u6557', - settings_autosave_retry: '\u91cd\u8a66', - settings_label_language: '\u8a9e\u8a00', + settings_label_font_size: '字型大小', + font_size_small: '小', + font_size_default: '預設', + font_size_large: '大', + font_size_xlarge: '超大', + settings_autosave_saving: '儲存中…', + settings_autosave_saved: '已儲存', + settings_autosave_failed: '儲存失敗', + settings_autosave_retry: '重試', + settings_label_language: '語言', settings_label_quota_chip: '在編輯器中顯示供應商配額標籤', settings_desc_quota_chip: '在編輯器底部顯示剩餘配額指示器(如 OpenRouter 點數餘額)。預設關閉。啟用時僅在寬螢幕(≥1400px)顯示,以保持筆記型電腦和標準桌面螢幕上編輯器的整潔。', - settings_label_hide_suggestions: 'Hide new-chat suggestions', - settings_desc_hide_suggestions: 'Hide the three default suggestion buttons on the empty new-chat screen to avoid accidental taps.', - settings_label_token_usage: '\u986f\u793a token \u7528\u91cf', + settings_label_hide_suggestions: '隱藏新聊天建議', + settings_desc_hide_suggestions: '隱藏空白新聊天畫面上的三個預設建議按鈕,避免誤觸。', + settings_label_token_usage: '顯示 token 用量', settings_label_sidebar_density: '側邊欄密度', - cmd_reasoning: '切換思考區塊可見性(顯示/隱藏)或設定努力等級', - settings_label_external_sessions: '顯示外部會話', + cmd_reasoning: '切換思考內容可見性(顯示/隱藏)、設定推理強度,或檢查目前狀態', + settings_label_external_sessions: '顯示外部對話', settings_label_previous_messaging_sessions: '顯示以前的訊息對話', - settings_label_sync_insights: '\u540c\u6b65\u5230 insights', - settings_label_check_updates: '\u6aa2\u67e5\u66f4\u65b0', - settings_label_ignore_agent_updates: 'Ignore Agent updates', - settings_label_whats_new_summary: "Summarize What's New with AI", - settings_label_bot_name: '預設助手名稱', - settings_label_password: '\u8a2a\u554f\u5bc6\u78bc', - settings_saved: '\u8a2d\u5b9a\u5df2\u5132\u5b58', - settings_save_failed: '\u5132\u5b58\u5931\u6557\uff1a', - settings_load_failed: '\u8a2d\u5b9a\u52a0\u8f09\u5931\u6557\uff1a', - archive_extracted: (n, c) => `\u5f9e ${c} \u500b\u58d3\u7e2e\u5305\u4e2d\u89e3\u58d3\u7e2e\u4e86 ${n} \u500b\u6a94\u6848`, - settings_saved_pw: '\u8a2d\u5b9a\u5df2\u5132\u5b58\uff0c\u5bc6\u78bc\u4fdd\u8b77\u5df2\u555f\u7528\uff0c\u7576\u524d\u700f\u89bd\u5668\u6703\u4fdd\u6301\u767b\u5165', - settings_saved_pw_updated: '\u8a2d\u5b9a\u5df2\u5132\u5b58\uff0c\u5bc6\u78bc\u5df2\u66f4\u65b0', - // login page - login_title: '\u767b\u5f55', - login_subtitle: '\u8f38\u5165\u5bc6\u78bc\u7e7c\u7e8c\u4f7f\u7528', - login_placeholder: '\u5bc6\u78bc', - login_btn: '\u767b\u5f55', - login_invalid_pw: '\u5bc6\u78bc\u932f\u8aa4', - login_conn_failed: '\u9023\u63a5\u5931\u6557', - // missing keys from English + settings_label_sync_insights: '同步至 insights', + settings_label_check_updates: '檢查更新', + settings_label_ignore_agent_updates: '忽略 Agent 更新', + settings_label_whats_new_summary: '使用 AI 摘要新版內容', + settings_label_bot_name: '助理名稱', + settings_label_password: '存取密碼', + settings_saved: '設定已儲存', + settings_save_failed: '儲存失敗:', + settings_load_failed: '載入設定失敗:', + settings_saved_pw: '設定已儲存,密碼保護已啟用,此瀏覽器會維持登入狀態', + settings_saved_pw_updated: '設定已儲存,密碼已更新', + // login page (used server-side via /api/i18n/login endpoint) + login_title: '登入', + login_subtitle: '輸入密碼繼續使用', + login_placeholder: '密碼', + login_btn: '登入', + login_invalid_pw: '密碼錯誤', + login_conn_failed: '連線失敗', dialog_confirm_title: '確認操作', - dialog_prompt_title: '輸入內容', + dialog_prompt_title: '輸入值', dialog_confirm_btn: '確認', - discard: '放棄', - clear: '清空', + discard: '捨棄', + clear: '清除', create: '建立', remove: '移除', project_name_prompt: '專案名稱:', - tab_chat: '\u804a\u5929', - tab_memory: '\u8a18\u61b6', - tab_skills: '\u6280\u80fd', - tab_tasks: '\u4efb\u52d9', - tab_todos: '待辦', - tab_insights: '統計', - tab_dashboard: 'Hermes 儀表板', - dashboard_loopback_warning: '儀表板在伺服器上僅限 loopback 存取。請從伺服器本機瀏覽,或使用 --host 0.0.0.0 重新啟動(不安全)。', - tab_logs: 'Logs', - tab_workspaces: '\u5de5\u4f5c\u5340', - tab_kanban: 'Kanban', + // Sidebar & Tabs + tab_chat: '聊天', + tab_tasks: '任務', + tab_skills: '技能', + tab_memory: '記憶', + tab_workspaces: '工作區', + tab_profiles: '設定檔', + tab_kanban: '看板', kanban_board: '看板', kanban_visible_tasks: '{0} 個可見任務', kanban_search_tasks: '搜尋任務', @@ -9520,48 +9694,22 @@ const LOCALES = { kanban_description: '描述', kanban_description_placeholder: '選填 — 需要完成的事項、驗收標準、連結', kanban_status: '狀態', - kanban_status_original_hint: '實際狀態:{0}。此對話框僅支援編輯 Triage/Todo/Ready。', kanban_assignee: '指派對象', kanban_assignee_placeholder: '選填 — 個人資料或名稱', kanban_tenant: '租戶', - kanban_tenant_placeholder: '預設', + kanban_tenant_placeholder: '選填,專案或團隊 slug', kanban_priority: '優先順序', kanban_priority_hint: '數字越大越先執行。預設為 0。', kanban_title_required: '標題為必填。', kanban_new_task: '新任務', - kanban_add_comment: '新增留言', - kanban_only_mine: '僅顯示我的', - kanban_bulk_action: '批次操作', - kanban_nudge_dispatcher: '預覽調度器', - kanban_stats: '統計', - kanban_worker_log: '工作者日誌', - kanban_block: '封鎖', - kanban_unblock: '解除封鎖', - kanban_back_to_board: '返回看板', - kanban_lanes_by_profile: '按設定檔分泳道', - kanban_new_board: '新看板…', - kanban_rename_board: '重新命名目前看板…', - kanban_archive_board: '封存目前看板…', - kanban_archive_board_confirm: '封存看板「{name}」?任務仍保留在磁碟上,可從 kanban/boards/_archived/ 復原。', - kanban_board_archived: '看板已封存', - kanban_board_name: '名稱', - kanban_board_slug: '代號(小寫、連字號)', - kanban_board_description: '描述(選填)', - kanban_board_icon: '圖示(表情符號,選填)', - kanban_board_color: '顏色(選填)', - kanban_board_name_required: '名稱為必填', - kanban_board_slug_required: '代號為必填', - kanban_card_complete: '完成', - kanban_card_archive: '封存', - kanban_unassigned: '未指派', - kanban_status_archived: '已封存', kanban_edit_task: '編輯任務', + kanban_status_original_hint: '實際狀態:{0}。此對話框僅支援編輯 Triage/Todo/Ready。', kanban_run_dispatcher: '執行調度器', - kanban_run_dispatcher_confirm: '將認領此看板的 Ready 任務並產生工作子程序(每次點擊最多 8 個)。是否繼續?', + kanban_run_dispatcher_confirm: '將認領此看板的 Ready 任務並產生工作子程序(每次點選最多 8 個)。是否繼續?', kanban_assignee_profiles_label: 'Hermes 設定檔', kanban_assignee_other_label: '其他(CLI 通道 / 已刪除的設定檔)', kanban_assignee_unassigned: '— 未指派(不會自動執行)—', - kanban_ready_needs_assignee: '您選擇了「未指派」+「Ready」。調度器將跳過此任務。再次送出以確認,或選擇一個設定檔。', + kanban_ready_needs_assignee: '已選擇「未指派」+「Ready」。調度器將跳過此任務。再次送出以確認,或選擇一個設定檔。', kanban_dispatch_preview_prefix: '預覽:', kanban_dispatch_run_prefix: '已調度:', kanban_dispatch_spawned: '已啟動', @@ -9571,512 +9719,224 @@ const LOCALES = { kanban_dispatch_skipped_nonspawnable: '跳過(未知設定檔)', kanban_dispatch_auto_blocked: '自動封鎖', kanban_dispatch_timed_out: '逾時', - kanban_dispatch_crashed: '崩潰', + kanban_dispatch_crashed: '當機', + kanban_add_comment: '新增留言', + kanban_only_mine: '只看我的', + kanban_bulk_action: '批次動作', + kanban_nudge_dispatcher: '預覽調度器', + kanban_stats: '統計', + kanban_worker_log: 'Worker 記錄', + kanban_block: '封鎖', + kanban_unblock: '解除封鎖', + kanban_back_to_board: '回到看板', + kanban_lanes_by_profile: '依設定檔分欄', + kanban_new_board: '新增看板…', + kanban_rename_board: '重新命名目前看板…', + kanban_archive_board: '封存目前看板…', + kanban_archive_board_confirm: '封存看板「{name}」?任務仍會保留在磁碟上,且可從 kanban/boards/_archived/ 還原看板。', + kanban_board_archived: '看板已封存', + kanban_board_name: '名稱', + kanban_board_slug: 'Slug(小寫、連字號)', + kanban_board_description: '描述(選填)', + kanban_board_icon: '圖示(emoji,選填)', + kanban_board_color: '顏色(選填)', + kanban_board_name_required: '名稱為必填', + kanban_board_slug_required: 'Slug 為必填', + kanban_card_complete: '完成', + kanban_card_archive: '封存', + kanban_unassigned: '未指派', + kanban_status_archived: '已封存', + tab_todos: '待辦', + tab_insights: '統計', + tab_dashboard: 'Hermes 儀表板', + dashboard_loopback_warning: '儀表板在伺服器上僅限 loopback 存取。請從伺服器本機瀏覽,或使用 --host 0.0.0.0 重新啟動(不安全)。', + tab_logs: '記錄', + tab_settings: '設定', + new_conversation: '新增對話', + filter_conversations: '篩選對話……', + session_time_unknown: '未知', + session_time_minutes_ago: (m) => `${m}分`, + session_time_hours_ago: (h) => `${h}小時`, + session_time_days_ago: (d) => `${d}天`, + session_time_last_week: '1週', + session_time_bucket_today: '今天', + session_time_bucket_yesterday: '昨天', + session_time_bucket_this_week: '本週', + session_time_bucket_last_week: '上週', + session_time_bucket_older: '更早', + scheduled_jobs: '排程工作', + new_job: '新任務', + loading: '載入中……', + search_skills: '搜尋技能……', + new_skill: '新技能', + personal_memory: '個人記憶', + current_task_list: '目前任務清單', + // Logs + logs_title: '記錄', + logs_file: '記錄檔', + logs_tail: '追蹤記錄', + logs_auto_refresh: '自動重新整理', + logs_wrap: '自動換行', + logs_copy_all: '複製全部', + logs_empty: '沒有記錄可顯示。', + logs_loading: '正在載入記錄…', + logs_load_failed: '載入記錄失敗:', + logs_status_idle: '請選擇記錄檔以檢視最近幾行。', + logs_no_mtime: '修改時間未知', + logs_truncated_hint: '正在顯示大型記錄檔的尾端;較早的位元組已略過,以限制記憶體用量。', + logs_copied: '已複製記錄', logs_severity: '嚴重性', logs_severity_all: '全部', logs_severity_errors: '錯誤', logs_severity_warnings: '警告+', logs_filter_active: '已顯示(篩選器已啟用)', - new_conversation: '新對話', - filter_conversations: '篩選對話', - scheduled_jobs: '排程任務', - new_job: '\u65b0\u4efb\u52d9', - search_skills: '\u641c\u5c0b\u6280\u80fd', - new_skill: '\u65b0\u6280\u80fd', - save_skill: '\u5132\u5b58\u6280\u80fd', - personal_memory: '\u500b\u4eba\u8a18\u61b6', - current_task_list: '\u76ee\u524d\u4efb\u52d9\u6e05\u55ae', + + // Insights + insights_title: '用量分析', + insights_sessions: '對話', + insights_messages: '訊息', + insights_tokens: 'Token', + insights_cost: '估計成本', + insights_no_cost: 'N/A', + insights_models: '模型', + insights_activity_by_day: '每日活動', + insights_activity_by_hour: '每小時活動', + insights_peak_hour: '高峰:{hour}', + insights_token_breakdown: 'Token 明細', + insights_input_tokens: '輸入', + insights_output_tokens: '輸出', + insights_total: '總計', + insights_daily_tokens: '每日 Token', + insights_model_name: '模型', + insights_model_sessions: '對話', + insights_model_tokens: 'Token', + insights_model_cost: '成本', + insights_model_share: '占比', + insights_no_usage_data: '尚無用量資料', + insights_footer: '顯示最近 {days} 天的資料', + insights_skill_usage_title: '技能使用情況', + insights_skill_usage_sub: '工具呼叫頻率', + insights_skill_usage_total: '呼叫總數', + insights_skill_usage_skills_used: '已使用技能', + insights_skill_usage_no_data: '尚無技能使用資料', + insights_skill_usage_no_data_hint: '在對話中使用技能後,資料會顯示在這裡。', + insights_skill_usage_footer: '資料來源:~/.hermes/skills/', + insights_skill_usage_col_skill: '技能', + insights_skill_usage_col_uses: '使用次數', + insights_skill_usage_col_views: '檢視次數', + insights_skill_usage_col_share: '使用占比', + insights_skill_usage_col_patches: 'Patch', + workspace_desc: '新增工作區,並為對話切換工作區。', session_meta_messages: (n) => `${n} 則訊息`, session_meta_children: (n) => `${n} 則子`, + // Softened label: avoids exposing the technical internal term + // 'segment' in the default visible badge. User-facing copy remains + // translatable for locales that prefer a different wording. (#2155) session_meta_segments: (n) => `${n} 段`, - session_lineage_toggle_hint: '{0} — 較早的上下文輪次已摺疊在這裡。點擊可顯示或隱藏。', - session_lineage_static_hint: '{0} — 較早的上下文輪次已摺疊在這裡。', - session_child_toggle_hint: '{0} — 從此工作階段衍生的子對話。點擊可顯示或隱藏。', + session_lineage_toggle_hint: '{0} — 較早的脈絡回合已摺疊在這裡。點選可顯示或隱藏。', + session_lineage_static_hint: '{0} — 較早的脈絡回合已摺疊在這裡。', + session_child_toggle_hint: '{0} — 從此對話衍生的子對話。點選可顯示或隱藏。', session_readonly_title_hint: '唯讀匯入工作階段 — {0}', session_lineage_segment_untitled: '未命名段', session_lineage_segment_open: '開啟脈絡段', - new_profile: '\u65b0\u914d\u7f6e\u6a94', - transcript: '\u8a18\u9304', - download_transcript: '\u4e0b\u8f09\u8a18\u9304', - import: '\u5c0e\u5165', + new_profile: '新增設定檔', + transcript: '對話記錄', + download_transcript: '下載為 Markdown', + import: '匯入', export_session_json: 'JSON', - export_session_json_tooltip: '\u5c07\u6703\u8a71\u5b8c\u6574\u532f\u51fa\u70ba JSON', - import_session_json_tooltip: '\u5f9e JSON \u532f\u5165\u6703\u8a71', - clear_conversation_btn_tooltip: '\u6e05\u7a7a\u6b64\u6703\u8a71\u4e2d\u7684\u6240\u6709\u8a0a\u606f', - editing: '\u7de8\u8f2f\u4e2d', - empty_title: '有什麼可以幫忙?', - empty_subtitle: '點擊上方按鈕開始對話', - cancel: '\u53d6\u6d88', - loading: '\u52a0\u8f09\u4e2d', - create_job: '\u5efa\u7acb\u4efb\u52d9', - suggest_plan: '幫我規劃一個小專案', - suggest_schedule: '今天的時程如何?', - suggest_files: '這個工作區有哪些檔案?', - sign_out: '\u767b\u51fa', - settings_label_shutdown: '\u505c\u6b62 Hermes WebUI \u4f3a\u670d\u5668', - settings_desc_shutdown: '\u6b63\u5e38\u505c\u6b62\u672c\u5730\u7684 WebUI \u4f3a\u670d\u5668\u3002\u5982\u679c\u4f60\u900f\u904e ./ctl.sh start \u555f\u52d5\uff0c\u4e26\u5e0c\u671b\u4e0d\u5207\u63db\u5230\u7d42\u7aef\u5c31\u505c\u6b62\uff0c\u9019\u5f88\u6709\u7528\u3002\u8981\u518d\u6b21\u9032\u5165 WebUI\uff0c\u9700\u8981\u91cd\u65b0\u555f\u52d5\u4f3a\u670d\u5668\uff08./ctl.sh start \u6216\u539f\u751f\u61c9\u7528\u7a0b\u5f0f\uff09\u3002', - settings_btn_shutdown: '\u505c\u6b62\u4f3a\u670d\u5668', - settings_shutdown_confirm_title: '\u505c\u6b62 Hermes WebUI', - settings_shutdown_confirm_message: '\u505c\u6b62 Hermes WebUI \u4f3a\u670d\u5668\uff1f', - settings_shutdown_confirm_btn: '\u505c\u6b62', - settings_shutdown_stopped_message: '\u4f3a\u670d\u5668\u5df2\u505c\u6b62\u3002\u4f60\u53ef\u4ee5\u95dc\u9589\u9019\u500b\u5206\u9801\u3002', - password_placeholder: '\u5bc6\u78bc', - password_env_var_locked: '\u76ee\u524d\u5df2\u8a2d\u5b9a HERMES_WEBUI_PASSWORD \u74b0\u5883\u8b8a\u6578\u4e14\u512a\u5148\u751f\u6548\u3002\u8acb\u53d6\u6d88\u8a2d\u5b9a\u4e26\u91cd\u65b0\u555f\u52d5\u4f3a\u670d\u5668\uff0c\u624d\u80fd\u5728\u6b64\u7ba1\u7406\u5bc6\u78bc\u3002', - password_env_var_locked_placeholder: '\u5df2\u9396\u5b9a\uff1a\u5df2\u8a2d\u5b9a HERMES_WEBUI_PASSWORD \u74b0\u5883\u8b8a\u6578', - disable_auth: '\u505c\u7528\u9a57\u8b49', + export_session_json_tooltip: '將對話完整匯出為 JSON', + import_session_json_tooltip: '從 JSON 匯入對話', + clear_conversation_btn_tooltip: '清空此對話中的所有訊息', + // Settings detail settings_label_rtl: '從右到左聊天版面', settings_desc_rtl: '為阿拉伯語或希伯來語等語言翻轉聊天訊息和編輯器輸入的對齊方式。僅影響聊天區域 — 側邊欄和其他面板保持從左到右。', - settings_label_sound: '\u901a\u77e5\u8072\u97f3', - settings_label_notifications: '\u700f\u89bd\u901a\u77e5', - settings_desc_sound: '助手完成回答時播放聲音。', - settings_desc_notifications: '當分頁在後台時,有回答完成時會顯示系統通知。', - settings_desc_token_usage: '\u5728\u52a9\u624b\u6bcf\u6b21\u56de\u7b54\u4e0b\u65b9\u986f\u793a Input/Output token \u6578\u91cf\u3002\u4e5f\u53ef\u4ee5\u7528 /usage \u5207\u63db\u3002', + settings_label_sound: '通知聲音', + settings_desc_sound: '助理完成回覆時播放音效。', + // TTS (#499) + tts_listen: '收聽', + tts_not_supported: '語音合成無法使用', + settings_label_tts: '回覆語音合成', + settings_desc_tts: '在每則助理訊息上顯示喇叭按鈕,使用瀏覽器語音合成功能朗讀內容。', + settings_label_tts_auto_read: '自動朗讀回覆', + settings_desc_tts_auto_read: '每則新的助理回覆完成時自動朗讀。開始輸入時會暫停。', + // Composer voice-mode pref (#1488) + settings_label_voice_mode: '免持語音模式按鈕', + settings_desc_voice_mode: '在聽寫麥克風旁顯示語音模式按鈕(音訊波形)。可自然說話,Hermes 會在停頓後自動送出並朗讀回覆。需要同時支援語音辨識與 TTS 的瀏覽器。', + settings_label_raw_audio: '傳送原始音訊,而不是先轉寫', + settings_desc_raw_audio: '錄製並將原始音訊檔傳送給 Agent,而不是先轉成文字。Agent 接著可以轉寫音訊,或處理原始音訊(情緒、背景噪音、自訂 STT)。行為類似 Telegram 語音訊息。', + voice_send_raw: '傳送原始音訊', + voice_raw_attached: '已附加音訊。請按 [送出] 或繼續輸入。', + settings_label_tts_voice: '語音', + settings_desc_tts_voice: '偏好的語音。系統會從瀏覽器可用的語音中填入。', + settings_label_tts_rate: '語速', + settings_label_tts_pitch: '音調', + settings_label_tts_engine: 'TTS 引擎', + settings_desc_tts_engine: '選擇語音引擎。Edge TTS 會透過伺服器使用 Microsoft 神經語音。', + settings_label_notifications: '瀏覽器通知', + settings_desc_notifications: '分頁在背景中時,回覆完成後顯示系統通知。', + settings_desc_token_usage: '在每則助理回覆下方顯示輸入/輸出 token 數量。也可以使用 /usage 切換。', + settings_label_api_redact: '在 API 回應中遮蔽敏感資料', + settings_desc_api_redact: '自行託管使用者可以為了透明度停用此功能(不建議在共用執行個體中停用)。', settings_sidebar_density_compact: '精簡', settings_sidebar_density_detailed: '詳細', settings_desc_sidebar_density: '控制左側對話清單要顯示多少額外資訊。', - settings_label_auto_title_refresh: '\u81ea\u9002\u61c9\u6a19\u984c\u66f4\u65b0', - settings_auto_title_refresh_off: '\u95dc\u9589', - settings_auto_title_refresh_5: '\u6bcf 5 \u8f2a\u5c0d\u8a71', - settings_auto_title_refresh_10: '\u6bcf 10 \u8f2a\u5c0d\u8a71', - settings_auto_title_refresh_20: '\u6bcf 20 \u8f2a\u5c0d\u8a71', - settings_desc_auto_title_refresh: '\u57fa\u65bc\u6700\u65b0\u5c0d\u8a71\u81ea\u52d5\u91cd\u65b0\u751f\u6210\u6703\u8a71\u6a19\u984c\uff0c\u4f7f\u5176\u968f\u5c0d\u8a71\u767c\u5c55\u4fdd\u6301\u76f8\u95dc\u3002\u9700\u8981\u914d\u7f6e LLM \u6a19\u984c\u751f\u6210\u6a21\u578b\u3002', - settings_desc_external_sessions: '在會話列表中顯示來自 CLI、Telegram、Discord、Slack 等管道的對話。點擊可導入並繼續對話。', + settings_label_auto_title_refresh: '自動調整標題更新', + settings_auto_title_refresh_off: '關閉', + settings_auto_title_refresh_5: '每 5 輪對話', + settings_auto_title_refresh_10: '每 10 輪對話', + settings_auto_title_refresh_20: '每 20 輪對話', + settings_desc_auto_title_refresh: '根據最新對話自動重新產生對話標題,讓標題隨對話發展保持相關。需要設定 LLM 標題產生模型。', + settings_desc_external_sessions: '在對話清單中顯示來自 CLI、Telegram、Discord、Slack 等管道的對話。點選即可匯入並繼續對話。', settings_desc_previous_messaging_sessions: '顯示被 reset 或 compression 替換的較舊的 Discord、Telegram、Slack 和 Weixin 對話。', - settings_desc_sync_insights: '將 WebUI token 使用情況同步到 state.db,使 hermes /insights 包含瀏覽器會話數據。預設未啟用。', - settings_desc_check_updates: '當有更新的 WebUI 或助手版本時顯示標記。將在後台正常執行 Git-Fetch。', - settings_desc_ignore_agent_updates: 'Keep WebUI update checks on, but hide Agent update notices and skip Agent update fetches.', - settings_desc_whats_new_summary: "Changes the What's New action from opening the raw diff first to generating a short, human-readable summary. The regular diff comparison stays available after the summary.", - settings_desc_bot_name: '僅用於預設個人檔案。其他個人檔案會使用各自的名稱。', - settings_desc_password: '\u8a2d\u5b9a WebUI \u767b\u5165\u5bc6\u78bc\u3002\u5047\u5982\u5df2\u8a2d\u7f6e\uff0c\u6bcf\u6b21\u52a0\u8f09\u90fd\u9700\u8981\u767b\u5165\u3002', - onboarding_password_will_enable: '\u5c07\u6703\u555f\u7528', - onboarding_password_will_replace: '\u5c07\u6703\u53d6\u4ee3', - onboarding_password_keep_existing: '\u4fdd\u7559\u76ee\u524d\u5bc6\u78bc', - onboarding_password_remains_disabled: '\u6703\u7e7c\u7e8c\u4fdd\u6301\u95dc\u9589', - // boot.js - cancelling: '\u6b63\u5728\u53d6\u6d88...', - cancel_failed: '\u53d6\u6d88\u5931\u6557\uff1a', - mic_denied: '\u9ea6\u514b\u98a8\u8a2a\u554f\u88ab\u62d2\u7d75\uff0c\u8acb\u6aa2\u67e5\u700f\u89bd\u5668\u6b0a\u9650\u3002', - mic_no_speech: '\u6c92\u6709\u6aa2\u6e2c\u5230\u8a71\u97f3\uff0c\u8acb\u518d\u5617\u4e00\u6b21\u3002', - mic_network: '\u8a71\u97f3\u8b58\u5225\u76ee\u524d\u4e0d\u53ef\u7528\u3002', - mic_error: '\u8a71\u97f3\u8f38\u5165\u51fa\u932f\uff1a', - session_imported: '\u6703\u8a71\u5df2\u5c0e\u5165', - import_failed: '\u5c0e\u5165\u5931\u6557\uff1a', - import_invalid_json: 'JSON \u7121\u6548', - image_pasted: '\u5df2\u7c98\u8cbc\u5716\u7247\uff1a', - // messages.js - edit_message: '\u7de8\u8f2f\u8a0a\u606f', - regenerate: '\u91cd\u65b0\u751f\u6210\u56de\u8986', - copy: '\u8907\u88fd', - copied: '\u5df2\u8907\u88fd', - // ui.js - workspace_desc: '\u8acb\u9078\u64c7\u5de5\u4f5c\u5340\uff0c\u6216\u8f09\u5165\u65b0\u540d\u7a31\u5beb\u4e00\u500b', - tab_profiles: '\u914d\u7f6e', - tab_settings: '\u8a2d\u5b9a', - profile_delete_confirm_message: '\u6b64\u914d\u7f6e\u6a94\u7684\u6240\u6709\u6703\u8a71\u3001\u8a2d\u5b9a\u3001\u6280\u80fd\u548c\u8a18\u61b6\u5c07\u88ab\u6c38\u4e45\u522a\u9664\u3002\u6b64\u64cd\u4f5c\u7121\u6cd5\u64a4\u92b7\u3002', - workspace_renamed: '\u5de5\u4f5c\u5340\u5df2\u91cd\u65b0\u547d\u540d', - cron_name_placeholder: '\u9078\u586b', - active_conversation_meta: (n) => `${n} 則訊息`, - all_uploads_failed: (n) => `${n} 個上傳失敗`, - cron_job_name_placeholder: '\u4efb\u52d9\u540d\u7a31', - cron_prompt_placeholder: '\u63d0\u793a\u8a5e', - cron_schedule_placeholder: '\u6392\u7a0b', - delete_confirm: (name) => `刪除「${name}」?`, - downloading: (filename) => `正在下載 ${filename}…`, - n_messages: (n) => `${n} 則訊息`, - load_older_messages: '↑ 向上捲動或點擊以載入較早的訊息', - session_jump_start: '開頭', - session_jump_start_label: '跳至會話開頭', - session_jump_end: '結尾', - session_jump_end_label: '跳至會話結尾', - jump_to_question: '回到問題', - jump_to_question_label: '跳至這則回答對應的問題', - onboarding_api_key_help_prefix: '\u900f\u904e\u4ee5\u4e0b\u65b9\u5f0f\u5132\u5b58\u70ba Hermes .env \u6a94\u6848\u4e2d\u7684\u6a5f\u5bc6', - onboarding_api_key_label: 'API \u91d1\u9470', - onboarding_api_key_placeholder: '\u7559\u7a7a\u4ee5\u4fdd\u7559\u5df2\u5132\u5b58\u7684\u91d1\u9470', - onboarding_api_key_label_optional: 'API key (optional)', // TODO: translate - onboarding_api_key_placeholder_optional: 'Leave blank for keyless servers', // TODO: translate - onboarding_api_key_help_keyless: 'Most LM Studio / Ollama / vLLM installs run keyless — leave this blank if your server doesn\'t require authentication. Use the Test connection button to verify.', // TODO: translate - onboarding_back: '\u4e0a\u4e00\u6b65', - onboarding_badge: '\u9996\u6b21\u57f7\u884c', - onboarding_base_url_help: '\u7528\u65bc OpenAI \u76f8\u5bb9\u8def\u7531\u5668\u3001\u81ea\u67b6\u4f3a\u670d\u5668\u3001LiteLLM\u3001Ollama\u3001LM Studio\u3001vLLM \u7b49\u7aef\u9ede\u3002', - onboarding_base_url_label: '\u57fa\u790e URL', - onboarding_base_url_placeholder: 'https://your-endpoint.example/v1', - onboarding_check_agent: 'Hermes Agent', - onboarding_check_agent_missing: '\u907a\u5931\u6216\u50c5\u90e8\u5206\u53ef\u7528', - onboarding_check_agent_ready: '\u5df2\u5075\u6e2c\u5230\u4e26\u53ef\u4f9b\u532f\u5165', - onboarding_check_password: '\u5bc6\u78bc', - onboarding_check_password_disabled: '\u5c1a\u672a\u555f\u7528', - onboarding_check_password_enabled: '\u5df2\u555f\u7528', - onboarding_check_provider: '\u63d0\u4f9b\u8005\u914d\u7f6e', - onboarding_check_provider_partial: '\u5df2\u5132\u5b58\u4f46\u672a\u5b8c\u6210', - onboarding_check_provider_pending: '\u9700\u8981\u9a57\u8b49', - onboarding_check_provider_ready: '\u53ef\u958b\u59cb\u804a\u5929', - onboarding_complete: '\u521d\u59cb\u8a2d\u5b9a\u5b8c\u6210', - onboarding_config_file: '\u8a2d\u5b9a\u6a94\uff1a', - onboarding_continue: '\u7e7c\u7e8c', - onboarding_current_provider: '\u76ee\u524d\u914d\u7f6e\uff1a', - onboarding_custom_model_help: '\u5c0d\u65bc\u81ea\u8a02\u7aef\u9ede\uff0c\u8acb\u6307\u5b9a\u60a8\u7684\u4f3a\u670d\u5668\u9810\u671f\u7684\u6a21\u578b ID\u3002', - onboarding_custom_model_placeholder: 'your_model_name', - onboarding_env_file: '.env \u6a94\u6848\uff1a', - onboarding_error_base_url_required: '\u81ea\u8a02\u7aef\u9ede\u9700\u8981\u57fa\u790e URL\u3002', - onboarding_probe_test_button: 'Test connection', // TODO: translate - onboarding_probe_probing: 'Testing connection…', // TODO: translate - onboarding_probe_ok: 'Connected. {n} model(s) available.', // TODO: translate - onboarding_probe_error_generic: 'Could not reach the configured base URL.', // TODO: translate - onboarding_probe_error_invalid_url: 'Base URL must start with http:// or https://.', // TODO: translate - onboarding_probe_error_dns: 'Could not resolve the host. Check the URL or use the host\'s IP address.', // TODO: translate - onboarding_probe_error_connect_refused: 'Connection refused — the server may not be running on that address. From inside Docker, try the host IP instead of localhost.', // TODO: translate - onboarding_probe_error_timeout: 'The endpoint did not respond in time. Check that the server is running and the URL is correct.', // TODO: translate - onboarding_probe_error_http_4xx: 'The endpoint returned a client error. Check authentication and the URL path (typically ends in /v1).', // TODO: translate - onboarding_probe_error_http_5xx: 'The endpoint returned a server error. Check the LM Studio / Ollama server logs.', // TODO: translate - onboarding_probe_error_parse: 'The endpoint did not return a model list in the expected shape. Verify the URL points to the OpenAI-compatible API root.', // TODO: translate - onboarding_probe_error_unreachable: 'Could not reach the configured base URL.', // TODO: translate - onboarding_error_probe_failed: 'Could not validate the configured base URL.', // TODO: translate - onboarding_error_choose_model: '\u8acb\u5148\u9078\u64c7\u6a21\u578b\u518d\u7e7c\u7e8c\u3002', - onboarding_error_choose_workspace: '\u8acb\u5148\u9078\u64c7\u5de5\u4f5c\u5340\u518d\u7e7c\u7e8c\u3002', - onboarding_error_model_required: '\u9700\u8981\u6a21\u578b\u3002', - onboarding_error_provider_required: '\u8acb\u5148\u9078\u64c7\u8a2d\u5b9a\u6a21\u5f0f\u518d\u7e7c\u7e8c\u3002', - onboarding_error_workspace_required: '\u9700\u8981\u5de5\u4f5c\u5340\u3002', - onboarding_finish_help: '\u5b8c\u6210\u5f8c\uff0conboarding_completed \u5c07\u5132\u5b58\u5728\u8a2d\u5b9a\u4e2d\uff0c\u60a8\u5c07\u9032\u5165\u6b63\u5e38\u61c9\u7528\u7a0b\u5f0f\u3002', - onboarding_lead: '\u5feb\u901f\u9010\u6b65\u8a2d\u5b9a\uff1a\u6aa2\u67e5 Hermes\u3001\u5132\u5b58\u63d0\u4f9b\u8005\u914d\u7f6e\u3001\u9078\u64c7\u5de5\u4f5c\u5340\u8207\u6a21\u578b\uff0c\u4e26\u53ef\u9078\u64c7\u52a0\u5165\u5bc6\u78bc\u4fdd\u8b77\u3002', - onboarding_missing_imports: '\u7f3a\u5c11\u7684\u532f\u5165\uff1a', - onboarding_model_label: '\u9810\u8a2d\u6a21\u578b', - onboarding_not_set: '\u672a\u8a2d\u5b9a', - onboarding_notice_finish: '\u60a8\u4e4b\u5f8c\u53ef\u4ee5\u96a8\u6642\u56de\u5230\u8a2d\u5b9a\u9801\u9762\u8b8a\u66f4\u9019\u4e9b\u503c\u3002', - onboarding_notice_password_enabled: '\u5bc6\u78bc\u5df2\u8a2d\u5b9a\u3002\u50c5\u5728\u9700\u8981\u53d6\u4ee3\u6642\u8f38\u5165\u65b0\u5bc6\u78bc\u3002', - onboarding_notice_password_recommended: '\u9078\u586b\uff0c\u4f46\u5efa\u8b70\u5728\u975e localhost \u74b0\u5883\u4f7f\u7528\u3002', - onboarding_notice_setup_already_ready: '\u5df2\u5075\u6e2c\u5230\u53ef\u7528\u7684 Hermes \u63d0\u4f9b\u8005\u914d\u7f6e\u3002\u60a8\u53ef\u4ee5\u4fdd\u7559\u6216\u5728\u6b64\u53d6\u4ee3\u3002', - onboarding_notice_setup_required: '\u5728\u6b64\u9078\u64c7\u5feb\u901f\u63d0\u4f9b\u8005\u8a2d\u5b9a\u8def\u5f91\u3002\u9032\u968e OAuth \u8a2d\u5b9a\u4ecd\u8acb\u4f7f\u7528 Hermes CLI\u3002', - onboarding_notice_system_ready: 'Hermes Agent \u53ef\u5f9e Web UI \u5b58\u53d6\u3002', - onboarding_notice_system_unavailable: 'Hermes Agent \u5c1a\u672a\u5b8c\u5168\u53ef\u7528\u3002\u5f15\u5c0e\u7a0b\u5f0f\u53ef\u80fd\u5b89\u88dd\u5b83\uff0c\u4f46\u63d0\u4f9b\u8005\u8a2d\u5b9a\u53ef\u80fd\u4ecd\u9700\u7d42\u7aef\u6a5f\u3002', - onboarding_notice_workspace: '\u9019\u4e9b\u503c\u4f7f\u7528\u8207\u4e00\u822c\u61c9\u7528\u7a0b\u5f0f\u76f8\u540c\u7684\u8a2d\u5b9a API\u3002', - onboarding_oauth_provider_not_ready_body: '\u6b64\u5be6\u4f8b\u8a2d\u5b9a\u4f7f\u7528 {provider}\uff0c\u5b83\u4f7f\u7528 OAuth \u800c\u975e API \u91d1\u9470\u3002\u8acb\u5728\u7d42\u7aef\u6a5f\u4e2d\u57f7\u884c hermes auth \u6216 hermes model \u9032\u884c\u6388\u6b0a\uff0c\u7136\u5f8c\u91cd\u65b0\u6574\u7406 Web UI\u3002', - onboarding_oauth_provider_not_ready_title: 'OAuth \u63d0\u4f9b\u8005\u5c1a\u672a\u6388\u6b0a', - onboarding_oauth_provider_ready_body: '\u6b64\u5be6\u4f8b\u8a2d\u5b9a\u4f7f\u7528\u900f\u904e Hermes CLI \u914d\u7f6e\u7684 OAuth \u63d0\u4f9b\u8005\uff08{provider}\uff09\u3002\u7121\u9700 API \u91d1\u9470 \u2014 \u6309\u7e7c\u7e8c\u5b8c\u6210\u8a2d\u5b9a\u3002', - onboarding_oauth_provider_ready_title: '\u63d0\u4f9b\u8005\u5df2\u6388\u6b0a', - onboarding_oauth_switch_hint: '\u6216\u9078\u64c7\u4e0b\u65b9\u5176\u4ed6\u63d0\u4f9b\u8005\u4ee5\u5207\u63db\u5230 API \u91d1\u9470\u8a2d\u5b9a\uff1a', - onboarding_open: '\u958b\u555f Hermes', - onboarding_password_help: '\u5bc6\u78bc\u900f\u904e\u73fe\u6709\u8a2d\u5b9a API \u5132\u5b58\uff0c\u4e26\u5728\u4f3a\u670d\u5668\u7aef\u9032\u884c\u96dc\u6e4a\u8655\u7406\u3002', - onboarding_password_label: '\u5bc6\u78bc\uff08\u9078\u586b\uff09', - onboarding_password_placeholder: '\u7559\u7a7a\u4ee5\u8df3\u904e', - onboarding_password_remains_disabled: '\u5c07\u4fdd\u6301\u505c\u7528', - onboarding_password_skipped: '\u66ab\u6642\u8df3\u904e', - onboarding_password_will_enable: '\u5c07\u555f\u7528', - onboarding_password_will_replace: '\u5c07\u53d6\u4ee3', - onboarding_provider_label: '\u8a2d\u5b9a\u6a21\u5f0f', - onboarding_quick_setup_badge: '\u5feb\u901f\u8a2d\u5b9a', - oauth_login_codex: 'Login with Codex (ChatGPT)', // TODO: translate - oauth_codex_step1: 'Step 1: Visit this URL and enter the code', // TODO: translate - oauth_codex_step2: 'Step 2: Enter this code on the page', // TODO: translate - oauth_codex_polling: 'Waiting for authorization...', // TODO: translate - oauth_codex_success: 'Codex OAuth login successful!', // TODO: translate - oauth_codex_error: 'OAuth login failed', // TODO: translate - oauth_codex_expired: 'Code expired, please try again', // TODO: translate - provider_category_easy_start: '\u5feb\u901f\u958b\u59cb', - provider_category_self_hosted: '\u672c\u5730 / \u958b\u6e90', - provider_category_specialized: '\u5c08\u696d\u670d\u52d9', - onboarding_skip: '\u8df3\u904e\u8a2d\u5b9a', - onboarding_skipped: '\u5df2\u8df3\u904e\u8a2d\u5b9a \u2014 \u4f7f\u7528\u73fe\u6709\u914d\u7f6e\u3002', - onboarding_step_finish_desc: '\u6aa2\u8996\u8a2d\u5b9a\u4e26\u9032\u5165\u61c9\u7528\u7a0b\u5f0f\u3002', - onboarding_step_finish_title: '\u5b8c\u6210', - onboarding_step_password_desc: '\u5206\u4eab\u524d\u4fdd\u8b77 Web UI\u3002', - onboarding_step_password_title: '\u9078\u586b\u5bc6\u78bc', - onboarding_step_setup_desc: '\u5132\u5b58\u6700\u5c0f\u53ef\u7528\u7684 Hermes \u63d0\u4f9b\u8005\u914d\u7f6e\u3002', - onboarding_step_setup_title: '\u63d0\u4f9b\u8005\u8a2d\u5b9a', - onboarding_step_system_desc: '\u9a57\u8b49 Hermes Agent \u8207\u914d\u7f6e\u53ef\u898b\u6027\u3002', - onboarding_step_system_title: '\u7cfb\u7d71\u6aa2\u67e5', - onboarding_step_workspace_desc: '\u70ba\u65b0\u6703\u8a71\u9078\u64c7\u9810\u8a2d\u503c\u3002', - onboarding_step_workspace_title: '\u5de5\u4f5c\u5340\u8207\u6a21\u578b', - onboarding_title: '\u6b61\u8fce\u4f7f\u7528 Hermes Web UI', - onboarding_unknown: '\u672a\u77e5', - onboarding_workspace_help: '\u9078\u64c7 Hermes \u5728\u8a2d\u5b9a\u5b8c\u6210\u5f8c\u7528\u65bc\u65b0\u804a\u5929\u5ba4\u7684\u6a21\u578b\u3002', - onboarding_workspace_label: '\u5de5\u4f5c\u5340', - onboarding_workspace_or_path: '\u6216\u8f38\u5165\u5de5\u4f5c\u5340\u8def\u5f91', - onboarding_workspace_placeholder: '/home/you/workspace', - project_name_prompt: '\u5c08\u6848\u540d\u7a31\uff1a', - provider_mismatch_warning: (provider) => `提供者不符:會話使用 ${provider}`, - session_meta_messages: (n) => `${n} 則訊息`, - session_meta_children: (n) => `${n} 則子`, - session_meta_segments: (n) => `${n} 段`, - session_lineage_segment_untitled: '未命名段', - session_lineage_segment_open: '開啟脈絡段', - skill_created: '\u6280\u80fd\u5df2\u5efa\u7acb', - skill_file_load_failed: '\u8f09\u5165\u6a94\u6848\u5931\u6557\uff1a', - skill_load_failed: '\u8f09\u5165\u6280\u80fd\u5931\u6557\uff1a', - skill_name_required: '\u9700\u8981\u6280\u80fd\u540d\u7a31', - skill_updated: '\u6280\u80fd\u5df2\u66f4\u65b0', - skills_no_match: '\u627e\u4e0d\u5230\u7b26\u5408\u7684\u6280\u80fd\u3002', - slash_skill_badge: '\u6280\u80fd', - slash_skill_desc: '\u547c\u53eb\u6b64\u6280\u80fd', - title_change_hint: '\u4f7f\u7528 /title <\u65b0\u540d\u7a31> \u91cd\u65b0\u547d\u540d\u3002', - title_current: '\u76ee\u524d\u6a19\u984c', - title_set: '\u6a19\u984c\u5df2\u8a2d\u70ba', - todos_no_active: '\u6b64\u6703\u8a71\u4e2d\u7121\u6d3b\u8e8d\u4efb\u52d9\u6e05\u55ae\u3002', - upload_failed: '\u4e0a\u50b3\u5931\u6557\uff1a', - upload_too_large: (maxMb, fileMb) => `\u6a94\u6848\u904e\u5927\uff08${fileMb} MB\uff09\u3002\u6700\u5927\u4e0a\u50b3\u5927\u5c0f\u70ba ${maxMb} MB\u3002`, - uploading: '上传中…', - uploaded: '已上传', - active_conversation_none: '\u672a\u9078\u53d6\u6d3b\u8e8d\u6703\u8a71\u3002', - add: '\u65b0\u589e', - add_failed: '\u65b0\u589e\u5931\u6557\uff1a', - auth_disabled: '\u9a57\u8b49\u5df2\u505c\u7528 \u2014 \u5bc6\u78bc\u4fdd\u8b77\u5df2\u95dc\u9589', - cancel_unavailable: '\u7121\u6cd5\u53d6\u6d88\u3002', - clear_conversation_message: '\u6e05\u9664\u6240\u6709\u8a0a\u606f\uff1f\u6b64\u64cd\u4f5c\u7121\u6cd5\u5fa9\u539f\u3002', - clear_conversation_title: '\u6e05\u9664\u5c0d\u8a71', - clear_failed: '\u6e05\u9664\u5931\u6557\uff1a', - content_required: '\u9700\u8981\u5167\u5bb9', - create_failed: '\u5efa\u7acb\u5931\u6557\uff1a', - delete_failed: '\u522a\u9664\u5931\u6557\uff1a', - disable: '\u505c\u7528', - disable_auth: '\u505c\u7528\u9a57\u8b49', - disable_auth_confirm_message: '\u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u5b58\u53d6\u6b64\u5be6\u4f8b\u3002', - disable_auth_confirm_title: '\u505c\u7528\u5bc6\u78bc\u4fdd\u8b77', - disable_auth_failed: '\u505c\u7528\u9a57\u8b49\u5931\u6557\uff1a', - discard_file_edits_message: '\u5207\u63db\u5de5\u4f5c\u5340\u5c07\u653e\u68c4\u672a\u5132\u5b58\u7684\u9810\u89bd\u8b8a\u66f4\u3002', - discard_file_edits_title: '\u653e\u68c4\u6a94\u6848\u7de8\u8f2f\uff1f', - dismiss: '\u95dc\u9589', - edit: '\u7de8\u8f2f', - error_prefix: '\u932f\u8aa4\uff1a', - default: 'default', - search: 'Search', - linked_files: '\u95dc\u806f\u6a94\u6848', - manage_profiles: '\u7ba1\u7406\u8a2d\u5b9a\u6a94', - memory_notes_label: '\u8a18\u61b6\uff08\u5099\u8a3b\uff09', - model_custom_label: '\u81ea\u8a02\u6a21\u578b ID', - model_custom_placeholder: '\u4f8b\u5982 openai/gpt-5.4', - model_search_no_results: '\u627e\u4e0d\u5230\u6a21\u578b', - model_group_configured: '已設定', - ws_search_placeholder: '搜尋工作區…', - ws_no_results: '找不到工作區', - model_search_placeholder: '\u641c\u5c0b\u6a21\u578b\u2026', - session_toolsets: 'Session Toolsets', // TODO: translate - session_toolsets_desc: 'Restrict available tools for this session (blank = use global config)', // TODO: translate - session_toolsets_global: 'Global (default)', // TODO: translate - session_toolsets_custom: 'Custom', // TODO: translate - session_toolsets_placeholder: 'tool1, tool2, \u2026', // TODO: translate - session_toolsets_apply: 'Apply', // TODO: translate - session_toolsets_clear: 'Clear (use global)', // TODO: translate - session_toolsets_applied: 'Toolsets updated', // TODO: translate - session_toolsets_cleared: 'Toolsets cleared — using global config', // TODO: translate - session_toolsets_failed: 'Failed to update toolsets: ', // TODO: translate - model_scope_advisory: '\u5f9e\u4e0b\u4e00\u5247\u8a0a\u606f\u8d77\u9069\u7528\u65bc\u6b64\u6703\u8a71\u3002', - model_scope_toast: '\u5f9e\u4e0b\u4e00\u5247\u8a0a\u606f\u8d77\u9069\u7528\u65bc\u6b64\u6703\u8a71\u3002', - my_notes: '\u6211\u7684\u5099\u8a3b', - name_required: '\u9700\u8981\u540d\u7a31', - never: '\u5f9e\u4e0d', - no_active_session: '\u7121\u6d3b\u8e8d\u6703\u8a71', - cmd_queue: '\u5c07\u8a0a\u606f\u52a0\u5165\u4e0b\u4e00\u8f2a\u7684\u4f47\u5217', - cmd_goal: '設定或查看持久目標', - goal_evaluating_progress: 'Evaluating goal progress…', - goal_working_toward: 'Working toward goal…', - goal_continuing_toast: 'Continuing toward goal…', - goal_status_none: 'No active goal. Set one with /goal .', - goal_status_active: (turns, max_turns, goal) => `⊙ Goal (active, ${turns}/${max_turns} turns): ${goal}`, - goal_status_paused: (turns, max_turns, reason, goal) => `⏸ Goal (paused, ${turns}/${max_turns}${reason ? `, ${reason}` : ''}): ${goal}`, - goal_status_done: (turns, max_turns, goal) => `✓ Goal done (${turns}/${max_turns}): ${goal}`, - goal_set: (turns, goal) => `⊙ Goal set (${turns}-turn budget): ${goal}`, - goal_paused: (goal) => `⏸ Goal paused: ${goal}`, - goal_resumed: (goal) => `▶ Goal resumed: ${goal}`, - goal_cleared: 'Goal cleared.', - goal_no_goal: 'No active goal.', - goal_achieved: (reason) => `✓ Goal achieved: ${reason}`, - goal_paused_budget_exhausted: (turns, max_turns) => `⏸ Goal paused — ${turns}/${max_turns} turns used. Use /goal resume to keep going, or /goal clear to stop.`, - goal_continuing: (turns, max_turns, reason) => `↻ Continuing toward goal (${turns}/${max_turns}): ${reason}`, - cmd_interrupt: '\u53d6\u6d88\u7576\u524d\u56de\u5408\u4e26\u767c\u9001\u65b0\u8a0a\u606f', - cmd_steer: '\u5728\u56de\u5408\u9032\u884c\u4e2d\u6ce8\u5165\u7d3a\u6b63\uff0c\u4e0d\u4e2d\u65b7\u4ee3\u7406', - cmd_queue_no_msg: '\u7528\u6cd5\uff1a/queue <\u8a0a\u606f>', - cmd_queue_not_busy: '\u6c92\u6709\u6d3b\u52d5\u4efb\u52d9 \u2014 \u76f4\u63a5\u767c\u9001\u5373\u53ef', - cmd_queue_confirm: '\u8a0a\u606f\u5df2\u52a0\u5165\u4f47\u5217', - cmd_interrupt_no_msg: '\u7528\u6cd5\uff1a/interrupt <\u8a0a\u606f>', - cmd_interrupt_confirm: '\u5df2\u4e2d\u65ad \u2014 \u6b63\u5728\u767c\u9001\u65b0\u8a0a\u606f', - cmd_steer_no_msg: '\u7528\u6cd5\uff1a/steer <\u8a0a\u606f>', - cmd_steer_fallback: 'Steer \u4e0d\u53ef\u7528 \u2014 \u5df2\u52a0\u5165\u4e0b\u4e00\u8f2a\u4f47\u5217', - cmd_steer_delivered: 'Steer \u5df2\u9001\u9054 \u2014 \u4ee3\u7406\u5c07\u5728\u4e0b\u4e00\u500b\u5de5\u5177\u7d50\u679c\u4e2d\u770b\u5230', - steer_leftover_queued: 'Steer \u5df2\u52a0\u5165\u4e0b\u4e00\u8f2a\u4f47\u5217', - busy_steer_fallback: 'Steer \u4e0d\u53ef\u7528 \u2014 \u5df2\u52a0\u5165\u4e0b\u4e00\u8f2a\u4f47\u5217', - busy_interrupt_confirm: '\u5df2\u4e2d\u65ad \u2014 \u6b63\u5728\u767c\u9001\u65b0\u8a0a\u606f', - settings_label_busy_input_mode: '\u5fd9\u788c\u8f38\u5165\u6a21\u5f0f', - settings_desc_busy_input_mode: '\u63a7\u5236\u5728\u4ee3\u7406\u904b\u884c\u6642\u767c\u9001\u8a0a\u606f\u7684\u884c\u70ba\u3002\u4f47\u5217\u7b49\u5f85\uff1b\u4e2d\u65b7\u53d6\u6d88\u4e26\u91cd\u65b0\u958b\u59cb\uff1bSteer\u4e2d\u9014\u6ce8\u5165\u7d3a\u6b63\uff0c\u4e0d\u4e2d\u65b7\u3002', - settings_label_fade_text_effect: '文字淡入效果', - settings_desc_fade_text_effect: '在助理回覆時讓新串流輸出的詞語淡入顯示。類似 OpenWebUI;為獲得最佳效能預設關閉。', - settings_busy_input_mode_queue: '\u52a0\u5165\u4f47\u5217', - settings_busy_input_mode_interrupt: '\u4e2d\u65ad\u7576\u524d\u56de\u5408', - settings_busy_input_mode_steer: 'Steer\uff08\u4e2d\u9014\u7d3a\u6b63\uff09', - no_active_task: '\u7121\u57f7\u884c\u4e2d\u7684\u4efb\u52d9\u53ef\u505c\u6b62\u3002', - no_notes_yet: '\u5c1a\u7121\u5099\u8a3b\u3002', - no_profile_yet: '\u5c1a\u7121\u8a2d\u5b9a\u6a94\u3002', - agent_soul: '智能體靈魂', - no_soul_yet: '尚無靈魂定義。', - external_notes_sources: '第三方筆記', - external_notes_empty: '尚未看到任何筆記或知識 MCP 來源。設定 Joplin、Obsidian、Notion、llm-wiki 或其他筆記伺服器後,會顯示在這裡。', - external_notes_auto_recall_hint: '自動會話召回維持不變;這個抽屜只顯示已設定的來源,以及可用的讀取/搜尋工具。', - external_notes_no_tools: '此來源目前沒有可見的讀取/搜尋工具。', - external_notes_tool_count: (count) => `${count} 個筆記工具可用`, - external_notes_configured_hint: '此已設定來源應提供工具名稱;當 WebUI 執行階段提供即時 schema 時會顯示在這裡。', - external_notes_recent_ai: 'AI 最近使用', - external_notes_auto: 'auto', - external_notes_recent_ai_reason: '自動召回', - external_notes_search_placeholder: '搜尋筆記…', - external_notes_search_empty: '搜尋已設定的筆記來源後,可在這裡預覽筆記。', - not_available: '\u7121', - profile_active: '\u555f\u7528\u4e2d', - profile_api_key_placeholder: 'API \u91d1\u9470\uff08\u9078\u586b\uff09', - profile_api_keys_configured: 'API \u91d1\u9470\u5df2\u8a2d\u5b9a', - profile_base_url_placeholder: '\u57fa\u672c URL\uff08\u9078\u586b\uff0c\u4f8b\u5982 http://localhost:11434\uff09', - profile_base_url_rule: '\u57fa\u672c URL \u5fc5\u9808\u4ee5 http:// \u6216 https:// \u958b\u982d', - profile_clone_label: '\u5f9e\u555f\u7528\u4e2d\u7684\u8a2d\u5b9a\u6a94\u8907\u88fd\u914d\u7f6e', - profile_model_label: '\u6a21\u578b / \u63d0\u4f9b\u5546', - profile_model_hint: '\u70ba\u9019\u500b\u65b0\u8a2d\u5b9a\u6a94\u9078\u64c7\u5df2\u8a2d\u5b9a\u7684\u63d0\u4f9b\u5546\u548c\u6a21\u578b\u3002', - profile_model_use_default: '\u4f7f\u7528\u555f\u7528\u4e2d\u8a2d\u5b9a\u6a94\u7684\u9810\u8a2d\u503c', - profile_created: (name) => `設定檔 ${name} 已建立`, - profile_default_label: '\uff08\u9810\u8a2d\uff09', - profile_delete_confirm_title: (name) => `刪除設定檔「${name}」?`, - profile_deleted: (name) => `設定檔 ${name} 已刪除`, - profile_gateway_running: 'Gateway \u57f7\u884c\u4e2d', - profile_gateway_stopped: 'Gateway \u5df2\u505c\u6b62', - profile_name_placeholder: '\u8a2d\u5b9a\u6a94\u540d\u7a31\uff08\u5c0f\u5beb\u5b57\u6bcd\u3001\u6578\u5b57\u3001\u9023\u5b57\u865f\uff09', - profile_name_rule: '\u50c5\u9650\u5c0f\u5beb\u5b57\u6bcd\u3001\u6578\u5b57\u3001\u9023\u5b57\u865f\u548c\u5e95\u7dda', - profile_no_configuration: '\u7121\u914d\u7f6e', - profile_skill_count: (n) => `${n} 個技能`, - profile_switch_title: '\u5207\u63db\u5230\u6b64\u8a2d\u5b9a\u6a94', - profile_switched: (name) => `已切換到 ${name}`, - profile_switched_new_conversation: (name) => `已切換到 ${name}(新會話)`, - profile_use: '\u4f7f\u7528', - profiles_load_failed: '\u8f09\u5165\u8a2d\u5b9a\u6a94\u5931\u6557', - profiles_no_profiles: '\u627e\u4e0d\u5230\u8a2d\u5b9a\u6a94\u3002', - remove: '\u79fb\u9664', - remove_failed: '\u79fb\u9664\u5931\u6557\uff1a', - rename_failed: '\u91cd\u65b0\u547d\u540d\u5931\u6557\uff1a', - retry_failed: '\u91cd\u8a66\u5931\u6557\uff1a', - save: '\u5132\u5b58', - save_failed: '\u5132\u5b58\u5931\u6557\uff1a', - session_time_bucket_last_week: '\u4e0a\u9031', - session_time_bucket_older: '\u66f4\u65e9', - session_time_bucket_this_week: '\u672c\u9031', - session_time_bucket_today: '\u4eca\u5929', - session_time_bucket_yesterday: '\u6628\u5929', - session_time_days_ago: (d) => `${d}\u5929`, - session_time_hours_ago: (h) => `${h}\u5c0f\u6642`, - session_time_last_week: '1\u9031', - session_time_minutes_ago: (m) => `${m}\u5206`, - session_time_unknown: '\u672a\u77e5', - settings_unsaved_changes: '\u60a8\u6709\u672a\u5132\u5b58\u7684\u8b8a\u66f4\u3002', - sign_out_failed: '\u767b\u51fa\u5931\u6557\uff1a', - stream_stopped: '\u56de\u61c9\u5df2\u505c\u6b62\u3002', - switch_failed: '\u5207\u63db\u5931\u6557\uff1a', - undid_messages_suffix: '\u5247\u8a0a\u606f\u3002', - undid_n_messages: '\u5df2\u79fb\u9664', - undo_exchange: '\u5fa9\u539f\u6700\u5f8c\u4e00\u8f2a', - undo_failed: '\u5fa9\u539f\u5931\u6557\uff1a', - user_profile: '\u4f7f\u7528\u8005\u8a2d\u5b9a\u6a94', - view: '\u6aa2\u8996', - workspace_add_path_placeholder: '\u65b0\u589e\u5de5\u4f5c\u5340\u8def\u5f91\uff08\u4f8b\u5982 /Users/you/project\uff09', - workspace_added: '\u5de5\u4f5c\u5340\u5df2\u65b0\u589e', - workspace_already_saved: '\u5de5\u4f5c\u5340\u5df2\u5132\u5b58 \u2014 \u5f9e\u6e05\u55ae\u4e2d\u9078\u53d6', - workspace_busy_switch: 'Agent \u57f7\u884c\u4e2d\u7121\u6cd5\u5207\u63db\u5de5\u4f5c\u5340', - workspace_choose_path: '\u9078\u64c7\u5de5\u4f5c\u5340\u8def\u5f91', - workspace_choose_path_meta: '\u65b0\u589e\u9a57\u8b49\u904e\u7684\u8def\u5f91\u4e26\u5207\u63db\u6b64\u6703\u8a71', - workspace_manage: '\u7ba1\u7406\u5de5\u4f5c\u5340', - workspace_manage_meta: '\u958b\u555f Spaces \u9762\u677f', - workspace_not_added: '\u5de5\u4f5c\u5340\u672a\u65b0\u589e', - workspace_paths_validated_hint: '\u8def\u5f91\u6703\u5148\u9a57\u8b49\u662f\u5426\u5b58\u5728\u518d\u5132\u5b58\u3002', - - workspace_drag_hint: '拖曳以重新排列', - workspace_reorder_failed: '重新排列失敗', - workspace_remove_confirm_message: (name) => `移除工作區「${name}」?`, - workspace_remove_confirm_title: '\u79fb\u9664\u5de5\u4f5c\u5340', - workspace_removed: '\u5de5\u4f5c\u5340\u5df2\u79fb\u9664', - workspace_switch_prompt_confirm: '\u5207\u63db', - workspace_switch_prompt_message: '\u8f38\u5165\u5de5\u4f5c\u5340\u7684\u7d55\u5c0d\u8def\u5f91\u4ee5\u65b0\u589e\u4e26\u5207\u63db\u6b64\u6703\u8a71\u3002', - workspace_switch_prompt_placeholder: '/Users/you/project', - workspace_switch_prompt_title: '\u5207\u63db\u5de5\u4f5c\u5340', - workspace_switched_to: (name) => `已切換到 ${name}`, - workspace_use: '\u4f7f\u7528', - workspace_use_title: '\u5728\u7576\u524d\u6703\u8a71\u4e2d\u4f7f\u7528', - bg_complete: '\u80cc\u666f\u4efb\u52d9\u5b8c\u6210', - bg_error_multi: (n) => `${n} 個背景任務失敗`, - cmd_status: '顯示會話資訊', - memory_saved: '記憶已儲存', - profile_delete_title: '刪除此設定檔', - bg_error_single: (n) => `${n} 個背景任務失敗`, - bg_failed: '\u80cc\u666f\u4efb\u52d9\u5931\u6557\uff1a', - bg_label: '\u80cc\u666f\u7d50\u679c\uff1a', - bg_no_answer: '\uff08\u7121\u56de\u61c9\uff09', - bg_running: '\u80cc\u666f\u57f7\u884c\u4e2d\u2026', - btw_asking: '\u6b63\u5728\u8a62\u554f\u9644\u5e36\u554f\u984c\u2026', - btw_done: '\u9644\u5e36\u554f\u984c\u5df2\u56de\u7b54', - btw_failed: '\u9644\u5e36\u554f\u984c\u5931\u6557\uff1a', - btw_label: '\u9644\u5e36\u554f\u984c \u2014 \u4e0d\u5728\u6b77\u53f2\u8a18\u9304\u4e2d', - btw_no_answer: '\u672a\u6536\u5230\u56de\u61c9\u3002', - cmd_background: '\u5728\u80cc\u666f\u57f7\u884c\u63d0\u793a\u8a5e', - cmd_background_usage: '/background <\u63d0\u793a\u8a5e> \u2014 \u5e73\u884c\u57f7\u884c\u4e0d\u963b\u585e', - cmd_btw: '\u63d0\u51fa\u9644\u5e36\u554f\u984c\uff08\u66ab\u6642\u6027\uff09', - cmd_btw_usage: '/btw <\u554f\u984c> \u2014 \u4f7f\u7528\u7576\u524d\u6703\u8a71\u80cc\u666f\u63d0\u554f', - cmd_compact: '\u58d3\u7e2e\u5c0d\u8a71\u4e0a\u4e0b\u6587', - cmd_retry: '\u91cd\u65b0\u767c\u9001\u6700\u5f8c\u4e00\u689d\u8a0a\u606f', - cmd_stop: '\u505c\u6b62\u7576\u524d\u56de\u61c9', - cmd_title: '\u53d6\u5f97\u6216\u8a2d\u5b9a\u6703\u8a71\u6a19\u984c', - cmd_undo: '\u79fb\u9664\u6700\u5f8c\u4e00\u8f2a\u5c0d\u8a71', - cmd_voice: '\u5207\u63db\u9ea5\u514b\u98a8\u8f38\u5165', - cmd_voice_use_mic: '\u9ede\u64ca\u7de8\u8f2f\u5668\u4e2d\u7684\u9ea5\u514b\u98a8\u6309\u9215\u3002', - cmd_webui_only_session: '\u6b64\u6307\u4ee4\u4e0d\u9069\u7528\u65bc CLI \u532f\u5165\u7684\u6703\u8a71\u3002', - cron_all_runs: '\u6240\u6709\u57f7\u884c', - cron_completion_status: (n) => `${n} 次完成`, - cron_delete_confirm_message: '\u6b64\u64cd\u4f5c\u7121\u6cd5\u5fa9\u539f\u3002', - cron_delete_confirm_title: '\u522a\u9664\u6392\u7a0b\u4efb\u52d9', - cron_hide_runs: '\u96b1\u85cf\u57f7\u884c\u8a18\u9304', - cron_job_created: '\u6392\u7a0b\u4efb\u52d9\u5df2\u5efa\u7acb', - cron_duplicate: '\u8907\u88fd', - cron_duplicated: '\u4efb\u52d9\u5df2\u8907\u88fd\uff08\u5df2\u66ab\u505c\uff09', - cron_job_deleted: '\u6392\u7a0b\u4efb\u52d9\u5df2\u522a\u9664', - cron_job_name_placeholder: '\u4efb\u52d9\u540d\u7a31', - cron_job_paused: '\u6392\u7a0b\u4efb\u52d9\u5df2\u66ab\u505c', - cron_job_resumed: '\u6392\u7a0b\u4efb\u52d9\u5df2\u6062\u5fa9', - cron_job_triggered: '\u6392\u7a0b\u4efb\u52d9\u5df2\u89f8\u767c', - cron_job_updated: '\u6392\u7a0b\u4efb\u52d9\u5df2\u66f4\u65b0', - cron_last: '\u4e0a\u6b21', - cron_last_output: '\u6700\u5f8c\u8f38\u51fa', - cron_expand_prompt: '展開提示詞', - cron_collapse_prompt: '收起提示詞', - cron_expand_output: '展開輸出', - cron_collapse_output: '收起輸出', - cron_view_full_output: 'View full output', - cron_next: '\u4e0b\u6b21', - cron_no_jobs: '\u627e\u4e0d\u5230\u6392\u7a0b\u4efb\u52d9\u3002', - cron_no_runs_yet: '\uff08\u5c1a\u7121\u57f7\u884c\u8a18\u9304\uff09', - cron_pause: '\u66ab\u505c', - cron_prompt_placeholder: '\u63d0\u793a\u8a5e', - cron_prompt_required: '\u9700\u8981\u63d0\u793a\u8a5e', - cron_resume: '\u6062\u5fa9', - cron_run_now: '\u7acb\u5373\u57f7\u884c', - cron_schedule_placeholder: '\u6392\u7a0b', - cron_schedule_required: '\u9700\u8981\u6392\u7a0b', - cron_schedule_required_example: '\u9700\u8981\u6392\u7a0b\uff08\u4f8b\u5982 "0 9 * * *" \u6216 "every 1h"\uff09', - cron_status_active: '已啟用', - cron_status_running: '\u57f7\u884c\u4e2d\u2026', - cron_status_error: '\u932f\u8aa4', - cron_status_off: '\u672a\u555f\u7528', - cron_status_paused: '\u5df2\u66ab\u505c', - cron_status_needs_attention: '\u9700\u8981\u8655\u7406', - cron_attention_desc: '\u9019\u500b\u91cd\u8907\u6392\u7a0b\u4efb\u52d9\u6c92\u6709\u4e0b\u6b21\u57f7\u884c\u6642\u9593\u3002\u6392\u7a0b\u5668\u53ef\u80fd\u7121\u6cd5\u8a08\u7b97\u4e0b\u4e00\u6b21\u57f7\u884c\u3002', - cron_attention_croniter_hint: 'Gateway \u57f7\u884c\u74b0\u5883\u53ef\u80fd\u7f3a\u5c11 croniter \u5957\u4ef6\u3002\u8acb\u7528\u652f\u63f4 cron \u7684\u74b0\u5883\u91cd\u555f Gateway\uff0c\u7136\u5f8c\u6062\u5fa9\u9019\u500b\u4efb\u52d9\u3002', - cron_attention_resume: '\u6062\u5fa9\u4e26\u91cd\u65b0\u8a08\u7b97', - cron_jobs_project: '\u5b9a\u6642\u4efb\u52d9', - cron_attention_run_once: '\u7acb\u5373\u57f7\u884c\u4e00\u6b21', - cron_attention_copy_diagnostics: '\u8907\u88fd\u8a3a\u65b7\u8cc7\u8a0a', - cron_diagnostics_copied: '\u6392\u7a0b\u4efb\u52d9\u8a3a\u65b7\u8cc7\u8a0a\u5df2\u8907\u88fd', - providers_empty: '\u627e\u4e0d\u5230\u53ef\u8a2d\u5b9a\u7684\u63d0\u4f9b\u8005\u3002', - providers_enter_key: '\u8acb\u8f38\u5165 API \u91d1\u9470', + settings_desc_sync_insights: '將 WebUI token 用量鏡射到 state.db,讓 hermes /insights 納入瀏覽器工作階段資料。預設為關閉。', + settings_desc_check_updates: '有較新版 WebUI 或 Agent 時顯示橫幅。系統會定期在背景執行 git fetch。', + settings_desc_ignore_agent_updates: '保留 WebUI 更新檢查,但隱藏 Agent 更新通知,並略過 Agent 更新 fetch。', + settings_desc_whats_new_summary: '將 [新版內容] 動作改為先產生簡短、易讀的摘要,而不是先開啟原始 diff。摘要完成後仍可使用一般 diff 比較。', + settings_desc_bot_name: '助理在整個 UI 中顯示的名稱。預設為 Hermes。', + settings_desc_password: '輸入新密碼即可設定或變更密碼。留空會保留目前設定。', + password_placeholder: '輸入新密碼……', + password_env_var_locked: '目前已設定 HERMES_WEBUI_PASSWORD 環境變數且優先生效。請取消設定並重新啟動伺服器,才能在此管理密碼。', + password_env_var_locked_placeholder: '已鎖定:已設定 HERMES_WEBUI_PASSWORD 環境變數', + disable_auth: '停用驗證', + sign_out: '登出', + settings_label_shutdown: '停止 Hermes WebUI 伺服器', + settings_desc_shutdown: '正常停止本機 WebUI 伺服器。適合透過 ./ctl.sh start 啟動,且想要不切換到終端機就停止伺服器的情境。要再次進入 WebUI,需要重新啟動伺服器(./ctl.sh start 或原生應用程式)。', + settings_btn_shutdown: '停止伺服器', + settings_shutdown_confirm_title: '停止 Hermes WebUI', + settings_shutdown_confirm_message: '停止 Hermes WebUI 伺服器?', + settings_shutdown_confirm_btn: '停止', + settings_shutdown_stopped_message: '伺服器已停止。可以關閉這個分頁。', + // Providers panel + providers_tab_title: '供應商', + providers_section_title: '供應商', + providers_section_meta: '管理 AI 提供者的 API 金鑰。變更會立即生效。', + providers_status_configured: 'API 金鑰已設定', + providers_status_not_configured: '無 API 金鑰', + providers_status_oauth: 'OAuth', + providers_status_api_key: 'API 金鑰', + providers_status_not_configured_label: '未設定', + providers_oauth_hint: '已透過 OAuth 驗證。無需 API 金鑰。', + providers_oauth_config_yaml_hint: '已透過 config.yaml 設定權證。要更新,請編輯 config.yaml 中的 providers 區段,或執行 hermes auth。', + providers_oauth_not_configured_hint: '尚未驗證。請在終端機執行 hermes auth 以設定此提供者。', + providers_save: '儲存', + providers_refresh_models: '重新整理模型', + providers_refreshing: '正在重新整理…', + providers_models_refreshed: '模型已重新整理', + providers_remove: '移除', + providers_saving: '儲存中…', + providers_removing: '移除中…', + providers_enter_key: '請輸入 API 金鑰', + providers_empty: '找不到可設定的提供者。', + providers_key_updated: 'API 金鑰已儲存', + providers_key_removed: 'API 金鑰已移除', providers_key_placeholder_new: 'sk-...', - providers_key_placeholder_replace: '\u8f38\u5165\u65b0\u91d1\u9470\u4ee5\u53d6\u4ee3\u2026', - providers_key_removed: 'API \u91d1\u9470\u5df2\u79fb\u9664', - providers_key_updated: 'API \u91d1\u9470\u5df2\u5132\u5b58', + providers_key_placeholder_replace: '輸入新金鑰以取代…', provider_quota_title: '目前提供者配額', provider_quota_active_provider: '目前提供者', provider_quota_last_checked_after_refresh: '重新整理後檢查', provider_quota_last_checked: '上次檢查 {0}', provider_quota_refresh_usage: '重新整理用量', - provider_quota_refreshing: '正在重新整理...', + provider_quota_refreshing: '正在重新整理……', provider_quota_refresh_title: '立即重新整理提供者用量限制', provider_quota_refresh_succeeded: '提供者用量已重新整理', provider_quota_refresh_failed: '提供者用量重新整理失敗', @@ -10107,146 +9967,356 @@ const LOCALES = { provider_quota_pool_summary_exhausted: '{0} 個已耗盡', provider_quota_pool_summary_failed: '{0} 個失敗', provider_quota_pool_summary_checked: '已檢查 {0} 個', - providers_oauth_hint: '\u5df2\u900f\u904e OAuth \u9a57\u8b49\u3002\u7121\u9700 API \u91d1\u9470\u3002', - providers_oauth_config_yaml_hint: '\u5df2\u900f\u904e config.yaml \u8a2d\u5b9a\u6b0a\u8b49\u3002\u8981\u66f4\u65b0\uff0c\u8acb\u7de8\u8f2f config.yaml \u4e2d\u7684 providers \u5340\u6bb5\uff0c\u6216\u57f7\u884c hermes auth\u3002', - providers_oauth_not_configured_hint: '\u5c1a\u672a\u9a57\u8b49\u3002\u8acb\u5728\u7d42\u7aef\u6a5f\u57f7\u884c hermes auth \u4ee5\u8a2d\u5b9a\u6b64\u63d0\u4f9b\u8005\u3002', - providers_remove: '\u79fb\u9664', - providers_removing: '\u79fb\u9664\u4e2d\u2026', - providers_save: '\u5132\u5b58', - providers_refresh_models: 'Refresh models', - providers_refreshing: 'Refreshing…', - providers_models_refreshed: 'Models refreshed', - providers_saving: '\u5132\u5b58\u4e2d\u2026', - providers_section_meta: '管理 AI 提供者的 API 金鑰。變更會立即生效。', - providers_section_title: '供應商', - providers_status_api_key: 'API 金鑰', - providers_status_configured: 'API \u91d1\u9470\u5df2\u8a2d\u5b9a', - providers_status_not_configured: '\u7121 API \u91d1\u9470', - providers_status_not_configured_label: '\u672a\u8a2d\u5b9a', - providers_status_oauth: 'OAuth', - providers_tab_title: '供應商', - status_agent_running: 'Agent 執行中', - status_profile: '個人資料', - status_hermes_home: 'Hermes 主目錄', - status_started: '開始時間', - status_tokens: 'Token', - status_updated: '已更新', - status_ephemeral: '临时快照 — 不会保存到对话历史。', - status_no_tokens: '未使用 Token', - status_unknown: '未知', - status_completed: '\u5df2\u5b8c\u6210', - status_failed: '\u5931\u6557', - status_heading: '\u6703\u8a71\u72c0\u614b', - status_load_failed: '\u8f09\u5165\u72c0\u614b\u5931\u6557\uff1a', - status_messages: '\u8a0a\u606f\u6578', - status_model: '\u6a21\u578b', - status_provider: '供应商', - status_no: '\u5426', - status_personality: '\u4eba\u8a2d', - status_session_id: '\u6703\u8a71 ID', - status_title: '\u6a19\u984c', - status_workspace: '\u5de5\u4f5c\u5340', - status_yes: '\u662f', - usage_default_model: '\u9810\u8a2d', - usage_estimated_cost: '\u9810\u4f30\u8cbb\u7528', - usage_heading: 'Token \u7528\u91cf', - usage_input_tokens: '\u8f38\u5165 Token', - usage_load_failed: '\u8f09\u5165\u7528\u91cf\u5931\u6557\uff1a', - usage_output_tokens: '\u8f38\u51fa Token', - usage_personality_none: '\u7121', - usage_settings_tip: '\u6ce8\u610f\uff1a\u8cbb\u7528\u70ba\u9810\u4f30\u503c\u3002', - usage_total: '\u7e3d Token \u6578', - usage_unknown: '\u672a\u77e5', - cmd_yolo: 'YOLO 模式切換', - yolo_no_session: '無活動工作階段', - yolo_enabled: '⚡ YOLO 模式已開啟 — 將跳過所有審批', - yolo_disabled: 'YOLO 模式已關閉', - cmd_branch:'Fork this conversation into a new session', - cmd_branch_usage:'/branch [name] — fork conversation (optionally with a name)', - branch_forked:'Forked into new session', - branch_failed:'Fork failed: ', - fork_from_here:'Fork from here', - forked_from:'Forked from', - yolo_pill_label: 'YOLO', - yolo_pill_title_active: 'YOLO 模式激活 — 點擊關閉', - approval_skip_all: '⚡ 本次工作階段全部跳過', - approval_skip_all_title: '跳過本次工作階段的所有審批提示', - // composer action tooltips - composer_send: '\u50b3\u9001\u8a0a\u606f', - composer_queue: '\u8a0a\u606f\u52a0\u5165\u4f47\u5217', - composer_interrupt: '\u4e2d\u65b7\u4e26\u50b3\u9001', - composer_steer: '\u5f15\u5c0e\u76ee\u524d\u56de\u61c9', - composer_stop: '\u505c\u6b62\u7522\u751f', - composer_disabled_clarify: '\u8acb\u56de\u8986\u4e0a\u65b9\u7684\u6f84\u6e05\u8981\u6c42', - composer_disabled_compression: '\u7b49\u5f85\u58d3\u7e2e\u5b8c\u6210', - composer_disabled_empty: '\u8acb\u8f38\u5165\u8a0a\u606f\u5f8c\u50b3\u9001', - composer_mobile_workspace: '工作區', - composer_mobile_model: '模型', - composer_mobile_reasoning: '推理', - composer_mobile_context: '上下文', - // Queued messages - queued_label: '回應後發送', - queued_count: (n) => n === 1 ? '1 已排隊' : `${n} 已排隊`, - queued_cancel: '取消排隊訊息', + cancel: '取消', + create_job: '建立工作', + save_skill: '儲存技能', + editing: '編輯中', + // Empty state + empty_title: '需要什麼協助?', + empty_subtitle: '可以提問、執行命令、瀏覽檔案,或管理排程工作。', + suggest_files: '這個工作區有哪些檔案?', + suggest_schedule: '今天有哪些行程?', + suggest_plan: '協助我規劃一個小專案。', + // onboarding + onboarding_badge: '首次使用', + onboarding_title: '歡迎使用 Hermes Web UI', + onboarding_lead: '快速設定精靈會驗證 Hermes、儲存實際的供應商設定、選擇工作區與模型,並可選擇用密碼保護應用程式。', + onboarding_back: '上一頁', + onboarding_continue: '繼續', + onboarding_skip: '跳過設定', + onboarding_skipped: '已略過設定,使用現有設定。', + onboarding_open: '開啟 Hermes', + onboarding_step_system_title: '系統檢查', + onboarding_step_system_desc: '驗證 Hermes Agent 與設定可見性。', + onboarding_step_setup_title: '供應商設定', + onboarding_step_setup_desc: '儲存最低限度的 Hermes 供應商設定。', + onboarding_step_workspace_title: '工作區與模型', + onboarding_step_workspace_desc: '選擇新工作階段與聊天的預設值。', + onboarding_step_password_title: '選用密碼', + onboarding_step_password_desc: '分享 Web UI 前先保護它。', + onboarding_step_finish_title: '完成', + onboarding_step_finish_desc: '檢查設定並進入應用程式。', + onboarding_notice_system_ready: 'Hermes Agent 看起來可由 Web UI 存取。', + onboarding_notice_system_unavailable: 'Hermes Agent 尚未完全可用。Bootstrap 可以安裝它,但供應商設定可能仍需要使用終端機。', + onboarding_check_agent: 'Hermes Agent', + onboarding_check_agent_ready: '已偵測到且可匯入', + onboarding_check_agent_missing: '缺少或僅能部分匯入', + onboarding_check_password: '密碼', + onboarding_check_password_enabled: '已啟用', + onboarding_check_password_disabled: '尚未啟用', + onboarding_check_provider: '供應商設定', + onboarding_check_provider_ready: '已可聊天', + onboarding_check_provider_partial: '已儲存但不完整', + onboarding_check_provider_pending: '需要驗證', + onboarding_config_file: '設定檔:', + onboarding_env_file: '.env 檔案:', + onboarding_unknown: '未知', + onboarding_current_provider: '目前設定:', + onboarding_missing_imports: '缺少的匯入內容:', + onboarding_notice_setup_required: '請在這裡選擇簡易供應商路徑。進階 OAuth 流程目前仍需使用 Hermes CLI 處理。', + onboarding_notice_setup_already_ready: '已偵測到可用的 Hermes 供應商設定。可以保留或在這裡替換。', + onboarding_oauth_provider_ready_title: '供應商已完成驗證', + onboarding_oauth_provider_ready_body: '這個執行個體已設定為使用 Hermes CLI 設定的 OAuth 供應商({provider})。這裡不需要 API 金鑰,請點選 [繼續] 完成設定。', + onboarding_oauth_provider_not_ready_title: 'OAuth 供應商尚未完成驗證', + onboarding_oauth_provider_not_ready_body: '這個執行個體已設定為使用 {provider},此供應商使用 OAuth 而不是 API 金鑰。請在終端機執行 hermes auth 或 hermes model 完成驗證,然後重新載入 Web UI。', + onboarding_oauth_switch_hint: '或在下方選擇其他供應商,切換為 API 金鑰設定:', + oauth_login_codex: '使用 Codex(ChatGPT)登入', + oauth_codex_step1: '步驟 1:前往此 URL 並輸入驗證碼', + oauth_codex_step2: '步驟 2:在頁面上輸入此驗證碼', + oauth_codex_polling: '正在等待授權…', + oauth_codex_success: 'Codex OAuth 登入成功!', + oauth_codex_error: 'OAuth 登入失敗', + oauth_codex_expired: '驗證碼已過期,請再試一次', + onboarding_notice_workspace: '這些值會重複使用一般應用程式相同的設定 API。', + onboarding_workspace_label: '工作區', + onboarding_workspace_or_path: '或輸入工作區路徑', + onboarding_workspace_placeholder: '/home/you/workspace', + onboarding_provider_label: '設定模式', + onboarding_quick_setup_badge: '快速設定', + provider_category_easy_start: '快速開始', + provider_category_self_hosted: '開源/自行託管', + provider_category_specialized: '專業服務', + onboarding_api_key_label: 'API 金鑰', + onboarding_api_key_placeholder: '留空可保留現有已儲存金鑰', + onboarding_api_key_label_optional: 'API 金鑰(選用)', + onboarding_api_key_placeholder_optional: '無需金鑰的伺服器可留空', + onboarding_api_key_help_keyless: '多數 LM Studio / Ollama / vLLM 安裝不需要金鑰;如果伺服器不需要驗證,請留空。請使用 [測試連線] 按鈕確認。', + onboarding_api_key_help_prefix: '系統會使用以下名稱,將它以祕密值形式儲存在 Hermes .env 檔案中', + onboarding_base_url_label: 'Base URL', + onboarding_base_url_placeholder: 'https://your-endpoint.example/v1', + onboarding_base_url_help: '可用於 OpenAI 相容路由器、自行託管伺服器、LiteLLM、Ollama、LM Studio、vLLM 或類似端點。', + onboarding_model_label: '預設模型', + onboarding_workspace_help: '選擇設定完成後 Hermes 應在新聊天中使用的模型。', + onboarding_custom_model_placeholder: 'your-model-name', + onboarding_custom_model_help: '自訂端點請輸入伺服器預期的確切模型 ID。', + onboarding_notice_password_enabled: '已設定密碼。只有要替換時才需要輸入新密碼。', + onboarding_notice_password_recommended: '建議設定密碼,尤其是要將 UI 暴露到 localhost 以外時。', + onboarding_password_label: '密碼(選用)', + onboarding_password_placeholder: '留空可略過', + onboarding_password_help: '密碼會透過既有設定 API 儲存,並在伺服器端雜湊。', + onboarding_notice_finish: '之後可以重新開啟 [設定] 變更這些值。', + onboarding_not_set: '未設定', + onboarding_password_will_enable: '將會啟用', + onboarding_password_will_replace: '將取代', + onboarding_password_keep_existing: '保留目前密碼', + onboarding_password_remains_disabled: '將保持停用', + onboarding_password_skipped: '暫時略過', + onboarding_finish_help: '完成後會在設定中儲存 onboarding_completed,並進入一般應用程式。', + onboarding_error_choose_workspace: '請先選擇工作區再繼續。', + onboarding_error_choose_model: '請先選擇模型再繼續。', + onboarding_error_provider_required: '請先選擇設定模式再繼續。', + onboarding_error_base_url_required: '自訂端點必須提供 Base URL。', + onboarding_probe_test_button: '測試連線', + onboarding_probe_probing: '正在測試連線…', + onboarding_probe_ok: '已連線。共有 {n} 個模型可用。', + onboarding_probe_error_generic: '無法連上設定的 Base URL。', + onboarding_probe_error_invalid_url: 'Base URL 必須以 http:// 或 https:// 開頭。', + onboarding_probe_error_dns: '無法解析主機。請檢查 URL,或改用主機的 IP 位址。', + onboarding_probe_error_connect_refused: '連線遭拒;伺服器可能沒有在該位址執行。若在 Docker 內使用,請嘗試以主機 IP 取代 localhost。', + onboarding_probe_error_timeout: '端點未及時回應。請確認伺服器正在執行,且 URL 正確。', + onboarding_probe_error_http_4xx: '端點回傳請求端錯誤。請檢查驗證資訊與 URL 路徑(通常以 /v1 結尾)。', + onboarding_probe_error_http_5xx: '端點回傳伺服器錯誤。請檢查 LM Studio / Ollama 伺服器記錄。', + onboarding_probe_error_parse: '端點未回傳預期格式的模型清單。請確認 URL 指向 OpenAI 相容 API 根路徑。', + onboarding_probe_error_unreachable: '無法連上設定的 Base URL。', + onboarding_error_probe_failed: '無法驗證設定的 Base URL。', + onboarding_error_workspace_required: '工作區為必填。', + onboarding_error_model_required: '模型為必填。', + onboarding_complete: '初始設定已完成', - // Skills + // panel/runtime i18n + error_prefix: '錯誤:', + default: '預設', + search: '搜尋', + not_available: '無', + never: '從不', + add: '新增', + add_failed: '新增失敗:', + remove_failed: '移除失敗:', + switch_failed: '切換失敗:', + name_required: '需要名稱', + content_required: '需要內容', + view: '檢視', + dismiss: '關閉', + disable: '停用', + cron_no_jobs: '找不到排程任務。', + cron_status_off: '未啟用', + cron_status_paused: '已暫停', + cron_status_error: '錯誤', + cron_status_active: '已啟用', + cron_status_running: '執行中…', + cron_status_needs_attention: '需要處理', + cron_attention_desc: '這個重複排程任務沒有下次執行時間。排程器可能無法計算下一次執行。', + cron_attention_croniter_hint: 'Gateway 執行環境可能缺少 croniter 套件。請用支援 cron 的環境重啟 Gateway,然後恢復這個任務。', + cron_attention_resume: '恢復並重新計算', + cron_jobs_project: '定時任務', + cron_attention_run_once: '立即執行一次', + cron_attention_copy_diagnostics: '複製診斷資訊', + cron_diagnostics_copied: '排程任務診斷資訊已複製', + cron_next: '下次', + cron_last: '上次', + cron_run_now: '立即執行', + cron_pause: '暫停', + cron_resume: '恢復', + cron_job_name_placeholder: '任務名稱', + cron_schedule_placeholder: '排程', + cron_prompt_placeholder: '提示詞', + cron_last_output: '最後輸出', + cron_expand_prompt: '展開提示詞', + cron_collapse_prompt: '收起提示詞', + cron_expand_output: '展開輸出', + cron_collapse_output: '收起輸出', + cron_view_full_output: '檢視完整輸出', + cron_all_runs: '所有執行', + cron_hide_runs: '隱藏執行記錄', + cron_no_runs_yet: '(尚無執行記錄)', + cron_schedule_required_example: '需要排程(例如「0 9 * * *」或「every 1h」)', + cron_schedule_required: '需要排程', + cron_prompt_required: '需要提示詞', + cron_job_created: '排程任務已建立', + cron_duplicate: '複製', + cron_duplicated: '任務已複製(已暫停)', + cron_job_triggered: '排程任務已觸發', + cron_job_paused: '排程任務已暫停', + cron_job_resumed: '排程任務已恢復', + cron_job_updated: '排程任務已更新', + cron_delete_confirm_title: '刪除排程任務', + cron_delete_confirm_message: '此操作無法復原。', + cron_job_deleted: '排程任務已刪除', + cron_completion_status: (name, status) => `排程「${name}」${status}`, + status_failed: '失敗', + status_completed: '已完成', + todos_no_active: '此對話中沒有使用中的任務清單。', + clear_conversation_title: '清除對話', + clear_conversation_message: '清除所有訊息?此操作無法復原。', + clear_failed: '清除失敗:', + skills_no_match: '找不到符合的技能。', + skill_enabled: '技能已啟用', + skill_disabled: '技能已停用', + skill_toggle_failed: '切換技能狀態失敗:', + linked_files: '關聯檔案', + skill_load_failed: '載入技能失敗:', + skill_file_load_failed: '載入檔案失敗:', + skill_name_required: '需要技能名稱', + skill_updated: '技能已更新', + skill_created: '技能已建立', skill_deleted: '技能已刪除', - skill_delete_confirm: '確定要刪除此技能嗎?', - skills_empty_title: '尚無技能', - skills_empty_sub: '安裝技能以擴展代理的能力', + skill_delete_confirm: '要刪除技能「{0}」嗎?', + skills_empty_title: '選擇技能', + skills_empty_sub: '從側邊欄選擇技能以檢視內容,或建立新技能。', skills_edit: '編輯', skills_delete: '刪除', - skills_back_to: '返回技能列表', + skills_back_to: '回到 {0}', + tasks_empty_title: '選擇排程任務', + tasks_empty_sub: '從側邊欄選擇任務以檢視詳細資料與執行記錄,或建立新任務。', + workspaces_empty_title: '選擇工作區', + workspaces_empty_sub: '從側邊欄選擇工作區以檢視其檔案與設定,或新增工作區。', + profiles_empty_title: '選擇設定檔', + profiles_empty_sub: '從側邊欄選擇 Agent 設定檔以檢視並編輯設定,或建立新設定檔。', + memory_notes_label: '記憶(備註)', + memory_saved: '記憶已儲存', + my_notes: '我的備註', + user_profile: '使用者設定檔', + external_notes_sources: '第三方筆記', + external_notes_empty: '尚未看到任何筆記或知識 MCP 來源。設定 Joplin、Obsidian、Notion、llm-wiki 或其他筆記伺服器後,會顯示在這裡。', + external_notes_auto_recall_hint: '自動對話召回維持不變;這個抽屜只顯示已設定的來源,以及可用的讀取/搜尋工具。', + external_notes_no_tools: '此來源目前沒有可見的讀取/搜尋工具。', + external_notes_tool_count: (count) => `${count} 個筆記工具可用`, + external_notes_configured_hint: '此已設定來源應提供工具名稱;當 WebUI 執行階段提供即時 schema 時會顯示在這裡。', + external_notes_recent_ai: 'AI 最近使用', + external_notes_auto: '自動', + external_notes_recent_ai_reason: '自動召回', + external_notes_search_placeholder: '搜尋筆記…', + external_notes_search_empty: '搜尋已設定的筆記來源後,可在這裡預覽筆記。', + source_active: '使用中', + source_configured: '已設定', + no_notes_yet: '尚無備註。', + no_profile_yet: '尚無設定檔。', + agent_soul: 'Agent 靈魂', + no_soul_yet: '尚無靈魂定義。', + workspace_choose_path: '選擇工作區路徑', + workspace_choose_path_meta: '新增驗證過的路徑並切換此對話', + workspace_manage: '管理工作區', + workspace_manage_meta: '開啟 Spaces 面板', + workspace_use_title: '在目前對話中使用', + workspace_use: '使用', + workspace_add_path_placeholder: '新增工作區路徑(例如 /home/user/my-project)', + workspace_paths_validated_hint: '路徑會先驗證是否存在再儲存。', - // Tasks - tasks_empty_title: '無任務', - tasks_empty_sub: '管理排程與背景任務', - - // Workspaces - workspaces_empty_title: '尚無工作區', - workspaces_empty_sub: '設定工作區以組織您的專案', - - // Profiles - profiles_empty_title: '尚無設定檔', - profiles_empty_sub: '建立設定檔以快速切換環境', - - // Skill editor + workspace_drag_hint: '拖曳以重新排列', + workspace_reorder_failed: '重新排列失敗', + workspace_added: '工作區已新增', + workspace_renamed: '工作區已重新命名', + workspace_remove_confirm_title: '移除工作區', + workspace_remove_confirm_message: (name) => `移除工作區「${name}」?`, + workspace_removed: '工作區已移除', + workspace_switch_prompt_title: '切換工作區', + workspace_switch_prompt_message: '輸入工作區的絕對路徑以新增並切換此對話。', + workspace_switch_prompt_confirm: '切換', + workspace_switch_prompt_placeholder: '/Users/you/project', + workspace_not_added: '工作區未新增', + workspace_already_saved: '工作區已儲存 — 從清單中選取', + workspace_busy_switch: 'Agent 執行中無法切換工作區', + discard_file_edits_title: '放棄檔案編輯?', + discard_file_edits_message: '切換工作區將放棄未儲存的預覽變更。', + workspace_switched_to: (name) => `已切換到 ${name}`, + profiles_no_profiles: '找不到設定檔。', + profile_api_keys_configured: 'API 金鑰已設定', + profile_gateway_running: 'Gateway 執行中', + profile_gateway_stopped: 'Gateway 已停止', + profile_active: '啟用中', + profile_no_configuration: '沒有設定', + profile_skill_count: (n) => `${n} 個技能`, + profile_use: '使用', + profile_switch_title: '切換到此設定檔', + profile_delete_title: '刪除此設定檔', + profile_default_label: '(預設)', + profile_name_placeholder: '設定檔名稱(小寫字母、數字、連字號)', + profile_clone_label: '從啟用中的設定檔複製設定', + profile_model_label: '模型 / 供應商', + profile_model_hint: '為這個新設定檔選擇已設定的供應商和模型。', + profile_model_use_default: '使用啟用中設定檔的預設值', + profile_base_url_placeholder: '基本 URL(選填,例如 http://localhost:11434)', + profile_api_key_placeholder: 'API 金鑰(選填)', + manage_profiles: '管理設定檔', + profiles_load_failed: '載入設定檔失敗', + profile_switched_new_conversation: (name) => `已切換至設定檔:${name},並開始新對話`, + profile_switched: (name) => `已切換至設定檔:${name}`, + profile_name_rule: '僅限小寫字母、數字、連字號和底線', + profile_base_url_rule: '基本 URL 必須以 http:// 或 https:// 開頭', + profile_created: (name) => `設定檔 ${name} 已建立`, + profile_delete_confirm_title: (name) => `刪除設定檔「${name}」?`, + profile_delete_confirm_message: '此設定檔的所有對話、設定、技能和記憶將被永久刪除。此操作無法復原。', + profile_deleted: (name) => `設定檔 ${name} 已刪除`, + active_conversation_none: '未選取使用中的對話。', + active_conversation_meta: (title, count) => `${title} · ${count} 則訊息`, + settings_unsaved_changes: '有未儲存的變更。', + sign_out_failed: '登出失敗:', + disable_auth_confirm_title: '停用密碼保護', + disable_auth_confirm_message: '任何人都可以存取此執行個體。', + auth_disabled: '驗證已停用 — 密碼保護已關閉', + disable_auth_failed: '停用驗證失敗:', + bg_error_single: (title) => `「${title}」發生錯誤`, + bg_error_multi: (count) => `${count} 個對話發生錯誤`, + // skill form skill_name: '名稱', skill_category: '類別', - skill_category_placeholder: '例如: devops', - skill_content: '內容', - skill_content_placeholder: '輸入技能內容...', - skill_rename_not_supported: '此技能不支援重新命名', + skill_category_placeholder: '選填,例如 devops', + skill_content: 'SKILL.md 內容', + skill_content_placeholder: 'YAML frontmatter + Markdown 內文', + skill_rename_not_supported: '不支援重新命名技能。若要重新命名,請建立新技能並刪除舊技能。', skill_metadata: '中繼資料', - - // Cron labels + // cron form cron_name_label: '任務名稱', + cron_name_placeholder: '選填', cron_schedule_label: '排程', - cron_schedule_hint: "循環任務請用 'every 1h' 或 Cron 表達式。像 '30m' 這樣的裸時長只會執行一次。", - cron_schedule_once_warning: "像 '30m' 這樣的時長寫法只會執行一次,並在執行後移除。要保留循環任務,請使用 'every 30m'。", + cron_schedule_hint: '週期性任務請用「every 1h」或 Cron 表示式。像「30m」這樣的裸時長只會執行一次。', + cron_schedule_once_warning: '像「30m」這樣的時長寫法只會執行一次,並在執行後移除。要保留週期性任務,請使用「every 30m」。', cron_prompt_label: '提示', - cron_deliver_label: '發送至', - cron_deliver_local: '僅本地儲存', + cron_deliver_label: '傳送至', + cron_deliver_local: '本機(僅儲存輸出)', cron_deliver_custom: '自訂推送目標', cron_profile_label: '設定檔', cron_profile_server_default: '伺服器預設', cron_profile_server_default_hint: '執行時使用 WebUI 伺服器預設設定檔。沒有設定檔的既有工作會保留此舊行為。', + cron_toast_notifications_label: '完成 toast 通知', + cron_toast_notifications_hint: '此排程工作完成時顯示 toast 通知。即使關閉此選項,Tasks 徽章與新執行標記仍會更新。', + cron_toast_notifications_enabled: '已啟用', + cron_toast_notifications_disabled: '已停用', cron_skills_label: '技能', - cron_skills_placeholder: '選用技能(逗號分隔)', - cron_skills_edit_hint: '定義要載入的技能', - - // Workspace labels + cron_skills_placeholder: '新增技能(選填)…', + cron_skills_edit_hint: '技能清單建立後無法編輯。', + // workspace form workspace_name_label: '名稱', - workspace_name_placeholder: '例如: main-project', + workspace_name_placeholder: '選填的顯示名稱', workspace_path_label: '路徑', workspace_path_required: '工作區路徑為必填', - workspace_path_readonly: '路徑由環境設定檔決定,無法變更', + workspace_path_readonly: '路徑無法變更,只能重新命名。', workspace_new_title: '新增工作區', - - // Profile labels + // profile form profile_name_label: '名稱', profile_base_url_label: 'Base URL', profile_api_key_label: 'API 金鑰', + cmd_yolo: '切換 YOLO 模式(略過核准)', + yolo_no_session: '無活動工作階段', + yolo_enabled: '⚡ YOLO 模式已開啟,將略過所有核准', + yolo_disabled: 'YOLO 模式已關閉', + yolo_pill_label: 'YOLO', + yolo_pill_title_active: 'YOLO 模式已啟用,點選即可關閉', + approval_skip_all: '⚡ 本次工作階段全部跳過', + approval_skip_all_title: '略過本次工作階段的所有核准提示', + // composer action tooltips + composer_send: '傳送訊息', + composer_queue: '訊息加入佇列', + composer_interrupt: '中斷並傳送', + composer_steer: '引導目前回應', + composer_stop: '停止產生', + composer_disabled_clarify: '請回覆上方的澄清要求', + composer_disabled_compression: '等待壓縮完成', + composer_disabled_empty: '請輸入訊息後傳送', + composer_mobile_workspace: '工作區', + composer_mobile_model: '模型', + composer_mobile_reasoning: '推理', + composer_mobile_context: '脈絡', media_audio_label: '音訊', media_svg_label: '圖表', media_video_label: '影片', @@ -10265,101 +10335,23 @@ const LOCALES = { excalidraw_empty: '空圖表', excalidraw_render_error: '渲染圖表失敗', excalidraw_simplified: '簡化 SVG 預覽 — 與 Excalidraw 畫布不完全相同', - pdf_loading: '正在載入 PDF {0}…', - pdf_too_large: 'PDF 檔案過大,無法內嵌預覽', - pdf_no_pages: '無法渲染 PDF 預覽', - pdf_error: 'PDF 載入失敗', - pdf_download: '下載 PDF', - html_loading: '正在載入 HTML 預覽…', - html_too_large: 'HTML 檔案過大,無法內嵌預覽', - html_error: 'HTML 預覽載入失敗', - html_open_full: '開啟完整頁面', - html_sandbox_label: 'HTML 預覽', - // TTS (#499) - tts_listen: '收聽', - tts_not_supported: '語音合成無法使用', - settings_label_tts: '回覆語音合成', - settings_desc_tts: '在助手訊息上顯示喇叭按鈕', - settings_label_tts_auto_read: '自動朗讀回覆', - settings_desc_tts_auto_read: '自動朗讀助手回覆', - // Composer voice-mode pref (#1488) - settings_label_voice_mode: 'Hands-free voice mode button', // TODO: translate - settings_desc_voice_mode: 'Show the voice-mode button (audio waveform) next to the dictation mic. Lets you speak naturally — Hermes auto-sends after a pause and reads replies aloud. Requires a browser that supports both speech recognition and TTS.', - settings_label_raw_audio: 'Send raw audio instead of transcribing', - settings_desc_raw_audio: 'Record and send the original audio file to the agent instead of converting it to text first. The agent can then transcribe it or process the raw audio (emotion, background noise, custom STT). Like Telegram\'s voice message behavior.', - voice_send_raw: 'Send raw audio', - voice_raw_attached: 'Audio attached. Press Send or type more.', // TODO: translate - settings_label_tts_voice: '語音', - settings_desc_tts_voice: '選擇語音合成聲音', - settings_label_tts_rate: '語速', - settings_label_tts_pitch: '音調', - settings_label_tts_engine: 'TTS 引擎', - settings_desc_tts_engine: '选择语音引擎。Edge TTS 通过服务器使用微软神经语音。', + // ── Checkpoints / Rollback ── + checkpoint_title: '檢查點', + checkpoint_empty: '此工作區沒有檢查點。', + checkpoint_loading: '正在載入檢查點…', + checkpoint_error: '載入檢查點失敗', + checkpoint_date: '日期', + checkpoint_message: '訊息', + checkpoint_files: '檔案', + checkpoint_view_diff: '檢視差異', + checkpoint_restore: '還原', + checkpoint_restore_confirm_title: '要還原檢查點嗎?', + checkpoint_restore_confirm_message: (ckpt) => `要將工作區還原到檢查點「${ckpt}」嗎?這會用已儲存版本覆寫檔案。此檢查點之後新增的檔案不會被刪除。`, + checkpoint_restored: '已還原檢查點', + checkpoint_diff_title: '檢查點中的變更', + checkpoint_diff_no_changes: '這個檢查點與目前工作區沒有差異。', + checkpoint_diff_files_changed: (n) => `已變更 ${n} 個檔案`, - checkpoint_date: 'Date', // TODO: translate - checkpoint_diff_files_changed: (n) => `${n} file${n === 1 ? '' : 's'} changed`, // TODO: translate - checkpoint_diff_no_changes: 'No differences found between this checkpoint and the current workspace.', // TODO: translate - checkpoint_diff_title: 'Changes in checkpoint', // TODO: translate - checkpoint_empty: 'No checkpoints found for this workspace.', // TODO: translate - checkpoint_error: 'Failed to load checkpoints', // TODO: translate - checkpoint_files: 'Files', // TODO: translate - checkpoint_loading: 'Loading checkpoints…', // TODO: translate - checkpoint_message: 'Message', // TODO: translate - checkpoint_restore: 'Restore', // TODO: translate - checkpoint_restore_confirm_message: (ckpt) => `Restore workspace to checkpoint "${ckpt}"? This will overwrite files with the saved versions. Files added after this checkpoint will not be deleted.`, // TODO: translate - checkpoint_restore_confirm_title: 'Restore checkpoint?', // TODO: translate - checkpoint_restored: 'Checkpoint restored', // TODO: translate - checkpoint_title: 'Checkpoints', // TODO: translate - checkpoint_view_diff: 'View diff', // TODO: translate - insights_activity_by_day: 'Activity by Day', // TODO: translate - insights_activity_by_hour: 'Activity by Hour', // TODO: translate - insights_cost: 'Estimated Cost', // TODO: translate - insights_daily_tokens: 'Daily Tokens', - insights_model_name: 'Model', - insights_model_sessions: 'Sessions', - insights_model_tokens: 'Tokens', - insights_model_cost: 'Cost', - insights_model_share: 'Share', - insights_no_usage_data: 'No usage data yet', - insights_footer: 'Showing data from the last {days} days', // TODO: translate - insights_skill_usage_title: '技能使用統計', - insights_skill_usage_sub: '工具調用頻次', - insights_skill_usage_total: '總調用次數', - insights_skill_usage_skills_used: '已使用技能', - insights_skill_usage_no_data: '暫無技能使用數據', - insights_skill_usage_no_data_hint: '在會話中使用技能後,數據將在此顯示。', - insights_skill_usage_footer: '數據來源於 ~/.hermes/skills/', - insights_skill_usage_col_skill: 'Skill', // TODO: translate - insights_skill_usage_col_uses: 'Uses', // TODO: translate - insights_skill_usage_col_views: 'Views', // TODO: translate - insights_skill_usage_col_share: 'Usage %', // TODO: translate - insights_skill_usage_col_patches: 'Patches', // TODO: translate - insights_input_tokens: 'Input', // TODO: translate - insights_messages: 'Messages', // TODO: translate - insights_models: 'Models', // TODO: translate - insights_no_cost: 'N/A', // TODO: translate - insights_output_tokens: 'Output', // TODO: translate - insights_peak_hour: 'Peak: {hour}', // TODO: translate - insights_sessions: 'Sessions', // TODO: translate - insights_title: 'Usage Analytics', // TODO: translate - insights_token_breakdown: 'Token Breakdown', // TODO: translate - insights_tokens: 'Tokens', // TODO: translate - insights_total: 'Total', // TODO: translate - settings_desc_api_redact: 'Self-hosted users can disable for transparency (not recommended for shared instances).', // TODO: translate - settings_label_api_redact: 'Redact sensitive data in API responses', // TODO: translate - voice_error: 'Voice not supported in this browser', // TODO: translate - voice_listening: 'Listening…', // TODO: translate - voice_mode_active: 'Voice mode on', // TODO: translate - voice_mode_off: 'Voice mode off', // TODO: translate - voice_speaking: 'Speaking…', // TODO: translate - voice_thinking: 'Thinking…', // TODO: translate - // Composer voice buttons (#1488) - voice_dictate: 'Dictate', // TODO: translate - voice_dictate_active: 'Stop dictation', - voice_recording_active: '停止錄音', // TODO: translate - voice_mode_toggle: 'Voice mode', // TODO: translate - voice_mode_toggle_active: 'Exit voice mode', // TODO: translate - subagent_children: 'Subagent sessions', // TODO: translate }, pt: { @@ -13034,6 +13026,7 @@ const LOCALES = { theme_usage: 'Utilisation : /theme ', theme_set: 'Thème:', no_active_session: 'Aucune session active', + provider_mismatch_warning: (m,p)=>`«\u00a0${m}\u00a0» pourrait ne pas fonctionner avec votre fournisseur configuré (${p}). Envoyez quand même, ou exécutez \`hermes model\` dans votre terminal pour changer.`, cmd_queue: 'Mettre un message en file d\'attente pour le prochain tour', cmd_goal: 'Définir ou inspecter un objectif persistant', goal_evaluating_progress: 'Évaluer la progression des objectifs…', diff --git a/tests/test_issue603_provider_categories.py b/tests/test_issue603_provider_categories.py index 2a3ae65b..1a05c174 100644 --- a/tests/test_issue603_provider_categories.py +++ b/tests/test_issue603_provider_categories.py @@ -316,7 +316,7 @@ class TestI18nCategoryKeys: def test_zh_hant_has_all_category_keys(self): with open("static/i18n.js", encoding="utf-8") as f: content = f.read() - assert "\\u5feb\\u901f\\u958b\\u59cb" in content # zh-Hant easy_start + assert "快速開始" in content # zh-Hant easy_start class TestApplyBaseURLSpecialized: diff --git a/tests/test_zh_hant_locale.py b/tests/test_zh_hant_locale.py new file mode 100644 index 00000000..2f54f8c1 --- /dev/null +++ b/tests/test_zh_hant_locale.py @@ -0,0 +1,215 @@ +from pathlib import Path +import re + + +REPO = Path(__file__).resolve().parent.parent + + +def read(path: Path) -> str: + return path.read_text(encoding="utf-8") + + +def locale_block(src: str, marker: str) -> str: + start = src.index(marker) + open_brace = src.index("{", start) + pos = open_brace + 1 + depth = 1 + in_single = False + in_double = False + in_template = False + escaped = False + line_comment = False + block_comment = False + + while pos < len(src): + char = src[pos] + next_char = src[pos + 1] if pos + 1 < len(src) else "" + + if line_comment: + if char == "\n": + line_comment = False + elif block_comment: + if char == "*" and next_char == "/": + block_comment = False + pos += 1 + elif escaped: + escaped = False + elif in_single: + if char == "\\": + escaped = True + elif char == "'": + in_single = False + elif in_double: + if char == "\\": + escaped = True + elif char == '"': + in_double = False + elif in_template: + if char == "\\": + escaped = True + elif char == "`": + in_template = False + elif char == "/" and next_char == "/": + line_comment = True + pos += 1 + elif char == "/" and next_char == "*": + block_comment = True + pos += 1 + elif char == "'": + in_single = True + elif char == '"': + in_double = True + elif char == "`": + in_template = True + elif char == "{": + depth += 1 + elif char == "}": + depth -= 1 + if depth == 0: + return src[open_brace + 1 : pos] + + pos += 1 + + raise AssertionError(f"Locale block not closed: {marker}") + + +def entries(block: str) -> list[tuple[str, str]]: + return re.findall( + r"^\s+([a-zA-Z0-9_]+):\s*(.*?)(?:,\s*)?$", + block, + re.MULTILINE, + ) + + +def keys(block: str) -> list[str]: + return [key for key, _ in entries(block)] + + +def value_map(block: str) -> dict[str, str]: + return dict(entries(block)) + + +def arrow_arg_names(value: str) -> list[str] | None: + match = re.match(r"\((?P[^)]*)\)\s*=>", value) + if not match: + match = re.match(r"(?P[a-zA-Z_$][\w$]*)\s*=>", value) + if not match: + return None + return [match.group("arg")] + + args = match.group("args").strip() + if not args: + return [] + return [arg.strip() for arg in args.split(",") if arg.strip()] + + +def arrow_arg_count(value: str) -> int | None: + args = arrow_arg_names(value) + if args is None: + return None + return len(args) + + +def template_arg_refs(value: str, arg_names: list[str] | None) -> list[str]: + arg_index = {arg: index for index, arg in enumerate(arg_names or [])} + refs = [] + for var_name in re.findall(r"\$\{([a-zA-Z_]\w*)\}", value): + if var_name in arg_index: + refs.append(f"arg:{arg_index[var_name]}") + else: + refs.append(f"name:{var_name}") + return sorted(set(refs)) + + + +def test_english_locale_remains_english_source_text(): + src = read(REPO / "static" / "i18n.js") + en_block = locale_block(src, "\n en: {") + cjk_lines = [ + line.strip() + for line in en_block.splitlines() + if re.search(r"[\u4e00-\u9fff]", line) + ] + assert not cjk_lines, cjk_lines + +def test_zh_hant_locale_block_exists(): + src = read(REPO / "static" / "i18n.js") + assert "\n 'zh-Hant': {" in src + assert "_label: '繁體中文'" in src + assert "_speech: 'zh-TW'" in src + + +def test_zh_hant_locale_covers_english_keys_without_duplicates(): + src = read(REPO / "static" / "i18n.js") + en_block = locale_block(src, "\n en: {") + zh_block = locale_block(src, "\n 'zh-Hant': {") + en_keys = set(keys(en_block)) + zh_keys = keys(zh_block) + + duplicates = sorted({key for key in zh_keys if zh_keys.count(key) > 1}) + assert not duplicates, f"zh-Hant locale duplicate keys: {duplicates}" + + missing = sorted(en_keys - set(zh_keys)) + extra = sorted(set(zh_keys) - en_keys) + assert not missing, f"zh-Hant locale missing keys: {missing}" + assert not extra, f"zh-Hant locale extra keys: {extra}" + + + +def test_zh_hant_locale_preserves_function_and_placeholder_shapes(): + src = read(REPO / "static" / "i18n.js") + en_values = value_map(locale_block(src, "\n en: {")) + zh_values = value_map(locale_block(src, "\n 'zh-Hant': {")) + + function_mismatches = [] + placeholder_mismatches = [] + template_var_mismatches = [] + for key, en_value in en_values.items(): + assert key in zh_values, f"Missing zh-Hant translation: {key}" + zh_value = zh_values[key] + en_arg_names = arrow_arg_names(en_value) + zh_arg_names = arrow_arg_names(zh_value) + en_args = None if en_arg_names is None else len(en_arg_names) + zh_args = None if zh_arg_names is None else len(zh_arg_names) + if en_args != zh_args: + function_mismatches.append((key, en_args, zh_args)) + + placeholder_pattern = r"(?