No description
Find a file
spearzificial 68a7fc608d fix: translate the API copy that actually renders
Bundle translation worked, but the UI still showed Chinese. The visible text
does not come from plugin bundles at all: plugin descriptors, model and
provider names, and settings descriptions reach the browser as JSON over /api.
Measured in the Plugins view, all 76 distinct Chinese characters came from
/api/pluginManager/listBundles, which the bundle seam cannot see.

Add a second seam on the typert gateway. It resolves its own dispatchRpc per
request, so overriding that instance method intercepts every /api call without
claiming the interceptor slot the gateway already owns.

Rewriting JSON is deliberately narrow. An allowlist covers the six endpoints
that return server-authored copy; everything else, notably /api/session/list,
carries the operator's own prompts and transcripts and is left alone.

Three shapes needed handling, each found by testing against the live server:

- Locale maps ({ zh, en }) resolve to the English sibling, because the author's
  own English beats a dictionary pass.
- Bilingual descriptors joined by " · " keep their English half, which covers
  every such descriptor without a dictionary entry.
- Keys are not always trustworthy: dshmarket publishes its bilingual string
  under `en` and a short English one under `zh`, and one plugin repeats the same
  string under both. A locale map is therefore detected by shape, and an English
  sibling is only used when it is itself free of Chinese.

Also harvest author-written { zh, en } pairs from plugin locale maps (331
entries) as the highest-precedence dictionary source, and extend the curated
supplement with the vocabulary that unlocks whole families at once: "免费" alone
covers about twenty model names.

Measured on a live server: 107 -> 0 visible Chinese characters across the home,
Plugins, and Automation tasks views, 0 residual Chinese across all six
allowlisted endpoints, no page errors, and both bundle combos still compile.
2026-10-15 23:44:17 +05:30
lib fix: translate the API copy that actually renders 2026-10-15 23:44:17 +05:30
scripts fix: translate the API copy that actually renders 2026-10-15 23:44:17 +05:30
src fix: translate the API copy that actually renders 2026-10-15 23:44:17 +05:30
.gitignore fix: translate plugin bundles at the transport layer 2026-10-15 22:53:20 +05:30
cordis.patch.yml chore: rename package to chinese2english 2026-10-11 18:33:25 +05:30
dshmarket_dict.json feat: implement direct plugin bundle patching with comprehensive 500+ DSH dictionary 2026-10-12 15:44:54 +05:30
LICENSE feat: initial commit of dsh-plugin-english 2026-10-11 16:57:03 +05:30
locale-pairs.json fix: translate the API copy that actually renders 2026-10-15 23:44:17 +05:30
package.json fix: translate plugin bundles at the transport layer 2026-10-15 22:53:20 +05:30
patch-plugins.py feat: implement direct plugin bundle patching with comprehensive 500+ DSH dictionary 2026-10-12 15:44:54 +05:30
README.md fix: translate plugin bundles at the transport layer 2026-10-15 22:53:20 +05:30

chinese2english

Renders Chinese UI text in DeepSeek Harness third-party plugins as English.

Most community plugins ship hardcoded Chinese inside their client bundles. Those strings never reach DSH's locale dictionaries, so they stay Chinese even when the interface language is English. This plugin translates them at the transport layer, before any of that code runs.


How it works

Plugin bundles are served by DSH's clientModules service over /plugins/.... This plugin wraps clientModules.bundleResource, decodes each JavaScript response, rewrites the Chinese string literals it can translate, and returns the result. Because interception happens server-side, it covers every plugin at once, including combination bundles that carry dozens of them, and it runs before any plugin code is evaluated.

Two deliberate choices:

  • All-or-nothing literals. Chinese has no word boundaries, so replacing known words wherever they appear corrupts larger words (当前工作区 would become Saat IniWorkspace). A literal is translated only when every Chinese character in it is covered by a dictionary entry; anything else is left in Chinese, since half-translated text reads worse than untranslated text.
  • A compile gate. Each rewritten bundle is parsed with new Function before it is served. If a rewrite ever produced invalid JavaScript, the original bytes are served instead, so a bad dictionary entry cannot break the UI.

The client half does one thing: it selects the en locale through ctx.locale.setLocale, which persists the preference. It never touches the DOM.


What it does not cover

Translation works on string literals inside served bundles. Text that arrives another way stays as it is:

  • Plugin descriptors in package.json and README.md files (marketplace listings, plugin titles).
  • Server-side API prose that is fetched as JSON at runtime.
  • The long tail of one-off literals that the dictionary does not yet cover.

The shipped dictionary holds roughly 1,200 entries and covers about 45% of the Chinese literals in a typical plugin set. Coverage is concentrated on strings that appear repeatedly; rare one-off sentences are usually left in Chinese.


Installation

dsh plugin --profile web add chinese2english

Remove it with dsh plugin --profile web remove chinese2english.

Restart DSH after installing, so the plugin is loaded and its transport wrapper is installed before the first bundle request.


Development

npm run dict    # rebuild src/dictionary.json from its sources
npm run build   # bundle the server and client halves into lib/

Dictionary sources, merged in this order:

  1. dshmarket_dict.json — harvested pairs.
  2. UI_TRANSLATIONS in patch-plugins.py — harvested pairs.
  3. src/dictionary.extra.json — curated entries, merged last so they win.

Add or fix translations in src/dictionary.extra.json, then run npm run dict && npm run build.


License

MIT © oiupoyt