Создание альтернативы i18n¶
Кризис производительности в современной i18n¶
Если вы используете i18next с TypeScript, вы, вероятно, чувствовали эту боль. Несмотря на улучшения производительности, реальность отрезвляет:
протестировано на Apple M1
- Компиляция TypeScript: Каждые 1,000 ключей переводов добавляют ~1 секунду к времени сборки
tsc
- Отзывчивость IDE: Подсказки типов замедляются на 0.3+ секунды с большими словарями
- Размер бандла: i18next весит 41.6 КБ (13.2 КБ gzip) еще до добавления переводов
- Производительность во время выполнения: Парсинг пользовательского DSL становится узким местом в масштабе
Реальные разработчики чувствуют эту боль:
"Нам пришлось полностью убрать типизацию i18n из-за переполнения памяти CI с ~3к переводами" - Продакшн разработчик
"Удаление i18next улучшило производительность нашего SSR в 3 раза без потери функциональности" - Инженер по производительности
Но вот в чем дело: современный JavaScript имеет все необходимое встроенное.
Почему использовать нативные решения?¶
API интернационализации значительно созрел. У нас есть:
Intl.NumberFormat
для чисел, валют, единиц измеренияIntl.DateTimeFormat
для дат и времениIntl.PluralRules
для логики множественного числаIntl.RelativeTimeFormat
для форматирования "2 дня назад"
Эти API имеют нулевую стоимость, поддерживают tree-shaking и молниеносно быстры.
Решение: Система i18n из 5 файлов¶
Вот полная система интернационализации, которая проще, быстрее и более удобна в сопровождении, чем традиционные библиотеки:
1. Определение и управление языками¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
2. Динамическая загрузка переводов¶
1 2 3 4 5 6 7 8 9 10 11 12 |
|
3. Типобезопасные файлы переводов¶
1 2 3 4 5 6 7 8 9 10 |
|
4. Простая утилита для работы с cookie¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
5. Использование в компонентах¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Преимущества¶
✅ Молниеносно быстрые типы: Прямой доступ к объекту, без сложного сопоставления.
✅ Нулевые накладные расходы времени выполнения: Без парсинга DSL, без дополнительного размера библиотеки.
✅ Автоматическое разделение кода: Загружайте только те переводы, которые вам нужны
✅ Полная типобезопасность: TypeScript автоматически выводит всё
✅ Нативное форматирование: Используйте браузерные API для чисел, дат, множественного числа
✅ Простой API: t.key
вместо t('key')
✅ SSR из коробки: никаких дополнительных настроек для SSR
✅ Независимость от фреймворка: используйте со Svelte, React, Vue или jQuery 😁
Продвинутые паттерны¶
Поддержка пространств имён¶
Создавайте подкаталоги для различных функциональных областей:
1 2 3 4 5 6 7 8 9 |
|
Множественные формы с Intl.PluralRules¶
Для сложных форм множественного числа интегрируйте нативный API Intl.PluralRules
непосредственно в ваш словарь:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Использование остается красиво простым:
1 2 3 |
|
Прекрасно то, что каждый язык может определить свои собственные правила множественного числа - русский имеет другие категории по сравнению с английским, и API Intl.PluralRules
обрабатывает всю сложность за вас.
Серверный рендеринг¶
Одно из самых больших преимуществ этого подхода становится очевидным при серверном рендеринге. Это просто работает из коробки - никакой сложной настройки сервера, никаких несоответствий гидратации, никаких головных болей с определением локали.
Для серверных сред без состояния (Lambda, Vercel Functions и т.д.) это решение идеально подходит как есть. Каждый запрос получает свой собственный контекст выполнения, поэтому статические импорты работают прекрасно.
Для серверов с состоянием (Express, Fastify и т.д.) у вас есть простой путь миграции. Преобразуйте точечную нотацию t.key
в вызовы функций t().key
, затем реализуйте функцию t
используя AsyncLocalStorage
из Node.js:
1 2 3 4 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 |
|
Это обеспечивает изоляцию локали для каждого запроса без загрязнения глобального состояния - именно то, что нужно для обработки одновременных запросов.
Компромисс¶
Основной недостаток: Переводы живут в коде, что затрудняет их редактирование для нетехнических членов команды. Это не всегда проблема - многие команды предпочитают контролируемые разработчиками переводы для лучшего контроля версий и процессов проверки.
Для команд, которым нужно нетехническое редактирование, рассмотрите:
- Генерацию во время сборки из внешних источников
- Git-воркфлоу с инструментами управления переводами
- Гибридные подходы для разных типов контента
Попробуйте¶
Этот подход полностью изменил то, как я думаю об интернационализации. Иногда лучшее решение - не самое популярное, а то, которое использует то, что уже встроено в платформу.
Каков ваш опыт работы с производительностью i18n? Нашли ли вы другие легковесные альтернативы? Поделитесь своими мыслями в комментариях!