dsh-chat-translate
Verified@lynn123411/dsh-chat-translate · v3.4.0 · MIT · Web UI
Assistant reply-body translation for the DeepSeek Harness Web UI (OpenAI-compatible channel)
Install
dsh plugin add @lynn123411/dsh-chat-translate Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Readme
@lynn123411/dsh-chat-translate
DeepSeek Harness Web 界面的助手回答正文翻译插件。它接管助手行的渲染:正文块不论源语言,一律送翻译模型加工成自然简体中文(如 I traced the failing path to a stale lock file. → 中文;模型写出的生硬机器腔中文同样送一遍润色——弱模型的中文恰恰最需要加工),译文按原 markdown 结构重新渲染。只翻正文:Think 卡的思考链、工具调用行、用户消息、代码块、空白块不动。正文的排版与宿主原生完全一致,左缘不画任何标记。切换译文/原文在贴着正文左缘的那条 6px 透明窄带上(鼠标移上去变手型,点一下切双语,再点切回来),翻译失败时那一段保持原文、左缘只留一个小 ↻(悬停报通道细节,点它整行重译,等待期间原地转圈);正文整块不响应点击——选中文字、拖选复制都不会误触。不污染会话上下文。开关有两个入口:输入框下方那一行的「译」胶囊与本插件配置页的总开关,同一个状态两处同步。配置详见 docs/配置.md。
特性
- 接管助手行渲染:经 keyed slot
conversation.chat.node(keyassistant-step,priority -1)替换宿主的助手行渲染器。正文块从数据层拿原始 markdown(AssistantBlock.text),译文同样以 markdown 交给宿主公开的基线组件MarkdownText(micromark + GFM + KaTeX)重渲染——表格、列表、加粗、行内代码、公式的结构由官方渲染器保证,插件不自拼 markup。接管渲染器抛错时按框架退位规则退出该 cell,宿主原渲染器自动回位。 - 一律送译,不判源语言:正文的每一块都进模型,包括整段中文、纯数字、纯标点的块;只有 trim 后为空的块不送译、永不标记(它没送过模型,重试也永远不会成,标记只会留下消不掉的东西)。提示词要求模型把每一段都改写成自然、地道的简体中文——意义、语气、专名、数字与术语不动,不增不删;同时要求 markdown 记号原样保留。模型判断某段已经最好而返回一模一样的文字时,同样算翻译过、同样可切换(标记传达的是「这段过了模型」)。
- 除正文外与宿主逐分支等价:Think 折叠行(含工作细节策略下的摘要预览、Turn-process 折叠隐藏与页内搜索揭示)、连续图片组交回宿主渲染、工具调用行由宿主独立渲染、未知内容块落 JSON 展示、中断前缀行尾带「已停止」——这些 chrome 文案复用宿主
chat词典,两侧逐字一致。 - 正文排版原生,左缘不画任何东西:正文没有竖线、没有缩进——文字位置、列表与引用的缩进与宿主默认逐字一致。插件自己的两个可点物都落在正文左缘之外:成功块是一条 6px 宽的透明窄带(不占正文一个像素),失败块是一个 ↻ 按钮。窄带看不见,鼠标移上去变手型;它没有焦点框,键盘可以 Tab 到它但没有可见标记。可翻译与不可翻译时排版完全相同。
- 切换译文/原文:有译文的块,左缘那条窄带点一下切原文、再点一下切回译文。切回原文后界面上不会有任何提示说「这里其实有一份译文」——那段仍然能再切回来,只是标记不变(标记只说「这段过了模型」)。
- 落定才翻、进视口才翻:回答流式期间整行按原文渲染;
data-streaming落定且行进入视口(150px 缓冲)后,整行正文按估算 token 预算切批、逐批顺序请求——先回的段先出中文,按阅读顺序逐段呈现。历史会话因此只在真的被读到时才花请求。这是每行的首跑,也是唯一自动发生的请求。首跑期间界面不显示任何提示,中文回来直接替换原文。 - 失败只有一种:通道伤:块级失败不进缓存、保持原文,左缘留下一个 ↻ 按钮(
dsh-ct-retry,一直看得见,不靠悬停显形),它是失败段唯一的点击目标——失败段不放窄带,一段落只对应一个动作。鼠标停在 ↻ 上出气泡报出通道细节(超时、断流、空返回),读屏也读得到。点它整行重译:已成功的块保持显示不打扰,失败的块原地转圈(同一个按钮元素,不重挂载,键盘焦点不掉),转圈期间不能重复点。译文的结构漂移不再是失败理由(见下条)。通道失败不自动重试:一行首跑一次,落定即终态,救活只由 ↻ 发起。失败仍在控制台留一条警告。 - 按行幂等的翻译池:客户端按会话锚点键登记整行结果,同文本重复渲染不重发请求;行内容换代则整行重译,迟到的旧代结果作废。
- 结构重装配,形状问题只修不拒:宿主先把块按 markdown 结构切段——代码围栏与纯空白段逐字保留、永不送模型——散文段再按输入上限切片(单段超限按空行、单行、句末切开)、相邻片段打包成一个请求(输入上限 4096 估算 token、输出上限 8192 token)。回来的译文过形状修复(
repairShape):按段落块对齐,块内结构行(记号类别、表格竖线数、链接个数、缩进代码缩进)逐一对齐并把行首前缀修回原文同款(##→###、-→*、序号、引用深度、列表缩进的漂移就此消失),散文行自由重排(软换行渲染无感),空行布局一律取原文,[文字](URL)的 URL 按出现序逐字拼回。修不齐的片段自动重掷一次;仍不齐就照收模型的译文——原文一键可回,可读的译文优先于失败标记。反引号、行内代码内容一律不拦:是样式不是骨架。 - 单通道:AI 翻译(OpenAI 兼容协议):对接任意 OpenAI 兼容的
chat/completions服务(OpenAI、DeepSeek、通义、Ollama、本地 vLLM 等)。Key / Base URL / 模型三者齐备才翻译,缺任何一项保持原文,不做降级兜底。API Key 经 DSH 凭据服务读写~/.dsh/.credentials.yaml的TRANSLATE_API_KEY;Base URL 与模型在本插件的配置页配置。 - 串行与超时:同时最多一个在途请求,单次超时
aiTimeoutMs(默认 600000 毫秒,范围 500–900000)——每行首跑与每次手点都等到真实结果,嫌等就把超时调小。磁盘缓存池~/.dsh/dsh-chat-translate/cache.json(7 天 TTL、1000 条 LRU)按提示词修订号整体作废:文档里登记rev,换提示词语义后旧译文不会串代。 - 跟随宿主显示设置:Think 行的折叠摘要预览跟随「工作细节」模式(读
ui-chat配置的transcriptView,含 legacy 取值映射);设置缺席时按 standard。 - DSH 原生配置接入:配置就是本插件在 profile 里的插件配置——配置页经
ctx.configForms读写条目dsh-chat-translate的config,用户层落在当前 profile 的 patch;无任何自研配置文件,译文从不写回会话上下文。 - 配置页挂在宿主「插件」页:配置卡片注册进
plugins.bundle.config(key 为包名@lynn123411/dsh-chat-translate),路径是「插件」→本插件详情页 —— 配置直接铺在描述之下、行列表之上。页面由宿主画标题、图标与面包屑,卡片提供总开关、API Key、Base URL、模型、单次请求超时与「测试 AI 通道」;设置页里不再有任何本插件的入口。做法与约束见仓库docs/rules/plugin-config-page.md。
校验
cd plugins/dsh-chat-translate && pnpm check
check 串起类型检查、构建、七份测试与产物门禁(lib/ 不被索引跟踪)。测试覆盖:行渲染计划与宿主 AssistantMarkdown 的分支等价、翻译呈现单点(成功/失败两种标记、失败原因与补跑在途)、翻译池(同代幂等、换代重发、逐批落定、手动补跑、LRU)、配置面策略跟随,以及真 react + jsdom 的渲染自检——窄带切换、拖选与点正文不误触、失败段 ↻ 是唯一可点物、补跑在途原地转圈且不重挂载(键盘焦点不掉)、服务端败因进 ↻ 自己的读屏标签。服务端半边另有结构重装配、缓存与通道契约的回归。
安装
dsh plugin --profile web add @lynn123411/dsh-chat-translate