Интернационализация и локализация (i18n/l10n) прикладного кода — запрет языкового хардкода пользовательских строк в мультиязычных проектах. Определить, мультиязычен ли репозиторий (i18n-инфраструктура, несколько локалей), и адаптироваться. Ключи и словари, плюрализация/род (ICU MessageFormat), интерполяция, форматирование дат/чисел/валют (Intl API), RTL и логические CSS-свойства. Библиотеки по стеку — next-intl (Next.js App Router), react-i18next (React SPA), i18next + Accept-Language (Node-б...
Scanned 9/11/2026
Install to Claude Code
npx -y skills add Vitammiin/agent-vorcl-flow --skill i18n --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of I18n?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/vitammiin-i18n-agent-vorcl-flow)More formats (shields.io, HTML) on the badges page.
---
name: i18n
description: Интернационализация и локализация (i18n/l10n) прикладного кода — запрет языкового хардкода пользовательских строк в мультиязычных проектах. Определить, мультиязычен ли репозиторий (i18n-инфраструктура, несколько локалей), и адаптироваться. Ключи и словари, плюрализация/род (ICU MessageFormat), интерполяция, форматирование дат/чисел/валют (Intl API), RTL и логические CSS-свойства. Библиотеки по стеку — next-intl (Next.js App Router), react-i18next (React SPA), i18next + Accept-Language (Node-бэкенд). Use ВСЕГДА при генерации/рефакторинге кода с пользовательским текстом (UI, сообщения об ошибках/валидации, письма, уведомления) и при аудите на языковой хардкод.
version: 1.0.0
---
# Навык: Интернационализация (i18n / l10n)
Правило проекта: **в мультиязычном коде — ноль языкового хардкода**. Любая строка, которую видит пользователь, идёт через слой перевода, а не литералом в разметке/ответе. Подход — **определять и адаптировать**: сначала пойми, мультиязычен ли репозиторий, потом применяй строгость по ситуации.
**Навигатор.** С чего начать: [режим проекта](#определять-и-адаптировать-первый-шаг--всегда) → [что переводится, что нет](#что-переводится-а-что--нет) → перед сдачей [анти-паттерны](#анти-паттерны-ищи-и-убирай) и [чек-лист](#чек-лист-сдачи). Как писать: [ключи и словари](#ключи-и-словари) · [плюрализация/род (ICU)](#плюрализация-род-интерполяция-icu-messageformat) · [даты/числа/валюты (Intl)](#форматирование-встроенный-intl--не-хардкодь-формат). Справочно: [библиотеки по стеку](#библиотеки-по-стеку-мнение-по-умолчанию) · [frontend](#frontend-специфика) / [backend](#backend-специфика) · [RTL](#rtl-и-направление-текста).
## Определять и адаптировать (первый шаг — всегда)
Прежде чем писать текст в код, определи режим проекта по признакам:
- **i18n-пакет** в `package.json`: `next-intl`, `i18next`/`react-i18next`/`i18next-http-middleware`, `@formatjs/*`, `react-intl`, `vue-i18n`, `svelte-i18n`.
- **Каталоги словарей**: `messages/`, `locales/`, `i18n/`, `translations/`, `lang/`; файлы `<locale>.json`/`.po`/`.ftl`.
- **Роутинг локали**: сегмент `app/[locale]/`, `middleware.ts` с matcher локалей, `next.config` с `i18n`/`localePrefix`.
- **Конфиг локалей**: `SUPPORTED_LOCALES`, `LOCALES`, `LANGUAGES`, `defaultLocale`, `<html lang>`/`dir`.
Режимы:
- **Мультиязычный** (нашёл инфраструктуру и/или ≥2 локалей) → **строгий запрет хардкода**: каждая пользовательская строка через существующий слой перевода (`t()`/`useTranslation`/`getTranslations`), в тот же формат ключей и словарей, что уже в проекте. Нет ключа — заведи его в словари всех активных локалей (недостающие — с TODO-пометкой на перевод), но **не** оставляй литерал в коде.
- **Одноязычный** (инфраструктуры нет) → **не навязывай** полный i18n без запроса, но: строки держи **вынесенными/централизованными** (константы/словарь модуля), а не разбросанными по JSX; помечай найденный хардкод как потенциальный долг; форматирование дат/чисел/валют всё равно через `Intl`. Так проект остаётся i18n-ready без лишнего бойлерплейта.
- **Неоднозначно** (смешанные признаки) → уточни у пользователя целевые локали; по умолчанию считай мультиязычным, если есть хоть один пользователь-facing поток с не-дефолтным языком.
## Что переводится, а что — нет
**Пользовательская строка (переводится):** UI-текст, заголовки, кнопки, лейблы, плейсхолдеры, подсказки/tooltips, `alt`, `aria-label`/`aria-*`-тексты, тосты/снекбары, сообщения об ошибках и валидации, письма/пуши/SMS, тексты PDF/квитанций, пустые состояния, единицы измерения словами.
**НЕ переводится (оставляй как есть):** логи и лог-сообщения (один язык, обычно English), стабильные машинные **коды ошибок** (`AUTH_INVALID_TOKEN`), идентификаторы/enum-значения, имена полей API и ключи JSON, ключи аналитики/событий, технические имена, значения в БД, регэкспы/форматные шаблоны как таковые.
## Ключи и словари
- **Именование ключей** — по смыслу и области, не по тексту: `feature.section.action` (`checkout.summary.payButton`), а не `"Оплатить"` как ключ. Единый стиль (обычно `camelCase`/`dot.notation`) — как уже в проекте.
- **Где хранить**: централизованные `messages/<locale>.json` (next-intl) или feature-level `features/<feature>/locales/<locale>.json` — следуй существующей раскладке проекта, не смешивай две.
- **Типизация ключей**: типобезопасные ключи (генерация типов из словаря / `keyof`-типы next-intl / `i18next` `resources` типизация) — опечатка в ключе должна ловиться компилятором.
- **Никакой конкатенации переведённых кусков.** `t('greeting') + name` и `"Найдено " + n + " шт."` — запрещено: порядок слов и согласование зависят от языка. Используй интерполяцию и ICU (ниже).
- **Фолбэк-локаль** задан явно; отсутствующий ключ не должен рушить UI — фолбэк на дефолт + предупреждение в dev.
## Плюрализация, род, интерполяция (ICU MessageFormat)
- **Множественное число** — через `plural` (не `if (n === 1)`): у языков до 6 категорий (`zero/one/two/few/many/other`), русский/польский/арабский — нетривиальные правила. `{count, plural, one {# товар} few {# товара} many {# товаров} other {# товара}}`.
- **Род/выбор** — через `select`: `{gender, select, female {приглашена} male {приглашён} other {приглашён(а)}}`.
- **Интерполяция** — только именованными плейсхолдерами (`{name}`, `{count}`), значения подставляет библиотека; не собирай предложение из кусков вручную.
- Движки ICU: next-intl и `react-intl`/`@formatjs` — из коробки; для i18next — плагин `i18next-icu`.
## Форматирование (встроенный Intl — не хардкодь формат)
- **Даты/время** — `Intl.DateTimeFormat(locale, …)` (или обёртки библиотеки); не `dd.MM.yyyy` строкой. Учитывай **таймзону** (`timeZone`), храни в UTC, форматируй под пользователя.
- **Числа/валюты** — `Intl.NumberFormat(locale, { style: 'currency', currency })`; разделители, знак валюты и позиция зависят от локали.
- **Относительное время** — `Intl.RelativeTimeFormat`; **списки** — `Intl.ListFormat`; **сортировка/поиск** — `Intl.Collator` (не байтовое сравнение строк).
## Библиотеки по стеку (мнение по умолчанию)
- **Next.js (App Router)** → **next-intl**: локали через `app/[locale]/`, `next-intl/middleware` для роутинга/детекта, серверные переводы `getTranslations` в Server Components, `useTranslations` в Client Components; локализованные `generateMetadata` и `hreflang`.
- **React SPA (Vite/CRA)** → **react-i18next** (`i18next` + `react-i18next`): namespaces, ленивая загрузка, `useTranslation`; ICU через `i18next-icu`, детект через `i18next-browser-languagedetector`.
- **Node-бэкенд (Fastify/Express)** → **i18next** (+ `i18next-http-middleware`) или `@formatjs/intl`: локаль из `Accept-Language`/профиля пользователя, перевод сообщений на границе ответа; письма/уведомления — по локали получателя.
- **Vue** → `vue-i18n`. Общий низкоуровневый слой форматирования во всех стеках — встроенный `Intl`.
## Frontend-специфика
- **Server vs Client**: на сервере (RSC) бери переводы серверным API (`getTranslations`), на клиенте — хук; не тащи весь словарь в клиентский бандл — грузи только нужные namespaces/локаль.
- **SEO**: локализованные `<title>`/`meta`, `<link rel="alternate" hreflang>`, `<html lang dir>` под текущую локаль.
- Строки — только через слой перевода; никаких литералов в JSX (кроме служебных, не видимых пользователю).
## Backend-специфика
- **Локализуй на границе** (в ответе/письме) по `Accept-Language` или предпочтению пользователя, а не в глубине бизнес-логики.
- **API-контракт ошибок**: отдавай стабильный машинный `code` + параметры (`{ code: 'ORDER_LIMIT', params: { max: 5 } }`), а готовый переведённый текст формируй на клиенте/edge — либо, если API сам отдаёт текст, выбирай язык по локали запроса. Не «зашивай» один язык в тело ответа.
- Валидация (zod и т.п.): сообщения — локализуемые ключи, не хардкод-строки.
## RTL и направление текста
- Поддержи RTL-локали (ar, he, fa): `dir="rtl"` на `<html>`/контейнере, зеркалирование раскладки.
- **Логические CSS-свойства** вместо физических: `margin-inline`/`padding-inline`, `inset-inline-start/-end`, `text-align: start/end` (в Tailwind — логические утилиты `ms-*`/`me-*`/`ps-*`/`pe-*`, `start-*`/`end-*`). Иконки направления (стрелки, chevron) — зеркаль под RTL.
## Анти-паттерны (ищи и убирай)
- Литерал пользовательской строки прямо в JSX/шаблоне/HTTP-ответе в мультиязычном проекте.
- Конкатенация переведённых кусков; `"Показано " + n + " элементов"`; ручная плюрализация через `if (n === 1)`.
- Хардкод формата даты/числа/валюты (`toLocaleString()` без локали тоже зависит от среды — задавай локаль явно).
- Перевод того, что переводить нельзя: логов, машинных кодов ошибок, enum/идентификаторов.
- Ключ = сам текст (`t("Оплатить")`); отсутствие фолбэк-локали; несогласованные наборы ключей между локалями.
- Локаль не учтена в ключах кэша (один кэш на все языки) — данные/страницы кэшируются per-locale.
- Физические CSS-отступы, ломающие RTL; отсутствие `lang`/`dir`.
## Чек-лист сдачи
- [ ] Определён режим проекта (мультиязычный / одноязычный) и применена соответствующая строгость.
- [ ] Пользовательские строки вынесены в словарь/через `t()`; литералов в разметке/ответах нет.
- [ ] Ключи типизированы и согласованы между локалями; фолбэк-локаль задан.
- [ ] Плюрализация/род — через ICU; интерполяция — именованными плейсхолдерами.
- [ ] Даты/числа/валюты/списки — через `Intl` с явной локалью и таймзоной.
- [ ] Логи и машинные коды ошибок НЕ локализованы.
- [ ] RTL учтён (логические свойства, `dir`), если среди локалей есть RTL.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!