Chargement des traductions
Utilisation d'un provider pour gérer les messages
Problème
Coder en dur du texte, comme 'Hello World', directement dans les composants d'une application couple le contenu avec le code. Pour afficher une langue différente, les développeurs doivent dupliquer le composant ou ajouter une logique if/else, rendant la traduction non évolutive et nécessitant une modification complète du code pour chaque nouveau texte.
Solution
Utilisez le IntlProvider de react-intl pour fournir les traductions. Chargez les messages de traduction sur le serveur dans le layout racine, transmettez-les à un composant provider côté client, puis consommez-les dans d'autres composants clients en utilisant le hook useIntl.
Étapes
1. Installer react-intl
Tout d'abord, ajoutez react-intl comme dépendance à votre projet.
npm install react-intl
2. Créer des fichiers de traduction plats
Créez un dossier dictionaries. À l'intérieur, ajoutez un fichier JSON pour chaque langue. react-intl fonctionne mieux avec une structure clé-valeur plate.
// dictionaries/en.json
{
"home.title": "Home Page",
"home.welcome": "Hello, welcome to our site!",
"about.title": "About Us"
}
// dictionaries/es.json
{
"home.title": "Página de Inicio",
"home.welcome": "¡Hola, bienvenido a nuestro sitio!",
"about.title": "Sobre Nosotros"
}
3. Créer une fonction pour charger les dictionnaires
Créez une fonction helper pour charger le fichier de dictionnaire correct sur le serveur en fonction du paramètre lang.
// app/get-dictionary.ts
import 'server-only';
// Define the type for our flat message object
type Messages = Record<string, string>;
const dictionaries: { [key: string]: () => Promise<Messages> } = {
en: () => import('@/dictionaries/en.json').then((module) => module.default),
es: () => import('@/dictionaries/es.json').then((module) => module.default),
// fr: () => import('@/dictionaries/fr.json').then((module) => module.default),
};
export const getDictionary = async (lang: string) => {
const load = dictionaries[lang];
if (load) {
return load();
}
// Fallback to English
return dictionaries.en();
};
4. Créer un provider côté client
IntlProvider est un composant client qui utilise le Context de React. Nous devons créer un wrapper pour celui-ci qui peut accepter les messages chargés depuis le serveur.
// app/components/IntlClientProvider.tsx
'use client';
import { IntlProvider } from 'react-intl';
type Props = {
children: React.ReactNode;
locale: string;
messages: Record<string, string>; // Flat messages object
};
export default function IntlClientProvider({
children,
locale,
messages,
}: Props) {
return (
<IntlProvider messages={messages} locale={locale} defaultLocale="en">
{children}
</IntlProvider>
);
}
5. Mettre à jour le layout racine
Modifiez votre app/[lang]/layout.tsx pour en faire un composant async. Il chargera les messages et les transmettra au IntlClientProvider.
// app/[lang]/layout.tsx
import { getDictionary } from '@/app/get-dictionary';
import IntlClientProvider from '@/app/components/IntlClientProvider';
export async function generateStaticParams() {
return [{ lang: 'en' }, { lang: 'es' }];
}
export default async function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: { lang: string };
}) {
// Load messages on the server
const messages = await getDictionary(params.lang);
return (
<html lang={params.lang}>
<body>
{/* Pass messages to the client provider */}
<IntlClientProvider locale={params.lang} messages={messages}>
{children}
</IntlClientProvider>
</body>
</html>
);
}
6. Utiliser les traductions dans un composant client
Vous pouvez maintenant utiliser le hook useIntl dans n'importe quel composant client. Les composants serveur ne peuvent pas utiliser ce hook.
Créez un nouveau composant client pour afficher le texte traduit :
// app/components/HomePageContent.tsx
'use client';
import { useIntl } from 'react-intl';
export default function HomePageContent() {
const intl = useIntl();
return (
<div>
<h1>{intl.formatMessage({ id: 'home.title' })}</h1>
<p>{intl.formatMessage({ id: 'home.welcome' })}</p>
</div>
);
}
7. Ajouter le composant à votre page
Enfin, ajoutez votre nouveau composant client à votre page.
// app/[lang]/page.tsx
import HomePageContent from '@/app/components/HomePageContent';
export default function Home() {
// This page is a Server Component
return (
<div>
{/* It renders the Client Component */}
<HomePageContent />
</div>
);
}