Internationalisation Next.js avec next-intl — Guide complet i18n pour App Router

AI Bot
Par AI Bot ·

Chargement du lecteur de synthèse vocale...

Construire des applications pour un public mondial demande bien plus que la simple traduction de chaînes de caractères. Vous avez besoin de routage basé sur la locale, de support pour les mises en page de droite à gauche (RTL), de règles de pluralisation, de formatage des dates et nombres, et une expérience développeur qui évolue avec votre application. next-intl est devenu la solution de référence pour l'internationalisation dans les applications Next.js App Router, offrant des traductions type-safe, le support des Server Components et une intégration transparente avec les React Server Components.

Dans ce guide, vous construirez une application Next.js entièrement internationalisée supportant l'anglais, l'arabe (RTL) et le français — de la configuration du projet aux patterns de déploiement en production.

Prérequis

Avant de commencer, assurez-vous d'avoir :

  • Node.js 20+ installé
  • Connaissance de base de Next.js App Router (layouts, pages, server components)
  • Familiarité avec TypeScript
  • Un éditeur de code comme VS Code avec l'extension i18n Ally (recommandé)

Ce que vous allez construire

Une application Next.js multilingue comprenant :

  • Routage basé sur la locale (/en/about, /ar/about, /fr/about)
  • Détection automatique de la locale et redirection
  • Support de mise en page RTL pour l'arabe
  • Messages de traduction type-safe
  • Contenu dynamique avec interpolation et pluralisation
  • Formatage des dates et nombres selon la locale
  • Un composant de changement de langue
  • SEO optimisé avec les balises hreflang appropriées

Étape 1 : Créer un nouveau projet Next.js

Commencez par créer une nouvelle application Next.js :

npx create-next-app@latest my-i18n-app --typescript --tailwind --eslint --app --src-dir
cd my-i18n-app

Installez next-intl :

npm install next-intl

La structure de votre projet devrait ressembler à ceci :

my-i18n-app/
├── src/
│   ├── app/
│   │   ├── layout.tsx
│   │   └── page.tsx
│   └── ...
├── package.json
└── tsconfig.json

Étape 2 : Définir la configuration d'internationalisation

Créez le fichier de configuration qui définit vos locales supportées et la locale par défaut.

Créez src/i18n/config.ts :

export const locales = ["en", "ar", "fr"] as const;
export type Locale = (typeof locales)[number];
 
export const defaultLocale: Locale = "en";
 
export const localeNames: Record<Locale, string> = {
  en: "English",
  ar: "العربية",
  fr: "Français",
};
 
// Locales utilisant la direction de texte de droite à gauche
export const rtlLocales: Locale[] = ["ar"];
 
export function isRtlLocale(locale: Locale): boolean {
  return rtlLocales.includes(locale);
}

Étape 3 : Créer les fichiers de messages de traduction

Créez un répertoire messages à la racine de votre projet avec un fichier JSON pour chaque locale.

messages/en.json :

{
  "Metadata": {
    "title": "My International App",
    "description": "A fully internationalized Next.js application"
  },
  "Navigation": {
    "home": "Home",
    "about": "About",
    "contact": "Contact",
    "blog": "Blog"
  },
  "HomePage": {
    "title": "Welcome to Our Platform",
    "subtitle": "Build global applications with ease",
    "cta": "Get Started",
    "features": {
      "title": "Why Choose Us",
      "speed": "Lightning Fast",
      "speedDescription": "Optimized for performance across all regions",
      "i18n": "Built for Global",
      "i18nDescription": "Native support for {count, plural, =1 {# language} other {# languages}}",
      "secure": "Enterprise Security",
      "secureDescription": "Bank-grade encryption and compliance"
    },
    "stats": {
      "users": "{count, number} active users",
      "countries": "Available in {count, number} countries",
      "uptime": "{value}% uptime"
    }
  },
  "Common": {
    "loading": "Loading...",
    "error": "Something went wrong",
    "retry": "Try Again",
    "back": "Go Back",
    "lastUpdated": "Last updated: {date, date, medium}"
  }
}

messages/ar.json :

{
  "Metadata": {
    "title": "تطبيقي الدولي",
    "description": "تطبيق Next.js متعدد اللغات بالكامل"
  },
  "Navigation": {
    "home": "الرئيسية",
    "about": "من نحن",
    "contact": "اتصل بنا",
    "blog": "المدونة"
  },
  "HomePage": {
    "title": "مرحباً بكم في منصتنا",
    "subtitle": "بناء تطبيقات عالمية بسهولة",
    "cta": "ابدأ الآن",
    "features": {
      "title": "لماذا تختارنا",
      "speed": "سرعة فائقة",
      "speedDescription": "محسّن للأداء في جميع المناطق",
      "i18n": "مصمم للعالمية",
      "i18nDescription": "{count, plural, =1 {لغة واحدة} two {لغتان} few {# لغات} many {# لغة} other {# لغة}}",
      "secure": "أمان مؤسسي",
      "secureDescription": "تشفير بمستوى البنوك والامتثال"
    },
    "stats": {
      "users": "{count, number} مستخدم نشط",
      "countries": "متاح في {count, number} دولة",
      "uptime": "{value}٪ وقت التشغيل"
    }
  },
  "Common": {
    "loading": "جارٍ التحميل...",
    "error": "حدث خطأ ما",
    "retry": "حاول مرة أخرى",
    "back": "العودة",
    "lastUpdated": "آخر تحديث: {date, date, medium}"
  }
}

messages/fr.json :

{
  "Metadata": {
    "title": "Mon Application Internationale",
    "description": "Une application Next.js entièrement internationalisée"
  },
  "Navigation": {
    "home": "Accueil",
    "about": "À propos",
    "contact": "Contact",
    "blog": "Blog"
  },
  "HomePage": {
    "title": "Bienvenue sur Notre Plateforme",
    "subtitle": "Créez des applications mondiales facilement",
    "cta": "Commencer",
    "features": {
      "title": "Pourquoi Nous Choisir",
      "speed": "Ultra Rapide",
      "speedDescription": "Optimisé pour la performance dans toutes les régions",
      "i18n": "Conçu pour le Monde",
      "i18nDescription": "{count, plural, =1 {# langue} other {# langues}} prises en charge nativement",
      "secure": "Sécurité Entreprise",
      "secureDescription": "Chiffrement de niveau bancaire et conformité"
    },
    "stats": {
      "users": "{count, number} utilisateurs actifs",
      "countries": "Disponible dans {count, number} pays",
      "uptime": "{value} % de disponibilité"
    }
  },
  "Common": {
    "loading": "Chargement...",
    "error": "Une erreur est survenue",
    "retry": "Réessayer",
    "back": "Retour",
    "lastUpdated": "Dernière mise à jour : {date, date, medium}"
  }
}

Remarquez comment les traductions arabes utilisent les règles de pluralisation ICU avec les catégories spécifiques à l'arabe (two, few, many), que next-intl gère automatiquement via le standard ICU MessageFormat.

Étape 4 : Configurer la résolution des requêtes next-intl

Créez src/i18n/request.ts — c'est la configuration centrale que next-intl utilise pour résoudre les messages à chaque requête :

import { getRequestConfig } from "next-intl/server";
import { locales, type Locale } from "./config";
 
export default getRequestConfig(async ({ requestLocale }) => {
  // Valider que la locale entrante est supportée
  let locale = await requestLocale;
 
  if (!locale || !locales.includes(locale as Locale)) {
    locale = "en";
  }
 
  return {
    locale,
    messages: (await import(`../../../messages/${locale}.json`)).default,
    timeZone: "UTC",
    now: new Date(),
  };
});

Étape 5 : Configurer Next.js avec le plugin next-intl

Mettez à jour votre next.config.ts pour inclure le plugin next-intl :

import createNextIntlPlugin from "next-intl/plugin";
 
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
 
const nextConfig = {
  // votre configuration Next.js existante
};
 
export default withNextIntl(nextConfig);

Étape 6 : Mettre en place le routage basé sur la locale

Restructurez votre répertoire app pour utiliser un segment dynamique [locale]. C'est le fondement du routage basé sur la locale.

src/app/
├── [locale]/
│   ├── layout.tsx        # Layout racine avec locale
│   ├── page.tsx           # Page d'accueil
│   ├── about/
│   │   └── page.tsx       # Page À propos
│   └── contact/
│       └── page.tsx       # Page Contact
├── layout.tsx             # Layout racine minimal (sans locale)
└── not-found.tsx          # 404 global

Créez le layout racine src/app/layout.tsx (minimal — passe simplement les enfants) :

import { ReactNode } from "react";
 
type Props = {
  children: ReactNode;
};
 
export default function RootLayout({ children }: Props) {
  return children;
}

Maintenant créez src/app/[locale]/layout.tsx — c'est ici que réside la vraie logique de mise en page :

import { ReactNode } from "react";
import { notFound } from "next/navigation";
import { NextIntlClientProvider } from "next-intl";
import { getMessages, setRequestLocale } from "next-intl/server";
import { locales, type Locale, isRtlLocale } from "@/i18n/config";
import "./globals.css";
 
type Props = {
  children: ReactNode;
  params: Promise<{ locale: string }>;
};
 
export function generateStaticParams() {
  return locales.map((locale) => ({ locale }));
}
 
export default async function LocaleLayout({ children, params }: Props) {
  const { locale } = await params;
 
  // Valider la locale
  if (!locales.includes(locale as Locale)) {
    notFound();
  }
 
  // Activer le rendu statique
  setRequestLocale(locale);
 
  // Obtenir tous les messages pour la locale courante
  const messages = await getMessages();
 
  const dir = isRtlLocale(locale as Locale) ? "rtl" : "ltr";
 
  return (
    <html lang={locale} dir={dir}>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}

Points clés à noter :

  • generateStaticParams active la génération statique pour toutes les locales
  • setRequestLocale opte pour le rendu statique (requis pour la génération statique)
  • NextIntlClientProvider rend les traductions accessibles aux composants client
  • L'attribut dir est défini dynamiquement — rtl pour l'arabe, ltr pour les autres

Étape 7 : Créer le Middleware de détection de locale

Créez src/middleware.ts à la racine des sources :

import createMiddleware from "next-intl/middleware";
import { locales, defaultLocale } from "./i18n/config";
 
export default createMiddleware({
  locales,
  defaultLocale,
  // Rediriger vers les chemins préfixés par la locale
  localePrefix: "always",
  // Détecter la locale depuis l'en-tête Accept-Language
  localeDetection: true,
});
 
export const config = {
  // Correspondre à tous les chemins sauf API, fichiers statiques, etc.
  matcher: ["/((?!api|_next|_vercel|.*\\..*).*)"],
};

Avec ce middleware :

  • Visiter / redirige vers /en (ou la locale détectée)
  • Visiter /about redirige vers /en/about
  • Visiter /ar/about sert directement la version arabe
  • L'en-tête Accept-Language est utilisé pour les nouveaux visiteurs

Étape 8 : Construire la page d'accueil avec les traductions

Créez src/app/[locale]/page.tsx :

import { useTranslations } from "next-intl";
import { setRequestLocale } from "next-intl/server";
 
type Props = {
  params: Promise<{ locale: string }>;
};
 
export default async function HomePage({ params }: Props) {
  const { locale } = await params;
  setRequestLocale(locale);
 
  return <HomeContent />;
}
 
function HomeContent() {
  const t = useTranslations("HomePage");
 
  return (
    <main className="min-h-screen">
      {/* Section Hero */}
      <section className="flex flex-col items-center justify-center px-4 py-24 text-center">
        <h1 className="mb-4 text-5xl font-bold tracking-tight">
          {t("title")}
        </h1>
        <p className="mb-8 max-w-2xl text-xl text-gray-600">
          {t("subtitle")}
        </p>
        <button className="rounded-lg bg-blue-600 px-8 py-3 text-lg font-semibold text-white transition hover:bg-blue-700">
          {t("cta")}
        </button>
      </section>
 
      {/* Section Fonctionnalités */}
      <section className="mx-auto max-w-6xl px-4 py-16">
        <h2 className="mb-12 text-center text-3xl font-bold">
          {t("features.title")}
        </h2>
        <div className="grid gap-8 md:grid-cols-3">
          <FeatureCard
            title={t("features.speed")}
            description={t("features.speedDescription")}
          />
          <FeatureCard
            title={t("features.i18n")}
            description={t("features.i18nDescription", { count: 3 })}
          />
          <FeatureCard
            title={t("features.secure")}
            description={t("features.secureDescription")}
          />
        </div>
      </section>
 
      {/* Section Statistiques */}
      <section className="bg-gray-50 px-4 py-16 dark:bg-gray-900">
        <div className="mx-auto grid max-w-4xl gap-8 text-center md:grid-cols-3">
          <div>
            <p className="text-4xl font-bold text-blue-600">
              {t("stats.users", { count: 50000 })}
            </p>
          </div>
          <div>
            <p className="text-4xl font-bold text-blue-600">
              {t("stats.countries", { count: 120 })}
            </p>
          </div>
          <div>
            <p className="text-4xl font-bold text-blue-600">
              {t("stats.uptime", { value: 99.9 })}
            </p>
          </div>
        </div>
      </section>
    </main>
  );
}
 
function FeatureCard({
  title,
  description,
}: {
  title: string;
  description: string;
}) {
  return (
    <div className="rounded-xl border p-6 transition hover:shadow-lg">
      <h3 className="mb-2 text-xl font-semibold">{title}</h3>
      <p className="text-gray-600">{description}</p>
    </div>
  );
}

Remarquez comment useTranslations fonctionne dans les composants serveur — pas besoin de la directive "use client". La fonction t() supporte nativement le format ICU MessageFormat pour la pluralisation et le formatage des nombres.

Étape 9 : Construire un composant de changement de langue

Créez src/components/LanguageSwitcher.tsx :

"use client";
 
import { useLocale, useTranslations } from "next-intl";
import { useRouter, usePathname } from "next/navigation";
import { locales, localeNames, type Locale } from "@/i18n/config";
import { useTransition } from "react";
 
export default function LanguageSwitcher() {
  const locale = useLocale();
  const router = useRouter();
  const pathname = usePathname();
  const t = useTranslations("LanguageSwitcher");
  const [isPending, startTransition] = useTransition();
 
  function handleLocaleChange(newLocale: string) {
    // Remplacer le segment de locale actuel dans le chemin
    const segments = pathname.split("/");
    segments[1] = newLocale;
    const newPathname = segments.join("/");
 
    startTransition(() => {
      router.replace(newPathname);
    });
  }
 
  return (
    <div className="relative">
      <label htmlFor="locale-select" className="sr-only">
        {t("label")}
      </label>
      <select
        id="locale-select"
        value={locale}
        onChange={(e) => handleLocaleChange(e.target.value)}
        disabled={isPending}
        className="appearance-none rounded-lg border bg-white px-4 py-2 text-sm font-medium shadow-sm transition hover:border-blue-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 disabled:opacity-50 dark:bg-gray-800 rtl:text-right"
        aria-label={t("current", { language: localeNames[locale as Locale] })}
      >
        {locales.map((loc) => (
          <option key={loc} value={loc}>
            {localeNames[loc]}
          </option>
        ))}
      </select>
      {isPending && (
        <span className="absolute end-2 top-1/2 -translate-y-1/2">
          <span className="inline-block h-4 w-4 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" />
        </span>
      )}
    </div>
  );
}

Ce composant :

  • Utilise useTransition pour un changement de locale fluide sans bloquer l'interface
  • Remplace le segment de locale dans le chemin URL
  • Affiche un spinner de chargement pendant la transition
  • Utilise rtl:text-right pour un alignement RTL correct
  • Est entièrement accessible avec les labels ARIA appropriés

Étape 10 : Gérer les mises en page RTL avec Tailwind CSS

Tailwind CSS v3.3+ inclut un support RTL natif via les variantes rtl: et ltr:. Puisque nous définissons l'attribut dir dans le layout, ces variantes fonctionnent automatiquement.

Voici les patterns clés pour des mises en page RTL :

{/* Utiliser les propriétés logiques au lieu des physiques */}
{/* Au lieu de ml-4 / mr-4, utiliser ms-4 / me-4 */}
<div className="ms-4">Marge au début (gauche en LTR, droite en RTL)</div>
<div className="me-4">Marge à la fin (droite en LTR, gauche en RTL)</div>
 
{/* Au lieu de pl-4 / pr-4, utiliser ps-4 / pe-4 */}
<div className="ps-6 pe-2">Padding début et fin</div>
 
{/* Au lieu de left-0 / right-0, utiliser start-0 / end-0 */}
<div className="absolute start-0">Positionné au début</div>
 
{/* Pour les icônes directionnelles qui doivent être inversées */}
<svg className="rtl:rotate-180">→</svg>
 
{/* Alignement du texte */}
<p className="text-start">Aligné au début de la direction du texte</p>
 
{/* Flexbox et Grid - automatiquement RTL-aware */}
<div className="flex gap-4">Les éléments circulent correctement dans les deux directions</div>

La règle la plus importante : utilisez les propriétés logiques (start/end) au lieu des physiques (left/right). Ce seul changement résout 90% des problèmes de mise en page RTL.

Étape 11 : Ajouter la sécurité de type aux traductions

L'une des fonctionnalités les plus puissantes de next-intl est la sécurité de type des traductions. Créez un fichier de déclaration de type pour obtenir l'autocomplétion et les vérifications à la compilation.

Créez src/i18n/types.ts :

import en from "../../messages/en.json";
 
// Utiliser les messages anglais comme source de vérité pour les types
type Messages = typeof en;
 
declare global {
  interface IntlMessages extends Messages {}
}

Maintenant quand vous utilisez t("HomePage.features.speed"), TypeScript va :

  • Autocomplete les clés de messages disponibles
  • Afficher une erreur si vous référencez une clé inexistante
  • Valider les paramètres d'interpolation

Étape 12 : Formater les dates, nombres et temps relatifs

next-intl fournit des utilitaires de formatage sensibles à la locale qui exploitent l'API Intl.

import { useFormatter, useNow, useTranslations } from "next-intl";
 
function StatsSection() {
  const format = useFormatter();
  const now = useNow();
  const t = useTranslations("Common");
 
  // Formatage des nombres
  const revenue = format.number(1234567.89, {
    style: "currency",
    currency: "USD",
  });
  // en: "$1,234,567.89" | ar: "١٬٢٣٤٬٥٦٧٫٨٩ US$" | fr: "1 234 567,89 $US"
 
  // Formatage des dates
  const date = format.dateTime(new Date("2026-03-18"), {
    year: "numeric",
    month: "long",
    day: "numeric",
  });
  // en: "March 18, 2026" | ar: "١٨ مارس ٢٠٢٦" | fr: "18 mars 2026"
 
  // Temps relatif
  const lastWeek = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
  const relative = format.relativeTime(lastWeek);
  // en: "7 days ago" | ar: "قبل ٧ أيام" | fr: "il y a 7 jours"
 
  return (
    <div>
      <p>{revenue}</p>
      <p>{date}</p>
      <p>{relative}</p>
      <p>{t("lastUpdated", { date: new Date() })}</p>
    </div>
  );
}

Étape 13 : Gérer le contenu dynamique et le texte enrichi

next-intl supporte le formatage de texte enrichi, vous permettant d'intégrer des composants dans les chaînes traduites.

Dans vos fichiers de messages :

{
  "RichText": {
    "welcome": "Bienvenue sur <bold>notre plateforme</bold>. Lisez nos <link>conditions d'utilisation</link>.",
    "highlight": "Cette fonctionnalité est <highlight>nouvelle</highlight> et disponible pour les utilisateurs <badge>Pro</badge>."
  }
}

Dans votre composant :

import { useTranslations } from "next-intl";
 
function WelcomeMessage() {
  const t = useTranslations("RichText");
 
  return (
    <p>
      {t.rich("welcome", {
        bold: (chunks) => <strong>{chunks}</strong>,
        link: (chunks) => (
          <a href="/terms" className="text-blue-600 underline">
            {chunks}
          </a>
        ),
      })}
    </p>
  );
}

Cette approche garde vos fichiers de traduction propres tout en permettant aux traducteurs de contrôler l'ordre des mots — essentiel pour des langues comme l'arabe où la structure des phrases diffère significativement du français.

Étape 14 : Ajouter le SEO avec des métadonnées sensibles à la locale

Créez des métadonnées appropriées pour chaque locale, incluant les liens alternatifs hreflang.

Mettez à jour src/app/[locale]/layout.tsx :

import { getTranslations } from "next-intl/server";
import { locales } from "@/i18n/config";
import type { Metadata } from "next";
 
type Props = {
  params: Promise<{ locale: string }>;
};
 
export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: "Metadata" });
 
  // Générer les liens alternatifs pour toutes les locales
  const languages: Record<string, string> = {};
  for (const loc of locales) {
    languages[loc] = `https://example.com/${loc}`;
  }
 
  return {
    title: {
      default: t("title"),
      template: `%s | ${t("title")}`,
    },
    description: t("description"),
    alternates: {
      languages,
    },
    openGraph: {
      title: t("title"),
      description: t("description"),
      locale: locale,
      alternateLocale: locales.filter((l) => l !== locale),
    },
  };
}

Étape 15 : Tester votre implémentation i18n

Lancez votre serveur de développement et vérifiez que tout fonctionne :

npm run dev

Testez ces scénarios :

  1. Redirection par défaut : Visitez http://localhost:3000 — vous devriez être redirigé vers /en
  2. Changement de langue : Utilisez le sélecteur pour basculer entre anglais, arabe et français
  3. Mise en page RTL : Passez en arabe et vérifiez que la mise en page se reflète correctement
  4. Accès direct par URL : Visitez http://localhost:3000/ar directement
  5. Interpolation des traductions : Vérifiez que les nombres, dates et pluriels s'affichent correctement
  6. Gestion 404 : Visitez http://localhost:3000/de (locale non supportée)

Étape 16 : Conseils d'optimisation pour la production

Activer le rendu statique

Pour les meilleures performances, activez la génération statique pour toutes vos pages localisées. Ajoutez setRequestLocale en haut de chaque page et layout qui utilise des traductions :

import { setRequestLocale } from "next-intl/server";
 
export default async function Page({ params }: Props) {
  const { locale } = await params;
  setRequestLocale(locale);
 
  // ... le reste du composant
}

Découpage des messages

Pour les grandes applications, évitez de charger toutes les traductions sur chaque page. Découpez les messages par namespace pour optimiser la taille du bundle côté client.

Analyse du bundle

Vérifiez que vos bundles de traduction ne gonflent pas votre JavaScript côté client :

npx @next/bundle-analyzer

Les composants serveur utilisant useTranslations n'ajoutent pas de traductions au bundle client — seuls les composants avec "use client" qui utilisent NextIntlClientProvider incluent les traductions dans le bundle client.

Dépannage

Problème courant : "Unable to find next-intl locale"

Cela signifie généralement que le middleware ne correspond pas à vos routes. Vérifiez :

  1. Le pattern matcher dans middleware.ts est correct
  2. Le fichier middleware est à src/middleware.ts (pas dans app/)
  3. Vous avez redémarré le serveur de développement après avoir ajouté le middleware

Problème courant : Désynchronisation d'hydratation avec RTL

Si vous voyez des avertissements d'hydratation lors du basculement entre LTR et RTL :

  1. Assurez-vous que dir et lang sont définis sur l'élément html dans le layout serveur
  2. Ajoutez suppressHydrationWarning à la balise html si vous utilisez un provider de thème

Prochaines étapes

Maintenant que vous avez une base i18n solide, envisagez :

  • Ajouter plus de locales — créez simplement un nouveau fichier de messages et ajoutez la locale à votre configuration
  • Mettre en place un système de gestion des traductions comme Crowdin ou Lokalise pour les workflows de traduction en équipe
  • Implémenter du contenu spécifique à la locale — images, vidéos ou mises en page différentes par locale
  • Ajouter une recherche sensible à la locale avec une analyse textuelle appropriée par langue

Conclusion

Vous avez construit une application Next.js internationalisée prête pour la production avec next-intl qui supporte :

  • Des traductions type-safe avec autocomplétion
  • Un routage basé sur la locale avec détection automatique
  • Le support de mise en page RTL pour l'arabe avec les propriétés logiques Tailwind CSS
  • Le format ICU MessageFormat pour la pluralisation et le formatage
  • Des métadonnées SEO optimisées avec les balises hreflang
  • Une expérience fluide de changement de langue

La combinaison de Next.js App Router et next-intl offre l'une des meilleures expériences développeur pour construire des applications multilingues. L'approche server-first signifie que les traductions ne gonflent pas votre bundle client, et le support du format ICU MessageFormat gère les nuances des différentes langues — des règles de pluralisation arabes au formatage des nombres français — sans aucune logique personnalisée.

Que vous construisiez pour la région MENA, les marchés européens ou un public véritablement mondial, cette fondation évolue avec votre application et maintient votre workflow de traduction gérable à mesure que votre contenu grandit.


Vous voulez lire plus de tutoriels? Découvrez notre dernier tutoriel sur Introduction à la biologie végétale.

Discutez de votre projet avec nous

Nous sommes ici pour vous aider avec vos besoins en développement Web. Planifiez un appel pour discuter de votre projet et comment nous pouvons vous aider.

Trouvons les meilleures solutions pour vos besoins.

Articles connexes

Construire une application full-stack en temps réel avec Convex et Next.js 15

Apprenez à construire une application full-stack en temps réel avec Convex et Next.js 15. Ce tutoriel couvre la conception de schémas, les requêtes, les mutations, les abonnements en temps réel, l'authentification et le téléchargement de fichiers — le tout avec une sécurité de types de bout en bout.

30 min read·

Construire un Chatbot IA Local avec Ollama et Next.js : Guide Complet

Construisez un chatbot IA privé fonctionnant entièrement sur votre machine locale avec Ollama et Next.js. Ce tutoriel pratique couvre l'installation, le streaming des réponses, la sélection de modèles et le déploiement d'une interface de chat prête pour la production — le tout sans envoyer de données dans le cloud.

25 min read·