Vai al contenuto principale
R

dsh-client-locale-ru

ragnoryok1/dsh-client-locale-ru

Russian (ru) language pack for the dsh web GUI: 584 namespaces and 67724 strings, including 520 third-party plugin dictionaries and Russian plural forms.

Installazione

dsh plugin --profile web add github:ragnoryok1/dsh-client-locale-ru

README

@ragnoryok1/dsh-client-locale-ru

Русский | English | 中文

Русский языковой пакет для DeepSeek Harness

npm license verify dsh namespaces strings

Русский (ru) язык для веб-интерфейса DeepSeek Harness (dsh). Пакет регистрирует ru как выбираемый язык клиента через сервис локали (ctx.locale.addLanguage) и везёт по словарю на каждый namespace — 584 namespace, 67 666 строк, сборка под dsh 0.2.1-rc.2. Установка: dsh plugin --profile web add @ragnoryok1/dsh-client-locale-ru, затем Русский в Settings → General. Недостающие ключи падают в английский, поэтому более новый харнесс продолжает работать. Область — собственный интерфейс харнесса (64 namespace и 2 996 строк) и словари 521 стороннего плагина, переведённые с английского, который публикует сам плагин. 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: 584 namespace, 67 666 строк, словари плагинов помечены отдельно.

Плагины за пределами дерева харнесса переводятся так же, но их английский текст берётся из собственной публикации: plugins/<namespace>.json хранит пакет, версию, лицензию и строки, выгруженные из бандла. Что осталось английским в вашей установке, покажет npm run report:plugins: он обходит node_modules профиля, находит у каждого плагина его собственный словарь и сверяет ключи с нашими, а плагин без словаря так и помечает — переводить нечего, пока он не спросит перевод.

Отдельно стоит сказать про семейство @linxin666: тринадцать словарей, и каждый переведён целиком — от нескольких десятков строк до четырёх сотен.

СловарьПакетСтрок
update@linxin666/dsh-update43
git-graph@linxin666/dsh-client-ui-git-graph63
dsh-web-ui-usage@linxin666/dsh-usage67
dsh-web-ui-session-archive@linxin666/dsh-session-archive124
pet@linxin666/dsh-pet81
remote@linxin666/dsh-remote-web-ui117
dsh-skill-explorer@linxin666/dsh-client-ui-skill-explorer114
dsh-web-ui-market@linxin666/dsh-client-ui-market106
liangshen@linxin666/dsh-liangshen42
dsh-web-ui-preset-center@linxin666/dsh-client-ui-preset-center46
dsh-ssh@linxin666/dsh-ssh158
task-board@linxin666/dsh-client-ui-task-board439
task-board-github@linxin666/dsh-client-ui-task-board-github113
Итого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 иначе получил бы именно пользователь, а аудит этого не увидел бы — он читает исходники. Публикуемый пакет занимает 2013 КБ: баннер отдаётся 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 — и не трогает то, что не должен.

Проверки

npm run build               # сборка трёх выходов
npm run check:typography    # 18 правил типографики, включая «не трогать»
npm run check:locale        # сосуществование словарей: 6 проверок
npm run check:plural        # формы числа: 1 вызов / 2 вызова / 5 вызовов
npm run check:composition   # собранные фразы: «Пн, Ср в 09:00», «Раз в 2 дня»
npm run check:namespaces    # NAMESPACES.md совпадает с собранным бандлом
npm run check:tarball       # что установят: архив распаковывается и проверяется
npm run check:workflows     # оба workflow запускают всю цепочку verify
npm run check:readmes:pairs # три README двигаются вместе (хеши разделов)
npm run check:plugin-names   # названия плагинов по-русски на настоящем документе
npm run check:descriptor-patch # патч для харнесса совпадает с переводами
npm run audit -- <дерево харнеса>   # аудит локали
npm run verify -- <дерево харнеса>  # всё вместе

npm run namespaces          # перегенерировать NAMESPACES.md и pack-count.json
npm run readmes:record      # перезаписать хеши разделов после правки трёх README
npm run diff:harness -- <старое> <новое>  # что харнесс переформулировал

Отдельная проверка складывает фразы так, как это делает харнесс, и читает результат целиком. Аудит сверяет значение с его собственным шаблоном, поэтому фраза, верная в одиночку, но сломанная подстановкой, для него невидима: frequency.weekly был переведён как «По {weekdays} в {time}», а дни приходят как «Пн, Ср» — получалось «По Пн, Ср в 09:00», чего не увидит ни одна построчная проверка. Так же проверяются «Каждые 2 дня» (теперь «Раз в 2 дня»), «Каждый день в 09:00 (Europe/Moscow)» и составной интервал с формами числа. Третье, что нашлось этим же способом: time.locale — не текст, а тег для Intl, и он был en. Правило с ограничением по месяцу показывало «Каждый день в January», а подпись часового пояса — «Moscow Standard Time» в русском интерфейсе. Теперь тег ru (у китайского словаря харнесса точно так же zh-CN), а месяц встаёт в скобки: «Каждый день (январь, март)».

Тот же разбор по частям нашёлся в описании cron. Там были сокращения («Каждые {step} мин», «Каждые {count} ч») и книжные обороты («в минуту {minutes}», «минуты {minutes} в часы {hours}»). Счётные части получили формы числа — «Каждые 3 минуты» / «Каждые 5 минут», «Каждые 2 часа» / «Каждые 6 часов», — а остальные части переписаны в один читаемый вид с метками: «Каждый час, минуты: 5, 30», «минуты: 5, часы: 09–17». Вся фраза расписания складывается проверкой целиком: «Пн–Пт каждые 5 минут». Тем же способом закреплены даты: отметка «5 окт. 2026 г., 15:51» и подпись пояса «Москва, стандартное время» — из Intl с нашим тегом, без единого латинского слова.

Аудит выполняется в CI (.github/workflows/verify.yml) против закреплённого тега харнеса, а не против случайного локального чекаута. Раз в неделю тот же прогон запускается по расписанию: перевод гниёт и без наших правок — харнесс уезжает вперёд, локально всё зелено, а расхождение всплывает только при сборке у пользователя. Гейтами проверяются полнота (ключи и namespace), формы числа, плейсхолдеры, остатки английского и китайского, терминология, латиница в прозе, гигиена текста, краевые пробелы, стиль, типографика значений, «ё», составные фразы, длина подписей в боковой панели и заявленные числа — и каждая из этих проверок уже ловила настоящие дефекты. Рядом аудит печатает справочные отчёты, которые гейтом не являются, потому что требуют решения человека: сколько namespace сверено и какие не удалось привязать, остались ли места «число + склоняемое слово», и не выросли ли короткие строки больше чем в 2,8 раза от английского (риск для вёрстки — «Effort» → «Уровень рассуждения» это нормальная длина русского, а не дефект).

Шаблоны харнесса аудит читает в том виде, в каком их пишут: строкой, массивом абзацев (так хранятся руководства режимов) и ссылкой на константу ('hint.plan': PLAN_NEXT_ACTION_EN). Пока читался только первый вид, десять ключей — восемь из них целые руководства — молча выпадали из сверки. И наоборот: пустой файл политики (keep-english.json, пустой раздел terminology.json) теперь валит аудит, а не ослабляет гейт незаметно. Так же сверяются и числа, которые README о себе заявляют: устаревший счётчик — это просто неверное утверждение, и аудит читает его из бейджа, описания и текста всех трёх README, а также из описания в package.json — того, что npm показывает в поиске и на странице пакета (там дольше всех жило «55 namespaces»), включая разряды («2,542 строки») — именно эта запись дольше всех держала в себе число 2,489, пока гейт видел только форму без разрядов. Там же сверяется и фраза о том, против какой версии харнесса пакет собран: она сравнивается с тегом, закреплённым в workflow, потому что проверяет пакет именно он (оба README обещали 0.2.1-alpha.2, когда CI уже стоял на dsh-v0.2.1-rc.2). Там же меряется и размер публикуемого пакета: npm run check:size собирает архив и сравнивает заявленные килобайты с настоящими (допуск в один килобайт — gzip на разных сборках Node сжимает чуть иначе, а сама фраза округлена до целых килобайт).

  • мёртвые namespace — каждый namespace, который регистрирует пакет, обязан существовать в харнессе. В 0.1.6 переводы каталога расписания были зарегистрированы под именем schedule.manager, тогда как читает их schedule.catalog: проверка покрытия по ключам при этом рапортовала «всё переведено»;
  • пары форм числа — множества .one/.other должны совпадать, потому что клиент выбирает форму как count === 1 ? '.one' : '.other'. Этого мало для русского: каждой паре нужны ещё .few и .many, иначе обёртка молча вернётся к нейтральному .other и вместо «2 дня» покажет «2 д». Проверка сверяет это по namespace — обёртка ищет форму в том namespace, который спросил, поэтому пара, забытая в одном экране при наличии в другом, иначе осталась бы незамеченной. Так нашлись четыре единицы времени (unit.day/hour/minute/second в schedule.catalog) и trigger в менеджере задач; заодно единицы перестали быть сокращениями («д», «ч», «мин») и получили полные формы в нужном падеже — «через 2 дня», «через 5 часов», а «Каждые 2 дня» стало «Раз в 2 дня». То же требование действует и для ключей, которые пакет добавил сам (terminal.expand и родственные: харнесс передаёт им счёт, но пары не заводит) — их формы держатся только нами, и потеря одной ничем больше не обнаружилась бы;
  • плейсхолдеры — русское значение обязано нести ровно те {name}, что и английский шаблон ключа: лишний плейсхолдер попадает на экран буквально (Заняло {duration}7мин 26с, исправлено в #2), а потерянный молча убирает подставленное значение. Для пакетов, которые везут только китайский словарь, шаблоном служит zh. Наши собственные формы числа — добавленные .few/.many и .one у ключа, который харнесс не паровал, — в харнессе отсутствуют, поэтому сверяются с шаблоном соседней формы того же слова (.one/ .other) или самого ключа. Без этого 52 значения не проверялись вовсе: именно так из формы может пропасть {count}, и на экране останется фраза без числа.
  • остатки — значение обязано быть русским: точная копия английского шаблона, китайский иероглиф или пустая строка там, где шаблон не пуст, — это ошибка. Копии английского допускаются только по решению, записанному в scripts/keep-english.json (адреса, форматные строки без слов, названия протоколов и инструментов, аббревиатуры), поэтому новая недопереведённая строка не проедет молча. Сами решения тоже проверяются: запись, которая больше ничего не разрешает, валит сборку — либо ключа в пакете уже нет, либо значение перевели и решение устарело. Так нашлась запись про deepSeekBaseUrl: английский шаблон обзавёлся пояснением про DEEPSEEK_BASE_URL, а подсказка в поле ввода — пример адреса, поэтому пояснение на экране было бы мусором внутри поля. Запись убрана, значение оставлено. Решение может называть и целый закрытый список: chat · app.* разрешает тридцать названий приложений одной строкой — словарь имён приложений и есть список имён. А значения без слов вне плейсхолдеров ({from}–{to}, {percent}%, , ) решения не требуют вовсе: переводить в них нечего, и политика остаётся про слова, а не про пунктуацию. Сверка остатков читает все шаблоны ключа, а не только блок en: раньше 60 значений в словарях с неопознанным блоком не проверялись вовсе, теперь сверено 2911 значения, 68 из них покрыты решениями (38 записей, одна из них — шаблон), и зона исчезла как класс. Шире от этого правило не стало: пустое значение — ошибка только там, где ни один шаблон не пуст, иначе русский справедливо опускает префикс, который английский тоже опускает (message.stepProcess.sharedPrefix). И точное совпадение — не единственный вид копии: значение, отличающееся от шаблона только регистром или краевыми пробелами (Cancel при шаблоне cancel), — это тот же непереведённый текст, и оно тоже требует решения. Иначе такая строка читалась бы как английская, а все проверки оставались бы зелёными.
  • мёртвые ключи — ключ, которого нет ни в одном словаре харнесса и на который не ссылается ни один его исходник, — это остаток от прежней версии: он ничего не показывает и только путает. Такие ключи валят сборку. Ключ, который компонент всё ещё спрашивает, остаётся в справочном отчёте: его значение — единственное, что может попасть на экран.
  • терминология — одно понятие переводится одним способом. Запрещённые варианты («кеш» вместо «кэш», «сеанс» вместо «сессия», «этап» вместо «шаг») валят сборку, а scripts/terminology.json хранит и решение, и счётчики выбранных форм, чтобы дрейф был виден раньше, чем станет дефектом. Проверка сразу нашла ключ confirm.description, переведённый в двух namespace по-разному — «шаги» и «этапы». Слово не может писаться с «ё» и без него: «ещё» и «еще» в одном пакете читаются как машинный перевод, поэтому «ё» внутри проверки сводится к «е», и два написания одной формы валят сборку. Исключения — настоящие разные слова вроде «все» и «всё»: они объявлены в scripts/yo-pairs.json, а запись, чьи написания из пакета ушли, тоже валит сборку. Там же проверяется латиница внутри русских фраз: имя продукта, команды или код-токен допустимы, простое английское слово в предложении — нет. Название продукта обязано писаться так, как его пишет харнесс: «Github Desktop» вместо «GitHub Desktop» читается как опечатка в имени продукта, и появляется она только у нас. Ориентир — английские шаблоны; слово, которое харнесс пишет только строчными («cursor», «desktop»), не считается — там заглавная буква как раз и означает имя продукта. Рядом проверяется механическая гигиена: двойные пробелы, пробел перед знаком препинания, непарные «ёлочки» и скобки, неразрывный пробел внутри значения, а также краевые пробелы — значение, которое начинается или кончается пробелом, компонент склеивает с соседним, поэтому оно обязано совпадать с английским шаблоном своего namespace. Тем же шаблоном сверяется стиль: если английский кончается знаком, русский не должен его терять (на этом проверка нашла registryCustomHint без точки), а регистр первой буквы обязан совпадать — кроме сокращений вроде JSON и шаблонов, начинающихся с плейсхолдера. Отдельно проверяется обращение к пользователю: внутри фразы русский интерфейс пишет «вы» со строчной, а «Вы» с заглавной — только в начале предложения, где это просто орфография. Наконец, пакет сверяется сам с собой: одну и ту же английскую фразу он обязан переводить одним способом. Если два namespace дают разные русские предложения (считаются шаблоны от четырёх слов — короткая подпись законно зависит от контекста), сборка падает. Так нашёлся confirm.description: один вариант обещал «пропускать шаги подтверждения», другой — «уменьшать число шагов», а английское «subsequent tasks» во втором стало «текущей задачей». Намеренное расхождение объявляется в scripts/one-rendering.json вместе с причиной, и устаревшее исключение тоже валит сборку — иначе список решений тихо расширял бы проверку. Обратное направление печатается справочно: одинаковый русский ответ на разные английские фразы от четырёх слов — это след копипасты (подсказка, приехавшая от соседнего ключа) либо два разных факта, слитых в одну фразу. Гейтом это быть не может: русский законно сливает слова, которые английский различает, — поэтому обе стороны печатаются рядом, и решение принимает человек.

За свежестью тега следит отдельный workflow: watch-upstream раз в неделю сравнивает закреплённый тег с тегами харнесса, при новом открывает issue со списком шагов и красит прогон — чтобы отставание находилось по расписанию, а не по чужому скриншоту. Сравнение версий проверяется без сети (npm run check:upstream: порядок предрелизов, равенство версий, переход между линиями) и входит в verify: релиз должен быть новее собственных предрелизов, иначе дозор срабатывал бы вечно.

Число покрытия не является гейтом: часть разделов пакет сознательно оставляет на английском. Рядом печатается отчёт по namespace: аудит восстанавливает связь «namespace → словарь» по тому, кто его регистрирует (NS или литерал в locale.register; bind и PropsLocale только читают namespace), и показывает ключи, которых нет ни в своём namespace, ни в общем common, куда рантайм падает при поиске. Глобальное сравнение имён такие дыры не видит: перевод, лежащий под чужим namespace, считается покрытием, а экран в это время показывает английский. Отчёт справочный — одинаковое имя в разных namespace может значить разное (list.aria — «Активные напоминания» в каталоге и «Фоновые задачи» в задачах), поэтому перевод переносится в чужой namespace только там, где оба namespace обслуживает один и тот же словарь. На закреплённом теге отчёт пуст: каждая строка, которую харнесс рисует в нашем namespace, лежит именно в нём. Сверяются все 584 namespace пака — привязка строится и по импорту словаря рядом с регистрацией, и по именам, которые передаёт сама регистрирующая строка (locale.register(NS, { zh, en })); без второго правила common и settings.locale, чьи словари лежат в соседнем каталоге, оставались бы вне сверки. Обратная сторона проверяется жёстко: namespace, который харнесс регистрирует и наполняет ключами, а пак не регистрирует, — это отказ сборки, потому что такой экран остаётся английским, а покрытие по именам ключей этого не видит. Так нашёлся settings.sessionLog — строка «Загружать журнал сессии» на странице общих настроек.

Область покрытия: харнесс и словари плагинов

Пакет переводит собственные namespace клиента харнесса — 64 namespace сверенных с закреплённым тегом, — и словари сторонних плагинов: 520 плагинов, чей английский текст выгружен из их собственной публикации вместе с версией и лицензией.

Поиск по реестру npm — шесть запросов вместо одного «dsh» — нашёл ещё 40 плагинов со своим словарём. 39 из них переведены; три имени (dsh-automation, remote, settings.ip-pool) уже заняты словарями других плагинов и оставлены прежним владельцам, чтобы не подменить перевод чужого продукта. Итог на 22 октября 2026: 584 namespace, 67 666 значений, 520 словарей, 47 700 различных русских строк в собранном пакете. Замер конкурентов тем же методом — docs/competitors.md.

Раньше словари плагинов в область не входили, и на то была причина: у dshmarket уже версия 1.66.44, её ключи меняются независимо от харнесса, а молчаливое обещание «покрыто всё» — это не обещание, а долг, который нельзя предъявить. Ответ оказался простым: чужой английский текст выгружается (npm run fetch:plugins) и хранится рядом с переводом — с именем пакета, версией и лицензией, а аудит сверяет наш перевод именно с этим снимком, а не с чужим русским. Мы проверили 17 самых скачиваемых плагинов экосистемы (npm, keywords:dsh-plugin, скачивания за месяц) и посмотрели, какие из них вообще поставляют собственные строки:

Что обнаруженоПлагинов
Своих строк нет — интерфейс берёт текст из namespace харнесса11 из 17
Крупный собственный словарь (подтверждено вручную)2 — dshmarket (733 ключа), @nanmicoder/dsh-agent-teams (420)
Только типы .d.ts, строк нет1 — dsh-plugin-model-proxy
Требует отдельной проверки3

У 11 из 17 популярнейших плагинов русский интерфейс уже работает без отдельного словаря: их текст лежит в общих namespace харнесса, которые пакет переводит полностью. Словари есть там, где плагин везёт свои строки, — их 32, и у каждого зафиксирована версия, с которой выгружен английский текст.

Такой словарь — обязательство следить за чужими релизами, но теперь оно проверяемое: новая версия плагина с другими ключами видна как расхождение снимка, а не как тишина. Нужен конкретный плагин — заведите issue: словарь для него возможен как отдельный слой, привязанный к версии, а не как молчаливое обещание «покрыто всё».

Разработка

pnpm install
pnpm run build     # tsdown -> lib/index.js (node half) + lib/client.js (client bundle)
npm pack           # -> ragnoryok1-dsh-client-locale-ru-<version>.tgz

lib/client.js собирается в формате, который понимает клиентский загрузчик dsh (__ModuleLoader__.load), и экспортирует inject/apply.

Релизы

Публикация в npm выполняется workflow publish по тегу — учётные данные лежат в секрете репозитория (NPM_TOKEN), поэтому токен не нужно ни вводить в терминал, ни пересылать. Ручная публикация с машины возможна, но не нужна.

npm version 0.3.0 --no-git-tag-version      # поднять версию в package.json
# …и синхронно обновить версию в блоке deepseek-harness-meta в этом README
git commit -am "release: 0.3.0" && git tag v0.3.0 && git push origin v0.3.0

Перед публикацией workflow проверяет:

  1. версия в теге совпадает с версией в package.json;
  2. версия в блоке deepseek-harness-meta совпадает с package.json — маркетплейс берёт её оттуда, причём читает только при первой индексации, поэтому расхождение не исправляется само;
  3. типографику (18 правил);
  4. аудит локализации против закреплённого тега харнесса — мёртвые namespace, дубли и пары форм числа упадут и остановят публикацию;
  5. совместимость со всеми версиями из compatible_versions: для каждой скачивается её рантайм локали с npm и против него прогоняются три набора — сосуществование языков, формы числа и собранные фразы (npm run check:compat, входит в CI) — обещание в meta-блоке проверяется, а не подразумевается.

Отдельно проверяется само объявление совместимости (npm run check:peers, входит в verify): харнесс читает наши peerDependencies для @deepseek-ai/dsh* не как версии пакетов, а как диапазон версий рантайма и с includePrerelease — и если диапазон не удовлетворит работающий dsh, пользователь увидит предупреждение о несовместимости и запрос на исключение. Скрипт прогоняет это правило харнесса по всем заявленным версиям: сейчас проходят все восемь.

Проверить всё то же локально, без публикации:

npm run verify -- путь/к/дереву/харнесса

Для workflow есть ручной запуск с переключателем «только проверки, без публикации» (workflow_dispatch → dry-run).

Содержимое

  • src/client/dicts.ts — русские словари: 584 namespace и 67 666 строк, файл 71 453 строки. Это и есть основная ценность.
  • src/client/index.ts — точка входа клиентского плагина (регистрация ru + словарей).
  • src/index.ts — пустая host-половина (apply()).
  • cordis.patch.yml — профиль-патч (- insert: клиентской строки locale-ru).

Что переведено

Актуальный набор — по тегам харнеса: ключи сняты с профильного коммита, а добавленные позже падают на en при поиске, поэтому пакет не ломает интерфейс на новых версиях.

0.1.7 — исправлен мёртвый namespace, переведён менеджер задач, переписаны числительные

Главное в релизе — исправление ошибки из 0.1.6. Тогда было записано, что namespace schedule.catalog упразднён, а его место занял schedule.manager. На деле в харнесе оба namespace живут и по отдельности: schedule.catalog — это каталог напоминаний в шапке сессии с частотами и единицами, schedule.manager — новый менеджер задач автоматизации. Из-за неверного вывода ~30 строк переводов (напоминания, частота, единицы времени) были зарегистрированы под именем, которое никто не читает, и никогда не показывались в интерфейсе. Теперь каталог зарегистрирован как schedule.catalog.

  • исправлено: переводы каталога расписания снова видны — trigger.*, list.*, delete.*, frequency.*, cron.*, unit.*, relative.*, mark.aria, hover.more;
  • добавлен schedule.manager (188 ключей) — менеджер задач автоматизации целиком на русском: панель и каталог задач, поиск, фильтр состояний, сведения о задаче и её вкладки, журнал запусков с правилами хранения, редактор расписания (дата, время, час, минута, секунда, часовой пояс, интервал повтора), правила повтора (разово, каждые N минут/часов/ секунд, ежедневно, пн–пт, еженедельно, свой cron), cron-форма с выбором дат и минуты, удаление с подтверждением, уведомления и карточки;
  • числительные переписаны (17 пар ключей): формы, которые ломались на числах 2–4, заменены на корректные при любом n ≥ 2 — например «2 субагентов» → «Субагентов: 2», «каждые 2 часов» → «каждые 2 ч». Ещё 8 строк с {count} перед склоняемым словом переведены на сокращения: «ещё 3 строк» → «ещё 3 стр.»;
  • добавлено 7 ключей, которые отсутствовали: blocked.composer, defaultWorkspace.title, schedule.active, settings.transcript.expanded, status.scheduled, status.overdue и namespace shortcuts.layout (подпись команды показа левой панели);
  • новая проверка в проекте: аудит имён namespace. Прежняя проверка покрытия сверяла ключи внутри namespace, но не сверяла сами имена, поэтому целый namespace мог быть зарегистрирован под несуществующим именем и тихо не работать. Теперь имена извлекаются из всех способов их объявления (const NS/SETTINGS_NS/namespace, locale.register, locale.bind, PropsLocale<…>) и сравниваются множествами.

В 0.1.2 добавлены разделы, которых не было в 0.1.1: open-in-app («Открыть в приложении»), sidebarFiles, sidebarRight (правый сайдбар с файлами) и sidebarCodePreview (предпросмотр кода). Также обновлены ключи, изменившиеся в харнесе 0.1.5, и удалены 21 ключ, которых в нём больше нет.

В 0.1.3 пакет догнал харнес 0.1.6-alpha.1: добавлено 139 ключей и 7 новых разделов — sidebarTerminal (терминал в правом сайдбаре), settings.archivedSessions (архивные сессии) и семейство предпросмотра документов (sidebarDocumentPreview, documentHtml, sidebarImage, documentMarkdown, sidebarPdf). Кроме этого переведена экспериментальная «Автопроверка» (permission.access: auto.*), подписи и токены палитры команд, поля эндпоинтов в настройках моделей и изменения в conversation, trajectory, chat, session-log-download. 28 ключей, исчезнувших из харнеса, удалены.

Проверка покрытия выполняется по исходникам харнеса: для каждого namespace сравниваются множества ключей, поэтому следующий выпуск начинается с точного списка «добавить / проверить / удалить».

В 0.1.6 пакет догнал харнес 0.1.7-rc.2: добавлено 252 ключа, 18 обновлены, 26 удалены, добавлены два новых namespace. Изменения:

  • shortcuts (новый namespace, 56 ключей) — редактор горячих клавиш: запись сочетания, конфликты, зарезервированные комбинации, подсказки для macOS и Windows, восстановление значений по умолчанию;
  • schedule.manager (70 ключей на тот момент) — менеджер задач автоматизации: список, удаление, повтор, история запусков, выражения Cron. Ошибочно было записано, что namespace schedule.catalog при этом упразднён; в 0.1.7 это исправлено — оба namespace существуют параллельно;
  • settings.account (50 ключей) — первый запуск приложения: приветствие, выбор назначения и глубины показа хода работы, пополнение баланса, выход из учётной записи во время выполнения задач;
  • добавлены подписи добавления и удаления инструментов на ходу (message.tools*, trajectory.layout.*), команды правой боковой панели (sidebarRight), состояния «сначала выберите сессию» в панелях, обновлено название раздела настроек: «Инструменты для кода» вместо «Инструментов разработчика»;
  • 18 ключей обновлены под изменившийся английский текст, 26 удалены. Единый термин «рабочая папка» вместо «рабочей области» в одном месте.

В 0.1.5 пакет догнал харнес 0.1.7-rc.1: добавлено 49 ключей, 13 обновлены, 16 удалены, namespace directory-browser убран (в rc.1 его больше нет). Появились подписи шагов работы инструментов (message.stepProcess.prepare.* и done.* — чтение изображений, запись файлов, подготовка к поиску по коду, веб-поиску, координации субагентов и другие), просмотр изображений во весь экран (image.*), режимы показа ходов «Стандартный» и «Подробный», установка плагинов из GitHub с таймаутом и китайским зеркалом, предупреждение о несовместимой версии плагина, выбор источника загрузки моделей для голосового ввода и сообщения команды Cordis. Уточнены формулировки, где upstream заменил «teammate/agent» на «subagent», а «Beta» — на «Experimental».

Также в 0.1.5 исправлена единица счёта в инвентаре плагинов: было «187 плагины», стало «187 плагинов». Переведены и встроенные снимки интерфейса, добавлены npm keywords и исправлен peer-диапазон @deepseek-ai/dsh-client-locale (>=0.1.0-rc.2 <0.2.0) — раньше ^0.1.0 не разрешался, потому что пакет публикуется только под prerelease-версиями.

В 0.1.4 пакет догнал харнес 0.1.7-alpha.2 — самый крупный скачок: добавлено 905 ключей, 29 изменены, 126 удалены. Новые разделы:

  • pluginManager — встроенная панель плагинов: установка, удаление, включение и отключение компонентов, версии, реестры и подсказки по установке;
  • settings.account — учётная запись DeepSeek: вход, баланс, расход, API-ключ;
  • отдельные разделы настроек, на которые разъехался прежний settings.plugins: settings.agentLoop, settings.shell, settings.subagent, settings.webSearch;
  • sidebarBrowser — встроенный браузер в правой панели (адрес, песочница, восстановление страницы);
  • sidebarExcel и sidebarOffice — предпросмотр таблиц и документов Office; масштабирование (zoom.*) добавлено в PDF и изображения;
  • voice-input — экспериментальный голосовой ввод.

Также переведены новые тексты в conversation (+194), chat (+53), workspace (+43: архив сессий, закрепление), deliverables (+31: обзор изменений хода), job (+24: живой вывод фоновых задач), settings (+22: обновление десктопного приложения), plan, open-in-app, trajectory, model, reference, session-log-download и в руководствах по режимам агента (settings.agentPreset, 12 длинных текстов). Раздел settings.archivedSessions удалён: в 0.1.7 upstream убрал этот пакет, а архив сессий переехал в workspace.

Лицензия

MIT

История изменений

CHANGELOG.md — что было в каждом выпуске.

Plugin correlati