dsh-plugin-skill2cn
Translate the English description of a skill into Chinese and restore the original in one click; a newly installed skill is surfaced right away.
- Stars
- 0
- Language
- TypeScript
- Created
- Sep 17, 2026
- Updated
- Sep 20, 2026
Introduction
Skill2CN · Skill Localization (dsh-plugin-skill2cn)
English | 简体中文
Translate the English description of DSH skills into Simplified Chinese, with one-click restore.
- Single entry point: a dedicated "技能汉化 / Skill Localization" section page in the DSH settings UI (3 tabs: Untranslated / Translated / Model Settings), plus a bottom-right prompt card when new skills appear
- Translation granularity: only the
descriptionvalue inSKILL.mdfrontmatter;nameand the skill body are left byte-for-byte intact - Write-to-disk: the translation is written straight back to the
SKILL.mdon disk (rationale indocs/adr/0001-write-to-disk-translation.md); DSH hot-reloads it, so no restart is needed - Single source of truth: the
manifest.jsonbackup ledger. The panel reconciles "disk ↔ ledger" to derive each skill's state: untranslated / translated / no-translation-needed / stale
Features
| Feature | What it does |
|---|---|
| Untranslated tab | Groups skills by source (workspace / global / plugin package), with a Translate button per skill and a Translate All batch action |
| Translated tab | Per-skill Restore, View original toggle, and a Restore All batch action |
| Batch jobs | Async with a concurrency cap of 3, live progress, and a success/failure summary; failed items stay on the panel with a Retry button |
| New-skill prompt | A shell.overlay card in the bottom-right corner asking whether to translate newly discovered skills (deprecated ones are never re-asked) |
| Model Settings tab | Three translation routes — follow the current session route, pick a configured provider/model, or use a custom endpoint (OpenAI- or Anthropic-compatible protocol) — plus a Test button |
| Upgrade reconcile | On panel open, entries overwritten by a package upgrade are either silently cleared or marked stale, and can be re-translated |
| CJK heuristic | Descriptions that are already Chinese are marked "no translation needed" and skipped by batch runs |
Demo video
https://github.com/user-attachments/assets/a98d7649-052b-4912-8ff5-1a472abf2dda
The intro video and the usage poster above (source HTML) were made by our teammate 阿根 (Agen). The video file is also kept in the repo at docs/assets/introduction-video.mp4.
Install
dsh plugin --profile <profile> add <path-to-this-repo-or-tarball>
A link: install (local path) does not run prepare, so no allowBuilds entry is needed. Restart DSH once after installing (this loads the host half for the first time). After that:
- change the host (
src/service.ts,src/core/**) →pnpm build, then restart DSH - change the client (
src/client/**) →pnpm build, then reload the browser
Uninstall
Click Restore All on the Translated tab first. Write-to-disk changes are not undone automatically by uninstalling (ADR-0001, Consequences).
dsh plugin --profile <profile> remove dsh-plugin-skill2cn
The ledger at $DSH_HOME/skill2cn/manifest.json is left behind (harmless, safe to delete by hand).
Development
pnpm install
pnpm dev # tsdown watch (tsc transpiles standard decorators into lib-tsc first, then bundles)
pnpm test # core unit tests (vitest)
pnpm typecheck # both tsconfigs: host + client
pnpm build # emits lib/index.js (host ESM) + lib/client.js (closure-factory CJS)
Requirements: Node ≥ 22.13 and pnpm 11. (pnpm 11 requires Node ≥ 22.13 and is
also the version that produced pnpm-lock.yaml.)
Build pipeline
The @Remote decorator needs TypeScript's standard-decorator transpilation, which esbuild/tsdown does not perform, so the build runs in two steps:
tsc -p tsconfig.build.json emits lib-tsc/, then tsdown bundles from the lib-tsc/index.js entry into lib/index.js.
lib-tsc/ is an intermediate artifact (already covered by .gitignore and regenerated by pnpm build).
Translation routing
The Model Settings tab offers three routes:
-
Follow the current DSH session route (default) — reuses the provider/model of the most recent session request. If no route has been captured yet,
Testasks you to send a session message first. -
Use a configured provider/model — the dropdown is populated from
ctx.remote.llm.listConfigurableProviders();Discover modelscallsdiscoverModelson the provider'ssettingsNs. Some providers register no discovery capability, in which case you can type the model name manually. -
Custom endpoint — pick a protocol (
OpenAI-compatible/Anthropic-compatible) under Advanced, then fill in Base URL / API key / model name. Both are non-streaming:- OpenAI-compatible →
POST {baseURL}/chat/completions(Authorization: Bearer) - Anthropic-compatible →
POST {baseURL}/messages(sends bothx-api-keyandAuthorization: Bearerso official and proxy endpoints both work;anthropic-version: 2023-06-01,max_tokensrequired)
The Base URL must include the version segment (e.g.
https://api.deepseek.com/v1orhttps://api.anthropic.com/v1) — the resource path is appended by the plugin. Note this differs from how you configure ananthropicprovider inside DSH, where the base excludes/v1(the SDK owns the path); copying that style here gives you a 404. - OpenAI-compatible →
Test runs one real, small translation through the current route and reports a verdict first: a green "configuration succeeded" or a red "configuration failed", with details on the second line (translation + latency + the actual model name; on failure, the host's original reason). The sample sentence is fixed in the host (Use when translating skill descriptions into Simplified Chinese.) — deliberately this plugin's own self-description, so a passing test also demonstrates that the route can translate the very thing you need translated, and the skill identifier in it doubles as a check of the built-in "do not translate identifiers" rule.
How it works
Translation is write-to-disk (ADR-0001): the plugin reads the target SKILL.md, records the English original in the backup ledger, calls the LLM, then rewrites only the description: line of the frontmatter. DSH's chokidar watcher fires skills/change, so the next model step already sees the Chinese description. The ledger — not any guess about a file's language — is the only thing that decides translated vs. untranslated.
Known limitations
- The workspace group follows the session workspace (
session.header.cwd; falling back to the most recent session with a header, and only then to the process cwd). So "workspace" means the project you have open in DSH, not the directory DSH was started from — starting DSH from inside a checkout does not make that checkout's own project skills a translation target. - Enumeration uses the
ctx.skillsregistry winner set: skills that lost a same-name override, and in-memory provider skills with no file on disk, do not appear on the panel. - The "no translation needed" heuristic treats a description as Chinese when it has ≥ 4 CJK ideographs and at least half as many CJK characters as Latin letters. Chinese descriptions routinely carry identifiers and product names (
dingtalk-*,Shadcn/ui,utility-first,spec/tickets), which a strict "more CJK than Latin" rule would misjudge as needing translation. See the acceptance record for the real-data verification. - The "configured route" dropdown lists DSH's provider catalog, which is not the same as the providers with a registered adapter on your machine: picking an unregistered one makes
Testreportno adapter registered for provider "..."(surfaced verbatim rather than swallowed). - Skills from the plugin package source are overwritten when the npm package is upgraded or reinstalled; their badge carries a ⚠️ and the automatic reconcile on panel open handles the fallout (silently clearing the record or marking it stale).
Testing
pnpm test # 12 spec files, 94 test cases
Acceptance
The itemized, measured results for all nine SPEC §7 acceptance criteria are in docs/ACCEPTANCE.md (including the DSH API mismatches found during implementation and the defects they exposed).
Documentation
CONTEXT.md— glossary; the authoritative definition of every concept in this plugindocs/SPEC.md— product spec and acceptance criteriadocs/adr/0001-write-to-disk-translation.md— architecture decision: write-to-diskdocs/ACCEPTANCE.md— implementation acceptance recorddocs/README.md— documentation index
Contributing
See CONTRIBUTING.md. This repository is a published snapshot: development happens in a private working tree, and this directory is re-synced on each release, so a PR may be re-applied onto that tree rather than merged directly.