Comment valider les paramètres de locale dans les URL avec React Router v7
Gérer les codes de locale non pris en charge de manière élégante
Problème
Lorsque les identifiants de locale font partie de la structure d'URL, ils se transforment en entrée utilisateur pouvant contenir n'importe quelle valeur arbitraire. Un utilisateur peut saisir manuellement /xx/about, /gibberish/contact, ou tout autre code de locale invalide dans la barre d'adresse. Sans validation, l'application doit décider comment gérer ces entrées invalides. Autoriser les locales invalides à continuer peut entraîner des traductions manquantes, un formatage incorrect ou des erreurs d'exécution lorsque les bibliothèques i18n tentent de charger des données de locale inexistantes. Revenir silencieusement à une locale par défaut sans en informer l'utilisateur crée une confusion quant à la langue qu'il consulte. Afficher des limites d'erreur ou des pages vides laisse les utilisateurs bloqués sans chemin clair pour avancer.
Le défi est amplifié par le fait que la validation de la locale doit intervenir tôt dans le cycle de vie de la requête, avant le rendu des composants et avant le chargement des données de traduction. Si la validation se produit trop tard, l'application peut avoir déjà tenté de récupérer des ressources spécifiques à la locale ou initialisé des fournisseurs i18n avec une configuration invalide, gaspillant des ressources et causant potentiellement des défaillances en cascade.
Solution
Validez le paramètre de locale dans un loader de route avant le rendu de la page. Les loaders dans React Router s'exécutent avant le montage des composants, ce qui en fait l'endroit idéal pour vérifier si la locale demandée existe dans la liste des langues prises en charge par votre application. Si la locale est valide, laissez la requête se poursuivre normalement. Si la locale est invalide, redirigez immédiatement l'utilisateur vers une solution de repli sûre — soit le même chemin avec une locale par défaut valide, soit une page dédiée introuvable qui explique le problème.
Cette approche empêche les locales invalides d'atteindre vos composants et fournisseurs i18n. En renvoyant une réponse de redirection depuis le loader, vous exploitez le système de navigation intégré de React Router pour gérer l'erreur de manière élégante. La redirection se produit sur le serveur pendant le SSR ou sur le client pendant la navigation, garantissant un comportement cohérent entre les stratégies de rendu. Les utilisateurs reçoivent un retour immédiat via le changement d'URL, et votre application évite de tenter de charger des ressources pour des locales inexistantes.
Étapes
1. Définissez vos locales prises en charge
Créez une liste de codes de locale valides que votre application prend en charge. Cette liste sert de source de vérité pour la validation.
export const SUPPORTED_LOCALES = ["en", "es", "fr", "de", "ja"] as const;
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
export function isValidLocale(locale: string): locale is SupportedLocale {
return SUPPORTED_LOCALES.includes(locale as SupportedLocale);
}
Cette fonction utilitaire fournit une validation type-safe et peut être réutilisée dans les loaders et d'autres parties de votre application.
2. Ajoutez la validation au loader de votre route préfixée par locale
Dans le module de route pour vos pages préfixées par locale, exportez un loader qui vérifie le paramètre de locale et redirige s'il est invalide.
import type { Route } from "./+types/page";
import { redirect } from "react-router";
import { isValidLocale } from "~/i18n/locales";
export async function loader({ params }: Route.LoaderArgs) {
const { locale } = params;
if (!locale || !isValidLocale(locale)) {
return redirect("/en/not-found");
}
return { locale };
}
export default function Page({ loaderData }: Route.ComponentProps) {
return (
<div>
<h1>Content in {loaderData.locale}</h1>
</div>
);
}
Le loader extrait la locale de l'URL, la valide et redirige vers une solution de repli sûre si la validation échoue. Si la locale est valide, il renvoie des données que les composants peuvent utiliser.
3. Configurez vos routes avec des paramètres de locale
Dans votre fichier routes.ts, définissez des routes qui incluent la locale comme segment dynamique.
import { type RouteConfig, route } from "@react-router/dev/routes";
export default [
route(":locale/about", "./routes/about.tsx"),
route(":locale/contact", "./routes/contact.tsx"),
route(":locale/not-found", "./routes/not-found.tsx"),
] satisfies RouteConfig;
Chaque route avec un paramètre :locale invoquera son loader, où la validation se produit avant le rendu du composant.
4. Créez une page introuvable pour les locales invalides
Créez une page dédiée qui explique que la locale n'a pas été trouvée et propose des options de navigation.
import { Link } from "react-router";
import { SUPPORTED_LOCALES } from "~/i18n/locales";
export default function NotFound() {
return (
<div>
<h1>Language Not Found</h1>
<p>The requested language is not supported.</p>
<nav>
<p>Choose a language:</p>
<ul>
{SUPPORTED_LOCALES.map((locale) => (
<li key={locale}>
<Link to={`/${locale}`}>{locale.toUpperCase()}</Link>
</li>
))}
</ul>
</nav>
</div>
);
}
Cette page fournit un retour clair et des étapes d'action concrètes, aidant les utilisateurs à se remettre de l'erreur sans quitter votre application.
5. Ajouter une route catch-all pour les chemins complètement invalides
Pour les URL qui ne correspondent à aucun modèle de route défini, ajoutez une route splat à la fin de votre configuration de routes.
import { type RouteConfig, route } from "@react-router/dev/routes";
export default [
route(":locale/about", "./routes/about.tsx"),
route(":locale/contact", "./routes/contact.tsx"),
route(":locale/not-found", "./routes/not-found.tsx"),
route("*", "./routes/catch-all.tsx"),
] satisfies RouteConfig;
La route splat correspond à tout chemin qui ne correspond pas aux routes précédentes, vous permettant de gérer les URL complètement malformées séparément des codes de locale invalides.
6. Rediriger optionnellement vers une locale par défaut au lieu d'une page introuvable
Si vous préférez corriger silencieusement les locales invalides plutôt que d'afficher une erreur, redirigez vers le même chemin avec une locale par défaut.
import type { Route } from "./+types/page";
import { redirect } from "react-router";
import { isValidLocale } from "~/i18n/locales";
const DEFAULT_LOCALE = "en";
export async function loader({ params, request }: Route.LoaderArgs) {
const { locale } = params;
if (!locale || !isValidLocale(locale)) {
const url = new URL(request.url);
const newPath = url.pathname.replace(/^\/[^/]+/, `/${DEFAULT_LOCALE}`);
return redirect(newPath);
}
return { locale };
}
Cette approche préserve le reste du chemin de l'URL tout en remplaçant uniquement le segment de locale invalide, offrant une expérience utilisateur plus fluide lorsque la locale est le seul problème.