Chargement des traductions

Utilisation d'un fournisseur 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 IntlProvider de react-intl pour fournir des 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

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 d'aide pour charger le fichier de dictionnaire approprié 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 fournisseur côté client

IntlProvider est un composant client qui utilise le Context de React. Nous devons créer un wrapper 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>; // Objet de messages plat
};

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 à 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 };
}) {
  // Charger les messages sur le serveur
  const messages = await getDictionary(params.lang);

  return (
    <html lang={params.lang}>
      <body>
        {/* Transmettre les messages au fournisseur client */}
        <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. Ajoutez 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() {
  // Cette page est un composant serveur
  return (
    <div>
      {/* Elle rend le composant client */}
      <HomePageContent />
    </div>
  );
}