Как реализовать маршрутизацию на основе локали в Next.js (Pages Router) v16

Настройка маршрутизации с сегментами локали

Проблема

При создании многоязычного приложения один фундаментальный выбор определяет всё остальное: как приложение будет определять, на каком языке отображать контент? Без явного механизма URL /about становится неоднозначным — он может представлять контент на любом языке. Пользователи не могут делиться ссылками на конкретные языковые версии, а поисковые системы затрудняются понять, какая версия предназначена для какой аудитории. Эта неоднозначность создает проблемы как для пользовательского опыта, так и для SEO, так как нет четкого способа идентифицировать или сохранить контент на определенном языке.

Решение

Добавьте идентификатор языка прямо в путь URL, настроив встроенную поддержку маршрутизации i18n в Next.js. Укажите локали, которые вы хотите поддерживать, и локаль по умолчанию в конфигурации Next.js. Next.js автоматически обработает маршрутизацию, создавая пути вроде /fr/about и /nl-NL/about, при этом локаль по умолчанию не будет иметь префикса. Это делает каждый путь уникальным для конкретного языка, устраняя неоднозначность как для пользователей, так и для поисковых систем.

Шаги

1. Добавьте конфигурацию i18n в next.config.js

Добавьте конфигурацию i18n в файл next.config.js, чтобы указать, какие локали поддерживает ваше приложение.

module.exports = {
  i18n: {
    locales: ["en-US", "fr", "nl-NL"],
    defaultLocale: "en-US",
  },
};

Локали — это идентификаторы UTS Locale, стандартизированный формат для определения локалей, который обычно состоит из языка, региона и скрипта, разделенных дефисом. Локаль по умолчанию используется при посещении пути без префикса локали.

2. Получите информацию о локали на страницах

Используйте хук useRouter() для получения информации о локали в компонентах страниц.

import { useRouter } from "next/router";

export default function AboutPage() {
  const router = useRouter();
  const { locale, locales, defaultLocale } = router;

  return (
    <div>
      <h1>О нас</h1>
      <p>Текущая локаль: {locale}</p>
    </div>
  );
}

Свойство locale содержит текущую активную локаль, locales содержит все настроенные локали, а defaultLocale содержит настроенную локаль по умолчанию.

3. Доступ к локали в функциях получения данных

При предварительном рендеринге страниц с использованием getStaticProps или getServerSideProps информация о локали предоставляется в контексте.

import { GetStaticProps } from "next";

export const getStaticProps: GetStaticProps = async (context) => {
  const { locale } = context;

  const messages = await import(`../messages/${locale}.json`);

  return {
    props: {
      messages: messages.default,
    },
  };
};

Это позволяет загружать данные, специфичные для локали, во время сборки или по запросу, в зависимости от активной локали.

4. Переход между локалями

Используйте next/link с пропсом locale для перехода на другую локаль.

import Link from "next/link";

export default function LanguageSwitcher() {
  return (
    <nav>
      <Link href="/about" locale="en-US">
        English
      </Link>
      <Link href="/about" locale="fr">
        Français
      </Link>
      <Link href="/about" locale="nl-NL">
        Nederlands
      </Link>
    </nav>
  );
}

Если пропс locale не указан, во время клиентских переходов используется текущая активная локаль. Пропс locale позволяет пользователям переключать языки, оставаясь на одной и той же логической странице.

5. Генерация статических путей для всех локалей

При использовании getStaticPaths настроенные локали предоставляются в параметре контекста под locales, а настроенная локаль по умолчанию — под defaultLocale.

import { GetStaticPaths } from "next";

export const getStaticPaths: GetStaticPaths = async (context) => {
  const { locales } = context;

  const paths = locales.flatMap((locale) => [
    { params: { slug: "getting-started" }, locale },
    { params: { slug: "advanced" }, locale },
  ]);

  return {
    paths,
    fallback: false,
  };
};

Это гарантирует, что все версии ваших динамических страниц для разных локалей будут предварительно отрендерены во время сборки.