Содержимое этой страницы было переведено с помощью ИИ.
Смотреть последнюю версию оригинального контента на английскомНачало работы с интернационализацией (i18n) с Intlayer и Next.js с использованием Page Router
Что такое Intlayer?
Intlayer — это инновационная, с открытым исходным кодом библиотека интернационализации (i18n), разработанная для упрощения поддержки многоязычности в современных веб-приложениях. Intlayer бесшовно интегрируется с последними версиями фреймворка Next.js, включая его традиционный Page Router.
С помощью Intlayer вы можете:
- Легко управлять переводами с использованием декларативных словарей на уровне компонентов.
- Динамически локализовать метаданные, маршруты и контент.
- Обеспечить поддержку TypeScript с автогенерируемыми типами, улучшая автодополнение и обнаружение ошибок.
- Воспользоваться расширенными возможностями, такими как динамическое определение и переключение локали.
Intlayer совместим с Next.js 12, 13, 14 и 15. Если вы используете Next.js App Router, обратитесь к руководству по App Router. Для Next.js 15 следуйте этому руководству.
Пошаговое руководство по настройке Intlayer в приложении Next.js с использованием Page Router
Шаг 1: Установка зависимостей
Установите необходимые пакеты с помощью предпочитаемого менеджера пакетов:
npm install intlayer next-intlayer
intlayer
intlayer
Основной пакет, предоставляющий инструменты интернационализации для управления конфигурацией, перевода, объявления контента, транспиляции и CLI-команд.
next-intlayer
Пакет, который интегрирует Intlayer с Next.js. Он предоставляет провайдеры контекста и хуки для интернационализации в Next.js. Кроме того, включает плагин Next.js для интеграции Intlayer с Webpack или Turbopack, а также middleware для определения предпочтительного языка пользователя, управления куки и обработки перенаправлений 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-адреса, перенаправление через middleware, имена cookie, расположение и расширение ваших деклараций контента, отключить логи Intlayer в консоли и многое другое. Для полного списка доступных параметров обратитесь к документации по конфигурации.
Шаг 3: Интеграция Intlayer с конфигурацией Next.js
Измените конфигурацию Next.js, чтобы включить Intlayer:
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 для автоматического определения и обработки предпочтительной локали пользователя:
export { intlayerMiddleware 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: Определение динамических маршрутов локализации
Реализуйте динамическую маршрутизацию для предоставления локализованного контента в зависимости от локали пользователя.
Создайте страницы для конкретных локалей:
Переименуйте основной файл страницы, добавив динамический сегмент [locale].
bashmv src/pages/index.tsx src/pages/[locale]/index.tsx
Обновите _app.tsx для поддержки локализации:
Измените ваш _app.tsx, чтобы включить провайдеры Intlayer.
src/pages/_app.tsximport 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;
Настройка getStaticPaths и getStaticProps:
В вашем файле [locale]/index.tsx определите пути и свойства для обработки разных локалей.
src/pages/[locale]/index.tsximport 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: Объявите Ваш Контент
Создайте и управляйте объявлениями контента для хранения переводов.
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: Использование контента в вашем коде
Получайте доступ к словарям контента по всему вашему приложению для отображения переведённого контента.
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 и getStaticPropsexport default HomePage;
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> );};
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), вызывайте
значение функции следующим образом:
jsx<img src={content.image.src.value} alt={content.image.value} />
Чтобы узнать больше о хуке useIntlayer, обратитесь к документации.
(Необязательно) Шаг 8: Интернационализация ваших метаданных
Если вы хотите интернационализировать ваши метаданные, такие как заголовок страницы, вы можете использовать функцию getStaticProps, предоставляемую маршрутизатором страниц Next.js. Внутри вы можете получить содержимое с помощью функции getIntlayer для перевода ваших метаданных.
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;
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 для объявления ваших метаданных. Однако рекомендуется использовать файлы декларации контента, чтобы автоматизировать перевод ваших метаданных и в какой-то момент вынести контент отдельно.
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 позволяет предварительно загружать страницу, что помогает избежать полной перезагрузки страницы.
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(); 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, только ваш серверный код изменит локаль содержимого.
"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
Чтобы обеспечить навигацию вашего приложения с учётом текущей локали, вы можете создать пользовательский компонент Link. Этот компонент автоматически добавляет префикс текущего языка к внутренним URL, например, когда франкоязычный пользователь нажимает на ссылку на страницу "О нас", его перенаправляет на /fr/about вместо /about.
Это поведение полезно по нескольким причинам:
- SEO и удобство для пользователя: Локализованные URL помогают поисковым системам правильно индексировать страницы на конкретных языках и предоставляют пользователям контент на их предпочтительном языке.
- Последовательность: Используя локализованные ссылки по всему приложению, вы гарантируете, что навигация останется в рамках текущей локали, предотвращая неожиданные переключения языка.
- Поддерживаемость: Централизация логики локализации в одном компоненте упрощает управление URL, делая ваш код более удобным для поддержки и расширения по мере роста приложения.
Ниже приведена реализация локализованного компонента Link на TypeScript:
"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 автоматически обнаружит и использует плагин:
npm install @intlayer/swc --save-dev
Примечание: Эта оптимизация доступна только для Next.js версии 13 и выше.
Примечание: Этот пакет не устанавливается по умолчанию, так как плагины SWC в Next.js всё ещё находятся в экспериментальной стадии. Это может измениться в будущем.
Настройка TypeScript
Intlayer использует расширение модулей (module augmentation), чтобы использовать преимущества TypeScript и сделать ваш код более надёжным.
Убедитесь, что ваша конфигурация TypeScript включает автоматически сгенерированные типы.
{ // ... Ваши существующие настройки TypeScript "include": [ // ... Ваши существующие настройки TypeScript ".intlayer/**/*.ts", // Включить автоматически сгенерированные типы ],}
Конфигурация Git
Чтобы поддерживать ваш репозиторий в чистоте и избежать коммита сгенерированных файлов, рекомендуется игнорировать файлы, создаваемые Intlayer.
Добавьте следующие строки в ваш файл .gitignore:
# Игнорировать файлы, сгенерированные Intlayer.intlayer
Расширение для VS Code
Для улучшения вашего опыта разработки с Intlayer вы можете установить официальное расширение Intlayer для VS Code.
Установить из VS Code Marketplace
Это расширение предоставляет:
- Автодополнение для ключей переводов.
- Обнаружение ошибок в реальном времени для отсутствующих переводов.
- Встроенный просмотр переведённого контента.
- Быстрые действия для лёгкого создания и обновления переводов.
Для получения дополнительной информации о том, как использовать расширение, обратитесь к документации по расширению Intlayer для VS Code.
Дополнительные ресурсы
- Документация Intlayer: Репозиторий GitHub
- Руководство по словарю: Словарь
- Документация по конфигурации: Руководство по конфигурации
Следуя этому руководству, вы сможете эффективно интегрировать Intlayer в ваше приложение Next.js с использованием Page Router, обеспечивая надежную и масштабируемую поддержку интернационализации для ваших веб-проектов.
Продвинутые возможности
Чтобы пойти дальше, вы можете реализовать визуальный редактор или вынести ваш контент, используя CMS.
История документа
- 5.5.10 - 2025-06-29: Инициализация истории
Если у вас есть идея по улучшению этой документации, не стесняйтесь внести свой вклад, подав запрос на вытягивание на GitHub.
Ссылка на документацию GitHub