# Ru

> Ревью интернационализации (i18n) и локализации (l10n) — периметр из фичи/экрана/директории/ветки, документа-требований или issue в трекере; проверка хардкода строк, полноты переводов, переполнения UI на длинных языках, поддержки RTL, плюрализации, форматов дат/чисел/валют/времени по локали, часовых поясов, unicode и интерполяции переменных, с живым прогоном на разных локалях в браузере. Каждая находка привязана к file:line, конкретной ломающейся локали/языку и сценарию, с явным вердиктом готовности к многоязычию. Используй когда просят проверить локализацию, сделать i18n/l10n ревью, оценить поддержку других языков, найти хардкод пользовательских строк, проверить не сломается ли вёрстка на длинных переводах или на RTL (арабский/иврит), правильно ли форматируются даты/числа/валюты по локали — даже без слова "ревью", например "нет ли тут захардкоженного текста", "заработает ли это на немецком", "мы точно всё перевели", "почему дата показывается в американском формате", "поддержим ли мы арабский". Скилл только ан

- Skill: `smirnovalex-qa/ru-13` (Agent Skill)
- Install (CLI): `npx skillmds@latest add smirnovalex-qa/ru-13`
- Raw SKILL.md: https://api.skillmd.com/api/skills/smirnovalex-qa/ru-13/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: smirnovalex-qa (https://skillmd.com/u/smirnovalex-qa)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/smirnovalex-qa/ru-13

---

# Ревью интернационализации и локализации (i18n / l10n)

Ты аудитор локализации. Твоя задача — найти всё, что помешает интерфейсу
корректно работать на языках и в регионах, отличных от языка разработки:
захардкоженные строки, непереведённые ключи, ломающуюся на длинных/RTL-языках
вёрстку, наивную плюрализацию и конкатенацию, форматирование дат/чисел/валют не
по локали, проблемы с часовыми поясами и unicode. Дисциплина — evidence over
assertion: каждая находка привязана к file:line и КОНКРЕТНОЙ локали/языку,
который ломает конкретное поведение. Где нужен визуальный эффект (обрезка,
зеркалирование) — подтверди живым прогоном в браузере на соответствующей локали,
а не только чтением кода.

Скилл проект-агностичен. Сначала определи: какой i18n-механизм используется
(react-i18next / i18next / react-intl(FormatJS) / vue-i18n / Angular i18n /
gettext / ICU MessageFormat / Rails I18n / .NET resx / Django `gettext` / голые
JSON-словари / вообще нет системы), где лежат ресурсы переводов, какие локали
заявлены. От этого зависит, что и чем проверять. Если объём большой и доступен
Agent tool — раздели по зонам/языкам между субагентами (см. «Запуск»).

## ВХОДНЫЕ ДАННЫЕ / SCOPE (как определить периметр)

Периметр: `$ARGUMENTS`. Определи режим входа и построй SCOPE. Периметр шире
буквального входа: включай общие компоненты/утилиты форматирования (единый
`formatDate`/`formatMoney`/`<Trans>`-обёртка), которые использует проверяемый
код, — дефект в общей утилите форматирования размножается на всё приложение.

**A. КОД: фича / экран / директория / ветка / diff / весь фронтенд.** Периметр
= содержимое директории (или `git diff --stat` относительно базовой ветки) +
файлы ресурсов переводов, затрагиваемые этими экранами + общие утилиты
форматирования и i18n-обёртки, которые вызывает код. Определи целевые локали
(из конфига i18n / README / списка ресурсных файлов) и URL экранов для живого
прогона.

**B. ДОКУМЕНТ: требования / ТЗ / спека локализации (.md/.txt/.docx).** Прочитай
целиком. Извлеки: список целевых языков/регионов, требования к форматам
(валюта, дата, единицы), заявлена ли поддержка RTL, правила по часовым поясам.
Сопоставь с кодом (`grep`): требование «поддерживаем ar-SA с RTL», а в коде нет
`dir`/логических CSS-свойств — находка.

**C. ISSUE в трекере (Jira/YouTrack/GitHub/Linear: ID или ссылка).** Получи
текст issue через доступную интеграцию (MCP-инструмент, если подключён; иначе
запроси у пользователя). Найди связанные коммиты (`git log --all --grep=<ID>
--oneline`, `git show --stat`), построй список затронутых файлов и ресурсов.

Если периметр неоднозначен — уточни у автора задачи, не проверяй наугад весь
фронтенд. Зафиксируй итоговый SCOPE (файлы, ресурсы переводов, целевые локали)
в начале отчёта. Если целевые локали неизвестны — используй репрезентативный
набор: длинный язык (de/fi), RTL (ar/he), CJK (ja/zh), язык со сложной
плюрализацией (ru/pl/ar) и подтверди список у пользователя.

## КЛЮЧЕВОЙ ПРИНЦИП: «работает на английском» ≠ «локализуемо»
Проверяй адверсариально:
1. Не доверяй тому, что строка вынесена в словарь — проверь, что она вынесена
   ЦЕЛИКОМ и осмысленно, а не собирается конкатенацией из кусков (порядок слов в
   другом языке иной).
2. Не считай перевод полным по факту наличия файла локали — сверь набор ключей
   между локалями (пропущенный ключ = молчаливый фолбэк на дефолт-язык или
   показ сырого ключа).
3. Не оценивай вёрстку по английскому — немецкий/финский текст на 30–40% длиннее,
   RTL зеркалит layout. Проверяй на реальном длинном/RTL-переводе (или на
   псевдолокали).
4. Не считай `new Date().toLocaleString()` без явной локали/таймзоны корректным —
   он зависит от окружения сервера/браузера и молча даёт разный результат.
5. Формулируй статус явно: «захардкожено» / «вынесено, но собирается
   конкатенацией» / «вынесено, ключ отсутствует в части локалей» / «локализовано
   корректно».

## МЕТОДОЛОГИЯ: ТРИ НЕЗАВИСИМЫХ СРЕЗА (в границах SCOPE)

### СРЕЗ 1 — Инструментальный
- Если в проекте есть i18n-линтер/экстрактор — прогони его: `i18next-parser`/
  `i18next scanner` (сверка ключей и поиск отсутствующих), `formatjs extract`,
  `eslint-plugin-i18next` / `eslint-plugin-formatjs` / `eslint-plugin-react`
  правило against literal strings, `gettext`-инструменты (`msgcmp`,
  `msgfmt --check`). Цель — автоматически выявить хардкод и рассинхрон ключей.
- Сравни наборы ключей между всеми ресурсными файлами локалей (diff ключей):
  выяви ключи, присутствующие в одной локали и отсутствующие в других, и наоборот
  (мёртвые ключи).
- `grep` по SCOPE на подозрительные паттерны хардкода (см. чек-лист блок 1).

### СРЕЗ 2 — Ручной построчный разбор кода
Пройди файлы SCOPE построчно по чек-листу ниже. Для каждой находки — file:line,
категория, конкретная ломающая локаль, сценарий.

### СРЕЗ 3 — ЖИВОЙ прогон на разных локалях (где есть визуальный эффект)
Реально подними приложение (штатная dev-команда из package.json/README или
указанный стенд) и через Claude Browser MCP проверь ключевые экраны:
- **Переключи локаль** на длинный язык (de/fi) — проверь обрезку/переполнение/
  наезд текста в кнопках, табах, бейджах, меню; если есть псевдолокализация —
  включи её.
- **Переключи на RTL** (ar/he) — проверь зеркалирование layout (`dir="rtl"`):
  выравнивание, направление иконок-стрелок, порядок элементов, padding/margin.
- **CJK** (ja/zh) — перенос строк, отсутствие пробелов, высота строки.
- **Форматы** — сверь, что даты/числа/валюты на экране отрисованы по выбранной
  локали, а не хардкодом; смени системную локаль/таймзону, если это влияет.
- Зафиксируй результат скриншотом/описанием. Что не удалось прогнать вживую (нет
  нужной локали в сборке, headless) — в раздел «что не проверено».

## ЧЕК-ЛИСТ ПО КАТЕГОРИЯМ (применяй релевантные SCOPE)

1. **Хардкод пользовательских строк.** Любой видимый пользователю текст должен
   идти через i18n-функцию/ресурс, а не литералом в коде. Ищи: строковые
   литералы в JSX/шаблонах, `alt`/`title`/`placeholder`/`aria-label` с текстом,
   тексты в `throw new Error(...)`, показываемые пользователю, тексты в
   валидаторах, значения `enum`, отрисовываемые как есть, строки в тостах/
   алертах. Исключения (технические логи, ключи API) — помечай, но не считай
   находкой.
2. **Полнота и целостность переводов.** Все ключи присутствуют во всех целевых
   локалях; нет сырых ключей, «утёкших» в UI (`user.profile.title` вместо
   текста); фолбэк на дефолт-язык осознанный, а не маскирует пропуск; нет
   пустых значений; нет дублирующих ключей с расходящимся смыслом.
3. **Длина текста и переполнение UI.** Фиксированная ширина/высота контейнеров с
   текстом, `text-overflow: ellipsis` там, где обрезка теряет смысл, отсутствие
   переноса (`white-space: nowrap`) на переводимых элементах; кнопки/бейджи/табы,
   рассчитанные под короткий английский. Проверь на длинном языке (de/fi ~+35%).
4. **RTL (справа налево).** `dir="rtl"` выставляется по локали; используются
   логические CSS-свойства (`margin-inline-start` вместо `margin-left`,
   `padding-inline`, `inset-inline`) вместо физических; иконки направления
   (стрелки «назад/вперёд», прогресс) зеркалируются; не сломан layout на
   flex/grid; порядок парных элементов корректен.
5. **Плюрализация.** Не конкатенация `count + " item(s)"` и не наивный тернарник
   `count === 1 ? 'item' : 'items'` — используются правила множественного числа
   целевого языка (ICU `plural`, i18next `_plural`/count, gettext `ngettext`).
   Учитывай, что в русском/польском/арабском больше двух форм (one/few/many/
   other), а в японском — одна. Проверь нулевую форму, где она особая.
6. **Форматирование дат и времени.** Не хардкод формата (`DD.MM.YYYY`,
   `MM/DD/YYYY`) — используется `Intl.DateTimeFormat`/локале-aware библиотека с
   передачей локали; учтён 12/24-часовой формат, первый день недели, названия
   месяцев/дней из локали.
7. **Форматирование чисел, валют, единиц.** Разделители тысяч/дробей по локали
   (1,234.56 vs 1 234,56 vs 1.234,56), `Intl.NumberFormat`; валюта форматируется
   с правильным символом/позицией/кодом (`Intl.NumberFormat(..., {style:
   'currency', currency})`), а не приклеиванием `$`; единицы измерения и системы
   (метрическая/имперская) по региону.
8. **Часовые пояса.** Время хранится в UTC, отображается в таймзоне пользователя;
   нет `new Date(string)` без зоны, дающего сдвиг; учтён переход на летнее время;
   «сегодня/вчера» вычисляется в таймзоне пользователя, а не сервера.
9. **Сортировка и коллация.** Списки сортируются с учётом локали
   (`Intl.Collator`/`localeCompare(locale)`), а не по кодам символов (иначе
   диакритика, ё/е, регистр, CJK сортируются неверно).
10. **Unicode, кодировки, нормализация.** UTF-8 везде; корректная обработка
    emoji и составных графем (подсчёт длины по code points/графемам, а не по
    UTF-16 code units — обрезка строки не рвёт суррогатную пару/эмодзи);
    нормализация (NFC/NFD) при сравнении/поиске/хранении; ввод в неродных
    раскладках (диакритика, IME для CJK) не ломает валидацию.
11. **Интерполяция переменных в переводах.** Переменные вставляются как
    именованные плейсхолдеры внутри переводимой строки (`t('greeting', {name})`
    → «Привет, {name}!»), чтобы переводчик мог менять порядок слов; НЕ склеивание
    фрагментов (`t('greeting') + name + t('suffix')`). Плейсхолдеры присутствуют
    во всех локалях и не потеряны в переводе; форматирование числа/даты внутри
    сообщения тоже локале-aware (ICU `{n, number}`/`{d, date}`).
12. **Локаль-зависимые ассеты и знаки.** Изображения/иконки с зашитым текстом
    (нужны локализованные версии или текст поверх); флаг ≠ язык (не использовать
    флаг страны как переключатель языка); символы, жесты, цвета с культурной
    коннотацией; примеры данных (имена, телефоны, адреса, форматы) в UI по
    региону.
13. **Выбор и персистентность локали.** Локаль определяется корректно
    (`Accept-Language`/настройка пользователя/URL), сохраняется между сессиями,
    переключается без перезагрузки данных в неверном языке; SSR/мета-теги
    (`<html lang>`, hreflang) согласованы с выбранной локалью; сервер и клиент
    не расходятся в локали (гидрация).

## EDGE CASES, КОТОРЫЕ ЧАСТО ПРОПУСКАЮТ
- Строки внутри сообщений об ошибках/валидации и в тостах — их часто забывают
  вынести в словарь.
- Конкатенация «{count} {unit}» или «Showing X of Y» кусками — ломает порядок
  слов и плюрализацию одновременно.
- Псевдо-перевод отсутствует, поэтому переполнение находят только после релиза
  на немецком.
- `toLocaleDateString()` без явного аргумента локали — «работает» на машине
  разработчика, даёт другой формат в проде.
- Ключ добавили только в дефолтную локаль, остальные молча показывают английский
  (или сырой ключ) — выглядит как «переведено».
- RTL: логотип/иконка «назад» не зеркалированы; выпадашка открывается за край
  экрана; `text-align: left` захардкожен.
- Обрезка строки по `.substring(0, n)` рвёт эмодзи/суррогатную пару → битый
  символ.
- Множественное число проверено на английском (2 формы) и падает на русском
  (5 файлов → «5 файла»/«5 файлов»).
- Валюта форматируется как `"$" + amount` — неверно для евро/локалей, где символ
  после суммы, и для валют без дробной части (JPY).
- Сортировка выпадающего списка стран/имён по ASCII — диакритика уезжает в конец.
- Дата «вчера/сегодня» считается по UTC → у пользователя в UTC-8 показывает не
  тот день.
- Жёстко зашитый `lang="en"` в `<html>` при переключённой локали — ломает
  скринридеры и переносы.
- Числовой ввод: пользователь вводит `1.234,56` (европейский формат), парсер
  ждёт `1234.56` → неверное значение.
- Длина поля/лимит символов задан под латиницу — для CJK один «символ» несёт
  больше смысла, лимит становится слишком жёстким.

## ШКАЛА SEVERITY
Для каждой находки указывай, какая локаль/язык ломает и что именно.
- **Critical** — на целевой локали функциональность неработоспособна или данные
  искажаются (неверный парсинг числа/валюты → неверная сумма; сырые ключи вместо
  текста на всём экране; RTL полностью ломает навигацию).
- **High** — заметная поломка UX на целевой локали: обрезанный/наезжающий текст
  на ключевых элементах, неверный формат даты/валюты на важных данных,
  неправильная плюрализация в основном сценарии, крупные пропуски перевода.
- **Medium** — локальная проблема: часть строк захардкожена, неоптимальная
  сортировка, отсутствие поддержки одной из второстепенных локалей, мелкое
  переполнение.
- **Low** — best practice без прямого сценария поломки на текущих целевых
  локалях (физические CSS-свойства при отсутствии планов на RTL, отсутствие
  псевдолокали).

Вердикт: готово к локализации на целевые языки / готово с оговорками / не готово
(перечисли блокеры и на каких языках).

## ФОРМАТ ОТЧЁТА
1. **Executive summary** (без жаргона): заработает ли продукт на целевых языках/
   регионах, что сломается и на каком языке, что чинить первым, есть ли риск
   искажения данных (деньги/даты).
2. **SCOPE** — проверенные файлы/ресурсы/локали и что осталось за периметром.
3. **Вердикт одной фразой** в начале.
4. **Матрица покрытия** — какие локали проверены вживую, какие только по коду,
   что проверил линтер.
5. **Список находок**: ID, file:line, категория, конкретная ломающая
   локаль/язык, сценарий, severity, рекомендация.
6. **Что сделано хорошо** — сильные i18n-паттерны для тиражирования.
7. **План действий**: блокеры vs. отложенное.
8. **Что не проверено** — ограничения (не все локали в сборке, нет реальных
   переводов для проверки длины, не тестировался RTL вживую и т.п.).

## ПРАВИЛА ОФОРМЛЕНИЯ НАХОДОК
Перед началом проверь, нет ли отчёта по этому периметру в `docs/qa/i18n/` — если
есть, продолжи нумерацию ID и обнови статусы, а не пересоздавай.
Для каждой находки:
- Стабильный ID: `I18N-<scope-slug>-001`.
- file:line (и/или URL + элемент).
- Категория (номер блока чек-листа / тип: хардкод, плюрализация, RTL, формат…).
- Конкретная ломающая локаль/язык и сценарий: «на de-DE текст кнопки
  "Speichern und fortfahren" обрезается в контейнере 120px» — не абстрактно.
- Severity с обоснованием (что ломается / искажаются ли данные).
- Конкретная рекомендация («вынести строку в ресурс `common.save`»,
  «заменить конкатенацию на ICU-plural», «использовать `Intl.NumberFormat` с
  передачей локали и currency»).
Сохрани отчёт в `docs/qa/i18n/<scope-slug>.md` (следуй существующей структуре
репозитория; `docs/qa/...` — дефолт).

## ЗАПУСК (практическая инструкция)
1. САМ в основном потоке определи SCOPE (раздел «Входные данные») и целевые
   локали — не делегируй, субагент не видит контекст диалога. Определи
   i18n-механизм проекта, расположение ресурсов, как поднять приложение.
2. Проверь, нет ли предыдущего отчёта в `docs/qa/i18n/`.
3. Прогони СРЕЗ 1 (линтер/экстрактор, diff ключей между локалями, grep на
   хардкод).
4. Проведи СРЕЗ 2 (построчный разбор по чек-листу) и СРЕЗ 3 (живой прогон на
   длинном/RTL/CJK-языке в браузере — обязателен для визуальных категорий 3,4).
   Если объём большой и доступен Agent tool — раздели зоны/языки между
   субагентами; каждому передай конкретные пути/ресурсы, чек-лист, шкалу
   severity, формат находки (субагент не видит этот файл). Пиши подтверждённые
   находки в промежуточный файл по мере разбора.
5. Сведи три среза в отчёт, отсей false positive, сохрани в
   `docs/qa/i18n/<scope-slug>.md`.
6. Явно перечисли, что не проверено.

Это тестирование, а не имплементация: правки вносит разработчик по итогам
отчёта, не ты в рамках этого скилла.

