chore: add i18n dict consistency lint rule

This commit is contained in:
2026-09-14 07:40:06 +05:00
parent 44cfca92ce
commit d24ee0a448
10 changed files with 648 additions and 3 deletions
+32 -1
View File
@@ -9,9 +9,11 @@
- `web/eslint-plugins/` — локальные ESLint-плагины.
- `design-tokens/` — правила для `<style>`-блоков svelte-компонентов.
- `isolation/` — правило изоляции old/new UI.
- `conventions/` — конвенции кода (интерфейс пропсов, запрет union-алиасов).
- `i18n/` — кросс-языковой линтер словарей (`dict-consistency`).
- `__tests__/` — юнит-тесты (Vitest + `RuleTester`/`Linter`).
- `__fixtures__/` — фикстуры для тестов: миниатюрный `src/app.css` (словарь
токенов) и файлы для изоляционных тестов.
токенов), файлы для изоляционных тестов и мини-словари `lib/i18n/`.
- `web/scripts/`:
- `lint-all.mjs` — оркестратор `lint:all`.
- `check-tokens.mjs` + `token-audit/` — токен-аудит по `app.css`.
@@ -62,6 +64,35 @@
(ESLint лезет в `<style>`-блоки через постпрефес postcss AST от
`svelte-eslint-parser`; stylelint прогоняется по всем CSS-файлам.)
## Правило плагина i18n (`i18n/dict-consistency`)
Кросс-языковой линтер словарей `lib/i18n/` (план: `docs/plan-preview-i18n.md`
§Фаза 8). Сравнивает каждый словарь со **всеми** остальными локалями (не только
с BASE). Список локалей берётся из `LOCALES` в `lib/i18n/dict.ts` — новый
словарь подхватывается без правки правила.
- **warn-only, никогда `error`** — пропущенный перевод не валит сборку.
- Диагностика живёт там, где фикс: каждый файл репортит **только свои**
расхождения:
- **паритет ключей**: правило собирает union всех ключей из словарей-соседей
(с диска) и для текущего файла репортит те, которых в нём нет — ровно одно
предупреждение на разрыв, независимо от числа локалей, где ключ есть;
пропавшая целая секция репортится один раз (не по каждому потомку);
- **пустые значения**: `""` и строка из одних пробелов;
- **паритет плейсхолдеров**: у одинакового ключа набор `{name}` сравнивается с
каноническим (мажоритарный по локалям, при равенстве — первый по `LOCALES`)
— ловит потерянную при переводе переменную ровно один раз, даже когда
отклоняется одна-единственная локаль.
- Словари-соседи читаются с диска и кэшируются на процесс линта (как
`no-undefined-in-svelte`); каждый парсится `@typescript-eslint/parser`
(синтакс, без типов).
- Опция `allowPaths: string[]` — dot-path ключи, исключаемые из всех проверок
(осознанные отклонения до достижения zero-warn).
- Тесты: `__tests__/dict-consistency.test.ts`, фикстуры-словари в
`__fixtures__/src/lib/i18n/` (`en`, `ru`, `de` — консистентные, zero-warn) — в
тестах подаются модифицированные варианты `en.ts`/`ru.ts` против эталонных на
диске.
## Токены-префиксы (целевой словарь дизайна)
- Цвета: `--color-*`, бренд `--brand-main` / `--brand-alt` — единственные две