Отримуйте сповіщення про майбутні випуски Intlayer
    Дата створення:2026-01-10Останнє оновлення:2026-01-10

    Перекладіть ваш сайт Next.js 16 (без [locale] у шляху сторінки) за допомогою Intlayer | Інтернаціоналізація (i18n)

    Дивіться Шаблон додатка на GitHub.

    Зміст

    Що таке Intlayer?

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

    З Intlayer ви можете:

    • Легко керувати перекладами, використовуючи декларативні словники на рівні компонентів.
    • Динамічно локалізувати метадані, маршрути та контент.
    • Отримувати доступ до перекладів як у клієнтських, так і в серверних компонентах.
    • Забезпечити підтримку TypeScript за допомогою автозгенерованих типів, що покращує автозаповнення та виявлення помилок.
    • Отримуйте переваги розширених можливостей, таких як динамічне визначення та перемикання локалі.
    Intlayer сумісний з Next.js 12, 13, 14 та 16. Якщо ви використовуєте Next.js Page Router, зверніться до цього посібника. Для Next.js 12, 13, 14 з App Router зверніться до цього посібника.

    Покроковий посібник зі встановлення Intlayer у застосунку Next.js

    Крок 1: Встановлення залежностей

    Встановіть необхідні пакети за допомогою npm:

    bash
    npm install intlayer next-intlayernpx intlayer init
    • intlayer

      Основний пакет, який надає інструменти інтернаціоналізації для управління конфігурацією, перекладів, оголошення контенту, транспіляції та команд CLI.

    • next-intlayer

    Пакет, який інтегрує Intlayer з Next.js. Він надає провайдери контексту та хуки для інтернаціоналізації в Next.js. Крім того, він включає плагін для Next.js для інтеграції Intlayer з Webpack або Turbopack, а також proxy для визначення переважної локалі користувача, керування cookie та обробки перенаправлень URL.

    Крок 2: Налаштуйте ваш проєкт

    Ось фінальна структура, яку ми створимо:

    .├── src│   ├── app│   │   ├── layout.tsx│   │   ├── page.content.ts│   │   └── page.tsx│   ├── components│   │   ├── clientComponentExample│   │   │   ├── client-component-example.content.ts│   │   │   └── ClientComponentExample.tsx│   │   ├── localeSwitcher│   │   │   ├── localeSwitcher.content.ts│   │   │   └── LocaleSwitcher.tsx│   │   └── serverComponentExample│   │       ├── server-component-example.content.ts│   │       └── ServerComponentExample.tsx│   └── proxy.ts├── intlayer.config.ts├── next.config.ts├── package.json└── tsconfig.json
    Якщо ви не хочете маршрутизацію за локалями, intlayer можна використовувати як простий provider / hook. Дивіться цей посібник для детальнішої інформації.

    Створіть конфігураційний файл для налаштування мов вашого застосунку:

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = {  internationalization: {    locales: [      Locales.ENGLISH,      Locales.FRENCH,      Locales.SPANISH,      // Ваші інші локалі    ],    defaultLocale: Locales.ENGLISH,  },  routing: {    mode: "search-params", // або `no-prefix` - Корисно для виявлення в middleware  },};export default config;
    Через цей файл конфігурації ви можете налаштувати локалізовані URL-адреси, перенаправлення через проксі, назви 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. Додатково він надає aliases для оптимізації продуктивності та забезпечує сумісність із server components.

    Функція withIntlayer() повертає Promise. Вона дозволяє підготувати словники Intlayer перед початком збірки. Якщо ви хочете використовувати її разом з іншими плагінами, ви можете дочекатися її виконання за допомогою await. Приклад:

    const nextConfig = await withIntlayer(nextConfig);const nextConfigWithOtherPlugins = withOtherPlugins(nextConfig);export default nextConfigWithOtherPlugins;

    Якщо ви хочете використовувати його синхронно, ви можете використати функцію withIntlayerSync(). Приклад:

    const nextConfig = withIntlayerSync(nextConfig);const nextConfigWithOtherPlugins = withOtherPlugins(nextConfig);export default nextConfigWithOtherPlugins;

    Intlayer автоматично визначає, чи ваш проєкт використовує webpack чи Turbopack на основі прапорів командного рядка --webpack, --turbo, або --turbopack, а також вашої поточної версії Next.js.

    Оскільки next>=16, якщо ви використовуєте Rspack, ви повинні явно змусити Intlayer використовувати конфігурацію webpack, вимкнувши Turbopack:

    withRspack(withIntlayer(nextConfig, { enableTurbopack: false }));

    Крок 4: Визначте динамічні маршрути локалей

    Видаліть усе з RootLayout і замініть на наступний код:

    src/app/layout.tsx
    import type { Metadata } from "next";import type { ReactNode } from "react";import "./globals.css";import { IntlayerClientProvider, LocalPromiseParams } from "next-intlayer";import { getHTMLTextDir, getIntlayer } from "intlayer";import { getLocale } from "next-intlayer/server";export { generateStaticParams } from "next-intlayer";export const generateMetadata = async ({  params,}: LocalPromiseParams): Promise<Metadata> => {  const { locale } = await params;  const { title, description, keywords } = getIntlayer("metadata", locale);  return {    title,    description,    keywords,  };};const RootLayout = async ({  children,}: Readonly<{  children: ReactNode;}>) => {  const locale = await getLocale();  return (    <html lang={locale} dir={getHTMLTextDir(locale)}>      <IntlayerClientProvider defaultLocale={locale}>        <body>{children}</body>      </IntlayerClientProvider>    </html>  );};export default RootLayout;

    Крок 5: Оголосіть свій контент

    Створюйте та керуйте деклараціями контенту для збереження перекладів:

    src/app/metadata.content.ts
    import { t, type Dictionary } from "intlayer";import { Metadata } from "next";const metadataContent = {  key: "metadata",  content: {    title: t({      uk: "Назва мого проєкту",      en: "My Project Title",      fr: "Le Titre de mon Projet",      es: "El Título de mi Proyecto",    }),    description: t({      uk: "Відкрийте для себе нашу інноваційну платформу, розроблену для оптимізації робочого процесу та підвищення продуктивності.",      en: "Discover our innovative platform designed to streamline your workflow and boost productivity.",      fr: "Découvrez notre plateforme innovante conçue pour simplifier votre flux de travail et booster votre productivité.",      es: "Descubra nuestra plataforma innovadora diseñada para simplificar su flujo de trabajo y aumentar su productividad.",    }),    keywords: t({      uk: ["інновації", "продуктивність", "робочий процес", "SaaS"],      en: ["innovation", "productivity", "workflow", "SaaS"],      uk: ["інновації", "продуктивність", "робочий процес", "SaaS"],      fr: ["innovation", "productivité", "flux de travail", "SaaS"],      es: ["innovación", "productividad", "flujo de trabajo", "SaaS"],    }),  },} as Dictionary<Metadata>;export default metadataContent;
    src/app/metadata.content.mjs
    import { t, type Dictionary } from "intlayer";/** @type {import('intlayer').Dictionary<import('next').Metadata>} */const metadataContent = {  key: "metadata",  content: {    title: t({      uk: "Назва мого проєкту",      en: "My Project Title",      fr: "Le Titre de mon Projet",      es: "El Título de mi Proyecto",    }),    description: t({      uk: "Відкрийте для себе нашу інноваційну платформу, створену для оптимізації робочого процесу та підвищення продуктивності.",      en: "Discover our innovative platform designed to streamline your workflow and boost productivity.",      uk: "Відкрийте для себе нашу інноваційну платформу, створену для оптимізації вашого робочого процесу та підвищення продуктивності.",      fr: "Découvrez notre plateforme innovante conçue pour simplifier votre flux de travail et booster votre productivité.",      es: "Descubra nuestra plataforma innovadora diseñada para simplificar su flujo de trabajo y aumentar su productividad.",    }),    keywords: t({      uk: ["інновація", "продуктивність", "робочий процес", "SaaS"],      en: ["innovation", "productivity", "workflow", "SaaS"],      fr: ["innovation", "productivité", "flux de travail", "SaaS"],      es: ["innovación", "productividad", "flujo de trabajo", "SaaS"],    }),  },};export default metadataContent;
    "keywords": {  "nodeType": "translation",  "translation": {    "uk": ["інновації", "продуктивність", "робочий процес", "SaaS"],    "en": ["innovation", "productivity", "workflow", "SaaS"],    "fr": ["innovation", "productivité", "flux de travail", "SaaS"],    "es": ["innovación", "productividad", "flujo de trabajo", "SaaS"]  }}

    } }

    ```tsx fileName="src/app/page.content.ts" contentDeclarationFormat="typescript"import { t, type Dictionary } from "intlayer";const pageContent = {  key: "page",  content: {    getStarted: {      main: t({        uk: "Почніть з редагування",        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/page.tsx
    import type { FC } from "react";import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";import {  IntlayerServerProvider,  useIntlayer,  getLocale,} from "next-intlayer/server";import { NextPage } from "next";import { headers, cookies } from "next/headers";const PageContent: FC = () => {  const content = useIntlayer("page");  return (    <>      <p>{content.getStarted.main}</p>      <code>{content.getStarted.pageLink}</code>    </>  );};const Page: NextPage = async () => {  const locale = await getLocale();  return (    <IntlayerServerProvider locale={locale}>      <PageContent />      <ServerComponentExample />      <ClientComponentExample />    </IntlayerServerProvider>  );};export default Page;
      <ServerComponentExample />  <ClientComponentExample /></IntlayerServerProvider>

    ); };

    export default Page;

    ```jsx fileName="src/app/page.csx" codeFormat="commonjs"import { ClientComponentExample } from "@components/clientComponentExample/ClientComponentExample";import { ServerComponentExample } from "@components/serverComponentExample/ServerComponentExample";import { IntlayerServerProvider, useIntlayer, getLocale } from "next-intlayer/server";import { NextPage } from "next";import { headers, cookies } from "next/headers";const Page: NextPage = async () => {  const content = useIntlayer("page");  return (    <>      <p>{content.getStarted.main}</p>      <code>{content.getStarted.pageLink}</code>    </>  );};const Page: NextPage = async () => {  const locale = await getLocale();  return (    <IntlayerServerProvider locale={locale}>      <PageContent />      <ServerComponentExample />      <ClientComponentExample />    </IntlayerServerProvider>  );};
    • IntlayerClientProvider використовується для надання локалі компонентам на стороні клієнта. Його можна розмістити в будь-якому батьківському компоненті, включно з layout. Однак рекомендовано розміщувати його в layout, оскільки Next.js спільно використовує код layout між сторінками, що робить це ефективнішим. Використовуючи IntlayerClientProvider у layout, ви уникаєте повторної ініціалізації для кожної сторінки, покращуєте продуктивність і підтримуєте послідовний контекст локалізації в усьому застосунку.
    • IntlayerServerProvider використовується для надання локалі дочірнім серверним компонентам. Його не можна встановлювати в layout.

      Layout і сторінка не можуть ділитись загальним server context, оскільки система server context базується на сховищі даних для кожного запиту (через механізм React's cache), внаслідок чого кожен «context» створюється заново для різних сегментів застосунку. Розміщення провайдера в спільному layout порушить цю ізоляцію та перешкоджатиме правильній передачі значень server context вашим server компонентам.
    src/components/clientComponentExample/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/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>  );};
    Якщо ви хочете використовувати ваш контент у рядковому атрибуті, наприклад alt, title, href, aria-label тощо, ви повинні викликати значення функції, наприклад:
    <img src={content.image.src.value} alt={content.image.value} />
    Щоб дізнатися більше про хук useIntlayer, зверніться до документації.

    (Необов'язково) Крок 7: Налаштування проксі для визначення локалі

    Налаштуйте проксі для визначення преференованої локалі користувача:

    src/proxy.ts
    export { intlayerProxy as proxy } from "next-intlayer/proxy";export const config = {  matcher:    "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)",};
    Проксі intlayerProxy використовується для визначення преферованої локалі користувача та перенаправлення його на відповідну URL-адресу, як зазначено в конфігурації. Крім того, воно дозволяє зберігати преферовану локаль користувача в cookie.
    Якщо потрібно з'єднати кілька проксі разом (наприклад, intlayerProxy з авторизацією або власними проксі), Intlayer тепер надає допоміжну функцію multipleProxies.
    import { multipleProxies, intlayerProxy } from "next-intlayer/proxy";import { customProxy } from "@utils/customProxy";export const proxy = multipleProxies([intlayerProxy, customProxy]);

    (Необов'язково) Крок 8: Змініть мову вашого контенту

    Щоб змінити мову вашого контенту в Next.js, рекомендований спосіб — використовувати компонент Link для перенаправлення користувачів на відповідну локалізовану сторінку. Компонент Link забезпечує prefetch сторінки, що допомагає уникнути повного перезавантаження сторінки.

    src/components/localeSwitcher/LocaleSwitcher.tsx
    "use client";import type { FC } from "react";import { Locales, getHTMLTextDir, getLocaleName } from "intlayer";import { useLocale } from "next-intlayer";export const LocaleSwitcher: FC = () => {  const { locale, availableLocales, setLocale } = useLocale({    onChange: () => window.location.reload(),  });  return (    <div>      <button popoverTarget="localePopover">{getLocaleName(locale)}</button>      <div id="localePopover" popover="auto">        {availableLocales.map((localeItem) => (          <button            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>          </button>        ))}      </div>    </div>  );};
    Альтернативний спосіб — використати функцію setLocale, яку надає хук useLocale. Ця функція не дозволяє виконувати prefetch сторінки. Детальніше див. документацію хуку useLocale.

    Посилання на документацію:

    (Необов'язково) Крок 9: Отримати поточну локаль у Server Actions

    Якщо вам потрібна активна локаль всередині Server Action (наприклад, для локалізації електронних листів або виконання логіки, що залежить від локалі), викличте getLocale з next-intlayer/server:

    src/app/actions/getLocale.ts
    "use server";import { getLocale } from "next-intlayer/server";export const myServerAction = async () => {  const locale = await getLocale();  // Виконайте необхідні дії з локаллю};

    Функція getLocale використовує каскадну стратегію для визначення локалі користувача:

    1. Спочатку вона перевіряє заголовки запиту на наявність значення локалі, яке могло бути встановлене проксі
    2. Якщо локаль не знайдена в заголовках, вона шукає локаль, збережену в cookies
    3. Якщо cookie не знайдено, вона намагається визначити бажану мову користувача з налаштувань браузера
    4. Як останній варіант, вона повертається до локалі за замовчуванням, налаштованої в застосунку

    Це гарантує, що вибирається найбільш відповідна локаль на основі доступного контексту.

    (Необов'язково) Крок 10: Оптимізуйте розмір бандла

    При використанні next-intlayer словники за замовчуванням включаються в бандл для кожної сторінки. Щоб оптимізувати розмір бандла, Intlayer надає необов'язковий SWC-плагін, який інтелектуально замінює виклики useIntlayer за допомогою макросів. Це гарантує, що словники включатимуться лише в бандли сторінок, які їх фактично використовують.

    Щоб увімкнути цю оптимізацію, встановіть пакет @intlayer/swc. Після встановлення next-intlayer автоматично виявить і використає плагін:

    bash
    npm install @intlayer/swc --save-devnpx intlayer init
    Примітка: Ця оптимізація доступна лише для Next.js 13 і новіших версій.
    Примітка: Цей пакет не встановлюється за замовчуванням, оскільки SWC-плагіни в Next.js все ще є експериментальними. Це може змінитися в майбутньому.
    Примітка: Якщо ви встановите опцію як importMode: 'dynamic' або importMode: 'live', це залежатиме від Suspense, тож вам доведеться обгорнути виклики useIntlayer у межі Suspense. Це означає, що ви не зможете використовувати useIntlayer безпосередньо на верхньому рівні вашого компонента Page або Layout.

    Стеження за змінами словників у Turbopack

    При використанні Turbopack як сервера розробки з командою next dev, зміни в словниках за замовчуванням не будуть виявлятися автоматично.

    Це обмеження виникає через те, що Turbopack не може запускати плагіни webpack паралельно, щоб відстежувати зміни у ваших файлах контенту. Щоб обійти це, потрібно використовувати команду intlayer watch, щоб одночасно запускати сервер розробки та спостерігача складання Intlayer.

    package.json
    {  // ... Ваші існуючі конфігурації package.json  "scripts": {    // ... Ваші існуючі налаштування скриптів    "dev": "intlayer watch --with 'next dev'",  },}
    Якщо ви використовуєте next-intlayer@<=6.x.x, потрібно зберегти прапорець --turbopack, щоб додаток Next.js 16 працював правильно з Turbopack. Ми рекомендуємо використовувати next-intlayer@>=7.x.x, щоб уникнути цього обмеження.

    Налаштування TypeScript

    Intlayer використовує module augmentation, щоб отримати переваги TypeScript і зміцнити вашу codebase.

    Автозаповнення

    Помилка перекладу

    Переконайтеся, що ваша конфігурація TypeScript включає автозгенеровані типи.

    tsconfig.json
    {  // ... Ваші існуючі конфігурації TypeScript  "include": [    // ... Ваші існуючі конфігурації TypeScript    ".intlayer/**/*.ts", // Include the auto-generated types  ],}

    Налаштування Git

    Рекомендується ігнорувати файли, згенеровані Intlayer. Це дозволить уникнути їх додавання до вашого Git-репозиторію.

    Для цього можна додати наступні інструкції до файлу .gitignore:

    .gitignore
    # Ігнорувати файли, згенеровані Intlayer.intlayer

    Розширення VS Code

    Щоб покращити досвід розробки з Intlayer, ви можете встановити офіційне розширення Intlayer VS Code Extension.

    Встановити з VS Code Marketplace

    Це розширення надає:

    • Автодоповнення для ключів перекладу.
    • Виявлення помилок у реальному часі для відсутніх перекладів.
    • Вбудований попередній перегляд перекладеного вмісту.
    • Швидкі дії для легкого створення та оновлення перекладів.

    Для детальнішої інформації про використання розширення зверніться до документації Intlayer VS Code Extension.

    Розширені можливості

    Щоб розширити можливості, ви можете реалізувати візуальний редактор або винести свій вміст, використовуючи CMS.

    Отримуйте сповіщення про майбутні випуски Intlayer