> Produkt- und Website-Texte mit LLMs übersetzen, ohne Platzhalter, Pluralformen oder Tonalität zu beschädigen: Glossar, ICU-Nachrichten, QA-Checks, Review.
>
> Web page: https://balazscsorba.com/de/blog/llm-translation-pipeline-i18n · Language: Deutsch · Also available in: [English](https://balazscsorba.com/blog/llm-translation-pipeline-i18n.md) · [Magyar](https://balazscsorba.com/hu/blog/llm-translation-pipeline-i18n.md)
> Author: Balázs Csorba · Published: 2026-10-17 · Keywords: llm translation pipeline, icu messageformat placeholders, vue i18n llm translation, translation memory llm, glossary enforcement translation, german informal sie du, hungarian translation quality llm, structured output json translation, machine translation post-editing, locale file validation, cldr plural categories

[Blog](https://balazscsorba.com/de/blog)/Web-Engineering

# Eine LLM-Übersetzungspipeline für i18n: Glossar, Platzhalter und Review

Produkt- und Website-Texte mit LLMs übersetzen, ohne Platzhalter, Pluralformen oder Tonalität zu beschädigen: Glossar, ICU-Nachrichten, QA-Checks, Review.

[Balázs Csorba](https://balazscsorba.com/de/about)·17\. Oktober 2026·9 Min. Lesezeit

-   Translation
-   i18n
-   LLM
-   Vue
-   Localization

![Drei Quellkarten, eine übersetzte Karte mit Glossar-Lesezeichen, dann eine geprüfte Klemmschiene.](https://balazscsorba.com/images/blog/llm-translation-pipeline-i18n/cover.webp?v=1f3b83218d)

## Das Wichtigste in Kürze

-   Platzhalter, Tags und ICU-Syntax vor dem Modell schützen und danach prüfen; dieser Check findet fast alle echten Fehler.
-   Werte übersetzen, nie Schlüssel, und die Dateistruktur unverändert lassen, damit der Build diffbar und prüfbar bleibt.
-   Ein Glossar plus eine Nicht-übersetzen-Liste bringt mehr Konsistenz als jede Prompt-Formulierung, weil es maschinell erzwungen wird.
-   Deutsch und Ungarisch brauchen frühe Entscheidungen: formelle oder informelle Anrede, Zusammensetzungen und Anführungszeichen.
-   Das Modell übersetzt, Skripte prüfen, und Menschen sehen nur die Texte an, bei denen ein Fehler teuer wird.

Auf dieser Seite

1.  [Was tatsächlich kaputtgeht](https://balazscsorba.com/#why-translation-breaks)
2.  [Die Pipeline](https://balazscsorba.com/#pipeline-stages)
3.  [Platzhalter und Tags zuerst schützen](https://balazscsorba.com/#protect-placeholders)
4.  [Plural und Select gehören zu ICU](https://balazscsorba.com/#icu-messages)
5.  [Werte übersetzen, niemals Schlüssel](https://balazscsorba.com/#structured-output)
6.  [Glossar und Translation Memory](https://balazscsorba.com/#glossary-and-translation-memory)
7.  [Besonderheiten bei Deutsch und Ungarisch](https://balazscsorba.com/#german-and-hungarian-notes)
8.  [Checks, die fast alles finden](https://balazscsorba.com/#qa-checks)
9.  [Kosten und Durchsatz](https://balazscsorba.com/#cost-and-throughput)
10.  [Wo Menschen weiterhin zählen](https://balazscsorba.com/#review-gates)
11.  [Quellen](https://balazscsorba.com/#sources)

Diesen Artikel anhören

0:000:00

Jede Produktwebsite bekommt früher oder später eine Übersetzungspipeline, ob geplant oder nicht. Die übliche Version ist eine Tabelle, ein Skript, das jemand einmal geschrieben hat, und die Regel, dass die deutschen Texte vor dem Release-Branch fertig sein müssen. Das funktioniert, bis ein Platzhalter umbenannt wird, eine Pluralform verschwindet oder derselbe Button-Text auf drei Arten übersetzt ist.

Dieser Beitrag beschreibt die Pipeline, die ich für Vue- und Nuxt-Seiten verwende: Texte liegen in JSON, ein Modell übersetzt Werte mit Glossar und explizitem Kontext, Skripte prüfen das Ergebnis maschinell, und Menschen sehen nur die Texte an, bei denen ein Fehler teuer wird. Das ist bewusst langweilig, und genau darum geht es: Übersetzen soll ein Build-Schritt sein, kein Ereignis.

## Was tatsächlich kaputtgeht

Maschinelle Übersetzung von reinem Fließtext ist für europäische Sprachen gelöst. Kaputt geht in Software alles, was der Satz nicht trägt: das `{count}` mitten im String, der HTML-Tag um einen Link, die Pluralform, die Deutsch und Ungarisch beide brauchen, der Produktname, der englisch bleiben muss.

-   Ein verlorener oder umbenannter Platzhalter, der eine funktionierende Seite zum Laufzeitfehler oder zu einer leeren Stelle macht.
-   Eine kaputte ICU-Nachricht, weil Pluralkategorien je Sprache verschieden sind und Konkatenation sie nicht ausdrücken kann.
-   Übersetzte HTML- oder Markdown-Tags, die entweder das Rendering brechen oder im sichtbaren Text landen.
-   Inkonsistente Terminologie: dasselbe Feature heißt auf einer Seite drei verschiedene Dinge.
-   Tonalitätsdrift, bei der eine formelle deutsche Oberfläche den Leser plötzlich duzt.

## Die Pipeline

Fünf Stufen: extrahieren, übersetzen, prüfen, reviewen, veröffentlichen. Nur zwei davon brauchen ein Modell.

Der Extraktionsschritt ist der einzige Ort, der Quelltexte erzeugt. Ein hartcodierter String in einer Komponente wird nie übersetzt; die erste nützliche Prüfung ist deshalb ein Linter, der sichtbare Textliterale in Templates als Fehler meldet. Der Übersetzungsschritt ist zustandslos: er liest Quelldatei, Glossar und die vorherige Übersetzung desselben Schlüssels und schreibt neue Werte.

## Platzhalter und Tags zuerst schützen

Ein Platzhalter ist ein Vertrag zwischen dem String und dem Code, der ihn rendert. Das Modell darf ihn weder übersetzen noch umstellen oder weglassen, und der Code darf nicht annehmen, dass er überlebt hat. Das zuverlässige Muster: alle Platzhalter vor der Anfrage extrahieren und die Liste nach der Antwort vergleichen; eine Abweichung ist ein harter Fehler, keine Warnung.

```
import re

PLACEHOLDER = re.compile(r"\{[A-Za-z_][\w]*(?:,[^}]*)?\}|\{[0-9]+\}|%[sd]|</?[a-z][^>]*>")

def slots(text: str) -> list[str]:
    "Every placeholder and tag in the string, in order of appearance."
    return PLACEHOLDER.findall(text)

def check(source: str, target: str) -> list[str]:
    "Returns the differences; empty list means the translation is safe to ship."
    a, b = slots(source), slots(target)
    return [f"missing {s}" for s in a if s not in b] + [f"added {s}" for s in b if s not in a]
```

Tags verdienen dieselbe Behandlung. Enthält der Quelltext `<strong>{name}</strong>`, darf die Übersetzung den Tag verschieben, muss aber beide Hälften und den Platzhalter behalten. Ein einfacher geordneter Vergleich fängt die häufigen Fälle, ein HTML-Parser den Rest.

## Plural und Select gehören zu ICU

Deutsch und Ungarisch unterscheiden Singular und Plural, deshalb wirkt eine rein englische Pluralform harmlos bis zum ersten Zählerstand null. ICU MessageFormat löst das sauber, und Vue I18n spricht ICU, sodass die Nachricht in der Locale-Datei liegen und als Einheit übersetzbar bleiben kann.

String

en

de

hu

Warenkorb-Zähler

{count, plural, one {# item} other {# items}}

{count, plural, one {# Artikel} other {# Artikel}}

{count, plural, one {# termék} other {# termék}}

Speichergröße

{size} GB of {total} GB used

{size} GB von {total} GB belegt

{size} GB a {total} GB-ból

```
<p>{{ $t('cart.items', { count: items.length }, items.length) }}</p>

// en.json
"cart": { "items": "{count, plural, one {# item} other {# items}}" }

// de.json
"cart": { "items": "{count, plural, one {# Artikel} other {# Artikel}}" }

// hu.json
"cart": { "items": "{count, plural, one {# termék} other {# termék}}" }
```

Zwei Gewohnheiten halten das am Laufen. Baue nie einen Satz, indem du ein übersetztes Fragment mit einer Zahl oder einem Namen verkettest, denn die Wortstellung unterscheidet sich; halte die Zahl innerhalb der Nachricht. Und lass die Pipeline nie eine halb übersetzte Pluralform sehen: übersetze die ganze ICU-Nachricht als einen String, mit denselben Kategorienamen, und lass einen Check bestätigen, dass jede Kategorie der Quelle im Ziel existiert.

## Werte übersetzen, niemals Schlüssel

Der Übersetzungsschritt bekommt ein JSON-Objekt und liefert ein Objekt mit derselben Form zurück. Schlüssel sind Bezeichner und bleiben unangetastet, nur Werte ändern sich. Mit Structured Outputs ist das auf API-Ebene erzwingbar, und auch ohne Schema ist es der einfachste prüfbare Vertrag: die Menge der Schlüssel muss vorher und nachher identisch sein.

```
{
  "page": "checkout",                  // context for the model, not translated
  "glossary": [["cart", "Warenkorb"], ["checkout", "Kassa"]],
  "strings": {
    "cart.title": "Your cart",
    "cart.empty": "Your cart is empty",
    "cart.items": "{count, plural, one {# item} other {# items}}"
  }
}
```

Die Gruppierung ist wichtiger als die Größe. Strings, die sich eine Seite, eine Komponente oder eine Tonalität teilen, gehören in eine Anfrage, weil das Modell die Nachbarn als Kontext nutzt. Zwanzig bis sechzig Strings pro Anfrage sind ein guter Bereich: ein Retry ist günstig, und der Kontext bleibt spezifisch. Übersetze nur neu, was sich geändert hat, per Hash-Vergleich des Quellwerts, dann bleiben die laufenden Kosten nach dem ersten Durchlauf nahe null.

## Glossar und Translation Memory

Ein Glossar ist das günstigste Konsistenzwerkzeug der Pipeline: eine Liste von Quellbegriffen mit freigegebenen Zielbegriffen und einer Regel zu Groß- und Kleinschreibung sowie Flexion. Das Modell bekommt es als Eingabe, ein Check erzwingt es danach. Erscheint eine verbotene Übersetzung, wird der String einmal mit dem zitierten Verstoß wiederholt; danach geht er ins Review statt zu loopen.

Quelle

Deutsch

Ungarisch

Regel

cart

Warenkorb

kosár

Substantiv, im Deutschen groß

checkout

Kassa

fizetés

nicht übersetzen, nicht beugen

AI agent

AI-Agent

AI-ügynök

englischen Begriff behalten, beim ersten Vorkommen erklären

Translation Memory ist die andere Hälfte: exakte Treffer aus früheren Releases werden ohne Modellaufruf wiederverwendet, unscharfe Treffer als Vorschlag übergeben. In einem JSON-pro-Sprache-Aufbau ist die Memory nur eine Tabelle aus Quell-Strings und akzeptierten Zielen, der Effekt ist aber derselbe: das Modell sieht nur, was wirklich neu ist, und Reviewer sehen nur, was sich seit dem letzten Release geändert hat.

## Besonderheiten bei Deutsch und Ungarisch

Deutsch bestraft Inkonsistenz stärker als Grammatikfehler. Wähle eine Anrede pro Produkt, dokumentiere sie und lege sie in den Styleguide, der mit dem Glossar ausgeliefert wird; ein Shop, der im Footer siezt und im Onboarding duzt, wirkt zusammengesetzt. Substantive bleiben groß, Komposita werden zusammengeschrieben, und Anführungszeichen sind die deutschen: „so“, nicht "so".

Ungarisch ist agglutinierend und kennt kein grammatisches Geschlecht, was die Pipeline auf zwei praktische Arten verändert. Erstens lassen sich "user" oder "customer" nicht per Pronomen weiterführen: die Übersetzung muss das Substantiv wiederholen oder ohne es formuliert werden. Zweitens hängen Suffixe an Substantiven, also muss ein Platzhalter innerhalb eines Kasussuffixes vermieden oder die Nachricht umgebaut werden, bis das Suffix neben dem Wort steht.

-   Schreibe pro Sprache eine einseitige Tonalitätsnotiz und halte sie neben dem Glossar im Repository.
-   Jeder wiederkehrende Begriff wird ein Glossareintrag, statt im Prompt wiederholt zu werden.
-   Lass einen Muttersprachler die Tonalitätsnotiz einmal korrigieren und behandle die Korrekturen danach als Lint-Regeln.
-   Prüfe das Ergebnis im Layout, nicht im JSON: Deutsch und Ungarisch sind meist länger als Englisch.

## Checks, die fast alles finden

Jeder Fehlermodus aus dem ersten Abschnitt hat einen maschinellen Check. Führe sie im selben Commit wie die Übersetzung aus, nicht später in einem Aufräum-Sprint; eine Pipeline, die nicht laut scheitern kann, liefert kaputte Strings leise aus.

```
// verify-locales.mjs - runs in CI, exits non-zero on the first real problem
const checks = [
  ['placeholder parity', (src, tgt) => sameSlots(src, tgt)],
  ['icu category parity', (src, tgt) => sameIcuCategories(src, tgt)],
  ['no empty values', (src, tgt) => tgt.trim().length > 0],
  ['glossary respected', (src, tgt) => glossaryViolations(src, tgt).length === 0],
  ['length sanity', (src, tgt) => tgt.length < src.length * 2.2],
]
```

-   Platzhalter- und Tag-Parität, pro String und pro ICU-Nachricht.
-   Identische Schlüsselmengen zwischen Quell- und Ziel-Locale-Datei.
-   Keine leeren oder unveränderten Werte, wo sich die Quelle geändert hat.
-   Glossarverstöße mit dem betroffenen Begriff, damit der Retry-Prompt ihn zitieren kann.
-   Längenverhältnis-Grenzen, die Kürzungen und ausufernde Erweiterungen melden, bevor ein Designer sie sieht.

**Lass Skripte entscheiden, nicht das Modell**

Es ist verlockend, einen fehlschlagenden Check in einer Schleife ans Modell zurückzugeben, bis er passt. Begrenze die Schleife auf einen Retry und eskaliere beim zweiten Fehlschlag ins Review: Ein Modell, das einen Platzhalter-Check erfüllen soll, findet Wege, ihn zu erfüllen, auch erfundene Platzhalterkopien im Text.

Der Check besitzt den Vertrag; das Modell schlägt nur Werte vor.

## Kosten und Durchsatz

Übersetzen ist ein kleiner Teil der LLM-Rechnung, weil die Strings kurz sind. Als Faustregel kosten tausend Strings mit je etwa zwanzig Wörtern rund 20k Eingabe- und 25k Ausgabe-Tokens; bei einem Mittelklasse-Modell mit drei Dollar pro Million Eingabe- und fünfzehn Dollar pro Million Ausgabe-Tokens sind das etwa fünfundvierzig Cent pro tausend Strings. Frontier-Modelle kosten ein Vielfaches und lohnen sich hier selten.

Durchlauf

Was es sieht

Kostentreiber

Erster Volllauf

Jeder Quell-String plus Glossar

Quellmenge, einmalig

Release-Delta

Nur Schlüssel mit geändertem Quell-Hash

Änderungsrate

Exakter Memory-Treffer

Nichts, aus der Memory kopiert

Null

Review

Diffs, markierte Verstöße, Stichproben

Menschenminuten

Die Durchsatzfrage ist wichtiger als der Preis. Ein voller Durchlauf über ein paar tausend Strings dauert Minuten und kann in der CI laufen; der Engpass ist das Review. Deshalb sollte die Pipeline Reviewern einen Diff der geänderten Schlüssel und eine Liste markierter Strings zeigen, statt einer Datei, die von oben gelesen werden muss.

## Wo Menschen weiterhin zählen

Ein Review-Gate lohnt seine Kosten, wenn ein Fehler teuer ist: Onboarding, Preisseiten, Rechtstexte, alles, was Kunden dir zurückspiegeln. Für den langen Schwanz aus Fehlermeldungen und Einstellungslabels schlagen automatische Checks plus Glossar einen hastigen menschlichen Durchgang; das Gegenteil zu behaupten verschiebt die Arbeit nur ins nächste Release.

1.  Die Pipeline erzeugt einen Diff pro Sprache und eine Liste markierter Strings.
2.  Ein Reviewer gibt nur die markierten und gut sichtbaren Einträge frei oder bearbeitet sie.
3.  Freigegebene Werte werden zurückgeschrieben, was die Translation Memory aktualisiert.
4.  Der Build veröffentlicht die Seite, und die Checks laufen erneut auf dem veröffentlichten Artefakt.

Nichts davon ist exotisch. Quelltexte in JSON, daneben ein Glossar, ein Modell, das Werte übersetzt, ein Skript, das Verträge prüft, und ein Mensch, der den Diff ansieht. Die Pipeline ist bewusst langweilig, weil die interessanten Teile eines Produkts niemals die Übersetzungen sein sollten.

## Quellen

1.  [Unicode ICU User Guide: Formatting Messages](https://unicode-org.github.io/icu/userguide/format_parse/messages/)
2.  [Vue I18n: Message Format Syntax](https://vue-i18n.intlify.dev/guide/essentials/syntax)
3.  [Nuxt i18n: Getting started](https://i18n.nuxtjs.org/docs/getting-started)
4.  [Unicode CLDR: Plural rules](https://cldr.unicode.org/index/cldr-spec/plural-rules)
5.  [OpenAI: Structured outputs](https://platform.openai.com/docs/guides/structured-outputs)
6.  [DeepL API: Glossaries](https://developers.deepl.com/docs/api-reference/glossaries)
7.  [W3C: Localization vs. internationalization](https://www.w3.org/International/questions/qa-i18n)
8.  [GNU gettext manual](https://www.gnu.org/software/gettext/manual/gettext.html)
9.  [RFC 5646: Tags for Identifying Languages](https://www.rfc-editor.org/rfc/rfc5646)
10.  [Rat für deutsche Rechtschreibung](https://www.rechtschreibrat.com/)
11.  [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/)

## Häufige Fragen

Brauche ich noch ein Translation-Management-System?

Nicht zwingend. Eine JSON-Datei pro Sprache mit Review-Gate im Repository reicht für die meisten Produktseiten. Ein TMS lohnt sich, sobald externe Übersetzer, viele Sprachen oder Release-Branches dazukommen.

Wie groß sollte ein Übersetzungs-Batch sein?

So klein, dass ein Fehlschlag günstig zu wiederholen ist, so groß, dass Kontext vorhanden ist. In der Praxis funktionieren 20 bis 60 Strings pro Anfrage, gruppiert nach Seite oder Komponente.

Darf das Modell die ganze Datei als Kontext sehen?

Ja, als reine Lesehilfe. Schicke die Quelldatei mit den zu übersetzenden Strings markiert und lass die Antwort nur die übersetzten Werte enthalten. Das hält Prompt und Antwortschema klein.

Was ist mit Sprachen ohne Pluralform wie im Englischen?

ICU löst das, aber nur wenn auch der Quelltext ICU nutzt. Zähler und Pluralformen zuerst in ICU-Nachrichten überführen und dann die Nachricht übersetzen, nicht den zusammengesetzten Satz.

Braucht es noch Post-Editing?

Bei sichtbaren Texten ja. Bei selten gelesenen Fehlermeldungen und Einstellungslabels schlagen ein gutes Glossar und automatische Checks einen hastigen menschlichen Durchgang meist.

Geschrieben von Balázs Csorba

Senior Fullstack & AI Engineer in der Steiermark – über 10 Jahre Vue, Nuxt, Node.js und PHP, heute baue ich Werkzeuge für KI-Agenten.

[Vue.js- & Nuxt-Entwicklung →](https://balazscsorba.com/de/expertise/vue-nuxt-developer)[Über mich →](https://balazscsorba.com/de/about)

## Weitere Artikel

-   [Schema.org-Strukturdaten für B2B-Shops: Preise hinter Logins, Einheiten und Varianten](https://balazscsorba.com/de/blog/schema-org-structured-data-b2b-shop)
-   [Ein KI-Assistent für den Support im B2B-Shop: Tools, Berechtigungen und die Übergabe an Menschen](https://balazscsorba.com/de/blog/ai-assistant-b2b-shop-customer-support)
-   [Streaming-Chat mit KI in Vue und Nuxt: von Anfang an barrierefrei](https://balazscsorba.com/de/blog/vue-ai-chat-ui-streaming-accessibility)
-   [Mehrsprachiges SEO mit Nuxt i18n: URL-Strategie, hreflang, Canonicals und Sitemaps](https://balazscsorba.com/de/blog/nuxt-i18n-multilingual-seo-hreflang)

## Klingt nach dem, was du suchst?

Erzähl mir von deinem Projekt oder deiner Stelle – ich freue mich, von dir zu hören.

[Kontakt aufnehmen](mailto:contact@balazscsorba.com) [Auf LinkedIn vernetzen](https://www.linkedin.com/in/balazs-csorba)
