Спросите свой вопрос и получите сводку документа, используя эту страницу и выбранного вами поставщика AI
Содержимое этой страницы было переведено с помощью ИИ.
Смотреть последнюю версию оригинального контента на английскомЕсли у вас есть идея по улучшению этой документации, не стесняйтесь внести свой вклад, подав запрос на вытягивание на GitHub.
Ссылка на документацию GitHubКопировать Markdown документа в буфер обмена
next-intl VS Intlayer | Benchmark интернационализации Next.js (i18n)
next-intl - самая популярная библиотека i18n для Next.js. Intlayer - это альтернатива на основе компилятора с областью видимости компонента. Обе локализуют приложение App Router. Вопрос в том, какие затраты каждая из них влечет после сборки приложения.
Эта статья - не учебное пособие. Это сравнение, подкрепленное числами из Benchmark Bloom, открытого набора инструментов для тестирования, который создает одно и то же приложение с каждой библиотекой и измеряет то, что браузер фактически загружает и выполняет.
tl;dr: На одном и том же приложении Next.jsnext-intlдобавляет +12.6 KB gzip JavaScript на каждую страницу, против +0.3 KB для Intlayer. Без дополнительной работыnext-intlпоставляет ~90% строк иностранных страниц с каждой страницей. Чтобы достичь утечки 0% сnext-intl, требуется область видимости namespace и per-pagepick(messages, [...]). Intlayer достигает 0% по умолчанию, потому что его компилятор ограничивает контент для каждого компонента. Если вы хотите APInext-intlс выходом Intlayer, адаптер@intlayer/next-intlпоказал 147.5 KB на страницу против 153.6 KB с оригиналом.
Вкратце
- next-intl - Легковесная, хорошо документированная, поддержка ICU message format, встроенная поддержка App Router с middleware, форматировщиками и помощниками навигации. Контент хранится в централизованных JSON каталогах; оптимизация производительности (namespaces, выборка сообщений для каждой страницы, ленивая загрузка) - ваша ответственность.
- Intlayer - Компонентоцентричная модель контента. Словари
.content.tsнаходятся рядом с компонентом, который они обслуживают, compiler во время сборки выполняет tree-shaking и ленивую загрузку для каждого компонента и локали, строгие типы TypeScript генерируются из вашего контента, и отсутствующие переводы вызывают ошибку во время сборки. Поставляется с middleware, помощниками SEO, Visual Editor / CMS и переводом с поддержкой AI.
Открыть таблицу в модальном окне для четкого просмотра всех данных
Значки обновляются автоматически. Снимки экрана будут изменяться с течением времени.
Сравнение функций "рядом"
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Функция | next-intlayer (Intlayer) | next-intl |
|---|---|---|
| Переводы рядом с компонентами | ✅ Да, .content.ts расположен вместе с каждым компонентом | ❌ Нет, централизованный messages/{locale}.json |
| Интеграция TypeScript | ✅ Строгие типы автоматически генерируются из контента | ✅ Хорошо, типизация ключей через расширение global.d.ts |
| Обнаружение отсутствующих переводов | ✅ Ошибка TypeScript + ошибка/предупреждение на этапе сборки | ⚠️ Fallback во время выполнения + предупреждение консоли |
| Rich content (JSX / Markdown / components) | ✅ Прямая поддержка | ⚠️ t.rich() / t.markup() с заполнителями тегов |
| ICU support | ⚠️ WIP | ✅ Да |
| Formatting (dates, numbers, currencies) | ✅ useNumber, useDate, ... (Intl под капотом) | ✅ useFormatter() (Intl под капотом) |
| Локализованная маршрутизация и middleware | ✅ Встроенный прокси/middleware, getMultilingualUrls | ✅ Встроенный middleware, Link, redirect, usePathname |
| SEO помощники (hreflang, sitemap, robots) | ✅ Встроенные помощники | ⚠️ Ручной, на основе конфигурации маршрутизации |
| Синхронные серверные компоненты | ✅ useIntlayer из next-intlayer/server работает в любом дочернем серверном компоненте | ⚠️ getTranslations асинхронен; синхронные дочерние компоненты нуждаются в t переданном как props |
| Статический рендеринг | ✅ Не блокирует статический рендеринг | ⚠️ Требует setRequestLocale(); каталоги с пространствами имён по-прежнему исключали страницы из статического рендеринга в наших тестах |
| Tree-shaking (отправка только используемого контента) | ✅ По компоненту, по локали, автоматизировано компилятором | ⚠️ Ручная работа: пространства имён + pick(messages, [...]) на страницу |
| Lazy loading | ✅ importMode: 'dynamic' (одна строка конфигурации) | ⚠️ Ручной динамический импорт в getRequestConfig |
| Purge unused content | ✅ Dead dictionaries are dropped at build time | ❌ Not built-in |
| Testing missing translations (CLI / CI) | ✅ npx intlayer content test | ⚠️ Not built-in; docs suggest npx @lingual/i18n-check |
| AI-powered translation | ✅ Built-in, uses your own provider keys | ❌ No |
| Визуальный редактор / CMS | ✅ Бесплатный визуальный редактор + опциональная CMS | ❌ Нет (внешние платформы локализации) |
| MCP server & Agent Skills | ✅ Да | ❌ Нет |
| Экосистема / сообщество | ⚠️ Меньше, но быстро растет | ✅ Большое, справочный стандарт Next.js |
Бенчмарк
Что было измерено
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 | Все локали и все страницы объединены вместе | Быстрые прототипы, AI-generated код |
| dynamic | Загружается только активная локаль, но все страницы сразу | Большинство проектов |
| scoped-static | Пространства имён по маршрутам, без ленивой загрузки | Редкий случай |
| scoped-dynamic | Пространства имён по маршрутам + ленивая загрузка. Отправляется только текущая страница в текущей локали | Приложения с строгим бюджетом производительности |
Intlayer не имеет варианта "scoped": компилятор автоматически распределяет контент по компонентам, поэтому его строки static и dynamic уже распределены по области видимости.
Для каждой сборки набор тестов записывает:
- Lib size: gzip размер пустого компонента, который только импортирует i18n библиотеку. Фиксированная стоимость runtime.
- Page JS: gzip JavaScript, скачанный на страницу, усреднённый по всем страницам и локалям.
- Locale leak %: доля переведённых строк, найденных в скачанном JS, которые принадлежат локали, которую пользователь не просматривает (отпечатано на
enиfr, поэтому 50% означает "другая измеренная локаль полностью присутствует"; с 10 связанными локалями, реальные потери выше). - Page leak %: доля переведённых строк, найденных в скачанном JS, которые принадлежат странице, на которой пользователь не находится.
- Component avg: средний gzip размер каждого компонента, скомпилированного в изоляции. Показывает, сколько i18n runtime один компонент тянет за собой.
- E2E reactivity: время в реальном масштабе времени между выбором нового языка и обновлением
html[lang]в DOM (Playwright, 5 итераций). - Hydration: продолжительность фазы гидрации React.
Приведённые ниже числа получены из запуска от 2026-09-12 сnext-intl4.14.2,use-intl4.14.2 иintlayer9.5.1. Тестовое приложение намеренно небольшое (несколько десятков строк на язык), поэтому процентные значения утечек описывают паттерн: они растут вместе с вашим контентом, тогда как стоимость runtime остаётся постоянной.
Результаты на Next.js (App Router)
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Library | Strategy | Lib size (gz) | Page JS avg (gz) | Locale leak | Page leak | Component avg (gz) | E2E reactivity | Hydration |
|---|---|---|---|---|---|---|---|---|
| base (no i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
next-intl | static | 14.7 KB | 153.6 KB | 4.2% | 89.8% | 21.8 KB | 16.0 ms | 14.7 ms |
next-intl | dynamic | 14.7 KB | 153.6 KB | 9.7% | 89.9% | 21.8 KB | 15.6 ms | 14.8 ms |
next-intl | scoped-static | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 80.1 KB | 17.9 ms | 17.4 ms |
next-intl | scoped-dynamic | 14.7 KB | 153.6 KB | 0.0% | 0.0% | 22.9 KB | 17.8 ms | 16.8 ms |
next-intlayer | static | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 8.5 KB | 15.5 ms | 16.9 ms |
next-intlayer | dynamic | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 6.9 KB | 15.3 ms | 15.9 ms |
@intlayer/next-intl (compat) | static | 8.0 KB | 147.5 KB | 0.0% | 0.0% | 8.1 KB | 14.5 ms | 12.8 ms |
@intlayer/next-intl (compat) | dynamic | 8.0 KB | 148.7 KB | 0.0% | 0.0% | 8.1 KB | 11.7 ms | 12.8 ms |
Как это читать
- Стоимость runtime. Базовое приложение весит 141.0 KB на страницу.
next-intlдоводит это значение до 153.6 KB (+12.6 KB gzip на каждой странице), Intlayer до 141.3 KB (+0.3 KB). Этот разрыв не зависит от количества строк: это runtime библиотеки. - Leakage. В двух конфигурациях, которые большинство команд фактически используют (
staticиdynamic),next-intlдоставляет ~90% строк иностранных страниц на каждую страницу: весьen.jsonпопадает в клиентский провайдер. Чтобы достичь 0%, требуются конфигурацииscoped-*: разделить каталоги на namespaces, затем выбрать нужные с помощьюpick()на каждой странице. Intlayer находится на 0% в обоих случаях без всего этого. - JavaScript на странице не изменился для
next-intlмежду стратегиями. Тестовое содержимое небольшое, поэтому утечка ~90% составляет всего несколько KB здесь. В реальном приложении со сотнями строк на странице это соотношение становится доминирующей стоимостью. Тем временем +12.6 KB runtime оплачивается в каждой конфигурации. - Размер компонента. Компонент, который вызывает
useTranslations(), компилируется в среднем до 21.8 KB; тот же компонент сuseIntlayer()компилируется до 6.9 KB. В конфигурацииscoped-staticкомпонентыnext-intlувеличиваются до 80.1 KB, потому что каждый встраивает свой каталог пространства имен. - Реактивность и гидратация находятся в одном диапазоне для обеих библиотек на Next.js (15-18 мс). Ни одна из них не является узким местом здесь.
Результаты на TanStack Start (use-intl)
use-intl - это не зависящее от фреймворка ядро next-intl. Тот же API, тот же формат сообщений. Его сравнение с intlayer на TanStack Start исключает из уравнения части, специфичные для Next.js.
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Библиотека | Стратегия | Размер библиотеки (gz) | Среднее JS страницы (gz) | Утечка локали | Утечка страницы | Среднее размер компонента (gz) | E2E реактивность |
|---|---|---|---|---|---|---|---|
| base (без i18n) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms |
use-intl | static | 14.1 KB | 179.8 KB | 50.0% | 89.8% | 76.0 KB | 6.7 ms |
use-intl | dynamic | 14.1 KB | 119.4 KB | 0.0% | 89.8% | 75.9 KB | 7.0 ms |
use-intl | scoped-static | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 20.9 ms |
use-intl | scoped-dynamic | 14.1 KB | 128.7 KB | 0.0% | 0.0% | 87.1 KB | 13.3 ms |
intlayer | static | 5.0 KB | 125.8 KB | 50.0% | 0.0% | 8.1 KB | 3.2 ms |
intlayer | dynamic | 5.0 KB | 118.6 KB | 0.0% | 0.0% | 6.3 KB | 3.6 ms |
@intlayer/use-intl (compat) | dynamic | 7.3 KB | 129.7 KB | 0.0% | 0.0% | 9.3 KB | 8.7 ms |
Как это читать
- Наивная конфигурация
use-intlдоставляет на 68.8 KB больше JS на страницу чем базовое приложение, причём половина строк принадлежит неправильной локали и 90% неправильной странице. use-intlв режимеdynamicдостигает 119.4 KB, близко к 118.6 KB Intlayer, но все еще несет 89.8% утечку страницы: строки всех страниц для активной локали загружаются на каждой странице. Их группировка по маршруту (scoped-*) устраняет утечку, но добавляет еще ~9 KB накладных расходов на chunk.- В Intlayer строка
staticуже имеет 0% утечку страницы: компилятор собирает только словари, используемые компонентами на странице. ВключениеimportMode: 'dynamic'(одна строка вintlayer.config.ts) также устраняет утечку локали. - Размер компонента показывает разницу в архитектуре: 76-87 KB на компонент с
use-intlпротив 6-8 KB с Intlayer.useTranslations()привязывает каждый компонент к глобальному дереву сообщений;useIntlayer()привязывает его к собственному словарю. - Переключение локали в 2-4 раза быстрее с Intlayer (3 мс против 7-21 мс).
Почему такая разница? Централизованные каталоги vs скомпилированные словари
next-intl следует классической модели: один JSON на локаль, загруженный в getRequestConfig, переданный в NextIntlClientProvider, доступный через t("namespace.key").
Копировать код в буфер обмена
Runtime не может знать, какие ключи будет использовать страница, поэтому безопасный стандарт - отправить весь каталог. Оптимизация означает, что вы разделяете каталог на пространства имён, вы решаете, какие пространства имён нужны каждой странице, и вы поддерживаете это соответствие в синхронизации при перемещении компонентов. Строка scoped-dynamic в тесте производительности - это награда за эту работу, и большинство команд туда никогда не доходят.
Intlayer переворачивает ответственность. Контент объявляется рядом с компонентом:
Копировать код в буфер обмена
При сборке компилятор (@intlayer/swc / @intlayer/babel) видит, какой компонент импортирует какой словарь. Он объединяет только те словари, только для активной локали, и удаляет те, которые ничто не импортирует. Паттерн "scoped-dynamic" становится результатом сборки вместо дисциплины, которую команда должна поддерживать.
Чтобы получить цифрыdynamicстроки, установитеdictionary.importMode: 'dynamic'вintlayer.config.ts. См. документацию по оптимизации bundle.
Опыт разработчика
Client компонент
next-intl
Копировать код в буфер обмена
Копировать код в буфер обмена
Помните, что нужно включить пространство имёнcounterв сообщения, передаваемые вNextIntlClientProviderна каждой странице, которая отображает этот компонент.
Intlayer
Копировать код в буфер обмена
Копировать код в буфер обмена
Не требуется регистрировать на странице: компонент содержит свой собственный контент.
Синхронный серверный компонент
Компоненты системы проектирования (navbar, footer, карточки) часто являются серверными компонентами, отрендеренными как дочерние элементы клиентских компонентов, поэтому они не могут быть async.
next-intl
Копировать код в буфер обмена
Страница должна await getTranslations("counter") и await getFormatter(), затем передать результаты вниз как props. Компонент больше не является самостоятельным.
Intlayer
Копировать код в буфер обмена
Метаданные
next-intl
Копировать код в буфер обмена
Intlayer
Копировать код в буфер обмена
Сохраните API next-intl, получите вывод Intlayer
Вам не нужно переписывать компоненты, чтобы получить указанные выше числа производительности. @intlayer/next-intl - это готовый адаптер: он сохраняет useTranslations, getTranslations, useFormatter, t.rich(), ICU plurals и помощники next-intl/navigation, и предоставляет их из словарей Intlayer, скомпилированных компилятором Intlayer.
Копировать код в буфер обмена
В benchmark, compat-сборка того же приложения сократилась с 153.6 KB до 147.5 KB за страницу, с 21.8 KB до 8.1 KB за компонент, и с ~90% page leakage на 0%, при этом код приложения остался без изменений. Ваши существующие файлы messages/{locale}.json могут остаться источником истины благодаря JSON sync plugin.
Смотрите руководство миграции next-intl для пошагового процесса.
Когда выбрать что?
- Выбирайте next-intl, если вам нужен стандарт экосистемы для Next.js, вы полагаетесь на ICU MessageFormat, ваше приложение небольшого или среднего размера, или вы интегрируетесь с платформой перевода (Crowdin, Phrase, Lokalise...), которая ожидает централизованный JSON. Учтите время на организацию пространств имён каталогов и выбор сообщений для каждой страницы, если производительность важна.
- Выбирайте Intlayer, если вам нужно контент, привязанный к компонентам, строгий TypeScript, ошибки missing-key на этапе сборки, автоматический tree-shaking и ленивая загрузка, синхронные серверные компоненты и встроенные инструменты редактирования (Visual Editor, CMS, перевод с помощью AI, MCP server). Особенно актуально для больших модульных кодовых баз и дизайн-систем.
- Выбирайте
@intlayer/next-intl, если вы уже используетеnext-intlи хотите сэкономить на размере бандла без полного переписывания.
Связанные сравнения
- i18next vs Intlayer (тот же benchmark)
- Lingui vs Intlayer (тот же benchmark)
- vue-i18n vs Intlayer benchmark (тот же benchmark)
- next-i18next vs next-intl vs Intlayer
- Is next-intl outdated?
GitHub STARs
GitHub stars - это сильный индикатор популярности проекта, доверия сообщества и долгосрочной актуальности. Хотя это не прямая мера технического качества, они отражают, сколько разработчиков находят проект полезным, следят за его развитием и, вероятно, готовы его использовать.
Заключение
next-intl - это надежная, хорошо поддерживаемая библиотека, и benchmark подтверждает, что это далеко не худший вариант для Next.js. Однако её централизованная модель каталога возлагает все оптимизации на разработчика: наивная конфигурация пропускает ~90% контента иностранных страниц, а само runtime стоит +12,6 KB gzip на каждой странице.
Intlayer переносит эту работу в компилятор. Словари для каждого компонента, ленивая загрузка для каждого локала и очистка мертвого контента являются выходными данными сборки, а не соглашениями. Результат в том же приложении: +0.3 KB на страницу, 0% утечек, компоненты в 3 раза меньше и переключение локали в 2-4 раза быстрее на TanStack Start.
Все необработанные данные, тестовые приложения и скрипты находятся в репозитории Benchmark Bloom. Запустите его самостоятельно.
Обратитесь к документации 'Why Intlayer?' для получения дополнительных сведений.
Комментарии
Пока нет комментариев. Будьте первым, кто поделится своими мыслями.
