Организация переводов в i18next напрямую влияет на масштабируемость приложения, скорость загрузки и удобство сопровождения. При росте проекта монолитный файл переводов перестаёт быть управляемым: увеличивается вероятность конфликтов, усложняется локализация новых функций, а загрузка лишних строк становится неоправданной нагрузкой.
Разделение переводов строится вокруг идеи контекстной изоляции текста — каждый набор строк должен обслуживать ограниченную область интерфейса и загружаться только тогда, когда он нужен.
Ключевая стратегия в i18next — использование namespace (пространств имён).
Переводы группируются в логические блоки:
Каждый namespace хранится в отдельном файле:
locales/
en/
common.json
auth.json
profile.json
ru/
common.json
auth.json
profile.json
auth.json:
{
"login": "Вход",
"logout": "Выход",
"emailPlaceholder": "Введите email",
"passwordPlaceholder": "Введите пароль"
}
common.json:
{
"save": "Сохранить",
"cancel": "Отмена",
"loading": "Загрузка..."
}
i18next.t('login', { ns: 'auth' });
i18next.t('save', { ns: 'common' });
Или при настройке fallback namespace:
i18next.init({
ns: ['common', 'auth', 'profile'],
defaultNS: 'common'
});
В современных фронтенд-архитектурах чаще используется разбиение по фичам, а не по типам строк.
Каждая бизнес-функция приложения получает собственный набор переводов.
locales/
ru/
feature-auth.json
feature-cart.json
feature-checkout.json
feature-cart.json:
{
"title": "Корзина",
"empty": "Корзина пуста",
"removeItem": "Удалить товар",
"total": "Итого"
}
i18next.init({
ns: ['feature-auth', 'feature-cart', 'feature-checkout'],
defaultNS: 'feature-auth'
});
i18next.t('title', { ns: 'feature-cart' });
Функциональное разделение лучше соответствует компонентной архитектуре:
Подход применяется в более крупных системах, где важна унификация терминов.
locales/
ru/
ui.json
domain.json
system.json
{
"button.save": "Сохранить",
"button.delete": "Удалить",
"input.search": "Поиск"
}
{
"order.status.pending": "В обработке",
"order.status.completed": "Завершён",
"payment.method.card": "Банковская карта"
}
Недостаток — усложнение структуры для небольших приложений.
Разделение переводов становится особенно эффективным при использовании динамической загрузки.
Переводы загружаются только при обращении к маршруту или компоненту.
import Backend from 'i18next-http-backend';
i18next.use(Backend).init({
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json'
},
ns: ['common', 'auth', 'profile'],
defaultNS: 'common'
});
i18next.loadNamespaces('profile');
Или в React:
useEffect(() => {
i18next.loadNamespaces('profile');
}, []);
Структура локалей почти всегда включает уровень языка:
locales/
en/
ru/
de/
i18next поддерживает fallback:
i18next.init({
fallbackLng: 'en'
});
Структура ключей должна быть идентичной во всех языках.
Иначе fallback теряет смысл.
В сложных системах один и тот же термин может иметь разные значения.
Слово “status”:
{
"order.status": "Статус заказа",
"user.status": "Статус пользователя",
"task.status": "Статус задачи"
}
{
"order": {
"status": "Статус заказа"
},
"user": {
"status": "Статус пользователя"
}
}
i18next.t('order.status');
i18next.t('user.status');
Переводы часто содержат динамические значения.
{
"welcome": "Привет, {{name}}",
"cart.items": "Товаров: {{count}}"
}
Интерполяционные строки стоит выделять в отдельные группы:
locales/
ru/
messages.json
labels.json
templates.json
Шаблоны обычно:
В монорепо переводами часто пользуются несколько приложений.
packages/
app-web/
locales/
app-admin/
locales/
shared/
locales/
Содержит:
Без shared слоя возникает:
При активной разработке структура ключей меняется.
locales/
ru/
v1/
v2/
i18next.init({
ns: ['v2/common', 'v2/auth']
});
На практике почти всегда используется гибрид:
locales/
ru/
common.json
errors.json
features/
auth.json
cart.json
checkout.json
domains/
order.json
user.json
Приводит к:
Когда в одном файле:
Разные языки содержат:
Даже при правильной структуре весь перевод может попадать в bundle.
entity.action.context
Примеры:
{
"cart.remove.item": "Удалить товар",
"auth.login.submit": "Войти",
"order.status.pending": "Ожидает обработки"
}