// 增强设置页文案表(语言相关):中文界面用 ZH,英文界面用 EN。 // 每个键与 src/lib/client/logic/settings-section.ts 里的 ZhSettingsSection 对应。 const SETTINGS_ZH = { nav: '增强设置', sectionIntro: '配置界面增强、布局与提示词注入。', zhComplete: '中文补全', zhCompleteDesc: '修正中文界面残留的英文,统一术语与数量/时长格式', zhAgentPrompt: '代理角色提示中文化', zhAgentPromptDesc: '四个默认代理的系统提示词换成中文版本(仅新会话生效,不重新注入已有会话)', zhToolDesc: '工具说明中文化', zhToolDescDesc: '注入模型请求的工具说明翻译为中文(工具名与参数不变;仅新会话生效)', zhContextInject: '上下文注入中文化', zhContextInjectDesc: 'DSH 注入会话的官方上下文(工作区指令、skill 目录、运行时上下文、模式切换/动态插件/定时提醒通知、压缩检查点)在进入会话历史前换成中文(GUI 与模型请求一致显示;仅新会话生效;翻译快照头部行会使 DSH 每步注入一条替换快照,会话日志略增)', thinkingAuto: '自动展开最新思考', thinkingAutoDesc: '思考输出流式出现时自动展开最新一条,新的思考出现时收起上一条', thinkMaxLines: '默认展开行数', thinkMaxLinesDesc: '思考展开后默认只显示 N 行,超出部分折叠(减少超长思考引起的卡顿);0 表示不限制', thinkMaxLinesUnit: '行', thinkMaxLinesFrom: '折叠显示方向', thinkMaxLinesFromDesc: '选择默认显示思考的开头还是结尾', thinkMaxLinesFromLatest: '最新 N 行', thinkMaxLinesFromEarliest: '最早 N 行', thinkExpandMore: '再展开 {n} 行(还有 {m} 行)', thinkExpandRest: '展开全部(还有 {n} 行)', thinkMode: '展开模式', thinkModeDesc: '按钮模式:折叠后点「再展开」按钮逐批展开;滚动模式:正文自带滚动条,用鼠标滚轮上下查看', thinkModeButton: '按钮模式', thinkModeScroll: '滚动模式', zhPrompt: '提示词注入', zhPromptDesc: '向大模型注入下方的提示词(后续模型请求生效)', promptTextLabel: '注入文本', promptTextPlaceholder: '在此输入要注入的提示词…', promptTargetLabel: '注入到', promptTargetSystem: '初始系统提示', promptTargetUser: '首用户提示词', promptOrderLabel: '排序位置', promptOrderDesc: '初始系统提示内的段落位置(-9999–9999,数字越小越靠前)。默认 100 = 角色提示之后;填 -1001 及更小则排到最前面。', promptOrderInvalid: '请输入 -9999–9999 的整数', draftSave: '保存', draftRevert: '还原', draftSaving: '保存中…', draftIdle: '改动先暂存,点「保存」后生效', draftUnsaved: '有 {n} 项改动未保存', draftSaveFailed: '保存失败,改动已保留', autoArchive: '自动归档旧会话', autoArchiveDesc: '新建会话界面打开时,自动把超过指定天数未活动的会话归档(仅从列表隐藏,日志保留);设为 0 可关闭此功能', autoArchiveUnit: '天', autoArchiveNotified: '有 {n} 个会话已归档', archiveView: '查看已归档', archiveViewDesc: '工作区行新增「归档」按钮:点击后该分组正常会话隐藏,归档会话行直接出现在官方列表该分组内(随列表整体滚动、按最近活动时间降序、默认 5 个、每批再展开 5 个),行尾三点菜单含重命名 / 分叉 / 取消归档 / 删除,点击归档行即恢复并打开', styleGroup: '对话样式相关', styleGroupDesc: '思考展开的界面增强', listGroup: '对话列表相关', listGroupDesc: '归档、删除与多选等列表功能', serviceMonitor: '服务监控', serviceMonitorCardDesc: '监控对话中启动的本地服务与自定义监控项', serviceMonitorDesc: '双形态:左侧会话列表与设置之间保留原面板,同时在右侧边栏新增「服务监控」tab(入口在右栏引导页);显示对话期间新启动的本地监听服务,悬停时按需解析进程,点击时在文件管理器中定位;tab 底部「基线端口」区可点击把基线端口重新纳入监控', serviceMonitorPanel: '工作区常驻监控', serviceMonitorPanelDesc: '左侧会话列表与设置之间常驻显示服务监控面板', serviceMonitorTab: '侧边栏监控卡片', serviceMonitorTabDesc: '右侧边栏新增「服务监控」tab(入口在引导页)', serviceMonitorInterval: '刷新间隔', serviceMonitorIntervalDesc: '监控面板轮询主机快照的间隔;范围 2–300 秒', serviceMonitorIntervalUnit: '秒', serviceTargetsLabel: '自定义监控项', serviceTargetsDesc: '名字和地址都是文本框,可随时修改(回车或失焦保存,地址无效标红不保存);条目常驻监控面板:在线绿点、离线灰点,悬停查询监听进程,点击定位进程目录', serviceTargetNamePlaceholder: '名字(可空)', serviceTargetAddrPlaceholder: '127.0.0.1:81', serviceTargetAdd: '添加', serviceTargetRemove: '删除', serviceTargetInvalid: '地址无效或非本机回环地址;支持 127.0.0.1:81 / localhost:3000 / [::1]:8080', zhWebSearch: '启用多引擎搜索', zhWebSearchDesc: '开启后由本插件按下方「搜索后端优先级」接管 web_search 的后端选择;关闭则保持部署里配置的后端。多引擎(免 Key 的 DuckDuckGo/Yandex/Bing/Wikipedia,外加可选的 Tavily)是优先级列表里的一项。', searchOrder: '搜索后端优先级', searchOrderDesc: '从上到下依次尝试:某后端未注册、不可用或调用失败时自动降级到下一个,全部失败才报错;用户取消时不重试。DeepSeek Search API 开始计费后可把它移到末位。', searchOrderMoveUp: '上移', searchOrderMoveDown: '下移', searchOrderBackendDeepseekApi: 'DeepSeek Search API', searchOrderBackendZhipu: '智谱 GLM 搜索', searchOrderBackendFree: '免 Key 多引擎(DDG/Bing/Yandex/Wikipedia + Tavily)', searchOrderBackendMessages: 'DeepSeek Messages 搜索', searchOrderBackendUnknown: '其它后端', searchOrderEmpty: '优先级列表为空:当前不接管后端选择。', searchOrderRestore: '恢复默认顺序', zhWebFetch: '启用免 Key 网页读取', zhWebFetchDesc: '开启后由本插件按下方「读取后端优先级」接管 web_fetch(网页读取)的后端选择;关闭则保持部署里配置的后端。免 Key 环(Exa/Parallel/Keenable 公共端点)是优先级列表里的一项:抓取会把 URL 发给对应厂商的公共云服务。', fetchOrder: '读取后端优先级', fetchOrderDesc: '从上到下依次尝试:某后端未注册、不可用或调用失败时自动降级到下一个,全部失败才报错;用户取消时不重试。免 Key 环内部按 Exa → Parallel → Keenable 依次尝试。', fetchOrderMoveUp: '上移', fetchOrderMoveDown: '下移', fetchOrderBackendDeepseekApi: 'DeepSeek Fetch API', fetchOrderBackendZhipu: '智谱 webReader', fetchOrderBackendFree: '免 Key 环(Exa/Parallel/Keenable)', fetchOrderBackendLocal: '本地抓取(官方 http)', fetchOrderBackendUnknown: '其它后端', fetchOrderEmpty: '优先级列表为空:当前不接管后端选择。', fetchOrderRestore: '恢复默认顺序', searchPerQuery: '每查询返回条数', searchPerQueryDesc: '每个查询最多保留几条来源,0 表示不接管(沿用官方 8 条 + 多查询交错合并)。设为 N 后结果按查询分组:查询一 N 条 → 查询二 N 条,跨查询重复链接去重。实际条数还受「网页搜索」设置里「每次搜索结果数」限制。', searchPerQueryUnit: '条', searchGroup: '网络搜索', searchGroupDesc: '搜索后端与 API Key', searchToggleEnabled: '智能搜索按钮', searchToggleEnabledDesc: '在输入框下方工具行显示「智能搜索」按钮(默认开)。按钮状态按会话记忆:取消后该会话不再注入联网搜索与网页读取的工具和说明段。关闭本项则按钮完全不显示,相关代码也不加载、不运行。', searchApiKeyLabel: 'Tavily API Key', searchApiKeyDesc: '可选。填入后搜索优先走 Tavily 官方 API(免费额度 1000 次/月,每次搜索消耗 1 点),用尽后自动降级到免 Key 引擎;留空则只用免 Key 多引擎。Key 保存在 DSH 凭据文件(refs 段的 TAVILY_API_KEY),不写入插件配置、日志或诊断快照;保存后立即生效,无需重启。', searchApiKeyPlaceholder: 'tvly-...', searchApiKeySave: '保存', searchApiKeyClear: '清除', searchApiKeyConfigured: '已配置', searchApiKeyNotConfigured: '未配置', searchApiKeySourceFile: '凭据文件', searchApiKeySourceEnv: '环境变量', searchApiKeyEnvNote: '当前由环境变量提供,且环境变量优先于凭据文件;要修改请改环境变量,此处的「清除」不会生效。', searchApiKeyInvalid: 'Key 不合法:不能为空、不能含空格或换行,且不超过 512 字符', searchApiKeyRouteMissing: '主机接口未就绪:凭据接口是本版本新增的,需重启一次 dsh web 后可用(key 本身没有问题)', searchApiKeySaved: '已保存', searchApiKeySaveFailed: '保存失败', searchApiKeyUnreachable: '无法连接主机', deleteSession: '会话删除按钮', deleteSessionDesc: '会话列表三点菜单显示「删除会话」项(日志移入系统回收站,不保留恢复位);关闭时多选菜单的「批量删除」同样隐藏', batchOps: '会话多选', batchOpsDesc: '悬停空闲会话行首的空图标位出现复选框,可多选后通过任意会话三点菜单「批量删除 / 批量归档」(运行中、待交互与完成未读的行不可选)', pluginSyncGroup: '插件同步', pluginSyncGroupDesc: '把另一侧配置里已安装的插件同步到当前环境(同名只取最高版本)', pluginSyncIntro: '把参考 profile 已安装的插件同步到当前 profile:在网页端运行时方向为「桌面版 → 网页端」,在桌面版运行时为「网页端 → 桌面版」。两边相同的包会自动跳过;同名包只取版本号更高的一侧——当前版本已经不低于参考时保持不动,绝不降级;已经装过的包也不会被移除。同步走 DSH 官方插件管理器,与桌面应用侧栏「插件」页是同一条通道。', pluginSyncCheck: '检查差异', pluginSyncRun: '一键同步', pluginSyncRunning: '同步中…', pluginSyncRetry: '重试', pluginSyncApproveBuilds: '允许构建脚本并重试', pluginSyncSource: '参考', pluginSyncTarget: '目标', pluginSyncNone: '没有需要同步的插件,两边已一致。', pluginSyncCurrent: '已一致', pluginSyncSkipped: '已跳过(当前版本不低于参考,不降级)', pluginSyncActionInstall: '待安装', pluginSyncActionUpgrade: '待更新', pluginSyncActionEnable: '待启用', pluginSyncResultApplied: '已生效', pluginSyncResultRestart: '需重启', pluginSyncResultFailed: '失败', pluginSyncComplete: '同步完成,全部生效。', pluginSyncPartial: '同步已结束,但有条目未完全生效(见下方状态)。', pluginSyncPendingBuilds: '该包的构建脚本需显式允许后才能完成安装', pluginSyncUnavailable: '当前不可同步', pluginSyncRouteMissing: '主机接口未就绪:插件同步接口是本版本新增的,需重启一次后可用', pluginSyncUnreachable: '无法连接主机', pluginSyncFailed: '同步失败', } const SETTINGS_EN = { nav: 'Enhancements', sectionIntro: 'Configure UI enhancements, layout and prompt injection.', zhComplete: 'Chinese completion', zhCompleteDesc: 'Fix leftover English in the Chinese UI and normalize terms/formats', zhAgentPrompt: 'Localize agent role prompts', zhAgentPromptDesc: 'Replace the 4 default agents\' system prompts with Chinese versions (new sessions only; existing sessions are never re-injected)', zhToolDesc: 'Localize tool descriptions', zhToolDescDesc: 'Translate the tool descriptions injected into model requests into Chinese (tool names and parameters stay; new sessions only)', zhContextInject: 'Localize injected context', zhContextInjectDesc: 'Replace DSH-injected official context (workspace instructions, skill catalog, runtime context, mode-switch/dynamic-plugin/scheduled-reminder notices, compaction checkpoint) with Chinese before it enters session history (GUI and model requests stay consistent; new sessions only; translating the snapshot header makes DSH inject one replacement snapshot per step, slightly growing the session log)', thinkingAuto: 'Auto-expand latest thinking', thinkingAutoDesc: 'While thinking streams in, expand the newest output and collapse the previous one (Chinese UI only)', thinkMaxLines: 'Default expanded lines', thinkMaxLinesDesc: 'Show only N lines of an expanded thinking block; the rest collapses (reduces UI lag on very long thinking); 0 disables the limit', thinkMaxLinesUnit: 'lines', thinkMaxLinesFrom: 'Collapse direction', thinkMaxLinesFromDesc: 'Show the beginning or the end of the thinking by default', thinkMaxLinesFromLatest: 'Latest N lines', thinkMaxLinesFromEarliest: 'Earliest N lines', thinkExpandMore: 'Expand {n} more lines ({m} left)', thinkExpandRest: 'Expand all ({n} more lines)', thinkMode: 'Expand mode', thinkModeDesc: 'Button mode: click "expand" to reveal more lines; scroll mode: the folded body gets its own scrollbar, use the mouse wheel to browse', thinkModeButton: 'Button mode', thinkModeScroll: 'Scroll mode', zhPrompt: 'Prompt injection', zhPromptDesc: 'Inject the prompt below into subsequent model requests', promptTextLabel: 'Injected text', promptTextPlaceholder: 'Type the prompt text to inject…', promptTargetLabel: 'Inject into', promptTargetSystem: 'Initial system prompt', promptTargetUser: 'First user prompt', promptOrderLabel: 'Order', promptOrderDesc: 'Placement inside the initial system prompt (-9999–9999, lower comes first). The default 100 sits right after the persona; -1001 or lower moves it to the very front.', promptOrderInvalid: 'Enter an integer from -9999 to 9999', draftSave: 'Save', draftRevert: 'Revert', draftSaving: 'Saving…', draftIdle: 'Changes are held until you press Save', draftUnsaved: '{n} unsaved change(s)', draftSaveFailed: 'Save failed — changes kept', autoArchive: 'Auto-archive old sessions', autoArchiveDesc: 'When the New Session view opens, archive sessions inactive for more than the set days (hide from lists only; logs stay). Set 0 to disable this feature', autoArchiveUnit: 'days', autoArchiveNotified: '{n} session(s) archived', archiveView: 'Archived session view', archiveViewDesc: 'Add an "Archive" button to each workspace row: clicking it hides the group\'s normal sessions and shows archived session rows inside the official list (scrolls with the list, sorted by most recent activity, 5 by default, 5 more per expand); the row menu has Rename / Fork / Unarchive / Delete, and clicking an archived row restores and opens it', styleGroup: 'Chat display', styleGroupDesc: 'Thinking display enhancement', listGroup: 'Session list', listGroupDesc: 'Archive, delete and multi-select features', serviceMonitor: 'Service monitor', serviceMonitorCardDesc: 'Watch locally started services and custom entries', serviceMonitorDesc: 'Dual form: keeps the original panel between the session list and Settings in the left sidebar, and adds a "Service monitor" tab in the right sidebar (entry on the guide page); shows local listening services started during the conversation; hover resolves the process on demand and click reveals its location; the tab\'s "Baseline ports" section lets you bring a baseline port back into monitoring with a click', serviceMonitorPanel: 'Workspace panel monitor', serviceMonitorPanelDesc: 'Keep the service monitor panel visible between the session list and Settings in the left sidebar', serviceMonitorTab: 'Sidebar monitor tab', serviceMonitorTabDesc: 'Add a "Service monitor" tab to the right sidebar (entry on the guide page)', serviceMonitorInterval: 'Refresh interval', serviceMonitorIntervalDesc: 'How often the sidebar panel polls the host snapshot; 2-300 seconds', serviceMonitorIntervalUnit: 's', serviceTargetsLabel: 'Custom watch entries', serviceTargetsDesc: 'Name and address are editable text boxes, change them anytime (Enter or blur saves; invalid addresses are outlined red and not saved); entries stay in the panel permanently: green dot when online, gray dot when offline, hover resolves the listening process, click reveals the process folder', serviceTargetNamePlaceholder: 'Name (optional)', serviceTargetAddrPlaceholder: '127.0.0.1:81', serviceTargetAdd: 'Add', serviceTargetRemove: 'Remove', serviceTargetInvalid: 'Invalid or non-loopback address; use 127.0.0.1:81 / localhost:3000 / [::1]:8080', zhWebSearch: 'Enable multi-engine search', zhWebSearchDesc: 'When on, this plugin takes over the web_search backend selection using the "Search backend priority" list below; when off, the backend configured by the deployment stays in place. Multi-engine (keyless DuckDuckGo/Yandex/Bing/Wikipedia plus the optional Tavily API) is one entry in that priority list.', searchOrder: 'Search backend priority', searchOrderDesc: 'Tried top to bottom: a backend that is not installed, unavailable, or fails falls through to the next one, and only a total failure reports an error; a user cancellation never retries. Move DeepSeek Search API to the bottom once it starts billing.', searchOrderMoveUp: 'Move up', searchOrderMoveDown: 'Move down', searchOrderBackendDeepseekApi: 'DeepSeek Search API', searchOrderBackendZhipu: 'Zhipu GLM search', searchOrderBackendFree: 'Keyless multi-engine (DDG/Bing/Yandex/Wikipedia + Tavily)', searchOrderBackendMessages: 'DeepSeek Messages search', searchOrderBackendUnknown: 'Other backend', searchOrderEmpty: 'The priority list is empty, so the backend selection is left alone.', searchOrderRestore: 'Restore defaults', zhWebFetch: 'Enable keyless web reader', zhWebFetchDesc: 'When on, this plugin takes over the web_fetch backend selection using the "Fetch backend priority" list below; when off, the backend configured by the deployment stays in place. The keyless ring (Exa/Parallel/Keenable public endpoints) is one entry in that priority list: fetching sends the URL to the vendor\'s public cloud service.', fetchOrder: 'Fetch backend priority', fetchOrderDesc: 'Tried top to bottom: a backend that is not installed, unavailable, or fails falls through to the next one, and only a total failure reports an error; a user cancellation never retries. Inside the keyless ring, Exa → Parallel → Keenable are tried in order.', fetchOrderMoveUp: 'Move up', fetchOrderMoveDown: 'Move down', fetchOrderBackendDeepseekApi: 'DeepSeek Fetch API', fetchOrderBackendZhipu: 'Zhipu webReader', fetchOrderBackendFree: 'Keyless ring (Exa/Parallel/Keenable)', fetchOrderBackendLocal: 'Local fetch (official http)', fetchOrderBackendUnknown: 'Other backend', fetchOrderEmpty: 'The priority list is empty, so the backend selection is left alone.', fetchOrderRestore: 'Restore defaults', searchPerQuery: 'Results per query', searchPerQueryDesc: 'How many sources to keep per query; 0 leaves the official behavior (8 sources, round-robin merge). With N, results are grouped by query — query one N sources, then query two N sources — with cross-query duplicate links dropped. The effective count is also capped by the Search API "Results per search" setting.', searchPerQueryUnit: 'sources', searchGroup: 'Web search', searchGroupDesc: 'Search backend and API key', searchToggleEnabled: 'Smart search button', searchToggleEnabledDesc: 'Show the "Smart search" button in the composer tool row (on by default). The button remembers its state per session: turning it off stops that session from receiving the web search and page fetch tools and guidance. Turning this setting off hides the button entirely and keeps its code from loading or running.', searchApiKeyLabel: 'Tavily API key', searchApiKeyDesc: 'Optional. When set, search prefers the Tavily API (1,000 free credits/month, 1 credit per search) and falls back to the keyless engines once exhausted; leave empty to use the keyless engines only. The key is stored in the DSH credentials file (TAVILY_API_KEY in the refs section) and never written into plugin config, logs, or diagnostics snapshots; it takes effect immediately, no restart needed.', searchApiKeyPlaceholder: 'tvly-...', searchApiKeySave: 'Save', searchApiKeyClear: 'Clear', searchApiKeyConfigured: 'Configured', searchApiKeyNotConfigured: 'Not configured', searchApiKeySourceFile: 'credentials file', searchApiKeySourceEnv: 'environment variable', searchApiKeyEnvNote: 'Currently provided by an environment variable, which takes precedence over the credentials file; change the environment variable instead — "Clear" has no effect here.', searchApiKeyInvalid: 'Invalid key: must not be empty, must not contain whitespace, and must be at most 512 characters', searchApiKeyRouteMissing: 'Host endpoint not ready: the credentials endpoint is new in this build and needs one dsh web restart to become available (the key itself is fine)', searchApiKeySaved: 'Saved', searchApiKeySaveFailed: 'Save failed', searchApiKeyUnreachable: 'Cannot reach the host', deleteSession: 'Session delete button', deleteSessionDesc: 'Show "Delete session" in the session row menu (log moves to system recycle bin; no restore position); when off, "Delete selected" is hidden from the batch menu too', batchOps: 'Session multi-select', batchOpsDesc: 'Hover the empty leading icon slot of an idle session row to check it; with sessions selected, any row menu offers "Delete selected / Archive selected" (running, pending-interaction and unread-completion rows are not selectable)', pluginSyncGroup: 'Plugin sync', pluginSyncGroupDesc: 'Copy plugins installed in the other profile (highest version wins)', pluginSyncIntro: 'Copy the plugins installed in the reference profile into the current profile: running in the web app the direction is desktop → web, running in the desktop app it is web → desktop. Packages that already match are skipped, and for the same package only the higher version is kept — if this profile is already at or above the reference it is left alone, never downgraded. Nothing installed here is ever removed. Sync uses the official DSH plugin manager — the same channel as the desktop app sidebar "Plugins" page.', pluginSyncCheck: 'Check differences', pluginSyncRun: 'Sync now', pluginSyncRunning: 'Syncing…', pluginSyncRetry: 'Retry', pluginSyncApproveBuilds: 'Allow build scripts and retry', pluginSyncSource: 'From', pluginSyncTarget: 'To', pluginSyncNone: 'Nothing to sync; both sides already match.', pluginSyncCurrent: 'In sync', pluginSyncSkipped: 'Skipped (this profile is already at or above the reference; never downgraded)', pluginSyncActionInstall: 'To install', pluginSyncActionUpgrade: 'To update', pluginSyncActionEnable: 'To enable', pluginSyncResultApplied: 'Applied', pluginSyncResultRestart: 'Restart needed', pluginSyncResultFailed: 'Failed', pluginSyncComplete: 'Sync finished; everything is live.', pluginSyncPartial: 'Sync finished, but some entries did not fully apply (see status below).', pluginSyncPendingBuilds: 'This package needs its build scripts explicitly allowed to finish installing', pluginSyncUnavailable: 'Not available here', pluginSyncRouteMissing: 'Host endpoint not ready: the plugin-sync endpoint is new in this build and needs one restart to become available', pluginSyncUnreachable: 'Cannot reach the host', pluginSyncFailed: 'Sync failed', }