Software-Lokalisierung
Ein Leitfaden für die React-Lokalisierung mit i18next

React ist heute so allgegenwärtig, dass es fast als Standard für den Bau von Web-Apps (und unzähligen anderen UIs) gelten kann. Ein Teil des Erfolgs von React ist die starke Fokussierung auf komponentenbasierte, reaktive Benutzeroberflächen: Um komplette Apps zu erstellen, muss oft ein eigenes Framework um React herum entwickelt werden. Was passiert also, wenn die React-App andere Sprachen sprechen muss? Vielleicht wird hier an die beliebteste Bibliothek für Internationalisierung, i18next, gedacht. Eine kluge Wahl: Neben seiner Beliebtheit ist i18next ausgereift und flexibel erweiterbar. Jedes Internationalisierungsproblem, das man sich vorstellen kann, ist wahrscheinlich bereits mit i18next oder einem seiner vielen Plugins gelöst.
In diesem Tutorial wird gezeigt, wie i18next mit React genutzt werden kann, um dynamische Anwendungen in mehreren Sprachen zu erstellen. Alles wird abgedeckt, von der grundlegenden Einrichtung bis hin zu fortgeschrittenen Funktionen, damit die React-App in Nullkommanichts mehrere Sprachen spricht.
Internationalisierung und Lokalisierung
Internationalisierung (i18n) und Lokalisierung (l10n) ermöglichen es, Apps in verschiedenen Sprachen und für verschiedene Regionen verfügbar zu machen, oft für mehr Profit. Für alle, die neu in i18n und l10n sind, ist unser Leitfaden zur Internationalisierung empfehlenswert.
Voraussetzungen und Paketversionen
Es wird vorausgesetzt, dass Kenntnisse in der React-Entwicklung vorhanden sind, und der i18n-Code wird so klar wie möglich erklärt.
Um die Demo-App auf dem eigenen Rechner auszuführen (was nicht unbedingt notwendig ist), ist eine relativ aktuelle Version von Node.js erforderlich. Apropos, hier sind die Pakete, die in diesem Leitfaden verwendet werden (mit Versionen zum Zeitpunkt des Schreibens):
- vite (5.0) — Der superschnelle Modul-Bundler (es kann create-react-app / Webpack oder ein anderes Tool verwendet werden).
- typescript (5.3) — In TypeScript wird geschrieben, aber das ist nicht zwingend notwendig. Wenn gewünscht, kann einfaches JavaScript verwendet werden.
- React (18.2)
- i18next (23.7) — Unsere i18n-Bibliothek.
- i18next-http-backend (2.4) — Lädt Übersetzungsdateien.
- i18next-browser-languagedetector (7.2) — Erkennt die Sprache des Nutzers.
- tailwindcss (3.4) — Wird für das Styling verwendet; hier weitgehend optional.
Die Demo-App: ein Spielplatz für React und i18next
Eine interaktive Demo als Begleiter zu diesem Artikel kann direkt auf StackBlitz aufgerufen werden. Alternativ kann der Projektcode von GitHub geholt und auf dem eigenen Rechner ausgeführt werden; es sollte nur sichergestellt sein, dass eine aktuelle Version von Node.js installiert ist.


📣 Shoutout » Ein Dankeschön an rawpixel.com für die Bereitstellung des Grid Background, der kostenlos auf Freepik erhältlich ist, den wir in unserer Demo-App verwenden.
i18next für eine React-App installieren und konfigurieren – so geht’s
Die Installation wird natürlich mit NPM (oder einem ähnlichen Tool) durchgeführt.
npm install react-i18next i18next
Code-Sprache: Bash (bash)
i18next
ist die Kernbibliothek, aber das i18next-Team bietet auch eine offizielle Erweiterung für React, react-i18next
, an. Mit der Installation beider Pakete erhält man einen maßgeschneiderten React-Hook und Komponenten, die das Arbeiten mit i18next in React-Projekten erleichtern und beschleunigen.
Jetzt werden diese Bibliotheken konfiguriert und mit der React-App verbunden. Ein neues Verzeichnis src/i18n
wird erstellt und eine Konfigurationsdatei darin abgelegt.
// src/i18n/config.ts
// Core-i18next-Bibliothek.
import i18n from "i18next";
// Bindings für React: Komponenten ermöglichen,
// neu rendern, wenn sich die Sprache ändert.
import { initReactI18next } from "react-i18next";
i18n
// Hinzufügen von React-Bindings als Plugin.
.use(initReactI18next)
// Initialisierung der i18next-Instanz.
.init({
// Konfigurationsoptionen
// Angabe der verwendeten Standardsprache (Locale)
// wenn ein*e Nutzer*in unsere Seite zum ersten Mal besucht.
// Es wird hier Englisch verwendet, aber es kann auch eine andere Sprache genutzt werden,
// welche Locale auch immer gewünscht ist.
lng: "en",
// Fallback-Locale, die verwendet wird, wenn eine Übersetzung
// fehlt in der aktiven Lokalisierung. Nochmal, es kann die bevorzugte Sprache verwendet werden
// bevorzugte Locale hier.
fallbackLng: "en",
// Ermöglicht nützliche Ausgaben im Browser
// Dev-Konsole.
debug: true,
// Normalerweise wird `escapeValue: true` bevorzugt, da es
// stellt sicher, dass i18next jeglichen Code in
// Übersetzungsnachrichten schützt, um gegen
// XSS (Cross-Site-Scripting)-Attacken zu schützen. Allerdings
// React übernimmt das Escaping selbst, daher schalten wir es ab
// wir es in i18next ab.
Interpolation: {
escapeValue: false,
},
// Übersetzungsnachrichten. Beliebige Sprachen hinzufügen
// die hier gewünscht werden.
Ressourcen: {
// Englisch
en: {
// `translation` ist der Standard-Namespace.
// Mehr Details zu Namespaces folgen in Kürze.
translation: {
hello_world: "Hallo, Welt!"
},
},
// Arabisch
ar: {
translation: {
hello_world: "مرحباً بالعالم!",
},
},
},
});
export default i18n;
Code-Sprache: TypeScript (typescript)
Eine i18next-Instanz wird für das grundlegende Setup initialisiert und konfiguriert. i18next ist sehr anpassbar, daher lohnt sich ein Blick in die Konfigurationsoptionen Dokumentation, um nach Belieben Anpassungen vorzunehmen.
Jetzt wird diese Datei in den Einstiegspunkt der App importiert, um sie zu verbinden.
// src/main.tsx
// 👆 Das könnte index.tsx oder sein
// index.js in deiner App sein.
importiere React aus "react";
importiere ReactDOM von "react-dom/client";
import App from "./App.tsx";
+ import "./i18n/config.ts";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
Code-Sprache: Diff (diff)
Wenn jetzt die App ausgeführt wird, sollte in der Entwicklertools-Konsole des Browsers eine Meldung zu sehen sein, die bestätigt, dass i18next korrekt initialisiert wurde. Das ist der debug: true
Option zu verdanken, die zur Config hinzugefügt wurde.
Ein kurzer Test: Übersetzung einer Komponente
Wie funktioniert das Ganze in einer React-Komponente? Lasst es uns mal versuchen.
// src/App.tsx
// React-Hook, der gewährleistet, dass Komponenten
// neu gerendert werden, wenn sich die Locale ändert.
import { useTranslation } from "react-i18next";
function App() {
// Die `t()`-Funktion gibt uns
// Zugriff auf die aktive Locale
// Übersetzungen.
const { t } = useTranslation();
return (
<div className="...">
{/* Der Schlüssel, den wir unter
`resources.translation` in
src/i18n/config.ts */}
<h2>{t("hello_world")}</h2>
</div>
);
}
export default App;
Code-Sprache: TypeScript (typescript)
Wird die App jetzt geladen, sollte die englische „Hello, World!“-Nachricht zu sehen sein.
Und wenn die Standard-Locale auf Arabisch umgestellt wird, rendert die Komponente neu und zeigt die arabische hello_world
Übersetzung.
Namespaces
Vielleicht ist der Übersetzung
-Namensraum unter Ressourcen
aufgefallen, als i18next konfiguriert wurde. Namensräume sind effektiv Gruppen, und i18next nutzt sie, um Übersetzungen in logische Sammlungen aufzuteilen für größere Apps (z.B. Admin, Öffentlich).
Das kann Apps performanter machen, wenn die Übersetzungen jedes Namensraums in einer separaten Datei untergebracht sind und die Datei eines Namensraums nur bei Bedarf geladen wird, idealerweise asynchron. (Das asynchrone Laden von Dateien wird gleich behandelt).
Übersetzung
ist der Standard-Namensraum, der von i18next verwendet wird, und es ist der einzige, der in diesem Artikel genutzt wird. Die Namensräume Dokumentationsseite bietet weitere Informationen für alle, die tiefer eintauchen möchten.
Sprachcodes (en, ar, etc.)
Ein Locale legt eine Sprache, eine Region und manchmal mehr fest. In der Regel nutzen Locales IETF BCP 47 Sprach-Tags, wie en
für Englisch, fr
für Französisch und es
für Spanisch. Für eine genaue Datums- und Zahlenlokalisierung empfiehlt es sich, eine Region mit dem ISO Alpha-2-Code hinzuzufügen (z. B. BH
für Bahrain, CN
für China, US
für die Vereinigten Staaten). So könnte ein vollständiges Locale en-US
für amerikanisches Englisch oder zh-CN
für in China verwendetes Chinesisch aussehen.
🔗 Auf Wikipedia gibt es mehr Sprach-Tags und mit dem Suchtool der ISO können Ländercodes gefunden werden.
✋ Bei der Verwendung von reinen Sprach-Locales wie en
und ar
funktioniert die Locale-Auflösung von i18next am besten. In diesem Artikel wird das beibehalten, aber es sollte beachtet werden, dass der Browser die Region für die Formatierung auswählt, wenn Daten und Zahlen lokalisiert werden. Angenommen, ar, könnte ein Browser wählen, Daten für Arabisch-Ägypten (ar-EG) zu formatieren, während ein anderer Saudi-Arabien (ar-SA) auswählt. Dieses Problem wird etwas später in diesem Artikel gelöst, wenn eigene benutzerdefinierte Zahlen- und Datumsformatierer geschrieben werden.
Übersetzungsdateien asynchron laden – so geht’s
Gerade werden Übersetzungen in die i18n-Konfigurationsdatei eingefügt.
// src/i18n/config.ts
import i18n from "i18next";
// ...
i18n
// ...
.init({
//...
Ressourcen: {
en: {
translation: {
hello_world: "Hallo, Welt!"
},
},
ar: {
translation: {
hello_world: "مرحباً بالعالم!",
},
},
},
});
export default i18n;
Code-Sprache: TypeScript (typescript)
Das funktioniert vielleicht gut für ein paar Sprachen und einige Übersetzungsnachrichten, aber wie man sich vorstellen kann, lässt sich diese Lösung nicht besonders gut skalieren. Mit jeder weiteren Sprache und Übersetzung, die hinzugefügt wird, bläht sich die Konfigurationsdatei auf und das anfängliche Laden der App wird langsamer.
Zudem ist es oft gewünscht, eine einzelne Sprachdatei an einen Übersetzer weiterzugeben, und dieser Ansatz ist dafür nicht wirklich geeignet.
Es wäre besser, die Übersetzungen in separate Dateien aufzuteilen, jeweils eine für jede Sprache. Währenddessen sollte sichergestellt werden, dass die Übersetzungsdatei der aktiven Sprache asynchron aus dem Netzwerk geladen wird. Das wird die App beschleunigen, während sie skaliert, und es ermöglichen, jedem Übersetzer nur die Datei(en) in der jeweiligen Sprache bereitzustellen.
Zuerst wird das offizielle i18next HTTP API Backend-Plugin installiert. Es ist der einfachste Weg, Übersetzungsdateien aus dem Netzwerk herunterzuladen und mit i18next zu verknüpfen.
npm install i18next-http-backend
Code-Sprache: Bash (bash)
Als nächstes wird das Backend konfiguriert.
// src/i18n/config.ts
import i18n from "i18next";
+ import HttpApi from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
i18n
+ // Das Backend als Plugin einbinden.
+ .use(HttpApi)
.use(initReactI18next)
.init({
lng: "en",
fallbackLng: "en",
debug: true,
Interpolation: {
escapeValue: false,
},
- // Die eingebetteten Übersetzungen entfernen.
- resources: {
- en: {
- translation: {
- hello_world: "Hallo, Welt!"
- },
- },
- ar: {
- translation: {
- hello_world: "مرحباً بالعالم!"
- },
- },
- },
});
export default i18n;
Code-Sprache: Diff (diff)
Nachdem die Inline-Übersetzungen entfernt wurden, ist es besser, sie in separaten Dateien hinzuzufügen. Standardmäßig wird das HTTP API-Backend beim Start von i18next an einer bestimmten URL nach einer Übersetzungsdatei suchen. Ist die aktive Sprache Englisch, wird die Datei unter einer öffentlichen URL relativ zum Stammverzeichnis unserer Website gesucht: http://example.com/locales/en/translation.json
🗒️ Nicht vergessen, translation
ist der Standard-Namespace.
Die Dateien sollten dort hinzugefügt werden, wo das Backend sie erwartet, also im public
Verzeichnis, so dass sie im Netzwerk zum Download bereit sind.
// public/locales/en/translation.json
{
"hello_world": "Hallo, Welt!"
}
// public/locales/ar/translation.json
{
"hello_world": "مرحباً بالعالم!"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
Laden wir die App jetzt neu, sollte alles wie zuvor funktionieren. Schaut man jedoch in den Netzwerk-Tab der Entwicklerkonsole des Browsers, bemerkt man einige neue Anfragen.
Zum Schluss noch eine Sache: Es wird eine React Suspense Grenze hinzugefügt, so dass bei langsamen Verbindungen ein hilfreicher Indikator angezeigt wird, während die aktiven Übersetzungsdateien heruntergeladen werden.
// src/main.tsx
importiere React aus "react";
importiere ReactDOM von "react-dom/client";
import App from "./App.tsx";
import "./i18n/config.ts";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
+ <React.Suspense fallback={<div>Wird geladen...</div>>
<App />
+ </React.Suspense>
</React.StrictMode>,
);
Code-Sprache: Diff (diff)
Sollte das Laden unserer Übersetzungsdatei etwas Zeit in Anspruch nehmen, erscheint eine „Wird geladen…“-Nachricht statt einer leeren Seite.
✋ Die Fallback-Locale(s) werden immer geladen. Bei der aktuellen Konfiguration werden sowohl die arabischen als auch die englischen (en
) Übersetzungsdateien geladen, wenn Arabisch (ar
) als aktive Sprache eingestellt ist. Das liegt daran, dass en
als Fallback-Lokalisierung festgelegt wurde, als i18next konfiguriert wurde. Fehlt eine arabische Übersetzung, sollte die englische Entsprechung angezeigt werden, das ergibt Sinn.
🔗 Der Pfad zur Übersetzungsdatei und andere Optionen können überschrieben werden, wenn das HTTP-API-Backend konfiguriert wird. Mehr erfahren auf der offiziellen Plugin-Seite.
Das sind die Grundlagen des asynchronen Ladens von Übersetzungsdateien. Mit nur wenigen Zeilen Code wurde unsere App deutlich skalierbarer gemacht.
Wie wird die aktive Sprache abgerufen und eingestellt?
In Komponenten und benutzerdefinierten Hooks kann der useTranslation()
Hook verwendet werden, um die i18next-Instanz zu erhalten, die i18n
genannt wird. Mit diesem Objekt lässt sich die aktive Sprache abrufen und festlegen.
// In Komponenten oder Hooks
import { useTranslation } from "react-i18next";
// ...
const { i18n } = useTranslation();
const activeLocale = i18n.resolvedLanguage;
// => "en" wenn die aktive Sprache Englisch ist
i18n.changeLanguage("ar");
// Aktive Sprache ist jetzt Arabisch; Komponenten
// werden neu gerendert, um dies widerzuspiegeln.
Code-Sprache: TypeScript (typescript)
Es gibt zwei Eigenschaften, um auf die aktive Sprache zuzugreifen:
i18n.language
ist entweder die erkannte Sprache (wenn die Browsererkennung verwendet wird, dazu später mehr) oder die direkt überi18n.changeLanguage()
eingestellte.i18n.resolvedLanguage
ist die tatsächliche Sprache, die nach der Auflösung der Fallbacks verwendet wird und eine entsprechende Übersetzungsdatei hat.
Angenommen, es wird i18n.changeLanguage("ar-SA")
aufgerufen, um die Sprache in der App auf Saudi-Arabisch zu ändern. Es gibt keine ar-SA
Übersetzungsdatei, daher greift i18next auf die ar
Datei zurück. In diesem Fall:
i18n.language === "ar-SA"
i18n.resolvedLanguage === "ar"
🔗 Mehr über die aufgelöste Sprache in den offiziellen Dokumenten erfahren.
Einen Sprachumschalter erstellen – so geht’s
Oft wird eine Möglichkeit gewünscht, damit Benutzer manuell ihre bevorzugte Sprache auswählen können. Mit den gerade besprochenen i18n
Elementen, i18n.resolvedLanguage
und i18n.changeLanguage()
, kann eine Benutzeroberfläche zum Wechseln der Spracheinstellungen erstellt werden.
Zuerst sollte ein unterstütztes Sprachen-Objekt in die Konfiguration eingefügt werden.
// src/i18n/config.ts
import i18n from "i18next";
import HttpApi from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
+ // Namen für jede Spracheinstellung hinzufügen, um
+ // dem Nutzer in unserer Sprache anzeigen
+ // Switcher.
+ export const supportedLngs = {
+ en: "Englisch",
+ ar: "Arabisch (العربية)",
+ };
i18n
.use(HttpApi)
.use(initReactI18next)
.init({
lng: "en",
fallbackLng: "en",
+ // i18next explizit mitteilen, dass unsere
+ // unterstützte Gebietsschemas.
+ unterstützteSprachen: Object.keys(supportedLngs),
debug: true,
Interpolation: {
escapeValue: false,
},
});
export default i18n;
Code-Sprache: Diff (diff)
Das supportedLngs Objekt wird exportiert, weil es im Lokalisierungswechsler gebraucht wird. Apropos:
// src/i18n/LocaleSwitcher.tsx
import { useTranslation } from "react-i18next";
import { supportedLngs } from "./config";
export default function LocaleSwitcher() {
const { i18n } = useTranslation();
return (
<div className="...">
<div className="...">
<select
value={i18n.resolvedLanguage}
onChange={(e) => i18n.changeLanguage(e.target.value)}
>
{Object.entries(supportedLngs).map(([code, name]) => (
<option value={code} key={code}>
{name}
</option>
))}
</select>
</div>
</div>
);
}
Code-Sprache: TypeScript (typescript)
🔗 Die vollständige Codeauflistung für LocaleSwitcher
, inklusive Icon und Styles, ist in unserem GitHub-Repo zu finden.
Mit Object.entries wird { en: umgewandelt. "Deutsch", ...}
Objekt wird in ein Array von Arrays umgewandelt, [["de", "Deutsch"], ...]
. Die Elemente dieses Arrays werden zerlegt und in <option value="en">Englisch</option>
Elemente für das <select>
umgewandelt.
Wenn dieser <LocaleSwitcher>
in die Kopfzeile der App eingefügt wird, ergibt sich folgendes:
📣 Vielen Dank an The Icon Z für das Bereitstellen des Sprach-Icons auf The Noun Project.
Wie lässt sich die Sprache des Nutzers automatisch erkennen?
Bisher wurde darauf vertraut, dass die Standardsprache (in unserem Fall Englisch) verstanden wird und bei Bedarf eine andere ausgewählt wird. Aber nicht alle können Englisch lesen. Es könnte sinnvoll sein, die Spracheinstellungen im Browser des Nutzers zu erkennen und unsere Website in einer Sprache zu präsentieren, die dieser so nah wie möglich kommt.
Zum Glück wird die automatische Spracherkennung mit dem offiziellen i18next-Sprachenerkennungs-Plugin zum Kinderspiel. Lasst es uns installieren.
npm install i18next-browser-languagedetector
Code-Sprache: Bash (bash)
Nun muss das Plugin bei der Konfiguration der i18next-Instanz eingebunden werden.
// src/i18n/config.ts
import i18n from "i18next";
+ import LanguageDetector from "i18next-browser-languagedetector";
import HttpApi from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
export const supportedLngs = {
en: "Englisch",
ar: "Arabisch (العربية)",
};
i18n
.use(HttpApi)
+ .use(LanguageDetector)
.use(initReactI18next)
.init({
- // Diese explizite Einstellung muss entfernt werden
- // der aktiven Lokalisierung, oder sie wird
- // die automatisch erkannte Locale überschreiben.
lng: "en",
fallbackLng: "en",
supportedLngs: Object.keys(supportedLngs),
debug: true,
Interpolation: {
escapeValue: false,
},
});
export default i18n;
Code-Sprache: Diff (diff)
Wenn die lng
-Einstellung in unserer Konfiguration beibehalten wird, wird immer die erkannte Spracheinstellung überschrieben.
OK, dieses neue Setup mal ausprobieren. Es können die Spracheinstellungen des Browsers geöffnet und sichergestellt werden, dass Arabisch ganz oben auf der Liste steht (oder jede Sprache, die in der App unterstützt wird).

Wenn jetzt unsere Webseite besucht wird, wird sie auf Arabisch angezeigt. Hier zeigt der Spracherkenner, was er kann: Es wird die Browsereinstellung aus dem JavaScript navigator
Objekt ausgelesen und mit einer der unterstützten Sprachen unserer App abgeglichen. Hier führt ar-EG
zu einem Fallback auf das unterstützte ar
, sodass die Seite auf Arabisch angezeigt wird.
Erkennungsquellen
Standardmäßig durchläuft der i18next-browser-languagedetector
eine Reihe von Quellen zur automatischen Erkennung der Sprache. Wird eine Spracheinstellung in einer dieser Quellen gefunden, stoppt der Vorgang und wechselt zu dieser Spracheinstellung. Andernfalls wird die Liste weiter abgearbeitet. Hier ist die Standard-Kaskade:
- Die URL-Abfragezeichenfolge. Das kann ausprobiert werden:
/?lng=en
besuchen und die Seite sollte auf Englisch umschalten. - Ein Cookie (standardmäßig
i18next
genannt), der den Wert der zuletzt ermittelten Locale speichert. - Ein localeStorage-Schlüssel (standardmäßig
i18nextLng
genannt), der den Wert der zuletzt ermittelten Locale speichert. - Ein sessionStorage-Schlüssel (standardmäßig
i18nextLng
genannt), der den Wert der zuletzt ermittelten Locale speichert. - Das
navigator
-Objekt, das die Sprachen in den Browser-Einstellungen anzeigt. - Das Attribut
<html lang>
.
🔗 Ähnlich wie andere i18next-Funktionen ist der Detektor hochgradig konfigurierbar und unterstützt sogar die Erkennung über den URL-Pfad oder die Subdomain. Sogar benutzerdefinierte Erkennungslogik ist möglich. Mehr Infos gibt es in den offiziellen Detektor-Dokumenten.
Caching der ermittelten Sprache
Standardmäßig wird das zuletzt aufgelöste Locale im localStorage zwischengespeichert. Bei einem ersten Besuch der Seite durchläuft der Detektor die übliche Kaskade und landet auf einem Locale – wahrscheinlich einem, das im Browser des Benutzers konfiguriert ist, oder einem unserer Fallbacks. Jedes Mal, wenn der Nutzer danach die Seite besucht, liest der Detektor den im localStorage gespeicherten Wert und verwendet diese Locale, ohne weiter zu suchen.
Dieses Caching-Verhalten findet bei i18next.init()
und i18n.changeLanguage()
statt. Wenn also ein bevorzugtes Locale manuell ausgewählt wird, überschreibt dies alle anderen Erkennungen.
Grundsätzlich wird versucht, das Locale des Nutzers zu erkennen, aber letztendlich bleibt die Wahl dem Nutzer überlassen.
🤿 In unserem speziellen Leitfaden Erkennung des Nutzer-Locale in einer Webanwendung wird tiefer in die Erkennung des Nutzer-Locale auf dem Server und im Browser eingegangen, sogar bis hin zur Geolokalisierung.
Arbeiten mit Sprachen, die von rechts nach links geschrieben werden – so geht’s
Weltweit lesen und sprechen Hunderte Millionen Menschen Sprachen, die von rechts nach links geschrieben werden, wie Arabisch, Hebräisch, Urdu und mehr. Dennoch wird RTL (von rechts nach links) oft erst nachträglich bei Lokalisierungsbemühungen berücksichtigt. Vor ein paar Jahren war die Unterstützung von RTL etwas mühsam. Heutzutage vereinfachen moderne Browser den Prozess der Unterstützung des RTL-Dokumentenflusses und bewältigen die meisten Komplexitäten. Es sind nur minimale Anpassungen in den Anwendungen erforderlich, um RTL vollständig zu unterstützen.
i18next kann die Ausrichtung eines bestimmten Locales mit der Methode i18n.dir()
erkennen. Es wird ein benutzerdefinierter Hook geschrieben, um die Dokumentausrichtung abhängig vom aktiven Locale festzulegen.
// src/i18n/useLocalizeDocumentAttributes.ts
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
export default function useLocalizeDocumentAttributes() {
const { i18n } = useTranslation();
useEffect(() => {
if (i18n.resolvedLanguage) {
// Das Attribut <html lang> setzen.
document.documentElement.lang = i18n.resolvedLanguage;
// Das Attribut <html dir> setzen.
document.documentElement.dir = i18n.dir(i18n.resolvedLanguage);
}
}, [i18n, i18n.resolvedLanguage]);
}
Code-Sprache: TypeScript (typescript)
🗒️ Zu beachten ist, dass resolvedLanguage
die Sprache ist, die am besten zur ausgewählten oder erkannten Sprache passt und die wir unterstützen. resolvedLanguage
ist im Grunde genommen die aktive Lokalisierung.
Um die allgemeine Dokumentrichtung auf RTL zu ändern, muss nur <html dir="rtl">
eingestellt werden. Alle modernen Browser unterstützen dies und passen die Seite entsprechend an. Auf das <html>
-Element wird über document.documentElement
zugegriffen.
🗒️ Es ist auch eine gute Praxis, das <html lang>
Attribut zu setzen (es hilft bei der Barrierefreiheit, der Benutzererfahrung, der Suchmaschinenoptimierung und mehr).
Der neue Hook wird zur <App>
Komponente hinzugefügt, um ihn in Aktion zu sehen.
// src/App.tsx
import { useTranslation } from "react-i18next";
+ import useLocalizeDocumentAttributes from "./i18n/useLocalizeDocumentAttributes";
import Header from "./layout/Header";
function App() {
const { t } = useTranslation();
+ useLocalizeDocumentAttributes();
return (
<div className="...">
{/* ... */}
</div>
);
}
export default App;
Code-Sprache: Diff (diff)

🔗 i18n.dir()
gehört zur i18n-Objekt-API.
🗒️ Es gehört mehr zu RTL, als nur das <html dir>
umzudrehen. Zum Beispiel muss oft darauf geachtet werden, dass der horizontale Abstand (Margin, Padding) in die richtige Richtung ausgerichtet ist. Dabei können CSS-Logik-Eigenschaften (margin-block-start
anstelle von margin-left
) hilfreich sein.
Wie kann der Titel des Dokuments lokalisiert werden?
Natürlich ist der <title>
unserer Seite sehr wichtig für die Suchmaschinenoptimierung (SEO) und das Nutzererlebnis – schließlich wird der Titel im Browser-Tab angezeigt. Die Lokalisierung eines Seitentitels ist unkompliziert. Zuerst fügen wir Übersetzungsnachrichten für den Seitentitel hinzu:
// public/locales/en/translation.json
{
+ "app_title": "React + i18next Playground",
"hello_world": "Hallo, Welt!"
}
// public/locales/ar/translation.json
{
+ "app_title": "ملعب ريأكت و أي إيتين نكست",
"hello_world": "مرحباً بالعالم!"
}
Code-Sprache: Diff (diff)
Als Nächstes aktualisieren wir unseren useLocalizeDocumentAttributes
Hook, um den Dokumenttitel festzulegen.
// src/i18n/useLocalizeDocumentAttributes.ts
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
export default function useLocalizeDocumentAttributes() {
- const { i18n } = useTranslation();
+ const { t, i18n } = useTranslation();
useEffect(() => {
if (i18n.resolvedLanguage) {
document.documentElement.lang = i18n.resolvedLanguage;
document.documentElement.dir = i18n.dir(i18n.resolvedLanguage);
}
+ // 👇 Dokumenttitel lokalisieren.
+ document.title = t("app_title");
- }, [i18n, i18n.resolvedLanguage]);
+ }, [i18n, i18n.resolvedLanguage, t]);
}
Code-Sprache: Diff (diff)


Wie mit dynamischen Werten in Übersetzungen gearbeitet wird?
Häufig müssen Strings zur Laufzeit in Übersetzungsnachrichten eingefügt werden. Ein gutes Beispiel dafür ist der Name des eingeloggten Nutzers, z.B. „Hallo, username
!“, wobei username
zur Laufzeit ersetzt und nicht fest in die Nachricht eincodiert werden sollte.
i18next unterstützt das durch Interpolation: Eine Variable wird in einer Übersetzungsnachricht festgelegt und zur Laufzeit ausgetauscht. In unseren Nachrichten wird eine {{variable}}
-Syntax verwendet, um dies zu erreichen. Hinzufügen einer neuen Übersetzungsnachricht mit interpolierten Variablen:
// public/locales/en/translation.json
{
"app_title": "React + i18next Playground",
"hello_world": "Hallo, Welt!"
+ "user_greeting": "Hallo {{firstName}} {{lastName}} 👋"
}
// public/locales/ar/translation.json
{
"app_title": "ملعب ريأكت و أي إيتين نكست",
"hello_world": "مرhaba بالعالم!"
+ "user_greeting": "أهلاً بك {{firstName}} {{lastName}} 👋"
}
Code-Sprache: Diff (diff)
Nun können die Identifikatoren firstName
und lastName
als Parameter verwendet werden, wenn t()
aufgerufen wird, und ihre tatsächlichen Werte zur Laufzeit eingefügt werden.
// In unserer Komponente
import { useTranslation } from "react-i18next";
// Ein fiktiver Dienst nur zur Demonstration.
import { useLoggedInUser } from "../some/fake/service";
export default function MyComponent() {
const { t } = useTranslation();
const user = useLoggedInUser();
return (
<p>
{t("user_greeting", {
// 👇 Diese zur Laufzeit interpolieren.
firstName: user.firstName,
lastName: user.LastName,
})
</p>
);
}
Code-Sprache: TypeScript (typescript)
Der zweite Parameter zu t()
kann eine Map von Werten sein, die zur Laufzeit in die Übersetzungsnachricht eingefügt werden. Es können so viele Werte in einer Nachricht sein, wie gewünscht; es muss nur daran gedacht werden, für jeden in der Nachricht enthaltenen Wert einen Schlüssel/Wert in der Map einzuschließen.
In der Live-StackBlitz-Demo werden Texteingaben genutzt, um die interpolierten Werte zur Laufzeit zu erstellen.
🔗 Probier die StackBlitz-Demo selbst aus. Der Interpolationscode kann auch von GitHub geholt werden.
🤿 Wie gewohnt bietet i18next viele Optionen für die Interpolation, einschließlich der Änderung der {{}}
Spezifizierer, dem Übergeben ganzer Objekte, dem Unescaping von HTML und mehr. Die offiziellen Interpolations Dokumente bieten hier umfassende Informationen.
Mit Pluralen in Übersetzungen arbeiten – so geht’s
Während Englisch einfache Singular- und Pluralformen hat (wie „Apfel“ vs „Äpfel“), gibt es in anderen Sprachen wie Russisch und Arabisch komplexere Pluralregeln. Zum Glück macht i18next diese Komplexität leicht verständlich. Für eine Nachricht im Plural müssen einfach alle Pluralformen in der aktuellen Sprache angegeben werden.
// public/locales/en/translation.json
{
// ...
"trees_grown_one": "Ein Baum 🌳 wurde gepflanzt",
"trees_grown_other": "{{count}} Bäume 🌳 wurden gepflanzt"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
Wieder hat Englisch zwei Pluralformen, eins
und andere
. i18next verwendet eine Suffix-Syntax, um alle Pluralformen für eine Nachricht anzugeben, genau wie oben zu sehen. In unseren Komponenten wird dies als einzelne Nachricht verwendet, wobei die Suffixe vom Schlüssel weggelassen werden.
{/* Hier wird weder _one noch _other verwendet. */}
<p>{t("trees_grown", { count: 3 })}</p>
Code-Sprache: TypeScript (typescript)
Wenn i18next auf die spezielle count
Variable stößt, ist klar, dass es sich um eine Nachricht im Plural handelt, und die passende Pluralform wird basierend auf der count
ausgewählt.
🗒️ Es könnte aufgefallen sein, dass der Nullfall oben eine eigene Nachricht hat. Auch wenn zero
keine offizielle Pluralform im Englischen ist, unterstützt i18next immer den Nullfall. Für das oben Genannte wurde einfach eine trees_grown_zero
Nachricht in unsere englische Übersetzungsdatei hinzugefügt.
Mit komplexen Pluralformen arbeiten
Während viele Sprachen eine | andere
Pluralform haben, haben viele andere keine. Arabisch hat zum Beispiel sechs Pluralformen. Mit i18next lassen sich diese ganz einfach mit derselben Suffix-Syntax hinzufügen.
// public/locales/ar/translation.json
{
// ...
"trees_grown_zero": "Es wurde noch kein Baum gepflanzt.",
"trees_grown_one": "Ein Baum wurde gepflanzt 🌳"
"trees_grown_two": "Zwei Bäume wurden gepflanzt 🌳"
"trees_grown_few": "{{count}} Bäume wurden gepflanzt 🌳"
"trees_grown_many": "{{count}} Bäume wurden gepflanzt 🌳"
"trees_grown_other": "{{count}} Bäume wurden gepflanzt 🌳"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
Auch hier muss der t()
Aufruf nicht geändert werden. t("trees_grown", { count: 1 })
funktioniert genau wie vorher. i18next sieht count
und erkennt, dass eine Pluralform in der aktiven Sprache (hier Arabisch) aufgelöst werden muss.

🗒️ Man könnte sich fragen, wo die Pluralformen für eine unbekannte Sprache zu finden sind. Es gibt ein praktisches Web-Tool, das verwendet werden kann, um die richtigen Suffixe für eine Sprache zu erhalten. Die Hauptquelle ist die Language Plural Rules Auflistung für das CLDR (Common Locale Data Repository).
Die richtigen Zählzahlen verwenden
Bevor es weitergeht, wird hier erst ein Problem behoben: In den obigen arabischen Nachrichten werden die gleichen Ziffern gezeigt, die im Englischen verwendet werden (0, 1, 2, …). In vielen arabischen Regionen sind jedoch die offiziellen Ziffern die östlichen arabischen Ziffern (٠,١,٢, …). Um sicherzustellen, dass i18next die Zählungen für die aktive Locale passend formatiert, muss das number
Format in den Übersetzungsnachrichten angegeben werden.
// public/locales/en/translation.json
{
// ...
"trees_grown_one": "Ein Baum 🌳 wurde gepflanzt",
- "trees_grown_other": "{{count}} Bäume 🌳 wurden gepflanzt"
+ "trees_grown_other": "Es wurden {{count, number}} Bäume 🌳 gepflanzt"
}
// public/locales/ar/translation.json
{
// ...
"trees_grown_zero": "Es wurde noch kein Baum gepflanzt.",
"trees_grown_one": "Ein Baum wurde gepflanzt 🌳"
"trees_grown_two": "Zwei Bäume wurden gepflanzt 🌳"
- "trees_grown_few": "Es wurden {{count}} Bäume gepflanzt 🌳",
Es wurden {{count, number}} Bäume gepflanzt 🌳
- "trees_grown_many": "Es wurden {{count}} Bäume gepflanzt 🌳"
+ "trees_grown_many": "لقد زرعنا {{count, number}} شجرة 🌳",
- "trees_grown_other": "Es wurden {{count}} Bäume 🌳 gepflanzt"
+ "trees_grown_other": "Es wurden {{count, number}} Bäume 🌳 gepflanzt"
}
Code-Sprache: Diff (diff)
Mit diesem Update sehen unsere arabischen Pluralformen korrekt aus.
✋ Tatsächlich ist das keine hundertprozentige Lösung für die Darstellung unserer lokalisierten Anzahl
, da momentan auf die Standard-Region des Browsers für Arabisch beim Formatieren der Zahl zurückgegriffen wird. Das wird im nächsten Abschnitt behoben, wenn ein eigener Zahlenformatierer implementiert wird.
🤿 Tiefer eintauchen mit Pluralbildung: Ein Leitfaden zur Lokalisierung von Pluralen, in dem die leistungsstarke ICU-Nachrichtensyntax und ordinale Pluralformen behandelt werden, während i18next genutzt wird.
🔗 Mit Pluralen in unserer StackBlitz-Demo spielen. Auch der Plural-Code von GitHub kann geholt werden.
Lokalisierte Zahlen formatieren – so geht’s
i18n ist mehr als nur String-Übersetzungen. Der Umgang mit Zahlen und Daten ist für die meisten Apps entscheidend, und jede Region der Welt handhabt die Formatierung von Zahlen und Daten anders.
Ein Hinweis zur regionalen Formatierung
Zahlen- und Datumsformate werden von der Region und nicht nur von der Sprache bestimmt. Zum Beispiel verwenden sowohl die USA als auch Kanada Englisch, aber sie haben unterschiedliche Datumsformate und Maßeinheiten. Es ist besser, eine qualifizierte Locale (wie en-US
) anstelle eines einfachen Sprachcodes (en
) zu nutzen.
Die Verwendung eines Sprachcodes allein, wie zum Beispiel ar
für Arabisch, kann zu Unstimmigkeiten führen. Verschiedene Browser könnten standardmäßig auf verschiedene Regionen wie Saudi-Arabien (ar-SA
) oder Ägypten (ar-EG
) eingestellt sein, was zu unterschiedlichen Datumsformaten aufgrund der verschiedenen regionalen Kalender führt.
In den Tutorials nutzen wir normalerweise qualifizierte Locales (wie en-US
, ar-EG
), um solche Unklarheiten zu vermeiden. Aber i18next kann knifflig sein, wenn mit Fallbacks zu einer qualifizierten Lokalisierung gearbeitet wird: Es fällt immer auf die Version mit nur der Sprache zurück, daher ist es schwierig, eine qualifizierte Locale als Standard-Fallback einzustellen. Also bleiben en
und ar
als unterstützte App-Locales erhalten, und benutzerdefinierte Formatter werden verwendet, um explizite regionale Formatierungen durchzusetzen (mehr zu benutzerdefinierten Formatierern gleich).
🗒️ Alternativ lässt sich eine eigene Fallback-Logik nutzen, um das Beharren von i18next auf rein sprachliche Fallbacks zu umgehen. Im Abschnitt Fallback der i18next-Dokumentation findet sich ein Beispiel für das Erstellen einer benutzerdefinierten Fallback-Funktion.
Zahlen in Nachrichten
Wir haben die Zahlenformatierung schon in unseren Übersetzungsnachrichten behandelt, als wir die count
Variable in unseren Pluralformen formatiert haben. Auf einfachste Weise erhält man die Standard-Nummernformatierung, indem man den number
Formatbezeichner für eine interpolierte Zahl in einer Nachricht bereitstellt:
// public/locales/en/translation.json
{
// ...
"simple_number": "Eine einfache Zahl (Standardformatierung): {{value, number}}"
}
// public/locales/ar/translation.json
{
// ...
"simple_number": "Zahl im Standardformat: {{value, number}}"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
Und in den Komponenten:
<p>{t("simple_number", { value: 2.04 })</p>
Code-Sprache: TypeScript (typescript)


Der number-Formatter, den i18next zur Verfügung stellt, nutzt im Hintergrund das JavaScript-Standardobjekt Intl.NumberFormat. Intl.NumberFormat ermöglicht viele Formatierungsoptionen, die alle zur Verfügung stehen, wenn der number Formatter verwendet wird. Es müssen nur die Optionen mit einer number(option1: value1; option2: value2 ...)
-Syntax angegeben werden. Hier ein paar Beispiele:
// public/locales/en/translation.json
{
// ...
"simple_number": "Eine einfache Zahl (Standardformatierung): {{value, number}}",
"percent": "Prozentsatz (Werte zwischen 0 und 1 verwenden): {{value, number(style: percent)}}",
"custom_number": "Individuelle Formatierung: {{value, number(minimumFractionDigits: 2; maximumFractionDigits: 4; signDisplay: always)}}"
}
// In unseren Komponenten
<p>{t("simple_number", value: 0.333333)}</p>
<p>{t("percent", value: 0.333333)}</p>
<p>{t("custom_number", value: 0.333333)}</p>
Code-Sprache: TypeScript (typescript)
Mit number(...)
wird jedes Schlüssel/Wert-Paar zwischen den Klammern im zweiten options
-Parameter des Intl.NumberFormat
-Konstruktors durchgereicht.
🔗 Alle verfügbaren Optionen sind in der MDN-Dokumentation für Intl.NumberFormat zu finden.
Natürlich sollten auch die anderen Sprachen nicht vergessen werden:
// public/locales/ar/translation.json
{
// ...
"simple": "Zahl im Standardformat: {{value, number}}",
"percent": "Prozentsatz (Verwende Werte zwischen 0 und 1): {{value, number(style: percent)}}",
"custom_number": "Benutzerdefiniertes Format: {{value, number(minimumFractionDigits: 2; maximumFractionDigits: 4; signDisplay: always)}}"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
🤿 Natürlich können Währungen auch auf diese Weise formatiert werden. i18next bietet auch eine Währungsabkürzung: {{value, currency(USD)}}
. Erfahre mehr darüber, einschließlich wie Optionen für die Zahlenformatierung beim Aufruf von t()
übergeben werden, in den offiziellen Zahlenformatierungs Dokumenten.
Eigene Formatierer
Um das Problem der regionalen Mehrdeutigkeit, das im obigen Abschnitt erwähnt wurde, zu lösen, können die eigenen Formatter von i18next genutzt und ein eigener für Zahlen erstellt werden. Dieser eigene Formatter überschreibt den standardmäßigen number
Formatter, der von i18next bereitgestellt wird, und stellt sicher, dass immer eine qualifizierte Locale (z.B. ar-EG
) verwendet wird, wenn Zahlen formatiert werden.
Nicht vergessen, wenn wir das nicht machen, überlassen wir es dem Browser, die Region zu bestimmen. Zum Beispiel zeigt der Arc-Browser (Chrome-basiert) unsere arabischen Zahlen als 0, 1, 2 Ziffern. Wie bereits erwähnt, bevorzugen viele arabische Regionen das Ziffernsystem ١، ٢، ٣ (östliches Arabisch).

Dies liegt wahrscheinlich an der standardmäßigen Region, die Arc für Arabisch voraussetzt.
OK, nun zur Lösung. Es sollte eine neue Datei erstellt werden, um unsere benutzerdefinierten Formatierer zu speichern und unseren Zahlenformatierer hinzuzufügen.
// src/i18n/formatters.tsx
/**
* Gibt den standardmäßigen qualifizierten Locale-Code zurück
* (Sprache-REGION) für die gegebene Locale.
*
* @param lng - Der Sprachcode.
* @returns Der qualifizierte Locale-Code,
* einschließlich Region.
*/
function qualifiedLngFor(lng: string): string {
switch (lng) {
// Ägypten als Standardformatierung verwenden
// Region für Arabisch.
case "ar":
return "ar-EG";
// USA als Standardformat verwenden
// Region für Englisch
case "en":
return "en-US";
default:
return lng;
}
}
/**
* Eine Zahl formatieren.
*
* @param value - Die Zahl zum Formatieren.
* @param lng - Die Sprache, in der die Zahl formatiert werden soll.
* @param options - an Intl.NumberFormat übergeben.
* @returns die formatierte Zahl.
*/
export function number(
value: number,
lng: string | undefined,
options?: Intl.NumberFormatOptions,
): string {
return new Intl.NumberFormat(
qualifiedLngFor(lng!),
options,
).format(value);
}
Code-Sprache: TypeScript (typescript)
Der neue Zahlenformatierer wird mit der i18next-Instanz verbunden:
// src/i18n/config.ts
import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import HttpApi from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
+ import { number } from "./formatters";
// ...
i18next
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init({
// ...
});
+ i18next.services.formatter?.add("number", number);
export default i18next;
Code-Sprache: Diff (diff)
Wenn die number
oder number(...)
Spezifizierer in Übersetzungsnachrichten genutzt werden, kommt der individuelle Zahlenformatierer von i18next anstelle des Standardformatierers zum Einsatz. Die Bibliothek übergibt der Formatierungsfunktion Folgendes:
value
— Die zur Laufzeit zu interpolierende und zu formatierende Zahl.lng
— Die aktive aufgelöste Spracheinstellung,en
oderar
.options
— Alle Optionen, die wir in Klammern angegeben haben, alsnumber(...)
aufgerufen wurde. Diese werden in ein Optionsobjekt umgewandelt, das für denIntl.NumberFormat
-Konstruktor bereit ist.
🔗 Im Abschnitt Hinzufügen einer benutzerdefinierten Formatfunktion in den offiziellen Dokumenten gibt es weitere Infos, einschließlich wie benutzerdefinierte Formatierer für die Performance zwischengespeichert werden können.
In der Formatierungsfunktion nehmen wir diese Werte und verwenden unsere eigene Instanz des Standard-Intl.NumberFormat
-Objekts, um die Zahl zu formatieren. Es wird sichergestellt, dass die Locale, die an Intl.NumberFormat
übergeben wird, immer eine explizite Region hat, indem qualifiedLngFor()
genutzt wird.
Mit dem neu konfigurierten Formatierer wird der Arc-Browser jetzt die Region Ägypten beim Formatieren der arabischen Zahlen berücksichtigen. Tatsächlich sollte dieses Verhalten jetzt in allen Browsern einheitlich sein.

Es wird bemerkt, dass der Währungswert immer noch westliche arabische Ziffern (1, 2, 3) verwendet. Das liegt daran, dass es mit dem Kurzform-currency
-Formatierer von i18next formatiert wird:
// public/locales/ar/translation.json
{
// ...
"currency": "Währungsformat: {{value, currency(USD)}}"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
Um das zu beheben, wird einfach ein weiterer benutzerdefinierter Formatierer benötigt, der currency
überschreibt:
// src/i18n/formatters.tsx
function qualifiedLngFor(lng: string): string {
switch (lng) {
case "ar":
return "ar-EG";
case "en":
return "en-US";
default:
return lng;
}
}
export function number(
value: number,
lng: string | undefined,
options?: Intl.NumberFormatOptions,
): string {
return new Intl.NumberFormat(
qualifiedLngFor(lng!),
options,
).format(value);
}
+ export function currency(
+ value: number,
+ lng: string | undefined,
+ options?: Intl.NumberFormatOptions,
+ ): string {
+ // Der oben genannte Zahlenformatierer sollte verwendet werden...
+ return number(value, lng, {
+ // ...aber sicherstellen, dass wir formatieren
+ // als Währung formatiert.
+ style: "currency",
+ ...options,
+ });
+ }
Code-Sprache: Diff (diff)
Natürlich muss dieser neue Formatierer verbunden werden, damit er wirksam wird:
// src/i18n/config.ts
//...
- importiere { number } von "./formatters";
+ import { currency, number } from "./formatters";
// ...
i18next
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init({
// ...
});
i18next.services.formatter?.add("number", number);
+ i18next.services.formatter?.add("currency", currency);
export default i18next;
Code-Sprache: Diff (diff)
Damit wird sichergestellt, dass der Währungs
Kurzformatierer die neuen expliziten Regionen beim Formatieren berücksichtigt:

🔗 Mit der live StackBlitz-Demo lassen sich lokalisierte Zahlenformate testen, einschließlich eigenständiger Zahlen (außerhalb von Übersetzungsnachrichten). Der Zahlencode von GitHub kann auch abgerufen werden.
🤿 Der Kurze Leitfaden zur Lokalisierung von Zahlen geht detailliert auf Zahlensysteme und andere Aspekte von lokalisierten Zahlen ein.
So wird das Formatieren von lokalisierten Daten durchgeführt
Um den Ausflug in die Formatierung abzurunden, sollten die Datumsangaben lokalisiert werden.
✋ Dieser Abschnitt baut auf dem vorherigen auf, daher sollte der Abschnitt über Zahlen zuerst gelesen werden.
Wie wahrscheinlich schon vermutet, stellt i18next einen eingebauten Datumsformatierer für die Nachrichten zur Verfügung. Es wird datetime
genannt und nutzt im Hintergrund das Standardobjekt Intl.DateTimeFormat. So kann es genutzt werden:
// public/locales/en/translation.json
{
// ...
"simple_date": "Ein einfaches Datum (Standardformat): {{value, datetime}}"
}
// public/locales/ar/translation.json
{
// ...
"simple_date": "تاريخ بسيط (التنسيق الافتراضي): {{value, datetime}}"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)
In den Komponenten muss entweder ein Date-Objekt oder ein UTC-Timestamp als Wert zum Formatieren bereitgestellt werden:
// In den Komponenten
{/* Ein `Date`-Objekt wird verwendet. */}
<p>
{t("simple_date", {
value: new Date("2024-01-25"),
})}
</p>
{/* Verwendung eines UTC-Timestamps `number` */}
<p>
{t("simple_date", { value: 1706140800000 })}
</p>
Code-Sprache: TypeScript (typescript)
Die oben genannten Daten sind gleichwertig, so behandelt der datetime
Formatierer sie als identisch:


Ein individueller Datums- und Zeitformatierer
Wie bei Zahlen sind auch Daten regionsabhängig. Einige Regionen sprechen vielleicht dieselbe Sprache, verwenden aber völlig unterschiedliche Kalender. Genau wie bei Zahlen, wenn kein Datum für Intl.DateTimeFormat
angegeben wird — das vom datetime
Formatierer von i18next im Hintergrund verwendet wird — überlassen wir es dem Browser, die Region für uns zu bestimmen. Dies kann zu uneinheitlicher Formatierung zwischen Browsern führen. Hier ist ein Beispiel dafür, wie der Arc-Browser die oben genannten arabischen Daten formatiert.

Für Zahlen wurde dieses Problem bereits gelöst. Es muss lediglich ein neuer Formatter für unsere Datumsangaben hinzugefügt werden.
// src/i18n/formatters.tsx
// ...
function qualifiedLngFor(lng: string): string {
switch (lng) {
case "ar":
return "ar-EG";
case "en":
return "en-US";
default:
return lng;
}
}
// ...
+ /**
+ * Formatiert ein Datum und eine Uhrzeit.
+ *
+ * @param value - Das Datum, das formatiert werden soll.
+ * @param lng - Die Sprache, in der die Zahl formatiert wird.
+ * @param options - an Intl.DateTimeFormat übergeben.
+ * @returns Das formatierte Datum und die Uhrzeit.
+ */
+ export function datetime(
+ value: Datum | Nummer
+ lng: string | undefined,
+ options?: Intl.DateTimeFormatOptions,
+ ): string {
+ return new Intl.DateTimeFormat(
+ qualifiedLngFor(lng!),
+ options,
+ ).format(value);
+ }
// ...
Code-Sprache: Diff (diff)
Unser benutzerdefinierter Datumsformatierer nutzt qualifiedLngFor
genau wie unsere benutzerdefinierten Zahlenformatierer. Beim Formatieren von Datumsangaben wird immer explizit eine Region verwendet: USA für Englisch und Ägypten für Arabisch.
Unser Formatierer wird zur i18next
-Instanz hinzugefügt, um den Standard-datetime
-Formatierer zu ersetzen:
// src/i18n/config.ts
//...
- import { currency, number } von "./formatters";
+ import { datetime, currency, number } von "./formatters";
// ...
i18next
.use(HttpApi)
.use(LanguageDetector)
.use(initReactI18next)
.init({
// ...
});
i18next.services.formatter?.add("number", number);
i18next.services.formatter?.add("currency", currency);
+ i18next.services.formatter?.add("datetime", datetime);
export default i18next;
Code-Sprache: Diff (diff)

Änderung des Datumsformats
Ähnlich wie bei Zahlen, können für den datetime
Formatter Optionen festgelegt werden, die dann an den Intl.DateTimeFormat-Konstruktor weitergegeben werden.
// public/locales/en/translation.json
{
// ...
"long_date": "Langes Datumsformat: {{value, datetime(dateStyle: long)}}",
"custom_date": "Benutzerdefiniertes Datumsformat: {{value, datetime(weekday: long; year: 2-digit; month: short; day: numeric)}}"
}
// In unseren Komponenten
<p>
{t("long_date", { value: new Date("2024-01-25") })}
</p>
<p>
{t("custom_date", {
value: new Date("2024-01-25"),
})}
</p>
Code-Sprache: TypeScript (typescript)
🔗 In der MDN-Dokumentation für Intl.DateTimeFormat sind alle verfügbaren Formatierungsoptionen aufgeführt.
Hier ist die arabische Version:
// public/locales/ar/translation.json
{
// ...
"long_date": "Format der langen Datumsangabe: {{value, datetime(dateStyle: long)}}",
"custom_date": "Benutzerdefiniertes Datumsformat: {{value, datetime(weekday: long; year: 2-digit; month: short; day: numeric)}}"
}
Code-Sprache: JSON / JSON mit Kommentaren (json)

🔗 Im i18next Formatierungs Guide gibt es mehr Infos zur Datumsformatierung, einschließlich relativer Daten.
🔗 In der Live-StackBlitz-Demo gibt es einen Date-Playground, wo verschiedene Daten getestet und in unterschiedlichen Formaten und Lokalisierungen dargestellt werden können.
🔗 Der Datencode und der Code für den Rest der Demo-App sind im GitHub-Repo zu finden.
Weiterlesen
Hier gibt es weitere Artikel zu React + i18next:
- Ein Schritt-für-Schritt-Leitfaden zur Internationalisierung von Next.js behandelt die Lokalisierung des Next.js Page Routers mit i18next.
- Ein React I18n Experiment mit Storybook und i18next zeigt, wie mit i18next gearbeitet wird, um Komponenten isoliert mit Storybook zu lokalisieren.
🔗 Natürlich lohnt es sich immer, den offiziellen React i18next-Leitfaden anzuschauen.
Bring deine Lokalisierung auf das nächste Level
Wir hoffen, dass dieser Leitfaden zur Lokalisierung von React-Apps mit i18next Spaß gemacht hat und hilfreich war.
Sobald mit der Übersetzung begonnen werden kann, übernimmt Phrase Strings die schwere Arbeit. Mit zahlreichen Tools zur Automatisierung des Übersetzungsprozesses und nativen Integrationen mit Plattformen wie GitHub, GitLab und Bitbucket, macht Phrase Strings die Übernahme und Verwaltung von Inhalten in seinem benutzerfreundlichen String-Editor einfach.
Sobald die Übersetzungen bereit sind, können sie mit einem einzigen Befehl oder automatisch in das Projekt zurückgeholt werden, so dass der Fokus auf dem geliebten Code bleibt. Jetzt kostenlose Testversion starten und selbst sehen, warum Entwickler Phrase Strings für die Software-Lokalisierung so gerne nutzen.