{"_id":"@creait/dsh-to-english","name":"@creait/dsh-to-english","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@creait/dsh-to-english","description":"Automatically rewrite market-downloaded plugins' Chinese copy/prompts into natural English, using a model you already have configured — once at install, then live-reloaded.","version":"0.1.0","type":"module","main":"lib/index.js","exports":{".":{"default":"./lib/index.js"},"./client":"./client/client.cjs","./package.json":"./package.json"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime","@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-api-remotes"],"platform":"web"}},"dependencies":{"@deepseek-ai/dsh-settings":"^0.1.0-rc.6","@deepseek-ai/schemastery":"^3.18.1","chokidar":"^4.0.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-llm":"^0.1.0-rc.6"},"license":"MIT","engines":{"node":">=20"},"keywords":["dsh","deepseek-harness","cordis","plugin","translate","english","localization","market"],"repository":{"type":"git","url":"git+https://github.com/CREAIT-nl/dsh-plugins.git","directory":"to-english"},"homepage":"https://github.com/CREAIT-nl/dsh-plugins/tree/main/to-english#readme","bugs":{"url":"https://github.com/CREAIT-nl/dsh-plugins/issues"},"author":{"name":"Francesco G","email":"francesco@creait.nl"},"scripts":{"test":"node --test test/*.test.js"},"gitHead":"488ad11d2a6582854dc98b84feacf32e0a2d2337","_id":"@creait/dsh-to-english@0.1.0","_nodeVersion":"25.8.1","_npmVersion":"11.11.0","dist":{"integrity":"sha512-xF8S7bJQlTvIHDDeHOieRY9H3Tkrpc83tyHvSr+XF8Q20nZeTDPlBZVUEKz3gzCW/RdX5SwTCWYSROU8YiZH0g==","shasum":"f09c53b3f11c963be11362f8edcf40b53295fbac","tarball":"https://registry.npmjs.org/@creait/dsh-to-english/-/dsh-to-english-0.1.0.tgz","fileCount":12,"unpackedSize":150321,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEX0fBG2QmSmi8tBHR2is8s9hiwyuJfPWrm0b7CbAAn6AiAHP2+HPkjnQZFJQrHpXSxh3thl1y0I3ximvV3FE0pipw=="}]},"_npmUser":{"name":"creait","email":"francesco@creait.nl"},"directories":{},"maintainers":[{"name":"creait","email":"francesco@creait.nl"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-to-english_0.1.0_1787577869024_0.5809993213090481"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-24T13:24:28.842Z","0.1.0":"2026-08-24T13:24:29.162Z","modified":"2026-08-24T13:24:29.400Z"},"maintainers":[{"name":"creait","email":"francesco@creait.nl"}],"description":"Automatically rewrite market-downloaded plugins' Chinese copy/prompts into natural English, using a model you already have configured — once at install, then live-reloaded.","homepage":"https://github.com/CREAIT-nl/dsh-plugins/tree/main/to-english#readme","keywords":["dsh","deepseek-harness","cordis","plugin","translate","english","localization","market"],"repository":{"type":"git","url":"git+https://github.com/CREAIT-nl/dsh-plugins.git","directory":"to-english"},"author":{"name":"Francesco G","email":"francesco@creait.nl"},"bugs":{"url":"https://github.com/CREAIT-nl/dsh-plugins/issues"},"license":"MIT","readme":"# @creait/dsh-to-english\n\nRewrites a market-installed plugin's Chinese copy into English, using a model\nyou already have configured — once when it lands, then live-reloaded.\n\nMost of the DSH plugin market is written in Chinese. Installing from it gives\nyou a working plugin whose settings page, tool descriptions, log lines and\nREADME you cannot read. Translating by hand is a per-plugin chore that has to be\nredone on every update, and a blunt \"replace every CJK run\" pass produces\nsomething worse: a plugin that reads English and no longer works.\n\nThe untouched original is always kept beside the file as `.zh.bak`.\n\n## How it translates\n\n**One pass over the whole file is the default.** The model is handed the entire\nfile and returns the entire file. What stands behind it is not a diff gate but a\nparser: `node --check` for `.js`/`.cjs`/`.mjs` (on a sibling temp file, so the\npackage's own `type` field decides script-vs-module exactly as it will at load\ntime), `JSON.parse` for `.json`, a YAML parse for `.yml`/`.yaml`. A file that\nfails is handed back to the model with the parser's complaint, up to three\nrepair round-trips. A reply shorter than 60% of the original is treated as\ntruncated rather than as a translation — prose has no parser to catch a\nhalf-written README.\n\nFiles up to **48 KB** go through this path. Above that the model would have to\necho back more than the completion budget allows.\n\n**The segment path is the fallback.** For a file too large to echo back, or one\nthe model could never get past its parser, the older pipeline still runs: only\nline ranges containing Chinese are sent, the reply must have the same number of\nlines, and each line is checked against the original's code skeleton before it\nis accepted. A conservative partial translation beats none at all. Nothing above\n512 KB is touched at all.\n\nWhy the default moved: the skeleton comparison is safe, and it is also why\nChinese that has to change *shape* to become English never translated.\n`/^[好嗯啊]*\\s*继续/` has to become `/^(ok|um|ah)*\\s*continue/` — a character\nclass turning into an alternation, because Chinese marks optionality per\ncharacter and English words are longer than one character. Every such line came\nback rejected.\n\nWhat that trades away is real and worth stating: **`node --check` catches a file\nthat stopped parsing, not one that still parses and now means something else.**\nA renamed identifier, a reworded `id:` in `cordis.patch.yml`, a translated\n`\"main\"` in `package.json` all survive their parser. The contract asks the model\nto leave those alone; nothing enforces it. Read the diff against `.zh.bak`.\n\n## What it will not translate\n\n`translateEverything` (default `true`) decides whether Chinese the *program*\nmatches on is rewritten or preserved. On an English-only harness, preserving it\njust leaves a feature switched off — the phrases that would fire it can never be\ntyped — so the default is to translate it, and to change its shape where English\ndemands a different one. Turn it off and the segment path locks three shapes:\n\n**Match data.** dsh-recall's auto-recall gate is ~324 characters of Chinese\ntrigger phrases and Chinese regexes. A line holding a regex literal with CJK, or\na line that is only quoted literals and commas, is locked.\n\n**The non-English half of an i18n table.** A `var zh = {…}` next to a\n`var en = {…}` is already bilingual; rewriting `zh` serves English to the people\nwho deliberately picked Chinese. A brace-depth scan from a head line bound to a\nnon-English language tag locks the block.\n\nTwo things are locked regardless of that setting.\n\n**Names the code looks up.** Variable and function names, object keys, import\nand route paths, settings namespaces, and the `id`, `name` and `main` fields of\n`package.json` and `cordis.patch.yml`. In the segment path `keepsStructure`\nenforces this by comparing the code skeleton, and YAML gets its own gate — a\nquoted scalar is writable only if the *original* held CJK, so\n`prompt: \"你是助手\"` translates and `name: 'dsh-enhance'` does not. In the\nwhole-file path this is a contract clause, not a gate.\n\n**Protocol strings.** `lib/semantic.js`'s `QUERY_PREFIX` in dsh-recall is the\nBGE embedding model's required instruction prefix. It belongs to the checkpoint,\nnot to the user: a model trained on Chinese instructions expects its Chinese\ninstruction whatever language the query is in. No deterministic rule catches\nthis — it is a prompt clause in both paths. **Review the diff.**\n\n`README.zh.md` and its siblings are skipped outright — the English README is the\nfile next to it, and translating it spends the budget producing a second English\nREADME under a name that says it is Chinese. A `README.md` that is itself the\nlocalized half (a Chinese `README.md` beside an English `README_EN.md`) is\nskipped the same way.\n\n### The one structural edit the segment path allows\n\n`\"请求 \" + <b>{n}</b> + \" 次\"` puts the measure word after the number and English\nputs it in front, so the trailing literal has nothing left to hold and must go.\n`dropsOnlyAffixes` permits that deletion under narrow terms — only a short CJK\nliteral, at most two per line, exactly one separator removed each, and only when\nanother Chinese literal on the same line survives, so `t(\"中文标题\", fallback)`\ncannot quietly lose an argument. Every such acceptance is logged and listed\nunder `relaxed` in the file report.\n\n## Install\n\nNot on npm yet, and pnpm cannot install a subdirectory of a git repo — so\nclone the repo and point the profile at the folder:\n\n```sh\ngit clone https://github.com/CREAIT-nl/dsh-plugins.git\ndsh plugin --profile web add ./dsh-plugins/to-english\n```\n\nThat records a `link:` rather than copying the package in, which is what you\nwant here: pnpm does not install a link target's dependencies into the linking\nproject, so the profile's `node_modules` stays free of a second copy of any\n`@deepseek-ai/*` runtime. Run `pnpm install` inside `to-english/` once, then\nrestart `dsh web` — the boot manifest is built at startup.\n\nThe package ships its own `cordis.patch.yml`, so it inserts its roster row on\nits own — no manual profile edit. Add it to `dsh.profile.bundles` to activate\nthe browser half.\n\n## Configure\n\nSettings live in the `dsh-to-english` namespace, or in the GUI at\n**Settings → To English**.\n\n| Key | Default | What it does |\n|---|---|---|\n| `enabled` | `true` | Run automatically when a plugin is installed. |\n| `provider` / `model` | `''` | Which configured model translates. Empty means the first available. |\n| `prompt` | style guidance | Editable. Style only — the mechanical contract lives in `WHOLE_FILE_RULES` and `PROTOCOL_SYSTEM`, where an edited prompt cannot weaken it. |\n| `rewriteRadius` | `1` | Segment path only. Lines without Chinese on each side of a Chinese line that are also open to rewriting. `0` leaves a mixed passage reading like a graft; `1` lets the model repair the English clause the Chinese was joined to. Capped at `5`. |\n| `translateEverything` | `true` | Translate the match data and locale tables described above rather than preserving them. The gates that stop the model renaming *code* are unaffected. |\n\nThe automatic run fires on a **new** top-level package directory appearing in\nthe profile's `node_modules`. Anything installed before this plugin existed\nnever crossed that trigger — use the settings section's **Translate now** box,\nwhich takes a package name and runs the same pipeline.\n\n## Routes\n\nLoopback-only, mirroring the gen-limit settings-route pattern — the harness\nsettings wire only exposes namespaces on its own allowlist, which a plugin\ncannot widen:\n\n| Route | Purpose |\n|---|---|\n| `GET/POST /api/dsh-to-english/config` | read/write the settings above |\n| `GET /api/dsh-to-english/catalog` | live provider/model list |\n| `POST /api/dsh-to-english/translate` | translate + reload one installed plugin now |\n| `GET /api/dsh-to-english/status` | enabled, provider, model, last run |\n\n## What breaks this\n\nThe watcher, the settings provider and the live-reload seam are pre-1.0\ninternal dsh surfaces with no compatibility guarantee. `peerDependencies` pins\nthe versions this was built against; a harness upgrade can move them.\n\nTranslation is a model call, so it is not deterministic. In the segment path a\nline that fails its check is left in Chinese and counted in the report. In the\nwhole-file path a file that fails its parser three times is abandoned and falls\nback to segments. Neither can make a mediocre translation good, and neither\ncatches a change that parses. Read the report, and for anything carrying a\nprotocol string, read the diff.\n\nThe settings nav glyph is a deliberate reach past the API. `settings.section`\nhas no icon option — the shell picks the glyph from a hardcoded section-id map\nand falls back to the gear for ids it does not know, ours included. So the\nclient half repaints its own row: it finds the nav cell by label and replaces\nthe gear's markup with the official `IconListPenOutline16`. It fails safe — if\nthe shell's markup moves, nothing matches and the row keeps the gear.\n","readmeFilename":"README.md","_rev":"1-6e85192d4f0fb7ea16fe59a0ebd22947"}