Библиотека i18next предназначена для интернационализации и локализации приложений на JavaScript. Она предоставляет гибкую систему перевода интерфейсов, поддержку нескольких языков, динамическую загрузку переводов, работу с форматированием строк, множественными формами, контекстами и интеграцию с популярными фреймворками.
Архитектура библиотеки построена вокруг нескольких ключевых компонентов:
Базовая инициализация выглядит следующим образом:
import i18next from 'i18next';
i18next.init({
lng: 'ru',
fallbackLng: 'en',
resources: {
ru: {
translation: {
welcome: 'Добро пожаловать'
}
},
en: {
translation: {
welcome: 'Welcome'
}
}
}
});
Получение перевода выполняется через функцию t():
console.log(i18next.t('welcome'));
Переводы в I18next организуются в виде объектов ресурсов.
Структура ресурсов:
{
язык: {
namespace: {
ключ: значение
}
}
}
Пример:
resources: {
ru: {
common: {
save: 'Сохранить',
cancel: 'Отмена'
}
},
en: {
common: {
save: 'Save',
cancel: 'Cancel'
}
}
}
Использование namespace:
i18next.init({
ns: ['common'],
defaultNS: 'common'
});
i18next.t('save');
Либо:
i18next.t('common:save');
Namespaces позволяют разделять переводы по модулям приложения.
Типичная структура:
locales/
├── en/
│ ├── common.json
│ ├── auth.json
│ └── dashboard.json
└── ru/
├── common.json
├── auth.json
└── dashboard.json
Пример загрузки:
i18next.init({
ns: ['common', 'auth'],
defaultNS: 'common'
});
Использование:
i18next.t('auth:login');
Преимущества namespace:
Fallback используется, если перевод отсутствует.
Настройка:
i18next.init({
lng: 'fr',
fallbackLng: 'en'
});
Если во французском языке ключ отсутствует, библиотека возьмёт значение из английского.
Поддерживаются массивы fallback-языков:
fallbackLng: ['en', 'ru']
Можно задавать fallback по регионам:
fallbackLng: {
'de-CH': ['fr', 'it'],
default: ['en']
}
I18next поддерживает древовидную структуру ключей.
Пример:
resources: {
ru: {
translation: {
user: {
profile: {
title: 'Профиль'
}
}
}
}
}
Использование:
i18next.t('user.profile.title');
Это особенно полезно для больших приложений.
Интерполяция позволяет вставлять динамические данные в строки перевода.
Пример:
resources: {
ru: {
translation: {
greeting: 'Привет, {{name}}'
}
}
}
Использование:
i18next.t('greeting', {
name: 'Алексей'
});
Результат:
Привет, Алексей
Несколько параметров:
welcome: 'Пользователь {{name}} имеет {{count}} сообщений'
i18next.t('welcome', {
name: 'Иван',
count: 10
});
По умолчанию I18next экранирует HTML для защиты от XSS.
interpolation: {
escapeValue: true
}
Пример:
message: 'Привет {{name}}'
i18next.t('message', {
name: '<script>alert(1)</script>'
});
Результат будет безопасным.
Отключение экранирования:
interpolation: {
escapeValue: false
}
Использовать такую настройку необходимо осторожно.
Библиотека поддерживает правила множественного числа для разных языков.
Пример для английского:
resources: {
en: {
translation: {
item_one: '{{count}} item',
item_other: '{{count}} items'
}
}
}
Использование:
i18next.t('item', { count: 1 });
i18next.t('item', { count: 5 });
Для русского языка формы сложнее:
resources: {
ru: {
translation: {
item_one: '{{count}} товар',
item_few: '{{count}} товара',
item_many: '{{count}} товаров',
item_other: '{{count}} товара'
}
}
}
Примеры:
i18next.t('item', { count: 1 });
i18next.t('item', { count: 2 });
i18next.t('item', { count: 5 });
I18next автоматически выбирает нужную форму.
Контексты используются для выбора перевода в зависимости от ситуации.
Пример:
resources: {
ru: {
translation: {
friend_male: 'Друг',
friend_female: 'Подруга'
}
}
}
Использование:
i18next.t('friend', {
context: 'male'
});
И:
i18next.t('friend', {
context: 'female'
});
Контексты можно комбинировать с множественными формами.
I18next поддерживает форматирование через Intl.
Пример:
interpolation: {
format(value, format, lng) {
if (format === 'currency') {
return new Intl.NumberFormat(lng, {
style: 'currency',
currency: 'USD'
}).format(value);
}
return value;
}
}
Использование:
price: 'Цена: {{value, currency}}'
i18next.t('price', {
value: 1500
});
Форматирование дат:
interpolation: {
format(value, format, lng) {
if (value instanceof Date) {
return new Intl.DateTimeFormat(lng).format(value);
}
return value;
}
}
Использование:
today: 'Сегодня {{date}}'
i18next.t('today', {
date: new Date()
});
Язык можно изменять во время работы приложения.
i18next.changeLanguage('en');
Пример:
button.addEventListener('click', () => {
i18next.changeLanguage('ru');
});
После смены языка интерфейс может быть автоматически обновлён через интеграции с фреймворками.
Для автоматического определения языка используется плагин
i18next-browser-languagedetector.
Пример:
import LanguageDetector from 'i18next-browser-languagedetector';
i18next
.use(LanguageDetector)
.init({
fallbackLng: 'en'
});
Источники определения:
navigator.language;Для загрузки переводов по сети используется
i18next-http-backend.
Установка backend:
import Backend from 'i18next-http-backend';
i18next
.use(Backend)
.init({
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
});
Файл перевода:
/locales/ru/common.json
Содержимое:
{
"hello": "Привет"
}
Загрузка переводов только при необходимости:
i18next.loadNamespaces('dashboard');
Такой подход уменьшает стартовый размер приложения.
I18next поддерживает кэширование через localStorage.
Пример:
import ChainedBackend from 'i18next-chained-backend';
import LocalStorageBackend from 'i18next-localstorage-backend';
import HttpBackend from 'i18next-http-backend';
i18next
.use(ChainedBackend)
.init({
backend: {
backends: [
LocalStorageBackend,
HttpBackend
],
backendOptions: [
{
expirationTime: 7 * 24 * 60 * 60 * 1000
},
{
loadPath: '/locales/{{lng}}/{{ns}}.json'
}
]
}
});
Для React используется библиотека react-i18next.
Инициализация:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n
.use(initReactI18next)
.init({
lng: 'ru'
});
Использование хука:
import { useTranslation } from 'react-i18next';
function App() {
const { t } = useTranslation();
return <h1>{t('welcome')}</h1>;
}
React-интеграция поддерживает Suspense.
<Suspense fallback="Loading...">
<App />
</Suspense>
Это позволяет ожидать загрузку переводов до отображения интерфейса.
Компонент Trans позволяет использовать HTML и
React-компоненты внутри переводов.
Пример перевода:
{
"description": "Перейдите <1>по ссылке</1>"
}
Использование:
<Trans i18nKey="description">
Перейдите <a href="/home">по ссылке</a>
</Trans>
Через плагин ICU библиотека получает расширенные возможности форматирования.
Пример:
import ICU from 'i18next-icu';
i18next.use(ICU).init();
Перевод:
{
"message": "{count, plural, one {# сообщение} few {# сообщения} many {# сообщений}}"
}
I18next поддерживает post processors.
Пример:
i18next.use({
type: 'postProcessor',
name: 'uppercase',
process(value) {
return value.toUpperCase();
}
});
Использование:
i18next.t('hello', {
postProcess: 'uppercase'
});
Можно указывать запасные ключи:
i18next.t(['error.404', 'error.unspecific']);
Если первый ключ отсутствует, используется второй.
Метод exists():
i18next.exists('profile.title');
Пример:
if (i18next.exists('new.feature')) {
renderFeature();
}
I18next умеет возвращать целые объекты.
Пример:
resources: {
ru: {
translation: {
menu: {
home: 'Главная',
about: 'О нас'
}
}
}
}
Использование:
i18next.t('menu', {
returnObjects: true
});
Пример:
resources: {
ru: {
translation: {
errors: [
'Ошибка сети',
'Ошибка сервера'
]
}
}
}
Получение массива:
i18next.t('errors', {
returnObjects: true
});
I18next предоставляет систему событий.
Пример:
i18next.on('languageChanged', (lng) => {
console.log('Язык изменён:', lng);
});
Другие события:
initialized;loaded;failedLoading;missingKey.Настройка:
saveMissing: true
Пример:
i18next.init({
saveMissing: true
});
Можно отправлять отсутствующие ключи на сервер.
Пример backend:
const Backend = {
type: 'backend',
read(language, namespace, callback) {
fetch(`/api/translations/${language}/${namespace}`)
.then((response) => response.json())
.then((data) => callback(null, data))
.catch((error) => callback(error, false));
}
};
Подключение:
i18next.use(Backend);
Для серверных приложений существует middleware.
Пример с Express:
import middleware from 'i18next-http-middleware';
app.use(middleware.handle(i18next));
Получение перевода:
req.t('welcome');
I18next поддерживает SSR.
Основные задачи SSR:
Для React часто используется связка:
Для Next.js применяется библиотека next-i18next.
Пример конфигурации:
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'ru']
}
};
Использование:
import { useTranslation } from 'next-i18next';
const { t } = useTranslation('common');
I18next предоставляет типизацию.
Пример:
import i18next from 'i18next';
i18next.t('welcome');
Расширение типов:
declare module 'i18next' {
interface CustomTypeOptions {
defaultNS: 'common';
resources: {
common: {
welcome: string;
};
};
}
}
Преимущества:
Основные методы оптимизации:
Рекомендуемая структура:
src/
├── locales/
│ ├── en/
│ │ ├── common.json
│ │ ├── auth.json
│ │ └── dashboard.json
│ └── ru/
│ ├── common.json
│ ├── auth.json
│ └── dashboard.json
Рекомендации:
Плохо:
<button>Сохранить</button>
Хорошо:
<button>{t('save')}</button>
Плохо:
'Привет ' + name
Хорошо:
t('hello', { name })
Неправильно:
`${count} товаров`
Правильно:
t('items', { count })
Большие приложения без namespace быстро становятся неуправляемыми.
Основные достоинства библиотеки: