Comment prendre en charge les langues de droite à gauche (RTL) dans React Router v7
Inverser les mises en page pour l'arabe et l'hébreu
Problème
La plupart des systèmes de design supposent que le texte s'écoule de gauche à droite. La navigation commence à gauche, les barres latérales s'ancrent à gauche et le contenu se lit de gauche à droite. Mais l'arabe et l'hébreu se lisent de droite à gauche, et leurs mises en page doivent être inversées en conséquence — ce qui apparaît à gauche en anglais doit apparaître à droite en arabe. Sans cette inversion, l'interface entière semble à l'envers. Le flux visuel contredit le sens de lecture, créant une expérience désorientante où les utilisateurs doivent lutter contre la mise en page pour lire naturellement.
Le défi va au-delà du simple alignement du texte. Les marges, le remplissage, les bordures et le positionnement doivent tous s'adapter. Un bouton avec une marge à gauche en anglais doit avoir une marge à droite en arabe. Les icônes qui pointent vers la droite doivent pointer vers la gauche. Toute la logique spatiale de l'interface doit s'inverser pour correspondre au sens de lecture.
Solution
Définissez l'attribut dir sur l'élément <html> du document pour spécifier le sens du texte pour la langue actuelle. Utilisez ltr pour les langues de gauche à droite comme l'anglais et rtl pour les langues de droite à gauche comme l'arabe et l'hébreu. Ce seul attribut permet aux navigateurs d'inverser automatiquement de nombreux comportements de mise en page.
Concevez les mises en page en utilisant les propriétés logiques CSS comme margin-inline-start au lieu des propriétés physiques comme margin-left, afin que l'espacement s'adapte automatiquement lorsque le sens du texte change. Les propriétés logiques sont indépendantes du sens — elles définissent l'espacement par rapport au flux du texte plutôt qu'à des positions fixes sur l'écran. Lorsque le sens du document est RTL, margin-inline-start devient margin-right, et la mise en page s'inverse d'elle-même sans code supplémentaire.
Étapes
1. Détecter la direction du texte de la locale actuelle
React Router 7 nécessite une route racine dans app/root.tsx qui affiche le document HTML. Créez une fonction utilitaire qui associe les codes de locale à leur direction de texte.
const locales = {
en: { dir: "ltr" },
ar: { dir: "rtl" },
he: { dir: "rtl" },
es: { dir: "ltr" },
};
function getTextDirection(locale: string): "ltr" | "rtl" {
return locales[locale as keyof typeof locales]?.dir || "ltr";
}
Cette fonction renvoie la direction appropriée pour chaque locale prise en charge, avec une valeur par défaut de gauche à droite pour les locales inconnues.
2. Définir l'attribut dir sur l'élément html
Dans votre mise en page racine, récupérez la locale actuelle et appliquez la direction correspondante au document.
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" dir="ltr">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
export default function Root() {
return <Outlet />;
}
Remplacez le dir="ltr" codé en dur par une valeur dynamique basée sur votre mécanisme de détection de locale. Si votre application stocke la locale actuelle dans un loader ou un contexte, lisez-la ici et transmettez-la à getTextDirection.
3. Utiliser les propriétés logiques pour l'espacement
Remplacez les propriétés CSS physiques par leurs équivalents logiques dans vos composants et feuilles de style.
export default function Card({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) {
return (
<div
style={{
paddingInlineStart: "1rem",
paddingInlineEnd: "1rem",
marginInlineStart: "auto",
borderInlineStart: "4px solid blue",
}}
>
<h2>{title}</h2>
{children}
</div>
);
}
Lorsque dir="rtl" est défini, paddingInlineStart s'applique au côté droit et paddingInlineEnd au côté gauche, inversant automatiquement la mise en page. Le même composant fonctionne correctement dans les contextes LTR et RTL sans logique conditionnelle.
4. Appliquer les propriétés logiques aux conteneurs de mise en page
Utilisez les propriétés logiques pour les modèles de mise en page courants comme les barres de navigation et les grilles de contenu.
export default function Navigation() {
return (
<nav
style={{
display: "flex",
gap: "1rem",
paddingInline: "2rem",
borderBlockEnd: "1px solid #ccc",
}}
>
<a href="/" style={{ marginInlineEnd: "auto" }}>
Home
</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
);
}
paddingInline définit le padding des deux côtés en ligne, et marginInlineEnd: "auto" pousse le contenu vers le bord de début en ligne, qui bascule de gauche à droite lorsque la direction change. La mise en page de navigation s'inverse automatiquement pour les langues RTL.
5. Gérer les icônes et les graphiques directionnels
Pour les icônes qui représentent une direction ou un flux, retournez-les conditionnellement en fonction de la direction du texte.
function BackButton() {
const dir = document.documentElement.dir;
const iconStyle = {
transform: dir === "rtl" ? "scaleX(-1)" : "none",
marginInlineEnd: "0.5rem",
};
return (
<button>
<span style={iconStyle}>←</span>
Back
</button>
);
}
Cela retourne l'icône de flèche horizontalement en mode RTL tout en conservant le texte et l'espacement sensibles à la direction grâce aux propriétés logiques. Toutes les icônes n'ont pas besoin d'être retournées — seulement celles qui indiquent une direction ou un mouvement.