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

    Что такое Intlayer?

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

    С Intlayer вы можете:

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

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


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

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

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

    bash
    npm install intlayer next-intlayer
    
    bash
    yarn add intlayer next-intlayer
    
    bash
    pnpm add intlayer next-intlayer
    

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

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

    typescript
    // 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;
    

    Чтобы увидеть все доступные параметры, обратитесь к документации по конфигурации здесь.

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

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

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

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

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

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

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

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

    Измените src/app/page.ts на src/app/[locale]/page.ts

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

    tsx
    // src/app/layout.tsx
    
    import type { ReactNode } from "react";
    import "./globals.css";
    
    export { generateStaticParams } from "next-intlayer"; // Линия для вставки
    
    const RootLayout = ({
      children,
    }: Readonly<{
      children: ReactNode;
    }>) => children;
    
    export default RootLayout;
    

    Затем добавьте новую разметку в вашу директорию [locale]:

    tsx
    // 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;
    

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

    Создайте и управляйте вашими словарями контента:

    tsx
    // 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;
    

    Смотрите, как объявить ваши файлы декларации Intlayer.

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

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

    tsx
    // src/app/[locale]/page.ts
    
    import { ClientComponentExample } from "@component/ClientComponentExample";
    import { LocaleSwitcher } from "@component/LangSwitcherDropDown";
    import { NestedServerComponentExample } from "@component/NestedServerComponentExample";
    import { ServerComponentExample } from "@component/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 используется для предоставления локали серверным дочерним элементам
           *   Не работает, если установлен в разметке
           */}
          <IntlayerServerProvider locale={locale}>
            <ServerComponentExample />
          </IntlayerServerProvider>
          {/**
           *   IntlayerClientProvider используется для предоставления локали клиентским дочерним элементам
           *   Може быть установлен в любом родительском компоненте, включая разметку
           */}
          <IntlayerClientProvider locale={locale}>
            <ClientComponentExample />
          </IntlayerClientProvider>
        </>
      );
    };
    
    export default Page;
    
    tsx
    // src/components/ClientComponentExample.tsx
    
    "use client";
    
    import { useIntlayer } from "next-intlayer";
    
    export const ClientComponentExample = () => {
      const content = useIntlayer("client-component-example"); // Создайте соответствующее объявление контента
    
      return (
        <div>
          <h2>{content.title} </h2>
          <p>{content.content}</p>
        </div>
      );
    };
    
    tsx
    // src/components/ServerComponentExample.tsx
    
    import { useIntlayer } from "next-intlayer/server";
    
    export const ServerComponentExample = () => {
      const content = useIntlayer("server-component-example"); // Создайте соответствующее объявление контента
    
      return (
        <div>
          <h2>{content.title} </h2>
          <p>{content.content}</p>
        </div>
      );
    };
    

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

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

    Для более подробного использования intlayer в клиентском или серверном компоненте смотрите пример Next.js здесь.

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

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

    typescript
    // src/app/[locale]/layout.tsx или 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: url,
          languages: { ...multilingualUrls, "x-default": "/" },
        },
        openGraph: {
          url: multilingualUrls[locale],
        },
      };
    };
    
    // ... Остальная часть кода
    

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

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

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

    tsx
    // 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;
    
    tsx
    // 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: Изменение языка вашего контента

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

    tsx
    import { Locales } from "intlayer";
    import { useLocale } from "next-intlayer";
    
    const MyComponent = () => {
      const { setLocale } = useLocale();
    
      return (
        <button onClick={() => setLocale(Locales.English)}>Изменить язык</button>
      );
    };
    

    Настройка TypeScript

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

    alt text

    alt text

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

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

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

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

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

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

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

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