dsh-bilingual-helper:在每條對話下面放一個 EN 翻譯按鈕

前言

DSH 的會話界面裏,中文提問和中文回答都在同一屏顯示。做雙語閱讀練習的人常見的做法是把整段文本複製出去再翻譯,或者開另一個翻譯窗口逐句對照,過程中原文容易被覆蓋、也容易對錯行。實際翻譯時還有一個問題:整條消息一次性送翻譯,長回答不僅慢,還會把代碼塊一起改掉。

下面介紹的插件處理的正是這個問題。它由 SCUklr 維護,在社區目錄的「聯網工具」分類下,包名 @local/dsh-bilingual-helper,倉庫地址見文末。它的形態是 DSH bundle plugin:在每個提問和每個回答下方各加一個 EN 按鈕,點一下就在原消息下方展開該條消息的完整英文翻譯,再點一次收起,原文不動。

它解決什麼問題

定位一句話:給 DSH 會話加一層「按需展開」的中英對照面板,翻譯只針對當前這條消息,而不是整個會話或整篇導出。

目前已覈實的行爲:

  • 中文提問下方、中文回答下方出現 EN 英文翻譯 按鈕;已經是英文的消息不出現按鈕(沒有可翻譯內容)。
  • 每行獨立展開、獨立緩存,摺疊後再展開是瞬時的,不會重複請求。
  • 代碼塊(``` 圍起來的部分)原樣保留、不送翻譯,只翻正文。
  • 長消息自動切塊,逐塊翻譯後再按原文順序拼回。
  • 深色 / 淺色主題自動適配,只用主題 token。
  • 網絡或服務錯誤時在面板內以紅色文案顯示,按鈕變爲「重試」,不會靜默失敗。

翻譯從哪來

點擊按鈕時,該消息正文發給 DSH 內置的翻譯服務(ctx.translator),返回純文本譯文。默認走 deepseek-official 付費路由:deepseek-flash 模型、thinking 關閉、單條文本、固定直譯提示詞(無對話歷史、無工具),按輸入 / 輸出 token 計費。README 給出的量級是約 0.5–1.5 分 / 條,具體見 DeepSeek 定價頁。

這個路由有兩個約束:

  1. 必須攜帶當前會話 id。瀏覽器半邊從 Chat 節點的標準 props 裏讀取 sessionId,隨請求一起發給 Host 半邊。
  2. 會話必須處於活躍狀態。歷史或已歸檔會話裏點擊會失敗,面板顯示 TRANSLATION_SESSION_INACTIVE 之類的錯誤,需要回到活躍會話再點。

隱私方面:點擊按鈕等於把該消息正文發送給 DeepSeek;不點擊就不發送任何內容。

如果想回到不花錢的路線,把 cordis.patch.yml(以及 profile 裏 cordis.patch.yml 的覆蓋行)中兩處 provider: deepseek-official 改成 bing 或 google。匿名接口不消耗 token、不需要會話 id,但譯文質量是 NMT 直譯。

啓用與使用

插件的目錄目前在 ~/Agent&AI_dev/dsh-plugins/en-translation,profile 只保存一個 link: 依賴和一條 node_modules 軟鏈。README 未給出獨立的安裝命令,安裝路徑是 profile 裏的 link: 依賴註冊,包名爲 @local/dsh-bilingual-helper。

啓用步驟:

  1. 在 Settings → Plugins 中確認 @local/dsh-bilingual-helper 已列出並啓用。
  2. 無需重啓,裝好後瀏覽器頁面會自動加載。目錄在含 & 的路徑下(Agent&AI_dev),shell 裏操作記得加引號。
  3. 打開任意活躍會話,點提問或回答下方的 EN 英文翻譯;點「收起翻譯」摺疊;點「重試」重新請求。

配置項在 cordis.patch.yml 中本插件行的 config:

config:
  targetLanguage: en        # 目標語言,BCP 47,如 en、ja
  provider: deepseek-official  # 付費路由;也可改 bing / google 走匿名 NMT

換 provider 時兩處都要改(bundle 配置和 profile 覆蓋行),否則實際生效的可能仍是緩存的舊配置。

目錄結構與調用方式

倉庫很小,主要文件職責如下:

dsh-plugins/en-translation/
├── package.json        bundle 清單:dsh.bundle.patch + dsh.client(web, immediately)
├── cordis.patch.yml    插入兩行:translator(內置翻譯服務)+ 本插件
├── index.js            Host 半邊:在同源 Web 上註冊 /dsh-en-translation/* 路由
├── client.js           瀏覽器半邊:Chat 行定義 + 渲染器 + 按鈕 UI
├── locale/{zh,en}.json 插件面板裏的標題與說明
└── icon.svg            原創圖標

行從哪來:瀏覽器半邊註冊兩個 Conversation Definition(en-translation-question 匹配 user/message,en-translation-answer 匹配 assistant/message),各自發布 kind: "en-translation" 的 Chat Node,錨在該消息自己的 seq 上,因此行落在消息正下方。

橋接部分值得說幾句,因爲 bundle 的瀏覽器半邊不能直接調用 Host 服務,也沒有 host.call。Host 半邊改用 ctx.webServer 註冊同源 JSON 端點,瀏覽器只做 fetch:

GET  /dsh-en-translation/health  → 翻譯服務是否可用、可用 provider
POST /dsh-en-translation/translate  {text, sessionId?} → {ok, translation, chunks, elapsedMs}
POST /dsh-en-translation/debug    → 僅開發用,DEBUG=true 時把診斷寫進系統臨時目錄

譯文按會話持久化,同一會話內同一段文本重複展開不再請求;頁面內存裏另有一份緩存,最多 200 條。

已知限制

這些限制來自 README,先看再決定要不要開付費路由:

  • 付費路由比匿名 NMT 慢:實測 270 字約 1.5 s、800 字約 3 s、接近 3000 字的單塊約 10–20 s。超長回答會被切成多塊串行翻譯,前端總超時 90 s,極長消息可能失敗,面板會提示原因。
  • 付費路由綁定活躍會話,歷史 / 已歸檔會話裏點翻譯會失敗。
  • 切到付費路由後每條新消息都會消耗 token(同一會話內重複展開命中緩存則免費),會話日誌裏會新增 plugin:translator/request|result 記錄。
  • 機器翻譯會改寫 Markdown 排版與專有名詞;原文始終保留在上方,可對照閱讀。
  • 一條回覆如果分多個 assistant 消息(多步工具調用),中文的每一步都有自己的按鈕。
  • 翻譯結果不落盤、不跨頁面持久化,刷新頁面後需重新點一次。

搬遷與重裝

兩條來自 README 的注意點:

  1. 目錄移動後必須重新安裝並更新鏈接,profile 只保存一個 link: 依賴和一條 node_modules 軟鏈。
  2. dsh-client-modules 會把「Loader 行名 + 根目錄」對應的包元數據緩存到進程重啓爲止(sourceKey = baseUrl + '\0' + loaderName)。所以「刪掉同名包 → 原地改名或換路徑重裝」時,前端會靜默不加載,而 Host 半邊正常。解決辦法二選一:裝機時換一個新包名(當前做法是 @local/dsh-bilingual-helper),或者重啓 DSH 應用。原地改文件內容、路徑不變則不受影響。

適合誰

適合在 DSH 會話裏做中英對照閱讀、需要按句子覈對譯文、又不想離開聊天界面的人。插件以當前 DSH 進程的權限運行,並在點擊時把消息正文發送給翻譯服務方,安裝前應先讀一遍源碼和許可證(MIT,© 2026 SCUklr),再決定是否信任這條數據通路。

倉庫:https://github.com/SCUklr/dsh-bilingual-helper
目錄頁:https://www.skillhub.cn/plugins/SCUklr/dsh-bilingual-helper

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜