@ragnoryok1/dsh-client-locale-ru

Плагин делает интерфейс DeepSeek Harness русским. Переводится всё, что вы видите: настройки, боковые панели, диалоги, подсказки, сообщения об ошибках — и меню сторонних плагинов, у которых нет своего русского перевода.
Сейчас в пакете 587 разделов и 69 538 строк, из них 520 словарей сторонних плагинов — больше, чем у любого другого русского пакета для харнесса, который я смог найти.
Установка — одна команда: dsh plugin --profile web add @ragnoryok1/dsh-client-locale-ru, дальше русский выбирается в настройках, в разделе General.
Кроме перевода плагин делает три вещи, которых харнесс сам не умеет: подставляет русские формы числа («1 вызов», «2 вызова», «5 вызовов»), приводит текст к русской типографике («ёлочки», длинное тире, многоточие) и переводит названия плагинов, у которых нет своей локали. Каждую из этих надстроек можно выключить одной строкой в профиле — перевод при этом останется.
Пакет не меняет файлы харнесса и не трогает ваши данные. Если в новой версии харнесса появится строка, которой в пакете ещё нет, она останется английской: интерфейс продолжит работать. Лицензия MIT, пакет поддерживается сообществом и не связан с DeepSeek.
If the pack was useful to you, please star the repository. It is the only signal that a translation is wanted, and it is what decides which parts get worked on next.
Полный список переведённого — в NAMESPACES.md: 600 namespace, 69 538 строк, словари плагинов помечены отдельно.
Плагины за пределами дерева харнесса переводятся так же, но их английский текст берётся из собственной публикации: plugins/<namespace>.json хранит пакет, версию, лицензию и строки, выгруженные из бандла. Что осталось английским в вашей установке, покажет npm run report:plugins: он обходит node_modules профиля, находит у каждого плагина его собственный словарь и сверяет ключи с нашими, а плагин без словаря так и помечает — переводить нечего, пока он не спросит перевод.
Отдельно стоит сказать про семейство @linxin666: тринадцать словарей, и каждый переведён целиком — от нескольких десятков строк до четырёх сотен.
| Словарь | Пакет | Строк |
|---|---|---|
update |
@linxin666/dsh-update |
43 |
git-graph |
@linxin666/dsh-client-ui-git-graph |
63 |
dsh-web-ui-usage |
@linxin666/dsh-usage |
67 |
dsh-web-ui-session-archive |
@linxin666/dsh-session-archive |
124 |
pet |
@linxin666/dsh-pet |
81 |
remote |
@linxin666/dsh-remote-web-ui |
117 |
dsh-skill-explorer |
@linxin666/dsh-client-ui-skill-explorer |
114 |
dsh-web-ui-market |
@linxin666/dsh-client-ui-market |
106 |
liangshen |
@linxin666/dsh-liangshen |
42 |
dsh-web-ui-preset-center |
@linxin666/dsh-client-ui-preset-center |
46 |
dsh-ssh |
@linxin666/dsh-ssh |
158 |
task-board |
@linxin666/dsh-client-ui-task-board |
439 |
task-board-github |
@linxin666/dsh-client-ui-task-board-github |
113 |
| Итого | 13 словарей | 1 513 |
Названия и описания самих плагинов на странице «Плагины» пакет перевести не может: харнесс хранит их в locale/<язык>.json внутри каждого пакета и собирает из них карту перевода, а resolveText в сервисе локали словари не спрашивает вовсе. У 221 пакета есть locale/en.json, у 219 — locale/zh.json, и ни у одного нет locale/ru.json: эти 261 строка остаются английскими при любом языковом пакете. Разрыв считает scripts/descriptor-coverage.mjs, разбор механизма и 32 готовых перевода — в docs/descriptor-upstream.md.
Чужой перевод мы не копируем: сверять его было бы не с чем, а аудит сравнивает наше значение с английским шаблоном того же плагина. И одно предупреждение на будущее: если в профиле окажется второй пакет, который сам регистрирует русский, язык достанется тому, кто зарегистрировал его первым, — второй молча пропустит свои namespace, и в интерфейсе будет чужой перевод.
Как это выглядит
Русский в списке языков и переведённые разделы настроек (снимки сделаны в сборке 0.1.8:
тот же экран, но формулировки и часть разделов с тех пор изменились — например, подпись
размера шрифта теперь «Влияет только на содержимое диалога»):


Оба снимка обрезаны по левой границе панели: в кадр не попадают названия рабочих пространств и сессий.
Пакет — не только словарь. Сверх перевода он делает три вещи: приводит текст к русской экранной типографике («ёлочки», тире с пробелами, одно многоточие вместо трёх точек), выбирает формы числа по Intl.PluralRules('ru') вместо нейтральных подписей и подставляет русские названия тем плагинам, чей пакет не везёт своей локали.
Каждый проход можно выключить, не трогая перевод: в строке профиля cordis.yml достаточно config: { typography: false }, так же отключаются plurals и pluginNames. Пропущенный переключатель считается включённым, поэтому существующий профиль править не нужно.
Типографика — единственный проход, который переписывает введённый вами текст. Если она мешает в поле ввода, выключайте именно её: остальное останется русским.
Установка
Это гибридный плагин (dsh.bundle + dsh.client), поэтому он ставится как обычный профиль-бандл через dsh plugin:
dsh plugin --profile web add @ragnoryok1/dsh-client-locale-ru
Дальше при следующем старте dsh web в настройках появится Русский. Отдельно pnpm add в собранный dsh web не нужен — плагин тянет штатную локаль через сервис locale.
Если pnpm отвечает ERR_PNPM_NO_MATURE_MATCHING_VERSION — это не поломка пакета, а
политика зрелости: профиль не ставит версии, опубликованные меньше 48 часов назад.
Подождите сутки-двое (имя версии в сообщении показывает, сколько осталось) или снимите
ограничение minimumReleaseAge в настройках профиля.
Манифест проверяется по правилам харнесса, а не на глаз (npm run check:manifest, входит в
verify). Правила вычитаны из его исходников и каждое — это отказ, который иначе увидел бы
пользователь: parseDshClient принимает platform любой строкой, но потребители отбирают
только platform === 'web', поэтому опечатка 'Web' молча выключила бы клиентскую
половину; declared dsh.client без экспорта ./client заставляет client-modules бросить
ошибку; dsh.bundle.patch обязан указывать на существующий файл.
Установка из GitHub тоже работает: dsh plugin --profile web add Ragnoryok1/dsh-client-locale-ru (в таком виде команду генерирует каталог плагинов, без @-скоупа) ставит архив репозитория, а собранный lib/ лежит в git — сборка на вашей машине не запускается и не требуется. Поэтому npm run check:built (входит в verify) пересобирает lib/ и сверяет его с коммитом: устаревший бандл в git иначе получил бы именно пользователь, а аудит этого не увидел бы — он читает исходники. Публикуемый пакет занимает 2031 КБ: баннер отдаётся JPEG, а иконка и карта исходников в npm не входят.
Почему гибрид
dsh web берёт клиентские (UI) плагины только из workspace-пакетов, а внешний npm-пакет с одним dsh.client не подхватывается. Чтобы внешний плагин с UI-частью был устанавливаемым, он должен объявлять dsh.bundle (профиль-слой), чей cordis.patch.yml через - insert: добавляет клиентскую строку locale-ru в браузерный ростер. Так устроены и другие сторонние плагины (например @zseven-w/dsh-android).
Как это работает
- Хост-половина (
lib/index.js) — пустойapply(): языковому плагину не нужна серверная логика, она лишь даёт корректную cordis-строку для Loader. - Браузерная половина (
lib/client.js) — регистрируетruи словари через сервисlocale(инжект изctx). Рантайм-импортов фреймворка нет — только сервис. - Рантайм-зависимостей нет —
lib/client.jsне импортирует другие пакеты, поэтому не тянет тяжёлых зависимостей. - Эффекты — язык и словари регистрируются через
ctx.effect(...), поэтому выгружаются вместе с плагином (HMR-безопасно). - Плюралы — контракт локали не несёт правил плюрализации: компоненты выбирают форму
как
count === 1 ? 'ключ.one' : 'ключ.other', а русскому нужны три (1 вызов / 2 вызова / 5 вызовов). Пакет берёт это на себя: рядом с.oneи.otherв словарях лежат.fewи.many, а обёртка надtranslateрантайма пересчитывает форму черезIntl.PluralRules('ru')для любого вызова с числовымcountилиn. Форму решает число, а не ключ, который выбрал компонент, поэтому «2 вызова инструментов» и «5 вызовов инструментов» получаются из одного и того же места вызова. Формы есть не только у парных ключей: если харнесс передаёт число ключу без пары (terminal.expandс{n}), пакет добавляет к нему свои.one/.few/.many— «Показать ещё 1 строку / 3 строки / 7 строк», — а обёртка ищет форму и для таких ключей. Там, где форма неуместна (в предложении несколько чисел), значение переписано нейтрально к числу: «Символов: {total}» вместо «{total} символов», «файлов: {files}» вместо «{files} файлов». Проверяется скриптом:npm run check:pluralна счетах 0, 1, 2, 3, 5 и 22, на ключе без пары, на дробном числе и на чужом языковом пакете, чьи формы наши правила не переписывают. - Фолбэк — отсутствующий русский ключ падает на
en(настроенныйfallback).
Типографика
Пакет приводит уже отрисованный русский текст к типографским правилам: «ёлочки» вместо
прямых кавычек, длинное тире вместо дефиса между словами, многоточие вместо трёх точек,
неразрывный пробел между числом и следующим словом или единицей измерения (чтобы «187
плагинов» не разрывалось на две строки) и такой же пробел после короткого слова — предлога,
союза или частицы: «в режим» переносится целиком, а не оставляет «в» висеть в конце строки.
Правила намеренно осторожны: срабатывают только на однозначных шаблонах, а код, поля ввода,
редактируемый текст и элементы с data-typography="off" не трогаются вообще. Повторный
проход ничего не меняет.
Сам проход видит только текстовые узлы, а значение из словаря попадает и в атрибуты —
title, aria-label, placeholder, — до которых он не достаёт. Поэтому значения
проверяются отдельно: в пакете не может быть прямых кавычек, дефиса вместо тире, тире без
пробела или трёх точек. Иначе одна и та же строка выглядела бы по-разному в зависимости от
того, куда её поставили, а в подсказке и в подписи для скринридера правила бы не работали
вовсе.
Текст, который меняется после первого прохода — счётчики токенов, таймеры, прогресс, —
обрабатывается заново: живое «4 с» сохраняет неразрывный пробел. Это проверяется на настоящем
документе, а не только на строках: npm run check:typography:dom (jsdom, шесть случаев —
первый проход, изменение текста, добавленное поддерево, остановка при выгрузке, чужой язык и
переключение языка).
Проход включается только пока активен русский: правила русские, и применять их к другому
языку значило бы править текст, который пакету не принадлежит — в английском интерфейсе
"quotes" превратились бы в «quotes». Пакет слушает locale/change и запускает или
останавливает проход при переключении, а не при установке.
Правило для числовых диапазонов («5–10» через среднее тире) сознательно не добавлено:
единственная строка с дефисом между числами во всём пакете — пример cron-выражения
0 9 * * 1-5, и тире его испортило бы. Измерено, а не предположено.
Правила проверяются скриптом, а не на глаз: npm run check:typography.
Имена плагинов
Название плагина приходит из его собственного файла locale/<язык>.json, а служба локализации
разрешает эту карту, не обращаясь к зарегистрированным словарям: её собственная документация
говорит «maps do not consult registered dictionaries». Поэтому словарём название плагина не
перевести — у пакета нет доступа к чужой карте, и английское название остаётся английским,
пока сам плагин не привезёт locale/ru.json.
Пакет несёт эти названия сам: названия 32 плагинов харнесса и названия с описаниями 33
сторонних плагинов, чьи словари он переводит. У каждого — английский текст, из которого сделан
перевод, и русский. Отрисованный интерфейс проходит через проход, который подставляет
русский текст на место английского: в карточках плагинов, в строках состава bundle, на
странице плагина и в реестре настроек. Подменяется и имя для скринридера (aria-label),
чтобы карточка читалась по-русски целиком.
Проход берёт только точное совпадение: строка целиком равна названию или описанию из пакета. Предложение, в котором название лишь упомянуто, остаётся как было; код, поля ввода и переписка не трогаются. Как и типографский проход, он работает только пока активен русский.
Те же 32 названия уходят в харнесс отдельным патчем (docs/harness-descriptors-ru.patch): в
интерфейсе самого харнесса плагины называются по-русски, и патч этот до начала. Патч —
собираемый артефакт: он строится из переводов и дерева харнесса, а гейт
npm run check:descriptor-patch падает, когда собранный и лежащий в репозитории разошлись.
Сторонние названия лежат в src/client/plugin-names-ru.json: файл собирается из
выгруженных словарей плагинов (npm run build:plugin-names), а гейт
npm run check:plugin-names:map падает, когда карта разошлась со словарями. Одно и то же
английское название не может быть переведено дважды — по-разному у харнесса и у плагина.
npm run check:plugin-names доказывает на настоящем документе (jsdom, 12 случаев), что проход
переводит название, описание, имя для скринридера и строку bundle — и не трогает то, что не
должен.
Если хотите перевести харнесс на свой язык
Порядок, ловушки и проверки, через которые мы прошли, собраны в
docs/how-to-translate-dsh.md: как найти секции, почему
нельзя собирать шаблоны по одному ключу из любого файла, что делает с переводом смена
зависимости рантайма и как отдать публикацию CI.
Лицензия
MIT
История изменений
CHANGELOG.md — что было в каждом выпуске.
No comments yet. Be the first to write one.