Этот сайт — 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 компонентов: useTranslation → useTranslations.
Шаг 6: Обновление Link (30 минут)
Замена ручных локализованных 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-intl | next-i18next | |
|---|---|---|
| App Router | Нативная, первоклассная поддержка | Добавлена позже, ощущается прикрученной |
| Server Components | getTranslations() — чистый async | Требует обходных путей |
| Типобезопасность | Встроенная | Возможна, но требует ручной настройки |
| Роутинг | Включён (middleware, Link, redirect) | BYO или ограниченный роутинг |
| Формат переводов | JSON | JSON (формат i18next) |
| Множественное число | ICU MessageFormat | Формат i18next (_one, _other) |
| Экосистема | Меньше, специфична для Next.js | Огромная (экосистема i18next) |
Когда выбирать next-intl
- Новый Next.js App Router проект
- Хочешь типобезопасные переводы без лишней настройки
- Хочешь роутинг локалей из коробки
- Команда фокусируется на Next.js
Когда выбирать next-i18next
- Существующая экосистема i18next (общие переводы с React Native)
- Pages Router без планов миграции
- Переводчики используют инструменты с экспортом в формат i18next
- Нужны плагины i18next (загрузка из CMS)
Стоило ли?
Да. 5 часов миграции, а улучшение DX реальное — типобезопасные ключи, чище паттерны в Server Components, никакого кастомного роутинга. Я написал о полной i18n-архитектуре включая роутинг, SEO и RSC-паттерны.
Собираешь мультиязычный Next.js и не уверен, какой i18n-подход выбрать? Напиши — я отгрузил оба и могу сэкономить тебе налог на неправильную библиотеку.