TL;DR: Современные инструменты локализации для React (i18next, react-intl, Lingui) решают базовые задачи, но для enterprise-решений требуют кастомизации. Рассмотрим архитектурные паттерны и инструменты для сложных кейсов.
Введение: почему локализация — это инженерная задача
Локализация (l10n) и интернационализация (i18n) в крупных проектах — это не просто подстановка строк. Это:
- Динамические плейсхолдеры (например,
{count} items) - Плюрализация (разные формы для разных чисел)
- Гендерные формы
- Контекстные переводы (одно слово в разных значениях)
- Ленивая загрузка локалей
Пример боли из реального проекта:
// Проблема: разная структура предложений в языках
`Hello ${name}, you have ${count} new messages`
// В японском порядок будет обратным
Основные инструменты и их кастомизация
1. react-i18next: промышленный стандарт
Базовый пример:
import { useTranslation } from 'react-i18next';
function Component() {
const { t } = useTranslation();
return <h1>{t('welcome_message', { name: 'John' })}</h1>;
}
Продвинутые фичи:
- Namespace separation: Разделение переводов по модулям
- Backend plugins: Загрузка из CMS/API
- ICU-форматирование:
{ "unread_messages": "{count, plural, =0 {No messages} one {1 message} other {# messages}}" }
2. react-intl: форматирование по стандартам
Сильные стороны:
- Встроенные форматеры дат, чисел, валют
- Поддержка ICU из коробки
- Оптимизация через
FormattedMessage
Пример:
<FormattedMessage
id="welcome"
defaultMessage="Hello {name}"
values={{ name: 'John' }}
/>
3. Lingui: компромиссный вариант
Особенности:
- JSX-синтаксис через макросы
- Экстракция строк в сборке
- Поддержка PO-файлов
import { Trans } from '@lingui/macro';
<Trans>Hello {name}</Trans>
Архитектурные решения для сложных кейсов
Динамическая загрузка переводов
Оптимальная стратегия:
// webpackChunkName для анализа бандлов
import(`src/locales/${language}.json` /* webpackChunkName: "locale-[request]" */)
Интеграция с TMS (Translation Management System)
Пример конфига для Crowdin:
module.exports = {
projectId: process.env.CROWDIN_PROJECT_ID,
token: process.env.CROWDIN_TOKEN,
files: [
{
source: 'src/locales/en.json',
translation: 'src/locales/%locale%.json'
}
]
}
Валидация переводов
Скрипт для проверки:
const validateTranslations = (baseLang, otherLangs) => {
const baseKeys = Object.keys(baseLang);
return otherLangs.every(lang => {
const langKeys = Object.keys(lang);
return baseKeys.every(key => langKeys.includes(key));
});
};
Перфоманс-оптимизации
- Кеширование переводов в IndexedDB
- Tree-shaking локалей:
// config/i18n.js
const supportedLocales = ['en', 'es', 'fr'];
export const isLocaleSupported = locale => supportedLocales.includes(locale);
- SSR-поддержка:
// server.js
import { I18nextProvider } from 'react-i18next';
import { renderToString } from 'react-dom/server';
const lng = req.acceptsLanguages(supportedLocales) || 'en';
const i18n = i18next.createInstance().use(Backend).init({ lng });
const html = renderToString(
<I18nextProvider i18n={i18n}>
<App />
</I18nextProvider>
);
Заключение: checklist для продакшн-решения
- Поддержка динамической загрузки локалей
- Интеграция с CI/CD для синхронизации переводов
- Валидация ключей на этапе сборки
- Оптимизированные бандлы по языкам
- SSR-совместимость
- Инструменты для переводчиков (TMS, контекст)
Для enterprise-проектов рекомендую связку: i18next + ICU + Crowdin/Phrase + кастомный babel-plugin для статического анализа.
Источник: https://www.reddit.com/r/reactjs/comments/1tc9otb/suggestions_on_localization_engineering/