UI-Copy bleibt konsistent, wenn jeder sichtbare String in genau einem Katalog im Repo liegt, über einen Schlüssel referenziert wird und sich nur über einen reviewten Diff ändert. Es ist dieselbe Disziplin, die du längst auf Logik anwendest – nur eben auf Wortlaut. Alles Weitere auf dieser Seite ist die Praxis, die das absichert.
Das hier ist der praktische Leitfaden. Die Architektur dahinter und das Argument, warum die Codebase die Source of Truth für Produkt-Copy sein sollte, findest du unter Code-native Produkt-Copy. Lies dort nach, wenn du das Warum willst. Lies hier weiter, wenn du das Wie willst.
Wo sollte UI-Copy liegen?
In einer Katalogdatei pro Quellsprache, im Repository, direkt neben dem Code, der sie rendert. Nicht in einer Tabelle, nicht in einer Design-Datei, nicht auf einer Wiki-Seite, die im März noch stimmte. Der Katalog ist der Ort, an dem Entwickler, Reviewer, Übersetzer und Coding-Agent nachschauen, wenn sie wissen wollen, was ein Screen sagt.
Daraus ergeben sich diese praktischen Regeln:
- Ein Katalog, ein Quell-Locale. Eine einzige Datei
en.json(oder.po,.ftl,.strings, was auch immer deine i18n-Bibliothek liest) ist die maßgebliche Copy. Bei mehreren Apps in einem Monorepo bekommt jede App einen eigenen Katalog, und geteilte Strings kommen in einen gemeinsamen Katalog, den beide importieren. Vermeide zwei Dateien, die dieselbe Nachricht enthalten können. - Gruppiere nach Screen oder Feature, nicht nach Komponente. Schlüssel wie
checkout.summary.totalaltern besser alsSummaryCard.totalLabel, denn Komponenten werden umbenannt und aufgeteilt, während Screen und Nachricht bestehen bleiben. - Benenne den Schlüssel nach der Nachricht, nicht nach dem Wortlaut.
checkout.submitübersteht den Wechsel von „Place order“ zu „Buy now“.checkout.placeOrderButtonnicht – und die Diskrepanz zwischen Schlüssel und Text verleitet Reviewer später zu der Annahme, es seien zwei verschiedene Strings. - Halte den Katalog im selben Pull Request wie den Code, der ihn nutzt. Wird ein String in einem PR hinzugefügt und seine Komponente in einem anderen, wird er übersehen, vergessen oder dupliziert.
Wenn deine Strings noch Literale in Komponenten sind, ist der Katalog das Erste, was du anlegen solltest. Das von Hand zu tun, ist ein eigenes Projekt. Genau deshalb spricht viel dafür, das Repository zu verbinden und die Konvertierung automatisch laufen zu lassen, dazu weiter unten mehr.
Warum schlägt die Referenzierung per Schlüssel die Suche nach dem Literal?
Weil ein Schlüssel nur auf einen String auflösen kann, ein Literal aber auf so viele Arten getippt werden kann, wie es Entwickler gibt. „Sign in“, „Sign In“, „Log in“ und „Login“ sind für ein Suchtool vier Strings, für Nutzer aber eine Absicht. Wenn jede Komponente t("auth.signIn") aufruft, ist die Frage nach dem richtigen Wortlaut einmal an einer Stelle beantwortet, und die Antwort gilt überall, wo der Schlüssel verwendet wird.
Zwei Gewohnheiten halten das am Laufen:
- Erst wiederverwenden, dann neu anlegen. Such vor dem Anlegen eines Schlüssels im Katalog nach der Nachricht. Wenn
common.cancelexistiert, ist ein neuesdialog.cancelButtonmit demselben Text der Beginn von Drift und kein harmloses Duplikat. Beide werden unabhängig voneinander bearbeitet, sobald jemand einen davon ändert. - Konkateniere nicht.
t("cart.items") + " " + counterzeugt Text, den keine Katalogzeile beschreibt. Nutze die Interpolation und Pluralformen deiner Bibliothek, damit der ganze Satz eine reviewbare Einheit bleibt.
Die Ausrede, zu der man gern greift: „Dieser String kommt nur einmal vor, ein Literal reicht.“ Heute kommt er einmal vor. Morgen wird die Komponente kopiert, der Screen bekommt einen Zwilling, das Literal wandert mit – und driftet dann auseinander.
Wie reviewt man Copy-Änderungen im Pull Request?
Behandle eine geänderte Katalogzeile wie eine geänderte Funktionssignatur: etwas, das ein Reviewer liest, hinterfragt und freigibt. Diese Praxis macht aus Konsistenz kein Gedächtnisproblem mehr, sondern ein Review-Problem – und beim Review passt zuverlässig jemand auf.
Was das Katalog-Review funktionieren lässt:
- Eine Textänderung ist eine eigene Zeile im Diff. Das gilt nur, wenn der String im Katalog liegt. Eine Textänderung in einer Komponente ist zwar auch eine Diff-Zeile, versteckt sich aber zwischen Logikänderungen und wird als „nur Text“ überflogen.
- Leite Katalogänderungen an einen Copy-Owner. Ein
CODEOWNERS-Eintrag auf den Katalogpfad sorgt dafür, dass bei jeder Änderung die Person angefragt wird, die für den Wortlaut zuständig ist – ob Produktverantwortliche, Content Designer oder der Entwickler, dem das Thema am meisten am Herzen liegt. Alles andere im PR läuft durch das normale Review. - Stell pro geänderter Zeile drei Fragen. Ist das der freigegebene Begriff für diese Sache? Passt es in Ton und Schreibweise zu den Strings drumherum? Beschreibt der Schlüsselname die Nachricht noch? Wer diese drei Fragen stellt, fängt das meiste ab, wofür ein Style-Guide da ist.
- Lehne stille Umbenennungen ab. Ein PR, der
auth.signInohne Erklärung von „Sign in“ auf „Log in“ ändert, ist eine Copy-Entscheidung, die zufällig die Person getroffen hat, die gerade editiert hat. Er braucht einen Satz in der PR-Beschreibung, der das Warum erklärt, oder er wird zurückgenommen.
Das Problem, das dadurch verhindert wird, hat einen Namen. Copy Drift bedeutet, dass nutzersichtbarer Text über Oberflächen und Zeit hinweg von seiner freigegebenen Quelle abweicht, weil es keine einzelne Source of Truth gibt, von der er abweichen könnte. Was ist Copy Drift behandelt die Ursachen; das Katalog-Review im Diff ist die Praxis, die die meisten davon stoppt.
Wie hältst du neue hartcodierte Strings draußen?
Lass jedes neue Literal den Build brechen. Regeln und Reviews fangen ab, wonach Menschen zu suchen daran denken. Eine Lint-Regel fängt den Rest ab – bei jedem Pull Request, ohne dass jemand daran denken muss.
Das Setup ist überschaubar:
- Aktiviere eine no-literal-string-Regel.
eslint-plugin-i18nextliefert eine für JavaScript- und TypeScript-Projekte mit. Beschränke sie auf JSX-Text und nutzersichtbare Attribute wie Input-Hints,title,aria-labelundalt, und nimm Testdateien und Storybook-Stories aus, damit die Regel glaubwürdig bleibt. - Lass sie dort laufen, wo gemergt wird. Ein Pre-Commit-Hook ist bequem; ein CI-Schritt ist der, der zählt, denn er läuft im Pull Request, egal ob der Editor der Autorin richtig konfiguriert war.
- Ergänze einen Check auf ungenutzte und fehlende Schlüssel. Die meisten i18n-Bibliotheken haben ein Begleittool, das Schlüssel auflistet, die im Code referenziert werden, aber im Katalog fehlen – und Schlüssel im Katalog, die nirgends referenziert werden. Lass es ebenfalls in CI laufen. Ungenutzte Schlüssel sind der Ort, an dem veralteter Wortlaut sich versteckt.
- Starte streng, erlaube Ausnahmen per Kommentar. Eine Regel, die für den gesamten Ordner
components/deaktiviert ist, ist keine Regel. Eine Regel, die in einer einzelnen Zeile mit Begründung deaktiviert wird, ist Dokumentation.
Teams, die mit KI-Coding-Tools arbeiten, trifft das härter, weil die Tools Komponenten aus lokalem Kontext neu generieren und dabei Literale wieder einschleppen. Warum Cursor AI immer wieder hartcodierte Strings hinzufügt geht die Lint-Regel im Detail durch, inklusive des dreistufigen Setups aus Rules-Datei, Linter und CI.
Was gehört in einen Copy-Style-Guide für Entwickler?
Eine kurze Datei im Repository, die auf einen Bildschirm passt, die Stimme festlegt, die Begriffe fixiert und sagt, wohin Strings gehören. Lange Style-Guides liegen im Wiki und werden einmal gelesen. Ein kurzer liegt neben dem Code und wird von Menschen und Tools bei jedem neuen String gelesen.
Ein funktionierender COPY.md (oder ein Abschnitt in deinem bestehenden Contributor-Guide) deckt ab:
- Die Stimme in drei Sätzen. Wie das Produkt klingt, wie formell es ist, ob es „du“ oder „der Nutzer“ sagt. Genug, um die meisten Diskussionen zu beenden.
- Begriffe, die nie variieren. Der Produktname für jedes Feature, die Verben für die zentralen Aktionen („Speichern“ oder „Aktualisieren“? „Löschen“ oder „Entfernen“?) und die Wörter, die ihr bewusst nicht verwendet.
- Regeln für Schreibweise und Interpunktion. Satzschreibweise oder Title Case in Buttons und Überschriften, Punkt am Ende von Tooltips oder nicht, wie Zahlen und Daten geschrieben werden.
- Wohin Strings gehören und wie Schlüssel benannt werden. Der Katalogpfad, die Gruppierungsregel, die Namensregel für Schlüssel und „erst suchen, dann anlegen“.
- Was tun bei Unsicherheit. Wen du fragst oder welchen Schlüssel du in der Zwischenzeit wiederverwendest.
Halte sie im Repository, damit eine Rules-Datei darauf verweisen kann, ein Reviewer sie in einem Kommentar verlinken kann und ein Coding-Agent sie liest, bevor er ein Label schreibt.
Wie verhinderst du, dass KI-Coding-Agents die Konsistenz kaputt machen?
Gib dem Agent eine Source of Truth zum Lesen und ein Gate, das ihn auffängt, wenn er sie ignoriert. Ein Agent, der ein Formular generiert, schreibt problemlos „Submit“ auf dem einen Screen und „Send“ auf dem nächsten, weil jeweils das lokal wahrscheinlichste Wort passte. Er ist nicht nachlässig; er hat schlicht nichts, woran er sich orientieren könnte.
Zwei Maßnahmen beheben das meiste. Erstens eine Rules-Datei (AGENTS.md, .cursor/rules, CLAUDE.md, je nachdem, was deine Tools lesen), die sagt: Nutzersichtbarer Text gehört in den Katalog, vorhandene Schlüssel werden wiederverwendet, und vor jedem Label wird COPY.md gelesen. Zweitens die Lint-Regel aus dem Abschnitt oben, denn eine Rules-Datei reduziert das Raten, und eine Lint-Regel fängt die Fehlgriffe ab, die trotzdem durchgerutscht sind.
Das ist alles, was diese Seite zu Agents zu sagen hat. Das konkrete Problem, dass ein Agent bestehende Strings umformuliert, und wie du diese Änderung sichtbar statt still machst, ist ein eigenes Thema: So verhinderst du, dass KI-Coding-Agents deine UI-Copy umschreiben.
Wo kommt Lokalisierung ins Spiel?
Konsistenz und Lokalisierung hängen von derselben Sache ab, einer abgestimmten Quelle – der Katalog, der dir das eine gibt, gibt dir auch das andere. Ein Team, das nicht sagen kann, welche von drei Formulierungen die freigegebene ist, kann auch keine davon korrekt übersetzen. Bring die Quelle in Ordnung, und die Übersetzung wird zu einem abgeleiteten Artefakt des Katalogs statt zu einem separaten Projekt mit eigener Kopie der Wahrheit.
In der Praxis heißt das: Der Katalog, den du für die Konsistenz angelegt hast, ist bereits die Datei, mit der ein Übersetzer oder ein Übersetzungstool arbeitet. Jeder Schlüssel bekommt seine Entsprechungen in allen Zielsprachen, dieselben Schlüsselnamen gelten, und eine Textänderung im Quellkatalog ist als Änderung sichtbar, der die Übersetzungen folgen müssen. Wenn diese Übersetzungen hinter der Quelle zurückbleiben, entsteht die Art von Problem, die in Warum Übersetzungsdateien nicht mehr synchron sind beschrieben ist – und die Lösung ist wieder dieselbe Disziplin: ein Katalog, Schlüssel, Änderungen im Diff.
Wo globalize.now ins Spiel kommt
globalize.now ist ein Code-nativ arbeitendes Copy-Management-System mit integrierter Lokalisierung, und jede Praxis auf dieser Seite ist das, was es von deinem Repository voraussetzt. Du verbindest in der App ein GitHub- oder GitLab-Repository. Ein Scan ermittelt, was vorhanden ist. Liegen die Strings als Literale in Komponenten, verschiebt eine einmalige Konvertierung sie hinter Schlüssel in einen Katalog und ergänzt das i18n-Setup, falls noch keins existiert. Nutzt du bereits next-intl, react-i18next, i18next oder Lingui, arbeitet es mit dem, was du hast. Das Ergebnis kommt als Pull Request auf einem eigenen Branch, sodass der erste Katalog genau das oben beschriebene Review durchläuft. Danach übersetzen Push-Jobs neue Quell-Strings, die du hinzufügst, und öffnen einen Pull Request mit dem Ergebnis. Das Repository bleibt die einzige Source of Truth.
Wir arbeiten darauf hin, dass dieselbe Disziplin auch über Marketing-Site, Landingpage und Produkt aus einer einzigen Quelle gilt, damit ein Feature überall gleich beschrieben wird, wo Nutzer ihm begegnen. Dorthin sind wir unterwegs; heute kannst du das noch nicht kaufen. Die Preise findest du auf der Preisseite.
Eine Checkliste für diese Woche
- Lege pro Quellsprache einen Katalog im Repository an und entscheide die Namensregel für Schlüssel.
- Verschiebe die Strings der Screens, die du am häufigsten anfasst, dorthin und referenziere sie per Schlüssel.
- Aktiviere eine no-literal-string-Lint-Regel, beschränkt auf nutzersichtbaren Text, und lass sie in CI laufen.
- Ergänze eine
CODEOWNERS-Zeile für den Katalogpfad. - Schreibe
COPY.md: Stimme, feste Begriffe, Regeln zur Groß- und Kleinschreibung, wohin Strings gehören. Eine Seite genügt. - Verweise in der Rules-Datei deines Agents auf den Katalog und auf
COPY.md. - Lehne im Review jede Wording-Änderung ab, für die in der PR-Beschreibung keine Begründung steht.
Wenn der zweite Schritt nach einem Monat Arbeit aussieht, verbinde ein Repository, lies den Plan, den globalize vorschlägt, und prüfe den Pull Request, den es öffnet.
globalize.now konvertiert hartcodierte App-Texte in übersetzungsreife Locale-Dateien und hält sie aktuell, während Sie veröffentlichen.
Probiere globalize.now kostenlos