Спросите свой вопрос и получите сводку документа, используя эту страницу и выбранного вами поставщика AI
Содержимое этой страницы было переведено с помощью ИИ.
Смотреть последнюю версию оригинального контента на английскомЕсли у вас есть идея по улучшению этой документации, не стесняйтесь внести свой вклад, подав запрос на вытягивание на GitHub.
Ссылка на документацию GitHubКопировать Markdown документа в буфер обмена
Lingui против Intlayer | Бенчмарк интернационализации (i18n) для React и Next.js
Lingui и Intlayer - единственные две библиотеки в этом сравнительном исследовании, которые опираются на компилятор, а не на обычный рантайм. Lingui извлекает сообщения из макросов во время сборки и компилирует каталоги под каждую локаль. Intlayer компилирует словари на уровне компонентов и применяет tree-shaking отдельно для каждого языка. В теории их показатели должны быть близки. Цифры показывают, в чем они существенно расходятся.
Данные получены с помощью Benchmark Bloom - открытого набора тестов, который собирает одно и то же приложение с каждой библиотекой и замеряет то, что браузер реально скачивает и исполняет.
Кратко (tl;dr): Lingui ближе всех подобрался к Intlayer по объему чистого JavaScript на страницу: 115-120 КБ против 118,6 КБ на TanStack Start при настроенной ленивой загрузке, и 148,6 КБ против 141,3 КБ на Next.js. Однако в остальных аспектах образуется значительный разрыв: изолированно скомпилированный компонент Lingui весит 58-153 КБ против 6-8 КБ у Intlayer, гидратация занимает 28-34 мс против 11-14 мс, запасной текст исходной локали дает утечку 3-15% английских строк на французские страницы даже в оптимизированных сборках, а достижение такой оптимизации требует ручного извлечения, сборки и маршрутного разделения каталогов. Intlayer обеспечивает наилучшие показатели без какой-либо ручной настройки.
Коротко о главном
- Lingui - работает на макросах (
t`...`,<Trans>,msg), поддерживает синтаксис ICU MessageFormat, каталоги в форматах.po/ JSON, пайплайнlingui extract+lingui compile. Компилирует идентификаторы в компактные хеши, поддерживает динамическую подгрузку каталогов по языкам. Зрелое, не привязанное к фреймворку решение с развитой инфраструктурой переводческих утилит вокруг формата.po. - Intlayer - компонентно-ориентированная модель контента. Словари
.content.tsрасполагаются прямо рядом с целевым компонентом; компилятор на этапе сборки выполняет tree-shaking и загружает переводы по требованию для каждого компонента и языка; генерирует строгие типы TypeScript на основе контента, а пропущенные переводы вызывают ошибку сборки. Содержит встроенные middleware, SEO-хелперы, Визуальный редактор / CMS и модуль автоперевода через ИИ.
Открыть таблицу в модальном окне для четкого просмотра всех данных
Значки обновляются автоматически. Актуальные значения меняются со временем.
Сопоставление функциональности
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Возможность | Intlayer (react-intlayer / next-intlayer) | Lingui (@lingui/core / @lingui/react) |
|---|---|---|
| Переводы рядом с компонентами | ✅ Да, файл .content.ts хранится в одной папке с компонентом | ⚠️ Исходные строки внутри JSX через макросы; переводы в централизованных .po каталогах |
| Интеграция с TypeScript | ✅ Строгая типизация автоматически генерируется из содержимого | ⚠️ Макросы типизированы; идентификаторы без типов, недостающие ключи не подсвечиваются |
| Поиск отсутствующих переводов | ✅ Ошибка TypeScript + предупреждение/ошибка во время сборки | ⚠️ lingui extract показывает статистику; в рантайме тихо откатывается на английский текст |
| Форматированный контент (JSX/Markdown/комп.) | ✅ Прямая встроенная поддержка | ✅ Компонент <Trans> со вложенными элементами |
| Поддержка ICU | ⚠️ В разработке | ✅ Да (макросы plural, select, selectOrdinal) |
| Форматирование (даты, числа, валюты) | ✅ useNumber, useDate, ... (на базе нативного Intl) | ✅ i18n.date(), i18n.number() |
| Локализованный роутинг и middleware | ✅ Встроенный прокси/middleware, метод getMultilingualUrls | ❌ Отсутствует в базовом пакете |
| Инструменты SEO (hreflang, sitemap...) | ✅ Встроенные хелперы | ❌ Требуется ручная реализация |
| Синхронные серверные компоненты (RSC) | ✅ useIntlayer из next-intlayer/server работает в любых дочерних серверных компонентах | ⚠️ Требуется экземпляр I18n на запрос, передаваемый вручную или через setI18n |
| Tree-shaking (поставка только нужного) | ✅ На уровне компонентов и языков, автоматически компилятором | ⚠️ По языкам через lingui compile; по маршрутам требует ручного разделения файлов каталога |
| Ленивая загрузка (Lazy loading) | ✅ importMode: 'dynamic' (одна строка в конфигурационном файле) | ⚠️ Ручной вызов import() скомпилированных каталогов + i18n.load() / i18n.activate() |
| Очистка неиспользуемого контента | ✅ Устаревшие словари удаляются во время сборки | ✅ lingui extract --clean удаляет неактуальные сообщения |
| Проверка отсутствующих строк (CLI / CI) | ✅ npx intlayer content test | ⚠️ Отчеты lingui extract (по умолчанию сборка не падает с ошибкой) |
| Сборочный процесс | ✅ Один плагин (@intlayer/swc / @intlayer/babel / vite-intlayer) | ⚠️ Плагин макросов (Babel или SWC) + раздельные шаги extract и compile |
| Перевод с помощью искусственного интеллекта | ✅ Встроен, использует ваши собственные ключи API | ❌ Нет |
| Визуальный редактор / CMS | ✅ Бесплатный Visual Editor + подключаемая CMS | ❌ Нет (формат .po интегрируется со сторонними TMS) |
| Сервер MCP и Agent Skills | ✅ Да | ❌ Нет |
| Экосистема и сообщество | ⚠️ Моложе, но стремительно развивается | ✅ Зрелое, независимое от конкретного фреймворка решение |
Сравнительное тестирование
Что исследовалось
Пакет Benchmark Bloom собирает абсолютно идентичное приложение на каждой библиотеке: 10 страниц (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), 10 локалей (en, fr, es, de, it, pt, zh, ja, ko, ru), одинаковая верстка и контент. Замеры проводились на страницах en и fr. Каждая библиотека исследовалась в четырех стратегиях загрузки:
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Стратегия | Описание | Где применяется |
|---|---|---|
| static | Каталоги всех языков импортируются и загружаются целиком на старте | Быстрые прототипы, код от нейросетей |
| dynamic | Через import() подгружается каталог только активного языка, но для всего сайта сразу | Подавляющее большинство проектов |
| scoped-static | По каталогу на каждый маршрут, все каталоги упакованы в общий стартовый бандл | Встречается редко |
| scoped-dynamic | По каталогу на маршрут + динамический import(). Только активная страница и нужный язык | Проекты со строгим лимитом по весу |
У Intlayer отсутствует вариант "scoped": компилятор изолирует контент на уровне каждого компонента автоматически, поэтому режимы static и dynamic изначально работают максимально изолированно.
В ходе каждого теста замеряются:
- Lib size: вес gzip пустого компонента, подключающего исключительно библиотеку i18n (базовый оверхед рантайма).
- Page JS: средний вес gzip JavaScript, загружаемого на страницу (усреднено по всем страницам и локалям).
- Locale leak %: доля переведенных строк в загруженном JS, относящихся к языкам, которые пользователь не просматривает.
- Page leak %: доля строк в загруженном JS, относящихся к страницам, на которых пользователь не находится.
- Component avg: средний вес gzip отдельного компонента при изолированной сборке.
- E2E reactivity: чистое время от момента выбора нового языка до фактического обновления атрибута
html[lang]в DOM (Playwright, среднее по 5 прогонам). - Hydration: время завершения фазы гидратации React.
Значения зафиксированы в тестировании от 2026-09-12 на базе@lingui/react6.6.0 иintlayer9.5.1. Тестовое приложение намеренно сделано компактным (несколько десятков фраз на язык), поэтому утечки наглядно отражают системную проблему: по мере роста проекта они пропорционально увеличиваются.
Результаты на Next.js
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Библиотека | Стратегия | Lib size (gz) | Page JS ср. (gz) | Утечка языка | Утечка страниц | Компонент ср. (gz) | E2E-реактивность | Гидратация |
|---|---|---|---|---|---|---|---|---|
| база (без i18n) | - | 0,0 КБ | 141,0 КБ | 0,0% | 0,0% | 0,9 КБ | 13,4 мс | 11,8 мс |
| Lingui | static | 11,9 КБ | 207,4 КБ | 50,0% | 90,0% | 73,3 КБ | 15,3 мс | 15,2 мс |
| Lingui | dynamic | 11,9 КБ | 145,4 КБ | 2,8% | 89,9% | 19,9 КБ | 15,7 мс | 12,7 мс |
| Lingui | scoped-static | 11,9 КБ | 148,2 КБ | 2,7% | 89,1% | 20,4 КБ | 15,1 мс | 13,1 мс |
| Lingui | scoped-dynamic | 11,9 КБ | 148,6 КБ | 14,8% | 0,0% | 152,6 КБ | 16,1 мс | 14,8 мс |
next-intlayer | static | 5,5 КБ | 141,3 КБ | 0,0% | 0,0% | 8,5 КБ | 15,5 мс | 16,9 мс |
next-intlayer | dynamic | 5,5 КБ | 141,3 КБ | 0,0% | 0,0% | 6,9 КБ | 15,3 мс | 15,9 мс |
Анализ данных
- Базовый вес рантайма. Пустой компонент с Lingui весит 11,9 КБ gzip против 5,5 КБ с Intlayer. В масштабе страницы лучшая сборка Lingui оказывается на +7,3 КБ тяжелее Intlayer (148,6 против 141,3 КБ); Intlayer добавляет всего +0,3 КБ к весу приложения без интернационализации.
- Простая сборка создает колоссальный оверхед. Загрузка всех каталогов сразу дает 207,4 КБ на страницу (+66 КБ к базовому весу). Половина строк относится к чужому языку, а 90% - к посторонним страницам сайта.
- Динамическая загрузка исправляет язык, но не маршруты. При наличии одного каталога на язык утечка страниц сохраняется на уровне ~90%: весь французский каталог отдается на каждой странице. Чтобы добиться 0% утечки страниц в Lingui, приходится настраивать
scoped-dynamic: собирать отдельный каталог на каждый маршрут и вручную подключать его в страницы. - Утечка оригинального текста. Даже в наиболее продуманных схемах от 3% до 15% английских строк попадают на страницы на французском языке. Макросы Lingui встраивают исходную строку для подстраховки в итоговый бандл. Intlayer разрешает фолбеки на этапе сборки и доставляет клиенту только целевой язык.
- Взрывной рост размера компонентов в
scoped-dynamic. Каждый изолированный компонент весит в среднем 152,6 КБ, поскольку через цепочку импортов в него попадают каталоги других маршрутов. Тот же компонент наuseIntlayer()занимает всего 6,9 КБ.
Результаты на TanStack Start
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Библиотека | Стратегия | Lib size (gz) | Page JS ср. (gz) | Утечка языка | Утечка страниц | Компонент ср. (gz) | E2E-реактивность | Гидратация |
|---|---|---|---|---|---|---|---|---|
| база (без i18n) | - | 0,0 КБ | 111,0 КБ | 0,0% | 0,0% | 0,7 КБ | 8,1 мс | 21,6 мс |
| Lingui | static | 11,2 КБ | 152,2 КБ | 50,0% | 90,0% | 58,0 КБ | 3,9 мс | 19,9 мс |
| Lingui | dynamic | 11,2 КБ | 115,2 КБ | 9,3% | 0,0% | 85,5 КБ | 5,9 мс | 28,0 мс |
| Lingui | scoped-static | 11,2 КБ | 120,8 КБ | 4,0% | 0,0% | 147,9 КБ | 7,1 мс | 33,9 мс |
| Lingui | scoped-dynamic | 11,2 КБ | 120,2 КБ | 8,6% | 0,0% | 83,7 КБ | 42,1 мс | 32,9 мс |
intlayer | static | 5,0 КБ | 125,8 КБ | 50,0% | 0,0% | 8,1 КБ | 3,2 мс | 11,5 мс |
intlayer | dynamic | 5,0 КБ | 118,6 КБ | 0,0% | 0,0% | 6,3 КБ | 3,6 мс | 14,1 мс |
@intlayer/lingui (адаптер) | dynamic | 10,3 КБ | 137,0 КБ | 9,9% | 0,0% | 12,8 КБ | 2,9 мс | 19,7 мс |
Анализ данных
- По объему JS на страницу Lingui незначительно выигрывает. Вариант Lingui
dynamicфиксирует 115,2 КБ, что на 3,4 КБ меньше, чем 118,6 КБ у Intlayer. Скомпилированные каталоги Lingui с хешированными ключами очень компактны, а роутер TanStack Start отлично разделяет код маршрутов, поэтому утечка страниц исчезает уже на шагеdynamic. - Все остальные метрики на стороне Intlayer. Гидратация с Lingui длится 28-34 мс против 11-14 мс с Intlayer: методы
i18n.load()+i18n.activate()обязаны отработать на клиенте до старта гидратации React. Отдельные компоненты весят 58-148 КБ вместо 6-8 КБ. Утечка исходного языка не обнуляется никогда (составляя 4-9%). - Смена языка в оптимизированном режиме заметно замедлена. Lingui в схеме
scoped-dynamicтратит 42 мс на сменуhtml[lang], поскольку браузер должен сначала запросить, получить и активировать новый каталог маршрута. Intlayer переключает язык за 3-4 мс в обоих сценариях. - Строка
staticу Intlayer сразу обеспечивает 0% утечки страниц, так как в бандл включаются исключительно словари, импортированные задействованными на странице компонентами. А параметрimportMode: 'dynamic'устраняет и языковую утечку. @intlayer/linguiсохраняет синтаксис макросов Lingui, связывая их со словарями Intlayer. Это решение жертвует небольшим объемом на страницу (137 КБ из-за присутствия макро-рантайма), взамен давая облегченные компоненты (12,8 КБ) и быструю гидратацию. Прекрасный вариант для плавного перехода.
В чем фундаментальная причина? Два компилятора, две единицы деления
Обе библиотеки компилируют код, но принципиально отличается объект компиляции.
Lingui компилирует каталоги. Макросы в коде извлекаются в единый файл .po на язык, а затем компилируются в модуль JS на язык. Главная единица деления - локаль. Чтобы разделить данные глубже (по маршрутам или компонентам), вам придется заводить отдельные каталоги, прописывать правила в lingui.config.ts и вручную настраивать их загрузку. Экземпляр I18n глобален, и каждый useLingui() подключает компонент ко всему его содержимому.
Копировать код в буфер обмена
Intlayer компилирует словари. Каждый файл .content.ts - это изолированный словарь под определенным ключом; компилятор выясняет, какой компонент использует какой ключ, и формирует компактный JSON строго для этого компонента и языка. Главная единица деления - компонент. Привязка к маршрутам происходит автоматически: страница скачивает словари только тех компонентов, которые выводятся на экран.
Копировать код в буфер обмена
Именно поэтому архитектура scoped-dynamic формируется в Intlayer автоматически на этапе сборки, тогда как в Lingui это требует масштабной ручной настройки.
Чтобы повторить показатели строкиdynamic, активируйтеdictionary.importMode: 'dynamic'вintlayer.config.ts. Подробнее в документации по оптимизации бандла.
Опыт разработки (Developer Experience)
Настройка
Lingui
Копировать код в буфер обмена
Копировать код в буфер обмена
Затем в сборщик добавляется плагин @lingui/babel-plugin-lingui-macro (или @lingui/swc-plugin), после правок выполняется lingui extract, перед сборкой - lingui compile, а приложение оборачивается в <I18nProvider i18n={i18n}>.
Intlayer
Копировать код в буфер обмена
Добавьте плагин intlayer() в vite.config.ts (или withIntlayer() в next.config.ts) и оберните дерево компонентов в <IntlayerProvider>. Никаких ручных команд извлечения или сборки: словари компилируются автоматически бандлером.
Компоненты
Lingui
Копировать код в буфер обмена
Английский текст пишется прямо в компоненте; перевод на французский хранится в src/locales/fr/messages.po под сгенерированным хеш-идентификатором после выполнения lingui extract. Если забыть запустить команду извлечения или сборки, на экране незаметно останется английский текст.
Intlayer
Копировать код в буфер обмена
Копировать код в буфер обмена
Оба языка находятся в одном файле рядом с компонентом. Отсутствие перевода для fr приведет к ошибке сборщика, а опечатка в имени ключа будет немедленно подсвечена TypeScript.
Вне компонентов React
Метаданные, функции загрузки данных (loaders), серверные функции: в любом контексте без дерева React.
Lingui
Копировать код в буфер обмена
Создание нового экземпляра I18n на каждый вызов, ручной импорт конкретного каталога и использование msg + i18n._() вместо привычного t. Как отмечается в примечаниях к бенчмарку, постоянный выбор между t, t` ` , i18n.t(), msg или <Trans> часто сбивает с толку.
Intlayer
Копировать код в буфер обмена
Использование макросов Lingui со словарями Intlayer
@intlayer/lingui работает как прозрачный адаптер для @lingui/core и @lingui/react. Макросы компилируются в прежнем режиме; генерируемые вызовы i18n._() берут данные из словарей Intlayer, а плагины синхронизации сохраняют файлы .po в качестве источника данных. Формы множественного числа и условия ICU отображаются абсолютно идентично.
Копировать код в буфер обмена
Оставьте @lingui/babel-plugin-lingui-macro или @lingui/swc-plugin в конфигурации сборщика перед компилятором Intlayer. См. документацию по совместимости с Lingui.
Что выбрать для вашего проекта?
- Выбирайте Lingui, если вам необходим синтаксис ICU MessageFormat с типизированными макросами, переводчики работают через файлы
.poв сформированном процессе TMS, вам удобнее писать текст прямо в JSX, а команда готова поддерживать процесс извлечения, сборки и деления каталогов. При правильной настройке ленивой загрузки размер итоговой страницы крайне конкурентен. - Выбирайте Intlayer, если вам нужны изолированный контент на уровне компонентов, строгая типизация TypeScript, контроль отсутствующих ключей на этапе сборки, автоматический tree-shaking и ленивая загрузка без конфигурации, легковесные компоненты, мгновенная смена локалей и встроенные инструменты редактирования (Визуальный редактор, CMS, перевод через ИИ, сервер MCP). Идеально подходит для модульных систем и дизайн-систем.
- Выбирайте
@intlayer/lingui, если у вас уже есть кодовая база на Lingui и вы хотите постепенно перейти на архитектуру словарей Intlayer, не переписывая макросы.
Похожие сравнения
- next-intl против Intlayer (в рамках того же бенчмарка)
- i18next против Intlayer (в рамках того же бенчмарка)
- vue-i18n против Intlayer (в рамках того же бенчмарка)
- Компилятор против декларативной i18n
Звезды на GitHub
Количество звезд на GitHub отражает интерес индустрии, уровень доверия сообщества и перспективность развития проекта. Это наглядно показывает, сколько разработчиков находят библиотеку полезной в реальной работе.
Заключение
Lingui - сильнейшая гибридная библиотека в данном бенчмарке. Ее скомпилированные и хешированные каталоги дают размер JavaScript на страницу, практически равный показателям Intlayer, а на TanStack Start даже слегка превосходящий его. Если бы единственным критерием были килобайты на страницу, результатом стала бы боевая ничья.
Но это не единственный показатель. Компилятор Lingui ограничен границами локали; все, что лежит ниже (каталоги маршрутов, ленивая загрузка, очистка запасного текста), требует ручного труда разработчика. Бенчмарк демонстрирует цену этого ограничения: компоненты в 10-20 раз тяжелее, гидратация в 2-3 раза медленнее, постоянная утечка 3-15% исходных текстов и пауза в 42 мс при переключении языка в оптимизированной сборке. Компилятор Intlayer работает на уровне каждого компонента, обеспечивая 6-8 КБ, 11-14 мс, 0% и 3-4 мс из коробки без лишней настройки.
Все первичные данные, тестовые приложения и скрипты опубликованы в репозитории Benchmark Bloom. Вы можете повторить эти тесты самостоятельно.
Подробнее читайте в материале 'Почему Intlayer?'.
Комментарии
Пока нет комментариев. Будьте первым, кто поделится своими мыслями.
