Intégrer next-intl pour l’internationalisation dans Next.js 15 : Guide Complet
Tutoriel étape par étape pour intégrer next-intl pour la traduction dans un projet Next.js 15.

La traduction (i18n) est essentielle pour les applications web modernes. Avec Next.js 15, la méthode recommandée pour ajouter la traduction est d'utiliser next-intl. Dans ce guide, vous apprendrez à configurer next-intl dans un projet Next.js 15 de manière pratique et efficace.
🚀 Vous cherchez un template Next.js avec next-intl déjà intégré ?
Si vous voulez éviter la configuration et commencer avec un template prêt pour la production qui inclut déjà l'internationalisation next-intl, découvrez notre Template Dashboard Financier Next.js.
🎯 Ce template premium inclut :
- ✅ next-intl déjà configuré et prêt à utiliser
- ✅ Basculement thème sombre/clair
- ✅ Gestion d'état Redux Toolkit
- ✅ Interface de dashboard financier moderne
- ✅ Authentification par email
- ✅ Design responsive
- ✅ Support TypeScript
Parfait pour les applications fintech, tableaux de bord bancaires et systèmes de gestion financière.
Voir la démo | Obtenir le template
1. Installer next-intl
Commencez par installer le package :
npm install next-intl2. Configurer le routage
Créez une configuration de routage pour définir vos langues supportées. Par exemple, dans src/i18n/routing.ts :
1// src/i18n/routing.ts
2import {defineRouting} from 'next-intl/routing';
3
4export const routing = defineRouting({
5 locales: ['en', 'fr', 'ar', 'es'],
6 defaultLocale: 'en'
7});3. Ajouter les helpers de navigation
Configurez les helpers de navigation dans src/i18n/navigation.ts :
// src/i18n/navigation.ts
import { createNavigation } from 'next-intl/navigation';
import { routing } from './routing';
export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing);4. Charger les messages côté serveur
Configurez le chargement des messages dans src/i18n/request.ts :
1// src/i18n/request.ts
2import { getRequestConfig } from 'next-intl/server';
3import { hasLocale } from 'next-intl';
4import { routing } from './routing';
5
6export default getRequestConfig(async ({ requestLocale }) => {
7 const requested = await requestLocale;
8 const locale = hasLocale(routing.locales, requested)
9 ? requested
10 : routing.defaultLocale;
11
12 const [seoMessages] = await Promise.all([
13 import(`../messages/seo/${locale}.json`).then(module => module.default).catch(() => ({})),
14 ]);
15
16 return {
17 locale,
18 messages: {
19 seo: seoMessages,
20 }
21 };
22});5. Fournir les messages à votre application
Encapsulez vos pages avec NextIntlClientProvider. Par exemple, dans src/app/[locale]/about/layout.tsx :
1// src/app/[locale]/about/layout.tsx
2import { NextIntlClientProvider } from "next-intl";
3
4export default async function AboutLayout({
5 children,
6 params,
7}: {
8 children: React.ReactNode;
9 params: Promise<{ locale: string }>;
10}) {
11 const { locale } = await params;
12
13 const [about] = await Promise.all([
14 import(`@/messages/about/${locale}.json`).then((mod) => mod.default),
15 ]);
16
17 const messages = { about };
18 return (
19 <NextIntlClientProvider locale={locale} messages={messages}>
20 {children}
21 </NextIntlClientProvider>
22 );
23}6. Organiser vos fichiers de messages
Stockez vos fichiers de traduction dans src/messages/, par exemple :
src/messages/about/en.json
src/messages/about/fr.json
src/messages/about/ar.json
src/messages/about/es.jsonChaque fichier contient les traductions pour un namespace, par exemple :
{
"header_story": "Notre histoire",
"header_title1": "Nous construisons"
// ...
}7. Utiliser les traductions dans les composants
Utilisez le hook useTranslations de next-intl :
1import { useTranslations } from "next-intl";
2
3export default function AboutHeader() {
4 const t = useTranslations("about");
5 return <h1>{t("header_title1")}</h1>;
6}8. Ajouter un sélecteur de langue
Voici le code complet du composant LanguageSelector :
1// src/components/LanguageSelector/index.tsx
2"use client";
3
4import React, { useState, useRef, useEffect } from "react";
5import { useParams, useRouter } from "next/navigation";
6import { cn } from "@/lib/utils";
7import { IconLanguage, IconChevronDown } from "@/lib/icons";
8
9interface Language {
10 code: string;
11 name: string;
12 rtl: boolean;
13}
14
15const languages: Language[] = [
16 { code: "en", name: "English", rtl: false },
17 { code: "fr", name: "Français", rtl: false },
18 { code: "es", name: "Español", rtl: false },
19 { code: "ar", name: "العربية", rtl: true },
20];
21
22export default function LanguageSelector() {
23 const [isOpen, setIsOpen] = useState(false);
24 const dropdownRef = useRef<HTMLDivElement>(null);
25 const router = useRouter();
26 const params = useParams();
27 const currentLocale = typeof params.locale === "string" ? params.locale : "en";
28
29 const currentLanguage = languages.find((lang) => lang.code === currentLocale) || languages[0];
30
31 useEffect(() => {
32 const handleClickOutside = (event: MouseEvent) => {
33 if (
34 dropdownRef.current &&
35 !dropdownRef.current.contains(event.target as Node)
36 ) {
37 setIsOpen(false);
38 }
39 };
40
41 document.addEventListener("mousedown", handleClickOutside);
42 return () => {
43 document.removeEventListener("mousedown", handleClickOutside);
44 };
45 }, []);
46
47 const changeLanguage = (langCode: string) => {
48 const currentPath = window.location.pathname;
49 const pathSegments = currentPath.split('/');
50 pathSegments[1] = langCode;
51 const newPath = pathSegments.join('/');
52 router.push(newPath);
53 setIsOpen(false);
54 };
55
56 return (
57 <div className="relative" ref={dropdownRef}>
58 <button
59 onClick={() => setIsOpen(!isOpen)}
60 className="flex items-center cursor-pointer px-2 py-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 text-sm"
61 aria-expanded={isOpen}
62 aria-haspopup="true"
63 >
64 <IconLanguage className="w-4 h-4 mr-1" />
65 <span className="font-medium text-xs mr-1">{currentLanguage.code.toUpperCase()}</span>
66 <IconChevronDown className={cn("w-3 h-3 transition-transform", isOpen ? "rotate-180" : "")} />
67 </button>
68
69 {isOpen && (
70 <div className="absolute z-50 mt-1 bg-white dark:bg-neutral-900 border border-gray-200 dark:border-gray-700 rounded-md shadow-lg py-1 w-40 min-w-max right-0">
71 <ul className="py-1">
72 {languages.map((language) => (
73 <li key={language.code}>
74 <button
75 onClick={() => changeLanguage(language.code)}
76 className={cn(
77 "w-full text-left cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-800 flex items-center",
78 language.code === currentLocale && "bg-gray-100 dark:bg-gray-800"
79 )}
80 >
81 <span className="inline-block me-2 w-max font-medium text-xs">{language.code.toUpperCase()}</span>
82 {language.name}
83 </button>
84 </li>
85 ))}
86 </ul>
87 </div>
88 )}
89 </div>
90 );
91}9. Tester votre configuration
Démarrez votre serveur de développement et visitez /en/about, /fr/about, etc. Vous devriez voir les bonnes traductions et pouvoir changer de langue.
Conclusion
Avec next-intl, ajouter la traduction à Next.js 15 est simple et puissant.
Références :
Cet article vous a été utile?
Vous pourriez aussi aimer

Top 10 des meilleurs templates Next.js Admin Dashboard - 2025

Publino : Le template Next.js ultime pour les startups modernes
