Skip to content

Architektur

Diese Seite gibt einen technischen Überblick für die Agenturen, die die Erweiterung warten, erweitern oder anbinden.

Zielplattform: Shopware ~6.6.9 || ~6.7.0, PHP >= 8.2, Vue-3-Administration.

Hinweis

Diese Seite beschreibt die Erweiterung, die in Ihrer Shopware-Installation läuft. Diese Dokumentation beschreibt den Managed-Übersetzungsdienst nur so, wie Händler ihn sehen: die Tarife, das Guthaben, die Servicestufen und das Kontingent. Siehe modernice All-in-One.

Konstanten

AngabeWert
Plugin-KlasseNice\Translate\NiceTranslate
Technischer NameNiceTranslate
Composer-Paketmodernice/sw-translate (Typ shopware-platform-plugin)
Namespace-WurzelNice\Translate\src/ (PSR-4)
VersionskonstanteNiceTranslate::VERSION
PHP-Anforderung>=8.2
Shopware-Anforderung~6.6.9 || ~6.7.0
Tabellenpräfix in der Datenbanknice_translate_
System-Config-DomainNiceTranslate.config.
Präfix der API-Routen/api/_action/nice-translate/
Präfix der API-Routennamenapi.action.nice_translate.
ACL-Schlüsselnice_translate (Rollen viewer, editor)
Service-Tag für Anbieternice_translate.provider
Administrationsmodulnice-translate

Es gibt keine config.xml. Jede Einstellung liegt in der Domain NiceTranslate.config.. Die eigene Einstellungsseite der Erweiterung schreibt die Einstellungen, und der PHP-Code liest sie mit im Code hinterlegten Standardwerten. Die Einstellungsreferenz enthält die vollständige Liste der Schlüssel.

Fünf Dateien enthalten die Service-Verdrahtung, und src/Resources/config/services.xml importiert alle davon: entity.xml, provider.xml, engine.xml, job.xml und api.xml. src/Resources/config/routes.xml lädt die Controller per Attribut:

xml
<import resource="../../Api/**/*Controller.php" type="attribute"/>

Komponentenüberblick

text
Administration (Vue module `nice-translate`)
        │  REST /api/_action/nice-translate/*

API controllers (Nice\Translate\Api)


JobService ──▶ Message queue (low priority) ──▶ JobStartHandler ──▶ TranslateBatchHandler ×N


                                                                   EntityTranslator (Engine)
                                                                    │ PlaceholderGuard
                                                                    │ GlossaryApplier
                                                                    │ Slot/CustomFields/Snippet walkers
                                                                    │ RecordTracker (hashes)


                                                              ProviderRegistry ──▶ TranslationProviderInterface
                                                                                     (DeepL, Google, OpenAI,
                                                                                      Anthropic, Gemini, Mistral,
                                                                                      Managed)

Die Erweiterung schreibt die übersetzten Inhalte über das Repository der jeweiligen Zielentität, in die nativen *_translation-Tabellen von Shopware. Eine eigene Kopie einer Übersetzung hält sie nicht vor.

Ablauf einer Anfrage

Ein manueller Übersetzungslauf durchläuft diese Schritte. Jeder Schritt committet, bevor der nächste beginnt. Stirbt ein Prozess während des Laufs, findet die Wiederherstellung deshalb einen Zustand, an dem sie ansetzen kann.

  1. Von der Administration zur API. Das Modul ruft die Admin-API über NiceTranslateApiService auf (apiEndpoint = '_action/nice-translate'). Ein ACL-Schutz sichert jede Route. Siehe Admin-API.

  2. JobController::create() zu JobService::create(). JobConfig::fromArray() normalisiert das config-Objekt aus dem Request-Body. Die Validierung prüft danach drei Dinge: ob der Anbieter bekannt und konfiguriert ist, ob sich die Zielsprachen auflösen lassen und ob die Erweiterung die Entitäten unterstützt. Die Erweiterung legt eine Zeile in nice_translate_job mit dem Status queued an und versendet JobStartMessage.

    Wenn der Messenger-Versand eine Exception wirft, liefert der Aufruf trotzdem 200 mit der Auftrags-ID. Die committete queued-Zeile ist die dauerhafte Startmarkierung, und die geplante Wiederherstellung stellt die Nachricht nachträglich zu.

  3. JobStartHandler. Eine Transaktion erledigt vier Dinge: Sie ermittelt die betroffenen Entitäts-IDs je Entität und Zielsprache, teilt sie in Batches der konfigurierten batchSize auf, schreibt das vollständige Manifest in nice_translate_job_batch, protokolliert die Fehler bei der Ermittlung und setzt den Auftrag mit seiner exakten total_items-Zahl auf running. Danach hält JobBatchDispatcher ein begrenztes Fenster offener TranslateBatchMessages gefüllt, deshalb flutet ein großer Katalog den Transport nicht.

  4. TranslateBatchHandler. Er liest den Auftragsstatus für jede Nachricht erneut, deshalb greift ein Abbruch zwischen zwei Batches. Er nimmt eine verbindungsgebundene Advisory Lock auf die stabile Request-ID des Batches. Existiert eine gespeicherte Quittung, spielt er diese Quittung erneut ein. Andernfalls ruft er EntityTranslator::translateBatch() auf. Die Inhalte und die Quittung committen zusammen. Die Fortschrittsverbuchung erhöht die Zähler und fügt eine Zeile in nice_translate_batch_completion ein. Nach der Verbuchung des Batches füllt der Dispatcher das Fenster um eins auf.

  5. Abschluss. Sobald processed + failed + skipped >= total gilt, setzt JobProgressUpdater::finish() den Endstatus und schreibt in derselben Transaktion einen unveränderlichen Snapshot in nice_translate_finished_event. JobFinishedEventRelay versendet TranslationJobFinishedEvent nach dem Commit. Siehe Events & Flow Builder.

Der Finalizer setzt completed oder completed_with_errors und sonst nichts (IF(failed_items > 0, …)). Den Status failed erreicht ein Auftrag nur über JobProgressUpdater::failQueued(). Diese Methode verarbeitet einen queued-Auftrag, dessen Manifest-Vorbereitung fehlschlug. JobService::cancel() setzt cancelled, und dieser Status löst kein Abschluss-Event aus.

Auftragsstatus: queued, running, completed, completed_with_errors, failed, cancelled.

Nachrichten und Handler

Alle drei Nachrichten implementieren LowPriorityMessageInterface von Shopware und transportieren nur skalare IDs und Arrays. Worker können den Kern-Traffic der Queue deshalb vorziehen. Eine echte Trennung der Queue hängt weiterhin von Ihrer Messenger- und Worker-Konfiguration ab.

NachrichtHandlerZweck
JobStartMessageJobStartHandlerDas Batch-Manifest aufbauen und den Auftrag starten
TranslateBatchMessageTranslateBatchHandlerGenau einen Batch ausführen oder erneut einspielen
RevertJobMessageRevertJobHandlerGeschütztes, per Keyset paginiertes Zurücksetzen des angewendeten Verlaufs eines Auftrags

TranslateBatchMessage trägt eine stabile requestId als Idempotenzschlüssel. Eine übergebene, gültige UUID nutzt der Handler unverändert. Andernfalls leitet er die ID deterministisch aus dem unveränderlichen Payload ab, deshalb nutzt jede erneute Zustellung derselben Arbeit denselben Schlüssel. Eine Nachricht mit jobId === null ist ein auftragsloser Batch aus der Automatisierung beim Speichern, und ihr configOverride enthält dann die serialisierte JobConfig.

Die Erweiterung registriert zwei geplante Aufgaben:

AufgabeAufgabennameStandardintervallDer Handler führt aus
AutoTranslateTasknice_translate.auto_translate3600 sDen Verlauf bei jedem Durchlauf aufräumen, danach einen fälligen geplanten Auftrag anlegen
BatchDispatchTasknice_translate.dispatch_batches60 sJobBatchDispatcher::recover() und JobFinishedEventRelay::recover()

AutoTranslateTask läuft stündlich und übersetzt höchstens einmal pro scheduledIntervalHours (Standard 24). Das Aufräumen des Verlaufs geschieht bei jedem Durchlauf. Aufträge entstehen nur, solange scheduledEnabled aktiv ist und das Intervall abgelaufen ist. Events & Flow Builder enthält die vollständige Kette der Prüfungen.

Beide Aufgaben brauchen laufende Worker (messenger:consume für die Transports und scheduled-task:run).

Engine-Pipeline

EntityTranslator::translateBatch(TranslationTask $task): BatchResult ist der anbieterunabhängige Kern. Ein Aufruf verarbeitet genau einen Batch: eine Entität, eine Liste von IDs, eine Zielsprache. Die Stufen laufen in dieser Reihenfolge:

#StufeWas passiert
0Frühe AusstiegeEine leere ID-Liste liefert ein leeres BatchResult. Die Pseudo-Entität snippet zweigt in den SnippetTranslator ab
1Anbieter und Locales auflösenProviderRegistry::get(), danach der Shopware-Locale-Code der Ausgangssprache und der Zielsprache
2Optionen normalisieren, Felder auflösenDie Engine führt die Auftragsoptionen mit der Systemkonfiguration zusammen, und TranslatableFieldResolver leitet die FieldSpec-Liste ab
3Doppelter LesevorgangEinmal im Kontext der Ausgangssprache mit berücksichtigter Vererbung, einmal im rohen Kontext der Zielsprache. Für cms_page ergänzt die Criteria sections.blocks.slots
4Fingerabdrücke ladenRecordTracker::getStates() für die Entität, dazu die Config-Zustände der cms_slot-Einträge bei CMS-Seiten
5Phase 1: Einheiten sammelnDie Skip-Gates je Feld entscheiden, welche Werte die Engine sendet
6Phase 2: AnbieteraufrufeGlossar vorbereiten, nach Format gruppieren (html / text), Chunking, Bisektion nach einem Fehler
7Phase 3: NachbearbeitungGlossar-Ersetzungen, Platzhalter wiederherstellen, Maximallängen durchsetzen
8Phase 4: SchreibenDie Engine setzt die Zusatzfeld- und Slot-Strukturen wieder zusammen und schreibt je Entität innerhalb von JobBatchStore::transactionalResult(), deshalb committen Inhalt und Quittung gemeinsam

Die Engine wertet die Skip-Gates auf Feldebene aus Stufe 5 in dieser Reihenfolge aus:

  1. mode === 'missing' und es existiert bereits ein direkter Zielwert → überspringen.
  2. Kein erfasster Zustand oder überhaupt kein Zielwert → nicht überspringen.
  3. skipUnchanged und der Hash der Quelle ist unverändert → überspringen.
  4. protectManualEdits und der aktuelle Zielwert entspricht nicht mehr dem letzten Wert der Erweiterung → überspringen.

Die Schreibvorgänge laufen über das Repository der Entität, als natives Übersetzungs-Payload, ['id' => …, 'translations' => [$targetLanguageId => [...fields]]], innerhalb des Context-States nice_translate.writing, deshalb löst der Subscriber für das Speichern keine Schleife aus.

PlaceholderGuard ersetzt die Twig-Ausdrücke, die Platzhalter im Stil %name%, {0}, %s, %d und die URLs vor der Übersetzung durch ⟦n⟧-Tokens. Kommt ein Token nicht zurück, wirft die Engine PlaceholderLostException und lässt dieses Feld fehlschlagen. Die Erweiterung schreibt nie beschädigte Inhalte. Schutzmechanismen beschreibt die Details.

Die Werte getMaxBatchSize() und getMaxChunkBytes() des Anbieters begrenzen das Chunking. EntityTranslator::CHUNK_BYTE_LIMIT (80 000 Bytes) deckelt es zusätzlich. Eigene Anbieter beschreibt, wie ein Anbieter daran teilnimmt.

Persistenz

Die Erweiterung besitzt elf Tabellen. Fünf davon haben DAL-Definitionen, die über shopware.entity.definition registriert sind. Die übrigen sechs sind reine DBAL-Aufzeichnungen ohne Repository und ohne Admin-API-Ressource.

TabelleDAL-EntitätZweck
nice_translate_jobTranslationJobDefinitionDer Auftragskopf: Status, Titel, Konfigurations-JSON, Anbieter, Sprachen, Zähler, Kosten oder Guthaben, Managed-Nutzung und -Kontingent, Zeitstempel
nice_translate_job_errorJobErrorDefinitionDie Fehler je Datensatz eines Auftrags, mit Fremdschlüssel auf den Auftrag und Cascade Delete
nice_translate_glossaryGlossaryDefinitionDie Glossarbegriffe: Modus keep oder replace, feste Übersetzungen je Sprache, Groß-/Kleinschreibung, Aktiv-Kennzeichen
nice_translate_usageUsageDefinitionDie monatliche Nutzung je Anbieter, eindeutig über (provider_id, period)
nice_translate_historyTranslationHistoryDefinitionDer vorherige und der neue Feldwert samt Status applied oder reverted für das geschützte Zurücksetzen
nice_translate_record— (nur DBAL)Die sha1-Fingerabdrücke der Quelle und des geschriebenen Ziels, je Entität, Feld und Sprache
nice_translate_job_batch— (nur DBAL)Das dauerhafte Batch-Manifest und die vorübergehende Quittung mit Zählern und Abrechnungsdaten, bis der Fortschritt verbucht ist
nice_translate_jobless_batch— (nur DBAL)Die dauerhafte Batch-Nachricht beim Speichern und ihr Abschluss-Marker
nice_translate_batch_completion— (nur DBAL)Die stabilen Batch-Request-IDs, die die Auftragszähler bereits enthalten
nice_translate_managed_usage_request— (nur DBAL)Die Upstream-Request-IDs des Managed-Dienstes, die die Monatsnutzung bereits enthält
nice_translate_finished_event— (nur DBAL)Die unveränderlichen Snapshots abgeschlossener Aufträge für das Flow-Event-Relay

Jedes DAL-Feld trägt ApiAware(AdminApiSource::class). Die Entitäten sind deshalb ausschließlich über die Admin-API erreichbar, und nie über die Store-API.

Eine Auftragszeile hält einen schmalen Ausschnitt der Managed-Nutzung fest. ManagedProvider validiert die gesamte Abrechnungsantwort des Upstreams und speichert danach sechs Felder: requestedTier, deliveredTier, multiplier, sourceCharacters, debitedCredits und providerAttempts. Die Kennungen der Route und der Upstream-Modelle, die er dafür geprüft hat, schreibt er nie in die Datenbank. Clients der Administration-API können die Topologie des Managed-Dienstes deshalb nicht beobachten.

Sieben Migrationen erzeugen und erweitern dieses Schema: Basisschema, Übersetzungsverlauf, Managed-Abrechnung, dauerhafte Batches, dauerhaftes Start-Relay, Outbox für Abschluss-Events sowie Batch-Absicherung und Aufräumarbeiten. Keine davon implementiert updateDestructive().

NiceTranslate::uninstall() steigt sofort aus, wenn der Händler die Benutzerdaten behält. Andernfalls entfernt die Methode alle elf Tabellen und löscht die NiceTranslate.%-Zeilen aus system_config. Die Übersetzungen in den nativen *_translation-Tabellen löscht sie nie.

Ausfallsicherheit

Übersetzungsarbeit ist teuer, und bei BYOK-Anbietern ist sie upstream nicht idempotent. Die Fehlerbehebung beschreibt den Betrieb der folgenden Mechanismen.

MechanismusGarantieWie
Dauerhafte ManifesteDie Arbeitsmenge ist allein aus der Datenbank bekannt, ohne eine Frage an den Transport, was er noch hältnice_translate_job_batch (und nice_translate_jobless_batch für Arbeit beim Speichern) hält die vollständige Liste der Batches fest, in derselben Transaktion, die den Auftrag auf running setzt. Die Wiederherstellung wartet, bevor sie nie versendete Arbeit übernimmt, stellt unvollständige Versandvorgänge nach einer Sicherheitsfrist erneut zu und rotiert pro Runde einen Batch je Auftrag, deshalb hungert ein großer alter Auftrag neuere Arbeit nicht aus
AusführungsquittungenEin Absturz kann weder übersetzten Inhalt ohne die zugehörigen Zähler und die Managed-Nutzung noch Zähler ohne Inhalt hinterlassenDer übersetzte Inhalt eines Batches und seine Quittung committen in einer Transaktion. Die Quittung hält die Zähler, die Fehlerzeilen und die Abrechnungsdaten, und nie übersetzte Inhalte. Die Fortschrittsverbuchung leert atomar den Quittungsinhalt, erhöht die Auftragszähler und fügt eine Zeile in nice_translate_batch_completion ein
Anbieteraufruf höchstens einmal (BYOK)Ein erneutes Einspielen ohne Quittung nach dem Anspruch wird zu einem dauerhaften Endfehler und gibt kein weiteres Geld ausBevor BYOK-Arbeit ihren nicht idempotenten Anbieter erreichen kann, hält das Manifest einen Versuchsanspruch fest. Stirbt ein Worker nach dem Anspruch, aber vor dem Anbieteraufruf, steht diese Arbeit nicht mehr automatisch zur Wiederholung bereit, denn die Alternative wäre eine zweite Zahlung. Managed-Aufrufe nutzen diesen Anspruch nicht. Ihre stabile Folge von Idempotenzschlüsseln hält das automatische Wiederholen auch nach einem unklaren Fehler sicher
Outbox für Abschluss-EventsDie Zustellung erfolgt mindestens einmal, und die Snapshots überleben den AuftragDie Zeile in nice_translate_finished_event entsteht in derselben Transaktion, die den Auftrag abschließt, und das Relay versendet erst nach diesem Commit. Ein fehlgeschlagener Versand behält seinen Lease-Zeitstempel, und die Wiederherstellung versucht ihn nach Ablauf des Stale-Fensters erneut. Die Snapshots sind unveränderlich und haben keinen Fremdschlüssel auf den Auftrag
Serialisierung doppelter ZustellungenZwei Zustellungen desselben Batches können nicht beide in den Anbieterpfad gelangen, und eine erneute Zustellung aktualisiert die Fehlerzeilen statt sie zu duplizierenJobBatchExecutionLock nimmt eine verbindungsgebundene Advisory Lock (GET_LOCK/RELEASE_LOCK) auf die stabile Request-ID, und eine bereits abgeschlossene Request-ID läuft ins Leere. Die Fehlerzeilen verwenden deterministische IDs aus Request-ID und Positionsindex

Achtung

Die Advisory Lock braucht eine feste, direkte MySQL- oder MariaDB-Sitzung für die Dauer eines Handler-Aufrufs. Datenbank-Proxys mit Transaction Pooling oder Multiplexing sind nicht unterstützt, sofern sie die Sitzungsbindung für GET_LOCK und RELEASE_LOCK nicht ausdrücklich erhalten.

Ausgewählte Grenzwerte für Ihre Kapazitätsplanung:

GrenzwertWert
Gleichzeitig offene Batch-Nachrichten je Auftrag100
Batch-Größe (batchSize)Standard 25, mindestens 5, höchstens 200
Gespeicherte Fehlerzeilen je Auftrag500
Wartezeit der Wiederherstellung vor der Übernahme nicht versendeter Arbeit60 s
Sicherheitsfenster für die erneute Zustellung unvollständiger Versandvorgänge900 s
Stale-Fenster für den Anspruch auf ein Abschluss-Event300 s
Aufbewahrung von Quittungen und Abschluss-Markern45 Tage
Verlaufs-IDs je Anfrage zum Zurücksetzen oder erneuten Anwenden200

Verzeichnisstruktur

PfadInhalt
Api/Die Admin-API-Controller: Job, Provider, Katalog, Nutzung, Glossar, Verlauf
Command/Die CLI-Befehle nice-translate:run und nice-translate:providers
Core/Content/Die DAL-Definitionen: TranslationJob (und das Aggregat JobError), Glossary, Usage, TranslationHistory
Engine/Die Übersetzungs-Pipeline, ihre DTOs und die Content-Walker
Job/Die Auftragsorchestrierung: Konfiguration, Service, Batch-Store, Dispatcher und Lock, Queue-Nachrichten und Handler, geplante Aufgaben, Subscriber, Flow-Event
Migration/Die Schema-Migrationen: Basisschema, Übersetzungsverlauf, Managed-Abrechnung, dauerhafte Batches, dauerhaftes Start-Relay, Outbox für Abschluss-Events, Batch-Absicherung und Aufräumarbeiten
Provider/Die Anbieterverträge, die Registry, das Locale-Mapping, die abstrakten HTTP- und LLM-Basisklassen, die konkreten Anbieter
Subscription/Die Anbindung von modernice All-in-One auf Basis von Shopware In-App Purchase
Usage/Die Nutzungsaufzeichnung (UsageRecorder)
Resources/config/services.xml, die Service-Dateien je Schicht und routes.xml
Resources/app/administration/Das Vue-Administrationsmodul, seine Komponenten, Extensions und Snippets

Erweiterungspunkte

ErweiterungspunktEinstieg
Einen Übersetzungsanbieter ergänzenTranslationProviderInterface implementieren und den Service mit nice_translate.provider taggen. Das optionale SupportsLiveModelsInterface ergänzt die Live-Modellliste. Siehe Eigene Anbieter
Auf abgeschlossene Aufträge reagierenDer Flow-Builder-Trigger nice_translate.job.finished oder ein PHP-Subscriber. Siehe Events & Flow Builder
Die Erweiterung aus eigenem Code aufrufenDie Routen unter /api/_action/nice-translate/. Siehe Admin-API
Auf den Berechtigungen der Erweiterung aufbauenDie Rollen nice_translate.viewer und nice_translate.editor. Siehe Berechtigungen (ACL)

modernice Extensions für Shopware 6. Shopware ist eine Marke der shopware AG — diese Dokumentation steht in keiner Verbindung zur shopware AG.