i18next-scanner представляет собой инструмент статического анализа исходного кода, предназначенный для автоматического извлечения ключей переводов для библиотеки интернационализации i18next. Основная задача — избавить проект от ручного ведения словарей, минимизировать расхождения между кодом и файлами локализации, а также стандартизировать процесс обновления переводов.
Анализ выполняется на уровне исходных файлов без запуска приложения. Инструмент проходит по дереву проекта, разбирает код и ищет вызовы функций, соответствующих паттернам использования i18next.
Основные источники извлечения:
t('key')i18next.t('key')useTranslationПарсинг основан на AST (Abstract Syntax Tree), что позволяет точно определять структуру кода, а не полагаться на регулярные выражения.
Процесс извлечения можно разделить на несколько этапов:
Каждый этап может быть расширен через плагины и пользовательские трансформеры.
Основной способ настройки — файл конфигурации
i18next-scanner.config.js.
Пример базовой конфигурации:
module.exports = {
input: [
'src/**/*.{js,jsx,ts,tsx}'
],
output: './',
options: {
debug: false,
removeUnusedKeys: true,
sort: true,
func: {
list: ['t', 'i18next.t'],
extensions: ['.js', '.jsx', '.ts', '.tsx']
},
lngs: ['en', 'ru'],
defaultLng: 'en',
defaultNs: 'translation',
resource: {
loadPath: 'locales/{{lng}}/{{ns}}.json',
savePath: 'locales/{{lng}}/{{ns}}.json',
jsonIndent: 2
}
}
};
Ключевые параметры:
Наиболее распространённый сценарий — анализ вызовов
t().
Пример кода:
t('home.title');
t('button.save');
i18next-scanner извлекает строки home.title и
button.save, формируя структуру JSON:
{
"home": {
"title": ""
},
"button": {
"save": ""
}
}
Поддерживаются вложенные ключи через точечную нотацию.
В React-компонентах часто используется хук:
const { t } = useTranslation();
return <h1>{t('dashboard.header')}</h1>;
Инструмент корректно определяет вызов t внутри JSX и
извлекает ключ dashboard.header, даже если он находится
внутри выражения.
Дополнительно поддерживаются:
t('key', { value: 10 });
t('key', { defaultValue: 'text' });
Параметры интерполяции не влияют на извлечение ключа, но могут использоваться для анализа структуры перевода.
i18next-scanner поддерживает разделение переводов на namespaces.
Пример:
t('auth:login.title');
t('profile:settings.name');
Результат распределяется по соответствующим файлам:
locales/
en/
auth.json
profile.json
Если namespace не указан, используется defaultNs.
Библиотека i18next поддерживает pluralization и context:
t('item', { count: 5 });
t('button', { context: 'mobile' });
i18next-scanner фиксирует базовый ключ item и
button, а расширения форм формируются уже на этапе runtime
i18next.
Для множественных форм структура может выглядеть так:
{
"item": {
"one": "",
"other": ""
}
}
Для исключения определённых частей кода используются ignore-паттерны:
ignore: ['**/node_modules/**', '**/*.test.js']
Также можно исключать динамические вызовы:
t(variableKey);
Такие случаи не могут быть корректно проанализированы статически и часто игнорируются или требуют кастомных парсеров.
Одним из ключевых ограничений является невозможность точного извлечения динамических значений:
t(`error.${code}`);
AST-аналитика фиксирует только факт вызова функции, но не может предсказать конечное значение ключа. Это приводит к необходимости:
i18next-scanner поддерживает пользовательские трансформеры AST.
Пример расширения:
module.exports = {
transform: function (file, enc, done) {
const parser = this.parser;
const content = file.contents.toString();
parser.parseFuncFromString(content, { list: ['t'] }, (key) => {
parser.set(key, '');
});
done();
}
};
Такая модель позволяет обрабатывать нестандартные конструкции, например:
t()Часто используется через отдельный loader или plugin:
const I18NextScanner = require('i18next-scanner');
module.exports = {
plugins: [
new I18NextScanner({
options: {
input: 'src/**/*.{js,jsx}'
}
})
]
};
Классическая интеграция:
const gulp = require('gulp');
const scanner = require('i18next-scanner');
gulp.task('i18n', function () {
return gulp
.src('src/**/*.{js,jsx}')
.pipe(scanner())
.pipe(gulp.dest('./'));
});
При работе с TypeScript учитываются:
t<Key>()Scanner работает на уровне транспилированного кода или через парсинг TS AST при соответствующей настройке.
При больших проектах с десятками тысяч файлов ключевыми становятся:
node_modulesСильная сторона подхода — отсутствие необходимости запускать приложение, что ускоряет CI/CD процессы.
Особенно критичны шаблонные строки, где ключ формируется через конкатенацию или переменные.
На практике часто применяется иерархическая модель:
t('auth.login.button.submit');
t('auth.login.error.invalid_credentials');
Такая структура позволяет:
i18next-scanner становится частью цепочки локализации:
t('key')Связь между кодом и словарями становится формализованной и поддерживаемой на уровне сборки, а не вручную.