Механизм расширения в i18next построен вокруг плагинов, которые подключаются к ядру через единый интерфейс и позволяют добавлять функциональность без изменения основной логики библиотеки. Каждый плагин реализует строго определённый контракт и регистрируется через систему инициализации экземпляра i18next.
Плагины в i18next не являются «надстройками» в классическом смысле фреймворков — они интегрируются на уровне жизненного цикла и становятся частью пайплайна обработки переводов, загрузки ресурсов, детекции языка и постобработки строк.
Экосистема i18next условно делится на несколько категорий расширений, каждая из которых отвечает за отдельный этап интернационализации:
1. Backend-плагины Отвечают за загрузку переводов из внешних источников:
2. LanguageDetector-плагины Определяют текущий язык пользователя:
3. Plugin-модули интеграции фреймворков Используются для подключения i18next к UI-фреймворкам:
4. Post-processor-плагины Обрабатывают итоговую строку перевода:
Плагины регистрируются через метод use, который
добавляет их в цепочку инициализации экземпляра i18next. Порядок
подключения имеет значение: каждый плагин может модифицировать состояние
или поведение до передачи управления следующему модулю.
import i18next fr om 'i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
i18next
.use(Backend)
.use(LanguageDetector)
.init({
fallbackLng: 'en',
debug: true,
resources: {}
});
Каждый вызов use() регистрирует плагин в внутреннем
массиве middleware. При вызове init() происходит
последовательная инициализация всех подключённых модулей.
Любой плагин i18next должен реализовывать определённый набор методов, зависящий от типа расширения. Базовый жизненный цикл включает следующие стадии:
init — инициализация плагинаread — чтение данных (для backend)create — создание ресурсов (опционально)detect — определение языка (для language detector)process — постобработка результатаПример структуры backend-плагина:
class CustomBackend {
constructor(services, options = {}) {
this.services = services;
this.options = options;
}
init(services, backendOptions, i18nextOptions) {
this.services = services;
this.options = backendOptions;
}
read(language, namespace, callback) {
fetch(`/locales/${language}/${namespace}.json`)
.then(res => res.json())
.then(data => callback(null, data))
.catch(err => callback(err, false));
}
}
export default CustomBackend;
Backend-плагины являются наиболее часто используемым типом расширений. Они позволяют абстрагировать источник переводов и динамически подгружать их при необходимости.
Наиболее распространённый вариант — загрузка JSON-файлов через HTTP:
import Backend from 'i18next-http-backend';
i18next.use(Backend).init({
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
});
Шаблоны {{lng}} и {{ns}} подставляются
автоматически, что позволяет масштабировать структуру локализации без
ручной обработки.
При необходимости можно реализовать загрузку из любой системы хранения:
class DatabaseBackend {
read(language, namespace, callback) {
db.query(
'SEL ECT content FR OM translations WH ERE lang = ? AND ns = ?',
[language, namespace],
(err, result) => {
if (err) return callback(err);
callback(null, JSON.parse(result.content));
}
);
}
}
Backend-плагин становится частью pipeline загрузки ресурсов и может кэшировать данные, объединять запросы и управлять стратегией обновления переводов.
Плагины определения языка интегрируются на этапе инициализации и
формируют начальное значение lng.
Пример использования стандартного детектора:
import LanguageDetector from 'i18next-browser-languagedetector';
i18next.use(LanguageDetector).init({
detection: {
order: ['querystring', 'cookie', 'localStorage', 'navigator'],
caches: ['localStorage', 'cookie']
}
});
LanguageDetector проходит по списку стратегий сверху вниз:
navigator.languageКаждая стратегия реализуется как функция, возвращающая строку языка
или undefined.
Пример кастомной стратегии:
const customDetector = {
name: 'customDetector',
lookup() {
return window.appLang || null;
},
cacheUserLanguage(lng) {
window.appLang = lng;
}
};
i18next.services.languageDetector.addDetector(customDetector);
Плагины интеграции обеспечивают реактивную связь между i18next и UI-слоем.
import { initReactI18next } from 'react-i18next';
i18next.use(initReactI18next).init({
resources: {
en: {
translation: {
key: 'value'
}
}
}
});
Этот плагин связывает i18next с контекстом React и обеспечивает обновление компонентов при смене языка.
Интеграционные плагины:
useTranslation)Post-processing применяется после получения строки перевода, но до возврата результата вызывающей стороне.
const uppercasePostProcessor = {
type: 'postProcessor',
name: 'uppercase',
process(value) {
return value.toUpperCase();
}
};
i18next.use(uppercasePostProcessor);
Использование в ключе перевода:
i18next.t('key', { postProcess: 'uppercase' });
Цепочка выполнения строго определена:
Нарушение порядка может привести к некорректной загрузке переводов или отсутствию интерполяции.
Большинство backend-плагинов работают асинхронно. i18next поддерживает callback- и Promise-ориентированную модель.
i18next.init((err, t) => {
if (err) return;
console.log(t('key'));
});
При использовании backend-загрузчиков возможна ленивое подгружение namespaces:
i18next.loadNamespaces('common', () => {
console.log(i18next.t('common:key'));
});
Система плагинов построена на сервисной архитектуре. Внутренние
сервисы доступны через services:
Плагин может модифицировать поведение этих сервисов:
class LoggerPlugin {
init(services) {
services.logger = {
log: (msg) => console.log('[i18n]', msg)
};
}
}
При подключении нескольких backend или detector плагинов действует принцип приоритетов. Последний зарегистрированный плагин может переопределять поведение предыдущего, если реализует одинаковые методы.
Пример:
i18next
.use(BackendA)
.use(BackendB);
В таком случае BackendB может перекрыть read-логику BackendA, если они конфликтуют по сервисам.
Плагины обязаны корректно обрабатывать ошибки через callback или reject:
read(language, namespace, callback) {
try {
const data = loadFromSource();
callback(null, data);
} catch (e) {
callback(e, false);
}
}
При отсутствии корректной обработки ошибок i18next переходит к fallback-логике (fallbackLng или fallback namespace).
Backend-плагины часто реализуют кэширование для снижения количества запросов:
class CachedBackend {
constructor() {
this.cache = new Map();
}
read(lng, ns, cb) {
const key = `${lng}-${ns}`;
if (this.cache.has(key)) {
return cb(null, this.cache.get(key));
}
fetch(`/locales/${lng}/${ns}.json`)
.then(r => r.json())
.then(data => {
this.cache.set(key, data);
cb(null, data);
});
}
}
Плагины зависят от версии i18next API. Основные точки несовместимости:
initПроверка совместимости осуществляется через
peerDependencies в package.json плагина и внутренние
проверки при инициализации.
Архитектура плагинов в i18next формирует модульную систему, в которой каждая функциональная часть интернационализации вынесена в отдельный подключаемый компонент. Это обеспечивает независимость источников переводов, гибкость определения языка и возможность модификации итогового результата без вмешательства в ядро библиотеки.