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

I18n and Localization

Обновлено: 2026-07-16

Пользователь видит согласованный язык во всём продукте: в навигации, основном контенте, accessibility, системных сообщениях, metadata и platform-specific поверхностях. Добавление locale не создаёт набор условных веток в компонентах и не оставляет скрытые части продукта на fallback-языке.

Этот документ задаёт общий контракт. Конкретный список locale, редакционный процесс и обязательный объём перевода фиксируются в project-specific SDD.

  • Пользовательский текст хранится под стабильными semantic message IDs в одном catalog/provider слое.
  • Компоненты и domain logic не выбирают текст через locale === "...", позиционные массивы или дублированные словари.
  • Source locale и fallback locale объявляются явно. Отсутствующий обязательный ключ считается ошибкой сборки или теста, а не штатным runtime-сценарием.
  • Типы или schema должны подтверждать одинаковую форму обязательных catalog ключей. Dynamic content проверяется отдельной schema.
  • UI copy, product content, accessibility copy и storefront metadata могут иметь разные файлы и владельцев, но используют один locale lifecycle.
  • Brand names, identifiers, URLs, asset IDs и telemetry event names не переводятся без отдельного product contract.

Проект фиксирует порядок выбора locale. Базовый порядок Digitable:

  1. явный URL, embed или platform override;
  2. сохранённый выбор пользователя;
  3. locale host-platform или operating system;
  4. browser language preference;
  5. объявленный fallback locale.

Нормализация выполняется в одном адаптере:

  • входные значения приводятся к BCP 47;
  • региональные варианты сопоставляются с поддерживаемым catalog;
  • platform/store codes преобразуются отдельной таблицей и не протекают в UI;
  • активный locale выставляется в <html lang>;
  • смена языка применяется без перезапуска там, где runtime это позволяет;
  • настройки и основной контент переключаются атомарно, без смешения языков.
  • Нельзя собирать переводимое предложение конкатенацией фрагментов.
  • Plural, number, currency, date, duration и list formatting используют стандартный Intl API или совместимую ICU MessageFormat реализацию.
  • Message ID описывает смысл, а не исходную фразу: match.finishTurn, а не endJumpChainText.
  • Placeholder имеет имя и тип, понятные переводчику: {turnCount}, а не {x}.
  • Текст кнопки описывает пользовательский outcome, а техническое состояние остаётся в domain model.
  • Значение не кодирует layout. Переносы, uppercase и декоративные символы не используются как замена компонентной разметке.

Длинный контент отделён от UI catalog и имеет:

  • стабильный content ID и locale;
  • ссылку на source revision;
  • состояние draft, reviewed или approved;
  • автора генерации или перевода без хранения приватных prompt payload;
  • явную fallback policy;
  • одинаковые structural IDs для сцен, глав, формул, таблиц, choices и media.

AI-generated или machine-translated текст нельзя молча обозначать как редакторски проверенный. При отсутствии approved-версии продукт либо показывает явно разрешённый fallback, либо исключает locale из release claim.

Общие визуальные assets переиспользуются между locale, если cultural adaptation не требуется. Текст внутри bitmap не используется для обязательной информации: локализуемый title treatment и captions накладываются layout-слоем.

  • Accessible name, description, validation, narration и screen-reader status проходят через тот же locale provider.
  • Смена locale обновляет aria-label, live regions, subtitles и narration вместе с видимым UI.
  • Shortcut labels и input hints описывают действие, а не только клавишу.
  • Locale QA включает screen reader order, keyboard focus и reduced-motion состояние хотя бы для source и fallback locale.
  • Проверяются source locale, fallback locale и locale с наиболее длинными строками.
  • Текст не обрезается в compact controls, mobile, embedded и desktop layouts.
  • Компоненты допускают перенос строки или adaptive width; font size не уменьшается от длины отдельного перевода.
  • Иконка не заменяет непонятную команду без tooltip или accessible label.
  • Screenshot baseline хранит locale и viewport в имени или metadata.

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

  1. прочитать owning SDD и текущий locale provider;
  2. определить source, fallback и release locales;
  3. добавить semantic key в source catalog;
  4. обновить все обязательные catalogs или явно отметить перевод как draft;
  5. проверить, что компонент не содержит locale branching;
  6. запустить catalog parity/schema checks;
  7. проверить runtime switch без reload, если он поддерживается;
  8. пройти responsive и accessibility QA на длинном locale;
  9. проверить platform/store adapters отдельно от application locale;
  10. обновить SDD, если меняются supported locales, fallback или content policy.

Агент не должен:

  • выдавать автоматический перевод за approved;
  • менять product terminology только в одном locale;
  • вставлять пользовательский текст напрямую в компонент;
  • создавать новый locale resolver рядом с существующим;
  • сохранять API token, private translation memory или customer content в catalog fixtures.

Минимальный release evidence:

catalog parity/schema: pass
source locale smoke: pass
fallback locale smoke: pass
runtime locale switch: pass or documented non-goal
longest-locale responsive QA: pass
localized accessibility names: pass
platform/store locale mapping: pass when applicable

Новый locale считается поддерживаемым только после прохождения обязательного product flow. Наличие нескольких переведённых экранов не является locale support claim.

Owning SDD должен отвечать:

  • какие locale входят в release;
  • какой locale source и fallback;
  • как определяется locale;
  • какие UI/content/a11y/store surfaces локализуются;
  • как версионируется длинный контент;
  • допускается ли fallback и где;
  • кто подтверждает approved;
  • какие automated и visual checks блокируют release.

Связанное решение: ADR-0002.