<!-- deepseek-harness-meta
{
  "name": "Community Russian dictionaries for DeepSeek Harness plugins",
  "version": "0.1.0",
  "tags": ["localization", "russian", "i18n", "web-gui", "language-pack"],
  "description": "Translates third-party DeepSeek Harness plugins without forking them: the missing Russian dictionary is contributed as data. It fills only the namespaces nobody has claimed and steps aside as soon as a plugin ships its own translation. Ships the plugin market's Russian dictionary as its first payload.",
  "compatible_versions": ["v0.2.1-alpha.1", "v0.2.0-rc.2", "v0.1.7-rc.2", "v0.1.7-rc.1"],
  "install_method": "dsh plugin --profile web add @ragnoryok1/dsh-locale-bridge"
}
-->

# @ragnoryok1/dsh-locale-bridge

[Русский](README.md) | **English** | [中文](README.zh.md)

Russian dictionaries for **third-party** [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugins — as data, without forks.

Third-party plugins register their own locale namespaces with `zh`/`en` and often ship no Russian. Translating them used to mean forking the plugin. This package contributes the missing dictionary as data instead: it attempts to register Russian for a namespace, keeps the result if the namespace was free, and steps aside when the plugin ships its own translation. The first payload is the plugin market (`dsh-market`). It cannot help plugins that draw their own text without asking the locale service — that limit is real, measured, and documented below.

## Why this is needed

Community plugins register their strings through the locale service (`ctx.locale.register`) with Chinese and English. They usually have no Russian, and the only way to get it was to **fork the plugin** — that is, to take on its updates forever.

The bridge solves this differently: the dictionary is contributed as **data**.

## How it behaves

Three rules, and all three follow from the locale contract rather than from our preferences:

1. **We fill only what is free.** `locale.register(ns, locale, dict)` throws if the namespace already has that language. The bridge attempts to register and **treats a refusal as a normal outcome**.
2. **We step aside for the author.** As soon as a plugin ships its own Russian, the bridge's registration is refused and it overrides nothing. No version conflict, no fight over the namespace.
3. **We report instead of staying silent.** There is no public way to ask which namespaces are taken — the dictionary map is private. So the fact that "it did not throw" is itself the proof that we are the ones who filled the dictionary, and it goes to the log instead of dissolving into a caught error.

## First payload: the plugin market

![The plugin market in Russian](images/market-ru.png)

The `dsh-market` dictionary is the interface of the [dshmarket](https://www.npmjs.com/package/dshmarket) plugin.

**687 of 687 strings translated** — the entire market interface.

**Checked on a live harness.** The market's label in settings comes from the dictionary
(`t('nav')`), and after installing the bridge it became Russian — «Маркет плагинов»,
the English «Plugin Market» is gone from the interface, and there are no errors in the console.

Coverage was measured on the screen, not from the file: out of 357 short English values
that could have appeared verbatim, **350 are shown in Russian**. The remaining seven
turned out to be false positives — they are **catalog data, not interface text**:

| Where it appeared | What it actually is |
|---|---|
| «local», «official», «source», «files» | plugin descriptions that the market receives from its own API |
| «Themes», «Theme» | category names («Themes & Appearance») from the same API |

They cannot be translated: this is catalog content, it belongs to the source and changes
without any involvement from us. The interface itself is fully translated.

## What it cannot do

**Plugins with their own strings are out of the bridge's reach.** An example is `@zseven-w/dsh-android`: it chooses the language itself (`androidCopy(locale)`, `zh`/`en` only) and never asks the locale service at all. No dictionary can reach such a plugin — it needs a change from the author.

This is not a flaw of the bridge but a boundary of the contract. It is measured: of ten third-party packages in the test profile, four use the locale contract, one draws its text itself, and five have no strings of their own.

## How to add a dictionary

Adding a translation is a **data change**, not a code change:

1. put the JSON alongside the others in `src/client/dicts/` (a flat "key → string" object);
2. add one line to the `DICTIONARIES` list in `src/client/index.ts`.

Keys must match the plugin's source dictionary: extra ones go nowhere, missing ones appear in English (the contract's standard fallback), so a partial dictionary is safe.

## Installation

```
dsh plugin --profile web add @ragnoryok1/dsh-locale-bridge
```

Russian is added automatically if the main localization package has not added it yet — the bridge works both on its own and together with it.

## Build

```
npm install
npm run build     # tsdown -> lib/index.js (host half) + lib/client.js (client bundle, словари внутри)
npm pack
```

## Contents

- `src/client/index.ts` — the bridge: adding the language, registering dictionaries, reporting;
- `src/client/dicts/*.json` — the "source" and "translation" dictionaries;
- `src/index.ts` — the empty host half;
- `cordis.patch.yml` — the profile patch.

## License

MIT. A community package, **not affiliated with DeepSeek**. Translations of third-party plugins are made by the community and may be inaccurate — report errors in the issues.
