Dans ce guide, nous allons voir comment configurer l'internationalisation de votre application Next.js en utilisant Next-intl sans avoir recours au système de routage i18n intégré. Cette approche est particulièrement utile dans les cas suivants :
- Vous souhaitez fournir un moyen pour les utilisateurs de changer de langue sans changer d'URL
- Votre application ne supporte qu'une seule langue à la fois
Structure du projet
Voici la structure de fichiers que nous allons mettre en place :
├── messages
│ ├── en.json
│ ├── fr.json
│ └── ...
├── next.config.ts
├── src
│ ├── i18n
│ │ ├── config.ts
│ │ ├── request.ts
│ │ └── service
│ │ └── locale.ts
│ └── app
│ ├── layout.tsx
│ └── page.tsx
Étape 1 : Configuration des locales disponibles
Commençons par créer le fichier src/i18n/config.ts
pour définir les langues supportées par notre application :
export type Locale = (typeof locales)[number];
export const locales = ['fr', 'en'] as const;
export const defaultLocale: Locale = 'fr';
Ce fichier définit les langues disponibles dans notre application (français et anglais), avec le français comme langue par défaut.
Étape 2 : Création du service de gestion des locales
Créons ensuite le fichier src/i18n/service/locale.ts
pour gérer la détection et la configuration de la langue :
'use server';
import {cookies} from 'next/headers';
import { defaultLocale, Locale } from '../config';
// Nom du cookie qui stockera la locale choisie par l'utilisateur
const COOKIE_NAME = 'NEXT_LOCALE';
// Function pour récupérer la locale actuelle de l'utilisateur
export async function getUserLocale() {
return (await cookies()).get(COOKIE_NAME)?.value ??
defaultLocale;
}
// Function pour définir la locale de l'utilisateur
export async function setUserLocale(locale: Locale) {
(await cookies()).set(COOKIE_NAME, locale)
}
Ce service utilise les cookies pour stocker et récupérer la langue choisie par l'utilisateur. Si aucune langue n'est définie, il utilise la langue par défaut.
Étape 3 : Configuration des requêtes internationalisées
Créons maintenant le fichier src/i18n/request.ts
qui sera utilisé pour configurer les requêtes avec la bonne locale :
import {getRequestConfig} from 'next-intl/server';
import { getUserLocale } from './service/locale';
export default getRequestConfig(async () => {
const locale = await getUserLocale();
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default,
timeZone: 'Europe/Paris'
};
});
Cette configuration permet de charger dynamiquement les traductions correspondant à la langue de l'utilisateur.
Étape 4 : Configuration du layout principal
Maintenant, configurons le layout principal de notre application (app/layout.tsx
) pour intégrer Next-intl :
import { cn } from "@/src/lib/utils";
import { GeistMono } from "geist/font/mono";
import { GeistSans } from "geist/font/sans";
import type { Metadata } from "next";
import { Space_Grotesk } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/src/components/theme-provider";
import { NextIntlClientProvider } from "next-intl";
import { PropsWithChildren } from "react";
import { LayoutParams } from "@/src/types/next";
import { getLocale, getMessages } from "next-intl/server";
export default async function RootLayout({ children }: PropsWithChildren<LayoutParams>) {
const locale = await getLocale();
const messages = await getMessages();
return (
<>
<html lang={locale} className="h-full" suppressHydrationWarning>
<body
suppressHydrationWarning
className={cn(
"bg-background h-full font-sans antialiased",
GeistMono.variable,
GeistSans.variable,
CaptionFont.variable,
)}
>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
</ThemeProvider>
</body>
</html>
</>
);
}
Ce layout configure l'application pour utiliser Next-intl et applique la langue détectée au niveau de l'attribut lang
de l'élément HTML.
Étape 5 : Création des fichiers de traduction
Créez vos fichiers de traduction dans le dossier messages
. Par exemple :
messages/fr.json
:
{
"title": "Bonjour monde",
"welcome": "Bienvenue sur notre site"
}
messages/en.json
:
{
"title": "Hello world",
"welcome": "Welcome to our website"
}
Étape 6 : Utilisation des traductions dans vos composants
Pour utiliser les traductions dans vos composants, importez les hooks de Next-intl :
'use client';
import { useTranslations } from 'next-intl';
export default function HomePage() {
const t = useTranslations();
return (
<div>
<h1>{t('title')}</h1>
<p>{t('welcome')}</p>
</div>
);
}
Étape 7 : Ajout d'un sélecteur de langue (optionnel)
Vous pouvez ajouter un sélecteur de langue pour permettre aux utilisateurs de changer de langue :
'use client';
import { useTranslations } from 'next-intl';
import { useRouter } from 'next/navigation';
import { setUserLocale } from '@/src/i18n/service/locale';
import { locales } from '@/src/i18n/config';
export default function LanguageSwitcher() {
const t = useTranslations();
const router = useRouter();
const handleLanguageChange = async (locale: string) => {
await setUserLocale(locale as any);
router.refresh();
};
return (
<div>
<select onChange={(e) => handleLanguageChange(e.target.value)}>
{locales.map((locale) => (
<option key={locale} value={locale}>
{t(`languages.${locale}`)}
</option>
))}
</select>
</div>
);
}
Conclusion
Vous avez maintenant configuré avec succès l'internationalisation de votre application Next.js en utilisant Next-intl sans le routage i18n intégré. Cette approche vous permet de:
- Gérer les traductions de manière efficace
- Permettre aux utilisateurs de changer de langue sans changer d'URL
- Détecter automatiquement la langue de l'utilisateur via un cookie
N'oubliez pas d'ajouter de nouvelles traductions au fur et à mesure que votre application évolue. Vous pouvez également créer des dossiers spécifiques pour chaque locale si vous avez besoin d'organiser vos traductions par section ou fonctionnalité.