Начало работы с интернационализацией (i18n) с Intlayer и Next.js 14 с маршрутизатором App

    Что такое Intlayer?

    Intlayer — это инновационная библиотека для интернационализации (i18n) с открытым исходным кодом, разработанная для упрощения поддержки многоязычности в современных веб-приложениях. Intlayer seamlessly integrates with the latest Next.js 14 framework, including its powerful App Router. Он оптимизирован для работы с Server Components для эффективного рендеринга и полностью совместим с Turbopack (с Next.js >= 15).

    С помощью Intlayer вы можете:

    • Легко управлять переводами, используя декларативные словари на уровне компонентов.
    • Динамически локализовать метаданные, маршруты и содержимое.
    • Получать доступ к переводам как в компонентах на стороне клиента, так и на стороне сервера.
    • Обеспечить поддержку TypeScript с автогенерируемыми типами, улучшая автозаполнение и обнаружение ошибок.
    • Воспользоваться расширенными функциями, такими как динамическое определение и переключение локали.

    Intlayer совместим с Next.js 12, 13, 14 и 15. Если вы используете маршрутизатор страниц Next.js, вы можете обратиться к этому руководству. Для Next.js 15 с или без turbopack обратитесь к этому руководству.


    Пошаговое руководство по настройке Intlayer в приложении Next.js

    Шаг 1: Установка зависимостей

    Установите необходимые пакеты с помощью npm:

    bash
    npm install intlayer next-intlayer
    • intlayer

      Основной пакет, который предоставляет инструменты интернационализации для управления конфигурацией, переводом, декларацией контента, трансалиацией и CLI командами.

    • next-intlayer

      Пакет, который интегрирует Intlayer с Next.js. Он предоставляет контекстные провайдеры и хуки для интернационализации Next.js. Кроме того, он включает плагин Next.js для интеграции Intlayer с Webpack или Turbopack, а также промежуточное ПО для определения предпочтительной локали пользователя, управления куками и обработки перенаправления URL.

    Шаг 2: Настройте ваш проект

    Создайте конфигурационный файл для настройки языков вашего приложения:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // Ваши другие локали    ],    defaultLocale: Locales.ENGLISH,  },};export default config;

    С помощью этого конфигурационного файла вы можете настроить локализованные URL, промежуточные перенаправления, имена куки, местоположение и расширение ваших деклараций контента, отключить логи Intlayer в консоли и многое другое. Для полного списка доступных параметров смотрите документацию по конфигурации.

    Шаг 3: Интегрируйте Intlayer в вашу конфигурацию Next.js

    Настройте вашу установку Next.js для использования Intlayer:

    next.config.mjs
    import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {};export default withIntlayer(nextConfig);

    Плагин withIntlayer() используется для интеграции Intlayer с Next.js. Он обеспечивает сборку файлов декларации контента и их мониторинг в режиме разработки. Он определяет переменные окружения Intlayer в средах Webpack или Turbopack. Кроме того, он предоставляет псевдонимы для оптимизации производительности и обеспечивает совместимость с серверными компонентами.

    Шаг 4: Настройте промежуточное программное обеспечение для определения локали

    Настройте промежуточное ПО для определения предпочтительной локали пользователя:

    src/middleware.ts
    export { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = {  matcher:    "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",};

    intlayerMiddleware используется для определения предпочтительной локали пользователя и перенаправления его на соответствующий URL, как указано в конфигурации. Кроме того, он позволяет сохранить предпочтительную локаль пользователя в куке.

    Настройте параметр matcher, чтобы он соответствовал маршрутам вашего приложения. Для получения дополнительных подробностей смотрите документацию Next.js по настройке matcher.

    Шаг 5: Определите динамические маршруты локали

    Удалите все из RootLayout и замените его следующим кодом:

    src/app/layout.tsx
    import type { PropsWithChildren, FC } from "react";import "./globals.css";const RootLayout: FC<PropsWithChildren> = ({ children }) => children;export default RootLayout;

    Оставляя компонент RootLayout пустым, вы можете установить атрибуты lang и dir для тега <html>.

    Для реализации динамической маршрутизации укажите путь для локали, добавив новую разметку в вашем каталоге [locale]:

    src/app/[locale]/layout.tsx
    import type { Next14LayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });const LocaleLayout: Next14LayoutIntlayer = ({  children,  params: { locale },}) => (  <html lang={locale} dir={getHTMLTextDir(locale)}>    <body className={inter.className}>{children}</body>  </html>);export default LocaleLayout;

    Путь [locale] используется для определения локали. Пример: /en-US/about будет относиться к en-US, а /fr/about к fr.

    Затем реализуйте функцию generateStaticParams в разметке вашего приложения.

    src/app/[locale]/layout.tsx
    export { generateStaticParams } from "next-intlayer"; // Строка для вставкиconst LocaleLayout: Next14LayoutIntlayer = ({  children,  params: { locale },}) => {  /*... Остальная часть кода */};export default LocaleLayout;

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

    Шаг 6: Объявите ваш контент

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

    src/app/[locale]/page.content.ts
    import { t, type DeclarationContent } from "intlayer";const pageContent = {  key: "page",  content: {    getStarted: {      main: t({        en: "Get started by editing",        fr: "Commencez par éditer",        es: "Comience por editar",      }),      pageLink: "src/app/page.tsx",    },  },} satisfies DeclarationContent;export default pageContent;

    Ваши декларации контента могут быть определены в любом месте вашего приложения, как только они включены в каталог contentDir (по умолчанию ./src). И совпадают с расширением файла декларации контента (по умолчанию .content.{ts,tsx,js,jsx,mjs,cjs}). Для получения дополнительных сведений смотрите документацию по декларации контента.

    Шаг 7: Используйте контент в вашем коде

    Получите доступ к вашим словарям контента по всему вашему приложению:

    src/app/[locale]/page.tsx
    import { ClientComponentExample } from "@components/ClientComponentExample";import { ServerComponentExample } from "@components/ServerComponentExample";import { type Next14PageIntlayer, IntlayerClientProvider } from "next-intlayer";import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";const Page: Next14PageIntlayer = ({ params: { locale } }) => {  const content = useIntlayer("page", locale);  return (    <>      <p>        {content.getStarted.main}        <code>{content.getStarted.pageLink}</code>      </p>      <IntlayerServerProvider locale={locale}>        <IntlayerClientProvider locale={locale}>          <ServerComponentExample />          <ClientComponentExample />        </IntlayerClientProvider>      </IntlayerServerProvider>    </>  );};export default Page;
    • IntlayerClientProvider используется для предоставления локали компонентам на стороне клиента. Его можно разместить в любом родительском компоненте, включая разметку. Однако рекомендуется размещать его в разметке, потому что Next.js делит код разметки между страницами, что делает его более эффективным. Используя IntlayerClientProvider в разметке, вы избегаете повторной инициализации его для каждой страницы, что улучшает производительность и поддерживает постоянный контекст локализации по всему вашему приложению.
    • IntlayerServerProvider используется для предоставления локали дочерним элементам сервера. Его нельзя установить в разметке.

      Разметка и страница не могут разделять общий контекст сервера, поскольку система контекста сервера основана на хранилище данных на основе каждой заявки (с помощью механизма кэша React), что приводит к воссозданию каждого "контекста" для разных сегментов приложения. Размещение провайдера в общей разметке нарушило бы эту изоляцию, предотвращая правильное распространение значений контекста сервера к вашим серверным компонентам.

    src/components/ClientComponentExample.tsx
    "use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";const ClientComponentExample: FC = () => {  const content = useIntlayer("client-component-example"); // Создайте соответствующую декларацию контента  return (    <div>      <h2>{content.title} </h2>      <p>{content.content}</p>    </div>  );};
    src/components/ServerComponentExample.tsx
    import type { FC } from "react";import { useIntlayer } from "next-intlayer/server";const ServerComponentExample: FC = () => {  const content = useIntlayer("server-component-example"); // Создайте соответствующую декларацию контента  return (    <div>      <h2>{content.title} </h2>      <p>{content.content}</p>    </div>  );};

    Если вы хотите использовать ваш контент в атрибуте string, таком как alt, title, href, aria-label и т. д., вы должны вызвать значение функции, например:

    jsx
    <img src={content.image.src.value} alt={content.image.value} />

    Чтобы узнать больше о хуке useIntlayer, смотрите документацию.

    (Опционально) Шаг 8: Интернационализация ваших метаданных

    В случае, если вы хотите интернационализировать ваши метаданные, такие как заголовок вашей страницы, вы можете использовать функцию generateMetadata, предоставляемую Next.js. Внутри функции используйте функцию getTranslationContent, чтобы перевести ваши метаданные.

    src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx
    import {  type IConfigLocales,  getTranslationContent,  getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalParams } from "next-intlayer";export const generateMetadata = ({  params: { locale },}: LocalParams): Metadata => {  const t = <T>(content: IConfigLocales<T>) =>    getTranslationContent(content, locale);  /**   * Генерирует объект, содержащий все URL для каждой локали.   *   * Пример:   * ```ts   *  getMultilingualUrls('/about');   *   *  // Возвращает   *  // {   *  //   en: '/about',   *  //   fr: '/fr/about',   *  //   es: '/es/about',   *  // }   * ```   */  const multilingualUrls = getMultilingualUrls("/");  return {    title: t<string>({      en: "My title",      fr: "Mon titre",      es: "Mi título",    }),    description: t({      en: "My description",      fr: "Ma description",      es: "Mi descripción",    }),    alternates: {      canonical: "/",      languages: { ...multilingualUrls, "x-default": "/" },    },    openGraph: {      url: multilingualUrls[locale],    },  };};// ... Остальная часть кода

    Узнайте больше о оптимизации метаданных в официальной документации Next.js.

    (Опционально) Шаг 9: Интернационализация вашего sitemap.xml и robots.txt

    Чтобы интернационализировать ваш sitemap.xml и robots.txt, вы можете использовать функцию getMultilingualUrls, предоставляемую Intlayer. Эта функция позволяет вам генерировать многоязычные URL для вашей карты сайта.

    src/app/sitemap.ts
    import { getMultilingualUrls } from "intlayer";import type { MetadataRoute } from "next";const sitemap = (): MetadataRoute.Sitemap => [  {    url: "https://example.com",    alternates: {      languages: getMultilingualUrls("https://example.com"),    },  },  {    url: "https://example.com/login",    alternates: {      languages: getMultilingualUrls("https://example.com/login"),    },  },  {    url: "https://example.com/register",    alternates: {      languages: getMultilingualUrls("https://example.com/register"),    },  },];export default sitemap;
    src/app/robots.ts
    import type { MetadataRoute } from "next";import { getMultilingualUrls } from "intlayer";const getAllMultilingualUrls = (urls: string[]) =>  urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);const robots = (): MetadataRoute.Robots => ({  rules: {    userAgent: "*",    allow: ["/"],    disallow: getAllMultilingualUrls(["/login", "/register"]),  },  host: "https://example.com",  sitemap: `https://example.com/sitemap.xml`,});export default robots;

    Узнайте больше об оптимизации карты сайта в официальной документации Next.js. Узнайте больше об оптимизации robots.txt в официальной документации Next.js.

    (Опционально) Шаг 10: Измените язык вашего контента

    Чтобы изменить язык вашего контента, вы можете использовать функцию setLocale, предоставляемую хуком useLocale. Эта функция позволяет вам установить локаль приложения и соответственно обновить контент.

    src/components/LocaleSwitcher.tsx
    "use client";import {  Locales,  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import { type FC } from "react";const LocaleSwitcher: FC = () => {  const { locale, pathWithoutLocale, availableLocales, setLocale } =    useLocale();  return (    <ol>      {availableLocales.map((localeItem) => (        <li key={localeItem}>          <a            href={getLocalizedUrl(pathWithoutLocale, localeItem)}            hrefLang={localeItem}            aria-current={locale === localeItem ? "page" : undefined}            onClick={(e) => {              e.preventDefault();              setLocale(localeItem);            }}          >            <span>              {/* Язык на своём локале - например, Français */}              {getLocaleName(localeItem, locale)}            </span>            <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>              {/* Язык на текущем локале - например, Francés при текущем локале, установленном на Locales.SPANISH */}              {getLocaleName(localeItem)}            </span>            <span dir="ltr" lang={Locales.ENGLISH}>              {/* Язык на английском - например, French */}              {getLocaleName(localeItem, Locales.ENGLISH)}            </span>            <span>              {/* Язык на своём локале - например, FR */}              {localeItem}            </span>          </a>        </li>      ))}    </ol>  );};

    Справочные документы:

    Настройка TypeScript

    Intlayer использует расширение модулей для получения преимуществ TypeScript и повышения устойчивости вашей кодовой базы.

    alt text

    alt text

    Убедитесь, что ваша конфигурация TypeScript включает авто-сгенерированные типы.

    tsconfig.json
    {  // ... Ваша существующая конфигурация TypeScript  "include": [    // ... Ваша существующая конфигурация TypeScript    "types", // Включите авто-сгенерированные типы  ],}

    Конфигурация Git

    Рекомендуется игнорировать файлы, сгенерированные Intlayer. Это позволяет избежать их коммита в ваш репозиторий Git.

    Для этого вы можете добавить следующие инструкции в ваш файл .gitignore:

    .gitignore
    # Игнорировать файлы, сгенерированные Intlayer.intlayer

    Если у вас есть идея по улучшению этой документации, не стесняйтесь внести свой вклад, подав запрос на вытягивание на GitHub.

    Ссылка на документацию GitHub