So laden Sie Übersetzungen aus Dateien in React Router v7
Trennen Sie übersetzbare Inhalte vom Code
Problem
Das direkte Hardcodieren von benutzerseitigen Strings in Komponenten erzeugt eine enge Kopplung zwischen Inhalt und Code. Jede neue Sprache erfordert, dass Entwickler Implementierungsdateien ändern, wodurch bedingte Logik erweitert und die Komplexität erhöht wird. Wenn sich Texte ändern, erfordern selbst geringfügige Formulierungsanpassungen Code-Deployments. Dieser Ansatz macht Übersetzungs-Workflows von Engineering-Zyklen abhängig und verhindert, dass nicht-technische Teammitglieder Inhalte unabhängig verwalten können.
Mit dem Wachstum von Anwendungen werden verstreute String-Literale schwer nachzuverfolgen und zu pflegen. Jedes Vorkommen einer Phrase in einer Codebasis zu finden ist fehleranfällig, und die Sicherstellung von Konsistenz über ähnliche Nachrichten hinweg wird ohne eine zentrale Quelle der Wahrheit nahezu unmöglich.
Lösung
Extrahieren Sie alle übersetzbaren Strings in externe JSON-Dateien, die nach Sprache organisiert sind, mit einer Datei pro Locale. Ersetzen Sie hardcodierte Strings in Komponenten durch Nachrichten-Identifikatoren, die auf Einträge in diesen Dateien verweisen. Zur Laufzeit lädt die Anwendung die entsprechende Übersetzungsdatei basierend auf der Locale des Benutzers und stellt diese Nachrichten der Internationalisierungsbibliothek zur Verfügung, die Identifikatoren in ihre übersetzten Werte auflöst.
Diese Trennung ermöglicht es Übersetzern, direkt mit JSON-Dateien zu arbeiten, ohne Code anzufassen, ermöglicht Inhaltsaktualisierungen durch einfache Dateiänderungen und bietet eine einzige Quelle der Wahrheit für die Strings jeder Sprache.
Schritte
1. Erstellen Sie Übersetzungsdateien für jede Locale
Organisieren Sie Übersetzungsdateien in einem dedizierten Verzeichnis mit einer JSON-Datei pro Sprache. Strukturieren Sie jede Datei als flaches Objekt, das Nachrichten-Identifikatoren auf übersetzte Strings abbildet.
{
"welcome.title": "Welcome back",
"welcome.subtitle": "Continue where you left off",
"nav.home": "Home",
"nav.about": "About",
"nav.contact": "Contact"
}
Speichern Sie dies als app/translations/en.json für Englisch und erstellen Sie dann parallele Dateien wie app/translations/es.json und app/translations/fr.json mit Übersetzungen für andere Sprachen. Verwenden Sie konsistente Schlüssel über alle Dateien hinweg, damit derselbe Identifikator in jeder Locale zur entsprechenden Übersetzung aufgelöst wird.
2. Übersetzungen in einem Route-Loader laden
Verwenden Sie einen Route-Loader, um die Übersetzungsdatei für das aktuelle Gebietsschema vor dem Rendern abzurufen. Dadurch wird sichergestellt, dass Nachrichten verfügbar sind, wenn Komponenten gemountet werden.
import type { Route } from "./+types/root";
import enMessages from "./translations/en.json";
import esMessages from "./translations/es.json";
import frMessages from "./translations/fr.json";
const messages: Record<string, Record<string, string>> = {
en: enMessages,
es: esMessages,
fr: frMessages,
};
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url);
const locale = url.searchParams.get("locale") || "en";
return {
locale,
messages: messages[locale] || messages.en,
};
}
Der Loader liest das Gebietsschema aus dem URL-Query-Parameter und gibt sowohl das Gebietsschema als auch die entsprechenden Nachrichten zurück. Komponenten können über loaderData auf diese Daten zugreifen, um den Internationalisierungs-Provider zu konfigurieren.
3. IntlProvider mit geladenen Nachrichten konfigurieren
Umschließen Sie Ihre Anwendung mit IntlProvider aus react-intl und übergeben Sie das Gebietsschema und die Nachrichten aus den Loader-Daten.
import { IntlProvider } from "react-intl";
import { Outlet } from "react-router";
import type { Route } from "./+types/root";
export default function Root({ loaderData }: Route.ComponentProps) {
return (
<IntlProvider locale={loaderData.locale} messages={loaderData.messages}>
<html lang={loaderData.locale}>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<Outlet />
</body>
</html>
</IntlProvider>
);
}
Der IntlProvider stellt das Gebietsschema und die Nachrichten allen untergeordneten Komponenten über den React-Context zur Verfügung. Untergeordnete Routen werden durch den Outlet gerendert und erben den Zugriff auf die Übersetzungsdaten.
4. Nachrichten in Komponenten über Identifier referenzieren
Ersetzen Sie hartcodierte Strings durch FormattedMessage-Komponenten, die auf Nachrichten-Identifier aus Ihren Übersetzungsdateien verweisen.
import { FormattedMessage } from "react-intl";
export default function Welcome() {
return (
<div>
<h1>
<FormattedMessage id="welcome.title" />
</h1>
<p>
<FormattedMessage id="welcome.subtitle" />
</p>
<nav>
<a href="/">
<FormattedMessage id="nav.home" />
</a>
<a href="/about">
<FormattedMessage id="nav.about" />
</a>
<a href="/contact">
<FormattedMessage id="nav.contact" />
</a>
</nav>
</div>
);
}
Jede FormattedMessage-Komponente sucht ihre id im Nachrichten-Objekt, das vom IntlProvider bereitgestellt wird, und rendert den entsprechenden übersetzten String. Wenn sich das Gebietsschema ändert und der Loader erneut mit anderen Nachrichten ausgeführt wird, zeigen alle Komponenten automatisch die neuen Übersetzungen an, ohne dass Code-Änderungen erforderlich sind.