i18n im Alleingang: 1993 Schlüssel, 6 Sprachen, 9 LLM-Durchläufe
Wichtige Erkenntnisse: Eine mobile App mit 1993 Übersetzungsschlüsseln in 6 Sprachen zu internationalisieren, ist dank LLM-Automatisierung im Alleingang machbar. Das Skript npm run translate erkennt den Delta, übersetzt nur die neuen Schlüssel über OpenRouter und hält die Synchronisierung in Echtzeit für wenige Cents pro Durchlauf aufrecht. Das Ergebnis: ein um das 6-fache gesteigerter Akquisitionskanal ohne kontinuierlichen menschlichen Aufwand.
TAMSIV wurde auf Französisch geboren. Jeder String, jede Fehlermeldung, jeder Platzhalter – alles war fest im JSX codiert. Als ich beschloss, 6 Sprachen (FR, EN, DE, ES, IT, PT) zu unterstützen, ahnte ich nicht, dass dies 1993 Übersetzungsschlüssel in 35 Dateien bedeuten würde. Und noch weniger, dass ich 9 aufeinanderfolgende Durchläufe benötigen würde, um ein stabiles Ergebnis zu erzielen.
Hier ist die vollständige Geschichte dieses i18n-Abenteuers, vom ersten t('key') bis zur automatisierten Pipeline, die heute läuft.
Warum eine Indie-App im Alleingang internationalisieren?
Die kurze Antwort: Nutzerakquise. Eine App, die nur auf Französisch verfügbar ist, verzichtet auf 95 % des Weltmarktes. Selbst in Europa bedeutet die Beschränkung des Publikums auf Französisch, Deutschland (83 Mio. Einwohner), Spanien (47 Mio.), Italien (60 Mio.), Portugal (10 Mio.) und natürlich die gesamte englischsprachige Welt zu ignorieren.
Aber jenseits des Marktes gibt es einen technischen Grund: Die Stores (Google Play, App Store) indizieren Metadaten in jeder Sprache. Eine in 6 Sprachen übersetzte Produktseite bedeutet eine 6-fach größere organische Entdeckungsfläche. Dies ist ein Hebel, der von Google selbst empfohlen wird.
Für einen Solo-Entwickler wie mich ist es auch ein Wettbewerbsvorteil gegenüber großen Apps, die die Lokalisierung über Englisch hinaus vernachlässigen. Wenn ein deutscher Nutzer nach "Aufgaben-App mit Spracheingabe" sucht und TAMSIV die einzige ist, die eine deutsche Produktseite hat, ist das ein Gewinn.
Wie extrahiert man 1993 Übersetzungsschlüssel, ohne den Verstand zu verlieren?
Erster Schritt: Ersetze jeden fest codierten französischen String durch einen t('key')-Aufruf. In 35 Dateien. Manuell. Es gibt keine zuverlässige Abkürzung für diesen Schritt – jeder String hat einen Kontext, und die Benennung des Schlüssels muss diesen Kontext widerspiegeln.
Ich habe die Schlüssel nach Bildschirm und Abschnitt strukturiert:
feed.empty_state– die Meldung, wenn der Feed leer istagenda.filter.participating– der Filter "Teilnehmend" in der Agendaprofile.settings.language– die Sprachauswahl in den Einstellungendictaphone.recording.title– der Titel des Aufnahmebildschirmsgroups.hierarchy.depth_limit– die Meldung zur Tiefenbegrenzung von Gruppen
Diese Konvention bildschirm.abschnitt.element ist entscheidend. Ohne sie landet man schnell bei Schlüsseln wie button_text_3, die drei Monate später nichts mehr bedeuten. Ich habe die Empfehlungen von i18next zur hierarchischen Benennung befolgt.
Praktischer Tipp: Ich habe mit den am häufigsten besuchten Bildschirmen (Diktiergerät, Feed, Agenda) begonnen, bevor ich mich den Einstellungen und sekundären Bildschirmen widmete. Das ermöglicht es, die Übersetzung auf den Hauptpfaden schnell zu testen.
Welches automatische Übersetzungstool soll man wählen, wenn man alleine ist?
1993 Schlüssel manuell in 5 Sprachen übersetzen? Das sind fast 10.000 einzelne Übersetzungen. Unmöglich für einen Solo-Entwickler. Klassische Dienste wie die Google Translate API oder DeepL fehlt der Anwendungsbezug – "Memo vocal" würde zu "Vocal memo" statt "Voice memo".
Ich habe ein Skript npm run translate geschrieben, das die französischen Schlüssel an OpenRouter (Gemini 2.5 Flash als Hauptmodell) sendet. Das LLM versteht den Anwendungsbezug und erstellt natürliche Übersetzungen:
- "Memo vocal" → "Voice memo" (EN), "Sprachnotiz" (DE), "Nota de voz" (ES)
- "Ajouter une tache" → "Add a task", "Aufgabe hinzufügen", "Agregar una tarea"
- "Tout voir" → "See all", "Alle anzeigen", "Ver todo"
Das Skript sendet die Schlüssel in Batches von 50, mit dem Anwendungskontext als System-Prompt: "Du übersetzt die Strings einer mobilen Aufgabenverwaltungs-App per Spracheingabe mit KI." Dieser Kontext macht den Unterschied in der Qualität aus.
Warum 9 Durchläufe und nicht nur einer?
Der erste Durchlauf übersetzte den Großteil des Korpus – etwa 1600 Schlüssel. Aber eine lebendige App entwickelt sich weiter. Jede neue Funktion fügt Schlüssel hinzu:
- Durchlauf 2: Gamification – 47 neue Schlüssel (Level, Abzeichen, Streaks)
- Durchlauf 3: Agenda – 62 Schlüssel (Ereignisse, Filter, Wiederholung)
- Durchlauf 4: Kollaborative Gruppen – 89 Schlüssel (Hierarchie, Berechtigungen, Zuweisungen)
- Durchlauf 5-7: Kontextuelle Korrekturen und Anpassungen nach Nutzerfeedback
- Durchlauf 8: Onboarding und Bildschirme für die erste Nutzung
- Durchlauf 9: Website (tamsiv.com) – ein zweiter separater Übersetzungskorpus
Das Skript erkennt fehlende Schlüssel, indem es fr.json (die Referenz) mit jeder Zieldatei vergleicht. Es übersetzt nur das Delta – die neuen oder geänderten Schlüssel. Keine Token-Verschwendung, kein Risiko, eine bereits validierte Übersetzung zu überschreiben.
Wie funktioniert die Übersetzungs-Pipeline konkret?
Die komplette Pipeline durchläuft 4 Schritte:
- Diff: Das Skript vergleicht
fr.jsonmiten.json,de.json,es.json,it.json,pt.json. Jeder Schlüssel, der in FR vorhanden, aber in einem Ziel fehlt, wird als "zu übersetzen" markiert. - Batch: Die zu übersetzenden Schlüssel werden in Paketen von 50 gruppiert (um innerhalb der Token-Grenzen des LLM zu bleiben).
- Übersetzung: Jeder Batch wird mit einem strukturierten Prompt an OpenRouter gesendet. Das LLM gibt ein gültiges JSON mit den Übersetzungen zurück.
- Merge: Die Übersetzungen werden in die Zieldateien zusammengeführt, wobei die alphabetische Reihenfolge und die bestehende Struktur erhalten bleiben.
Die Kosten? Etwa 0,02 bis 0,05 EUR pro Durchlauf mit Gemini 2.5 Flash über OpenRouter. Für 5 Sprachen. Das ist fast kostenlos im Vergleich zu professionellen Übersetzungsdiensten (die 0,10-0,20 EUR pro Wort berechnen).
Wie handhabt man die automatische Spracherkennung beim ersten Start?
Beim ersten Start erkennt TAMSIV die Systemsprache über getLocales() von React Native. Wenn die Sprache unterstützt wird (FR, EN, DE, ES, IT, PT), wird sie direkt verwendet. Andernfalls wird auf Englisch zurückgegriffen.
Die Auswahl wird dann in der Datenbank (Supabase) im Benutzerprofil gespeichert. Das ermöglicht es, die Präferenz auch beim Wechsel des Telefons wiederzufinden. Und es vermeidet das klassische Problem: Der Benutzer ändert die Sprache seines Betriebssystems aus einem bestimmten Grund, und alle seine Apps wechseln ohne Vorwarnung.
Ich habe auch eine Sprachauswahl in den Einstellungen hinzugefügt, damit der Benutzer unabhängig von der Systemsprache wählen kann. Das ist ein Detail, aber es macht einen Unterschied für Zweisprachige oder Expats.
Welche Fallstricke gibt es bei der automatischen Übersetzung durch LLMs?
Die Übersetzung durch LLMs ist nicht perfekt. Hier sind die Fallstricke, denen ich begegnet bin:
- Falsche Freunde: "Classeur" wurde als "Binder" statt "Folder" übersetzt – dem LLM fehlte anfangs der Anwendungsbezug.
- Grammatisches Geschlecht: Im Deutschen "die Aufgabe" (feminin) vs. "das Memo" (neutrum) – die Artikel müssen übereinstimmen.
- Plurale: Einige Sprachen haben komplexe Pluralregeln (Portugiesisch, Deutsch). Man muss die Singular-/Pluralformen explizit angeben.
- Länge: Deutsch produziert 30-50 % längere Wörter als Französisch. "Einstellungen" vs. "Parametres". Das sprengt die Layouts, wenn das UI-Design nicht flexibel ist.
- Sonderzeichen: Anführungszeichen variieren je nach Sprache (" " im Englischen, « » im Französischen, „ “ im Deutschen).
Die Lösung: ein detaillierter System-Prompt, der den Anwendungsbereich präzisiert, Beispiele für validierte Übersetzungen im Few-Shot-Verfahren und ein automatischer Korrekturlesedurchlauf, bei dem das LLM die Kohärenz seiner eigenen Übersetzungen überprüft.
Wie hält man die Synchronisierung langfristig aufrecht?
Das Schwierigste ist nicht die anfängliche Übersetzung – es ist die Wartung. Jede Änderung im Französischen muss weitergegeben werden. Wenn ich "Ajouter une tache" in "Creer une tache" ändere, müssen die 5 anderen Sprachen folgen.
Mein Synchronisierungssystem:
- Änderungserkennung: Ein SHA256-Hash jedes FR-Wertes wird gespeichert. Wenn sich der Hash ändert, wird der Schlüssel zur Neuübersetzung markiert.
- Automatische CI: Über GitHub Actions wird bei jedem Push auf
main, derfr.jsonändert, das Skript ausgeführt und ein Commit mit den aktualisierten Übersetzungen erstellt. - Manuelle Überprüfung: Ich gehe die Übersetzungs-Diffs im PR durch, um offensichtliche Fehler zu erkennen.
6 Sprachen werden in Echtzeit für wenige Cents pro Durchlauf gepflegt. Das Verhältnis von Aufwand zu Wirkung ist unschlagbar.
Welche konkreten Auswirkungen hat dies auf die Nutzerakquise?
Die Zahlen sprechen für sich. Nach der Internationalisierung:
- Entdeckungsfläche x6: Die Play Store-Seite wird in 6 Sprachen indexiert, was die abgedeckten Suchanfragen vervielfacht.
- Store-Konversionsrate: Ein Nutzer, der eine Beschreibung in seiner Sprache sieht, hat 2 bis 3 Mal höhere Chancen, die App zu installieren.
- Bindung: Die In-App-Erfahrung in der Muttersprache reduziert die Abwanderung in den ersten 7 Tagen drastisch.
- SEO der Website: Die Website tamsiv.com ist in 6 Sprachen mit lokalisierten URLs (
/fr/,/en/,/de/usw.) verfügbar, was das internationale Ranking verbessert.
Für einen Solo-Entwickler ist dies der Akquisitionshebel mit dem besten Kosten-Nutzen-Verhältnis. Kein Werbebudget, kein obskures Growth Hacking – nur intelligente automatisierte Übersetzung.
Wie wendest du diesen Ansatz auf dein eigenes Projekt an?
Wenn du eine App entwickelst und zögerst, sie zu internationalisieren, hier mein Rat: Mach es frühzeitig. Je länger du wartest, desto mehr Strings müssen extrahiert werden. Hier sind die wichtigsten Schritte:
- Strukturiere deine Schlüssel von Anfang an mit einer Konvention
bildschirm.abschnitt.element. - Wähle deine Zielsprachen entsprechend deinem Markt. Für Europa decken FR/EN/DE/ES/IT/PT die Mehrheit ab.
- Automatisiere die Übersetzung mit einem LLM über API (OpenRouter, OpenAI usw.). Die Kosten sind vernachlässigbar.
- Integriere es in deine CI, damit die Synchronisierung bei jedem Push automatisch erfolgt.
- Teste mit echten Muttersprachlern, wenn möglich – selbst ein kurzer Blick ist besser als nichts.
Der Build-in-Public-Weg von TAMSIV zeigt, dass man auch im Alleingang ein Lokalisierungsniveau erreichen kann, das mit großen Teams vergleichbar ist.
FAQ
Wie lange dauert die Internationalisierung einer React Native App?
Für TAMSIV dauerte die anfängliche Extraktion der 1993 Schlüssel etwa 3 Tage konzentrierter Arbeit. Die Einrichtung des automatischen Übersetzungsskripts einen halben Tag. Die folgenden Durchläufe dauern dank der Automatisierung jeweils nur wenige Minuten. Der Großteil der Arbeit liegt in der Extraktion – nicht in der Übersetzung.
Ist OpenRouter für die automatische Übersetzung zuverlässig?
Ja, mit den richtigen Vorsichtsmaßnahmen. Der System-Prompt muss den Anwendungsbezug, Beispiele für validierte Übersetzungen und Anweisungen zum Tonfall enthalten. Gemini 2.5 Flash über OpenRouter liefert Übersetzungen von höherer Qualität als Google Translate für Benutzeroberflächen-Strings, weil es den Kontext versteht. Der Fallback zwischen Modellen gewährleistet die Verfügbarkeit.
Sollten benutzergenerierte Inhalte übersetzt werden?
Nein. Aufgaben, Memos und Ereignisse bleiben in der Sprache des Benutzers. Nur die Benutzeroberfläche (Schaltflächen, Beschriftungen, Systemmeldungen, Benachrichtigungen) wird übersetzt. Die Übersetzung von Benutzerinhalten wäre sowohl kostspielig als auch verwirrend.
Wie geht man mit Sprachen mit unterschiedlichen Alphabeten (Arabisch, Japanisch) um?
TAMSIV konzentriert sich derzeit auf lateinische Sprachen. RTL-Sprachen (Arabisch, Hebräisch) oder Ideogramme (Chinesisch, Japanisch) erfordern zusätzliche Layout-Anpassungen (Textrichtung, Schriftarten, Abstände). Dies ist für eine spätere Phase geplant, aber jedes Alphabet ist eine eigene Baustelle.
Kann das Übersetzungsskript für ein anderes Projekt wiederverwendet werden?
Absolut. Das Skript ist generisch: Es nimmt eine JSON-Quelldatei, eine Liste von Zielsprachen und einen LLM-Endpunkt. Es genügt, den System-Prompt an den Kontext deiner Anwendung anzupassen. Das Delta-Only-Muster (nur neue Schlüssel übersetzen) funktioniert für jedes Projekt, das JSON-Übersetzungsdateien verwendet.