vue-i18n-kit 0.3.0 — TypeScript типы, устаревшие переводы, XLIFF/PO, DeepL и отчёт по покрытию

11.04.2026
vue-i18n-kit 0.3.0 — TypeScript типы, устаревшие переводы, XLIFF/PO, DeepL и отчёт по покрытию

Прошло несколько дней с последнего большого апдейта. За это время в редакторе и CLI добавилось достаточно, чтобы написать отдельный пост — не просто список изменений, а объяснение зачем и как.

Коротко о главном: TypeScript-типы из ключей локали, детектор устаревших переводов, экспорт и импорт XLIFF/PO, поддержка DeepL в автопереводе, отчёт по покрытию в трёх форматах и переработанный дашборд. Плюс подробно про мастер настройки — он достаточно умный, чтобы заслуживать отдельного объяснения.


Мастер настройки (vue-i18n-kit init)

Расскажу подробно, потому что вопросы визарда выглядят так, будто он всё знает наперёд — а это не магия, там несколько шагов со своей логикой.

bash Copy
npx vue-i18n-kit init

Шаг 0 — проверка существующего конфига

Первое, что делает init — ищет i18n-kit.config.json в корне проекта.

Если файл найден, визард показывает текущий список локалей и спрашивает:

Copy
◆  What would you like to do?
│  ○ Use existing config — open the editor
│  ○ Update settings (pre-filled with current values)
│  ○ Reinitialize from scratch

Use existing — просто выходит и советует запустить vue-i18n-kit ui. Update — запускает весь поток с уже заполненными значениями, так что можно просто нажимать Enter там, где всё устраивает. Reinitialize — чистый старт.

Если файла нет, визард автоматически сканирует исходники в поисках вызова createVueI18nPlugin. Если находит — подхватывает все уже подключённые локали, их пути и meta-данные (display, flag). Если не находит — стартует с чистого листа.

Шаг 1 — локали

Copy
◆  Locale codes (comma-separated, e.g. en, ru, de)
│  en, ru, de  ← если нашёл в проекте, подставил сам

После ввода кодов для каждой локали по очереди спрашивает:

  • Display name (например, English, Русский) — обязательно
  • Флаг-эмодзи (🇬🇧, 🇷🇺) — необязательно, Enter пропускает

Коды валидируются по формату BCP 47 (en, zh-CN, pt-BR) прямо в поле.

Шаг 2 — директории

Copy
◆  Locales directory (relative to project root)
│  src/locales
◆  Toolkit directory for generated files
│  i18n-tools

Locales directory — куда лежат или будут лежать JSON-файлы переводов. По умолчанию src/locales.

Toolkit directory — куда auto-config сложит сгенерированные файлы (locales.config.json, locales.entries.json). По умолчанию i18n-tools. Оба можно добавить в .gitignore.

Шаг 3 — интеграция с Vite / Nuxt

Визард ищет vite.config.ts или nuxt.config.ts. Если нашёл:

Copy
  Detected vite.config.ts. Add vueI18nMapPlugin automatically?
   Yes /  No

Yes — добавит (или обновит) vueI18nMapPlugin в конфигурационный файл. Если плагин уже есть, просто обновит данные. Остальные плагины и настройки не трогает.

Результат в vite.config.ts:

ts Copy
import { vueI18nMapPlugin } from 'vue-i18n-kit/vite'

export default defineConfig({
  plugins: [
    vue(),
    vueI18nMapPlugin({
      locales: {
        en: { path: 'src/locales/en.json', meta: { display: 'English', flag: '🇬🇧' } },
        ru: { path: 'src/locales/ru.json', meta: { display: 'Русский', flag: '🇷🇺' } },
      },
    }),
  ],
})

Для Nuxt — то же самое, но в vite.plugins внутри defineNuxtConfig.

Шаг 4 — что делать с существующими файлами

Для каждого JSON-файла, который уже есть на диске, визард спрашивает:

Copy
◆  src/locales/de.json already exists — what should we do?
│  ○ Keep existing file
│  ○ Overwrite with empty {}
│  ○ Copy structure from another locale

Copy structure — удобно когда только что добавили новый язык и хочется взять структуру ключей из en.json с пустыми значениями.

Итог

После всех шагов визард записывает:

  • i18n-kit.config.json — единый конфиг для CLI и редактора
  • Файлы локалей (если их не было или выбрали overwrite/copy)
  • i18n-tools/locales.config.json — для UI-сервера
  • Обновляет vite.config.ts / nuxt.config.ts (если согласились)

auto-config — что происходит за кулисами

Команда auto-config используется в паре с ui:

json Copy
"i18n:ui": "vue-i18n-kit auto-config && vue-i18n-kit ui"

Её задача — синхронизировать конфиг редактора с тем, что написано в main.ts.

Что она делает:

  1. Сканирует исходники проекта и находит вызов createVueI18nPlugin(...). Извлекает из него список локалей, пути к файлам (из import(...) или ~/...) и meta-данные каждой локали.

  2. Генерирует i18n-tools/locales.config.json — разрешённые абсолютные пути и метаданные. Именно его читает UI-сервер при старте.

  3. Генерирует i18n-tools/locales.entries.json — карту вида { "buttons.submit": ["src/components/Form.vue", "src/views/Login.vue"] }. Сканирует все .vue, .ts, .js файлы в src/** и собирает все вызовы t(), tm(), $t(). Эта карта нужна для определения неиспользуемых и phantom-ключей в редакторе.

  4. Обновляет viteI18nMapPlugin в vite.config.ts / nuxt.config.ts — заменяет весь вызов плагина актуальными данными. Остальное в конфиге не трогает.

Почему это удобно: createVueI18nPlugin — единственное место, где вы регистрируете локали. auto-config читает именно его, а не пытается угадать что-то из структуры папок. Добавили новую локаль в main.ts — запустили auto-config — редактор знает о ней.

Оба сгенерированных файла можно смело класть в .gitignore.


Что нового

TypeScript типы из ключей (vue-i18n-kit types)

bash Copy
vue-i18n-kit types
# → src/i18n.d.ts

vue-i18n-kit types --watch
# пересоздаёт при изменении locale JSON

Команда читает эталонную локаль и генерирует union-тип TranslationKey из всех ключей:

ts Copy
// src/i18n.d.ts (generated, do not edit)
export type TranslationKey =
  | 'buttons.submit'
  | 'buttons.cancel'
  | 'auth.login.title'
  | 'errors.form.min_length'
  // ...

declare module 'vue-i18n-kit' {
  interface Register {
    key: TranslationKey
  }
}

После этого t('buttons.typo') становится ошибкой компиляции. Автодополнение в IDE тоже работает.

Опции:

  • --out <path> — путь к файлу (по умолчанию src/i18n.d.ts)
  • --locale <code> — какую локаль использовать как источник
  • --dir <path> — директория с локалями
  • --watch — режим наблюдения

Детектор устаревших переводов

Ситуация: вы меняете текст в эталонной локали — допустим, переформулировали сообщение об ошибке. Переводы для ru и de при этом не обновились, они теперь переведены с предыдущей версии текста. Узнаёте об этом обычно случайно.

Новый механизм это фиксирует. В i18n-kit.config.json:

json Copy
{
  "staleTracking": true
}

Когда включено — каждый раз при сохранении значения в эталонной локали через редактор, в i18n-kit.notes.json записывается хеш этого значения. При следующей загрузке редактор сравнивает текущие значения с сохранёнными хешами — если расходятся, ключ помечается как устаревший.

В таблице: значок ⚠ outdated на ячейке ключа, фильтр stale в тулбаре. В панели детали — кнопка «Mark as reviewed», которая обновляет хеш и снимает метку.

Из командной строки:

bash Copy
vue-i18n-kit stale
# ⚠ 3 stale keys (reference value changed):
#   - errors.network  → affects: ru, de
#   - auth.reset.success  → affects: ru
#   - dashboard.welcome  → affects: de

XLIFF и PO — форматы для переводчиков

Профессиональные переводчики работают в CAT-инструментах (Phrase, Lokalise, Poedit, Weblate, OmegaT) — им нужны отраслевые форматы, не raw JSON.

Экспорт:

bash Copy
vue-i18n-kit export --locale ru --format xliff --out send/ru.xliff
vue-i18n-kit export --locale ru --format po    --out send/ru.po

XLIFF-файл содержит <source> (эталонный текст) и <target> (текущий перевод). Заметки из редактора попадают в <note>. PO-файл: msgctxt = ключ, msgid = эталон, msgstr = перевод, заметки как #. комментарии.

Импорт:

bash Copy
vue-i18n-kit import ru.xliff
vue-i18n-kit import ru.po --dry   # предпросмотр без записи

Локаль определяется из заголовка файла автоматически. Только затронутые ключи обновляются — остальные не трогаются.

В редакторе — кнопки Export и Import в хедере (выпадающие меню). Export открывает диалог выбора локали и формата. Import принимает .xliff и .po наравне с .csv.


DeepL — более качественный машинный перевод

LibreTranslate в качестве переводчика — это бесплатно и self-hosted, но качество заметно уступает нейронным движкам. DeepL даёт принципиально другой уровень — особенно для европейских языков.

Бесплатный план DeepL: 500 000 символов/месяц. Для локализации одного продукта обычно хватает.

Настройка:

В Settings (шестерёнка в хедере редактора) появился переключатель движка:

Copy
Translation engine:  [ LibreTranslate ]  [ DeepL ]

При выборе DeepL открывается поле Auth Key. Ключи, оканчивающиеся на :fx, автоматически направляются на api-free.deepl.com — не нужно думать, какой endpoint использовать.

Для поддерживаемых языков (DE, FR, IT, ES, NL, PL, PT, JA, RU) доступен выбор Formality — формальный или разговорный регистр текста.

Плейсхолдеры:

Большая проблема с машинным переводом и ICU-строками — движок норовит переставить или переименовать плейсхолдеры. {name} превращается в {nombre}, а {count, plural, one{…} other{…}} разбирается как текст и теряет структуру.

Решение: перед отправкой в DeepL все {…} блоки — и простые {name}, и целые ICU plural-блоки — заменяются на XML-теги: {name}<x id="0"/>. DeepL работает в режиме tag_handling: "xml" и не трогает теги. После перевода теги заменяются обратно.


Отчёт по покрытию (vue-i18n-kit stats)

bash Copy
vue-i18n-kit stats
Copy
  vue-i18n-kit stats  2026-04-11
  35 keys · 3 locales

  Coverage
  🇬🇧 English (en)    ████████████████████  100%
  🇷🇺 Русский (ru)    ████████████████░░░░   89%  4 missing
  🇩🇪 Deutsch (de)    ███████████████░░░░░   77%  8 missing

  By namespace
  namespace    keys    en       ru       de
  auth           12    100%     100%     92%
  dashboard      10    100%     0%       0%
  errors          8    100%     100%     75%

  Issues
  • 12 missing
  • 2 phantom (used in code, absent from files)

JSON для CI:

bash Copy
vue-i18n-kit stats --format json --out coverage.json

Полезно когда хочется упасть в пайплайне при недостаточном покрытии:

yaml Copy
- name: Check i18n coverage
  run: |
    npx vue-i18n-kit stats --format json --out coverage.json
    node -e "
      const r = require('./coverage.json');
      const low = r.locales.filter(l => l.coverage < 80);
      if (low.length) {
        console.error('Low coverage:', low.map(l => l.code + ' ' + l.coverage + '%'));
        process.exit(1);
      }
    "

JSON-отчёт содержит totalKeys, для каждой локали — filled, empty, missing, coverage, bytes, для каждого неймспейса — количество ключей, размер в байтах и покрытие по локалям.

HTML:

bash Copy
vue-i18n-kit stats --format html
# → i18n-stats.html

Самодостаточный файл с таблицами и progress bar-ами в тёмной теме. Удобно бросить коллегам или прикрепить к задаче.


Dashboard — карточка Coverage

Однострочный progress bar общего покрытия заменён на полноценный блок с рядами по каждой локали:

Copy
Coverage                                    91% overall
─────────────────────────────────────────────────────────
🇬🇧 English     ████████████████████  100%
🇷🇺 Русский     ████████████████░░░░   89%   4 missing
🇩🇪 Deutsch     ███████████████░░░░░   77%   8 missing

Цвет бара и процента показывает состояние: зелёный (100%), фиолетовый (≥ 80%), жёлтый (50–79%), красный (< 50%).


Превью фраз с несколькими плюрализациями

Раньше превью для ICU-ключей с одним плюральным блоком показывало фиксированную таблицу значений. Работало. Но только для строк с одним {count, plural}.

Теперь превью работает для любого количества плюральных и текстовых переменных в одной строке:

Copy
{count, plural, one {# item} other {# items}} and {length, plural, one {# page} other {# pages}}

Для каждой переменной — отдельное поле ввода. Для числовых (plural) — type="number", для текстовых — текстовый инпут. Результат рендерится по мере ввода, для каждой локали отдельно с учётом её CLDR-правил плюрализации.


Фильтры в редакторе

Небольшое изменение в поведении: фильтры Unused, Phantom и Stale раньше работали как чекбоксы — можно было включить одновременно с Missing. Теперь все шесть фильтров (All, Missing, Complete, Unused, Phantom, Stale) работают как радио-кнопки. Один активный фильтр за раз — поведение стало предсказуемым.


Итого

Всё это в версии 0.3.0:

bash Copy
npm install vue-i18n-kit@latest

Исходники и полный CHANGELOG — на GitHub.

Читать далее

05.04.2026

vue-i18n-kit: Locale Editor UI — дашборд, группы ключей и валидация

В новой версии vue-i18n-kit появился браузерный редактор локалей, который работает локально и не требует внешних сервисов. Дашборд с покрытием, группировка ключей по неймспейсам, валидация плейсхолдеров и ICU-синтаксиса, автоперевод пропущенных значений через LibreTranslate — и всё это прямо на вашей машине.

Метки
vue-i18n-kitлокализацияvue3i18nпереводыicu-messageformat