Comment maintenir la locale dans les liens de navigation avec React Router v7

Maintenir la locale lors de la navigation interne

Problème

Lorsque les informations de langue sont encodées dans le chemin URL, chaque lien de navigation doit préserver cette langue pour maintenir une expérience utilisateur cohérente. Si un utilisateur navigue sur la version française de votre site et clique sur un lien vers /about, il s'attend à rester en français et à naviguer vers /fr/about. Sans liens adaptés à la langue, les utilisateurs se retrouvent dans la langue par défaut en pleine session, brisant leur contexte de navigation et les forçant à changer manuellement de langue à nouveau. Cela crée des frictions et compromet l'expérience localisée.

Coder en dur le préfixe de langue dans chaque lien est source d'erreurs et rend le code fragile. À mesure que les utilisateurs naviguent dans l'application, la langue active peut changer, et la mise à jour manuelle de centaines de liens devient insoutenable.

Solution

Créez un composant Link personnalisé qui lit automatiquement la langue actuelle depuis l'URL et la préfixe à tous les chemins de navigation internes. En enveloppant le composant Link de React Router, vous centralisez la gestion des langues en un seul endroit. L'enveloppe extrait le paramètre de langue de la route actuelle et s'assure que chaque chemin de destination l'inclut, de sorte que la navigation préserve le choix de langue de l'utilisateur sans intervention manuelle.

Cette approche maintient les définitions de liens propres et indépendantes de la langue dans toute votre application tout en garantissant que le contexte linguistique accompagne chaque clic.

Étapes

Construisez un composant personnalisé qui utilise useParams pour extraire la langue actuelle de l'URL et enveloppe le composant Link de React Router pour préfixer la langue au chemin de destination.

import { Link, useParams } from "react-router";
import type { LinkProps } from "react-router";

export function LocaleLink({ to, ...props }: LinkProps) {
  const { locale } = useParams<{ locale: string }>();

  const localizedTo =
    typeof to === "string"
      ? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
      : {
          ...to,
          pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
        };

  return <Link to={localizedTo} {...props} />;
}

Ce composant lit le paramètre de langue de la route actuelle et le préfixe automatiquement à tout chemin que vous passez à la prop to, gérant à la fois les formes de chaîne et d'objet.

Remplacez les composants Link standard par LocaleLink partout où vous avez besoin d'une navigation préservant la locale.

import { LocaleLink } from "./LocaleLink";

export function Navigation() {
  return (
    <nav>
      <LocaleLink to="/">Home</LocaleLink>
      <LocaleLink to="/about">About</LocaleLink>
      <LocaleLink to="/products">Products</LocaleLink>
    </nav>
  );
}

Lorsqu'un utilisateur sur /fr/products clique sur le lien About, il navigue vers /fr/about. Le préfixe de locale est ajouté automatiquement sans encombrer la définition du lien.

3. Gérez les cas particuliers pour les chemins absolus et les liens externes

Étendez le wrapper pour détecter quand un chemin inclut déjà la locale ou pointe vers une URL externe, évitant ainsi le double préfixage ou la rupture de la navigation externe.

import { Link, useParams } from "react-router";
import type { LinkProps } from "react-router";

export function LocaleLink({ to, ...props }: LinkProps) {
  const { locale } = useParams<{ locale: string }>();

  if (!locale) {
    return <Link to={to} {...props} />;
  }

  const isExternal =
    typeof to === "string" &&
    (to.startsWith("http://") || to.startsWith("https://"));
  const alreadyLocalized =
    typeof to === "string" && to.startsWith(`/${locale}/`);

  if (isExternal || alreadyLocalized) {
    return <Link to={to} {...props} />;
  }

  const localizedTo =
    typeof to === "string"
      ? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
      : {
          ...to,
          pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
        };

  return <Link to={localizedTo} {...props} />;
}

Cela protège contre le double préfixage si un chemin commence déjà par la locale et laisse passer les URL externes inchangées, garantissant que le composant fonctionne de manière fiable dans tous les scénarios de navigation.