Intégration Next.js

@lingo.dev/compiler s'intègre avec Next.js App Router via un wrapper de configuration asynchrone qui prend en charge Webpack et Turbopack.

Configuration

1. Installer le package

pnpm install @lingo.dev/compiler

2. Configurer Next.js

Mettez à jour votre next.config.ts pour utiliser le wrapper asynchrone 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,
    },
  });
}

Pourquoi asynchrone ? Le wrapper charge les plugins de manière différée et résout la configuration dynamiquement. Cela maintient votre build rapide et permet le chargement conditionnel des plugins.

3. Ajouter le provider

Enveloppez votre application avec LingoProvider dans votre layout racine :

// 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>
  );
}

Important : Placez LingoProvider à l'intérieur de <html> mais en enveloppant tout le contenu. Il fonctionne avec les composants serveur et client.

Composants serveur React

Le compilateur prend entièrement en charge les composants serveur React (RSC). Les composants serveur sont traduits au moment du build, et les traductions sont intégrées dans la sortie serveur.

// 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>
  );
}

Aucun JavaScript côté client n'est ajouté pour le texte traduit dans les composants serveur.

Composants client

Pour les composants client, utilisez la directive "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>
  );
}

Les composants client reçoivent des bundles de traduction optimisés. Seules les traductions utilisées dans ce composant sont incluses.

Détection de la locale

Par défaut, la locale est stockée dans un cookie (locale). Le compilateur gère automatiquement la détection et la persistance de la locale.

Détection personnalisée de la locale côté serveur

Pour une logique personnalisée (base de données, en-têtes, sous-domaine), créez .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;
}

Cette fonction est appelée sur le serveur pour chaque requête. Elle doit retourner le code de locale (par exemple, "en", "es").

Persistance personnalisée de la locale côté client

Pour une logique personnalisée côté client (localStorage, paramètres d'URL), créez .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());
}

Consultez Résolveurs de locale personnalisés pour plus de détails.

Middleware pour le routage par locale

Si vous souhaitez un routage basé sur la locale (/en/about, /es/about), implémentez un 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|.*\\..*).*)"],
};

Mettez à jour vos routes pour utiliser le segment dynamique [locale] :

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

Configuration de build

Build de développement

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

Exécutez npm run dev pour démarrer le serveur de développement avec des pseudotraductions instantanées.

Build de production

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

Exécutez npm run build pour builder en production. Aucune clé API nécessaire — les traductions proviennent de .lingo/metadata.json.

Bonne pratique : générez les vraies traductions en CI avant de builder pour la production. Consultez Modes de build pour le workflow recommandé.

Support de Turbopack

Le compilateur fonctionne avec Webpack et Turbopack (Next.js 15+).

Pour utiliser Turbopack en développement :

next dev --turbo

Le compilateur détecte et configure automatiquement le bundler approprié.

TypeScript

Le compilateur est entièrement typé. Importez les types depuis @lingo.dev/compiler :

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

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

Problèmes courants

« Cannot find module '@lingo.dev/compiler/react' » Assurez-vous d'avoir installé le package : pnpm install @lingo.dev/compiler

Le HMR ne fonctionne pas après l'ajout de LingoProvider Assurez-vous que LingoProvider est correctement placé dans votre layout racine, et non dans un layout ou une page imbriqués.

Les traductions ne s'affichent pas dans le build de production Vérifiez que vous utilisez buildMode: "cache-only" et que .lingo/metadata.json contient les traductions pour toutes les locales.

« Missing translations for locale X » Exécutez votre serveur de développement avec usePseudotranslator: false pour générer de vraies traductions, ou lancez un build CI pour remplir .lingo/metadata.json.

Prochaines étapes