Engineering//8 Min. Lesezeit

i18n Health Checks: Fehlende Übersetzungen erkennen, bevor sie live gehen

Eray Gündoğmuş
Teilen

Fehlende Übersetzungen sind die Art von Fehler, die durch jede Stufe Ihrer Pipeline schlüpft. Unit-Tests bestehen, weil sie keine Übersetzungsdateien prüfen. Integrationstests bestehen, weil sie in der Standardsprache laufen. QA besteht, weil manuelle Tests selten alle zwölf Sprachen abdecken. Und dann sieht ein Nutzer in Brasilien checkout.confirm_button, wo eine Schaltflächenbeschriftung stehen sollte, und Sie erhalten einen Fehlerbericht, der Ihr Team nachlässig wirken lässt.

Das Problem ist nicht, dass Teams Übersetzungen vergessen. Es ist, dass es keine automatisierte Prüfung gibt, die Übersetzungslücken erkennt, so wie ein Typprüfer Typfehler oder ein Linter Code-Style-Probleme erkennt. Ihr Code hat ESLint, Prettier, TypeScript und eine vollständige CI-Pipeline. Ihre Übersetzungen haben... eine JSON-Datei, die hoffentlich jemand zu aktualisieren gedacht hat.

Dieser Beitrag beschreibt, wie automatisierte i18n Health Checks implementiert werden, die fehlende Übersetzungen, Platzhalter-Mismatches, verwaiste Schlüssel und hartcodierte Zeichenketten erkennen, bevor sie die Produktion erreichen.


Was prüft ein i18n Health Check eigentlich?

Ein umfassender i18n Health Check bewertet vier Dimensionen Ihres Übersetzungs-Setups:

1. Abdeckung: Sind alle Schlüssel übersetzt?

Die Abdeckung ist die einfachste und wirkungsvollste Prüfung. Für jeden Übersetzungsschlüssel, der in Ihrem Quellcode verwendet wird: Existiert eine Übersetzung in jeder Zielsprache?

Quellcode-Referenzen: 1.247 Schlüssel
Englisch (Quelle):    1.247/1.247 (100%)
Spanisch:             1.235/1.247 (99%)
Französisch:          1.198/1.247 (96%)
Japanisch:            1.150/1.247 (92%)
Koreanisch:           1.089/1.247 (87%)

Eine Abdeckungsprüfung erkennt das häufigste Szenario: Ein Entwickler fügt eine neue Funktion hinzu, schreibt die englischen Zeichenketten und wechselt zur nächsten Aufgabe. Die Schlüssel landen in der englischen JSON-Datei, werden aber nie zur Übersetzung eingereicht. Ohne eine Abdeckungsprüfung bleibt die Lücke unsichtbar, bis ein Nutzer auf sie stößt.

Abdeckungsprüfungen erkennen auch Namespace-Mismatches. Wenn Ihr Code auf t('checkout.confirm') verweist, der checkout-Namespace aber für Koreanisch nicht existiert, ist das eine Abdeckungslücke, die koreanischen Nutzern einen Rohschlüssel anzeigt.

2. Qualität: Sind Übersetzungen strukturell korrekt?

Die Abdeckung sagt Ihnen nur, ob eine Übersetzung existiert. Die Qualität sagt Ihnen, ob sie zur Laufzeit korrekt funktioniert.

Die kritischste Qualitätsprüfung ist die Platzhaltervalidierung. Wenn Ihre englische Zeichenkette lautet:

"You have {count} items in your cart, {name}."

Dann muss jede Übersetzung dieser Zeichenkette exakt {count} und {name} enthalten. Ein französischer Übersetzer, der {nombre} statt {count} schreibt, erzeugt einen Laufzeitfehler — die Interpolations-Engine findet keinen Wert für {nombre} und zeigt entweder den Rohplatzhalter an oder wirft einen Fehler.

Weitere Qualitätsprüfungen umfassen:

  • Leere Werte: Schlüssel, die in einer Sprachdatei vorhanden sind, aber leere Zeichenketten haben. Das deutet meist auf programmatische Schlüsselerstellung ohne tatsächliche Übersetzung hin.
  • Quellenidentische Zeichenketten: Übersetzungen, die Zeichen für Zeichen identisch mit der Quellsprache sind. Manche Zeichenketten (Markennamen, URLs) sind legitimerweise identisch, aber eine hohe Anzahl bedeutet meist nicht übersetzten Inhalt.
  • Übermäßige Länge: Übersetzungen, die deutlich länger als die Quelle sind und UI-Container überlaufen lassen können. Deutsche Übersetzungen sind bekanntermaßen 30–40 % länger als englische.

3. Struktur: Sind Übersetzungsdateien sauber?

Strukturprüfungen bewerten die Organisation und Hygiene Ihrer Übersetzungsdateien:

  • Verwaiste Schlüssel: Schlüssel, die in Übersetzungsdateien vorhanden sind, aber im Quellcode nie referenziert werden. Diese häufen sich an, wenn Funktionen entfernt, aber Übersetzungsdateien nicht bereinigt werden. Sie verschwenden den Aufwand der Übersetzer und erzeugen Verwirrung.
  • Doppelte Schlüssel: Derselbe Schlüssel, der in einer einzigen Datei zweimal definiert wird. JSON meldet bei doppelten Schlüsseln keinen Fehler — es wird stillschweigend der letzte verwendet, was zu verwirrendem Verhalten führen kann.
  • Benennungsinkonsistenz: Wenn 90 % Ihrer Schlüssel snake_case verwenden, aber einige camelCase, macht die Inkonsistenz Schlüssel schwerer zu finden und zu pflegen.

4. Code: Sind Zeichenketten ordnungsgemäß internationalisiert?

Code-Analyse verwendet AST-Parsing, um hartcodierte Zeichenketten in Ihren Quelldateien zu finden, die in Übersetzungsfunktionen eingewickelt werden sollten.

// Markiert: hartcodierte benutzerseitige Zeichenkette
<h1>Welcome to our app</h1>

// Nicht markiert: korrekt internationalisiert
<h1>{t('home.welcome_title')}</h1>

// Nicht markiert: nicht benutzerseitig (CSS-Klasse, Datenattribut)
<div className="container" data-testid="home">

Diese Prüfung erkennt i18n-Schulden an der Quelle. Neue Entwickler, die mit Ihrem i18n-Setup nicht vertraut sind, schreiben hartcodierte Zeichenketten. Ohne eine automatisierte Prüfung bleiben diese Zeichenketten bestehen, bis jemand sie bei einem Übersetzungs-Audit bemerkt.


Der Health Score: Komplexität auf eine Zahl reduzieren

Einzelne Prüfungen erzeugen detaillierte Berichte, aber für die CI-Integration und Trendverfolgung brauchen Sie eine einzige Zahl: den Health Score.

Ein gut konzipierter Health Score gewichtet Kategorien nach ihrer Auswirkung auf den Nutzer:

KategorieGewichtungBegründung
Abdeckung40%Fehlende Übersetzungen betreffen Nutzer direkt
Qualität30%Platzhalter-Bugs verursachen Laufzeitfehler
Struktur20%Verwaiste Schlüssel verschwenden Aufwand, brechen aber nicht die UX
Code10%Hartcodierte Zeichenketten sind Schulden, kein sofortiger Ausfall

Ein Projekt mit 87/100 könnte sich so aufteilen:

Gesamt: 87/100 BESTANDEN

Abdeckung    92/100  ████████████████████  3 fehlende Schlüssel
Qualität     85/100  █████████████████░░░  2 Platzhalter-Mismatches
Struktur     78/100  ███████████████░░░░░  12 verwaiste Schlüssel
Code         90/100  ██████████████████░░  4 hartcodierte Zeichenketten

Der Bestehen/Nichtbestehen-Schwellenwert ist konfigurierbar. Ein Schwellenwert von 80 ist für die meisten Teams praktisch — streng genug, um echte Probleme zu erkennen, und tolerant genug, dass kleinere Warnungen keine Deployments blockieren.


i18n Health Checks in CI/CD einrichten

Der eigentliche Wert von Health Checks entsteht dadurch, dass sie automatisch bei jedem Pull Request ausgeführt werden. So richten Sie einen GitHub Actions Workflow ein:

# .github/workflows/i18n-doctor.yml
name: i18n Health Check

on:
  pull_request:
    paths:
      - "locales/**"
      - "src/**"
      - "messages/**"

jobs:
  doctor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Bun
        uses: oven-sh/setup-bun@v2

      - name: Install dependencies
        run: bun install

      - name: Run i18n Doctor
        run: bunx @better-i18n/cli doctor --ci --threshold 80
        env:
          BETTER_I18N_API_KEY: ${{ secrets.BETTER_I18N_API_KEY }}

Was das --ci-Flag bewirkt

Das --ci-Flag ändert das Verhalten von Doctor für CI-Umgebungen:

  1. Exit-Code: Gibt Exit-Code 1 zurück, wenn der Scan fehlschlägt, wodurch der GitHub Actions Job fehlschlägt
  2. GitHub Annotations: Gibt Probleme im GitHub Actions Annotation-Format aus, sodass sie als Inline-Kommentare im PR-Diff erscheinen
  3. Zusammenfassung: Erstellt eine strukturierte Zusammenfassung für die GitHub Actions Check-Ausgabe
  4. Nicht-interaktiv: Unterdrückt Fortschrittsbalken und farbige Ausgabe

Path-Filter sind wichtig

Der paths-Filter in der Workflow-Konfiguration ist für die Performance wichtig. Ohne ihn läuft der Health Check bei jedem PR, einschließlich PRs, die nur Dokumentation oder Backend-Code ohne Übersetzungsauswirkung ändern. Filtern Sie auf Ihre Übersetzungsdatei-Verzeichnisse und Ihre Quellcode-Verzeichnisse.

Ergebnisse an die Plattform melden

Fügen Sie das --report-Flag hinzu, um Ergebnisse an Ihre Translation-Management-Plattform zu übermitteln:

- name: Run i18n Doctor
  run: bunx @better-i18n/cli doctor --ci --report --threshold 80
  env:
    BETTER_I18N_API_KEY: ${{ secrets.BETTER_I18N_API_KEY }}

Berichte enthalten den Commit-SHA, den Branch-Namen, die Dateianzahl und die Schlüsselanzahl. Im Laufe der Zeit entsteht so eine Historie Ihrer i18n-Gesundheit, die Sie nutzen können, um Verbesserungen zu verfolgen, Regressionen zu erkennen und Team-Ziele zu setzen.

Automatisch generierte Workflows

Wenn die manuelle Konfiguration von GitHub Actions wie unnötige Reibung erscheint, können manche Translation-Plattformen (einschließlich Better i18n) die Workflow-Datei für Sie erstellen. Die Plattform nutzt die GitHub API, um einen PR mit einer vorkonfigurierten Workflow-Datei in Ihrem Repository zu öffnen. Sie überprüfen ihn, mergen ihn, und der Health Check ist aktiv.


Was passiert, wenn eine Prüfung fehlschlägt?

Ein fehlgeschlagener Health Check sollte umsetzbare Informationen liefern, nicht nur ein rotes X. So sieht ein nützlicher Fehler aus:

Fehlende Übersetzungsschlüssel

Fehler: 12 Schlüssel fehlen in Zielsprachen

  checkout.confirm_order
    Fehlt in: fr, de, ja, ko
    Hinzugefügt in Commit: abc1234 (vor 2 Tagen)
    Datei: src/pages/Checkout.tsx:45

  checkout.payment_method
    Fehlt in: fr, de, ja, ko
    Hinzugefügt in Commit: abc1234 (vor 2 Tagen)
    Datei: src/pages/Checkout.tsx:52

Der Entwickler sieht genau, welche Schlüssel fehlen, in welchen Sprachen, wann sie hinzugefügt wurden und wo sie verwendet werden. Die Lösung ist klar: Übersetzungen für diese Schlüssel anfordern, bevor der Merge erfolgt.

Platzhalter-Mismatches

Fehler: Platzhalter-Mismatch in notifications.new_messages (de)
  Quelle:  "You have {count} new messages from {sender}"
  Ziel:    "Sie haben {anzahl} neue Nachrichten von {sender}"
  Fehlend: {count}
  Extra:   {anzahl}

Der Entwickler oder Übersetzer sieht den genauen Mismatch und kann die deutsche Übersetzung korrigieren, um {count} statt {anzahl} zu verwenden.

Hartcodierte Zeichenketten

Warnung: Hartcodierte Zeichenkette in JSX (src/components/Header.tsx:23)
  <h1>Welcome back!</h1>
  Vorschlag: <h1>{t('header.welcome_back')}</h1>

Dies ist eine Warnung, kein Fehler — sie blockiert den PR standardmäßig nicht. Sie erscheint aber im Bericht und trägt zum Code-Analyse-Score bei.


Reale Auswirkungen: Vorher und Nachher

Vorher: Der manuelle Prozess

  1. Entwickler fügt neue Funktion mit 30 neuen Schlüsseln hinzu
  2. Entwickler fügt englische Übersetzungen hinzu
  3. Entwickler öffnet PR, der überprüft und gemergt wird
  4. Zwei Wochen später testet QA die Funktion auf Französisch — findet 30 Rohschlüssel
  5. QA erstellt einen Fehlerbericht
  6. Entwickler erstellt ein Ticket für Übersetzungen
  7. Übersetzer liefert französische Übersetzungen
  8. Entwickler committet Übersetzungsdatei, öffnet neuen PR
  9. Wiederholen für Deutsch, Japanisch, Koreanisch usw.

Zeit vom Code-Merge bis zum vollständig übersetzten Feature: 3–6 Wochen.

Nachher: Automatisierte Health Checks

  1. Entwickler fügt neue Funktion mit 30 neuen Schlüsseln hinzu
  2. Entwickler fügt englische Übersetzungen hinzu
  3. Entwickler öffnet PR
  4. CI führt i18n Doctor aus — schlägt fehl mit „30 Schlüssel fehlen in fr, de, ja, ko"
  5. Entwickler fordert Übersetzungen über die Plattform an
  6. Übersetzungen kommen an (KI-generiert in Minuten, menschlich geprüft in Stunden)
  7. Entwickler fügt Übersetzungen zum PR hinzu
  8. CI läuft erneut — besteht
  9. PR wird mit allen Sprachen vollständig gemergt

Zeit vom Code-Merge bis zum vollständig übersetzten Feature: Am selben Tag.

Der Unterschied ist nicht nur Geschwindigkeit — es geht darum, das Problem am richtigen Ort zu erkennen. Eine CI-Prüfung erkennt fehlende Übersetzungen im selben PR, in dem die Schlüssel hinzugefügt wurden, während der Entwickler noch den vollen Kontext über das Feature hat. Ein Fehlerbericht drei Wochen später erfordert, dass der Entwickler den Kontext für ein Feature wiederherstellt, mit dem er längst abgeschlossen hat.


Gesundheit im Laufe der Zeit verfolgen

Ein einzelner Health Score ist nützlich für das Bestehen/Nichtbestehen-Gating. Eine Historie von Health Scores ist nützlich, um Trends zu verstehen.

Wenn Sie Doctor-Berichte an ein Plattform-Dashboard übermitteln, können Sie Folgendes verfolgen:

  • Score-Trajektorie: Verbessert sich Ihre i18n-Gesundheit, ist sie stabil oder verschlechtert sie sich?
  • Kategorie-Trends: Vielleicht ist Ihre Abdeckung ausgezeichnet, aber verwaiste Schlüssel häufen sich an. Die Kategorie-Aufschlüsselung zeigt, wo Sie Bereinigungsmaßnahmen konzentrieren sollten.
  • Branch-Vergleich: Feature-Branches haben oft niedrigere Scores (neue Schlüssel ohne Übersetzungen). Der Main-Branch sollte einen konstant hohen Score beibehalten.
  • Projektübergreifender Vergleich: Für Organisationen mit mehreren Produkten können Sie die i18n-Gesundheit über Projekte hinweg vergleichen, um zu ermitteln, welche Aufmerksamkeit benötigen.

Team-Ziele setzen

Health Scores machen es möglich, messbare i18n-Ziele zu setzen:

  • „Health Score von 90+ auf dem Main-Branch aufrechterhalten" — ein Qualitätsstandard
  • „Verwaiste Schlüssel bis Ende des Quartals von 200 auf 50 reduzieren" — eine Bereinigungsinitiative
  • „Null Platzhalter-Mismatches" — ein Zero-Defect-Ziel für die kritischste Prüfung

Häufige Einwände und Antworten

„Wir haben nur zwei Sprachen, das brauchen wir nicht." Zwei Sprachen genügen, damit Abdeckungslücken und Platzhalter-Mismatches nutzerseitige Fehler verursachen. Der Health Check ist leichtgewichtig — er fügt Ihrer CI-Pipeline Sekunden hinzu, keine Minuten.

„Unsere Übersetzer kümmern sich um die Qualität." Übersetzer gewährleisten sprachliche Qualität. Health Checks gewährleisten technische Qualität — Platzhalter-Korrektheit, Schlüsselabdeckung, Dateistruktur. Das sind unterschiedliche Belange. Ein Übersetzer kann nicht wissen, ob ein Schlüssel in Ihrem Quellcode referenziert wird.

„Wir fügen das später hinzu, wenn wir mehr Sprachen haben." i18n-Schulden häufen sich an. Die verwaisten Schlüssel, hartcodierten Zeichenketten und inkonsistenten Benennungen, die Sie mit zwei Sprachen aufbauen, werden viel schwieriger zu beheben, wenn Sie eine dritte, vierte und fünfte Sprache hinzufügen. Mit Health Checks früh zu beginnen, ist günstiger als sie nachträglich einzubauen.

„Unser CI ist bereits langsam." Ein Doctor-Scan eines 10.000-Schlüssel-Projekts mit 8 Sprachen dauert unter 10 Sekunden. Verwenden Sie --skip-code, um die AST-Analyse zu überspringen und das auf unter 3 Sekunden zu reduzieren. Der Path-Filter in der GitHub Actions Konfiguration stellt sicher, dass die Prüfung nur bei PRs läuft, die übersetzungsrelevante Dateien berühren.


Erste Schritte

Wenn Sie Better i18n verwenden, ist der Doctor-Befehl in die CLI integriert:

# CLI installieren
bun add -g @better-i18n/cli

# Ihren ersten Health Check ausführen
bi18n doctor

# Im CI-Modus mit Berichterstellung ausführen
bi18n doctor --ci --report --threshold 80

Wenn Sie Better i18n nicht verwenden, gelten die Prinzipien in diesem Beitrag für jedes Übersetzungs-Setup. Sie können ähnliche Prüfungen mit eigenen Skripten erstellen, die:

  1. Ihren Quellcode nach Übersetzungsschlüssel-Referenzen parsen
  2. Referenzierte Schlüssel mit Ihren Übersetzungsdateien vergleichen
  3. Platzhalter-Konsistenz validieren
  4. Ergebnisse im Annotation-Format Ihres CI-Systems ausgeben

Das Wichtige ist nicht, welches Tool Sie verwenden. Es ist, dass fehlende Übersetzungen aufhören, eine Überraschung zu sein, die Nutzer finden, und anfangen, eine CI-Prüfung zu sein, die Entwickler finden.


Fehlende Übersetzungen sind vermeidbare Fehler. Beginnen Sie damit, sie in CI zu erkennen — richten Sie Better i18n Doctor ein und führen Sie heute Ihren ersten Health Check durch.

Comments

Loading comments...