So unterstützen Sie Rechts-nach-links-Sprachen (RTL) in React Router v7

Layouts für Arabisch und Hebräisch spiegeln

Problem

Die meisten Designsysteme gehen davon aus, dass Text von links nach rechts fließt. Die Navigation beginnt links, Seitenleisten sind links verankert und Inhalte werden von links nach rechts gelesen. Arabisch und Hebräisch werden jedoch von rechts nach links gelesen, und ihre Layouts sollten entsprechend gespiegelt werden – was für Englisch links erscheint, sollte für Arabisch rechts erscheinen. Ohne diese Spiegelung fühlt sich die gesamte Benutzeroberfläche rückwärts an. Der visuelle Fluss widerspricht der Leserichtung und schafft eine desorientierte Erfahrung, bei der Benutzer gegen das Layout ankämpfen müssen, um natürlich zu lesen.

Die Herausforderung geht über einfache Textausrichtung hinaus. Ränder, Abstände, Rahmen und Positionierung müssen sich alle anpassen. Ein Button mit linkem Rand in Englisch sollte rechten Rand in Arabisch haben. Icons, die nach rechts zeigen, sollten nach links zeigen. Die gesamte räumliche Logik der Benutzeroberfläche muss sich umkehren, um der Leserichtung zu entsprechen.

Lösung

Setzen Sie das dir-Attribut auf dem <html>-Element des Dokuments, um die Textrichtung für die aktuelle Sprache anzugeben. Verwenden Sie ltr für Links-nach-rechts-Sprachen wie Englisch und rtl für Rechts-nach-links-Sprachen wie Arabisch und Hebräisch. Dieses einzelne Attribut bewirkt, dass Browser automatisch viele Layout-Verhaltensweisen spiegeln.

Gestalten Sie Layouts mit logischen CSS-Eigenschaften wie margin-inline-start anstelle von physischen Eigenschaften wie margin-left, damit sich Abstände automatisch anpassen, wenn sich die Textrichtung ändert. Logische Eigenschaften sind richtungsunabhängig – sie definieren Abstände relativ zum Textfluss und nicht zu festen Bildschirmpositionen. Wenn die Dokumentrichtung RTL ist, wird margin-inline-start zu margin-right, und das Layout spiegelt sich ohne zusätzlichen Code.

Schritte

1. Textrichtung des aktuellen Gebietsschemas erkennen

React Router 7 erfordert eine Root-Route unter app/root.tsx, die das HTML-Dokument rendert. Erstellen Sie eine Hilfsfunktion, die Gebietsschemacodes ihrer Textrichtung zuordnet.

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";
}

Diese Funktion gibt die entsprechende Richtung für jedes unterstützte Gebietsschema zurück und verwendet standardmäßig links-nach-rechts für unbekannte Gebietsschemata.

2. Das dir-Attribut am html-Element setzen

Rufen Sie in Ihrem Root-Layout das aktuelle Gebietsschema ab und wenden Sie die entsprechende Richtung auf das Dokument an.

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 />;
}

Ersetzen Sie den fest codierten Wert dir="ltr" durch einen dynamischen Wert basierend auf Ihrem Mechanismus zur Gebietsschemerkennung. Wenn Ihre App das aktuelle Gebietsschema in einem Loader oder Kontext speichert, lesen Sie es hier aus und übergeben Sie es an getTextDirection.

3. Logische Eigenschaften für Abstände verwenden

Ersetzen Sie physische CSS-Eigenschaften durch ihre logischen Äquivalente in Ihren Komponenten und Stylesheets.

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>
  );
}

Wenn dir="rtl" gesetzt ist, wird paddingInlineStart auf die rechte Seite und paddingInlineEnd auf die linke Seite angewendet, wodurch das Layout automatisch gespiegelt wird. Dieselbe Komponente funktioniert sowohl in LTR- als auch in RTL-Kontexten korrekt, ohne bedingte Logik.

4. Logische Eigenschaften auf Layout-Container anwenden

Verwenden Sie logische Eigenschaften für gängige Layout-Muster wie Navigationsleisten und Content-Grids.

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 setzt Padding auf beiden Inline-Seiten, und marginInlineEnd: "auto" schiebt den Inhalt an den Inline-Start-Rand, der sich von links nach rechts umkehrt, wenn sich die Richtung ändert. Das Navigationslayout spiegelt sich automatisch für RTL-Sprachen.

5. Icons und richtungsabhängige Grafiken handhaben

Für Icons, die eine Richtung oder einen Fluss darstellen, sollten Sie diese basierend auf der Textrichtung bedingt spiegeln.

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>
  );
}

Dies spiegelt das Pfeil-Icon im RTL-Modus horizontal, während Text und Abstände durch logische Properties richtungsbewusst bleiben. Nicht alle Icons müssen gespiegelt werden – nur solche, die eine Richtung oder Bewegung anzeigen.