Inhalt

Eine mehrsprachige Website hat ein unscheinbares Problem: Sie veraltet in drei Vierteln ihrer Sprachen. Ein Satz auf der deutschen Seite ist schnell korrigiert — bis dieselbe Korrektur auf Englisch, Französisch und Italienisch angekommen ist, vergehen Wochen. Also unterbleibt sie. Nach einem Jahr steht auf den Fremdsprachenseiten etwas anderes als auf der deutschen, und niemand weiss genau, was.

Der übliche Ausweg heisst Übersetzungsbüro oder Übersetzungs-API. Beides funktioniert, beides hat dieselbe Bremse: Es kostet pro Vorgang. Und was pro Vorgang kostet, macht man nicht wegen eines geänderten Halbsatzes.

Das Ziel

Übersetzen sollte so billig und beiläufig sein wie ein Rechtschreibprüfer. Genau das leistet ein Modell, das auf dem eigenen Rechner läuft: Ein Aufruf kostet nichts ausser Strom. Damit ändert sich, was praktisch möglich ist — nicht die Qualität einer einzelnen Übersetzung, sondern die Häufigkeit.

Bei uns sieht das heute so aus: Wir pflegen ausschliesslich Deutsch. Ein Befehl, und Englisch, Französisch und Italienisch ziehen nach. Wer einen einzigen Satz ändert, hat die drei Übersetzungen nach etwa zwanzig Sekunden — denn nachübersetzt wird nur, was sich geändert hat.

Der Gewinn, konkret

vorher mit lokaler Pipeline
Kosten je Lauf Vorgangspreis nur Strom
Kleine Korrektur nachziehen lohnt sich nicht ~20 Sekunden
Wiederholbarkeit jeder Lauf kostet neu beliebig oft
Ausprobieren teuer folgenlos
Abhängigkeit Kontingent, Preisliste, Verfügbarkeit keine

Der letzte Punkt wird leicht unterschätzt. Wenn ein Lauf nichts kostet, darf man ihn verwerfen. Wir haben unsere Prompts ein Dutzend Mal umgebaut, ganze Durchläufe weggeworfen und drei Modelle gegeneinander gemessen — bei Vorgangskosten hätten wir uns nach dem zweiten Versuch mit dem Ergebnis abgefunden.

Was man dafür braucht

Nichts Exotisches, aber auch nicht nichts — der Arbeitsspeicher ist der begrenzende Faktor:

Voraussetzung Konkret Anmerkung
Rechner Mac mit Apple Silicon, oder PC mit Grafikkarte Getestet auf einem MacBook Pro mit 36 GB
Arbeitsspeicher 16 GB genügen für kleine Modelle, 32 GB für grosse Das Modell muss vollständig hineinpassen
Software LM Studio, kostenlos Startet den lokalen Server
Laufzeit Node.js ab Version 18 Das Skript kommt ohne Abhängigkeiten aus
Speicherplatz 6–15 GB je Modell Siehe Tabelle unten
Zeit für den Aufbau ein halber Tag Modell laden, Skript anpassen, prüfen

Zwei Dinge, die man vorher wissen sollte: Ein Modell, das nicht in den Arbeitsspeicher passt, lädt gar nicht erst — LM Studio bricht mit einer klaren Meldung ab, statt den Rechner in die Knie zu zwingen. Und Übersetzen ist keine Sache von Sekunden: Für unsere komplette Website in drei Sprachen rechnen wir mit ein bis drei Stunden. Das ist einmalig; jeder weitere Lauf betrifft nur noch das Geänderte.

Was dabei herauskam, war weniger eine Frage der Modellwahl als eine Frage der Prüfung. Die interessanten Fehler waren nämlich nicht die, bei denen etwas sichtbar kaputtging.

Der Aufbau in drei Sätzen

LM Studio startet einen lokalen Server, der dieselbe Schnittstelle spricht wie die OpenAI-API. Ein Node-Skript schneidet die Inhalte in Blöcke, schickt sie dorthin und setzt die Antworten wieder zusammen. Ein Zwischenspeicher merkt sich jede Übersetzung am Hash des deutschen Originals, sodass der zweite Lauf nur noch geänderte Sätze anfasst.

Der entscheidende Entwurfsschritt liegt bei der Blockgrösse.

Kontext schlägt Kleinteiligkeit

Der erste Versuch zerlegte alles in einzelne Textstücke — 2 279 Stück für unsere Oberflächentexte. Jedes ging einzeln ans Modell. Das Ergebnis war mittelmässig, und zwar systematisch:

Deutsch einzeln übersetzt im Block übersetzt
Zur Übersicht For a quick overview Back to overview
Kontakt aufnehmen Contact us. / Alternatively: Get in touch. / Or: Reach out. Contact us
Individuelle Software Custom software. (The best option depends on the context.) Custom software

Einem Modell, das „Zur Übersicht” ohne jeden Zusammenhang sieht, fehlt schlicht die Information, dass es sich um eine Schaltfläche handelt. Es rät — und liefert bei kurzen Fragmenten gern gleich mehrere Vorschläge untereinander, was in einer Tabellenzelle das Layout sprengt.

Also andersherum: grosse Blöcke statt kleiner Stücke. Wir schneiden die Oberflächentexte entlang ihrer Baumstruktur in 109 Blöcke von im Mittel rund 2 300 Zeichen, Blogbeiträge gehen komplett in einem Stück durch. Aus 2 279 Anfragen werden 125. Geschnitten wird immer an ganzen Schlüsseln, nie mitten in einem Wert — dass dabei nichts verloren geht, prüft ein Test, der alle Blöcke wieder zusammensetzt und mit dem Original vergleicht.

Drei Modelle, drei Charaktere

Getestet auf einem Mac mit Apple Silicon, alle Modelle über LM Studio, jeweils derselbe Block von 2 701 Zeichen.

Modell Auf der Platte Durchsatz Oberflächentexte Ganze Beiträge
TranslateGemma 12B 12 GB ~1,9 Texte/s gebündelt gut —
gpt-oss-20b 11 GB ~72 Zeichen/s gut gut
Qwen3.5 9B 5,6 GB ~63 Zeichen/s gut Regelverstoss
Qwen3.8 27B 15 GB ~53 Zeichen/s gut gut

Bei Qwen lohnt der Blick auf die Nachkommastelle: qwen3.5-9b und qwen3.8-27b sind zwei Generationen derselben Familie, und die Unterschiede unten betreffen genau diese beiden Fassungen — nicht „Qwen3” im Allgemeinen. Produktiv läuft bei uns Qwen3.8 27B.

Die Grössen sind die tatsächlich belegten — Modelle werden quantisiert ausgeliefert, also mit reduzierter Rechengenauigkeit. Ein 27-Milliarden-Modell belegt so 15 statt über 50 Gigabyte, bei kaum merklichem Qualitätsverlust. Für den Einstieg reicht das kleinste: Bei den Oberflächentexten, die den Grossteil ausmachen, lieferte Qwen3.5 9B dieselbe Qualität wie sein dreimal grösserer Bruder.

Gemessen wird hier in Zeichen pro Sekunde, nicht in Tokens pro Sekunde. Das ist Absicht: Jedes Modell bringt seinen eigenen Tokenizer mit, und deutscher Text zerfällt darin unterschiedlich fein. Tokens sind deshalb zwischen Modellen nur bedingt vergleichbar — die Textmenge, die am Ende herauskommt, ist es. Zur Einordnung trotzdem eine Zahl: Qwen3.8 27B erzeugte für einen kompletten Blogbeitrag 1 714 Ausgabe-Tokens in 120 Sekunden, also rund 14 Tokens pro Sekunde; gpt-oss-20b liegt etwa beim Doppelten.

Die Zahlen sagen ohnehin weniger, als man erwartet. Ein dreimal kleineres Modell war nur rund 20 Prozent schneller — der Engpass auf dieser Hardware ist nicht die Rechenleistung, sondern die Speicherbandbreite. Für jeden einzelnen Token müssen alle Gewichte durch den Speicherbus. Auch mehr gleichzeitige Anfragen halfen kaum: Zwischen zwei und zwanzig parallelen Anfragen lag die Streuung der Messwerte höher als der Effekt.

Interessanter sind die Unterschiede im Verhalten.

TranslateGemma ist kein Gesprächspartner

Googles Übersetzungsmodell versteht keine Anweisungen — es übersetzt, was hereinkommt. Wer ihm ein JSON-Objekt mit der Bitte hinwirft, nur die Werte zu übersetzen, bekommt zerlegte Strukturen zurück. Struktur muss deshalb programmatisch erhalten werden.

Es hat zudem eine eigene Aufrufform: Sein Chat-Template erwartet Sprachcodes als Felder, nicht als Prompt. LM Studio reicht diese Felder über den Chat-Endpunkt aber nicht durch, sodass jeder Aufruf mit HTTP 400 endet. Der Weg führt über /v1/completions mit selbst nachgebautem Prompt — das Template liegt im Modellordner.

Dafür macht es, was es soll, und lässt Fachbegriffe in Ruhe. Produktnamen allerdings nicht: Aus „Exeoflow” wurde zuverlässig „Exeflow” oder „Exoflow”. Eigennamen müssen bei einem reinen Übersetzungsmodell vor dem Aufruf ausmaskiert werden.

Qwen3.5 9B übersetzt ein Feld zu viel

Das kleine Qwen hielt fast alle Regeln ein — Datum, Autor, Technologie-Listen, sogar Personennamen in Zitaten blieben unangetastet. Nur an einer Stelle scheiterte es reproduzierbar in jedem Durchlauf:

# Original                              # Übersetzung
tags: ['ki', 'glossar', 'agents']       tags: ['ai', 'glossary', 'agents']

Tags sind technische Bezeichner, keine Prosa — übersetzt zerlegen sie die Filterung. Qwen3.8 27B und gpt-oss machten diesen Fehler nicht. Behoben war er am Ende durch einen einzigen zusätzlichen Satz in der Anweisung: dass Tags Bezeichner sind und nie übersetzt werden.

gpt-oss-20b braucht eine englische Anweisung

Hier lag der lehrreichste Befund, und er ging beinahe unter. Mit einem deutschen System-Prompt übersetzte gpt-oss brav das Frontmatter und liess den gesamten Fliesstext unverändert deutsch — in fünf von fünf Läufen. Auch dann noch, als in der Anweisung ausdrücklich stand, der komplette Text sei zu übersetzen.

Derselbe Prompt auf Englisch: auf Anhieb korrekt. Nicht die Deutlichkeit der Anweisung war das Problem, sondern ihre Sprache. Instruct-Modelle sind überwiegend auf englische Anweisungen trainiert. Seither sind alle unsere Prompts englisch, auch wenn weder Quell- noch Zielsprache es sind — das macht die Pipeline unabhängig davon, mit welchem Modell sie gerade läuft.

Der Fehler, den wir fast übersehen hätten

Die Sache mit dem unübersetzten Text hat eine unangenehme Pointe: Unsere Prüfung meldete „bestanden”.

Sie verglich Überschriften, Tabellenzeilen, Fettschrift, Link-Ziele und Codeblöcke zwischen Original und Übersetzung. Ein unübersetzter Text besteht diese Prüfung mühelos — er hat ja perfekt erhaltene Struktur. Dreizehn Dateien mit vollständig deutschem Inhalt landeten so als en.md auf der Platte, und in einer Sprache, die man selbst nicht liest, fällt das erst Monate später auf.

Seither beantwortet die Pipeline auch die naheliegendste aller Fragen: Wurde überhaupt übersetzt? Sie misst, welcher Anteil des Fliesstexts wortgleich geblieben ist. Eine echte Übersetzung liegt bei rund sieben Prozent — einzelne Zeilen bleiben legitim gleich, etwa Eigennamen oder Fachbegriffe. Der durchgereichte deutsche Text lag bei hundert.

Ablauf je Block: Der deutsche Block geht an das lokale Modell, die Antwort durchläuft vier Prüfungen. Besteht sie, wird die Datei geschrieben; scheitert sie, geht der Block mit der Beanstandung zurück ans Modell, nach drei Versuchen wird er verworfen. Ein Block Teilbaum oder ganzer Beitrag Lokales Modell LM Studio, temperature 0 Prüfung Struktur erhalten Felder unverändert Platzhalter intakt überhaupt übersetzt geschrieben en · fr · it Beanstandung zurück ans Modell — max. 3 Versuche verworfen keine Datei

Besteht ein Block die Prüfung nicht, wird die Datei nicht geschrieben. Das klingt streng, ist aber die harmlosere Variante: Eine fehlende Sprachdatei übergeht der Seitengenerator einfach, sie fällt auch aus den hreflang-Verweisen. Eine kaputte Datei dagegen geht live.

Die Lehre daraus taugt über Übersetzungen hinaus: Eine Prüfung, die nur nach Schäden sucht, übersieht die Fälle, in denen schlicht nichts passiert ist.

Was sonst noch überraschte

Qwen3.8 denkt standardmässig laut. Bei einer Übersetzung ist das reine Wartezeit — 187 Reasoning-Tokens für einen Satz, 12,4 statt 1,4 Sekunden, bei identischem Ergebnis. Der von Qwen vorgesehene Schalter dafür sind die Template-Argumente enable_thinking und preserve_thinking, beide per Default aktiv. In LM Studio bewirken sie nichts: Die Antwort enthält mit enable_thinking: false exakt gleich viele Reasoning-Tokens wie ohne das Feld, und ein frei erfundener Schlüssel an derselben Stelle löst weder Fehler noch Wirkung aus — der ganze Block wird ignoriert, statt ans Chat-Template zu gehen. Nicht der Schalter ist falsch, sondern die Erwartung, dass jede Laufzeitumgebung ihn weiterreicht. Was hier abschaltet, ist reasoning_effort: 'none' — für das LM Studio sogar eine Warnung protokolliert, die Einstellung sei ungültig. Sie wirkt trotzdem.

Wiederholversuche brauchen kein Zufallselement. Unser erster Entwurf hob bei einem Fehlschlag die Temperatur an, um eine andere Antwort zu bekommen. Bei einem regelgebundenen Auftrag ist das kontraproduktiv: Mit temperature: 0 bestanden beide getesteten Modelle die Prüfung, mit 0.2 fielen beide durch. Streuung kostet genau die Regeltreue, um die es geht. Ein Instruct-Modell kann stattdessen mit einer konkreten Rückmeldung etwas anfangen — der zweite Versuch bekommt jetzt die Beanstandung in den Prompt.

Arrays sind eine stille Falle. In JavaScript ist ein Array ebenfalls typeof 'object'. Wer beim Aufteilen rekursiv hineinläuft, macht aus ["a","b"] unbemerkt {"0":"a","1":"b"} — und schreibt das in die Zieldatei.

Zum Nachbauen

Das Beispielskript unten ist eigenständig lauffähig, ohne Abhängigkeiten, und zeigt alle drei Bausteine: Blöcke schneiden, Antwort prüfen, Ergebnis zwischenspeichern.

  1. LM Studio herunterladen und installieren, ein Instruct-Modell laden (openai/gpt-oss-20b ist ein guter Start) und unter Developer den Server starten.
  2. Skript herunterladen und ausführen:
node lmstudio-translate-demo.mjs
node lmstudio-translate-demo.mjs --model=qwen/qwen3.8-27b --lang=French
node lmstudio-translate-demo.mjs --file=meine-texte.json
  1. Beim zweiten Lauf greift der Zwischenspeicher — geänderte Texte werden neu übersetzt, alles andere kommt aus der Datei.

Wer es produktiv einsetzt, sollte drei Dinge nicht weglassen: die Prüfung auf tatsächliche Übersetzung, den Zwischenspeicher (sonst kostet jede Korrektur einen kompletten Durchlauf) und einen Test, der die Zerlegung gegen das Original verifiziert. Alles andere lässt sich unterwegs nachziehen.

Und die Grundsatzfrage? Für eine Website mit vier Sprachen und regelmässigen Textänderungen rechnet sich der lokale Weg schon deshalb, weil er wiederholbar ist. Man kann einen Satz ändern und zwanzig Sekunden später alle drei Übersetzungen nachziehen — ohne über Kosten pro Aufruf nachzudenken.

Zum Projekt

Weitere Beiträge