/** `mobileNav` namespace dictionaries: drawer controls. */ export const NS = 'mobileNav' /** Simplified Chinese dictionary (the key-set source of truth). */ export const zh = { 'open': '打开目录', 'close': '收起目录', 'backdrop': '点击关闭目录', 'sessionLog': '导出会话日志', 'files': '文件浏览', 'previewFullscreen': '全屏预览', 'previewExitFullscreen': '退出全屏', 'allWorkspaces': '全部', 'switchWorkspace': '切换工作区', 'newSession': '新建会话', 'noSessions': '暂无会话,点击右下角加号新建', 'homeStatusOngoing': '运行中', 'homeStatusWarning': '待处理', 'homeStatusDone': '已完成', 'backToList': '返回会话列表', 'sessionInfo': '会话信息', 'workbench': '工作台', 'workbenchClose': '关闭工作台', 'sidebar': '侧边栏', 'switchView': '切换视图', 'attach': '添加附件', 'attachBusy': '上传中…', 'attachFailed': '上传失败,点按重试', 'attachRemove': '移除附件 {name}', 'infoClose': '关闭', 'infoMode': '模式', 'infoCwdFallback': '未知目录', 'infoSubagents': '{count} 个子代理', 'infoJobs': '{count} 个后台任务', 'activityOpen': '查看子代理与后台任务', 'infoStatTurns': '轮次', 'infoStatSteps': '步骤', 'infoStatTtft': '首字延迟', 'infoStatLlm': '模型耗时', 'infoStatTool': '工具耗时', 'infoStatCacheHit': '缓存命中', 'infoTokenFlow': 'Token {io}', 'infoExport': '导出日志', 'infoRename': '重命名', 'infoRenamePrompt': '会话新名称', 'infoFork': 'Fork 会话', 'infoArchive': '归档', 'infoArchiveConfirm': '归档后将从会话列表隐藏,确定继续?', 'infoActionError': '操作失败:{message}', 'turnFold': '过程 · {count} 步', 'turnFoldRunning': '进行中 · {count} 步', 'shareCardTurns': '{count} 轮对话', 'shareCardGeneratedBy': '由 DeepSeek Harness 生成', 'shareCardImage': '图片附件', 'shareAction': '分享图', 'sharePickerTitle': '分享范围', 'sharePickerAll': '全部对话', 'sharePickerLast': '最近 {count} 轮', 'sharePickerConfirm': '生成分享图', 'sharePickerBusy': '生成中…', 'shareTruncatedNote': '内容过长,已省略前 {count} 轮', 'shareErrRouteMissing': '当前 DSH 版本未提供分享图接口,请更新 DSH 后重试', 'shareErrSessionNotFound': '会话不存在或已被删除', 'shareErrBadRequest': '分享请求无效,请重试', 'shareErrNetwork': '网络连接失败,请检查网络后重试', 'shareErrServer': '服务暂时不可用,请稍后重试', 'shareErrBody': '分享数据异常,请重试', 'shareErrProbe': '当前浏览器无法生成分享图', 'shareErrRender': '生成分享图失败,请重试', 'shareErrSliceBudget': '分享图单段内容超出画布上限,请缩小分享范围后重试', 'shareErrEmpty': '会话暂无可分享的内容', 'shareStitchUnsupported': '当前浏览器暂不支持合成单张长图,已导出为多张图片', 'shareStitchFailed': '合成单张长图失败,已改为多张图片导出', 'settings': '设置', 'chipTaskboard': '任务看板', 'chipSsh': 'SSH', 'chipUsage': '用量', 'chipCustomize': '自定义入口', // --- 插件设置页(T15),主服务端区块 --- 'settings.summary': '远程访问的配对、设备、网关与推送设置', 'settings.unavailable': '当前部署未开放这项配置。', 'settings.readOnly': '当前部署的设置为只读。', 'settings.saveFailed': '保存未被接受;草稿已保留,可修改后重试。', 'settings.save': '保存', 'settings.saving': '保存中…', 'settings.overridden': '已覆盖', 'settings.reset': '重置', 'settings.roleTitle': '角色', 'settings.role': '运行角色', 'settings.roleHint': '本 DSH 进程在远程访问体系中的角色。', 'settings.roleHost': '主服务端(host)', 'settings.roleClient': '子客户端(client)', 'settings.reloadNote': '保存后插件会自动重载,网关短暂中断', 'settings.gatewayTitle': '网关与反代', 'settings.gatewayRunning': '运行中 · 端口 {port} · 转发到 {target}', 'settings.gatewayDown': '网关未运行', 'settings.gatewayAbnormal': '网关回应异常(HTTP {code})', 'settings.fieldHost': '监听地址', 'settings.fieldHostHint': '网关子进程绑定的地址,默认 127.0.0.1;反代部署保持本机回环。留空清除。', 'settings.fieldHostNote': '必须包含本机回环地址(填 127.0.0.1 或 0.0.0.0)。设置页通过回环地址管理网关,只填局域网 IP 会导致配对与设备管理不可用。', 'settings.fieldPort': '网关端口', 'settings.fieldPortHint': '网关子进程监听的端口,1–65535 的整数,默认 3088。', 'settings.fieldTrustedProxies': '可信代理', 'settings.fieldTrustedProxiesHint': '逗号分隔的反代 IP 列表,网关据此信任 X-Forwarded-* 头。留空清除。', 'settings.fieldRateLimit': '限流(次/分钟)', 'settings.fieldRateLimitHint': '尚未配对的请求每分钟允许的次数(按客户端 IP 计,已配对设备不受限),正整数。', 'settings.fieldVapidSubject': '推送联系人', 'settings.fieldVapidSubjectHint': 'VAPID subject,mailto: 或 https: 地址。留空清除。', 'settings.invalidPort': '需要 1–65535 的整数', 'settings.invalidPositiveInt': '需要正整数', 'settings.pushTitle': '推送', 'settings.fieldPushSummary': '推送内容摘要', 'settings.fieldPushSummaryHint': '在推送正文中包含回合的最终文本或待回答的问题。', 'settings.fieldPushTurnEnd': '回合结束推送', 'settings.fieldPushTurnEndHint': '每个顶层回合结束时都推送;默认仅在需要处理时推送。', 'settings.fieldPushTool': '注册 push_notify 工具', 'settings.fieldPushToolHint': '允许模型主动发送通知。', 'settings.fieldPushDebounceMs': '防抖间隔(毫秒)', 'settings.fieldPushDebounceMsHint': '两次推送之间的最小间隔,不小于 0 的整数。', 'settings.fieldLang': '通知语言', 'settings.fieldLangHint': '推送与配对页文案的语言;auto 跟随请求方。', 'settings.langAuto': '自动(auto)', 'settings.langZh': '中文(zh)', 'settings.langEn': 'English(en)', 'settings.invalidNonNegativeInt': '需要不小于 0 的整数', 'settings.pushTestLabel': '测试推送', 'settings.pushTestRun': '发送测试推送', 'settings.pushTestRunning': '发送中…', 'settings.pushTestOk': '已发送:成功 {sent} 条,失败 {failed} 条', 'settings.pushTestFail': '测试推送发送失败', 'settings.pairingTitle': '配对', 'settings.pairingWebGuide': '适用于手机、平板及各类浏览器。通过网关地址访问,可查看并操作服务端的全部会话。', 'settings.pairingDesktopGuide': '适用于已安装 DSH 桌面端、并启用 zen-remote 子客户端角色的计算机。配对后,服务端已开启远程连接的会话将显示在该计算机的侧边栏中,其余会话不可见。', 'settings.pairingGenerate': '生成配对码', 'settings.pairingGenerating': '生成中…', 'settings.pairingCodeLabel': '配对码', 'settings.pairingRemaining': '剩余 {count} 秒', 'settings.pairingFail': '配对码生成失败', 'settings.devicesTitle': '设备', 'settings.devicesEmpty': '暂无已配对的设备', 'settings.deviceRoleWeb': 'Web 应用端', 'settings.deviceRoleDesktop': '桌面应用端', 'settings.kindAuto': '自动', 'settings.kindPhone': '手机', 'settings.kindDesktop': '电脑', 'settings.deviceLastSeen': '最近在线 {time}', 'settings.devicePushOn': '已订阅推送', 'settings.devicePushOff': '未订阅推送', 'settings.deviceRename': '重命名', 'settings.renamePrompt': '设备新名称', 'settings.renameSave': '确定', 'settings.renameCancel': '取消', 'settings.deviceRevoke': '吊销', 'settings.deviceRoleSelect': '{name} 的角色', 'settings.deviceKindSelect': '{name} 的界面布局', 'settings.revokeConfirm': '吊销后该设备需要重新配对,确定继续?', 'settings.revokeAll': '全部吊销', 'settings.revokeAllConfirm': '将吊销全部已配对设备,确定继续?', 'settings.actionFail': '操作失败', 'settings.shareTitle': '远程共享', 'settings.shareListTitle': '已开启远程的会话', 'settings.shareListEmpty': '当前没有已开启远程的会话', 'settings.shareViewers': '{count} 台设备正在查看', 'settings.shareClose': '关闭远程', 'settings.shareCloseAll': '全部关闭', 'settings.shareCloseAllConfirm': '将关闭全部已开启远程的会话,确定继续?', 'settings.shareActionFail': '操作失败', 'settings.fieldServerName': '设备名称', 'settings.fieldServerNameHint': '其他设备远程访问时显示的名称,1–40 个字符,留空恢复默认。', 'settings.fieldServerNameHintClient': '配对时注册到服务端的名称,1–40 个字符。', 'settings.fieldIdleHours': '闲置休眠(小时)', 'settings.fieldIdleHoursHint': '超过该时长无新活动时,自动关闭远程连接。运行中或等待中的会话不计时。默认 48,取值大于 0 且不超过 8760。', 'settings.fieldAutoShare': '自动共享新会话', 'settings.fieldAutoShareHint': '新建的会话自动共享给已配对的设备。', 'settings.invalidName': '名称需要 1–40 个字符', 'settings.invalidHours': '需要大于 0 且不超过 8760 的数字', 'settings.remoteNotice': '配对与设备管理只能在服务端本机操作', 'settings.savedInvalid': '已保存的值无效,当前生效的是 {source} 的值', 'settings.sourceEnvBadge': '由环境变量锁定', 'settings.sourceFileBadge': '来自旧配置文件 lan-gate.config.json', 'settings.sourceEnv': '环境变量', 'settings.sourceFile': '旧配置文件 lan-gate.config.json', 'settings.sourceDefault': '默认值', 'settings.statusUnavailable': '无法读取插件状态(HTTP {code})', 'settings.statusUnknown': '无法读取插件状态', 'settings.refreshFailed': '状态刷新失败,当前显示的是上一次成功的数据', 'settings.resetPreview': '保存后恢复为下一层的值', // --- 插件设置页(T16),子客户端区块 --- 'settings.client.connectTitle': '连接服务端', 'settings.client.serverUrl': '服务端地址', 'settings.client.serverUrlHint': '服务端网关地址,例如 http://192.168.1.10:3088 或 https://dsh.example.com。', // The label above is the shared 设备名称 field in the role card (T57); this // is only the fallback name a pairing registers under when that field is // empty. 'settings.client.deviceNameDefault': '桌面应用端', // T60: the pairing button's disabled reason while the device-name draft is invalid. 'settings.client.fixDeviceName': '请先修正设备名称', 'settings.client.pairingCode': '配对码', 'settings.client.pairingCodeHint': '在服务端设置页生成「桌面应用端」配对码后填入(8 位,自动转大写并过滤 0/O/1/I/L 与符号)。', 'settings.client.pair': '配对', 'settings.client.pairing': '配对中…', 'settings.client.failInvalid': '服务端地址不合法', 'settings.client.failInsecureHttp': '公网地址必须使用 https;http 只允许局域网或 Tailscale 地址', 'settings.client.failBadCode': '配对码错误或已过期', 'settings.client.failLocked': '尝试次数过多,请 {minutes} 分钟后再试', 'settings.client.failUnreachable': '无法连接服务端', 'settings.client.failRoleMismatch': '该配对码不适用于桌面应用端', 'settings.client.failUnexpected': '服务端回应无法识别,请确认服务端已安装 dsh-zen-remote 2.0.0', 'settings.client.failWrite': '配对成功,但本机保存令牌失败:设置存储不可用或只读', 'settings.client.statusTitle': '连接状态', 'settings.client.statusUnpaired': '未配对', 'settings.client.statusConnected': '已连接到 {serverUrl}', 'settings.client.statusRevoked': '令牌已被吊销,请重新配对', 'settings.client.statusUnreachable': '服务端当前不可达', 'settings.client.statusUnexpected': '服务端版本不支持远程会话(需要 dsh-zen-remote 2.0.0)', 'settings.client.statusInvalidUrl': '服务端地址无效或不安全,请重新配对', 'settings.client.statusRefresh': '刷新', 'settings.client.statusRefreshing': '刷新中…', 'settings.client.tokenSet': '设备令牌已保存', 'settings.client.unpair': '解除配对', 'settings.client.unpairBusy': '解除中…', 'settings.client.unpairConfirm': '本机将忘记已保存的服务端令牌(服务端的设备记录不受影响)。确定继续?', 'settings.client.unpairDone': '本机已忘记令牌;如需彻底失效,请在服务端设备列表中吊销该设备', // --- 会话共享(T33b):标题行图标、右键菜单项、设置页共享列表 --- 'shareRemoteOn': '开启远程', 'shareRemoteOff': '关闭远程', 'shareRemoteStateOff': '未开启远程', // T67: the info-card row's on-state word — the icon only colored this // state and never had copy for it. 'shareRemoteStateOn': '已开启远程', // T67: the info-card row's label. 'infoRemoteAccess': '远程访问', 'shareRemoteBusy': '运行中,不计时', 'shareRemoteRemainingHours': '剩余闲置时间 {count} 小时', 'shareRemoteRemainingMinutes': '剩余闲置时间 {count} 分钟', 'shareRemoteConfirmOn': '开启远程后,已配对的桌面应用端将可以查看并操作此会话。确定开启?', 'shareRemoteConfirmOff': '关闭后,桌面应用端将无法再访问此会话。确定关闭?', 'shareRemoteFailSubagent': '开启远程失败:子智能体会话不能单独开启', 'shareRemoteFailEmpty': '开启远程失败:会话暂无内容', 'shareRemoteFailGeneric': '操作失败,请稍后再试', // --- T43 诊断区 --- 'settings.client.reconnect': '立即重连', 'settings.client.reconnectBusy': '重连中…', 'settings.client.statusConnectedName': '已连接到「{serverName}」', 'settings.client.statusOfflineRetry': '离线,将于 {seconds} 秒后重试', 'settings.client.statusOfflineRetrySoon': '离线,即将重试…', 'settings.client.statusIncompatible': '与服务端中继协议不兼容,请升级两端的 dsh-zen-remote', 'settings.client.diagTitle': '诊断', 'settings.client.diagLastError': '最近错误码:{code}', 'settings.client.diagInterceptInstalled': '请求拦截器已安装', 'settings.client.diagInterceptMissing': '请求拦截器未安装', 'settings.client.diagInterceptDisabled': '远程功能已停用:DSH 内部结构与预期不符', 'settings.client.diagRecentFailures': '最近的远程调用失败', 'settings.client.diagCompatGroups': '指纹有差异的组:{groups}', 'settings.client.diagCompatCalls': '最近的不兼容调用', // --- RD-3 远程会话拖拽守卫的诊断行(浏览器端计数,渲染时现读) --- 'settings.client.diagRemoteDrop': '远程拖拽守卫', 'settings.client.diagRemoteDropOk': '已安装 · 拦截 {intercepted} · 重派发 {redispatched} · 文件夹 {blocked} · 放行 {passthrough} · 重包失败 {failed}', 'settings.client.diagRemoteDropOff': '未安装({reason})', // --- RD-6 上传改道(fetch-route 拦截)的诊断行:读 remote-status 的 serviceProbe --- 'settings.client.diagUploadRedirect': '上传改道', 'settings.client.diagUploadRedirectOk': '已安装 · 上传已接管', 'settings.client.diagUploadRedirectRefused': '拒装:{reason}', 'settings.client.diagUploadRedirectPending': '服务注入未触发 · connection {connection} · fileUploads {fileUploads}', // --- PB-5 插件桥:主服务端同意小节 + 子客户端诊断小节 --- 'settings.bridge.title': '插件桥', 'settings.bridge.empty': '暂无插件登记插件桥', 'settings.bridge.loading': '正在读取插件桥登记…', 'settings.bridge.loadFailed': '插件桥列表读取失败(旧版服务端或经网关打开的页面)', 'settings.bridge.sessionOnly': '随会话共享转发', 'settings.bridge.consentToggle': '允许转发整机数据', 'settings.bridge.consentHint': '打开后,已配对的桌面应用端可在远程会话里读取该插件的整机数据。', 'settings.bridge.stateBridged': '已桥接', 'settings.bridge.stateNotOnServer': '服务端未安装', 'settings.bridge.stateVersionMismatch': '版本不同(服务端 {version})', 'settings.bridge.stateDeclarationMismatch': '声明不一致', 'settings.bridge.stateConsentOff': '服务端主人未允许整机数据', 'settings.bridge.stateOffline': '中继离线', 'settings.bridge.stateServerTooOld': '服务端 zen-remote 版本过旧', 'settings.bridge.interceptOff': '本机改道未启用:{reason}', // --- T34 子客户端远程状态:标题行图标、横幅、关闭远程 --- 'remoteStatusOnline': '远程会话 · 已连接', 'remoteStatusOffline': '服务端离线,正在重连', 'remoteStatusMismatch': '与服务端版本不一致,部分功能可能不可用', 'remoteStatusRevoked': '令牌已吊销,请在设置页重新配对', 'remoteStatusUnpaired': '已解除配对', 'remoteBannerOffline': '服务端离线,远程会话暂时只读,恢复连接后自动可用', 'remoteBannerRevoked': '令牌已吊销,请在设置页重新配对', 'remoteBannerUnpaired': '已解除配对', 'remoteBannerClosedIdle': '远程已关闭:闲置超过设定时间,已自动休眠', 'remoteBannerClosedManual': '远程已关闭:服务端已关闭此会话的远程', 'remoteBannerClosedClient': '远程已关闭:已在本机关闭远程', 'remoteStatusUnshareConfirm': '关闭远程后,此会话将从本机的远程分组中移除,服务端上的会话不受影响。确定关闭?', 'remoteStatusOfflineClick': '服务端离线,无法操作', 'remoteStatusUnshareFail': '关闭远程失败,请稍后再试', 'remoteStatusUnshareFailCode': '关闭远程失败({code}),请稍后再试', // --- PB-14: the unbridged better-sidebar note (a CSS variable the // remote-session stylesheet spends as the empty tab's ::before copy) --- 'remoteBridgeUnbridgedNote': 'better-sidebar 未在远程会话桥接(服务端未装同版本或未允许),文件与改动请以会话内消息为准', // 远程分组标题的后缀(后台 merge-streams 拿不到界面语言,固定用中文); // 这里登记英文对照,供界面侧需要复述同样状态时使用。 'remoteGroupOffline': '(离线)', 'remoteGroupRevoked': '(令牌已吊销)', 'remoteGroupUnpaired': '(已解除配对)', 'remoteGroupMismatch': '(版本有差异)', // --- 远程会话拖拽附件(RD-2):文件夹被拦截时的短暂提示 --- 'remoteDropFolderBlocked': '远程会话暂不支持拖入文件夹', // --- 2.2.6: 远程会话产物下载(deliverable 卡片 / 文档预览头) --- 'downloadToLocal': '下载到本机', 'downloadBusy': '下载中…', 'downloadFailed': '下载失败', // --- GW-10: 远程访问与配对向导(服务端公网/局域网接入 + 手机/桌面客户端配对) --- 'wizard.title': '远程访问与设备配对', 'wizard.subtitle': '配置本机作为服务端(开放手机与另一台电脑连入)或作为客户端连接远端主机', 'wizard.off': '局域网模式 / 待配置', 'wizard.step.pick': '选择角色与接入', 'wizard.step.configure': '填写连接参数', 'wizard.step.verify': '连通验证与配对', 'wizard.role.sectionTitle': '本机角色', 'wizard.role.host': '作为服务端(主机)', 'wizard.role.hostDesc': '本机运行主力会话与网关,允许手机或另一台 DSH 电脑连入并操作会话', 'wizard.role.client': '作为桌面客户端(从机)', 'wizard.role.clientDesc': '本机连接到另一台 DSH 服务端,在侧边栏直接查看与操作远端共享的会话', 'wizard.role.clientPickNote': '切为客户端后,本机将连接到远端服务端的网关(支持公网 HTTPS 域名或局域网 / Tailscale 地址)。点击「下一步」填写服务端地址与配对码。', 'wizard.ingressSectionTitle': '服务端接入方式', 'wizard.path.caddy': '内置 Caddy(推荐)', 'wizard.path.caddyDesc': '适合有公网 IP 的环境。自动下载 Caddy 并通过 Cloudflare DNS 申请证书,无需手写反代配置', 'wizard.path.external': '使用已有反向代理', 'wizard.path.externalDesc': '适合已部署 Nginx、Caddy 或 Lucky 的环境。提供现成转发规则,直接填入现有反代即可', 'wizard.path.cloudflared': 'Cloudflare Tunnel 内网穿透', 'wizard.path.cloudflaredDesc': '无需公网 IP,也不必配置路由器端口映射。通过 Cloudflare 隧道直连本机,需域名已接入 Cloudflare', 'wizard.path.lan': '局域网 / Tailscale 直连', 'wizard.path.lanDesc': '在同一局域网或虚拟局域网内连接手机与另一台电脑,无需域名与公网证书', 'wizard.next': '下一步', 'wizard.back': '上一步', 'wizard.hostName': '服务端显示名称', 'wizard.hostNamePlaceholder': '例如:mac-mini', 'wizard.hostNameHint': '其他电脑或手机连入后在侧边栏看到的主机名称(可留空使用默认名称)', 'wizard.autoShare': '新建会话自动共享给已配对的桌面客户端', 'wizard.lanUrl': '局域网 / Tailscale 访问地址(可选)', 'wizard.lanUrlPlaceholder': 'http://192.168.1.10:3088', 'wizard.lanUrlHint': '填写本机局域网或 Tailscale 地址(如 http://192.168.1.10:3088),方便下一步直接生成手机扫码二维码与客户端连接信息', 'wizard.domain': '访问域名', 'wizard.domainHint': '填写完整域名,如 dsh.example.com(不带 https:// 和路径)', 'wizard.httpsPort': 'HTTPS 端口', 'wizard.cfToken': 'Cloudflare API 令牌', 'wizard.cfTokenHint': '用于自动申请证书或配置隧道,以 0600 权限保存在本机,不写入配置文件', 'wizard.cfTokenHowTo': '如何获取 API 令牌', 'wizard.serverUrl': '反代后的公网地址', 'wizard.serverUrlHint': '填写完整 HTTPS 根地址,如 https://dsh.example.com(不支持子目录)', 'wizard.proxySnippet': '查看 Nginx / Caddy / Lucky 配置参考', 'wizard.badDomain': '域名格式无效,请填写如 dsh.example.com 的域名', 'wizard.badPort': '端口号需为 1–65535 之间的整数', 'wizard.missingToken': '请填写 Cloudflare API 令牌', 'wizard.badServerUrl': '请填写有效的根路径地址(公网需 https://,局域网可用 http://,不含子目录)', 'wizard.verify.gateway': '本地网关就绪', 'wizard.verify.public': '访问地址连通', 'wizard.verify.pairing': '设备配对状态', 'wizard.light.pass': '正常', 'wizard.light.pending': '待验证', 'wizard.light.fail': '异常', 'wizard.pairTarget.web': '配对手机 / 浏览器(扫码)', 'wizard.pairTarget.desktop': '配对另一台电脑(桌面客户端)', 'wizard.startVerify': '生成配对二维码', 'wizard.reverify': '重新生成二维码', 'wizard.pairingCode': '配对码', 'wizard.pairingSeconds': '有效期剩余 {seconds} 秒', 'wizard.qrHint': '用手机相机或浏览器扫码打开配对页,输入上方配对码完成连接', 'wizard.verifyPass': '配对成功,设备 {deviceId} 已连接', 'wizard.verifyCookieInsecure': '手机已完成配对,但反向代理未传递 X-Forwarded-Proto: https,导致安全 Cookie 未生效。请检查转发头后重试', 'wizard.verifyExpired': '配对码已过期,请点击下方按钮重新生成', 'wizard.verifyStale': '接入配置已变更,请重新生成二维码', 'wizard.verifyPending': '请用手机扫描二维码并在页面中输入配对码…', 'wizard.verifyNotStarted': '点击下方按钮验证访问地址并生成手机配对二维码', 'wizard.desktop.addressLabel': '服务端连接地址(供客户端填写)', 'wizard.desktop.addressFallback': 'http://<本机局域网IP>:{port}', 'wizard.desktop.generate': '生成桌面客户端配对码', 'wizard.desktop.regenerate': '重新生成配对码', 'wizard.desktop.copyInfo': '复制地址与配对码', 'wizard.desktop.guide': '在另一台电脑打开本插件详情页,第 1 步选「作为桌面客户端」,第 2 步填入上方服务端地址与 8 位配对码即可完成连接。', 'wizard.desktop.pairedTitle': '已连接的桌面客户端({count})', 'wizard.desktop.pairedEmpty': '暂未配对桌面客户端', 'wizard.client.deviceName': '本机设备名称', 'wizard.client.deviceNamePlaceholder': '例如:macbook-pro', 'wizard.client.deviceNameHint': '配对后在服务端设备列表中显示的名称', 'wizard.client.serverUrl': '服务端地址', 'wizard.client.serverUrlPlaceholder': 'https://dsh.example.com 或 http://192.168.1.10:3088', 'wizard.client.serverUrlHint': '填写服务端的公网 HTTPS 地址,或局域网 / Tailscale 下的 http://<服务端IP>:3088', 'wizard.client.pairingCode': '8 位桌面配对码', 'wizard.client.pairingCodePlaceholder': '在服务端向导第 3 步切到「配对另一台电脑」生成', 'wizard.client.pairingCodeHint': '输入服务端生成的 8 位桌面客户端专用配对码(自动转大写,自动过滤 0/O/1/I/L 及符号)', 'wizard.client.pairAndConnect': '配对并连接服务端', 'wizard.client.pairingBusy': '正在配对并连接…', 'wizard.client.skipToStatus': '已配对,查看连接状态', 'wizard.client.lightCredential': '本地配对凭证', 'wizard.client.lightConnection': '服务端连接', 'wizard.client.lightSync': '会话与插件同步', 'wizard.client.reconfigure': '更换服务端 / 重新配对', 'wizard.startFailed': '验证未通过:{reason}', 'wizard.startFailedProbe': '无法访问该连接地址({detail})', 'wizard.startFailedRuntime': '入口服务尚未运行,请先在上方启动', 'wizard.startFailedGateway': '本地网关未响应,请检查网关运行状态', 'wizard.startFailedPair': '无法生成配对码({detail})', 'wizard.startFailedUrl': '公网地址格式无效', 'wizard.remoteOnly': '安全限制:公网接入向导仅限在服务端本机操作', 'wizard.notWired': '当前服务端版本不支持此功能,请升级后重试', 'wizard.card.proxyTitle': '反向代理配置参考', 'wizard.card.tokenTitle': '获取 Cloudflare API 令牌', 'wizard.card.copy': '复制配置', 'wizard.card.copied': '已复制', 'wizard.card.close': '关闭', 'wizard.card.tokenStep1': '登录 Cloudflare 控制台(dash.cloudflare.com),进入右上角「我的个人资料 → API 令牌」(用户令牌,以 cfut_ 开头),或左侧「管理账户 → 账户 API 令牌」(账户令牌,以 cfat_ 开头)', 'wizard.card.tokenStep2': '点击「创建令牌」(Create Token),选择「编辑区域 DNS」(Edit zone DNS)模板', 'wizard.card.tokenStep3': '在「权限」中保留默认的「区域(Zone)· DNS · 编辑(Edit)」权限', 'wizard.card.tokenStep4': '在「区域资源」(Zone Resources)中选择「包括(Include)· 特定区域(Specific zone)· 你的域名」', 'wizard.card.tokenStep5': '若使用 Cloudflare Tunnel,点击「+ 添加更多权限」补充下方所列的隧道、账户设置与区域读取权限', 'wizard.card.tokenStep6': '点击「继续以显示摘要」(Continue to summary),核对无误后点击「创建令牌」(Create Token)', 'wizard.card.tokenStep7': '复制生成的 API 令牌密钥(仅在创建完成页显示一次,关闭后无法再次查看)', 'wizard.card.tokenStep8': '粘贴到下方输入框并点击「保存令牌」', 'wizard.card.tokenPerms': '所需权限对照', 'wizard.card.tokenPermDns': '区域 · DNS · 编辑', 'wizard.card.tokenPermDnsWhy': '必选,用于 DNS-01 证书签发与解析记录配置', 'wizard.card.tokenPermTunnel': '账户 · Cloudflare Tunnel · 编辑', 'wizard.card.tokenPermTunnelWhy': '仅 Cloudflare Tunnel 方式需要', 'wizard.card.tokenPermAccount': '账户 · 账户设置 · 读取', 'wizard.card.tokenPermAccountWhy': '仅 Cloudflare Tunnel 方式需要(读取账户 ID)', 'wizard.card.tokenPermZoneRead': '区域 · 区域 · 读取', 'wizard.card.tokenPermZoneReadWhy': '仅 Cloudflare Tunnel 方式需要(定位域名所属区域)', 'wizard.card.tokenPaste': '粘贴 API 令牌', 'wizard.card.tokenUse': '保存令牌', 'wizard.card.migrateTitle': '将域名接入 Cloudflare', 'wizard.card.migrateStep1': '在域名注册商后台关闭 DNSSEC(若已开启),并确认域名未锁定 NS(名称服务器)修改', 'wizard.card.migrateStep2': '登录 Cloudflare 控制台,在左侧导航进入「域(Domains)→ 概览」,点击「接入域」(Onboard a domain)', 'wizard.card.migrateStep3': '输入你的根域名(如 example.com),选择快速扫描 DNS 记录,点击继续并选择 Free 计划', 'wizard.card.migrateStep4': '核对扫描出的 DNS 解析记录后继续,复制 Cloudflare 分配的两个名称服务器(Nameservers)地址', 'wizard.card.migrateStep5': '前往域名注册商后台,将原有 NS 替换为 Cloudflare 分配的两个名称服务器地址', 'wizard.card.migrateStep6': '等待状态变为「活动(Active)」(通常数分钟至数小时),返回此处点击「重新检测域名状态」', 'wizard.card.migrateRecheck': '重新检测域名状态', 'wizard.card.proxyCheck': '已配置完成,去验证', 'wizard.card.portForwardTitle': '路由器端口映射说明', 'wizard.card.portForwardStep1': '登录路由器管理后台(常见地址为 192.168.1.1 或 192.168.0.1)', 'wizard.card.portForwardStep2': '进入「端口转发 / 虚拟服务器 / NAT」设置页面', 'wizard.card.portForwardStep3': '新增 TCP 转发规则:外部端口 {port} 指向本机内网 IP 的 {port} 端口', 'wizard.card.portForwardStep4': '保存规则后,使用手机移动网络(关闭 Wi-Fi)测试公网连接', 'wizard.portForwardEntry': '非 443 端口:查看路由器端口映射说明', 'wizard.migrateEntry': '域名尚未接入 Cloudflare?', 'wizard.ingress': '入口服务', 'wizard.caddy.start': '启动 Caddy', 'wizard.caddy.starting': '正在下载并启动…', 'wizard.caddy.stop': '停止', 'wizard.caddy.running': 'Caddy 运行中', 'wizard.caddy.stopped': 'Caddy 已停止', 'wizard.caddy.neverStarted': 'Caddy 未启动', 'wizard.caddy.startOk': 'Caddy 已启动', 'wizard.caddy.startFailed': 'Caddy 启动失败:{reason}', 'wizard.caddy.failDownload': '自动下载失败,请手动安装后重试', 'wizard.caddy.failValidate': '生成的配置文件校验未通过', 'wizard.caddy.failAlreadyRunning': '服务已在运行中', 'wizard.caddy.failMissingToken': '请先在上一步保存 Cloudflare API 令牌', 'wizard.caddy.failNoDomain': '请先在上一步填写有效的访问域名', 'wizard.caddy.failBadConfig': '配置参数有误:{detail}', 'wizard.caddy.failSpawn': '无法拉起 Caddy 进程', 'wizard.token.saved': '已保存在本机', 'wizard.token.saveFailed': '令牌保存失败,请重试', 'wizard.tunnel.setup': '创建并启动隧道', 'wizard.tunnel.stop': '停止', 'wizard.tunnel.running': '隧道运行中', 'wizard.tunnel.stopped': '隧道已停止', 'wizard.tunnel.neverStarted': '隧道未启动', 'wizard.tunnel.ok': 'Cloudflare 隧道已就绪并开始运行', 'wizard.tunnel.conflict': '检测到同名隧道,请选择要复用的隧道:', 'wizard.tunnel.useExisting': '复用隧道', 'wizard.tunnel.zoneNotFound': '当前令牌下未找到该域名所属的 Cloudflare 区域,请确认域名已接入该账号', 'wizard.tunnel.dnsConflict': '该域名已存在指向 {detail} 的 CNAME 记录,请先在 Cloudflare DNS 中清理后再试', 'wizard.tunnel.auth': 'Cloudflare 认证失败,请检查令牌权限是否正确', 'wizard.tunnel.network': '无法连接 Cloudflare API,请检查网络', 'wizard.tunnel.api': 'Cloudflare 接口报错:{detail}', 'wizard.tunnel.spawnFailed': 'cloudflared 启动失败:{detail}', 'wizard.tunnel.noToken': '请先在上一步保存 Cloudflare API 令牌', 'wizard.tunnel.badDomain': '域名格式无效', 'wizard.tunnel.checking': '正在配置隧道并启动(首次自动下载 cloudflared)…', 'wizard.check.okOnCf': '已确认域名托管在 Cloudflare', 'wizard.check.okNotOnCf': '未在 Cloudflare 中找到该域名,请先完成域名接入', 'wizard.check.failed': '域名检测失败:{reason}', 'wizard.overview.roleLabel': '当前角色', 'wizard.overview.gatewayLabel': '本地网关', 'wizard.overview.gatewayReady': '运行正常 · 端口 {port}', 'wizard.overview.gatewayDown': '未响应', 'wizard.overview.ingressLabel': '接入方式与地址', 'wizard.overview.devicesLabel': '已配对设备', 'wizard.overview.devicesSummary': '手机/网页 {web} 台 · 桌面客户端 {desktop} 台', 'wizard.overview.devicesNone': '暂未配对设备', 'wizard.overview.clientCredLabel': '本地配对凭证', 'wizard.overview.clientConnLabel': '服务端连接', 'wizard.overview.clientServerLabel': '远端服务端地址', 'wizard.overview.startSetup': '开始配置向导', 'wizard.overview.reconfigure': '修改接入配置', 'wizard.overview.pairPhone': '配对手机 / 扫码', 'wizard.overview.pairDesktop': '配对另一台电脑', 'wizard.overview.clientDetail': '连接详情与配对向导', 'wizard.overview.emptyIntro': '尚未完成远程访问配置。点击右侧按钮启动向导,按步骤配置本机作为服务端(开放手机与另一台电脑连入)或作为桌面客户端连接远端主机。', 'wizard.modal.title': '远程访问与配对向导', 'wizard.modal.stepTag': '第 {num} 步', 'wizard.modal.step1Desc': '选择本机作为服务端还是桌面客户端;若作为服务端,选择外部设备的连入方式', 'wizard.modal.step2Desc': '根据上一步选择的方案,填写对应的连接地址、域名或配对凭证', 'wizard.modal.step3Desc': '检测连通状态,并扫码配对手机或生成桌面客户端配对码', 'wizard.modal.selectedPlan': '已选方案:{plan}', 'wizard.modal.cancel': '取消', 'wizard.modal.saveAndNext': '保存并进入验证', 'wizard.modal.finish': '完成', 'wizard.light.probing': '检测中…', 'wizard.overview.manageDevices': '管理设备', 'wizard.devicesModal.title': '已配对设备管理', 'wizard.devicesModal.subtitle': '查看与管理已配对的手机/网页设备及桌面客户端,支持改名、切换布局或吊销凭证', 'wizard.devicesModal.retest': '重新测试连通性', } as const /** English dictionary, key-identical to the Chinese source of truth. */ export const en: Record = { 'open': 'Open directory', 'close': 'Close directory', 'backdrop': 'Click to close directory', 'sessionLog': 'Session log', 'files': 'Files', 'previewFullscreen': 'Fullscreen preview', 'previewExitFullscreen': 'Exit fullscreen', 'allWorkspaces': 'All', 'switchWorkspace': 'Switch workspace', 'newSession': 'New session', 'noSessions': 'No sessions yet — tap + to start one', 'homeStatusOngoing': 'Running', 'homeStatusWarning': 'Needs attention', 'homeStatusDone': 'Done', 'backToList': 'Back to sessions', 'sessionInfo': 'Session info', 'workbench': 'Workbench', 'workbenchClose': 'Close workbench', 'sidebar': 'Sidebar', 'switchView': 'Switch view', 'attach': 'Add attachment', 'attachBusy': 'Uploading…', 'attachFailed': 'Upload failed — tap to retry', 'attachRemove': 'Remove attachment {name}', 'infoClose': 'Close', 'infoMode': 'Mode', 'infoCwdFallback': 'Unknown directory', 'infoSubagents': '{count} subagents', 'infoJobs': '{count} background tasks', 'activityOpen': 'View subagents and background tasks', 'infoStatTurns': 'Turns', 'infoStatSteps': 'Steps', 'infoStatTtft': 'TTFT', 'infoStatLlm': 'LLM time', 'infoStatTool': 'Tool time', 'infoStatCacheHit': 'Cache hit', 'infoTokenFlow': 'Tokens {io}', 'infoExport': 'Export log', 'infoRename': 'Rename', 'infoRenamePrompt': 'New session name', 'infoFork': 'Fork session', 'infoArchive': 'Archive', 'infoArchiveConfirm': 'Archiving hides this session from the list. Continue?', 'infoActionError': 'Action failed: {message}', 'turnFold': 'Process · {count} steps', 'turnFoldRunning': 'Working · {count} steps', 'shareCardTurns': '{count} turns', 'shareCardGeneratedBy': 'Made with DeepSeek Harness', 'shareCardImage': 'Image attachment', 'shareAction': 'Share image', 'sharePickerTitle': 'Share range', 'sharePickerAll': 'Whole conversation', 'sharePickerLast': 'Last {count} turns', 'sharePickerConfirm': 'Generate', 'sharePickerBusy': 'Generating…', 'shareTruncatedNote': 'Long conversation — first {count} turns omitted', 'shareErrRouteMissing': 'This DSH version has no share-image endpoint — please update DSH', 'shareErrSessionNotFound': 'Session not found or deleted', 'shareErrBadRequest': 'Invalid share request — please try again', 'shareErrNetwork': 'Network error — check the connection and try again', 'shareErrServer': 'Service temporarily unavailable — try again later', 'shareErrBody': 'Unexpected share data — please try again', 'shareErrProbe': 'This browser cannot render share images', 'shareErrRender': 'Failed to generate the share image — please try again', 'shareErrSliceBudget': 'One slice of the share image exceeded the canvas limit — try a smaller share range', 'shareErrEmpty': 'Nothing to share in this session yet', 'shareStitchUnsupported': 'This browser cannot stitch one long image — exported as multiple images instead', 'shareStitchFailed': 'Could not stitch one long image — exported as multiple images instead', 'settings': 'Settings', 'chipTaskboard': 'Task board', 'chipSsh': 'SSH', 'chipUsage': 'Usage', 'chipCustomize': 'Customize shortcuts', 'settings.summary': 'Pairing, devices, gateway and push settings for remote access', 'settings.unavailable': 'This deployment does not serve this configuration.', 'settings.readOnly': 'This deployment stores settings read-only.', 'settings.saveFailed': 'The save was not accepted; drafts kept for correction.', 'settings.save': 'Save', 'settings.saving': 'Saving…', 'settings.overridden': 'Overridden', 'settings.reset': 'Reset', 'settings.roleTitle': 'Role', 'settings.role': 'Runtime role', 'settings.roleHint': 'This DSH process\u2019s role in the remote-access setup.', 'settings.roleHost': 'Main server (host)', 'settings.roleClient': 'Sub client (client)', 'settings.reloadNote': 'Saving reloads the plugin automatically; the gateway restarts briefly', 'settings.gatewayTitle': 'Gateway & reverse proxy', 'settings.gatewayRunning': 'Running · port {port} · forwarding to {target}', 'settings.gatewayDown': 'Gateway not running', 'settings.gatewayAbnormal': 'Gateway responded abnormally (HTTP {code})', 'settings.fieldHost': 'Bind address', 'settings.fieldHostHint': 'Address the gateway child binds to, default 127.0.0.1; keep the loopback behind a reverse proxy. Empty clears.', 'settings.fieldHostNote': 'Must include the machine\u2019s loopback address (enter 127.0.0.1 or 0.0.0.0). The settings page manages the gateway through the loopback — a LAN-only IP makes pairing and device management unusable.', 'settings.fieldPort': 'Gateway port', 'settings.fieldPortHint': 'Port the gateway child listens on, an integer from 1 to 65535, default 3088.', 'settings.fieldTrustedProxies': 'Trusted proxies', 'settings.fieldTrustedProxiesHint': 'Comma-separated proxy IPs the gateway trusts for X-Forwarded-* headers. Empty clears.', 'settings.fieldRateLimit': 'Rate limit (requests/min)', 'settings.fieldRateLimitHint': 'Requests per minute allowed from unpaired clients (counted per client IP; paired devices are exempt), a positive integer.', 'settings.fieldVapidSubject': 'Push contact', 'settings.fieldVapidSubjectHint': 'VAPID subject, a mailto: or https: address. Empty clears.', 'settings.invalidPort': 'Enter an integer from 1 to 65535', 'settings.invalidPositiveInt': 'Enter a positive integer', 'settings.pushTitle': 'Push', 'settings.fieldPushSummary': 'Push body summary', 'settings.fieldPushSummaryHint': 'Include the turn\u2019s final text or pending question in push bodies.', 'settings.fieldPushTurnEnd': 'Turn-end push', 'settings.fieldPushTurnEndHint': 'Pushes at every top-level turn end; by default only attention-needed moments push.', 'settings.fieldPushTool': 'Register the push_notify tool', 'settings.fieldPushToolHint': 'Allows the model to send notifications on its own.', 'settings.fieldPushDebounceMs': 'Debounce window (ms)', 'settings.fieldPushDebounceMsHint': 'Minimum milliseconds between two pushes, an integer of at least 0.', 'settings.fieldLang': 'Notification language', 'settings.fieldLangHint': 'Language of push bodies and the pairing page; auto follows the requester.', 'settings.langAuto': 'Auto (auto)', 'settings.langZh': '中文 (zh)', 'settings.langEn': 'English (en)', 'settings.invalidNonNegativeInt': 'Enter an integer of at least 0', 'settings.pushTestLabel': 'Test push', 'settings.pushTestRun': 'Send test push', 'settings.pushTestRunning': 'Sending…', 'settings.pushTestOk': 'Sent: {sent} succeeded, {failed} failed', 'settings.pushTestFail': 'The test push could not be sent', 'settings.pairingTitle': 'Pairing', 'settings.pairingWebGuide': 'For phones, tablets and browsers. Reach it through the gateway address to view and operate every session on the server.', 'settings.pairingDesktopGuide': 'For computers running the DSH desktop app with the zen-remote sub-client role enabled. After pairing, sessions the server shares for remote connection appear in that computer\u2019s sidebar; other sessions stay invisible.', 'settings.pairingGenerate': 'Generate pairing code', 'settings.pairingGenerating': 'Generating…', 'settings.pairingCodeLabel': 'Pairing code', 'settings.pairingRemaining': '{count}s remaining', 'settings.pairingFail': 'Could not generate a pairing code', 'settings.devicesTitle': 'Devices', 'settings.devicesEmpty': 'No paired devices yet', 'settings.deviceRoleWeb': 'Web app', 'settings.deviceRoleDesktop': 'Desktop client', 'settings.kindAuto': 'Auto', 'settings.kindPhone': 'Phone', 'settings.kindDesktop': 'Desktop', 'settings.deviceLastSeen': 'Last seen {time}', 'settings.devicePushOn': 'Push subscribed', 'settings.devicePushOff': 'Push off', 'settings.deviceRename': 'Rename', 'settings.renamePrompt': 'New device name', 'settings.renameSave': 'OK', 'settings.renameCancel': 'Cancel', 'settings.deviceRevoke': 'Revoke', 'settings.deviceRoleSelect': 'Role of {name}', 'settings.deviceKindSelect': 'Layout of {name}', 'settings.revokeConfirm': 'Revoking requires this device to pair again. Continue?', 'settings.revokeAll': 'Revoke all', 'settings.revokeAllConfirm': 'This revokes every paired device. Continue?', 'settings.actionFail': 'The action failed', 'settings.shareTitle': 'Remote sharing', 'settings.shareListTitle': 'Sessions shared remotely', 'settings.shareListEmpty': 'No sessions are currently shared', 'settings.shareViewers': 'Viewers: {count}', 'settings.shareClose': 'Stop sharing', 'settings.shareCloseAll': 'Close all', 'settings.shareCloseAllConfirm': 'This disables remote access for every shared session. Continue?', 'settings.shareActionFail': 'The action failed', 'settings.fieldServerName': 'Device name', 'settings.fieldServerNameHint': 'The name other devices see when they access this machine remotely, 1–40 characters. Empty restores the default.', 'settings.fieldServerNameHintClient': 'The name registered with the server when pairing, 1–40 characters.', 'settings.fieldIdleHours': 'Idle sleep (hours)', 'settings.fieldIdleHoursHint': 'Automatically closes the remote connection once a session has no new activity for this long. Running or waiting sessions never count. Default 48; the value must be greater than 0 and at most 8760.', 'settings.fieldAutoShare': 'Auto-share new sessions', 'settings.fieldAutoShareHint': 'Share every newly created session with paired devices.', 'settings.invalidName': 'Enter 1–40 characters', 'settings.invalidHours': 'Enter a number greater than 0 and at most 8760', 'settings.remoteNotice': 'Pairing and device management are only available on the server itself', 'settings.savedInvalid': 'The saved value is invalid; the value now in effect comes from {source}', 'settings.sourceEnvBadge': 'Locked by an environment variable', 'settings.sourceFileBadge': 'From the legacy lan-gate.config.json', 'settings.sourceEnv': 'an environment variable', 'settings.sourceFile': 'the legacy lan-gate.config.json', 'settings.sourceDefault': 'the default value', 'settings.statusUnavailable': 'Could not read the plugin status (HTTP {code})', 'settings.statusUnknown': 'Could not read the plugin status', 'settings.refreshFailed': 'The status refresh failed — showing the last successful data', 'settings.resetPreview': 'Saving reverts to the next layer\u2019s value', 'settings.client.connectTitle': 'Connect to the server', 'settings.client.serverUrl': 'Server address', 'settings.client.serverUrlHint': 'The server\u2019s gateway address, e.g. http://192.168.1.10:3088 or https://dsh.example.com.', // The label above is the shared 设备名称 field in the role card (T57); this // is only the fallback name a pairing registers under when that field is // empty. 'settings.client.deviceNameDefault': 'Desktop client', // T60: the pairing button's disabled reason while the device-name draft is invalid. 'settings.client.fixDeviceName': 'Fix the device name first', 'settings.client.pairingCode': 'Pairing code', 'settings.client.pairingCodeHint': 'Generate a desktop-client pairing code on the server\u2019s settings page and enter it here (8 characters; auto-uppercased and filters out 0/O/1/I/L and symbols).', 'settings.client.pair': 'Pair', 'settings.client.pairing': 'Pairing…', 'settings.client.failInvalid': 'The server address is not valid', 'settings.client.failInsecureHttp': 'Public addresses require https; http is only allowed for LAN or Tailscale addresses', 'settings.client.failBadCode': 'The pairing code is wrong or expired', 'settings.client.failLocked': 'Too many attempts — try again in {minutes} minutes', 'settings.client.failUnreachable': 'Could not reach the server', 'settings.client.failRoleMismatch': 'This pairing code is not valid for desktop clients', 'settings.client.failUnexpected': 'The server gave an unrecognized answer — make sure it runs dsh-zen-remote 2.0.0', 'settings.client.failWrite': 'Pairing succeeded, but saving the token locally failed: the settings store is unavailable or read-only', 'settings.client.statusTitle': 'Connection', 'settings.client.statusUnpaired': 'Not paired', 'settings.client.statusConnected': 'Connected to {serverUrl}', 'settings.client.statusRevoked': 'The pairing token was revoked. Pair this device again.', 'settings.client.statusUnreachable': 'The server is currently unreachable', 'settings.client.statusUnexpected': 'The server does not support remote sessions (needs dsh-zen-remote 2.0.0)', 'settings.client.statusInvalidUrl': 'The server address is invalid or insecure — pair again', 'settings.client.statusRefresh': 'Refresh', 'settings.client.statusRefreshing': 'Refreshing…', 'settings.client.tokenSet': 'Device token saved', 'settings.client.unpair': 'Unpair', 'settings.client.unpairBusy': 'Unpairing…', 'settings.client.unpairConfirm': 'This machine will forget the saved server token (the server\u2019s device record is untouched). Continue?', 'settings.client.unpairDone': 'The token was forgotten on this machine; to invalidate it fully, revoke the device in the server\u2019s device list', 'shareRemoteOn': 'Enable remote', 'shareRemoteOff': 'Disable remote', 'shareRemoteStateOff': 'Remote access off', // T67: the info-card row's on-state word and label. 'shareRemoteStateOn': 'Remote access on', 'infoRemoteAccess': 'Remote access', 'shareRemoteBusy': 'Running — not counting down', 'shareRemoteRemainingHours': 'Idle time remaining: {count} h', 'shareRemoteRemainingMinutes': 'Idle time remaining: {count} min', 'shareRemoteConfirmOn': 'Once enabled, paired desktop apps will be able to view and operate this session. Enable?', 'shareRemoteConfirmOff': 'Desktop apps will no longer be able to access this session. Disable?', 'shareRemoteFailSubagent': 'Enable remote failed: subagent sessions cannot be shared alone', 'shareRemoteFailEmpty': 'Enable remote failed: the session has no content yet', 'shareRemoteFailGeneric': 'The action failed — try again later', // --- T43 diagnostics --- 'settings.client.reconnect': 'Reconnect now', 'settings.client.reconnectBusy': 'Reconnecting…', 'settings.client.statusConnectedName': 'Connected to \u201c{serverName}\u201d', 'settings.client.statusOfflineRetry': 'Offline — retrying in {seconds} s', 'settings.client.statusOfflineRetrySoon': 'Offline — retrying now…', 'settings.client.statusIncompatible': 'Relay protocol mismatch with the server — update dsh-zen-remote on both ends', 'settings.client.diagTitle': 'Diagnostics', 'settings.client.diagLastError': 'Last error code: {code}', 'settings.client.diagInterceptInstalled': 'Request interceptor installed', 'settings.client.diagInterceptMissing': 'Request interceptor not installed', 'settings.client.diagInterceptDisabled': 'Remote features disabled: DSH internals differ from the expected shape', 'settings.client.diagRecentFailures': 'Recent remote call failures', 'settings.client.diagCompatGroups': 'Groups with fingerprint differences: {groups}', 'settings.client.diagCompatCalls': 'Recent incompatible calls', // --- RD-3: the remote drop guard's diagnostics line (browser-side // counters, read at render time) --- 'settings.client.diagRemoteDrop': 'Remote drop guard', 'settings.client.diagRemoteDropOk': 'Installed · intercepted {intercepted} · redispatched {redispatched} · folders {blocked} · passthrough {passthrough} · rewrap failed {failed}', 'settings.client.diagRemoteDropOff': 'Not installed ({reason})', // --- RD-6: the upload-redirect (fetch-route intercept) diagnostics row --- 'settings.client.diagUploadRedirect': 'Upload redirect', 'settings.client.diagUploadRedirectOk': 'Installed · upload wrapped', 'settings.client.diagUploadRedirectRefused': 'Refused: {reason}', 'settings.client.diagUploadRedirectPending': 'Service inject never fired · connection {connection} · fileUploads {fileUploads}', // --- PB-5 plugin bridge: host consent section + sub-client diagnostics --- 'settings.bridge.title': 'Plugin bridge', 'settings.bridge.empty': 'No plugin has registered a bridge yet', 'settings.bridge.loading': 'Loading the bridge registrations…', 'settings.bridge.loadFailed': 'The bridge listing failed to load (an older server, or the page opened through the gateway)', 'settings.bridge.sessionOnly': 'Forwards with shared sessions', 'settings.bridge.consentToggle': 'Allow forwarding whole-machine data', 'settings.bridge.consentHint': 'When on, paired desktop apps can read this plugin\u2019s whole-machine data in remote sessions.', 'settings.bridge.stateBridged': 'Bridged', 'settings.bridge.stateNotOnServer': 'Not installed on the server', 'settings.bridge.stateVersionMismatch': 'Version differs (server {version})', 'settings.bridge.stateDeclarationMismatch': 'Declaration mismatch', 'settings.bridge.stateConsentOff': 'Server owner has not allowed whole-machine data', 'settings.bridge.stateOffline': 'Relay offline', 'settings.bridge.stateServerTooOld': 'Server zen-remote is too old', 'settings.bridge.interceptOff': 'Local rerouting not enabled: {reason}', // --- T34 remote-status icon, composer banner, unshare --- 'remoteStatusOnline': 'Remote session · connected', 'remoteStatusOffline': 'Server offline — reconnecting', 'remoteStatusMismatch': 'Version differs from the server — some features may not work', 'remoteStatusRevoked': 'The pairing token was revoked — pair again in Settings', 'remoteStatusUnpaired': 'Not paired', 'remoteBannerOffline': 'Server offline — this remote session is read-only until the connection recovers', 'remoteBannerRevoked': 'The pairing token was revoked — pair again in Settings', 'remoteBannerUnpaired': 'Not paired', 'remoteBannerClosedIdle': 'Remote closed: idle past the configured time, the session went to sleep', 'remoteBannerClosedManual': 'Remote closed: the server withdrew this session\u2019s remote access', 'remoteBannerClosedClient': 'Remote closed: remote access was turned off on this machine', 'remoteStatusUnshareConfirm': 'Closing the remote removes this session from this machine\u2019s remote group; the session on the server is untouched. Close it?', 'remoteStatusOfflineClick': 'The server is offline — nothing to do', 'remoteStatusUnshareFail': 'Closing the remote failed — try again later', 'remoteStatusUnshareFailCode': 'Closing the remote failed ({code}) — try again later', 'remoteBridgeUnbridgedNote': 'better-sidebar is not bridged for this remote session (the server lacks the same version or has not allowed it) — treat files and changes as session messages only', // Remote group title suffixes (the background merger cannot know the UI // language and always uses the Chinese forms); the English equivalents // live here for UI surfaces that restate the same status. 'remoteGroupOffline': ' (offline)', 'remoteGroupRevoked': ' (token revoked)', 'remoteGroupUnpaired': ' (unpaired)', 'remoteGroupMismatch': ' (version mismatch)', // --- RD-2: the short toast when a folder drop into a remote session is blocked --- 'remoteDropFolderBlocked': 'Folders cannot be dropped into a remote session yet', // 2.2.6: remote-session artifact download (deliverable cards / document // preview header). 'downloadToLocal': 'Download to this computer', 'downloadBusy': 'Downloading…', 'downloadFailed': 'Download failed', // --- GW-10: remote access & device pairing wizard --- 'wizard.title': 'Remote Access & Device Pairing', 'wizard.subtitle': 'Set up this machine as a server (for phones and other computers) or as a client connected to a remote host', 'wizard.off': 'LAN mode / Not configured', 'wizard.step.pick': 'Role & Access', 'wizard.step.configure': 'Connection Settings', 'wizard.step.verify': 'Verify & Pair', 'wizard.role.sectionTitle': 'Machine Role', 'wizard.role.host': 'Server (Host)', 'wizard.role.hostDesc': 'Runs main sessions and the gateway on this machine so phones or other DSH computers can connect', 'wizard.role.client': 'Desktop Client', 'wizard.role.clientDesc': 'Connects to another DSH server so shared remote sessions appear directly in this sidebar', 'wizard.role.clientPickNote': 'In Client mode, this machine connects to a remote server gateway over HTTPS or LAN / Tailscale. Click "Next" to enter the server address and pairing code.', 'wizard.ingressSectionTitle': 'Server Access Method', 'wizard.path.caddy': 'Managed Caddy (Recommended)', 'wizard.path.caddyDesc': 'Best when you have a public IP. Downloads Caddy and issues TLS certificates via Cloudflare DNS automatically', 'wizard.path.external': 'Existing Reverse Proxy', 'wizard.path.externalDesc': 'Already running Nginx, Caddy, or Lucky? Copy a ready-made proxy rule into your existing setup', 'wizard.path.cloudflared': 'Cloudflare Tunnel', 'wizard.path.cloudflaredDesc': 'No public IP or router port forwarding needed. Connects directly through a Cloudflare tunnel', 'wizard.path.lan': 'LAN / Tailscale Direct', 'wizard.path.lanDesc': 'Connect phones and computers on the same LAN or Tailscale network without a domain or TLS certificate', 'wizard.next': 'Next', 'wizard.back': 'Back', 'wizard.hostName': 'Server Display Name', 'wizard.hostNamePlaceholder': 'e.g. mac-mini', 'wizard.hostNameHint': 'Name shown in the sidebar of connected computers and phones (leave blank for default)', 'wizard.autoShare': 'Automatically share new sessions with paired desktop clients', 'wizard.lanUrl': 'LAN / Tailscale URL (optional)', 'wizard.lanUrlPlaceholder': 'http://192.168.1.10:3088', 'wizard.lanUrlHint': 'Enter this machine\u2019s LAN or Tailscale URL (e.g. http://192.168.1.10:3088) to generate a phone QR code and copyable client address in the next step', 'wizard.domain': 'Domain', 'wizard.domainHint': 'Full domain name, e.g. dsh.example.com (without https:// or path)', 'wizard.httpsPort': 'HTTPS Port', 'wizard.cfToken': 'Cloudflare API Token', 'wizard.cfTokenHint': 'Used for certificate issuance or tunnel setup. Stored locally (0600) and never written to config files', 'wizard.cfTokenHowTo': 'How to create an API token', 'wizard.serverUrl': 'Public HTTPS URL', 'wizard.serverUrlHint': 'Root HTTPS URL, e.g. https://dsh.example.com (subdirectories are not supported)', 'wizard.proxySnippet': 'View Nginx / Caddy / Lucky config snippets', 'wizard.badDomain': 'Invalid domain format (e.g. dsh.example.com)', 'wizard.badPort': 'Port must be an integer between 1 and 65535', 'wizard.missingToken': 'Enter your Cloudflare API token', 'wizard.badServerUrl': 'Enter a valid root URL (https:// for public, http:// for LAN, no path)', 'wizard.verify.gateway': 'Local gateway', 'wizard.verify.public': 'Access URL reachable', 'wizard.verify.pairing': 'Device paired', 'wizard.light.pass': 'Ready', 'wizard.light.pending': 'Waiting', 'wizard.light.fail': 'Failed', 'wizard.pairTarget.web': 'Pair Phone / Browser (QR)', 'wizard.pairTarget.desktop': 'Pair Another Computer (Desktop Client)', 'wizard.startVerify': 'Generate Pairing QR Code', 'wizard.reverify': 'Regenerate QR Code', 'wizard.pairingCode': 'Pairing code', 'wizard.pairingSeconds': 'Expires in {seconds}s', 'wizard.qrHint': 'Scan with your phone to open the pairing page, then enter the code above', 'wizard.verifyPass': 'Paired — device {deviceId} connected', 'wizard.verifyCookieInsecure': 'Paired, but the reverse proxy did not pass X-Forwarded-Proto: https. Add the header so secure cookies work, then verify again', 'wizard.verifyExpired': 'Pairing code expired — generate a new one below', 'wizard.verifyStale': 'Configuration changed — generate a new QR code', 'wizard.verifyPending': 'Scan the QR code on your phone and enter the pairing code…', 'wizard.verifyNotStarted': 'Click the button below to verify the access URL and generate a phone pairing QR code', 'wizard.desktop.addressLabel': 'Server Address (for client machine)', 'wizard.desktop.addressFallback': 'http://:{port}', 'wizard.desktop.generate': 'Generate Desktop Pairing Code', 'wizard.desktop.regenerate': 'Regenerate Code', 'wizard.desktop.copyInfo': 'Copy Address & Code', 'wizard.desktop.guide': 'On the other computer, open this plugin page, choose "Desktop Client" in Step 1, and enter the server address and 8-character code above in Step 2.', 'wizard.desktop.pairedTitle': 'Paired Desktop Clients ({count})', 'wizard.desktop.pairedEmpty': 'No desktop clients paired yet', 'wizard.client.deviceName': 'This Computer\u2019s Name', 'wizard.client.deviceNamePlaceholder': 'e.g. macbook-pro', 'wizard.client.deviceNameHint': 'Shown in the server\u2019s paired device list', 'wizard.client.serverUrl': 'Server Address', 'wizard.client.serverUrlPlaceholder': 'https://dsh.example.com or http://192.168.1.10:3088', 'wizard.client.serverUrlHint': 'Enter the server\u2019s public HTTPS URL or LAN / Tailscale http://:3088 address', 'wizard.client.pairingCode': '8-Character Desktop Pairing Code', 'wizard.client.pairingCodePlaceholder': 'Generated under "Pair Another Computer" in Step 3 on the server', 'wizard.client.pairingCodeHint': 'Enter the 8-character desktop client code generated on the server (auto-uppercased; 0/O/1/I/L and symbols are filtered out)', 'wizard.client.pairAndConnect': 'Pair & Connect', 'wizard.client.pairingBusy': 'Pairing & connecting…', 'wizard.client.skipToStatus': 'Already Paired — View Status', 'wizard.client.lightCredential': 'Pairing token', 'wizard.client.lightConnection': 'Server connection', 'wizard.client.lightSync': 'Session & plugin sync', 'wizard.client.reconfigure': 'Change Server / Re-pair', 'wizard.startFailed': 'Verification failed: {reason}', 'wizard.startFailedProbe': 'access URL could not reach this gateway ({detail})', 'wizard.startFailedRuntime': 'ingress service is not running — start it above first', 'wizard.startFailedGateway': 'local gateway did not respond', 'wizard.startFailedPair': 'failed to generate pairing code ({detail})', 'wizard.startFailedUrl': 'invalid public URL', 'wizard.remoteOnly': 'Security restriction: public access setup is only available directly on the host machine', 'wizard.notWired': 'This feature requires a newer server version', 'wizard.card.proxyTitle': 'Reverse Proxy Configuration', 'wizard.card.tokenTitle': 'Create a Cloudflare API Token', 'wizard.card.copy': 'Copy', 'wizard.card.copied': 'Copied', 'wizard.card.close': 'Close', 'wizard.card.tokenStep1': 'In the Cloudflare dashboard (dash.cloudflare.com), open "My Profile → API Tokens" (user token, cfut_) or "Manage Account → Account API tokens" (account token, cfat_)', 'wizard.card.tokenStep2': 'Select "Create Token" and choose the "Edit zone DNS" template', 'wizard.card.tokenStep3': 'Under Permissions, keep the default "Zone · DNS · Edit" permission', 'wizard.card.tokenStep4': 'Under "Zone Resources", select "Include · Specific zone · your domain"', 'wizard.card.tokenStep5': 'If using Cloudflare Tunnel, click "+ Add more" to add the tunnel, account settings, and zone read permissions listed below', 'wizard.card.tokenStep6': 'Select "Continue to summary", review the details, and select "Create Token"', 'wizard.card.tokenStep7': 'Copy the generated token secret (shown only once)', 'wizard.card.tokenStep8': 'Paste it below and click "Save Token"', 'wizard.card.tokenPerms': 'Required permissions', 'wizard.card.tokenPermDns': 'Zone · DNS · Edit', 'wizard.card.tokenPermDnsWhy': 'Required for DNS-01 certificate issuance and DNS records', 'wizard.card.tokenPermTunnel': 'Account · Cloudflare Tunnel · Edit', 'wizard.card.tokenPermTunnelWhy': 'Cloudflare Tunnel only', 'wizard.card.tokenPermAccount': 'Account · Account Settings · Read', 'wizard.card.tokenPermAccountWhy': 'Cloudflare Tunnel only (reads account ID)', 'wizard.card.tokenPermZoneRead': 'Zone · Zone · Read', 'wizard.card.tokenPermZoneReadWhy': 'Cloudflare Tunnel only (locates domain zone)', 'wizard.card.tokenPaste': 'Paste API token', 'wizard.card.tokenUse': 'Save Token', 'wizard.card.migrateTitle': 'Add Your Domain to Cloudflare', 'wizard.card.migrateStep1': 'Turn off DNSSEC at your domain registrar (if active) and ensure nameserver changes are unlocked', 'wizard.card.migrateStep2': 'In the Cloudflare dashboard, go to "Domains → Overview" and select "Onboard a domain"', 'wizard.card.migrateStep3': 'Enter your apex domain (e.g. example.com), scan DNS records, click Continue, and select the Free plan', 'wizard.card.migrateStep4': 'Review the scanned DNS records, continue, and copy the two assigned Cloudflare nameservers', 'wizard.card.migrateStep5': 'At your domain registrar, replace the existing nameservers with the two Cloudflare nameservers', 'wizard.card.migrateStep6': 'Once the domain status becomes "Active" on the Domains page, return here and click "Recheck Domain"', 'wizard.card.migrateRecheck': 'Recheck Domain', 'wizard.card.proxyCheck': 'Configured — Verify Now', 'wizard.card.portForwardTitle': 'Router Port Forwarding', 'wizard.card.portForwardStep1': 'Sign in to your router admin page (typically 192.168.1.1 or 192.168.0.1)', 'wizard.card.portForwardStep2': 'Open "Port Forwarding / Virtual Server / NAT"', 'wizard.card.portForwardStep3': 'Add a TCP rule: external port {port} → this machine\u2019s LAN IP on port {port}', 'wizard.card.portForwardStep4': 'Save the rule and test the public URL over mobile data (with Wi-Fi turned off)', 'wizard.portForwardEntry': 'Non-443 port: router port forwarding guide', 'wizard.migrateEntry': 'Domain not on Cloudflare yet?', 'wizard.ingress': 'Ingress service', 'wizard.caddy.start': 'Start Caddy', 'wizard.caddy.starting': 'Downloading & starting…', 'wizard.caddy.stop': 'Stop', 'wizard.caddy.running': 'Caddy running', 'wizard.caddy.stopped': 'Caddy stopped', 'wizard.caddy.neverStarted': 'Caddy not started', 'wizard.caddy.startOk': 'Caddy started', 'wizard.caddy.startFailed': 'Caddy failed to start: {reason}', 'wizard.caddy.failDownload': 'auto-download failed — install Caddy manually and retry', 'wizard.caddy.failValidate': 'generated config failed validation', 'wizard.caddy.failAlreadyRunning': 'already running', 'wizard.caddy.failMissingToken': 'save your Cloudflare API token in the previous step first', 'wizard.caddy.failNoDomain': 'save a valid domain in the previous step first', 'wizard.caddy.failBadConfig': 'invalid configuration: {detail}', 'wizard.caddy.failSpawn': 'failed to start Caddy process', 'wizard.token.saved': 'Saved locally', 'wizard.token.saveFailed': 'Failed to save token — please retry', 'wizard.tunnel.setup': 'Create & Start Tunnel', 'wizard.tunnel.stop': 'Stop', 'wizard.tunnel.running': 'Tunnel running', 'wizard.tunnel.stopped': 'Tunnel stopped', 'wizard.tunnel.neverStarted': 'Tunnel not started', 'wizard.tunnel.ok': 'Cloudflare tunnel is active and running', 'wizard.tunnel.conflict': 'A tunnel with this name already exists — select one to reuse:', 'wizard.tunnel.useExisting': 'Reuse tunnel', 'wizard.tunnel.zoneNotFound': 'Domain zone not found under this token — make sure the domain is active on this Cloudflare account', 'wizard.tunnel.dnsConflict': 'A CNAME record for this domain already points to {detail} — remove it in Cloudflare DNS first', 'wizard.tunnel.auth': 'Cloudflare authentication failed — check token permissions', 'wizard.tunnel.network': 'Could not reach Cloudflare API', 'wizard.tunnel.api': 'Cloudflare API error: {detail}', 'wizard.tunnel.spawnFailed': 'cloudflared failed to start: {detail}', 'wizard.tunnel.noToken': 'Save your Cloudflare API token in the previous step first', 'wizard.tunnel.badDomain': 'Invalid domain format', 'wizard.tunnel.checking': 'Configuring tunnel & starting (downloading cloudflared on first run)…', 'wizard.check.okOnCf': 'Domain is active on Cloudflare', 'wizard.check.okNotOnCf': 'Domain not found on Cloudflare — add it to Cloudflare first', 'wizard.check.failed': 'Domain check failed: {reason}', 'wizard.overview.roleLabel': 'Current Role', 'wizard.overview.gatewayLabel': 'Local Gateway', 'wizard.overview.gatewayReady': 'Running · port {port}', 'wizard.overview.gatewayDown': 'Unreachable', 'wizard.overview.ingressLabel': 'Access Method & URL', 'wizard.overview.devicesLabel': 'Paired Devices', 'wizard.overview.devicesSummary': 'Phone/Web {web} · Desktop {desktop}', 'wizard.overview.devicesNone': 'No paired devices yet', 'wizard.overview.clientCredLabel': 'Local Credential', 'wizard.overview.clientConnLabel': 'Server Connection', 'wizard.overview.clientServerLabel': 'Remote Server URL', 'wizard.overview.startSetup': 'Start Setup Wizard', 'wizard.overview.reconfigure': 'Reconfigure Wizard', 'wizard.overview.pairPhone': 'Pair Phone (QR)', 'wizard.overview.pairDesktop': 'Pair Desktop Client', 'wizard.overview.clientDetail': 'Connection & Pairing Wizard', 'wizard.overview.emptyIntro': 'Remote access is not configured yet. Click the button on the right to launch the step-by-step wizard for server access or desktop client pairing.', 'wizard.modal.title': 'Remote Access & Pairing Wizard', 'wizard.modal.stepTag': 'Step {num}', 'wizard.modal.step1Desc': 'Choose whether this machine acts as the server or a desktop client, and select how devices connect', 'wizard.modal.step2Desc': 'Fill in the connection URL, domain, or pairing code for your selected plan', 'wizard.modal.step3Desc': 'Verify connectivity and pair your phone or desktop client', 'wizard.modal.selectedPlan': 'Selected plan: {plan}', 'wizard.modal.cancel': 'Cancel', 'wizard.modal.saveAndNext': 'Save & Verify', 'wizard.modal.finish': 'Done', 'wizard.light.probing': 'Checking…', 'wizard.overview.manageDevices': 'Manage Devices', 'wizard.devicesModal.title': 'Paired Devices', 'wizard.devicesModal.subtitle': 'View and manage paired phone/web and desktop client devices — rename, switch layout, or revoke access', 'wizard.devicesModal.retest': 'Retest Connectivity', } /** Key domain of the `mobileNav` namespace (zh is the source of truth). */ export type MobileNavKey = keyof typeof zh