Topics

Von Google Translate API zu LLM-Übersetzung – wie wir unsere Mehrsprachigkeit mit Claude API + R2 Differential Caching neu aufgebaut haben

  • column

Ich habe früher einen Artikel geschrieben über die Mehrsprachigkeit einer Astro SSG-Website mit Google Translate API. Dabei wurde die statische HTML nach dem Build mit Google Cloud Translation API übersetzt, um Versionen in verschiedenen Sprachen zu generieren. Als vereinfachte Mehrsprachigkeitslösung mit reduziertem Budget war dies durchaus praktisch.

Nach einiger Zeit des Betriebs traten jedoch auf beiden Seiten – SEO und Übersetzungsqualität – Punkte auf, die mir Sorgen bereiteten. Warum wir Google Translate aufgegeben haben, können Sie in einem separaten Artikel nachlesen.

Artikel: Migration der maschinellen Übersetzung von Google Translate zu Claude API

In diesem Artikel geht es um die praktische Implementierung – wie wir es tatsächlich umgestaltet haben. Wir haben die Übersetzungs-Engine von Google Translate auf ein LLM (Claude API) umgestellt und gleichzeitig die manuellen Betriebsaufgaben aus dem letzten Mal eliminiert.

LLM-Übersetzung beim Build mit R2 Differential Caching

Die Grundstrategie ist dieselbe wie zuvor – die Übersetzung wird während des Builds (serverseitig) abgeschlossen. Wir rufen die Claude API nicht vom Browser aus auf. Der Unterschied liegt in der Übersetzungs-Engine und dem Speicherort des Caches.

Der Build-Workflow sieht so aus.

npm run build
  ├── fetch-microcms   (microCMSから記事データ取得)
  ├── astro build      (日本語HTMLを生成 → dist/)
  ├── translate        (各ロケールのHTMLを生成 → dist/{locale}/)
  └── update-xml       (sitemap更新)

Was der Inhalt von translate (translate-html-llm.mjs) tut, läuft grob in dieser Reihenfolge ab.

  1. Laden des Übersetzungs-Cache (eine einzelne JSON-Datei) von Cloudflare R2
  2. Jede HTML-Datei unter dist/ mit cheerio laden und den zu übersetzenden Text extrahieren
  3. Falls vorhanden, Cache verwenden; ansonsten nur fehlende Einträge an Claude API senden
  4. Text durch Übersetzungsergebnisse ersetzen und in dist/{locale}/ schreiben
  5. Neu übersetzte Einträge mit Cache zusammenführen und zu R2 hochladen

Der Schlüssel liegt in zwei Aspekten: "Nur das Geänderte übersetzen" (Differential-Übersetzung) und das Speichern dieses Caches auf R2.

① Wie man Übersetzungen, die Inline-Tags überspannen, natürlich gestaltet

Dies war das Wichtigste, das ich verbessern wollte.

Nehmen wir an, der Text enthält folgendes HTML:

<p>私たちは<strong>ウェブアクセシビリティ</strong>を重視しています</p>

Bei der üblichen Übersetzungsverarbeitung würde wir / Web-Accessibility / legen großen Wert darauf als drei separate Fragmente übersetzt werden. Da sich die Satzfolge zwischen Japanisch und Deutsch unterscheidet, können beim Zurückplatzieren der übersetzten Fragmente an die ursprüngliche Position <strong> an falscher Stelle angebracht werden, oder der Satz wird von vornherein unnatürlich. Je mehr Inline-Tags ein Satz enthält, desto stärker wirkt sich das aus. Das war die größte Unzufriedenheit mit dem alten System.

Die Verbesserungsmethode besteht aus zwei Schritten.

Erstens: Segmentierung nach Block-Elementen. Die minimale Übersetzungseinheit ist nicht der "Platz zwischen Tags", sondern der vollständige Inhalt (innerHTML) von Block-Elementen wie p, h1 bis h6, li, td oder blockquote. Sätze werden nicht aufgeteilt.

Zweitens: Inline-Tags durch Marker ersetzen und den gesamten Satz als eine Übersetzungseinheit übergeben. Die <strong> und <a> im Chunk werden vorübergehend durch Marker wie ... ersetzt.

私たちは[[T1]]ウェブアクセシビリティ[[/T1]]を重視しています

Wir weisen das LLM an: "Dies ist ein Satz. Übersetzen Sie ihn natürlich und können die gleichen Marker an Wörtern platzieren, die Hervorhebung verdienen. Sie können die Marker-Positionen nach der Wortstellung Ihrer Übersetzung verschieben." Wenn die Übersetzung zurückkommt, stellen wir die Marker in die ursprünglichen <strong> oder <a href="..."> wieder her. Attribute (wie href oder class) werden unverändert beibehalten.

Dadurch bezieht sich <strong> auf der englischen Seite korrekt auf das richtige Wort und der Satz ist natürlich.

② Differenzielle Übersetzung und R2-Cache-Design

Wenn wir jedes Mal alles übersetzen würden, würden die Kosten ins Unermessliche wachsen. Wir hatten vorher einen Cache namens translate-cache.json, aber dieses Mal haben wir die Art und Weise überarbeitet, wie wir Schlüssel erstellen und wo wir sie speichern.

Ein Mechanismus, um Übersetzungen zu erneuern, wenn das Prompt geändert wird

Der Cache-Schlüssel wird aus einer Kombination von "Originaltext auf Japanisch + Gebietsschema + Inhalt des Übersetzungs-Prompts" erstellt. Auf diese Weise wird automatisch ein Eintrag als "nicht im Cache vorhanden" behandelt und neu übersetzt, wenn der Originaltext geändert wird oder wenn die Übersetzungsanweisungen oder Terminologie-Richtlinien (Prompt) geändert werden.

Das Ziel ist es, Fehler zu vermeiden, bei denen alte Übersetzungen im Cache verbleiben, obwohl der Prompt verbessert wurde. In der Praxis verwenden wir eine mit sha256 gehashte Zeichenkette als Schlüssel.

Die Cache-Struktur sieht wie folgt aus:

{"<sha256のキー>":{"value":"翻訳結果(マーカー込み)","locale":"en","model":"claude-haiku-4-5-20251001","translatedAt":"2026-06-12T..."}}

Cache in R2 platziert und manuelle Arbeit eliminiert

Das ist die Abrechnung der offenen Punkte vom letzten Mal.

Zuvor verwalteten wir den Cache in einer JSON-Datei im Repository. Wenn wir also einen Artikel im CMS hinzufügten und der Deploy-Hook den Build auslöste, konnte der Server nur den alten Cache auf Git sehen. Um das Problem zu umgehen, mussten wir nach der Regel vorgehen: „Wenn du einen Artikel hinzufügst, führe lokal einen Build durch und pushe die aktualisierte Cache-Datei zu Git."

Dieses Mal haben wir den Cache als einzelnes JSON-Blob auf Cloudflare R2 abgelegt. Bei jedem Build rufen wir ihn von R2 ab und schreiben ihn nach Abschluss zurück. Dadurch bleibt der Cache auch bei Builds über Webhook persistent, und die manuelle Arbeit von lokalem Build und Push ist vollständig entfallen. Wenn Sie einen Artikel hinzufügen und pushen, werden nur die neuen Teile übersetzt und der Cache wird automatisch aktualisiert.

Übersetzungspriorität

Die Inkonsistenz von Übersetzungsbegriffen (wie unterschiedliche Schreibweisen des Unternehmensnamens Liberogic) war auch beim letzten Mal ein Knackpunkt. Dieses Mal verarbeiten wir das in vier Stufen.

  1. Manuelles Überschreiben ((data-i18n-key) — Elemente in HTML, die mit data-i18n-key versehen sind, werden durch vordefinierte Übersetzungen festgelegt. Dies ermöglicht eine Lösung, bei der weder das LLM noch das Wörterbuch herangezogen wird und Sie sagen können: „Hier möchte ich absolut diese Übersetzung haben."
  2. Glossar (Terminwörterbuch) – Wiederholte statische Beschriftungen wie Navigationselemente oder Seitentitel werden durch ein JSON-Wörterbuch mit festgelegten Übersetzungen verwaltet. Eine Änderung im Wörterbuch und ein erneuter Build führen sofort zu einer Aktualisierung.
  3. R2-Cache – wenn nichts in den beiden obigen Optionen vorhanden ist, schauen wir uns den Cache an.
  4. Claude API ― nur das, was sonst nirgendwo existiert, wird am Ende an das LLM übergeben.

Die Vereinheitlichung von Begriffen im Fließtext kann ein Point-Lookup-Wörterbuch nicht erfassen (es unterstützt keine Teilübereinstimmungen), daher gleichen wir sie mit Begriffshinweisen auf der Systempromptsseite lose ab.

Mit den "Eigenheiten" von LLMs umgehen

Maschinelle Übersetzungen liefern manchmal fehlerhafte Ergebnisse – das war auch beim letzten Mal der Fall. LLMs haben ihre eigenen Eigenheiten. Hier sind einige Dinge, die sich in der tatsächlichen Anwendung herauskristallisiert haben.

  • Technische Texte bleiben vollständig auf Englisch erhalten. Das System kann die Liste der "Begriffe, die nicht übersetzt werden sollen" wie API, React und Vue übermäßig anwenden und den ganzen Satz auf Englisch zurückgeben. Wir beheben dies, indem wir im Benutzer-Prompt deutlich stärker betonen, dass die Ausgabe in der Sprache des Zielgebietsschemas erfolgen soll.
  • Die Position der Marker kehrt sich semantisch um. Das System kann sich bei der Bestimmung des hervorzuhebenden Wortes irren, und <strong> kann sich auf einen falschen Bereich beziehen. Das Problem ist behoben, wenn wir die betreffende Einträge löschen und erneut übersetzen.
  • Die Antwort wird bei CJK-Sprachen mitten im Satz abgeschnitten. Kanji verbraucht viele Token pro Zeichen, und wenn zu viele auf einmal eingegeben werden, erreicht die Ausgabe die Obergrenze und das JSON wird beschädigt. Wir beheben dies, indem wir max_tokens erhöhen und die Anzahl der Einträge pro Stapel reduzieren.
  • Literale und Fehler bei CJK-Daten. Zeilenumbrüche können als Zeichenfolge eindringen, oder 22. Mai 2026 enthält unnötige Leerzeichen. Diese werden durch Nachbearbeitungsskripte bereinigt.

Ein Betriebstipp, der sich bewährt hat: Fehlerhafte Stellen einzeln zu löschen und erneut zu übersetzen, ist am erfolgreichsten. Wenn man versucht, mehrere auf einmal zu korrigieren, neigen LLMs dazu, dieselbe Struktur in derselben Weise fehlzuinterpretieren. Eile mit Weile funktioniert am besten.

Kostenfragen

Wir verwenden einheitlich Claude Haiku 4.5 als Engine. Wir priorisieren Kosten und verbessern zuerst den Prompt und die Wörterbuch, wenn Qualitätsprobleme auftreten. Der Systemprompt nutzt Prompt Caching, um die Kosten für denselben festen Teil bei jeder Abfrage zu senken.

So sieht ein realistischer Richtwert aus.

Inhalt

Kosten

Erste vollständige Übersetzung für ein Gebietsschema

ca. 2,50–3 USD

Erste vollständige Übersetzung für alle Gebietsschemas

ca. 20 USD

Normales Deployment (nur Cache-Treffer)

praktisch 0 USD

Einen Artikel hinzufügen (wenige Übersetzungen)

ca. 0,01 USD

Tägliche Deployments kosten fast nichts, und das Hinzufügen von Artikeln kostet nur wenige Cent. Die anfängliche Umgestaltung erforderte zwar erhebliche Kosten, aber danach wurde der laufende Betrieb tatsächlich leichter als zuvor.

Fazit

Durch die Umstellung von Google Translate auf LLM-Übersetzung entstanden kaum zusätzliche Betriebskosten, und die Übersetzungsqualität verbesserte sich erheblich.

Nur weil es ein LLM ist, heißt das nicht, dass alles automatisch perfekt funktioniert. Wir müssen weiterhin Besonderheiten identifizieren und diese beheben. Aber da sich die Anpassungen auf Prompts und Wörterbücher konzentrieren – also leicht nachvollziehbare Orte – lassen sich Verbesserungen nun schneller umsetzen.

Dieser Artikel wurde geschrieben von

Von DTP in die Web-Welt – und dann Markup, Frontend, Projektleitung und Accessibility alles gemeistert: ein "Technik-Weise". Seit den Anfangstagen von Liberogic vielseitig tätig und mittlerweile eine lebende Wissensquelle im Unternehmen. Derzeit fasziniert von der Frage "Können wir Accessibility-Umsetzung noch stärker mit KI unterstützen?" und erforscht Optimierungsmöglichkeiten durch gezieltes Prompt-Engineering. Technisch wie gedanklich immer noch in Entwicklung.

Ayumi Futamata

IAAP-zertifizierter Web Accessibility Specialist (WAS) / Markup Engineer / Frontend Engineer / Web Director

Artikel dieses Mitarbeiters ansehen

Zuverlässige Teamstruktur und schnelle Reaktionsfähigkeit sind unsere Stärken

Bei Liberogic werden erfahrene Mitarbeiter aktiv bei der Projektförderung eingesetzt, daher erhalten wir hohe Bewertungen von unseren Kunden.
Wir weisen Projektmanager und Direktoren ordnungsgemäß zu und bemühen uns, Projekte reibungslos zu leiten. Wir vermeiden unnötige Kostensteigerungen durch vollständige Bindung und verteilen Ressourcen optimal. Wir sind auch bekannt für die Schnelligkeit bei der Erfassung von Geschäftsinhalten bis zur Erstellung und Einreichung von Angeboten.

※ Bitte beachten Sie, dass wir keine SES-ähnliche Vor-Ort-Arbeit aktiv durchführen.

Sie können nahezu alle wichtigen Projektmanagement-Tools und Chat-Tools verwenden, wie Slack, Teams, Redmine, Backlog, Asana, Jira, Notion, Google Workspace, Zoom, Webex und mehr.

Konsultieren Sie uns gerne bei Ihren Web-Fragen.

Fallstudien