dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DeepSeek Harness Web UI in Traditional Chinese (Taiwan) - converts the whole rendered interface, including third-party plugin copy, at the DOM layer.
繁體中文 | English
Renders the entire DeepSeek Harness (DSH) Web UI in Traditional Chinese (Taiwan) — DSH's own copy, third-party plugin copy, and text that later DSH versions add — by converting the DOM, not by shipping a language pack.
Settings -> General -> Language: 中文 (Simplified) <- the app's own locale
What you actually see: 繁體中文(台灣) <- converted on screen
Because it works at the render layer, it does not have the failure mode that dictionary-based language packs have: uncovered copy falls back to Simplified Chinese and the UI looks half-translated.
DSH ships exactly two locales: zh (Simplified) and en. Using DSH in Taiwan
breaks in three places at once:
This plugin attacks the shared root cause: whatever produced the text, it is converted on screen.
Goals
| G1 | The whole page in Traditional Chinese: DSH itself, third-party plugins, and dynamic content that appears later |
| G2 | Decoupled from the DSH version — a DSH upgrade must not break it |
| G3 | Touches no DSH internals: no dictionary registration, no LocaleRuntime patching, no @deepseek-ai/* peer range — so DSH's compatibility gate can never skip it, and it coexists with other locale plugins |
| G4 | A clear safety boundary: code, editors and anything you type are never altered |
| G5 | Reversible, auditable, tunable (a runtime switch, an override table, a skip marker) |
Non-goals
This is the reason the project exists, so here is the honest version. All figures were checked on 2026-10-13 from each package's npm manifest or repo README.
| Option | Mechanism | Covers third-party plugins | Relationship with DSH 0.2.0-rc.2 |
|---|---|---|---|
@huanlin/dsh-plugin-better-locale 0.4.3 | registers dictionaries (39 namespaces) | no | peer says ^0.1.5-rc.2 (excludes 0.2.x) → needs a manual exact-version exemption to load |
@mimateinn/dsh-i18n 0.2.6 | dictionaries + Simplified→Traditional character fallback | yes | peer says <0.2.0-0 → blocked by the compatibility gate without an exemption |
dsh-locale-zh-tw (npm, 0.1.1) | patches LocaleRuntime internals | yes | documents itself against the dsh-client-locale@0.1.1-rc.2 shape; degrades silently on mismatch |
dsh-multi-lang-ui 0.1.1 | dictionaries + char table + DOM fallback | yes | peer has no upper bound, passes the gate — mechanically the closest to this project |
iceice666/dsh-locale-zh-tw | dictionaries only (50 ns / 1691 strings) | no (by design, per its README) | — |
| dsh-zh-tw-ui (this project) | pure DOM conversion | yes | no peer dependencies, touches no DSH API |
Each existing approach has a structural weakness:
pluginManager, permission, settings.shell, settings.webSearch,
agent-team, voice-input, schedule.manager, …). Worse, its fallback chain
is zh-TW → zh → en, so the gaps render in Simplified, not English — which
is exactly why a language pack can look like "it installed but nothing
happened".dsh-locale-zh-tw) — tightly coupled to DSH
internals and designed to degrade silently: after a DSH update it can simply
stop doing anything, without an error.compatibility.json
exemption list is the fingerprint of working around that).This project's trade-off: touch no DSH API, work only on the DOM. The price is that it is a display-layer conversion; what you get is version independence, coverage of third-party plugins, and failures you can actually see. The full consequences are listed under Limitations.
Note:
dsh-multi-lang-uioverlaps this project functionally and is a valid alternative. This project deliberately stays smaller and single-purpose: DOM conversion only — one job, no dictionary to keep in sync, no@deepseek-ai/*dependency of any kind.
┌─ DSH's own copy (Simplified)
screen text ────┼─ third-party plugin copy (their own Simplified)
└─ content that appears later (streaming, dynamic panels)
│
▼
DOM text node → OpenCC cn→twp (Taiwan wording) → override table → write back
▲
└─ MutationObserver: re-run on added nodes / changed text
cn → twp (Simplified → Traditional with Taiwan vocabulary):
设置→設定, 网络→網路, 软件→軟體, 文件夹→資料夾, 服务器→伺服器, 内存→記憶體,
屏幕→螢幕, 鼠标→滑鼠, 保存→儲存, 搜索→搜尋, 插件→外掛.DEFAULT_OVERRIDES in src/convert.mjs) fixes wording
OpenCC misses or renders in a non-Taiwan way: 只讀→唯讀, 超時→逾時, 反饋→回饋,
獲取→取得, 許可權→權限.<html lang> is set to zh-Hant-TW so the browser picks Taiwan glyph forms.| Target | Behaviour |
|---|---|
<code> <pre> <kbd> <samp> <var>, CodeMirror / Monaco / xterm / ace / syntax highlighting | subtree and attributes untouched |
<input> <textarea> <select> <option> | only placeholder / title; what you type or pick is untouched |
contenteditable (including rich-text composers) | untouched |
<svg> <math>, <script> <style> <canvas> <iframe> <video> <audio> | untouched |
anything marked data-zh-tw-skip or translate="no" | untouched |
| strings without Han characters (English, kana, digits, code) | passed through |
In other words: code is never rewritten, and copying code behaves exactly as before.
git clone https://github.com/linmino/dsh-zh-tw-ui.git
cd dsh-zh-tw-ui
node install.mjs --profile desktop # 'desktop' is the default; use --profile web for the web profile
install.mjs does exactly four things, all reversible:
package.json and cordis.patch.yml up as *.zh-tw-ui.bak;dsh-zh-tw-ui to dsh.profile.bundles;locale row's preference to zh (Simplified underneath, Traditional
on screen — this keeps the UI Chinese even if you later remove another language
pack, instead of falling back to English with nothing to convert);<profile>/node_modules/dsh-zh-tw-ui → this directory.It runs no package manager, so nothing else in your profile is re-resolved.
Then restart DeepSeek Harness — a new bundle is composed only at boot; refreshing the page is not enough.
The name dsh-zh-tw-ui is currently free on npm. Once published:
dsh plugin --profile desktop add dsh-zh-tw-ui
node uninstall.mjs --profile desktop
Removes the link, drops the bundle entry and restores both backups. Your plugin sources are never deleted. Restart DSH afterwards.
The plugin has no UI and needs no configuration. To tune it, use the DevTools console of the main window:
__dshZhTw.status() // { version, enabled, textNodes, attributes, skippedSubtrees, passes }
__dshZhTw.off() // stop converting (text already converted stays)
__dshZhTw.on() // resume
__dshZhTw.toggle()
__dshZhTw.refresh() // full re-scan
__dshZhTw.convert('设置') // test one string -> '設定'
The switch is persisted in localStorage['dsh-zh-tw-ui:enabled'].
Change wording: edit DEFAULT_OVERRIDES in src/convert.mjs (a list of
[simplified, traditional] pairs), run node build.mjs, reload the page.
Exclude a region: add data-zh-tw-skip to the element (handy for
side-by-side references or screenshots).
An honest list. All of these follow from the display-layer design:
data-zh-tw-skip.node_modules, the link may disappear
(the plugin stops working; DSH itself is unaffected). Re-run
node install.mjs.npm install
npm test
14 tests covering:
code/pre/textarea/input/contenteditable/CodeMirror/Monaco/
svg/data-zh-tw-skip/translate="no", and form controls converting only their
placeholder;title/placeholder/aria-label/alt);off() stops, on() catches up on what it missed;lib/client.js loaded through DSH's real
window.__ModuleLoader__.load(...) protocol, applied to a DOM, including the
runtime switch and persistence;apply() never throws when there is no DOM (it can never break the client).build.mjs generates lib/client.js from src/ (with a syntax check)
install.mjs installs into a profile (backup, bundles, locale, link)
uninstall.mjs reverts
lib/index.js host half: a no-op
lib/client.js the generated browser bundle (the only file DSH loads)
src/apply.mjs cordis client plugin body (switch, runtime API)
src/convert.mjs conversion engine + Taiwan override table
src/dom-convert.mjs DOM walk, skip rules, MutationObserver
src/vendor/ vendored opencc-js (byte-identical, licenses included)
cordis.patch.yml inserts the plugin row into DSH's patch layer
test/run.mjs the test suite
MIT for this project (see LICENSE). It embeds opencc-js (MIT) and the OpenCC
dictionaries (Apache-2.0) — see THIRD-PARTY-NOTICES.md
for the file hashes and full license texts.