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.
Решение
- 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, и он — эталон тестов паритета. - Коды —
pt-BR,en,ruиzh-Hans, одни и те же в Docusaurus, в i18next, в<html lang>и вusers.locale. Локальный поиск использует свои коды (pt,en,ru,zh). - Разрешение locale в интерфейсе: выбор, записанный в учётной записи, побеждает всегда
и никогда не перезаписывается определением. Без выбора подсказывает браузер:
pt*→pt-BR;zh,zh-CN,zh-SGиzh-Hans*→zh-Hans;ru*→ru;en*→en. - Язык без каталога падает на pt-BR (решение владельца): немецкий, традиционный китайский и любой другой открываются на языке по умолчанию, а не на английском. Текст, отсутствующий в locale, падает на источник pt-BR — и в интерфейсе он не отсутствует, потому что паритет отклоняет.
- Переключение сайта — один PR, через
git mv: текущий английский уходит вwebsite/i18n/en/; АКТУАЛЬНЫЕ переводы pt-BR заменяют источник; устаревшие и отсутствующие оставляют страницу на том языке, на котором она есть, до её пакета, с предупреждением; аwebsite/i18n/pt-BR/docusaurus-plugin-content-docsуходит в ТОМ ЖЕ PR, иначе папка locale по умолчанию перекрыла быdocs/, и 97 устаревших копий попали бы в эфир. - Непереведённая страница или страница, чей источник изменился после перевода, ГОВОРИТ об этом,
на языке читающего: обёртка
DocItem/Contentотличает источник от перевода поmetadata.source, а каждая переведённая страница несёт во frontmattertraducao_de: <commit da fonte>. - Паритет ИЗМЕРЯЕТСЯ, а отчёт ГЕНЕРИРУЕТСЯ
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. - README — это витрина, по образцу photocraft, с pt-BR как источником и
README.en.md,README.ru.mdиREADME.zh-Hans.md. Переводы не несут версии и производных подсчётов: они ссылаются на pt-BR, который и проверяется. - ADR 0001–~0103 возвращаются к исходному тексту на pt-BR в
docs/adr/(решение владельца), а английский уходит вwebsite/i18n/en/. Это не редактирование принятого решения: это восстановление текста, который был принят и который сегодня находится в копии pt-BR. Действует только для копии, которая байт в байт совпадает с текстом commit создания; расходящаяся остаётся как есть и указывается в отчёте о паритете. - Пока не пришли пакеты английского, английский сайт показывает на португальском
RN и недавние ADR, с предупреждающей полосой (решение владельца). А
старые ссылки
/brabo/<ambiente>/pt-BR/…переписываются 404 корня в/brabo/<ambiente>/…, как/main/→/prd/из ADR 0073; английский уходит из корня в/brabo/<ambiente>/en/…(решение владельца). - Фазы. Фаза 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), а не интерфейса.