Creation:2024-12-07Last update:2026-05-31

    Переведите ваш Next.js and Page Router с Intlayer | Интернационализация (i18n)

    ide.intlayer.org

    Почему Intlayer лучше альтернатив?

    По сравнению с основными решениями, такими как next-intl или i18next, Intlayer представляет собой решение со встроенными оптимизациями, такими как:

    Intlayer оптимизирован для работы с Серверными компонентами для эффективного рендеринга и полностью совместим с Turbopack. Он не блокирует статический рендеринг и предлагает промежуточное программное обеспечение, а также все функции, необходимые для масштабирования интернационализации (i18n).

    Intlayer совместим с Next.js 12, 13, 14, 15 и 16. Если вы используете маршрутизатор страниц Next.js, вы можете обратиться к этому [руководству] (/ru/doc/environment/nextjs/next-with-page-router). Маршрутизация локали полезна для SEO, размера пакета и производительности. Если вам это не нужно, вы можете обратиться к этому [руководству] (/ru/doc/environment/nextjs/no-locale-path). Для Next.js 12, 13, 14 и 15 с App Router обратитесь к этому [руководству] (/ru/doc/environment/nextjs/14).

    Вместо загрузки огромных файлов JSON на свои страницы загружайте только необходимый контент. Intlayer помогает уменьшить размер бандла и страниц до 50 %.

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

    Совместное размещение контента уменьшает контекст, необходимый для моделей большого языка (LLM). Intlayer также поставляется с набором инструментов, таких как CLI для проверки отсутствия переводов,LSP, MCP, и навыки агента, чтобы сделать работу разработчика (DX) еще более удобной для агентов ИИ.

    Используйте автоматизацию для перевода в своем конвейере CI/CD, используя LLM по вашему выбору за счет вашего поставщика ИИ. Intlayer также предлагает компилятор для автоматизации извлечения контента, а также веб-платформу, которая помогает переводить в фоновом режиме.

    Подключение больших файлов JSON к компонентам может привести к проблемам с производительностью и реактивностью. Intlayer оптимизирует загрузку контента во время сборки (build time).

    Intlayer — это больше, чем просто решение i18n. Он предоставляет автономный визуальный редактор и полный CMS, чтобы помочь вам управлять многоязычным контентом в реальном времени, упрощая сотрудничество с переводчиками, копирайтерами и другими членами команды. Контент может храниться локально и/или удаленно.


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

    1. Установка зависимостей

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

      bash
      npm install intlayer next-intlayernpx intlayer init
      • intlayer

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

      • next-intlayer

        Пакет, который интегрирует Intlayer с Next.js. Он предоставляет провайдеры контекста и хуки для интернационализации в Next.js. Кроме того, включает плагин Next.js для интеграции Intlayer с Webpack или Turbopack, а также middleware для определения предпочтительного языка пользователя, управления куки и обработки перенаправлений 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-адреса, перенаправление через middleware, имена cookie, расположение и расширение ваших деклараций контента, отключить логи Intlayer в консоли и многое другое. Для полного списка доступных параметров обратитесь к документации по конфигурации.
    3. Интеграция Intlayer с конфигурацией Next.js

      Измените конфигурацию Next.js, чтобы включить Intlayer:

      next.config.mjs
      import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {  // Ваша существующая конфигурация Next.js};export default withIntlayer(nextConfig);
      Плагин Next.js withIntlayer() используется для интеграции Intlayer с Next.js. Он обеспечивает сборку файлов деклараций контента и их мониторинг в режиме разработки. Определяет переменные окружения Intlayer в средах Webpack или Turbopack. Кроме того, предоставляет алиасы для оптимизации производительности и гарантирует совместимость с серверными компонентами.
    4. Настройка Middleware для определения локали

      Настройте middleware для автоматического определения и обработки предпочтительной локали пользователя:

      src/middleware.ts
      export { intlayerProxy as middleware } from "next-intlayer/middleware";
      
      export const config = {
        matcher:
          "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",
      };
      Адаптируйте параметр matcher так, чтобы он соответствовал маршрутам вашего приложения. Для получения дополнительной информации обратитесь к документации Next.js по настройке matcher.
    5. Определение динамических маршрутов локализации

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

      1. Создайте страницы для конкретных локалей:

        Переименуйте основной файл страницы, добавив динамический сегмент [locale].

        bash
        mv src/pages/index.tsx src/pages/[locale]/index.tsx
      2. Обновите _app.tsx для поддержки локализации:

        Измените ваш _app.tsx, чтобы включить провайдеры Intlayer.

        src/pages/_app.tsx
        import type { FC } from "react";import type { AppProps } from "next/app";import { IntlayerClientProvider } from "next-intlayer";const App = FC<AppProps>({ Component, pageProps }) => {  const { locale } = pageProps; // извлекаем локаль из свойств страницы  return (    <IntlayerClientProvider locale={locale}>      <Component {...pageProps} />    </IntlayerClientProvider>  );}export default MyApp;
      3. Настройка getStaticPaths и getStaticProps:

        В вашем файле [locale]/index.tsx определите пути и свойства для обработки разных локалей.

        src/pages/[locale]/index.tsx
        import type { FC } from "react";import type { GetStaticPaths, GetStaticProps } from "next";import { type Locales, getConfiguration } from "intlayer";const HomePage: FC = () => <div>{/* Ваш контент здесь */}</div>;export const getStaticPaths: GetStaticPaths = () => {  const { internationalization } = getConfiguration();  const { locales } = internationalization;  const paths = locales.map((locale) => ({    params: { locale },  }));  return { paths, fallback: false };};export const getStaticProps: GetStaticProps = ({ params }) => {  const locale = params?.locale as string;  return {    props: {      locale,    },  };};export default HomePage;
      getStaticPaths и getStaticProps обеспечивают предварительную сборку необходимых страниц для всех локалей в Next.js Page Router. Такой подход снижает вычислительную нагрузку во время выполнения и улучшает пользовательский опыт. Для получения дополнительной информации обратитесь к документации Next.js по getStaticPaths и getStaticProps.
    6. Объявите Ваш Контент

      Создайте и управляйте объявлениями контента для хранения переводов.

      src/pages/[locale]/home.content.ts
      import { t, type Dictionary } from "intlayer";
      
      const homeContent = {
        key: "home",
        content: {
          title: t({
            en: "Welcome to My Website",
            fr: "Bienvenue sur mon site Web",
            es: "Bienvenido a mi sitio web",
            ru: "Добро пожаловать на мой сайт",
          }),
          description: t({
            en: "Get started by editing this page.",
            fr: "Commencez par éditer cette page.",
            es: "Comience por editar esta página.",
            ru: "Начните с редактирования этой страницы.",
          }),
        },
      } satisfies Dictionary;
      
      export default homeContent;

      Для получения дополнительной информации о декларации контента обратитесь к руководству по декларации контента.

    7. Использование контента в вашем коде

      Получайте доступ к словарям контента по всему вашему приложению для отображения переведённого контента.

      src/pages/[locale]/index.tsx
      import type { FC } from "react";
      import { useIntlayer } from "next-intlayer";
      import { ComponentExample } from "@components/ComponentExample";
      
      const HomePage: FC = () => {
        const content = useIntlayer("home");
      
        return (
          <div>
            <h1>{content.title}</h1>
            <p>{content.description}</p>
            <ComponentExample />
            {/* Дополнительные компоненты */}
          </div>
        );
      };
      
      // ... Остальная часть кода, включая getStaticPaths и getStaticProps
      
      export default HomePage;
      src/components/ComponentExample.tsx
      import type { FC } from "react";
      import { useIntlayer } from "next-intlayer";
      
      export const ComponentExample: FC = () => {
        const content = useIntlayer("component-example"); // Убедитесь, что у вас есть соответствующая декларация контента
      
        return (
          <div>
            <h2>{content.title}</h2>
            <p>{content.content}</p>
          </div>
        );
      };
      src/components/ComponentExample.tsx
      import type { FC } from "react";
      import { useIntlayer } from "next-intlayer";
      
      export const ComponentExample: FC = () => {
        const content = useIntlayer("component-example"); // Убедитесь, что у вас есть соответствующее объявление контента
      
        return (
          <div>
            <h2>{content.title}</h2>
            <p>{content.content}</p>
          </div>
        );
      };
      При использовании переводов в атрибутах типа string (например, alt, title, href, aria-label), вызывайте
      значение функции следующим образом:
      html
      <img src="{content.image.src.value}" alt="{content.image.value}" /><img src="{content.image.src.toString()}" alt="{content.image.toString()}" /><img src="{String(content.image.src)}" alt="{String(content.image)}" />
      Чтобы узнать больше о хуке useIntlayer, обратитесь к документации.
    8. Интернационализация ваших метаданных

      Необязательно

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

      src/pages/[locale]/metadata.content.ts
      import { type Dictionary, t } from "intlayer";
      import { type Metadata } from "next";
      
      const metadataContent = {
        key: "page-metadata",
        content: {
          title: t({
            en: "Create Next App",
            fr: "Создать приложение Next.js",
            es: "Создать приложение Next.js",
          }),
          description: t({
            en: "Generated by create next app",
            fr: "Сгенерировано с помощью create next app",
            es: "Сгенерировано с помощью create next app",
          }),
        },
      } satisfies Dictionary<Metadata>;
      
      export default metadataContent;
      src/pages/[locale]/index.tsx
      import { GetStaticPaths, GetStaticProps } from "next";
      import { getIntlayer, getMultilingualUrls } from "intlayer";
      import { useIntlayer } from "next-intlayer";
      import Head from "next/head";
      import type { FC } from "react";
      
      interface HomePageProps {
        locale: string;
        metadata: {
          title: string;
          description: string;
        };
        multilingualUrls: Record<string, string>;
      }
      
      const HomePage: FC<HomePageProps> = ({
        metadata,
        multilingualUrls,
        locale,
      }) => {
        const content = useIntlayer("page");
      
        return (
          <div>
            <Head>
              <title>{metadata.title}</title>
              <meta name="description" content={metadata.description} />
              {/* Генерация тегов hreflang для SEO */}
              {Object.entries(multilingualUrls).map(([lang, url]) => (
                <link key={lang} rel="alternate" hrefLang={lang} href={url} />
              ))}
              <link rel="canonical" href={multilingualUrls[locale]} />
            </Head>
      
            {/* Содержимое страницы */}
            <main>{/* Ваше содержимое страницы здесь */}</main>
          </div>
        );
      };
      
      export const getStaticProps: GetStaticProps<HomePageProps> = async ({
        params,
      }) => {
        const locale = params?.locale as string;
      
        const metadata = getIntlayer("page-metadata", locale);
      
        /**
         * Генерирует объект, содержащий все URL для каждого языка.
         *
         * Пример:
         * ```ts
         *  getMultilingualUrls('/about');
         *
         *  // Возвращает
         *  // {
         *  //   en: '/about',
         *  //   fr: '/fr/about',
         *  //   es: '/es/about',
         *  // }
         * ```
         */
        const multilingualUrls = getMultilingualUrls("/");
      
        return {
          props: {
            locale,
            metadata,
            multilingualUrls,
          },
        };
      };
      
      export default HomePage;
      
      // ... Остальная часть кода, включая getStaticPaths
      Обратите внимание, что функция getIntlayer, импортируемая из next-intlayer, возвращает ваш контент, обернутый в IntlayerNode, что позволяет интегрироваться с визуальным редактором. В то время как функция getIntlayer, импортируемая из intlayer, возвращает ваш контент напрямую без дополнительных свойств.

      В качестве альтернативы вы можете использовать функцию getTranslation для объявления ваших метаданных. Однако рекомендуется использовать файлы декларации контента, чтобы автоматизировать перевод ваших метаданных и в какой-то момент вынести контент отдельно.

      src/pages/[locale]/index.tsx
      import { GetStaticPaths, GetStaticProps } from "next";
      import {
        type IConfigLocales,
        getTranslation,
        getMultilingualUrls,
      } from "intlayer";
      import { useIntlayer } from "next-intlayer";
      import Head from "next/head";
      import type { FC } from "react";
      
      interface HomePageProps {
        locale: string;
        metadata: {
          title: string;
          description: string;
        };
        multilingualUrls: Record<string, string>;
      }
      
      const HomePage: FC<HomePageProps> = ({ metadata, multilingualUrls, locale }) => {
        const content = useIntlayer("page");
      
        return (
          <div>
            <Head>
              <title>{metadata.title}</title>
              <meta name="description" content={metadata.description} />
              {/* Генерация тегов hreflang для SEO */}
              {Object.entries(multilingualUrls).map(([lang, url]) => (
                <link
                  key={lang}
                  rel="alternate"
                  hrefLang={lang}
                  href={url}
                />
              ))}
              <link rel="canonical" href={multilingualUrls[locale]} />
            </Head>
      
            {/* Содержимое страницы */}
            <main>
              {/* Ваше содержимое страницы здесь */}
            </main>
          </div>
        );
      };
      
      export const getStaticProps: GetStaticProps<HomePageProps> = async ({
        params
      }) => {
        const locale = params?.locale as string;
        const t = <T>(content: IConfigLocales<T>) => getTranslation(content, locale);
      
        const metadata = {
          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",
          }),
        };
      
        const multilingualUrls = getMultilingualUrls("/");
      
        return {
          props: {
            locale,
            metadata,
            multilingualUrls,
          },
        };
      };
      
      export default HomePage;
      
      // ... Остальная часть кода, включая getStaticPaths
      Узнайте больше об оптимизации метаданных в официальной документации Next.js.
    9. Изменение языка вашего контента

      Необязательно

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

      src/components/LanguageSwitcher.tsx
      import {
        Locales,
        getHTMLTextDir,
        getLocaleName,
        getLocalizedUrl,
      } from "intlayer";
      import { useLocalePageRouter } from "next-intlayer";
      import { type FC } from "react";
      import Link from "next/link";
      
      const LocaleSwitcher: FC = () => {
        const { locale, pathWithoutLocale, availableLocales } = useLocalePageRouter();
      
        return (
          <div>
            <button popoverTarget="localePopover">{getLocaleName(locale)}</button>
            <div id="localePopover" popover="auto">
              {availableLocales.map((localeItem) => (
                <Link
                  href={getLocalizedUrl(pathWithoutLocale, localeItem)}
                  hrefLang={localeItem}
                  key={localeItem}
                  aria-current={locale === localeItem ? "page" : undefined}
                  onClick={() => setLocale(localeItem)}
                >
                  <span>
                    {/* Локаль - например, FR */}
                    {localeItem}
                  </span>
                  <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>
                </Link>
              ))}
            </div>
          </div>
        );
      };
      Альтернативный способ - использовать функцию setLocale, предоставляемую хуком useLocale. Эта функция не позволит предварительно загрузить страницу и приведёт к её перезагрузке.
      В этом случае, без перенаправления с помощью router.push, только ваш серверный код изменит локаль содержимого.
      src/components/LocaleSwitcher.tsx
      "use client";import { useRouter } from "next/navigation";import { useLocale } from "next-intlayer";import { getLocalizedUrl } from "intlayer";// ... Остальная часть кодаconst router = useRouter();const { setLocale } = useLocale({  onLocaleChange: (locale) => {    router.push(getLocalizedUrl(pathWithoutLocale, locale));  },});return (  <button onClick={() => setLocale(Locales.FRENCH)}>    Переключить на французский  </button>);
      API useLocalePageRouter идентичен useLocale. Чтобы узнать больше о хуке useLocale, обратитесь к документации.

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

    10. Необязательно

      Чтобы обеспечить навигацию вашего приложения с учётом текущей локали, вы можете создать пользовательский компонент Link. Этот компонент автоматически добавляет префикс текущего языка к внутренним URL, например, когда франкоязычный пользователь нажимает на ссылку на страницу "О нас", его перенаправляет на /fr/about вместо /about.

      Это поведение полезно по нескольким причинам:

      • SEO и удобство для пользователя: Локализованные URL помогают поисковым системам правильно индексировать страницы на конкретных языках и предоставляют пользователям контент на их предпочтительном языке.
      • Последовательность: Используя локализованные ссылки по всему приложению, вы гарантируете, что навигация останется в рамках текущей локали, предотвращая неожиданные переключения языка.
      • Поддерживаемость: Централизация логики локализации в одном компоненте упрощает управление URL, делая ваш код более удобным для поддержки и расширения по мере роста приложения.

      Ниже приведена реализация локализованного компонента Link на TypeScript:

      src/components/Link.tsx
      "use client";
      
      import { getLocalizedUrl } from "intlayer";
      import NextLink, { type LinkProps as NextLinkProps } from "next/link";
      import { useLocale } from "next-intlayer";
      import { forwardRef, PropsWithChildren, type ForwardedRef } from "react";
      
      /**
       * Утилита для проверки, является ли данный URL внешним.
       * Если URL начинается с http:// или https://, он считается внешним.
       */
      export const checkIsExternalLink = (href?: string): boolean =>
        /^https?:\/\//.test(href ?? "");
      
      /**
       * Кастомный компонент Link, который адаптирует атрибут href в зависимости от текущей локали.
       * Для внутренних ссылок используется `getLocalizedUrl`, чтобы добавить префикс локали (например, /fr/about).
       * Это гарантирует, что навигация останется в контексте текущей локали.
       */
      export const Link = forwardRef<
        HTMLAnchorElement,
        PropsWithChildren<NextLinkProps>
      >(({ href, children, ...props }, ref: ForwardedRef<HTMLAnchorElement>) => {
        const { locale } = useLocale();
        const isExternalLink = checkIsExternalLink(href.toString());
      
        // Если ссылка внутренняя и предоставлен действительный href, получить локализованный URL.
        const hrefI18n: NextLinkProps["href"] =
          href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href;
      
        return (
          <NextLink href={hrefI18n} ref={ref} {...props}>
            {children}
          </NextLink>
        );
      });
      
      Link.displayName = "Link";

      Как это работает

      • Определение внешних ссылок:
        Вспомогательная функция checkIsExternalLink определяет, является ли URL внешним. Внешние ссылки остаются без изменений, так как им не требуется локализация.

      • Получение текущей локали:
        Хук useLocale предоставляет текущую локаль (например, fr для французского).

      • Локализация URL:
        Для внутренних ссылок (то есть не внешних) используется функция getLocalizedUrl, которая автоматически добавляет префикс текущей локали к URL. Это означает, что если пользователь использует французский язык, передача /about в качестве href преобразуется в /fr/about.

      • Возврат ссылки:
        Компонент возвращает элемент <a> с локализованным URL, обеспечивая согласованную навигацию в соответствии с локалью.

      Интегрируя этот компонент Link по всему вашему приложению, вы поддерживаете единый и ориентированный на язык пользовательский опыт, а также улучшаете SEO и удобство использования.

    11. Оптимизация размера бандла

      Необязательно

      При использовании next-intlayer словари по умолчанию включаются в бандл для каждой страницы. Чтобы оптимизировать размер бандла, Intlayer предоставляет необязательный плагин SWC, который интеллектуально заменяет вызовы useIntlayer с помощью макросов. Это гарантирует, что словари включаются только в бандлы тех страниц, которые действительно их используют.

      Чтобы включить эту оптимизацию, установите пакет @intlayer/swc. После установки next-intlayer автоматически обнаружит и использует плагин:

      bash
      npm install @intlayer/swc --save-dev
      Примечание: Эта оптимизация доступна только для Next.js версии 13 и выше.

      Примечание: Этот пакет не устанавливается по умолчанию, так как плагины SWC в Next.js всё ещё находятся в экспериментальной стадии. Это может измениться в будущем.

    Настройка TypeScript

    Intlayer использует расширение модулей (module augmentation), чтобы использовать преимущества TypeScript и сделать ваш код более надёжным.

    Autocompletion

    Translation error

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

    tsconfig.json
    {  // ... Ваши существующие настройки TypeScript  "include": [    // ... Ваши существующие настройки TypeScript    ".intlayer/**/*.ts", // Включить автоматически сгенерированные типы  ],}

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

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

    Добавьте следующие строки в ваш файл .gitignore:

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

    Расширение для VS Code

    Для улучшения вашего опыта разработки с Intlayer вы можете установить официальное расширение Intlayer для VS Code.

    Установить из VS Code Marketplace

    Это расширение предоставляет:

    • Автодополнение для ключей переводов.
    • Обнаружение ошибок в реальном времени для отсутствующих переводов.
    • Встроенный просмотр переведённого контента.
    • Быстрые действия для лёгкого создания и обновления переводов.

    Для получения дополнительной информации о том, как использовать расширение, обратитесь к документации по расширению Intlayer для VS Code.

    Дополнительные ресурсы

    Следуя этому руководству, вы сможете эффективно интегрировать Intlayer в ваше приложение Next.js с использованием Page Router, обеспечивая надежную и масштабируемую поддержку интернационализации для ваших веб-проектов.

    Продвинутые возможности

    Чтобы пойти дальше, вы можете реализовать визуальный редактор или вынести ваш контент, используя CMS.