Skip to main content

Le guide complet de l'internationalisation Next.js

Configurez next-intl avec l'App Router, mettez en place le routage par locale et automatisez les traductions avec l'IA.

1

Installez next-intl

next-intl est un package unique qui gère le routage par locale, le chargement des messages et les hooks de traduction pour l'App Router de Next.js.

Terminal
npm install next-intl
Pourquoi next-intl plutôt que next-i18next ? next-intl est conçu pour l'App Router et les composants serveur. next-i18next a été conçu pour le Pages Router et n'offre qu'une prise en charge limitée de l'App Router.
2

Créez la configuration de requête i18n

Créez deux fichiers : src/i18n/request.ts pour le chargement des messages et src/i18n/routing.ts pour la définition des locales. Ils configurent la manière dont next-intl résout les messages et les routes.

src/i18n/routing.ts
// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';

export const routing = defineRouting({
  locales: ['en', 'de', 'ja', 'es'],
  defaultLocale: 'en',
  localePrefix: 'as-needed',  // /about for en, /de/about for de
});

export const { Link, redirect, usePathname, useRouter } =
  createNavigation(routing);
Turbopack (le bundler par défaut de Next.js 15) nécessite experimental.turbo.resolveAlias dans votre next.config.js. Sans cela, vous obtenez des erreurs « Couldn't find next-intl config file ».
3

Configurez le middleware

Ajoutez middleware.ts pour gérer la détection de locale, la réécriture d'URL et les redirections. Le middleware intercepte chaque requête et garantit l'application de la bonne locale.

middleware.ts
// middleware.ts  <- Must be in project ROOT, not src/
import createMiddleware from 'next-intl/middleware';
import { routing } from './src/i18n/routing';

export default createMiddleware(routing);

export const config = {
  matcher: ['/((?!api|_next|.*\\..*).*)'],
};
middleware.ts DOIT se trouver à la racine de votre projet, et non dans src/. C'est l'erreur de configuration la plus fréquente avec next-intl.
4

Mettez en place la structure de dossiers [locale]

Déplacez vos routes d'application dans app/[locale]/. Ajoutez generateStaticParams pour générer les pages de chaque locale au moment de la compilation. Cela crée une structure d'URL du type /en/about, /de/about, etc.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx
import { routing } from '@/i18n/routing';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}
Vous DEVEZ appeler setRequestLocale(locale) dans chaque page.tsx et layout.tsx qui utilise des traductions. Sans cela, Next.js bascule vers un rendu dynamique et les performances de votre build se dégradent considérablement.
5

Mettez à jour votre layout racine

Chargez les messages avec getMessages() et transmettez-les à NextIntlClientProvider dans votre layout racine de locale. Définissez l'attribut lang du html à partir du paramètre locale.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing';
import { notFound } from 'next/navigation';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  const { locale } = await params;
  if (!routing.locales.includes(locale as any)) notFound();

  setRequestLocale(locale);
  const messages = await getMessages();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider locale={locale} messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}
NextIntlClientProvider nécessite une prop locale explicite. L'omettre provoque des erreurs subtiles dans les composants client, difficiles à déboguer.
6

Utiliser les traductions dans les composants

Les composants serveur utilisent getTranslations (async, await). Les composants client utilisent useTranslations (hook). Choisissez en fonction du lieu de rendu de votre composant — les composants serveur excluent entièrement les traductions du bundle JavaScript.

app/[locale]/page.tsx
// Server Component (default)
import { getTranslations, setRequestLocale } from 'next-intl/server';

export default async function AboutPage({
  params,
}: { params: { locale: string } }) {
  const { locale } = await params;
  setRequestLocale(locale);
  const t = await getTranslations('AboutPage');

  return <h1>{t('title')}</h1>;
}

// Client Component ('use client')
'use client';
import { useTranslations } from 'next-intl';

export default function SearchBar() {
  const t = useTranslations('SearchBar');
  return <input placeholder={t('placeholder')} />;
}
Préférez les composants serveur pour le contenu traduit. Ils excluent les chaînes de traduction de votre bundle JavaScript client, ce qui réduit le temps de chargement pour les utilisateurs.
7

Ajoutez le SEO : métadonnées et hreflang

Utilisez generateMetadata pour produire des titres et descriptions de page propres à chaque locale. Ajoutez alternates.languages pour les balises hreflang afin que les moteurs de recherche découvrent toutes les versions linguistiques de chaque page.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx or any page.tsx
import { getTranslations } from 'next-intl/server';
import { routing } from '@/i18n/routing';

export async function generateMetadata({
  params,
}: { params: { locale: string } }) {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: 'Metadata' });

  return {
    title: t('title'),
    description: t('description'),
    alternates: {
      languages: Object.fromEntries(
        routing.locales.map((l) => [l, `/${l}`])
      ),
    },
  };
}
Sur Vercel, les builds peuvent générer localhost comme URL canonique si metadataBase n'est pas défini. Définissez toujours metadataBase dans votre layout racine avec votre domaine de production.
8

Gérez les pages d'erreur et introuvables

error.tsx et not-found.tsx nécessitent un traitement particulier, car ils peuvent s'afficher en dehors du layout de locale normal. Le not-found.tsx racine nécessite sa propre configuration de provider i18n pour afficher des messages d'erreur localisés.

app/[locale]/error.tsx
// app/[locale]/error.tsx
'use client';
import { useTranslations } from 'next-intl';

export default function Error() {
  const t = useTranslations('Error');
  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  );
}

// app/not-found.tsx (root level -- needs own provider)
import { routing } from '@/i18n/routing';

export default async function GlobalNotFound() {
  return (
    <html lang={routing.defaultLocale}>
      <body>
        <h1>404 - Page Not Found</h1>
      </body>
    </html>
  );
}
Next.js n'affiche votre page 404 localisée que lorsque notFound() est appelé explicitement dans votre code. Les routes inconnues sans page correspondante affichent la page 404 par défaut de Next.js, et non votre version localisée.
9

Automatiser les traductions

Une fois votre configuration i18n terminée, traduisez vos fichiers de messages avec l'IA directement depuis votre IDE, ou utilisez le CLI i18n Agent dans votre pipeline CI/CD pour une traduction automatisée à chaque déploiement.

Terminal
# In your IDE, ask your AI assistant:
> Translate messages/en.json to German, Japanese, and Spanish

✓ messages/de.json created (1.1s)
✓ messages/ja.json created (1.4s)
✓ messages/es.json created (1.0s)
Utilisez next-intl-localechain pour des replis de locale intelligents — un utilisateur pt-BR voit les traductions pt-PT au lieu de basculer vers l'anglais lorsque le portugais brésilien n'est pas disponible.

Automatiser la qualité des traductions

Détectez les clés manquantes et les espaces réservés cassés avant leur mise en production avec i18n-validate. Testez votre interface avec de fausses traductions grâce à i18n-pseudo avant l'arrivée des traductions réelles.

Outils open source pour l'i18n Next.js

Ces packages open source résolvent les difficultés courantes des flux de travail d'internationalisation dans Next.js.

next-intl-localechain

La version standard de next-intl revient directement à votre locale par défaut lorsqu'une traduction est manquante. Un utilisateur portugais brésilien voit alors s'afficher l'anglais au lieu d'excellentes traductions en pt-PT. next-intl-localechain ajoute des chaînes de repli intelligentes — il fusionne en profondeur les traductions des locales apparentées afin que les utilisateurs régionaux voient toujours la traduction disponible la plus proche.

src/i18n/request.ts
import { getRequestConfig } from 'next-intl/server';
import { withLocaleChain } from 'next-intl-localechain';

export default getRequestConfig(withLocaleChain({
  loadMessages: (locale) =>
    import(`../../messages/${locale}.json`).then(m => m.default),
  defaultLocale: 'en'
}));
Fusionne automatiquement en profondeur les traductions entre les chaînes de locales
Chaînes intégrées pour le portugais, l'espagnol, le français, l'allemand et bien d'autres langues
Ignore les fichiers de messages manquants sans générer d'erreur
Configuration en une ligne — encapsule votre getRequestConfig existant
Voir sur GitHub

@i18n-agent/cli

Un outil en ligne de commande pour traduire vos fichiers de messages Next.js sans quitter le terminal. Traduisez directement vos fichiers, vérifiez l'état des tâches et téléchargez les résultats. Fonctionne dans les pipelines CI/CD grâce à l'authentification par clé API, pour des flux de localisation entièrement automatisés.

Terminal
# Install the CLI
npm install -g @i18n-agent/cli

# Authenticate
i18nagent login

# Translate your message files
i18nagent translate ./messages/en.json --lang de,ja,es

# Or use in CI/CD with an API key
export I18N_AGENT_API_KEY=your-key-here
i18nagent translate ./messages/en.json --lang de,ja,es
Traduisez des fichiers JSON, YAML, PO et d'autres formats de fichiers i18n depuis le terminal
Prêt pour le CI/CD — authentifiez-vous via une variable d'environnement pour vos pipelines automatisés
Suivez l'état des tâches, relancez les tâches échouées et téléchargez les résultats
Sortie JSON exploitable par machine pour les scripts et l'automatisation
Voir sur GitHub

Pièges courants

« Unable to find next-intl locale »

Le middleware n'a pas correspondu à la requête. Vérifiez : middleware.ts est-il à la racine du projet ? Le motif du matcher exclut-il correctement les fichiers statiques ? La locale est-elle incluse dans votre configuration de routage ?

Rendu dynamique inattendu

setRequestLocale(locale) est absent d'une page ou d'un layout. Sans cela, next-intl utilise les en-têtes/cookies pour détecter la locale, ce qui force un rendu dynamique et empêche la génération statique.

Les routes parallèles cassent avec i18n

Les routes parallèles (@modal) et les routes d'interception ((.)photo) présentent des incompatibilités connues avec le segment dynamique [locale]. Utilisez un routage basé sur le middleware comme solution de contournement pour ces schémas de routage avancés.

Le changement de langue fait perdre la route actuelle

Lors du changement de locale, conservez le chemin d'accès actuel à l'aide de usePathname() et remplacez uniquement le segment de locale — attention aux paramètres de route dynamiques : ils doivent être résolus de nouveau pour la nouvelle locale.

Structure de fichiers recommandée

Project Structure
my-nextjs-app/
├── middleware.ts              # Locale routing (project root!)
├── next.config.mjs
├── messages/
│   ├── en.json                # Source messages
│   ├── de.json
│   └── ja.json
├── src/
│   ├── i18n/
│   │   ├── request.ts         # Message loading config
│   │   └── routing.ts         # Locale definitions
│   └── app/
│       └── [locale]/
│           ├── layout.tsx     # Root locale layout
│           ├── page.tsx       # Home page
│           ├── error.tsx      # Localized error page
│           ├── not-found.tsx  # Localized 404
│           └── about/
│               └── page.tsx
└── package.json

Essayez i18n Agent maintenant

Déposez votre fichier de traduction ici

JSON, YAML, PO, XML, CSV, Markdown, Properties

ou cliquez pour parcourir

Langues cibles

Aucune inscription requiseEstimation instantanée

Repli de locale avec next-intl-localechain

Lorsqu'une clé de traduction est manquante dans une locale régionale comme pt-BR, next-intl passe directement à la locale par défaut au lieu de vérifier d'abord la locale parente pt.

Terminal
npm install next-intl-localechain
Configuration
import { withLocaleChain } from 'next-intl-localechain';

export default withLocaleChain({
  fallbacks: {
    'pt-BR': ['pt', 'en'],
    'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
  },
  defaultLocale: 'en',
  loadMessages: (locale) => import(`./messages/${locale}.json`),
});

Consultez notre guide de repli de locale pour découvrir la liste complète des frameworks pris en charge et les 75 chaînes intégrées. Learn more →

Questions fréquentes