12. Internationalisierung
Internationalisierung
Abschnitt betitelt „Internationalisierung“Zwei Begriffe, die oft verwechselt werden. Internationalisierung (i18n) ist die Vorbereitung: Die Anwendung wird so gebaut, dass sie überhaupt in einer anderen Sprache laufen kann, ohne dass jemand Code ändert. Lokalisierung (l10n) ist die konkrete Anpassung an eine Sprache und Region: die Übersetzung, das Datumsformat, die Währung.
Das Erste ist eine Architekturentscheidung, das Zweite Fleißarbeit. Und deshalb steht dieses Kapitel hier und nicht am Jahresende: Eine Anwendung nachträglich zu internationalisieren bedeutet, jeden Text, jedes Datum und jede Zahl im ganzen Projekt einzeln anzufassen. Wer es von Anfang an mitdenkt, zahlt fast nichts.
Was alles sprachabhängig ist
Abschnitt betitelt „Was alles sprachabhängig ist“Die erste Überraschung liegt darin, wie wenig davon Text ist.
| Bereich | Deutsch (AT) | Englisch (US) |
|---|---|---|
| Datum | 12.03.2026 | 3/12/2026 |
| Uhrzeit | 14:30 | 2:30 PM |
| Dezimaltrennzeichen | 1.234,50 | 1,234.50 |
| Währung | 12,50 € | $12.50 |
| Erster Wochentag | Montag | Sonntag |
| Sortierung | Ä bei A | keine Umlaute |
| Adresse | Straße, dann Hausnummer | Hausnummer, dann Straße |
Dazu kommen Zeitzonen, Maßeinheiten, Namensreihenfolge und Papierformate. Und eine Ebene darunter liegen die kulturellen Fragen, die keine Bibliothek löst: Symbole werden nicht überall gleich verstanden (das Briefkastensymbol für „Nachricht” ist ein amerikanischer Briefkasten), Farben tragen unterschiedliche Bedeutungen, und Beispieldaten in Formularen sollten zur Region passen.
Ein Sonderfall betrifft das Deutsche direkt: die Anrede. Sie und du sind zwei verschiedene Grundhaltungen, und im Englischen gibt es diese Entscheidung nicht. Sie treffen sie einmal für das ganze Projekt und halten sie durch; ein Wechsel mitten in der Anwendung fällt sofort auf.
Sprachen im Routing
Abschnitt betitelt „Sprachen im Routing“| Strategie | Beispiel | Bewertung |
|---|---|---|
| Unterpfad | example.at/de/buchungen | einfach, ein Zertifikat, gut für Suchmaschinen |
| Unterdomain | de.example.at | getrennt betreibbar, mehr Aufwand bei Zertifikat und Cookies |
| Länderdomain | example.at, example.de | stärkstes Signal je Land, teuerste Variante |
Für Ihr Projekt ist der Unterpfad die richtige Wahl: eine Domain, ein Zertifikat, ein Deployment, und die Sprache steht sichtbar in der Adresse.
Die Spracherkennung folgt einer festen Rangfolge. Was der Benutzer ausdrücklich gewählt hat, gewinnt immer und wird gespeichert. Ist nichts gewählt, dient der Kopf Accept-Language des Browsers als Vorschlag. Ist auch der unbrauchbar, greift die Vorgabesprache. Ein häufiger Fehler ist, Accept-Language als Gesetz zu behandeln und die Wahl des Benutzers bei jedem Aufruf zu überschreiben.
Für Suchmaschinen kommen zwei Angaben dazu: hreflang benennt für jede Seite ihre Entsprechungen in den anderen Sprachen, und der kanonische Verweis zeigt auf die jeweils eigene Sprachfassung. Wie das in einen Auftritt eingebaut wird, vertieft die 5. Klasse.
In Next.js übernimmt eine Bibliothek wie next-intl die Verdrahtung: ein [locale]-Segment im App Router, eine Middleware, die Sprachen erkennt und umleitet, und Nachrichtenkataloge, die sowohl in Server- als auch in Client-Komponenten erreichbar sind.
Nachrichten schreiben
Abschnitt betitelt „Nachrichten schreiben“Nachrichten stehen in Katalogen, einer je Sprache, und werden über Schlüssel angesprochen.
{ "booking": { "title": "Buchungen", "count": "{n, plural, =0 {Keine Buchungen} one {# Buchung} other {# Buchungen}}", "confirmed": "Ihre Buchung für {machine} am {date, date, long} wurde bestätigt.", "canceledBy": "{gender, select, f {Sie hat} m {Er hat} other {Die Person hat}} storniert." }}Das Format heißt ICU-MessageFormat und kann drei Dinge, die man sonst mühsam nachbaut: Platzhalter, Pluralformen und Auswahl nach einem Merkmal.
Die Pluralregeln sind der eigentliche Grund für dieses Format. Deutsch und Englisch haben zwei Formen, und deshalb kommt man mit if (n === 1) erstaunlich weit. Polnisch hat vier, Arabisch sechs, Japanisch eine. Wer die Fallunterscheidung in den Code schreibt, hat sie in der falschen Sprache getroffen, denn welche Formen es gibt, ist eine Eigenschaft der Zielsprache und nicht der Anwendung.
Zwei Konventionen ersparen später Arbeit. Die Schlüssel werden nach Bereich hierarchisch benannt (booking.count) und sind nicht der deutsche Satz selbst; sonst bricht bei jeder Textkorrektur die Zuordnung. Und fehlende Übersetzungen fallen auf die Vorgabesprache zurück, werden dabei aber sichtbar gemacht, im Entwicklungsmodus deutlich markiert und im Build als Warnung. Eine stille Lücke bleibt sonst ein Jahr lang stehen.
Formatierung
Abschnitt betitelt „Formatierung“Alles, was mit Zahlen und Zeit zu tun hat, kann der Browser selbst. Eigene Formatierungsfunktionen sind an dieser Stelle immer schlechter.
| Werkzeug | Wofür |
|---|---|
Intl.DateTimeFormat | Datum und Uhrzeit, mit Zeitzone |
Intl.NumberFormat | Zahlen, Währung, Prozent, Einheiten |
Intl.RelativeTimeFormat | „vor 3 Tagen”, „in 2 Stunden” |
Intl.ListFormat | „A, B und C” gegen „A, B, and C” |
Intl.Collator | sprachrichtiges Sortieren und Vergleichen |
new Intl.NumberFormat("de-AT", { style: "currency", currency: "EUR" }).format(12.5);// "12,50 €"
new Intl.DateTimeFormat("de-AT", { dateStyle: "long", timeStyle: "short", timeZone: "Europe/Vienna",}).format(new Date("2026-03-12T13:30:00Z"));// "12. März 2026 um 14:30"Zeitzonen
Abschnitt betitelt „Zeitzonen“Die Regel lautet: in UTC speichern, lokal anzeigen. Die Datenbank kennt keine Sommerzeit, der Browser weiß, wo der Benutzer sitzt.
Der klassische Fehler betrifft Daten ohne Uhrzeit. Ein Geburtstag oder ein Feiertag ist kein Zeitpunkt, sondern ein Kalenderdatum. Wird 2026-03-12 als 2026-03-12T00:00:00Z gespeichert und in einer westlichen Zeitzone angezeigt, steht dort der 11. März. Solche Werte bleiben als reines Datum ohne Zeitzone erhalten, in der Datenbank als date und in JSON als "2026-03-12".
Mehrsprachige Inhalte
Abschnitt betitelt „Mehrsprachige Inhalte“Hier trennen sich zwei Dinge, die leicht durcheinandergeraten.
Oberflächentexte sind Beschriftungen, Meldungen und Schaltflächen. Sie gehören in die Kataloge, ändern sich mit dem Code und werden von Entwicklern und Übersetzern gepflegt.
Inhalte sind Nachrichten, Beschreibungen, Hausordnungen, Maschinenbeschreibungen. Sie gehören in die Datenbank oder ins CMS aus Kapitel 14 und werden von der Redaktion gepflegt, ohne dass jemand ein Deployment auslöst.
Für übersetzbare Inhalte in der eigenen Datenbank braucht es ein Datenmodell. Der übliche Weg ist eine Übersetzungstabelle:
model Machine { id Int @id @default(autoincrement()) internalNumber String texts MachineTranslation[]}
model MachineTranslation { machineId Int locale String // "de", "en" name String description String? machine Machine @relation(fields: [machineId], references: [id])
@@id([machineId, locale])}Drei Fragen gehören dazu: Was passiert, wenn eine Übersetzung fehlt (Rückfall auf die Vorgabesprache, sichtbar gekennzeichnet)? Kann eine Sprache freigegeben sein und eine andere noch in Arbeit (Redaktionsstatus je Sprache)? Und wie wird sortiert und gesucht? Sortierung läuft über Intl.Collator oder die passende Sortierfolge in PostgreSQL, und eine Volltextsuche braucht je Sprache ihre eigene Konfiguration, weil Wortstämme sprachabhängig sind.
Prozess und Prüfung
Abschnitt betitelt „Prozess und Prüfung“Zwei organisatorische Festlegungen gehören ins Repository: wer übersetzt, und wie Texte hin- und zurückkommen. Für ein Schulprojekt genügt es, die Kataloge im Repository zu pflegen und Änderungen über Merge Requests laufen zu lassen.
Prüfbar machen lässt sich das im Build. Ein Skript vergleicht die Kataloge und meldet fehlende Schlüssel (in einer Sprache vorhanden, in der anderen nicht) und verwaiste Schlüssel (im Katalog, im Code nirgends verwendet). Beides als Fehler in der Pipeline aus Kapitel 3 verhindert, dass unübersetzte Stände unbemerkt in die Produktion gehen.
Zwei Randfälle
Abschnitt betitelt „Zwei Randfälle“Rechts-nach-links. Arabisch und Hebräisch laufen von rechts nach links, und damit spiegelt sich das Layout. Wer von Anfang an logische CSS-Eigenschaften benutzt (margin-inline-start statt margin-left, padding-inline statt padding-left/right), bekommt das fast geschenkt. Gespiegelt werden auch Richtungssymbole wie Pfeile, nicht aber Uhren, Logos oder Abspielsymbole. Für Ihr Projekt ist das eine Übung zum Verständnis und keine Pflicht.
Textlänge. Deutsche Texte sind gegenüber englischen im Schnitt spürbar länger, einzelne Beschriftungen um mehr als die Hälfte. Ein Knopf, der auf „Save” zugeschnitten wurde, platzt bei „Speichern unter”. Layouts brauchen deshalb Luft, und die Prüfung ist einfach: Stellen Sie die Anwendung auf die Sprache mit den längsten Texten um und sehen Sie sich die schmalste Ansicht an.
Häufige Stolperfallen
Abschnitt betitelt „Häufige Stolperfallen“- Sätze aus Fragmenten zusammensetzen. In anderen Sprachen stimmt die Wortstellung nicht, und Übersetzer sehen keinen Zusammenhang.
- Plural mit
if (n === 1). Funktioniert in zwei Sprachen und in vielen anderen nicht. - Datum ohne Uhrzeit als Zeitpunkt speichern. Der Geburtstag rutscht je nach Zeitzone auf den Vortag.
- Zeiten lokal statt in UTC speichern. Spätestens bei der Zeitumstellung entstehen doppelte oder fehlende Stunden.
- Den deutschen Satz als Übersetzungsschlüssel verwenden. Die erste Textkorrektur bricht die Zuordnung in allen Sprachen.
- Sprachumschalter, der auf die Startseite springt. Der Benutzer verliert seinen Kontext.
Accept-Languageüber die ausdrückliche Wahl stellen. Die Anwendung wechselt dann bei jedem Besuch zurück.- Fehlende Übersetzungen still zurückfallen lassen. Niemand bemerkt, dass die halbe Anwendung einsprachig ist.
Lernergebnisse
Abschnitt betitelt „Lernergebnisse“- Erklären: Internationalisierung und Lokalisierung unterscheiden und begründen, warum die Vorbereitung früh erfolgt.
- Analysieren: benennen, welche Bestandteile einer Anwendung außer Texten sprachabhängig sind.
- Beurteilen: eine Routing-Strategie für Sprachen begründet wählen.
- Anwenden: eine Anwendung mit sprachabhängigem Routing und Nachrichtenkatalogen ausliefern.
- Anwenden: ICU-MessageFormat mit Platzhaltern, Pluralformen und Auswahl korrekt einsetzen.
- Erklären: begründen, warum Sätze nicht aus Fragmenten zusammengesetzt werden.
- Anwenden: Datum, Zahl, Währung und relative Zeiten mit den Intl-Schnittstellen formatieren.
- Anwenden: Zeitpunkte in UTC speichern und lokal anzeigen sowie reine Kalenderdaten korrekt behandeln.
- Beurteilen: entscheiden, welche Texte in den Katalog und welche Inhalte in Datenbank oder CMS gehören.
- Erschaffen: ein Datenmodell für übersetzbare Inhalte mit Rückfallsprache entwerfen.
Arbeit am Jahresprojekt
Abschnitt betitelt „Arbeit am Jahresprojekt“- Das Projekt ist in mindestens zwei Sprachen bedienbar, die Sprache steht im Pfad.
- Der Sprachumschalter bleibt auf der aktuellen Seite, die Wahl wird gespeichert.
- Datum, Zahlen und Währung sind über
Intlformatiert, Zeitpunkte liegen in UTC in der Datenbank. - Mindestens eine Nachricht nutzt Pluralformen über ICU.
- Mindestens ein inhaltliches Feld ist übersetzbar modelliert, mit Rückfall auf die Vorgabesprache.
- Ein Prüfskript meldet fehlende und verwaiste Übersetzungsschlüssel in der Pipeline.
Passende Übungen
Abschnitt betitelt „Passende Übungen“- Aufgabe - Zweite Sprache nachrüsten
- Aufgabe - Plural und Platzhalter mit ICU
- Aufgabe - Datum, Zeitzone und Formatierung