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

ADR 0216 — Четыре языка, с pt-BR как ИСТОЧНИКОМ и языком по умолчанию: документация и интерфейс на португальском, английском, русском и упрощённом китайском

Статус​

Accepted. 2026-10-15 (AT-545, эпик EP-032; решения владельца от 15.10). Владелец запросил документацию (сайт и README) и интерфейс на четырёх языках — бразильском португальском (ПО УМОЛЧАНИЮ), английском, русском и мандаринском (упрощённый китайский), — ПОЭТАПНО, и ответил на четыре открытых вопроса этого ADR (см. Решение, пункты 4, 9 и 10). Образец README и измеряемой локализации: репозиторий storytold/photocraft (README.md, docs/localization.md, docs/localization-parity.md).

Тема: docs. Отменяет английский как язык интерфейса по умолчанию, пришедший из основы i18n (RN-432) без ADR, и defaultLocale: 'en' сайта. Ни один принятый ADR не редактируется: RN-432 получает пересмотр новой RN в PR интерфейса.

Контекст​

Измерено в origin/dev (f0a355fe5a):

  • Сайт объявляет defaultLocale: 'en' и locales: ['en', 'pt-BR'] (website/docusaurus.config.ts:109-116), а docs/ — дерево locale по умолчанию. Но из 261 файла docs/ (5,7 М символов) 92 написаны на pt-BR в теле — RN (business-rules.md, 1,58 М, и business-rules/autenticacao.md), ADR начиная с 0127 и история фаз, — около 2,7 М символов. Сайт «en» отдаёт этот текст на португальском. Оболочка сайта (боковая панель, navbar, подвал) тоже на pt-BR, без единого файла перевода.
  • Переводы в website/i18n/pt-BR/ покрывают 135 из 261 страницы, и у 97 из них источник изменён после последнего commit перевода. Ничто не говорит об этом ни читателю, ни автору PR: правило traducao-pt-br в docmap — warn и ничего не измеряет.
  • Из 100 ADR с копией pt-BR 66 байт в байт совпадают с текстом commit, создавшего ADR: ADR 0001–~0103 были написаны на португальском, а то, что лежит в docs/adr/, — перевод на английский.
  • У интерфейса en по умолчанию только в web (apps/web/src/lib/idioma.ts:38, i18n.ts:52); api уже записывает pt-BR по умолчанию в users.locale (apps/api/src/db/schema/iam.ts:87). Это 2.310 текстов в 27 namespaces, около 90 тысяч символов на язык.
  • Язык ОТВЕТОВ агентов уже является открытым списком BCP-47 (ADR 0177, RN-618/622) и не зависит от языка интерфейса.
  • Тема Docusaurus включает переводы для pt-BR, ru и zh-Hans (@docusaurus/theme-translations@3.10.2); zh-CN там не существует. Локальный поиск (@easyops-cn/docusaurus-search-local) сегментирует китайский через jieba и индексирует русский через lunr-languages.

Решение​

  1. pt-BR — ИСТОЧНИК и язык по умолчанию в обоих продуктах. На сайте docs/ становится деревом pt-BR (defaultLocale: 'pt-BR'), а en, ru и zh-Hans живут в website/i18n/<locale>/. Альтернатива — оставить английский источником и лишь открыть сайт на pt-BR через localeConfigs.<locale>.baseUrl — возможна в Docusaurus 3.10 и была отвергнута: каждый новый текст рождался бы на английском, а 2,7 М символов на португальском продолжали бы отдаваться под меткой английского. В интерфейсе pt-BR — язык web по умолчанию и fallbackLng, и он — эталон тестов паритета.
  2. Коды — pt-BR, en, ru и zh-Hans, одни и те же в Docusaurus, в i18next, в <html lang> и в users.locale. Локальный поиск использует свои коды (pt, en, ru, zh).
  3. Разрешение locale в интерфейсе: выбор, записанный в учётной записи, побеждает всегда и никогда не перезаписывается определением. Без выбора подсказывает браузер: pt* → pt-BR; zh, zh-CN, zh-SG и zh-Hans* → zh-Hans; ru* → ru; en* → en.
  4. Язык без каталога падает на pt-BR (решение владельца): немецкий, традиционный китайский и любой другой открываются на языке по умолчанию, а не на английском. Текст, отсутствующий в locale, падает на источник pt-BR — и в интерфейсе он не отсутствует, потому что паритет отклоняет.
  5. Переключение сайта — один PR, через git mv: текущий английский уходит в website/i18n/en/; АКТУАЛЬНЫЕ переводы pt-BR заменяют источник; устаревшие и отсутствующие оставляют страницу на том языке, на котором она есть, до её пакета, с предупреждением; а website/i18n/pt-BR/docusaurus-plugin-content-docs уходит в ТОМ ЖЕ PR, иначе папка locale по умолчанию перекрыла бы docs/, и 97 устаревших копий попали бы в эфир.
  6. Непереведённая страница или страница, чей источник изменился после перевода, ГОВОРИТ об этом, на языке читающего: обёртка DocItem/Content отличает источник от перевода по metadata.source, а каждая переведённая страница несёт во frontmatter traducao_de: <commit da fonte>.
  7. Паритет ИЗМЕРЯЕТСЯ, а отчёт ГЕНЕРИРУЕТСЯ pnpm docs:generate (docs/reference/paridade-de-traducao.md, generated: true; --check отклоняет устаревший файл): по locale — переведённые страницы и символы относительно источника, устаревшие страницы, дата ревизии, нативная ревизия и то, что остаётся без перевода по решению; в интерфейсе — ключи по namespace против pt-BR и формы множественного числа Intl.PluralRules (pt-BR: one/many/other; en: one/other; ru: one/few/many/other; zh-Hans: other). Письменные правила живут в docs/explanation/localizacao.md, с терминологической заметкой для каждого языка — что никогда не переводится: Brabo, имена агентов и ролей из глоссария, данные пользователя, команды и номера RN/ADR.
  8. README — это витрина, по образцу photocraft, с pt-BR как источником и README.en.md, README.ru.md и README.zh-Hans.md. Переводы не несут версии и производных подсчётов: они ссылаются на pt-BR, который и проверяется.
  9. ADR 0001–~0103 возвращаются к исходному тексту на pt-BR в docs/adr/ (решение владельца), а английский уходит в website/i18n/en/. Это не редактирование принятого решения: это восстановление текста, который был принят и который сегодня находится в копии pt-BR. Действует только для копии, которая байт в байт совпадает с текстом commit создания; расходящаяся остаётся как есть и указывается в отчёте о паритете.
  10. Пока не пришли пакеты английского, английский сайт показывает на португальском RN и недавние ADR, с предупреждающей полосой (решение владельца). А старые ссылки /brabo/<ambiente>/pt-BR/… переписываются 404 корня в /brabo/<ambiente>/…, как /main/ → /prd/ из ADR 0073; английский уходит из корня в /brabo/<ambiente>/en/… (решение владельца).
  11. Фазы. Фаза 1: переключение сайта, входные страницы (intro, getting-started, glossary и учебник от нуля до результата) на четырёх языках, четыре README, полный интерфейс на ru и zh-Hans и измеренный паритет. Фаза 2 и далее: пакеты по категории боковой панели × locale, по одному PR на каждый — сначала pt-BR для 97 устаревших страниц и 26 только на английском, затем английский для страниц pt-BR, затем ru и zh-Hans.

Последствия​

  • Docmap заменяет правило traducao-pt-br на traducao, warn и НИКОГДА block: требование перевода в каждом PR документации стоило бы четырёх переводов на изменение. Отставание сдерживают сгенерированный отчёт и полоса на странице.
  • Фраза, привязанная к коду (verificarFrasesAncoradasNoCodigo, подсчёты), на странице, ставшей pt-BR, отклоняется как CEGO, пока шаблон не догонит, в PR пакета, — намеренно. Сегодня их 19. То же касается заголовка, который ищет procedimentos-do-runbook.mjs, и названий в docs/adr/temas.yml, когда индекс перевернётся.
  • ancoras-de-rn.mjs начинает проверять RN трёх переведённых locale, а links-do-locale.mjs начинает знать en, ru и zh-Hans как locale с префиксом.
  • users.locale получает ru и zh-Hans (enum Postgres, DTO, сгенерированные типы). Язык ответов не меняет механизма — учётная запись на ru уже получает общую ориентацию по BCP-47, — а нативные тексты ориентации и определение кириллицы и Han остаются измеряемым улучшением, а не предпосылкой.
  • Объявленные издержки: сборка сайта компилирует четыре locale (примерно вдвое больше сегодняшнего, не измерено); индекс поиска растёт (не измерено); перевод всего — это около 2,9 М символов на английский и 5,3 М на каждый из русского и китайского; каждый PR, меняющий переведённый источник, должен запускать pnpm docs:generate; английский уходит из корня окружения в /en/.
  • Без нативной ревизии русский и китайский выходят как машинный перевод, проверенный агентом, и отчёт говорит «нативная ревизия: нет», пока человек не проверит.

Вне охвата​

  • docs/reference/** (генерируемое) остаётся вне перевода, а генератор продолжает писать на английском.
  • Языки сверх четырёх, традиционный китайский и письмо справа налево.
  • Перевод содержимого, которое производят пользователь и агенты (артефакты, сообщения): это язык ПРОЕКТА и ответов (ADR 0177), а не интерфейса.