Начало работы с интернационализацией (i18n) с Intlayer и Next.js 15 App Router
Что такое Intlayer?
Intlayer — это инновационная библиотека интернационализации (i18n) с открытым исходным кодом, предназначенная для упрощения многоязычной поддержки в современных веб-приложениях. Intlayer бесшовно интегрируется с последней версией Next.js 15, включая его мощный App Router. Он оптимизирован для работы с Серверными Компонентами для эффективного рендеринга и полностью совместим с 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:
npm install intlayer next-intlayer
intlayer
Основной пакет, который предоставляет инструменты интернационализации для управления конфигурацией, переводом, декларацией контента, транспиляции и CLI команд.
next-intlayer
Пакет, который интегрирует Intlayer с Next.js. Он предоставляет контекст-провайдеры и хуки для интернационализации Next.js. Кроме того, он включает плагин Next.js для интеграции Intlayer с Webpack или Turbopack, а также промежуточное ПО для определения предпочтительной локали пользователя, управления cookie и обработки перенаправления URL.
Шаг 2: Настройте ваш проект
Создайте файл конфигурации для настройки языков вашего приложения:
import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // Ваши другие локали ], defaultLocale: Locales.ENGLISH, },};export default config;
Через этот файл конфигурации вы можете настроить локализованные URL, перенаправление промежуточного ПО, имена cookie, местоположение и расширение ваших деклараций контента, отключить логи Intlayer в консоли и многое другое. Для полного списка доступных параметров обратитесь к документации по конфигурации.
Шаг 3: Интегрируйте Intlayer в вашу конфигурацию Next.js
Настройте вашу конфигурацию Next.js для использования Intlayer:
import { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = {};export default withIntlayer(nextConfig);
Плагин withIntlayer() для Next.js используется для интеграции Intlayer с Next.js. Он обеспечивает сборку файлов декларации контента и их мониторинг в режиме разработки. Он определяет переменные окружения Intlayer в Webpack или Turbopack. Кроме того, он предоставляет псевдонимы для оптимизации производительности и обеспечивает совместимость с серверными компонентами.
Шаг 4: Настройте промежуточное ПО для определения локали
Настройте промежуточное ПО для определения предпочтительной локали пользователя:
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.
Шаг 5: Определите динамические маршруты локали
Удалите все из RootLayout и замените это следующим кодом:
import type { PropsWithChildren, FC } from "react";import "./globals.css";const RootLayout: FC<PropsWithChildren> = ({ children }) => children;export default RootLayout;
Оставляя компонент RootLayout пустым, вы можете установить атрибуты lang и dir в тег <html>.
Для реализации динамической маршрутизации предоставьте путь для локали, добавив новый макет в вашу директорию [locale]:
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/about к fr.
Затем реализуйте функцию generateStaticParams в макете вашего приложения.
export { generateStaticParams } from "next-intlayer"; // Строка для вставкиconst LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => { /*... Остальной код*/};export default LocaleLayout;
generateStaticParams гарантирует, что ваше приложение предварительно строит необходимые страницы для всех локалей, сокращая вычисления во время выполнения и улучшая пользовательский опыт. Для получения дополнительных сведений обратитесь к документации Next.js по generateStaticParams.
Шаг 6: Декларируйте ваш контент
Создайте и управляйте вашими декларациями контента для хранения переводов:
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: Используйте контент в вашем коде
Получите доступ к вашим словарям контента по всему вашему приложению:
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 { title, 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 используется для предоставления локали компонентам на клиентской стороне. Его можно разместить в любом родительском компоненте, включая макет. Однако рекомендуется размещать его в макете, поскольку Next.js делит код макета между страницами, что делает его более эффективным. Используя IntlayerClientProvider в макете, вы избегаете повторной инициализации для каждой страницы, улучшая производительность и поддерживая согласованный контекст локализации на протяжении всего вашего приложения.
- IntlayerServerProvider используется для предоставления локали серверам детям. Его нельзя устанавливать в макете.
Макет и страница не могут делить общий серверный контекст, поскольку система серверного контекста основана на хранилище данных на каждый запрос (через кэш React), что приводит к тому, что каждый «контекст» создается заново для разных сегментов приложения. Размещение провайдера в общем макете нарушило бы эту изоляцию, предотвращая правильную передачу значений серверного контекста вашим серверным компонентам.
"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> );};
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, обратитесь к документации.
(Дополнительно) Шаг 8: Интернационализация ваших метаданных
Если вы хотите интернационализировать свои метаданные, такие как заголовок вашей страницы, вы можете использовать функцию generateMetadata, предоставленную Next.js. Внутри функции используйте функцию getTranslationContent для перевода ваших метаданных.
import { type IConfigLocales, getTranslationContent, getMultilingualUrls,} from "intlayer";import type { Metadata } from "next";import type { LocalPromiseParams } from "next-intlayer";export const generateMetadata = async ({ params: { locale },}: LocalPromiseParams): Metadata => { const { locale } = await params; 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 для вашего карты сайта.
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;
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. Эта функция позволяет вам установить локаль приложения и обновить контент соответствующим образом.
"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, setLocale } = useLocale(); return ( <ol> {availableLocales.map((localeItem) => ( <li key={localeItem}> <Link 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> </Link> </li> ))} </ol> );};
Ссылки на документацию:
Настройка TypeScript
Intlayer использует наращение модулей, чтобы воспользоваться преимуществами TypeScript и сделать вашу кодовую базу более надежной.
Убедитесь, что ваша конфигурация TypeScript включает автоматически сгенерированные типы.
{ // ... Ваша существующая конфигурация TypeScript "include": [ // ... Ваша существующая конфигурация TypeScript "types", // Включите автоматически сгенерированные типы ],}
Конфигурация Git
Рекомендуется игнорировать файлы, сгенерированные Intlayer. Это позволит вам избежать их добавления в ваш репозиторий Git.
Для этого вы можете добавить следующие инструкции в ваш файл .gitignore:
# Игнорировать файлы, сгенерированные Intlayer.intlayer
Если у вас есть идея по улучшению этой документации, не стесняйтесь внести свой вклад, подав запрос на вытягивание на GitHub.
Ссылка на документацию GitHub