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

Прошло несколько дней с последнего большого апдейта. За это время в редакторе и CLI добавилось достаточно, чтобы написать отдельный пост — не просто список изменений, а объяснение зачем и как.
Коротко о главном: TypeScript-типы из ключей локали, детектор устаревших переводов, экспорт и импорт XLIFF/PO, поддержка DeepL в автопереводе, отчёт по покрытию в трёх форматах и переработанный дашборд. Плюс подробно про мастер настройки — он достаточно умный, чтобы заслуживать отдельного объяснения.
Мастер настройки (vue-i18n-kit init)
Расскажу подробно, потому что вопросы визарда выглядят так, будто он всё знает наперёд — а это не магия, там несколько шагов со своей логикой.
bash
npx vue-i18n-kit init
Шаг 0 — проверка существующего конфига
Первое, что делает init — ищет i18n-kit.config.json в корне проекта.
Если файл найден, визард показывает текущий список локалей и спрашивает:
◆ 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 — локали
◆ Locale codes (comma-separated, e.g. en, ru, de)
│ en, ru, de ← если нашёл в проекте, подставил сам
После ввода кодов для каждой локали по очереди спрашивает:
- Display name (например,
English,Русский) — обязательно - Флаг-эмодзи (
🇬🇧,🇷🇺) — необязательно, Enter пропускает
Коды валидируются по формату BCP 47 (en, zh-CN, pt-BR) прямо в поле.
Шаг 2 — директории
◆ 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. Если нашёл:
◆ Detected vite.config.ts. Add vueI18nMapPlugin automatically?
│ ● Yes / ○ No
Yes — добавит (или обновит) vueI18nMapPlugin в конфигурационный файл. Если плагин уже есть, просто обновит данные. Остальные плагины и настройки не трогает.
Результат в vite.config.ts:
ts
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-файла, который уже есть на диске, визард спрашивает:
◆ 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
"i18n:ui": "vue-i18n-kit auto-config && vue-i18n-kit ui"
Её задача — синхронизировать конфиг редактора с тем, что написано в main.ts.
Что она делает:
-
Сканирует исходники проекта и находит вызов
createVueI18nPlugin(...). Извлекает из него список локалей, пути к файлам (изimport(...)или~/...) иmeta-данные каждой локали. -
Генерирует
i18n-tools/locales.config.json— разрешённые абсолютные пути и метаданные. Именно его читает UI-сервер при старте. -
Генерирует
i18n-tools/locales.entries.json— карту вида{ "buttons.submit": ["src/components/Form.vue", "src/views/Login.vue"] }. Сканирует все.vue,.ts,.jsфайлы вsrc/**и собирает все вызовыt(),tm(),$t(). Эта карта нужна для определения неиспользуемых и phantom-ключей в редакторе. -
Обновляет
viteI18nMapPluginвvite.config.ts/nuxt.config.ts— заменяет весь вызов плагина актуальными данными. Остальное в конфиге не трогает.
Почему это удобно: createVueI18nPlugin — единственное место, где вы регистрируете локали. auto-config читает именно его, а не пытается угадать что-то из структуры папок. Добавили новую локаль в main.ts — запустили auto-config — редактор знает о ней.
Оба сгенерированных файла можно смело класть в .gitignore.
Что нового
TypeScript типы из ключей (vue-i18n-kit types)
bash
vue-i18n-kit types
# → src/i18n.d.ts
vue-i18n-kit types --watch
# пересоздаёт при изменении locale JSON
Команда читает эталонную локаль и генерирует union-тип TranslationKey из всех ключей:
ts
// 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
{
"staleTracking": true
}
Когда включено — каждый раз при сохранении значения в эталонной локали через редактор, в i18n-kit.notes.json записывается хеш этого значения. При следующей загрузке редактор сравнивает текущие значения с сохранёнными хешами — если расходятся, ключ помечается как устаревший.
В таблице: значок ⚠ outdated на ячейке ключа, фильтр stale в тулбаре. В панели детали — кнопка «Mark as reviewed», которая обновляет хеш и снимает метку.
Из командной строки:
bash
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
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
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 (шестерёнка в хедере редактора) появился переключатель движка:
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
vue-i18n-kit stats
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
vue-i18n-kit stats --format json --out coverage.json
Полезно когда хочется упасть в пайплайне при недостаточном покрытии:
yaml
- 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
vue-i18n-kit stats --format html
# → i18n-stats.html
Самодостаточный файл с таблицами и progress bar-ами в тёмной теме. Удобно бросить коллегам или прикрепить к задаче.
Dashboard — карточка Coverage

Однострочный progress bar общего покрытия заменён на полноценный блок с рядами по каждой локали:
Coverage 91% overall
─────────────────────────────────────────────────────────
🇬🇧 English ████████████████████ 100%
🇷🇺 Русский ████████████████░░░░ 89% 4 missing
🇩🇪 Deutsch ███████████████░░░░░ 77% 8 missing
Цвет бара и процента показывает состояние: зелёный (100%), фиолетовый (≥ 80%), жёлтый (50–79%), красный (< 50%).
Превью фраз с несколькими плюрализациями

Раньше превью для ICU-ключей с одним плюральным блоком показывало фиксированную таблицу значений. Работало. Но только для строк с одним {count, plural}.
Теперь превью работает для любого количества плюральных и текстовых переменных в одной строке:
{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
npm install vue-i18n-kit@latest
Исходники и полный CHANGELOG — на GitHub.