В основе i18next лежит строго модульная архитектура, в которой ядро библиотеки выполняет роль координатора, а вся функциональность, зависящая от среды выполнения или специфики проекта, выносится в подключаемые плагины. Такая структура позволяет использовать i18next как в браузере, так и в Node.js, React Native или на серверных рендерах без изменения основного кода.
Центральный объект i18n реализует минимальный набор
функций: управление ресурсами переводов, переключение языков,
интерполяцию строк и обработку fallback-логики. Всё остальное
подключается через механизм расширений.
Плагин в i18next — это объект или функция, реализующая контракт через
метод init и регистрируемая в ядре через
i18next.use().
Общий принцип выглядит следующим образом:
i18n;i18next.init().Типичная регистрация:
import i18n from 'i18next';
i18n
.use(plugin)
.init(options);
Метод use() не выполняет немедленную инициализацию. Он
только добавляет плагин в очередь, которая обрабатывается при запуске
init().
Архитектура инициализации строится вокруг последовательного подключения модулей:
use()init()Каждый плагин получает ссылку на основной объект:
plugin.init(i18n, options);
Таким образом обеспечивается слабая связность: плагины не зависят друг от друга напрямую.
Архитектура разделяет расширения на несколько категорий, каждая из которых отвечает за конкретный слой функциональности.
Backend отвечает за загрузку переводов из внешних источников: файловой системы, HTTP, базы данных.
Контракт backend-плагина:
read(language, namespace, callback)create() (опционально)init() (опционально)Пример поведения:
backend.read('en', 'common', (err, data) => {
// загрузка ресурсов переводов
});
Backend подключается как стандартный модуль:
i18n.use(BackendPlugin);
Архитектурно backend отделён от ядра, что позволяет заменять источник данных без изменения логики интерполяции и работы с языками.
Модуль определения языка отвечает за выбор активной локали пользователя.
Поддерживаемые источники:
Контракт детектора:
lookup(options)cacheUserLanguage(lng, options)Пример:
detector.lookup = function(options) {
return window.localStorage.getItem('lng');
};
Этот плагин особенно важен в SSR-архитектурах, где язык определяется на основе HTTP-заголовков.
PostProcessor позволяет изменять уже переведённую строку после выполнения интерполяции.
Интерфейс:
nameprocess(value, key, options, translator)Пример логики:
postProcessor.process = function(value) {
return value.toUpperCase();
};
Архитектурно этот слой располагается после всех операций перевода и интерполяции, но до возврата результата в приложение.
Форматтеры отвечают за локализованное форматирование значений: даты, числа, валюты.
В новых версиях i18next часто делегирует форматирование
Intl API, но архитектурно поддерживается расширение через
кастомные форматтеры.
Форматтер получает:
Эти модули отвечают за хранение состояния:
Типичный сценарий — сохранение языка пользователя:
cache.save('lng', 'en');
Кэширование особенно важно в браузерных приложениях с динамической подгрузкой namespaces.
Все плагины проходят через единый механизм регистрации:
i18n.use = function(module) {
modules.push(module);
return i18n;
};
При init() происходит обход массива:
modules.forEach(m => {
if (typeof m.init === 'function') {
m.init(i18n, options[m.type]);
}
});
Каждый модуль получает доступ к общему контексту, но не может напрямую вмешиваться в другие плагины.
Процесс перевода в i18next можно представить как последовательность слоёв:
t() функция)Каждый слой выполняет строго ограниченную задачу.
Resource Store — это внутренняя структура хранения переводов.
Она организована по принципу:
resources[language][namespace] = translations
Пример:
{
en: {
common: {
hello: "Hello"
}
}
}
Backend плагины не взаимодействуют напрямую с UI-слоем. Они только наполняют store.
Вызов:
i18n.t('common:hello');
Проходит следующий путь:
namespace:key)Backend плагины часто работают асинхронно. i18next поддерживает lazy loading namespaces:
Механизм:
i18n.loadNamespaces('common', () => {
// namespace готов
});
Архитектурно это снижает начальную нагрузку приложения.
Пользовательские плагины могут добавлять:
Пример кастомного плагина:
const customPlugin = {
type: 'backend',
init: function(services, options) {},
read: function(language, namespace, callback) {
fetch(`/api/translations/${language}/${namespace}`)
.then(res => res.json())
.then(data => callback(null, data));
}
};
Core services i18next включают:
languageUtilspluralResolverinterpolatorresourceStoreloggerПлагины получают доступ к этим сервисам через
init().
Важно, что архитектура не допускает замены core без форка библиотеки, но допускает расширение поведения через обёртки.
Если подключено несколько модулей одного типа, порядок имеет значение:
Порядок влияет на конечный результат перевода, особенно при наличии нескольких postProcessor-ов.
В SSR окружениях i18next интегрируется как middleware:
Middleware получает доступ к req и res, что
позволяет:
Ключевой принцип архитектуры — контрактность:
Это позволяет:
Несмотря на гибкость, архитектура имеет ограничения:
Эти особенности компенсируются стабильностью core API и предсказуемым жизненным циклом.
i18next использует события для синхронизации состояния:
initializedloadedlanguageChangedmissingKeyПлагины могут подписываться:
i18n.on('languageChanged', lng => {
// реакция на смену языка
});
Это позволяет строить реактивные системы поверх ядра.
В React и Vue архитектура плагинов используется косвенно:
Плагины остаются вне UI-слоя, обеспечивая чистое разделение ответственности.