
Dreißig Sprachen ohne Sicherheitsnetz ausliefern
GeekBye v1.8.3 verdrahtete react-i18next und übersetzte die ganze App in 30 Sprachen. Der Bibliotheks-Teil war Routine. Interessant ist, was fehlte: kein Schlüssel-Paritätscheck und kein String-Extraktor — also sickerte hartcodiertes Englisch durch, ein dänischer Tippfehler ging in Produktion, und das Changelog konnte sich nicht einigen, ob die App 28, 29 oder 30 Sprachen sprach.
Manche Releases sind ein Feature. GeekBye v1.8.3 sieht aus wie eines — „die App spricht jetzt 30 Sprachen" — aber das Feature war der einfache Teil, und darum geht es in diesem Post nicht. Zwischen dem 17. und 19. Februar 2026 verdrahteten zwei Pull Requests react-i18next in die App, refaktorierten jeden hartcodierten englischen String in einen Übersetzungsaufruf und bündelten dreißig Sprachdateien. Das ist echte Arbeit, aber es ist die Art Arbeit, die eine Bibliothek zur Routine machen soll. Die interessante Ingenieurskunst ist alles, was das Release nicht baute — das Sicherheitsnetz, das aufgefangen hätte, was es kaputt auslieferte.
Die Verdrahtung waren die einfachen 80%
Der Infrastruktur-Commit fügte react-i18next über i18next hinzu und tat das Konventionelle: eine i18n/index.ts, die initReactI18next aufruft, alle dreißig Sprach-JSONs statisch importiert und sie unter einem einzigen resources-Objekt registriert. Kein Lazy Loading — jede Sprache geht ins Bundle. Die Übersetzungs-Strings leben in src/i18n/locales/*.json als flache, punktnamensräumige Maps: sidebar.meetings, startMeeting.start, ein Schlüssel für einen String.
Die Migration von hartcodiertem Englisch zu t('key') wurde ehrlich gemacht, Komponentengruppe für Komponentengruppe, und man kann den Durchlauf im Commit-Log lesen: zuerst Sidebar, Navigation und Chat; dann Einstellungen, Login und Onboarding; dann Meetings, Dashboard, Toasts und Navbar-Tooltips. Jeder Commit ersetzte einen Schwung wörtlicher Strings durch Übersetzungsaufrufe. Neunundzwanzig nicht-englische Dateien landeten in einem einzigen Commit — ein Neuntausend-Zeilen-Abwurf, der die englische Quelle in alles von Bulgarisch bis Vietnamesisch übersetzte.
Nichts davon ist schwer richtig zu machen, denn es falsch zu machen ist laut: ein fehlender Provider stürzt ab, ein fehlerhaftes JSON parst nicht, ein schlechter Import bricht den Build. Die Bibliothek gibt dir Leitplanken für die mechanischen Fehler. Was sie dir nicht gibt, ist eine Leitplanke für den Fehler, der tatsächlich passiert ist.
Drei Sprach-Einstellungen, und warum das richtig ist
Bevor wir zu dem kommen, was kaputtging, eine Sache, die v1.8.3 genau richtig machte, weil es eine Unterscheidung ist, die viele Apps einebnen und nicht sollten. Nach diesem Release hat GeekBye drei unabhängige Sprach-Einstellungen:
- KI-Antwortsprache (
output_language) — in welcher Sprache der Assistent antwortet. Die älteste der drei, seit November 2025. - Transkriptionssprache (
transcriptLanguage) — in welcher Sprache die Sprach-Engine dein Mikrofon transkribiert. Ein paar Releases früher verdrahtet, in v1.7.6. - App-Sprache (
app_language) — die Sprache der Buttons, Menüs und des Onboardings. Neu in v1.8.3.
Das sind tatsächlich verschiedene Achsen. Ein Entwickler in Berlin will vielleicht eine deutsche Oberfläche, englische KI-Antworten (weil das die Sprache der Doku ist, die er einfügt) und englische Transkription (weil das Meeting auf Englisch ist). Das in eine einzige „Sprache"-Einstellung zusammenzufalten wäre für diese Person falsch, und der in diesem Release hinzugefügte Onboarding-Schritt präsentiert alle drei als getrennte Dropdowns genau aus diesem Grund.
Der schöne Zug ist der Upgrade-Pfad. Eine einmalige Migration kopiert beim ersten Start nach dem Update das bestehende output_language jedes Nutzers in den neuen app_language-Schlüssel, und der Provider löst die Sprache über eine Fallback-Kette auf — app_language, dann output_language, dann 'en'. So wachten Nutzer, die der App bereits gesagt hatten, dass sie spanische KI-Antworten wollten, mit einer spanischen Oberfläche auf, statt auf Englisch zurückgesetzt zu werden und die Einstellung suchen zu müssen. Eine neue Präferenz aus einer verwandten alten zu befüllen ist eine kleine Freundlichkeit, die eine Migration kostet und jedem Aktualisierenden ein kleines Ärgernis erspart.
Das Onboarding-Re-Render, das sich weigerte
Es gibt einen echten Bug, den es sich lohnt aus der i18n-Arbeit herauszuziehen, weil es eine React-Falle ist, in die jeder tappt, der Sprachwechsel zur Laufzeit macht. Der Onboarding-Assistent baut manche seiner Optionslisten in einem useMemo. Wenn du deine Sprache auf dem Sprachschritt selbst änderst, soll sich die UI sofort in der neuen Sprache neu zeichnen — und tat es nicht, weil t nicht im Dependency-Array des Memo stand. Die Übersetzungsfunktion wechselt ihre Identität, wenn die Sprache wechselt; wenn dein memoisierter Wert aus t gebaut ist, aber nicht davon abhängt, reicht dir React fröhlich die veraltete Version der vorherigen Sprache. Der Fix taucht zweimal im Log auf — einmal für den Assistenten, einmal für die Dropdown-Liste der Einstellungen — was dir sagt, dass es die Art Fehler ist, die man an jeder Stelle macht, an der man übersetzten Inhalt memoisiert, bis man lernt, immer t aufzulisten.
Das Onboarding trug auch eine Falte, die das Changelog nicht erwähnt: weil dies eine White-Label-Codebase ist, gibt es zwei Onboarding-Bäume zu übersetzen — einen GeekBye-Assistenten und einen Pavleur-Assistenten — die unter parallelen onboarding.*- und onboarding.pavleur.*-Schlüssel-Namensräumen leben. Jeder Onboarding-String wurde zweimal übersetzt, in zwei Markenstimmen, über alle neunundzwanzig Sprachen.
Was der Build nicht wusste, dass es ihm fehlte
Hier ist der Teil, der das zu einer Lektion statt einer Checkliste macht. v1.8.3 hatte keine automatische Möglichkeit, hartcodierte Strings zu extrahieren, und keinen CI-Check für Schlüssel-Parität über die Sprachen hinweg. Also lautete die Definition von „fertig": „jemand hat die Komponenten besucht, an die er sich erinnerte, und die Strings umschlossen, die er sah." Diese Definition ist löchrig.
Zwei Wochen nach dem Release landete ein Aufräum-Commit mit der Nachricht „translate all hardcoded English strings across 10 components into 30 languages". Zehn Komponenten — das Problem-Meldeformular, die Zusammenfassungs- und Metrik-Tabs, der Report-Tab, Transkript- und Chat-Inhalt, die Nutzungslimit-Aufforderung, Chat-Nachrichten, der Code-kopieren-Button, die schwebenden Aktions-Buttons — waren in v1.8.3 rausgegangen und sprachen noch mit jedem Englisch, in jeder Sprache. Niemandes Build schlug fehl. Kein Test wurde rot. Ein deutscher Nutzer sah einfach Englisch im Report-Tab, und der einzige Detektor war ein Mensch, der es irgendwann ansah.
Dieselbe Abwesenheit brachte die kleineren Peinlichkeiten hervor. Eine dänische Übersetzung ging mit dem falschen Wort raus — Luk application helt statt Luk applikationen helt — und wurde in einem späteren Release gepatcht, weil es kein muttersprachliches Reviewer-Gate und keine Möglichkeit für die Pipeline gab, es zu wissen. „App schließen"-Schlüssel fehlten im ersten Schwung und wurden Tage später nachgefüllt. Und jede Feature, die danach rauskam — ein Modifikatortasten-Preset, Mikrofon stummschalten, Recap-Chips, Overlay-Deckkraft — schleppte ihren eigenen „die neuen Schlüssel in 29 Sprachen übersetzen"-Commit hinter sich her, für immer, weil nichts die Invariante automatisch durchsetzte.
Man kann die Unordnung sogar in den Commit-Nachrichten messen. Dieselben dreißig Sprachdateien werden, Release für Release, als „30 Sprachen", „29 Sprachen" und — in einem Commit — „28 Locales" beschrieben. Nichts wurde hinzugefügt oder entfernt; es gibt dreißig Dateien an jedem Tag von v1.8.3 bis v2. Die Zahl driftet, weil es keine einzige Quelle der Wahrheit dafür gab, „wie viele Sprachen liefern wir aus", also zählte jeder Commit-Autor von Hand, mal Englisch als Sprache mitzählend und mal als Quelle. Ein Changelog, das seine eigene Zählung nicht stabil halten kann, ist ein kleines, ehrliches Signal, dass das, was es beschreibt, nicht von einer Maschine durchgesetzt wird.
Die Pluralisierungs-Tretmine
Noch eine Sache, die es zu markieren lohnt, nicht weil sie laut kaputtging, sondern weil sie die Art Bug ist, die dieses Setup einlädt und vor der es dich nicht warnt. Die Pluralisierung in diesen Sprachdateien wird von Hand gemacht, mit gepaarten Schlüsseln: meetings.meetingCount und meetings.meetingCountPlural, profiles.filesAttached und filesAttachedPlural. Das ist eine saubere englische Singular/Plural-Teilung. Sie ist auch falsch für einen Teil der Sprachen, die die App jetzt zu unterstützen behauptet. Russisch, Polnisch und Tschechisch haben je nach Zahl drei oder vier Pluralformen — „1 Datei", „2 Dateien", „5 Dateien" und „21 Dateien" können unterschiedliche Wortendungen tragen. Ein Zwei-Schlüssel-Singular/Plural-Schema kann das nicht ausdrücken, also rendern diese Zählungen grammatisch schief. i18next hat echte Plural-Maschinerie für genau das; die manuellen Paare umgehen sie, und kein Commit erkennt die Lücke an. Es ist das Pluralisierungs-Äquivalent des Hartcodierte-Strings-Lecks: unsichtbar für den Build, sichtbar nur für einen Muttersprachler.
Drei Dinge, die uns dieses Release lehrte
- Die Bibliothek sind die einfachen 80%; das Werkzeug sind die schweren 20%.
react-i18nextzu verdrahten und Strings massenweise zu übersetzen ist ein gelöstes Problem. Dreißig Dateien für immer in Parität zu halten ist es nicht — und es braucht einen Extraktor für hartcodierte Strings und einen CI-Check für fehlende Schlüssel, von denen dir keine Bibliothek einen liefert. Baue sie, bevor du „vollständige i18n" behauptest, sonst hast du eine Invariante behauptet, die du nicht halten kannst. - Trenne die Sprach-Einstellungen, die tatsächlich verschieden sind. UI-Sprache, Transkriptionssprache und KI-Antwortsprache sind drei Achsen, und v1.8.3 hatte recht, jeder ihren eigenen Schlüssel zu geben — und noch mehr recht, den neuen per Migration aus einem verwandten alten zu befüllen, sodass das Upgrade die Nutzer nichts kostete.
- Die Zählung deines Changelogs ist eine Disziplin-Metrik. Wenn dieselbe Dateimenge über drei Commits hinweg 28, 29 und 30 Sprachen ist, ist die Zahl nicht das Problem — die fehlende Quelle der Wahrheit ist es. Wenn keine Maschine deine Sprachen zählt, zählt sie niemand zweimal gleich.
Für das vorige Kapitel der v1-Geschichte, das Dashboard rund um ein einziges Wellen-Diagramm neu gestalten (v1.8.2); und für den ganzen Bogen, die Anatomie, Software bis zur Perfektion auszuliefern.