Получайте уведомления о предстоящих релизах Intlayer
    Создание:2024-12-06Последнее обновление:2025-06-29

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

    Смотрите Шаблон приложения на GitHub.

    Что такое Intlayer?

    Intlayer — это инновационная, открытая библиотека интернационализации (i18n), разработанная для упрощения поддержки многоязычности в современных веб-приложениях. Intlayer бесшовно интегрируется с последним фреймворком Next.js 15, включая его мощный App Router. Она оптимизирована для работы с Server Components для эффективного рендеринга и полностью совместима с Turbopack.

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

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

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


    Пошаговое руководство по установке 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, а также middleware для определения предпочтительной локали пользователя, управления cookie и обработки перенаправления 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.ts
    import type { NextConfig } from "next";import { withIntlayer } from "next-intlayer/server";const nextConfig: NextConfig = {  /* параметры конфигурации здесь */};export default withIntlayer(nextConfig);

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

    Шаг 4: Определение динамических маршрутов локалей

    Удалите всё из 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>.

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

    src/app/[locale]/layout.tsx
    import type { NextLayoutIntlayer } from "next-intlayer";import { Inter } from "next/font/google";import { getHTMLTextDir } from "intlayer";const inter = Inter({ subsets: ["latin"] });// Локальный макет для обработки маршрутизации с учетом локалиconst LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => {  const { locale } = await params; // Получаем текущую локаль из параметров  return (    <html lang={locale} dir={getHTMLTextDir(locale)}>      <body className={inter.className}>{children}</body>    </html>  );};export default LocaleLayout;

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

    На этом этапе вы столкнетесь с ошибкой: Error: Missing <html> and <body> tags in the root layout.. Это ожидаемо, поскольку файл /app/page.tsx больше не используется и может быть удален. Вместо этого сегмент пути [locale] активирует страницу /app/[locale]/page.tsx. Следовательно, страницы будут доступны по путям, таким как /en, /fr, /es в вашем браузере. Чтобы установить локаль по умолчанию в качестве корневой страницы, обратитесь к настройке middleware на шаге 7.

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

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

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

    Шаг 5: Объявите Ваш Контент

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

    src/app/[locale]/page.content.ts
    import { t, type Dictionary } from "intlayer";const pageContent = {  key: "page",  content: {    getStarted: {      main: t({        ru: "Начните с редактирования",        en: "Get started by editing",        fr: "Commencez par éditer",        es: "Comience por editar",      }),      pageLink: "src/app/page.tsx",    },  },} satisfies Dictionary;export default pageContent;

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

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

    Шаг 6: Использование контента в вашем коде

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

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

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

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

    src/components/ClientComponentExample.tsx
    "use client";import type { FC } from "react";import { useIntlayer } from "next-intlayer";export 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";export 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, обратитесь к документации.

    (Необязательно) Шаг 7: Настройка Middleware для определения локали

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

    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).*)",};

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

    (Необязательно) Шаг 7: Настройка Middleware для определения локали

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

    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, как указано в конфигурации. Кроме того, он позволяет сохранять предпочтительную локаль пользователя в cookie.

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

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

    src/app/[locale]/metadata.content.ts
    import { type Dictionary, t } from "intlayer";import { Metadata } from "next";const metadataContent = {  key: "page-metadata",  content: {    title: t({      en: "Create Next App",      fr: "Créer une application Next.js",      es: "Crear una aplicación Next.js",    }),    description: t({      en: "Generated by create next app",      fr: "Généré par create next app",      es: "Generado por create next app",    }),  },} удовлетворяет Dictionary<Metadata>;export default metadataContent;
    src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx
    import { getIntlayer, getMultilingualUrls } from "intlayer";import type { Metadata } from "next";import type { LocalPromiseParams } from "next-intlayer";export const generateMetadata = async ({  params,}: LocalPromiseParams): Promise<Metadata> => {  const { locale } = await params;  const metadata = getIntlayer("page-metadata", locale);  /**   * Генерирует объект, содержащий все URL для каждого языка.   *   * Пример:   * ```ts   *  getMultilingualUrls('/about');   *   *  // Возвращает   *  // {   *  //   en: '/about',   *  //   fr: '/fr/about',   *  *   es: '/es/about',   *  // }   * ```   */  const multilingualUrls = getMultilingualUrls("/");  return {    ...metadata,    alternates: {      canonical: multilingualUrls[locale as keyof typeof multilingualUrls],      languages: { ...multilingualUrls, "x-default": "/" },    },    openGraph: {      url: multilingualUrls[locale],    },  };};// ... Остальная часть кода

    Обратите внимание, что функция getIntlayer, импортируемая из next-intlayer, возвращает ваш контент, обёрнутый в IntlayerNode, что позволяет интегрироваться с визуальным редактором. В то время как функция getIntlayer, импортируемая из intlayer, возвращает ваш контент напрямую без дополнительных свойств.

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

    src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx
    import {  type IConfigLocales,  getTranslation,  getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalPromiseParams } from "next-intlayer";export const generateMetadata = async ({  params,}: LocalPromiseParams): Promise<Metadata> => {  const { locale } = await params;  const t = <T>(content: IConfigLocales<T>) => getTranslation(content, locale);  return {    title: t<string>({      ru: "Мой заголовок",      en: "My title",      fr: "Mon titre",      es: "Mi título",    }),    description: t({      ru: "Моё описание",      en: "My description",      fr: "Ma description",      es: "Mi descripción",    }),  };};// ... Остальная часть кода

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

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

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

    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;

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

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

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

    src/components/LocaleSwitcher.tsx
    "use client";import type { FC } from "react";import {  Locales,  getHTMLTextDir,  getLocaleName,  getLocalizedUrl,} from "intlayer";import { useLocale } from "next-intlayer";import Link from "next/link";export const LocaleSwitcher: FC = () => {  const { locale, pathWithoutLocale, availableLocales } = useLocale();  const { setLocaleCookie } = useLocaleCookie();  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={() => setLocaleCookie(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>);

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

    Чтобы навигация вашего приложения учитывала текущую локаль, вы можете создать собственный компонент 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 type { PropsWithChildren, FC } from "react";/** * Вспомогательная функция для проверки, является ли данный URL внешним. * Если URL начинается с http:// или https://, он считается внешним. */export const checkIsExternalLink = (href?: string): boolean =>  /^https?:\/\//.test(href ?? "");/** * Пользовательский компонент Link, который адаптирует атрибут href в зависимости от текущей локали. * Для внутренних ссылок используется `getLocalizedUrl` для добавления префикса локали к URL (например, /fr/about). * Это гарантирует, что навигация останется в контексте той же локали. */export const Link: FC<PropsWithChildren<NextLinkProps>> = ({  href,  children,  ...props}) => {  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} {...props}>      {children}    </NextLink>  );};

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

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

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

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

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

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

    (Необязательно) Шаг 12: Оптимизация размера бандла

    При использовании 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 и сделать ваш код более надёжным.

    alt text

    alt text

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

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

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

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

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

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

    Расширение VS Code

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

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

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

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

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

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

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

    История документации

    • 5.5.10 - 2025-06-29: Инициализация истории
    Получайте уведомления о предстоящих релизах Intlayer