Интеграция с Next.js

@lingo.dev/compiler интегрируется с Next.js App Router через асинхронный конфигуратор, который поддерживает и Webpack, и Turbopack.

Установка

1. Установите пакет

pnpm install @lingo.dev/compiler

2. Настройте Next.js

Обновите ваш next.config.ts, чтобы использовать асинхронный обёртчик withLingo():

import type { NextConfig } from "next";
import { withLingo } from "@lingo.dev/compiler/next";

const nextConfig: NextConfig = {
  // Your existing Next.js config
};

export default async function (): Promise<NextConfig> {
  return await withLingo(nextConfig, {
    sourceRoot: "./app",
    sourceLocale: "en",
    targetLocales: ["es", "de", "fr"],
    models: "lingo.dev",
    dev: {
      usePseudotranslator: true,
    },
  });
}

Почему async? Обёртка лениво загружает плагины и динамически подбирает конфиг. Это ускоряет сборку и позволяет подключать плагины по необходимости.

3. Добавьте провайдер

Обверните приложение в LingoProvider в корневом layout:

// app/layout.tsx
import { LingoProvider } from "@lingo.dev/compiler/react";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <LingoProvider>
      <html>
        <body>{children}</body>
      </html>
    </LingoProvider>
  );
}

Важно: Поместите LingoProvider внутрь <html>, оборачивая весь контент. Работает и с Server, и с Client Components.

React Server Components

Компилятор полностью поддерживает React Server Components (RSC). Серверные компоненты переводятся на этапе сборки, а переводы встраиваются в серверный вывод.

// app/page.tsx (Server Component)
export default function Page() {
  return (
    <div>
      <h1>Welcome to our app</h1>
      <p>This is a server component—translated at build time</p>
    </div>
  );
}

Для переведённого текста в Server Components не добавляется JS на клиенте.

Client Components

Для Client Components используйте директиву "use client":

"use client";

import { useLingoContext } from "@lingo.dev/compiler/react";

export function LanguageSwitcher() {
  const { locale, setLocale } = useLingoContext();

  return (
    <select value={locale} onChange={(e) => setLocale(e.target.value)}>
      <option value="en">English</option>
      <option value="es">Español</option>
      <option value="de">Deutsch</option>
    </select>
  );
}

Client Components получают оптимизированные translation-бандлы. Включаются только переводы, используемые в этом компоненте.

Определение локали

По умолчанию локаль хранится в cookie (locale). Компилятор сам определяет и сохраняет локаль.

Кастомное определение локали на сервере

Для своей логики (база, заголовки, поддомен) создайте .lingo/locale-resolver.server.ts:

// .lingo/locale-resolver.server.ts
import { headers } from "next/headers";

export async function getServerLocale(): Promise<string> {
  const headersList = await headers();
  const acceptLanguage = headersList.get("accept-language");

  // Parse accept-language header
  const locale = acceptLanguage?.split(",")[0]?.split("-")[0] || "en";

  return locale;
}

Эта функция вызывается на сервере для каждого запроса. Она должна возвращать код локали (например, "en", "es").

Кастомное сохранение локали на клиенте

Для своей логики на клиенте (localStorage, параметры URL) создайте .lingo/locale-resolver.client.ts:

// .lingo/locale-resolver.client.ts
export function getClientLocale(): string {
  // Check URL parameter first
  const params = new URLSearchParams(window.location.search);
  const urlLocale = params.get("lang");
  if (urlLocale) return urlLocale;

  // Fall back to localStorage
  return localStorage.getItem("locale") || "en";
}

export function persistLocale(locale: string): void {
  localStorage.setItem("locale", locale);

  // Optionally update URL
  const url = new URL(window.location.href);
  url.searchParams.set("lang", locale);
  window.history.replaceState({}, "", url.toString());
}

Подробнее см. в разделе Custom Locale Resolvers.

Middleware для маршрутизации по локали

Если хотите маршрутизацию по локали (/en/about, /es/about), реализуйте middleware Next.js:

// middleware.ts
import { NextRequest, NextResponse } from "next/server";

const locales = ["en", "es", "de", "fr"];
const defaultLocale = "en";

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Check if pathname already has a locale
  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  );

  if (pathnameHasLocale) return;

  // Get locale from cookie or accept-language header
  const localeCookie = request.cookies.get("locale")?.value;
  const acceptLanguage = request.headers.get("accept-language");
  const locale =
    localeCookie ||
    acceptLanguage?.split(",")[0]?.split("-")[0] ||
    defaultLocale;

  // Redirect to localized pathname
  request.nextUrl.pathname = `/${locale}${pathname}`;
  return NextResponse.redirect(request.nextUrl);
}

export const config = {
  matcher: ["/((?!api|_next|_vercel|.*\\..*).*)"],
};

Обновите свои маршруты, чтобы использовать динамический сегмент [locale]:

app/
  [locale]/
    page.tsx
    about/
      page.tsx
    layout.tsx

Конфигурация сборки

Сборка для разработки

{
  dev: {
    usePseudotranslator: true, // Fast fake translations
  }
}

Запустите npm run dev, чтобы стартовать dev-сервер с мгновенными псевдопереводами.

Сборка для продакшена

{
  buildMode: "cache-only", // Use pre-generated translations
}

Запустите npm run build для сборки продакшена. API-ключи не нужны — переводы берутся из .lingo/metadata.json.

Лучше всего: генерируйте реальные переводы в CI перед продакшен-сборкой. См. Build Modes для рекомендуемого workflow.

Поддержка Turbopack

Компилятор работает и с Webpack, и с Turbopack (Next.js 15+).

Чтобы использовать Turbopack в разработке:

next dev --turbo

Компилятор сам определяет и настраивает нужный бандлер.

TypeScript

Компилятор полностью типизирован. Импортируйте типы из @lingo.dev/compiler:

import type { LingoConfig } from "@lingo.dev/compiler";

const config: LingoConfig = {
  sourceRoot: "./app",
  sourceLocale: "en",
  targetLocales: ["es", "de"],
  models: "lingo.dev",
};

Частые проблемы

"Cannot find module '@lingo.dev/compiler/react'" Убедитесь, что вы установили пакет: pnpm install @lingo.dev/compiler

HMR не работает после добавления LingoProvider Проверьте, что LingoProvider находится в корневом layout, а не во вложенном layout или странице.

Переводы не отображаются в production-сборке Проверьте, что вы используете buildMode: "cache-only" и что в .lingo/metadata.json есть переводы для всех локалей.

"Отсутствуют переводы для локали X" Запустите dev-сервер с usePseudotranslator: false, чтобы сгенерировать настоящие переводы, или выполните CI-сборку, чтобы заполнить .lingo/metadata.json.

Дальнейшие шаги