Skip to main content
Назад до блогу
4 хв читання

next-intl vs next-i18next: вартість міграції, яку я реально заплатив

Я мігрував продакшн Next.js сайт з next-i18next на next-intl. Чому, скільки зайняло, що зламалося і чи було воно того варте.

next.jsi18nperformance

Цей сайт — dimaver6.com — починався на next-i18next. Я мігрував його на next-intl за один вихідний. Міграція була прямолінійною. Рішення мігрувати — ні.

Чому переключився

1. Підтримка App Router

next-i18next був зібраний для Pages Router. Коли Next.js перейшов на App Router, next-i18next додав підтримку, але вона відчувалася як прикручена збоку. Server Components потребували обхідних шляхів.

next-intl був спроєктований для App Router від початку. getTranslations() працює природно в Server Components, лейаутах і generateMetadata. Без обхідних шляхів, без прокидування пропсів.

2. Типобезпечність

next-intl підтримує типізовані ключі перекладів з коробки. Якщо я посилаюся на t('Navigation.bog') замість t('Navigation.blog') — TypeScript ловить на етапі збірки. next-i18next потребував додаткового налаштування для того самого рівня типобезпечності.

3. Інтеграція роутингу

next-intl включає шар роутингу (createNavigation, createMiddleware), що обробляє визначення локалі, роутинг із префіксами та генерацію hreflang. З next-i18next я керував роутингом локалей вручну — кастомний middleware, ручні hreflang-теги, окремий скрипт визначення локалі.

next-intl згорнув 4 файли кастомного коду роутингу в 2 файли конфігурації.

Міграція

Крок 1: Встановлення та налаштування (30 хвилин)

Створив i18n/config.ts, i18n/request.ts та i18n/navigation.ts.

Крок 2: Формат файлів перекладів (0 хвилин)

Обидві бібліотеки використовують JSON з однаковою структурою. Файли messages/*.json запрацювали як є.

Крок 3: Заміна middleware (45 хвилин)

60 рядків кастомного middleware → 6 рядків з createMiddleware від next-intl.

Крок 4: Оновлення Server Components (2 години)

Найбільша частина. Кожен Server Component із перекладами потребував оновлення:

// До: useTranslation (клієнтський хук)
// Після: getTranslations (асинхронна серверна функція)
import { getTranslations } from 'next-intl/server';

export default async function MyPage() {
  const t = await getTranslations('MyNamespace');
  return <h1>{t('title')}</h1>;
}

~25 компонентів. Більшість — механічний find-and-replace.

Крок 5: Оновлення Client Components (1 година)

~10 компонентів: useTranslationuseTranslations.

Заміна ручних локалізованих URL на Link з @/i18n/navigation. ~15 місць.

Крок 7: Оновлення метаданих (30 хвилин)

generateMetadata з getTranslations — чисто та природно.

Загальний час міграції: ~5 годин

Що зламалося

1. Регістр неймспейсів

next-i18next використовує lowercase (common). Я переключився на PascalCase (Common). Пропустив два місця — порожні рядки в російській локалі. Зловив TypeScript.

2. Синтаксис інтерполяції

Обидві використовують {variable}, але next-i18next також підтримував {{variable}}. Три рядки з подвійними фігурними дужками рендерилися як літеральний текст. Швидкий regex-фікс.

3. Правила множини

next-i18next: key_one, key_other. next-intl: ICU формат {count, plural, one {# item} other {# items}}. 4 рядки з множиною. 15 хвилин на конвертацію.

4. Перемикач мови

Компонент використовував i18next.changeLanguage(). next-intl перемикає через навігацію (редирект з іншим префіксом локалі). Потрібен був рерайт компонента.

Чесне порівняння

next-intlnext-i18next
App RouterНативна, першокласна підтримкаДодана пізніше, відчувається прикрученою
Server ComponentsgetTranslations() — чистий asyncПотребує обхідних шляхів
ТипобезпечністьВбудованаМожлива, але потребує ручного налаштування
РоутингВключений (middleware, Link, redirect)BYO або обмежений роутинг
Формат перекладівJSONJSON (формат i18next)
МножинаICU MessageFormatФормат i18next (_one, _other)
ЕкосистемаМенша, специфічна для Next.jsВеличезна (екосистема i18next)

Коли обирати next-intl

Коли обирати next-i18next

Чи було воно того варте?

Так. 5 годин міграції, а покращення DX реальне — типобезпечні ключі, чистіші патерни в Server Components, жодного кастомного роутингу. Я написав про повну i18n-архітектуру включаючи роутинг, SEO та RSC-патерни.


Збираєш мультимовний Next.js і не впевнений, який i18n-підхід обрати? Напиши — я відвантажив обидва і можу зекономити тобі податок на неправильну бібліотеку.