Comment détecter les préférences linguistiques de l'utilisateur dans React Router v7

Redirection automatique basée sur les préférences du navigateur

Problème

Chaque navigateur envoie un en-tête Accept-Language avec chaque requête HTTP, indiquant les langues préférées de l'utilisateur par ordre de préférence. Cet en-tête contient des informations précieuses sur la langue que l'utilisateur s'attend à voir, pourtant la plupart des applications l'ignorent complètement. Au lieu de cela, elles affichent une langue par défaut—généralement l'anglais—à chaque visiteur, forçant les utilisateurs à rechercher manuellement un sélecteur de langue alors que leur navigateur a déjà communiqué leur préférence. Cela crée des frictions inutiles et une mauvaise première impression, en particulier pour les utilisateurs internationaux.

Solution

Créez un loader pour le chemin racine qui lit l'en-tête Accept-Language de la requête entrante. Analysez l'en-tête pour extraire les langues préférées de l'utilisateur et leurs valeurs de qualité. Comparez les langues préférées avec les locales prises en charge par votre application. Si une correspondance est trouvée, redirigez l'utilisateur vers le chemin de cette locale. Si aucune langue prise en charge ne correspond, redirigez vers une locale par défaut. Cela garantit que les utilisateurs arrivent automatiquement sur une version localisée de votre site, en fonction des préférences qu'ils ont déjà configurées dans leur navigateur.

Étapes

1. Installez une bibliothèque pour analyser l'en-tête Accept-Language

L'en-tête Accept-Language a un format spécifique avec des valeurs de qualité qui nécessite une analyse minutieuse. Utilisez une bibliothèque dédiée pour gérer cela correctement.

npm install accept-language-parser

Cette bibliothèque analyse la chaîne d'en-tête en une liste ordonnée de préférences linguistiques, gérant les valeurs de qualité et les cas limites conformément à la spécification HTTP.

2. Définissez vos locales prises en charge

Créez un fichier d'aide qui répertorie les locales prises en charge par votre application et spécifie un repli par défaut.

export const supportedLocales = ["en", "fr", "de", "es", "ja"] as const;

export const defaultLocale = "en";

export type Locale = (typeof supportedLocales)[number];

Cela fournit une source unique de vérité pour les langues que votre application peut servir et garantit la sécurité des types dans l'ensemble de votre base de code.

3. Créer une fonction de détection de locale

Créez une fonction qui prend la valeur de l'en-tête Accept-Language et renvoie la locale prise en charge la mieux adaptée.

import parser from "accept-language-parser";
import { supportedLocales, defaultLocale, type Locale } from "./locales";

export function detectLocale(acceptLanguageHeader: string | null): Locale {
  if (!acceptLanguageHeader) {
    return defaultLocale;
  }

  const languages = parser.parse(acceptLanguageHeader);

  for (const lang of languages) {
    const code = lang.code.toLowerCase();
    if (supportedLocales.includes(code as Locale)) {
      return code as Locale;
    }
  }

  return defaultLocale;
}

Cette fonction analyse l'en-tête, parcourt les préférences linguistiques de l'utilisateur par ordre de qualité, et renvoie la première correspondance avec vos locales prises en charge ou revient à la locale par défaut.

4. Configurer la route index racine

Ajoutez une route index à votre configuration de routes qui gérera les requêtes vers le chemin racine.

import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/index.tsx"),
  route(":locale", "routes/locale-root.tsx", []),
] satisfies RouteConfig;

La route index interceptera les requêtes vers le chemin racine avant toute autre correspondance de route, vous permettant d'effectuer la détection de langue et la redirection.

5. Implémenter le loader de la route index avec détection de langue

Créez le module de route index qui lit l'en-tête Accept-Language et redirige vers le chemin de locale approprié.

import { redirect } from "react-router";
import type { Route } from "./+types/index";
import { detectLocale } from "~/utils/detect-locale";

export async function loader({ request }: Route.LoaderArgs) {
  const acceptLanguage = request.headers.get("Accept-Language");
  const locale = detectLocale(acceptLanguage);
  return redirect(`/${locale}`);
}

Lorsqu'un utilisateur visite le chemin racine, ce loader extrait l'en-tête Accept-Language de la requête, détermine la meilleure locale, et le redirige vers le chemin racine de cette locale, garantissant qu'il voit le contenu dans sa langue préférée dès le premier chargement de page.