@ragnoryok1/dsh-client-locale-ru 0.2.15 → 0.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/NAMESPACES.md +3 -3
- package/README.en.md +14 -403
- package/README.md +14 -403
- package/README.zh.md +14 -166
- package/lib/client.js +473 -531
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
|
+
## [0.2.17] — 2026-10-24
|
|
2
|
+
|
|
3
|
+
### Изменено
|
|
4
|
+
|
|
5
|
+
- **Описание пакета написано простым языком.** В npm, в мета-блоке README и в
|
|
6
|
+
описании каталогов стояло «Russian (ru) interface for the DeepSeek Harness web GUI:
|
|
7
|
+
584 namespaces, 67666 strings… **Hybrid dsh.bundle + dsh.client plugin**» — набор
|
|
8
|
+
внутренних терминов, из которого человек, выбирающий перевод, не узнавал ни что он
|
|
9
|
+
получит, ни зачем ему это. Теперь описание говорит о деле: весь интерфейс харнесса
|
|
10
|
+
и меню 520 сторонних плагинов, 584 раздела, 67 666 строк.
|
|
11
|
+
- **README сокращён с 607 строк до 210.** Убраны шесть разделов, написанных для
|
|
12
|
+
разработчика: «Область покрытия», «Разработка», «Релизы», «Содержимое», «Что
|
|
13
|
+
переведено» (118 строк истории версий — она и так в этом файле) и «Проверки» (184
|
|
14
|
+
строки про аудит, снимки словарей и совместимость). Команды сборки остаются в
|
|
15
|
+
git-истории, проверки — в `scripts/audit.mjs`; в README теперь только то, что
|
|
16
|
+
нужно читателю: что это, как поставить, как выглядит, типографика, имена плагинов.
|
|
17
|
+
|
|
18
|
+
### Исправлено
|
|
19
|
+
|
|
20
|
+
- **Ошибка в описании области покрытия.** Русское и китайское вступления говорили
|
|
21
|
+
«521 стороннего плагина», а в пакете 520 — цифра отставала от словаря, который был
|
|
22
|
+
удалён как несуществующий.
|
|
23
|
+
- **Аудит читал группированные числа неправильно.** В «67,666 strings» он видел
|
|
24
|
+
«666 строк» и валил сборку на верной цифре; шаблоны «<число> строк» ловили в тексте
|
|
25
|
+
посторонние числа — пример форматирования и длину самого файла словаря. Сверка
|
|
26
|
+
стала якорной, с поддержкой разрядов через запятую, пробел и неразрывный пробел.
|
|
27
|
+
|
|
28
|
+
## [0.2.16] — 2026-10-23
|
|
29
|
+
|
|
30
|
+
### Добавлено
|
|
31
|
+
|
|
32
|
+
- **Словарь плагина `@norman-else/dsh-claude@0.1.66` — 470 строк.** Плагин запускает
|
|
33
|
+
локальный Claude Code CLI как основную беседу внутри харнесса; своей русской локали у него
|
|
34
|
+
нет, поэтому весь его экран настроек — режимы разрешений, работа с рабочим деревом,
|
|
35
|
+
`/usage` подписки, ограничение простоя — оставался английским. Перевод лежит в namespace
|
|
36
|
+
`settings.claude-code`: термины взяты из уже переведённых словарей пакета («рабочее
|
|
37
|
+
дерево», «пул-реквест», «ревью», «раунд», «поле ввода»), а имена продуктов и команд
|
|
38
|
+
(`Claude Code`, `Jira`, `Atlassian`, `Bedrock`, `Vertex`, `Doctor`, `/usage`)
|
|
39
|
+
остались как есть. Английский текст выгружен из публикации плагина вместе с версией и
|
|
40
|
+
лицензией.
|
|
41
|
+
|
|
42
|
+
### Исправлено
|
|
43
|
+
|
|
44
|
+
- **Удалён словарь-призрак `acp_turn_sep_` — 528 строк, которых у плагина нет.**
|
|
45
|
+
Улучшенный разбор бандлов принял за имя словаря константу
|
|
46
|
+
`RESPONSES_TURN_SEPARATOR_ID_PREFIX` из плагина `billion-context`: `acp_turn_sep_` — это
|
|
47
|
+
префикс служебных идентификаторов, а не имя словаря. Эти строки в принципе не
|
|
48
|
+
могли появиться на экране, зато попадали в пакет, в счётчики и в политики. Настоящий словарь того
|
|
49
|
+
же плагина — `foldPositions` — остался на месте.
|
|
50
|
+
- **Режим `verbose` больше не называется «Подробный».** В списке «Детали работы»
|
|
51
|
+
два режима подписывались одним словом — «Подробный», и пункт «показывать всё, ничего не
|
|
52
|
+
сворачивая» выбирался наугад. Теперь у `verbose` своё
|
|
53
|
+
слово — «Развёрнутый»: рядом с «Компактным», «Стандартным» и «Подробным» он читается как
|
|
54
|
+
отдельный режим. Дефект нашёл `bondarevpm-tech` в PR #4; правка применена в `main`,
|
|
55
|
+
потому что пул-реквест разошёлся с веткой.
|
|
56
|
+
|
|
1
57
|
## [0.2.15] — 2026-10-22
|
|
2
58
|
|
|
3
59
|
### Изменено
|
package/NAMESPACES.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- Сгенерировано `npm run namespaces`; проверяется `npm run check:namespaces`. -->
|
|
2
2
|
# Что переведено
|
|
3
3
|
|
|
4
|
-
Пакет переводит **584 namespace** —
|
|
4
|
+
Пакет переводит **584 namespace** — 67666 строк. Колонка «как это выглядит»
|
|
5
5
|
берёт заголовок самого namespace (то, что читает пользователь), а не отдельное описание:
|
|
6
6
|
список нельзя разойтись с переводами.
|
|
7
7
|
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
| `.ndjson.zst` | Английская страница (USD) | 2 | dsh-usage-badge@0.1.9 |
|
|
16
16
|
| `.runs.json` | Название | 70 | dsh-tongflow@0.8.4 |
|
|
17
17
|
| `about.huaqiu` | О плагине | 9 | @huaqiu/dsh-huaqiu-about@0.6.6 |
|
|
18
|
-
| `acp_turn_sep_` | — | 528 | billion-context@0.1.204 |
|
|
19
18
|
| `agency` | — | 94 | @michengai/dsh-agency-agents@1.2.10 |
|
|
20
19
|
| `agent-community` | Bots团队 | 1 | @dsh-plugin-agent-community/ui-agent-community@0.3.9 |
|
|
21
20
|
| `agent-schedule` | tool.call.toolview | 61 | dsh-agent-toolkit@0.4.13 |
|
|
@@ -423,6 +422,7 @@
|
|
|
423
422
|
| `settings.catppuccin` | — | 34 | dsh-catppuccin@0.2.6 |
|
|
424
423
|
| `settings.chatTranslate` | — | 45 | @lynn123411/dsh-chat-translate@3.5.9 |
|
|
425
424
|
| `settings.checkpointRewind` | Хронология чекпоинтов | 49 | dsh-checkpoint-rewind@0.6.33 |
|
|
425
|
+
| `settings.claude-code` | Claude Code | 470 | @norman-else/dsh-claude@0.1.66 |
|
|
426
426
|
| `settings.codebuddy` | CodeBuddy | 50 | @shatyuka/dsh-llm-codebuddy@0.9.3 |
|
|
427
427
|
| `settings.codebuddy-cli` | Подключение DSH CodeBuddy CLI | 162 | dsh-codebuddy-cli@0.4.3 |
|
|
428
428
|
| `settings.codeIndex` | — | 12 | dsh-code-index@0.11.0 |
|
|
@@ -597,4 +597,4 @@
|
|
|
597
597
|
| `xrn1997-dsh-novel` | — | 160 | @xrn1997/dsh-novel@0.8.0 |
|
|
598
598
|
| `zhihu-search` | — | 19 | dsh-zhihu-search@2.2.1 |
|
|
599
599
|
|
|
600
|
-
Итого: **584** namespace, **
|
|
600
|
+
Итого: **584** namespace, **67666** строк.
|
package/README.en.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<!-- deepseek-harness-meta
|
|
2
2
|
{
|
|
3
3
|
"name": "Russian (ru) language pack for DeepSeek Harness",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.17",
|
|
5
5
|
"tags": ["localization", "russian", "i18n", "web-gui", "language-pack"],
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "Russian for the DeepSeek Harness web GUI: the whole interface plus the menus of 520 third-party plugins — 584 sections, 67 666 strings.",
|
|
7
7
|
"icon": "https://raw.githubusercontent.com/Ragnoryok1/dsh-client-locale-ru/main/assets/icon.png",
|
|
8
8
|
"compatible_versions": ["v0.2.1-rc.2", "v0.2.1-rc.1", "v0.2.1-alpha.5", "v0.2.1-alpha.4", "v0.2.1-alpha.3", "v0.2.1-alpha.2", "v0.2.1-alpha.1", "v0.2.0-rc.2", "v0.2.0-rc.1", "v0.1.7-rc.2", "v0.1.7-rc.1", "v0.1.7-alpha.2"],
|
|
9
9
|
"screenshots": "images",
|
|
@@ -22,16 +22,24 @@
|
|
|
22
22
|
[](https://github.com/Ragnoryok1/dsh-client-locale-ru/actions/workflows/verify.yml)
|
|
23
23
|
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
24
24
|
[](https://github.com/Ragnoryok1/dsh-client-locale-ru)
|
|
25
|
-
[](https://github.com/Ragnoryok1/dsh-client-locale-ru)
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
The plugin makes the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) interface Russian. Everything you see is translated: settings, side panels, dialogs, hints, error messages — and the menus of third-party plugins that ship no Russian of their own.
|
|
28
|
+
|
|
29
|
+
The pack currently holds 584 sections and 67,666 strings, 520 of them dictionaries of third-party plugins — more than any other Russian pack for the harness I could find.
|
|
30
|
+
|
|
31
|
+
Install is one command: `dsh plugin --profile web add @ragnoryok1/dsh-client-locale-ru`; Russian is then picked in the settings, under General.
|
|
32
|
+
|
|
33
|
+
Beyond translation the pack does three things the harness cannot do by itself: it chooses the Russian plural form by the number instead of a neutral label, applies Russian typography («ёлочки», em dashes, ellipses), and translates plugin names whose package ships no locale of its own. Each extra can be turned off with one line in the profile — the translation stays.
|
|
34
|
+
|
|
35
|
+
The pack does not modify harness files and does not touch your data. If a newer harness adds a string the pack does not know yet, it stays English: the interface keeps working. MIT, maintained by the community, not affiliated with DeepSeek.
|
|
28
36
|
|
|
29
37
|
> **If the pack was useful to you, please star the repository.** It is the only signal that a
|
|
30
38
|
> translation is wanted, and it is what decides which parts get worked on next.
|
|
31
39
|
|
|
32
40
|
---
|
|
33
41
|
|
|
34
|
-
The complete inventory is in [NAMESPACES.md](NAMESPACES.md): 584 namespaces, 67,
|
|
42
|
+
The complete inventory is in [NAMESPACES.md](NAMESPACES.md): 584 namespaces, 67,666 strings, with the bundled plugin dictionaries marked.
|
|
35
43
|
|
|
36
44
|
Plugins outside the harness tree are translated the same way, but their English text comes from their own publication: `plugins/<namespace>.json` records the package, the version, the licence and the strings extracted from its bundle. What is still English in your installation is shown by `npm run report:plugins`: it walks the profile's `node_modules`, finds each plugin's own dictionary and compares its keys with ours, and a plugin without a dictionary is reported as such — there is nothing to translate until it asks for one.
|
|
37
45
|
|
|
@@ -99,7 +107,7 @@ two (the message names the version) or drop the `minimumReleaseAge` limit in the
|
|
|
99
107
|
settings.
|
|
100
108
|
The manifest is checked against the harness's own rules rather than by eye (`npm run check:manifest`, part of `verify`). Each rule was read out of the harness sources and each is a failure the user would otherwise meet first: `parseDshClient` accepts `platform` as any string while the consumers keep only `platform === 'web'`, so a typo like `'Web'` would **silently drop** the client half; a declared `dsh.client` without the `./client` export makes `client-modules` throw; and `dsh.bundle.patch` has to point at a file that exists.
|
|
101
109
|
|
|
102
|
-
Installing from GitHub works too: `dsh plugin --profile web add Ragnoryok1/dsh-client-locale-ru` (the form the plugin catalogue generates, without the npm scope) installs the repository archive, and the built `lib/` is committed — no build runs on your machine, and none is needed. That is exactly why `npm run check:built` (part of `verify`) rebuilds `lib/` and compares it with the commit: a stale bundle in git would reach the user, while the audit would never see it, because the audit reads the sources. The published package is
|
|
110
|
+
Installing from GitHub works too: `dsh plugin --profile web add Ragnoryok1/dsh-client-locale-ru` (the form the plugin catalogue generates, without the npm scope) installs the repository archive, and the built `lib/` is committed — no build runs on your machine, and none is needed. That is exactly why `npm run check:built` (part of `verify`) rebuilds `lib/` and compares it with the commit: a stale bundle in git would reach the user, while the audit would never see it, because the audit reads the sources. The published package is 1975 kB: the banner ships as JPEG, and the icon and source map stay out of the npm payload.
|
|
103
111
|
|
|
104
112
|
## Why hybrid
|
|
105
113
|
|
|
@@ -194,403 +202,6 @@ translates the title, the description, the accessible name and a bundle row —
|
|
|
194
202
|
it must alone.
|
|
195
203
|
|
|
196
204
|
|
|
197
|
-
## Checks
|
|
198
|
-
|
|
199
|
-
```sh
|
|
200
|
-
npm run build # the three outputs
|
|
201
|
-
npm run check:typography # 18 typography rules, including "leave alone"
|
|
202
|
-
npm run check:locale # dictionaries side by side: 6 checks
|
|
203
|
-
npm run check:plural # plural forms: 1 вызов / 2 вызова / 5 вызовов
|
|
204
|
-
npm run check:composition # composed phrases: «Пн, Ср в 09:00», «Раз в 2 дня»
|
|
205
|
-
npm run check:namespaces # NAMESPACES.md matches the built bundle
|
|
206
|
-
npm run check:tarball # what gets installed: the archive is unpacked and checked
|
|
207
|
-
npm run check:workflows # both workflows run the whole verify chain
|
|
208
|
-
npm run check:readmes:pairs # the three READMEs move together (recorded section hashes)
|
|
209
|
-
npm run check:plugin-names # plugin names in Russian on a real document
|
|
210
|
-
npm run check:descriptor-patch # the harness patch matches the translations
|
|
211
|
-
npm run audit -- <harness tree> # the locale audit
|
|
212
|
-
npm run verify -- <harness tree> # everything together
|
|
213
|
-
|
|
214
|
-
npm run namespaces # regenerate NAMESPACES.md and pack-count.json
|
|
215
|
-
npm run readmes:record # re-record section hashes after editing all three READMEs
|
|
216
|
-
npm run diff:harness -- <old> <new> # what the harness reworded under us
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
A separate check composes phrases the way the harness does and reads the result whole. The
|
|
220
|
-
audit compares a value with its own template, so a phrase that is correct in isolation but
|
|
221
|
-
broken by substitution stays invisible to it: `frequency.weekly` was filled as «По {weekdays}
|
|
222
|
-
в {time} », while the days arrive as «Пн, Ср» — producing «По Пн, Ср в 09:00», which no
|
|
223
|
-
line-by-line check can see. The same way «Каждые 2 дня» (now «Раз в 2 дня»), «Каждый день в
|
|
224
|
-
09:00 (Europe/Moscow)» and a composed interval with the plural forms are pinned. The third find
|
|
225
|
-
of the same kind: `time.locale` is not text but a tag for `Intl`, and it was `en` — a rule
|
|
226
|
-
restricted to a month read «Каждый день в January», and the zone label «Moscow Standard Time»
|
|
227
|
-
inside a Russian interface. The tag is `ru` now (the harness's Chinese dictionary uses `zh-CN`
|
|
228
|
-
the same way), and the month sits in parentheses: «Каждый день (январь, март)».
|
|
229
|
-
|
|
230
|
-
The same part-by-part reading found the cron wording: abbreviations («Каждые {step} мин»,
|
|
231
|
-
«Каждые {count} ч») and bookish turns («в минуту {minutes}», «минуты {minutes} в часы
|
|
232
|
-
{hours}»). The counted parts gained plural forms — «Каждые 3 минуты» / «Каждые 5 минут»,
|
|
233
|
-
«Каждые 2 часа» / «Каждые 6 часов» — and the rest were rewritten into one readable labelled
|
|
234
|
-
style: «Каждый час, минуты: 5, 30», «минуты: 5, часы: 09–17». The whole schedule sentence is
|
|
235
|
-
asserted end to end: «Пн–Пт каждые 5 минут». The date stamps are pinned the same way: «5 окт. 2026 г., 15:51» and the zone label «Москва, стандартное время» come from Intl with our tag, without a single Latin word.
|
|
236
|
-
|
|
237
|
-
The audit runs in CI (`.github/workflows/verify.yml`) against a **pinned harness tag**,
|
|
238
|
-
not against some random local checkout. The same run also fires **weekly on a schedule**: a
|
|
239
|
-
translation rots without anyone editing it — the upstream moves on, everything is green
|
|
240
|
-
locally, and the drift surfaces only when a user builds. The gates cover completeness (keys and
|
|
241
|
-
namespaces), plural forms, placeholders, English and Chinese residue, terminology, Latin words in
|
|
242
|
-
prose, text hygiene, edge spaces, style, typography of values, «ё», composed phrases, the length
|
|
243
|
-
of settings sidebar labels and the advertised numbers — and every one of them has already caught
|
|
244
|
-
real defects. Beside them the audit
|
|
245
|
-
prints **advisory reports**,
|
|
246
|
-
which are not gates because they need a human decision: how many namespaces were compared and
|
|
247
|
-
which could not be linked, whether any «number + inflecting word» is left, and whether a short
|
|
248
|
-
string grew past 2.8× its English (a layout risk — «Effort» → «Уровень рассуждения» is normal
|
|
249
|
-
Russian length, not a defect).
|
|
250
|
-
|
|
251
|
-
The audit reads harness templates in the shape the harness writes them: a literal, an **array of
|
|
252
|
-
paragraphs** (that is how the preset guides are stored) and a **reference to a constant**
|
|
253
|
-
(`'hint.plan': PLAN_NEXT_ACTION_EN`). While only the first shape was read, ten keys — eight of
|
|
254
|
-
them whole guide documents — silently fell out of every comparison. And the other way round: an
|
|
255
|
-
empty policy file (`keep-english.json`, a `terminology.json` section) now fails the audit instead
|
|
256
|
-
of widening a gate unnoticed. The numbers the READMEs advertise are checked against the pack the
|
|
257
|
-
same way, because a stale count is simply a wrong claim — and the same numbers are read from the
|
|
258
|
-
`package.json` description, which is what npm shows in search and on the package page (that is
|
|
259
|
-
where «55 namespaces» lived longest) — including the grouped spelling: the
|
|
260
|
-
old leads said `2 489`, and the gate only read the ungrouped form, so the pattern now accepts
|
|
261
|
-
thousands separators. The sentence naming the harness version the pack was built against is
|
|
262
|
-
checked next to it, against the tag the workflow pins, because that workflow is what verifies
|
|
263
|
-
the pack (both leads claimed `0.2.1-alpha.2` while CI had already moved to
|
|
264
|
-
`dsh-v0.2.1-rc.2`). The published size is measured there too: `npm run check:size` packs the
|
|
265
|
-
archive and compares the advertised kilobytes with the real ones, allowing one kilobyte of slack
|
|
266
|
-
because gzip compresses slightly differently across Node builds while the sentence rounds to
|
|
267
|
-
whole kilobytes.
|
|
268
|
-
|
|
269
|
-
- **dead namespaces** — every namespace the package registers has to
|
|
270
|
-
exist in the harness. In 0.1.6 the schedule catalog translations were registered
|
|
271
|
-
under the name `schedule.manager`, whereas `schedule.catalog` is what reads them: the per-key
|
|
272
|
-
coverage check nonetheless reported «всё переведено»;
|
|
273
|
-
- **plural-form pairs** — the `.one`/`.other` sets have to match, because the client
|
|
274
|
-
chooses the form as `count === 1 ? '.one' : '.other'`. That is not enough for Russian:
|
|
275
|
-
every pair also needs `.few` and `.many`, or the wrapper quietly falls back to the neutral
|
|
276
|
-
`.other` and shows «2 д» where «2 дня» was possible. The check runs **per namespace** —
|
|
277
|
-
the wrapper looks the form up in the namespace that asked, so a pair missing on one screen
|
|
278
|
-
while present on another would otherwise stay invisible. It found the four time units
|
|
279
|
-
(`unit.day/hour/minute/second` in `schedule.catalog`) and `trigger` in the task manager;
|
|
280
|
-
the units stopped being abbreviations («д», «ч», «мин») and gained full forms in the right
|
|
281
|
-
case — «через 2 дня», «через 5 часов», and «Каждые 2 дня» became «Раз в 2 дня». The same
|
|
282
|
-
requirement covers the keys the pack added itself (`terminal.expand` and its kin: the
|
|
283
|
-
harness passes them a count but never pairs them) — their forms rest on us alone, and
|
|
284
|
-
losing one would be invisible to everything else;
|
|
285
|
-
- **placeholders** — a Russian value has to carry exactly the `{name}` placeholders its
|
|
286
|
-
English template carries: an extra one reaches the screen literally
|
|
287
|
-
(`Заняло {duration}7мин 26с`, fixed in #2), a dropped one silently removes the
|
|
288
|
-
interpolated value. Packages that ship only the Chinese dictionary are compared
|
|
289
|
-
against `zh`. Our **own plural forms** — the `.few`/`.many` we add, and the `.one` of a key
|
|
290
|
-
the harness never paired — do not exist upstream, so each is compared with the template of
|
|
291
|
-
a sibling form of the same word (`.one`/`.other`) or of the key itself. Without that, 52
|
|
292
|
-
values were never checked at all: that is exactly how a `{count}` can disappear from a form
|
|
293
|
-
and leave the sentence without its number.
|
|
294
|
-
- **residue** — a value has to be Russian: an exact copy of the English template, a leftover
|
|
295
|
-
Chinese character, or an empty string where the template has text is a defect. English
|
|
296
|
-
copies are allowed only by a decision recorded in `scripts/keep-english.json` (addresses,
|
|
297
|
-
format-only strings, protocol and tool names, abbreviations), so a new untranslated line
|
|
298
|
-
cannot slip through unnoticed. The decisions themselves are checked too: an entry that no
|
|
299
|
-
longer excuses anything fails the build — either its key left the pack, or the value was
|
|
300
|
-
translated and the decision went stale. This is how the `deepSeekBaseUrl` entry was found:
|
|
301
|
-
the English template gained a note about `DEEPSEEK_BASE_URL`, while the input placeholder
|
|
302
|
-
has to be a bare example URL, so that note would have been noise inside the field. The entry
|
|
303
|
-
is gone, the value stays. A decision may also name a closed list: `chat · app.*` allows
|
|
304
|
-
thirty application names in one line, because a dictionary of application names is a list of
|
|
305
|
-
names. And a value with no word outside its placeholders (`{from}–{to}`, `{percent}%`, `, `)
|
|
306
|
-
needs no decision at all: there is nothing in it to translate, so the policy stays about
|
|
307
|
-
words rather than about punctuation. The residue rule reads **every** template of a key, not
|
|
308
|
-
only the `en` block: 60 values in dictionaries with an unrecognised block used to go
|
|
309
|
-
unexamined, while now 2911 values are compared, 68 of them covered by decisions (38 entries,
|
|
310
|
-
one of them a pattern), and the zone is gone as a class. The rule did not become wider:
|
|
311
|
-
an empty value is a defect only where no template is empty either, since Russian justly
|
|
312
|
-
drops the prefix that English drops too (`message.stepProcess.sharedPrefix`).
|
|
313
|
-
- **dead keys** — a key no harness dictionary defines and no harness source names is a
|
|
314
|
-
leftover from an older version: it shows nothing and only misleads. Such keys fail the
|
|
315
|
-
build. A key a component still asks for stays in the advisory report, because the pack's
|
|
316
|
-
value is what reaches the screen.
|
|
317
|
-
- **terminology** — one concept, one rendering. Forbidden variants («кеш» for «кэш», «сеанс»
|
|
318
|
-
for «сессия», «этап» for «шаг») fail the build, and `scripts/terminology.json` keeps both
|
|
319
|
-
the decision and counts of the chosen forms, so drift shows up before it becomes a defect.
|
|
320
|
-
The check immediately found `confirm.description` translated two ways in two namespaces —
|
|
321
|
-
«шаги» and «этапы». One word may not be spelled both with and without «ё»: «ещё» next to
|
|
322
|
-
«еще» reads as machine translation, so the check folds «ё» to «е» and fails on two spellings
|
|
323
|
-
of one folded form. Real distinct pairs such as «все» and «всё» are declared in
|
|
324
|
-
`scripts/yo-pairs.json`, and a declaration whose spellings left the pack fails as well. The
|
|
325
|
-
same report covers Latin words inside Russian phrases: a product,
|
|
326
|
-
command or code token is allowed, an ordinary English word in a sentence is not. A product name
|
|
327
|
-
has to be spelled the way the harness spells it: «Github Desktop» for «GitHub Desktop» reads as a
|
|
328
|
-
typo in the product's own name, and the pack is the only place it can appear. The reference is
|
|
329
|
-
the English templates; a word the harness writes only in lowercase («cursor», «desktop») does not
|
|
330
|
-
count, because there a capital is exactly the product name. Next to it
|
|
331
|
-
comes mechanical hygiene: double spaces, a space before punctuation, unpaired «ёлочки» and
|
|
332
|
-
brackets, a non-breaking space inside a value, and edge spaces — a value that starts or ends
|
|
333
|
-
with one is glued to a neighbour by the component, so it has to match the English template
|
|
334
|
-
of its own namespace. The same template checks style: a terminator the English carries must
|
|
335
|
-
not disappear (this is how `registryCustomHint` was found without its period), and the case
|
|
336
|
-
of the first letter has to match — except for acronyms like `JSON` and templates that open
|
|
337
|
-
with a placeholder. The address to the reader is checked on its own: inside a sentence the
|
|
338
|
-
Russian interface writes «вы» lowercase, and «Вы» with a capital letter only at the start of
|
|
339
|
-
a sentence, where it is nothing but spelling. Finally the pack is compared with itself: one
|
|
340
|
-
English sentence has to come back as one Russian sentence. When two namespaces render it
|
|
341
|
-
differently — templates of four words or more are compared, because a short label legitimately
|
|
342
|
-
follows its context — the build fails. This is how `confirm.description` was found: one
|
|
343
|
-
rendering promised to «пропускать шаги подтверждения», the other to «уменьшать число шагов»,
|
|
344
|
-
and the English «subsequent tasks» had become «текущей задаче» in the second. A deliberate
|
|
345
|
-
divergence is declared in `scripts/one-rendering.json` with its reason, and an exception that
|
|
346
|
-
no longer matches anything fails as well — otherwise the list of decisions would quietly widen
|
|
347
|
-
the check. The opposite direction is printed as an advisory: the same Russian answer to
|
|
348
|
-
**different** English sentences of four words or more hints at a copy-paste — a hint carried
|
|
349
|
-
over from a neighbouring key, or two distinct facts collapsed into one phrase. It cannot be a
|
|
350
|
-
gate, because Russian legitimately merges words English keeps apart, so both sides are printed
|
|
351
|
-
together and a human decides.
|
|
352
|
-
|
|
353
|
-
A separate workflow watches the tag itself: `watch-upstream` compares the pinned tag with
|
|
354
|
-
the harness tags once a week, opens an issue with the steps when a newer one exists, and turns
|
|
355
|
-
the run red — so lagging behind is found on a schedule rather than in a user's screenshot. The
|
|
356
|
-
version comparison is checked without the network (`npm run check:upstream`: prerelease order,
|
|
357
|
-
equal versions, a move between lines) and is
|
|
358
|
-
part of `verify`: a release has to outrank its own prereleases, or the watch would fire forever.
|
|
359
|
-
|
|
360
|
-
The coverage number is not a gate: some sections are deliberately left in English. Next to it
|
|
361
|
-
the audit prints a **per-namespace** report: it rebuilds the namespace-to-dictionary link from
|
|
362
|
-
whoever registers it (`NS`, or a literal in `locale.register`; `bind` and `PropsLocale` only read
|
|
363
|
-
a namespace) and lists keys missing from both their own namespace and the shared `common`
|
|
364
|
-
dictionary the runtime falls back to. A global name comparison cannot see those holes: a
|
|
365
|
-
translation filed under another namespace counts as coverage while the screen shows English.
|
|
366
|
-
The report is advisory — the same key name can mean different things in different namespaces
|
|
367
|
-
(`list.aria` is "Active reminders" in the catalog and "Background jobs" in jobs), so a
|
|
368
|
-
translation is copied across namespaces only where one dictionary serves both. On the pinned
|
|
369
|
-
tag the report is empty: every string the harness renders in a namespace we register lives in
|
|
370
|
-
that namespace. All 584 of the pack's namespaces are compared — the link comes both from a
|
|
371
|
-
dictionary imported beside the registration and from the names that registration passes
|
|
372
|
-
(`locale.register(NS, { zh, en })`); without the second rule `common` and `settings.locale`,
|
|
373
|
-
whose dictionaries sit in a neighbouring directory, would stay uncovered. The other direction is
|
|
374
|
-
a failure rather than a report: a namespace the harness registers and fills with keys, which the
|
|
375
|
-
pack never registers, leaves that screen in English while key coverage still looks complete.
|
|
376
|
-
This is how `settings.sessionLog` was found — the “Upload Session Log” switch on the general
|
|
377
|
-
settings page.
|
|
378
|
-
|
|
379
|
-
## Coverage scope: the harness and plugin dictionaries
|
|
380
|
-
The package translates **the harness client's own namespaces** — 64 namespaces reconciled
|
|
381
|
-
against the pinned tag — and **the dictionaries of third-party plugins**: 520 plugins whose
|
|
382
|
-
English text is vendored from their own publication, with the version and the licence.
|
|
383
|
-
|
|
384
|
-
Searching the npm registry — six queries instead of one «dsh» — found 40 more plugins with
|
|
385
|
-
a dictionary of their own. 39 are translated; three names (`dsh-automation`, `remote`,
|
|
386
|
-
`settings.ip-pool`) are already taken by other plugins' dictionaries and stay with their
|
|
387
|
-
owners, so that nobody's product gets somebody else's translation. As of 22 October 2026:
|
|
388
|
-
**584 namespaces, 67 724 values, 520 dictionaries, 47 700 distinct Russian strings** in the
|
|
389
|
-
built package. The competitor measurement, by the same method —
|
|
390
|
-
[docs/competitors.md](https://github.com/Ragnoryok1/dsh-client-locale-ru/blob/main/docs/competitors.md).
|
|
391
|
-
|
|
392
|
-
Plugin dictionaries were out of scope before, and there was a reason: `dshmarket` is already
|
|
393
|
-
at version 1.66.44, its keys change independently of the harness, and a silent promise of
|
|
394
|
-
«everything is covered» is not a promise but a debt nobody can collect. The answer turned
|
|
395
|
-
out to be simple: the foreign English text is **vendored** (`npm run fetch:plugins`) and
|
|
396
|
-
stored next to the translation, with the package name, the version and the licence, and the
|
|
397
|
-
audit holds our translation to that snapshot rather than to somebody else's Russian. We
|
|
398
|
-
checked the 17 most-downloaded plugins in the ecosystem (npm, `keywords:dsh-plugin`, monthly
|
|
399
|
-
downloads) and looked at which of them ship strings of their own at all:
|
|
400
|
-
|
|
401
|
-
| What we found | Plugins |
|
|
402
|
-
|---|---|
|
|
403
|
-
| **No strings of their own** — the interface takes its text from harness namespaces | **11 of 17** |
|
|
404
|
-
| A large dictionary of their own (confirmed by hand) | 2 — `dshmarket` (733 keys), `@nanmicoder/dsh-agent-teams` (420) |
|
|
405
|
-
| `.d.ts` types only, no strings | 1 — `dsh-plugin-model-proxy` |
|
|
406
|
-
| Needs a separate check | 3 |
|
|
407
|
-
|
|
408
|
-
For 11 of the 17 most popular plugins the Russian interface already works without a
|
|
409
|
-
dictionary of their own: their text lives in the shared harness namespaces, which the package
|
|
410
|
-
translates in full. Dictionaries exist where a plugin carries strings of its own — there
|
|
411
|
-
are 32 of them, and each records the version its English text was vendored from.
|
|
412
|
-
|
|
413
|
-
Such a dictionary is a commitment to track someone else's releases, but it is now a
|
|
414
|
-
checkable one: a new version of the plugin with different keys shows up as a difference from
|
|
415
|
-
the snapshot instead of as silence. Need a specific plugin? Open an issue: a dictionary for
|
|
416
|
-
it is possible as a separate layer pinned to a version, rather than as a silent promise that
|
|
417
|
-
«everything is covered».
|
|
418
|
-
|
|
419
|
-
## Development
|
|
420
|
-
|
|
421
|
-
```sh
|
|
422
|
-
pnpm install
|
|
423
|
-
pnpm run build # tsdown -> lib/index.js (node half) + lib/client.js (client bundle)
|
|
424
|
-
npm pack # -> ragnoryok1-dsh-client-locale-ru-<version>.tgz
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
`lib/client.js` is built in the format the `dsh` client loader understands (`__ModuleLoader__.load`) and exports `inject`/`apply`.
|
|
428
|
-
|
|
429
|
-
## Releases
|
|
430
|
-
|
|
431
|
-
Publishing to npm is done by the `publish` workflow on a tag — the credentials live in a repository
|
|
432
|
-
secret (`NPM_TOKEN`), so the token never has to be typed into a terminal or passed around.
|
|
433
|
-
Publishing by hand from a machine is possible, but unnecessary.
|
|
434
|
-
|
|
435
|
-
```
|
|
436
|
-
npm version 0.3.0 --no-git-tag-version # поднять версию в package.json
|
|
437
|
-
# …и синхронно обновить версию в блоке deepseek-harness-meta в этом README
|
|
438
|
-
git commit -am "release: 0.3.0" && git tag v0.3.0 && git push origin v0.3.0
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
Before publishing, the workflow checks:
|
|
442
|
-
|
|
443
|
-
1. the version in the tag matches the version in `package.json`;
|
|
444
|
-
2. the version in the `deepseek-harness-meta` block matches `package.json` — the marketplace takes it from there,
|
|
445
|
-
and reads it **only on first indexing**, so a mismatch does not fix itself;
|
|
446
|
-
3. the typography (18 rules);
|
|
447
|
-
4. the localization audit against the pinned harness tag — dead namespaces, duplicates and plural-form
|
|
448
|
-
pairs will fail and stop the publication;
|
|
449
|
-
5. **compatibility with every version in `compatible_versions`**: each one's locale runtime is
|
|
450
|
-
downloaded from npm and three suites — language coexistence, plural forms and composed phrases
|
|
451
|
-
— run against it (`npm run check:compat`, part of CI), so the promise in the meta block is
|
|
452
|
-
checked rather than assumed.
|
|
453
|
-
|
|
454
|
-
The declaration itself is checked separately (`npm run check:peers`, part of `verify`): the harness
|
|
455
|
-
reads our `peerDependencies` for `@deepseek-ai/dsh*` not as package versions but as a range of
|
|
456
|
-
**runtime versions**, with `includePrerelease`, and a range that fails to satisfy the running dsh
|
|
457
|
-
makes the user see an incompatibility warning and an exemption prompt. The script runs that rule
|
|
458
|
-
over every claimed version — all eight pass today.
|
|
459
|
-
|
|
460
|
-
To check all the same things locally, without publishing:
|
|
461
|
-
|
|
462
|
-
```
|
|
463
|
-
npm run verify -- путь/к/дереву/харнесса
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
The workflow also has a manual run with a «только проверки, без публикации» toggle
|
|
467
|
-
(`workflow_dispatch` → `dry-run`).
|
|
468
|
-
|
|
469
|
-
## Contents
|
|
470
|
-
|
|
471
|
-
- `src/client/dicts.ts` — the Russian dictionaries (584 namespaces, 67,724 translations, ~46 000 lines). This is where the main value lies.
|
|
472
|
-
- `src/client/index.ts` — the client plugin entry point (registration of `ru` + the dictionaries).
|
|
473
|
-
- `src/index.ts` — the empty host half (`apply()`).
|
|
474
|
-
- `cordis.patch.yml` — the profile patch (`- insert:` of the client entry `locale-ru`).
|
|
475
|
-
|
|
476
|
-
## What is translated
|
|
477
|
-
|
|
478
|
-
The current set follows the harness tags: the keys were taken from the matching commit, and keys
|
|
479
|
-
added later fall back to `en` on lookup, so the package does not break the interface on newer versions.
|
|
480
|
-
|
|
481
|
-
### 0.1.7 — dead namespace fixed, task manager translated, plural forms rewritten
|
|
482
|
-
|
|
483
|
-
The headline item in the release is **a fix for a mistake from 0.1.6**. At the time it was recorded
|
|
484
|
-
that the namespace `schedule.catalog` had been retired and that `schedule.manager` had taken its place.
|
|
485
|
-
In reality **both** namespaces live in the harness, separately: `schedule.catalog` is the reminder
|
|
486
|
-
catalog in the session header with frequencies and units, `schedule.manager` is the new automation-task
|
|
487
|
-
manager. Because of that wrong conclusion, ~30 translation strings (reminders, frequency, time
|
|
488
|
-
units) were registered under a name nobody reads and were **never shown** in the interface. The
|
|
489
|
-
catalog is now registered as `schedule.catalog`.
|
|
490
|
-
|
|
491
|
-
- **fixed:** the schedule catalog translations are visible again — `trigger.*`, `list.*`,
|
|
492
|
-
`delete.*`, `frequency.*`, `cron.*`, `unit.*`, `relative.*`, `mark.aria`, `hover.more`;
|
|
493
|
-
- **`schedule.manager` added** (188 keys) — the automation-task manager entirely in
|
|
494
|
-
Russian: the task panel and catalog, search, status filter, task details and its tabs,
|
|
495
|
-
the **run log** with retention rules, the schedule editor (date, time, hour, minute,
|
|
496
|
-
second, time zone, repeat interval), repeat rules (once, every N minutes/hours/
|
|
497
|
-
seconds, daily, Mon–Fri, weekly, custom cron), the cron form with date and minute
|
|
498
|
-
pickers, deletion with confirmation, notifications and cards;
|
|
499
|
-
- **plural forms rewritten** (17 key pairs): forms that broke on the numbers 2–4
|
|
500
|
-
were replaced with ones that are correct for any `n ≥ 2` — for example «2 субагентов» → «Субагентов: 2»,
|
|
501
|
-
«каждые 2 часов» → «каждые 2 ч». Another 8 strings with `{count}` before an inflected word
|
|
502
|
-
were switched to abbreviations: «ещё 3 строк» → «ещё 3 стр.»;
|
|
503
|
-
- **7 missing keys added**: `blocked.composer`,
|
|
504
|
-
`defaultWorkspace.title`, `schedule.active`, `settings.transcript.expanded`,
|
|
505
|
-
`status.scheduled`, `status.overdue` and the namespace `shortcuts.layout` (the label for
|
|
506
|
-
the command that shows the left panel);
|
|
507
|
-
- **a new check in the project:** a namespace-name audit. The previous coverage check
|
|
508
|
-
compared keys inside a namespace but never compared the names themselves, so an entire
|
|
509
|
-
namespace could be registered under a non-existent name and quietly do nothing. Names
|
|
510
|
-
are now extracted from every way they can be declared (`const NS`/`SETTINGS_NS`/`namespace`,
|
|
511
|
-
`locale.register`, `locale.bind`, `PropsLocale<…>`) and compared as sets.
|
|
512
|
-
|
|
513
|
-
0.1.2 added sections that 0.1.1 did not have: `open-in-app` («Открыть в
|
|
514
|
-
приложении»), `sidebarFiles`, `sidebarRight` (the right sidebar with files) and
|
|
515
|
-
`sidebarCodePreview` (code preview). It also updated the keys that changed in
|
|
516
|
-
harness 0.1.5 and removed 21 keys that no longer exist there.
|
|
517
|
-
|
|
518
|
-
In 0.1.3 the package caught up with harness 0.1.6-alpha.1: 139 keys and 7 new
|
|
519
|
-
sections were added — `sidebarTerminal` (the terminal in the right sidebar), `settings.archivedSessions`
|
|
520
|
-
(archived sessions) and the document-preview family (`sidebarDocumentPreview`,
|
|
521
|
-
`documentHtml`, `sidebarImage`, `documentMarkdown`, `sidebarPdf`). Besides that, the experimental
|
|
522
|
-
«Автопроверка» was translated (`permission.access`: `auto.*`), along with the command-palette
|
|
523
|
-
labels and tokens, the endpoint fields in the model settings, and the
|
|
524
|
-
changes in `conversation`, `trajectory`, `chat`, `session-log-download`.
|
|
525
|
-
28 keys that had disappeared from the harness were removed.
|
|
526
|
-
|
|
527
|
-
The coverage check runs against the harness sources: for each namespace the
|
|
528
|
-
key sets are compared, so the next release starts from an exact
|
|
529
|
-
“add / check / remove” list.
|
|
530
|
-
|
|
531
|
-
In 0.1.6 the package caught up with harness **0.1.7-rc.2**: **252 keys** added, 18 updated,
|
|
532
|
-
26 removed, and two new namespaces added. The changes:
|
|
533
|
-
|
|
534
|
-
- **`shortcuts`** (new namespace, 56 keys) — the hotkey editor: recording
|
|
535
|
-
a combination, conflicts, reserved combinations, hints for macOS and
|
|
536
|
-
Windows, restoring the default values;
|
|
537
|
-
- **`schedule.manager`** (70 keys at the time) — the automation-task manager: list,
|
|
538
|
-
deletion, repeat, run history, Cron expressions. **It was wrongly recorded that
|
|
539
|
-
the namespace `schedule.catalog` had been retired by this; 0.1.7 fixed that — both
|
|
540
|
-
namespaces exist side by side**;
|
|
541
|
-
- **`settings.account`** (50 keys) — the app's first launch: the welcome,
|
|
542
|
-
the choice of purpose and of how much of the work is shown, topping up the balance, signing out of
|
|
543
|
-
the account while tasks are running;
|
|
544
|
-
- added the labels for adding and removing tools on the fly
|
|
545
|
-
(`message.tools*`, `trajectory.layout.*`), the right sidebar commands
|
|
546
|
-
(`sidebarRight`), the «сначала выберите сессию» states in the panels, and updated
|
|
547
|
-
the name of the settings section: «Инструменты для кода» instead of «Инструментов
|
|
548
|
-
разработчика»;
|
|
549
|
-
- 18 keys updated to match the changed English text, 26 removed. A single term,
|
|
550
|
-
«рабочая папка», instead of «рабочей области» in one place.
|
|
551
|
-
|
|
552
|
-
In 0.1.5 the package caught up with harness **0.1.7-rc.1**: **49 keys** added, 13 updated,
|
|
553
|
-
16 removed, and the namespace `directory-browser` dropped (it is gone in rc.1). There appeared
|
|
554
|
-
the labels for the steps tools go through (`message.stepProcess.prepare.*` and `done.*` —
|
|
555
|
-
reading images, writing files, preparing for code search, web search,
|
|
556
|
-
subagent coordination and others), full-screen image viewing
|
|
557
|
-
(`image.*`), the «Стандартный» and «Подробный» modes for showing the work, installing plugins
|
|
558
|
-
from GitHub with a timeout and a Chinese mirror, the warning about an incompatible
|
|
559
|
-
plugin version, the choice of model download source for voice input, and `Cordis` command
|
|
560
|
-
messages. The wording was tightened where upstream replaced “teammate/agent”
|
|
561
|
-
with “subagent” and “Beta” with “Experimental”.
|
|
562
|
-
|
|
563
|
-
0.1.5 also fixed the counting unit in the plugin inventory: it was «187 плагины»,
|
|
564
|
-
now it is «187 плагинов». The built-in interface screenshots were translated too, npm
|
|
565
|
-
keywords were added, and the peer range of `@deepseek-ai/dsh-client-locale`
|
|
566
|
-
(`>=0.1.0-rc.2 <0.2.0`) was fixed — previously `^0.1.0` did not resolve, because the package
|
|
567
|
-
is published only under prerelease versions.
|
|
568
|
-
|
|
569
|
-
In 0.1.4 the package caught up with harness **0.1.7-alpha.2** — the biggest jump:
|
|
570
|
-
**905 keys** added, 29 changed, 126 removed. New sections:
|
|
571
|
-
|
|
572
|
-
- **`pluginManager`** — the built-in plugin panel: installation, removal,
|
|
573
|
-
enabling and disabling components, versions, registries and install hints;
|
|
574
|
-
- **`settings.account`** — the DeepSeek account: sign-in, balance, spend,
|
|
575
|
-
API key;
|
|
576
|
-
- the separate settings sections the former `settings.plugins` split into:
|
|
577
|
-
**`settings.agentLoop`**, **`settings.shell`**, **`settings.subagent`**,
|
|
578
|
-
**`settings.webSearch`**;
|
|
579
|
-
- **`sidebarBrowser`** — the built-in browser in the right panel (address, sandbox,
|
|
580
|
-
restoring the page);
|
|
581
|
-
- **`sidebarExcel`** and **`sidebarOffice`** — preview of Office spreadsheets and
|
|
582
|
-
documents; zooming (`zoom.*`) was added to PDFs and images;
|
|
583
|
-
- **`voice-input`** — experimental voice input.
|
|
584
|
-
|
|
585
|
-
Also translated were the new texts in `conversation` (+194), `chat` (+53),
|
|
586
|
-
`workspace` (+43: session archive, pinning), `deliverables` (+31: the review of
|
|
587
|
-
work changes), `job` (+24: live output of background tasks), `settings` (+22:
|
|
588
|
-
desktop app update), `plan`, `open-in-app`, `trajectory`,
|
|
589
|
-
`model`, `reference`, `session-log-download`, and in the agent-mode
|
|
590
|
-
guides (`settings.agentPreset`, 12 long texts). The section
|
|
591
|
-
`settings.archivedSessions` was removed: in 0.1.7 upstream dropped that package, and the session
|
|
592
|
-
archive moved to `workspace`.
|
|
593
|
-
|
|
594
205
|
## License
|
|
595
206
|
|
|
596
207
|
MIT
|