Translation
TranslationÜbersetzung

Übersetzung

Direktive @strTranslate, um einen Feldwert über die API eines beliebigen Anbieters zu übersetzen.

Description

Füge die Direktive @strTranslate zu einem beliebigen Feld vom Typ String hinzu, um es in die gewünschte Sprache zu übersetzen.

Diese query übersetzt zum Beispiel die Felder title und excerpt eines Beitrags vom Englischen ins Französische (mit dem Standard-API-Anbieter):

{
  posts {
    enTitle: title
    frTitle: title @strTranslate(from: "en", to: "fr")
 
    enExcerpt: excerpt    
    frExcerpt: excerpt @strTranslate(from: "en", to: "fr")
  }
}

...mit folgendem Ergebnis:

{
  "data": {
    "posts": [
      {
        "enTitle": "Welcome to a single post full of blocks!",
        "frTitle": "Bienvenue dans un poste unique plein de blocs !",
        "enExcerpt": "When I look back on my past and think how much time I wasted on nothing, how much time has been lost in futilities, errors, laziness, incapacity to live; how little I appreciated it, how many times I sinned against my heart and soul-then my heart bleeds. Life is a gift, life is happiness, every…",
        "frExcerpt": "Quand je repense à mon passé et que je pense au temps que j'ai perdu pour rien, au temps perdu en futilités, en erreurs, en paresse, en incapacité de vivre ; combien je l'ai peu apprécié, combien de fois j'ai péché contre mon cœur et mon âme, alors mon cœur saigne. La vie est un cadeau, la vie est un bonheur, chaque…"
      },
      {
        "enTitle": "Explaining the privacy policy",
        "frTitle": "Expliquer la politique de confidentialité",
        "enExcerpt": "Our privacy policy is at https://gato-graphql-pro.lndo.site/privacy/, and we are based in Carimano.",
        "frExcerpt": "Notre politique de confidentialité se trouve sur https://gato-graphql-pro.lndo.site/privacy/, et nous sommes basés à Carimano."
      },
      {
        "enTitle": "HTTP caching improves performance",
        "frTitle": "La mise en cache HTTP améliore les performances",
        "enExcerpt": "Categories Block Latest Posts Block Did you know? We are not rich by what we possess but by what we can do without. Patience is the strength of the weak, impatience is the weakness of the strong.",
        "frExcerpt": "Catégories Bloquer les derniers messages Bloquer Le saviez-vous ? Nous ne sommes pas riches de ce que nous possédons mais de ce dont nous pouvons nous passer. La patience est la force du faible, l'impatience est la faiblesse du fort."
      }
    ]
  }
}

Schema Configuration

Die Direktive @strTranslate erfordert drei Argumente:

  • provider: der Anbieter, der für die Übersetzung verwendet werden soll
  • from: der Sprachcode des Ausgangstexts
  • to: der Sprachcode, in den übersetzt werden soll

Du kannst für diese Eigenschaften einen Standardwert im Tab "Schema Configuration => Translation" auf der Einstellungsseite festlegen. Diese Werte werden verwendet, wenn eines der Argumente in der query nicht angegeben wird:

{
  posts {
    title @strTranslate
  }
}

Wenn Standardwerte definiert sind, wird das entsprechende Argument im GraphQL-Schema außerdem nicht mehr als Pflichtfeld behandelt.

Standardmäßig entspricht der from-Standardwert der in WordPress verwendeten Sprache.

Über die Einstellungen

Trage die Felder provider/from/to in das entsprechende Eingabefeld auf der Einstellungsseite ein und klicke auf "Save Changes (All)":

Den Standard-'provider' sowie die Sprachen 'from' und 'to' festlegen
Den Standard-'provider' sowie die Sprachen 'from' und 'to' festlegen

In wp-config.php

Füge Konstanten in wp-config.php hinzu:

  • GATOGRAPHQL_TRANSLATION_DEFAULT_PROVIDER
  • GATOGRAPHQL_TRANSLATION_DEFAULT_FROM_LANG_CODE
  • GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE

Zum Beispiel:

define( 'GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE', 'fr' );

Über Umgebungsvariablen

Definiere Umgebungsvariablen:

  • TRANSLATION_DEFAULT_PROVIDER
  • TRANSLATION_DEFAULT_FROM_LANG_CODE
  • TRANSLATION_DEFAULT_TO_LANG_CODE

Mehrsprachige Übersetzung Sync/Async

Die Direktive @strTranslate sendet pro Sprache eine Anfrage. Wenn du in mehrere Sprachen übersetzt, kannst du entscheiden, ob die Anfragen asynchron (d. h. parallel) oder synchron (d. h. sequenziell) gesendet werden sollen.

Synchrone vs. asynchrone Anfragen:

  • Synchron: Jede Übersetzungsanfrage wartet, bis die vorherige abgeschlossen ist, bevor sie startet. Langsamer, aber sicherer hinsichtlich Rate-Limits.
  • Asynchron: Alle Übersetzungsanfragen werden gleichzeitig gesendet. Schneller, kann aber Rate-Limits treffen, wenn zu viele Anfragen auf einmal gesendet werden.
Sync/Async-Modus verwenden, um mehrere Sprachen gleichzeitig zu übersetzen
Sync/Async-Modus verwenden, um mehrere Sprachen gleichzeitig zu übersetzen

Request- und Connection-Timeouts

Das Übersetzen eines langen Dokuments über einen Drittanbieter kann langsam sein, und ein hängender Upstream würde sonst einen PHP-Worker blockieren, bis PHP selbst die Anfrage abbricht.

Dein Webserver setzt eine maximale Laufzeit für jede PHP-Anfrage über die Direktive max_execution_time durch (gesetzt in php.ini oder über das Hosting-Kontrollpanel — cPanel stellt sie in der Regel unter "Select PHP Version" → "Options" bereit, und verwaltete Hosts wie SiteGround / Kinsta Engine zeigen sie in ihren PHP-Einstellungen an).

Das Plugin stellt auf der Einstellungsseite unter Plugin Configuration > Translation zwei Optionen zur Verfügung:

  • Request timeout: die maximale Wartezeit (in Sekunden) auf die vollständige Antwort des Übersetzungsanbieters
  • Connection timeout: die maximale Wartezeit (in Sekunden) beim Herstellen der Verbindung zum Übersetzungsanbieter
Den Request-Timeout und den Connection-Timeout für die Übersetzung festlegen
Den Request-Timeout und den Connection-Timeout für die Übersetzung festlegen

Diese Werte sollten unterhalb des max_execution_time deines Servers liegen, damit eine hängende Übersetzung sauber mit einer kontrollierten Fehlermeldung scheitert, anstatt den generischen Server-Timeout auszulösen (HTTP 502 / 504 oder eine leere Seite mit "Maximum execution time of N seconds exceeded"). Falls deine Übersetzungen regelmäßig einen Timeout verursachen, erhöhe beide Werte zusammen mit dem max_execution_time deines Servers.

Debugging von API-Anfragen

Um die Anfragen an Übersetzungsanbieter (wie ChatGPT, Claude oder Google Translate) und deren Antworten zu debuggen, kannst du den Schweregrad 🔵 Info in den Logs-Einstellungen aktivieren.

Dadurch enthalten die Logs alle Interaktionen mit den Übersetzungsanbietern, gespeichert unter den Einträgen api-requests.

KI-Anfragen in den Logs
KI-Anfragen in den Logs

Was protokolliert wird

Für KI-Anbieter enthält der Eintrag api-requests detaillierte Informationen zu:

  • Dem Prompt, der an den Übersetzungsanbieter gesendet wurde
  • Der vollständigen empfangenen Antwort
  • Eventuellen Fehlern oder Problemen während der Kommunikation
  • Dem verwendeten Modell
  • Der Anzahl der verwendeten Tokens
Detail einer KI-Anfrage in den Logs
Detail einer KI-Anfrage in den Logs

Das folgende JSON "Additional context" zeigt zum Beispiel die Details einer an ChatGPT gesendeten Anfrage und deren Antwort:

{
  "request": {
    "model": "gpt-4o-mini",
    "messages": [
      {
        "role": "system",
        "content": "You are a language translator."
      },
      {
        "role": "user",
        "content": "I'm working on internationalizing my application.\n\nI've created a JSON with sentences in English. Please translate the sentences to Spanish from .\n\nIf a sentence contains HTML, do not translate inside the HTML tags. Keep emojis exactly as they are, do not translate them.\n\nThis is the JSON:\n\n[\"Welcome to a single post full of blocks!\",\"Repeating the privacy policy\",\"Explaining the privacy policy\",\"HTTP caching improves performance\",\"Public or Private API mode, for extra security\",\"GraphQL or REST? Why not both?\",\"Customize the schema for each client\",\"Nested mutations are a must have\",\"Working on flat chain syntax next\",\"Released v0.6, check it out\"]"
      }
    ],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "translation_response",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "translations": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "required": [
            "translations"
          ],
          "additionalProperties": false
        }
      }
    }
  },
  "response": {
    "id": "chatcmpl-BbjNiuO5Si1vhalfIXYU0hWiCmg12",
    "object": "chat.completion",
    "created": 1748332282,
    "model": "gpt-4o-mini-2024-07-18",
    "choices": [
      {
        "index": 0,
        "message": {
          "role": "assistant",
          "content": "{\"translations\":[\"¡Bienvenido a una publicación única llena de bloques!\",\"Repitiendo la política de privacidad\",\"Explicando la política de privacidad\",\"La caché HTTP mejora el rendimiento\",\"Modo API Público o Privado, para mayor seguridad\",\"¿GraphQL o REST? ¿Por qué no ambos?\",\"Personaliza el esquema para cada cliente\",\"Las mutaciones anidadas son imprescindibles\",\"Próximamente trabajando en la sintaxis de cadena plana\",\"Lanzada la versión v0.6, ¡échale un vistazo!\"]}",
          "refusal": null,
          "annotations": []
        },
        "logprobs": null,
        "finish_reason": "stop"
      }
    ],
    "usage": {
      "prompt_tokens": 184,
      "completion_tokens": 112,
      "total_tokens": 296,
      "prompt_tokens_details": {
        "cached_tokens": 0,
        "audio_tokens": 0
      },
      "completion_tokens_details": {
        "reasoning_tokens": 0,
        "audio_tokens": 0,
        "accepted_prediction_tokens": 0,
        "rejected_prediction_tokens": 0
      }
    },
    "service_tier": "default",
    "system_fingerprint": "fp_34a54ae93c"
  }
}