Перейти к содержимому

Локализация (i18n)

Перевод пользовательских строк (описания команд, параметры, тексты подтверждений) на разные языки. Этот документ покрывает конфигурацию, формат файлов и валидацию.

Что переводится:

  • Пользовательских команд: description, confirmation_text и описания параметров.
  • Группы команд: title и description (отображаются в TUI-браузере команд).
  • Заголовки секций и подписи свойств markdown-генератора (## Properties, ## Parameters, **Working directory** и т. д.).

Что НЕ переводится:

  • Собственные описания cobra-команд DWE (dwe deploy, dwe run, dwe docs и т. д.) — в v1 они остаются английскими. Это применимо только к пользовательским командам проекта и UI-строкам.
  • Сообщения об ошибках и логи — они машиночитаемые и всегда на английском.
  • Длинная продуктовая документация под docs/reference/ — она находится в отдельном неймспейсе.

Ключевой принцип дизайна: YAML-файлы команд остаются на 100% английскими (это канонический источник); переводы хранятся в sidecar-файлах по известной схеме. Авторы и переводчики не мешают друг другу.

DWE выбирает активную локаль по следующей цепочке приоритетов (от высшего к низшему):

  1. Флаг --lang — принимается каждой подкомандой dwe docs (show, list, search, export, generate, llms-txt). Применяется на один вызов, не сохраняется.
  2. Поле language в userconfigDWE_LANGUAGE переопределяет значение, загруженное из файла userconfig в этом слоте.
  3. Системная переменная окружения $LANG — парсится в 2-буквенный код (ru_RU.UTF-8ru; C и POSIX игнорируются).
  4. По умолчанию: en (английский).

Коды вроде ru-RU, ru_RU или ru_RU.UTF-8 нормализуются в ru на каждом уровне. Пустые значения и C/POSIX пропускаются, и цепочка продолжается со следующим источником.

Окно терминала
# Высший приоритет: флаг --lang на любой подкоманде docs
dwe docs show config/services/fields --lang ru
dwe docs list --lang ru
dwe docs generate --lang ru
# Через userconfig (~/.config/dwe/config или .dwe/config)
# language: de
dwe commands list
# → Выбирает немецкий
# Через переменную окружения — переопределяет поле `language` в userconfig
DWE_LANGUAGE=fr dwe commands list
# → Выбирает французский
# Через системный $LANG (используется только когда не задан флаг/конфиг/env)
LANG=es_ES.UTF-8 dwe commands list
# → Выбирает испанский
# Когда локаль не задана, используется английский
dwe commands list
# → Выбирает английский

Переводы лежат в YAML-файлах уровня проекта в директории workspace/i18n/. Глобального/пользовательского каталога переводов не существует; переводы — по проекту.

Расположение переводов проекта:

<project>/
workspace/
i18n/
ru.yml # русский
de.yml # немецкий
fr.yml # французский
# ... любой 2-буквенный код языка

Отсутствие директории workspace/i18n/ молча трактуется как пустота — система откатывается на английский.

Файлы переводов используют YAML-синтаксис со строгой валидацией полей — неизвестные ключи вызывают ошибку разбора (отлавливается dwe validate).

Валидный файл (ru.yml):

ui:
docs.section.properties: "Свойства"
docs.section.command: "Команда"
commands:
build.docker:
description: "Собрать образ Docker"
confirmation_text: "Вы уверены?"
params:
tag:
description: "Тег образа"
groups:
build:
title: "Сборка"
description: "Команды сборки"

Невалидный файл (опечатка в имени поля — строгий декод её отлавливает):

commands:
build.docker:
descripton: "..." # ← опечатка: "descripton" вместо "description"
# → ошибка строгого декода при загрузке

Строгая валидация ловит опечатки рано. Запустите dwe validate, чтобы вынести наружу любые проблемы.

Эти ключи заполняются английской базой, которая поставляется внутри бинарника dwe, и могут переопределяться или расширяться в файлах проекта.

Ключи этого неймспейса идут под блоком ui: в вашем YAML-файле — пишите голое имя ключа без префикса ui.:

ui:
docs.section.properties: "Propriétés"
docs.property.id: "Identifiant"

Заголовки секций (markdown-генератор):

  • docs.section.properties → “Properties”
  • docs.section.command → “Command”
  • docs.section.parameters → “Parameters”
  • docs.section.context → “Context”
  • docs.section.environment → “Environment Variables”
  • docs.section.with → “With”
  • docs.section.script → “Script”
  • docs.section.argv → “Argv”
  • docs.section.files → “Files”
  • docs.section.steps → “Steps”

Подписи свойств (в таблицах свойств и inline-описаниях):

  • docs.property.id → “ID”
  • docs.property.type → “Type”
  • docs.property.group → “Group”
  • docs.property.private → “Private”
  • docs.property.confirmation → “Confirmation”
  • docs.property.confirmation_text → “Confirmation text”
  • docs.property.success_message → “Success message”
  • docs.property.error_message → “Error message”
  • docs.property.shell → “Shell”
  • docs.property.service → “Service”
  • docs.property.workdir → “Working directory”
  • docs.property.builtin → “Builtin”
  • docs.property.compose_args → “Compose args”
  • docs.property.argv_append_from → “Argv append from”
  • docs.property.script → “Script”

Метки workflow (рендеринг секции Steps):

  • docs.workflow.parallel → “parallel”
  • docs.workflow.sub_steps → “sub-steps”

Модальное окно помощи TUI (?-окно в браузере команд и переменных):

  • tui.help.title → “Help”
  • tui.help.section.navigation → “Navigation”
  • tui.help.section.panels → “Panels”
  • tui.help.section.actions → “Actions”
  • tui.help.section.general → “General”
  • tui.help.action.focus.next → “Focus next panel”
  • tui.help.action.focus.prev → “Focus previous panel”
  • tui.help.action.help → “Toggle help”
  • tui.help.action.quit → “Quit”
  • tui.help.action.nav.up / .down / .left / .right → “Move up/down/left/right”
  • tui.help.action.nav.top → “Go to top”
  • tui.help.action.nav.bottom → “Go to bottom”
  • tui.help.action.nav.page-up / .page-down → “Page up/down”
  • tui.help.action.filter → “Filter”
  • tui.help.action.inspect → “Inspect”
  • tui.help.action.cmd.skip-confirm → “Skip confirmation”
  • tui.help.action.cmd.force-form → “Edit parameters”

Метка действия select намеренно не вынесена в ключ — она зависит от режима (Select в браузере команд, Edit в браузере переменных) и берётся из описания привязки, а не из ключа перевода.

Команды, определённые проектом (под workspace/commands/), могут иметь переводы. Структура ключа зеркалит ID и структуру команды:

commands:
<group>.<name>: # например, "services.main.db.migrate"
description: "..."
confirmation_text: "..."
messages:
success: "..."
error: "..."
params:
<paramName>: # например, "force"
description: "..."
options:
<value>: "..." # например, "prod": "Production"

Все поля необязательны; опущенные поля откатываются на английские значения из YAML-файла команды. Пример:

# workspace/commands/tools/deploy.yml (английский источник)
- id: deploy
description: "Deploy the application"
confirmation_text: "Deploy now?"
messages:
success: "Deployment completed successfully"
error: "Deployment failed"
params:
- name: env
description: "Environment (dev / prod)"
# workspace/i18n/ru.yml (русский перевод)
commands:
tools.deploy:
description: "Развернуть приложение"
# confirmation_text опущен → используется английское "Deploy now?"
messages:
success: "Развертывание завершено успешно"
error: "Развертывание не удалось"
params:
env:
description: "Окружение (разработка / производство)"
options:
dev: "Разработка"
prod: "Производство"

Группы команд (наборы связанных команд) могут иметь переведённые заголовки и описания:

groups:
<groupId>: # например, "services.main.db"
title: "..." # заголовок группы
description: "..." # описание группы

Пример:

workspace/i18n/ru.yml
groups:
services.main:
title: "Основные сервисы"
description: "Управление основными компонентами приложения"
services.tools:
title: "Инструменты"
description: "Утилиты и вспомогательные команды"

Встроенная английская база включена в каждый бинарник DWE. Вам не нужно создавать workspace/i18n/en.yml, если только вы не хотите переопределить встроенные UI-строки:

# workspace/i18n/en.yml (опционально; обычно не нужен)
ui:
docs.section.properties: "Properties"
commands:
myapp.deploy:
description: "Deploy the application"

Типичный файл русского перевода:

workspace/i18n/ru.yml
ui:
docs.section.properties: "Свойства"
docs.section.command: "Команда"
docs.section.parameters: "Параметры"
docs.section.context: "Контекст"
docs.section.environment: "Переменные окружения"
docs.section.with: "С"
docs.section.script: "Скрипт"
docs.section.argv: "Argv"
docs.section.files: "Файлы"
docs.property.id: "ID"
docs.property.type: "Тип"
docs.property.group: "Группа"
docs.property.private: "Приватный"
docs.property.confirmation: "Подтверждение"
docs.property.confirmation_text: "Текст подтверждения"
docs.property.success_message: "Сообщение об успехе"
docs.property.error_message: "Сообщение об ошибке"
docs.property.shell: "Shell"
docs.property.service: "Сервис"
docs.property.workdir: "Рабочая директория"
docs.property.builtin: "Встроенная"
commands:
myapp.deploy:
description: "Развернуть приложение"
confirmation_text: "Развернуть?"
messages:
success: "Приложение успешно развернуто"
error: "Развертывание не удалось"
params:
env:
description: "Окружение (dev/prod)"
options:
dev: "Разработка"
prod: "Производство"
myapp.rollback:
description: "Откатить развертывание"
groups:
myapp:
title: "Основное приложение"
description: "Команды для управления основным приложением"

Команда dwe validate проверяет файлы переводов на типичные проблемы:

  1. Ошибки разбора — строгая YAML-валидация ловит опечатки в именах полей (например, descripton: вместо description:). Исправьте файл и перезапустите dwe validate.

  2. Сиротские записи — перевод ссылается на команду или группу, которой больше нет в workspace/commands/. Это предупреждение (перевод безвреден, но не используется). Удалите сиротскую запись или переименуйте её, чтобы она соответствовала существующей команде.

  3. Неизвестные UI-ключи — ключ ui.*, которого нет в каноническом whitelist’е. Это предупреждение. Если ключ намеренный (например, кастомная UI-строка для будущей фичи), заведите запрос в issue-трекере проекта, чтобы добавить его в whitelist.

Пример вывода валидации:

Окно терминала
$ dwe validate
Diagnostics: 3 warnings, 0 errors
i18n.orphan [warning] workspace/i18n/ru.yml
Translation references command "old.command" that no longer exists
Hint: Rename or remove the entry
i18n.unknown_ui_key [warning] workspace/i18n/ru.yml
Unknown ui key "ui.custom.label"
Hint: Unknown ui key; if intentional, file a request to add it to the canonical set
No errors detected.

Все предупреждения информационные. Чтобы они блокировали CI, используйте dwe validate --strict.

DWE_LANGUAGE подставляется в загрузчик userconfig на старте; он перекрывает любое значение language, которое задано в ~/.config/dwe/config или в локальном конфиге проекта. Стоит ниже явного флага --lang и выше системной переменной $LANG:

Окно терминала
# Переопределить язык для одной команды (env побеждает userconfig и $LANG)
DWE_LANGUAGE=ru dwe commands list
# Закрепить на сессию shell
export DWE_LANGUAGE=de
dwe commands list # → немецкий
# Явный --lang всё равно побеждает DWE_LANGUAGE
DWE_LANGUAGE=de dwe docs show config/services/fields --lang ru
# → Рендерится на русском

Сгенерировать документацию на определённом языке:

Окно терминала
# Сгенерировать немецкую документацию
dwe docs generate --lang de
# Документация записывается в docs/reference/commands/de/
# Английская документация — в docs/reference/commands/en/

Флаг --lang принимает любой 2-буквенный код языка. Если локаль недоступна в вашем проекте, DWE откатывается на английский. Сгенерированная документация всегда живёт под commands/<lang>/.

Пользовательские команды и сгенерированная документация командного справочника локализуются через YAML-стор, описанный выше. Длинная справочная документация под docs/reference/ использует отдельный markdown-неймспейс (см. Переводы длинной документации ниже).

Собственные описания cobra-команд DWE (dwe deploy, dwe run, dwe docs, …) и сообщения об ошибках во время выполнения остаются английскими.

Отсутствующие файлы языков:

  • Если workspace/i18n/ не существует, все переводы откатываются на английский.
  • Если workspace/i18n/ru.yml отсутствует, но LANG=ru_RU.UTF-8, DWE откатывается на английский (молча; без предупреждения).

Отсутствующие отдельные ключи:

  • Если файл перевода содержит commands.deploy.description, но не commands.deploy.confirmation_text, текст подтверждения остаётся английским.
  • Если ключ ui.* отсутствует, используется английский откат.

Эта плавная деградация гарантирует, что частичные переводы всегда работают корректно — переведённые и непереведённые строки сосуществуют в одном интерфейсе.

DWE разделяет локализацию на два различных неймспейса:

  1. Строки команд/UI (этот документ): YAML-файлы под workspace/i18n/<lang>.yml. Переводы описаний команд, параметров, UI-кнопок и заголовков секций сгенерированной документации.
  2. Длинный markdown: markdown-файлы под docs/i18n/<lang>/reference/..., docs/i18n/<lang>/guides/... и docs/i18n/<lang>/internals/.... Переводы встроенной справочной документации, ориентированных на задачи руководств и архитектурных заметок.

Эти неймспейсы используют разные загрузчики, разные валидаторы и разные форматы файлов. Они НЕ сливаются и не разделяют переводы.

Встроенная (английская):

docs/
reference/ # пользовательский справочник
config/
workspace.md
services/
index.md
fields.md
...
...
guides/ # ориентированные на задачи руководства
add-a-service.md
daily-workflow.md
...
internals/ # архитектурные и контрибьюторские документы
packages.md
architecture.md
...

Переводы:

docs/
i18n/
ru/ # русский
reference/ # зеркалит docs/reference/
config/
workspace.md # русский перевод
services/
index.md
fields.md
guides/ # зеркалит docs/guides/
add-a-service.md
internals/ # зеркалит docs/internals/
packages.md
de/ # немецкий
reference/
config/
workspace.md
internals/
...
fr/ # французский (и т. д.)
...

Каждый переведённый файл — это самостоятельный markdown-файл в том же месте, что и его английский аналог, но под директорией i18n/<lang>/. Все три дерева — reference/, guides/ и internals/ — включены в манифест устаревания и проходят одну и ту же проверку хэша контента во время выполнения.

Переведённые markdown-файлы включают строку-заголовок, которая фиксирует, когда перевод был в последний раз синхронизирован с английской версией:

> Translated from: config/workspace @ ec4f57457d87
# DWE Configuration
...

Формат:

> Translated from: <relative-path> @ <hash>
  • <relative-path> — путь к английскому файлу-источнику относительно docs/ (например, reference/config/workspace, internals/architecture). Расширение .md опускается.
  • <hash> — первые 12 символов SHA256-хэша от байтов контента английского файла-источника.

Пример правильно отформатированного заголовка:

> Translated from: reference/config/services/index @ ec4f57457d87
# Services Configuration
This section describes how to configure services...

Как вычисляется хэш:

  1. Процесс сборки DWE (make build) обходит docs/reference/, docs/guides/ и docs/internals/ (плюс корневой README.md репозитория).
  2. Для каждого markdown-файла он вычисляет sha256(file_bytes) и берёт первые 12 hex-символов.
  3. Эти хэши встраиваются в бинарник dwe как манифест.
  4. Манифест коммитится в репозиторий, чтобы каждый бинарник, собранный из одного и того же исходного кода, видел одни и те же хэши.

Почему хэш контента, а не git commit SHA:

  • Хэш контента стабилен при ребейзах, cherry-pick’ах и переименованиях файлов. Git SHA меняется при каждом ребейзе.
  • Хэш контента работает на свежих чекаутах из tarball (нет директории .git/). Git SHA требует локальной истории git.
  • Хэш контента прозрачен для переводчиков: они могут вычислить и вставить хэш без знания git.

Проверка устаревания во время выполнения:

  1. Когда вы просматриваете переведённый документ через dwe docs show, dwe docs export или TUI, DWE читает переведённый файл и парсит заголовок с хэшем контента (regex: ^>\s*Translated from:\s*\S+\s*@\s*([0-9a-f]{12,64})\s*$).
  2. Он сравнивает разобранный хэш с встроенным манифестом.
  3. Если совпадают → перевод актуален (без баннера).
  4. Если отличаются → перевод устарел (показан info-баннер).
  5. Если запись манифеста отсутствует или пуста → проверка отключена (без баннера); это страховка для новых файлов или пустого манифеста на свежем чекауте.

Пользовательский опыт:

  • Актуальный перевод: Рендерится как есть, без баннера.
  • Устаревший перевод: Рендерится с предупреждающим баннером. Точная формулировка зависит от контекста (фактические значения хэша контента в баннер не подставляются):
    • В TUI-браузере:
      ⚠ This translation is outdated (last synced at previous version, current is newer). Press `e` to view the English version.
    • В dwe docs show / dwe docs export:
      ⚠ Warning: This translation is outdated. Use `--lang en` to view the English version.
  • Отсутствующий перевод: Рендерится английская версия с info-баннером:
    ℹ Translation not available for `ru`. Showing English version.

Чтобы добавить или обновить перевод длинного markdown’а:

  1. Скопируйте английский файл:

    Окно терминала
    cp docs/reference/config/services/index.md docs/i18n/ru/reference/config/services/index.md
    cp docs/reference/config/services/fields.md docs/i18n/ru/reference/config/services/fields.md
  2. Переведите контент (сохраните заголовок):

    > Translated from: reference/config/services/index @ <english-hash>
    # Конфигурация сервисов
    ...
  3. Получите английский хэш — первые 12 hex-символов от sha256(file_bytes):

    Окно терминала
    sha256sum docs/reference/config/services/index.md | cut -c1-12
    # Вывод: a1b2c3d4e5f6
  4. Обновите заголовок:

    > Translated from: reference/config/services/index @ a1b2c3d4e5f6
  5. Создайте pull request с обоими файлами — исходным и переведённым. CI проверяет, что хэш из заголовка соответствует встроенному манифесту.

Разрешение локали для длинной документации

Заголовок раздела «Разрешение локали для длинной документации»

Когда вы запускаете dwe docs show, dwe docs list, dwe docs export или пользуетесь TUI, активная локаль определяется так:

  1. Флаг --lang (только подкоманды docs; например, dwe docs show config/services/fields --lang ru)
  2. Переменная окружения DWE_LANGUAGE
  3. Настройка language в userconfig
  4. Системный $LANG (парсится в 2-буквенный код)
  5. По умолчанию: en

Важно: Разрешение локали для документации не зажато (unclamped). Строки команд/UI используют зажатую локаль (из YAML-стора переводов), а длинные документы используют сырой код локали, чтобы искать в дереве docs/i18n/<lang>/.... Это позволяет иметь разные уровни завершённости переводов в каждом неймспейсе: у вас могут быть французские переводы команд, но только английские длинные документы.

Команда dwe validate сейчас НЕ проверяет переводы длинного markdown’а (см. ниже «Связанные команды»). Несоответствия формата заголовка и хэша всплывают во время выполнения, когда вы просматриваете документацию, а не во время валидации.

Последующий трек (домен docs.* в фреймворке валидации) запланирован на v2, чтобы выносить устаревшие переводы во время CI, но v1 держит валидацию простой (только строки команд/UI).

  • dwe docs show <topic> — отображает документацию с автоматическим откатом по языку
  • dwe docs list — перечисляет доступные темы и языки
  • dwe docs export <dir> [--lang <code>] — экспортирует документацию с пофайловым откатом
  • dwe docs cache clear — очищает кеш mermaid-диаграмм
  • dwe docs — открывает интерактивный TUI-браузер
  • dwe commands list — отображает описания команд в активной локали
  • dwe commands <id> — показывает переведённые детали команды и тексты подтверждения
  • dwe docs generate --lang <code> — генерирует документацию на конкретном языке
  • dwe validate — проверяет файлы переводов (только строки команд/UI; валидация длинной документации запланирована)