Tłumaczenie
TłumaczenieTłumaczenie

Tłumaczenie

Dyrektywa @strTranslate do tłumaczenia wartości pola przy użyciu API dowolnego dostawcy.

Description

Dodaj dyrektywę @strTranslate do dowolnego pola typu String, aby przetłumaczyć je na wybrany język.

Na przykład poniższe query tłumaczy pola title i excerpt wpisu z angielskiego na francuski (używając domyślnego dostawcy API):

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

...dając w wyniku:

{
  "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

Dyrektywa @strTranslate wymaga podania trzech argumentów:

  • provider: dostawca używany do tłumaczenia
  • from: kod języka tekstu źródłowego
  • to: kod języka, na który ma nastąpić tłumaczenie

Możemy zdefiniować wartości domyślne dla tych właściwości w zakładce "Schema Configuration => Translation" na stronie Ustawień. Wartości te będą używane zawsze, gdy którykolwiek z tych argumentów nie zostanie podany w query:

{
  posts {
    title @strTranslate
  }
}

Ponadto po zdefiniowaniu wartości domyślnych odpowiedni argument w schemacie GraphQL przestaje być obowiązkowy.

Domyślnie wartość domyślna from to język używany w WordPress.

W Ustawieniach

Wpisz pola provider/from/to w odpowiednim polu na stronie Ustawień i kliknij "Save Changes (All)":

Ustawianie domyślnego 'provider' oraz języków 'from' i 'to'
Ustawianie domyślnego 'provider' oraz języków 'from' i 'to'

W wp-config.php

Dodaj stałe w wp-config.php:

  • GATOGRAPHQL_TRANSLATION_DEFAULT_PROVIDER
  • GATOGRAPHQL_TRANSLATION_DEFAULT_FROM_LANG_CODE
  • GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE

Na przykład:

define( 'GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE', 'fr' );

Za pomocą zmiennej środowiskowej

Zdefiniuj zmienne środowiskowe:

  • TRANSLATION_DEFAULT_PROVIDER
  • TRANSLATION_DEFAULT_FROM_LANG_CODE
  • TRANSLATION_DEFAULT_TO_LANG_CODE

Wielojęzyczne tłumaczenie Sync/Async

Dyrektywa @strTranslate wysyła jedno żądanie na język do przetłumaczenia. Podczas tłumaczenia na wiele języków możesz zdecydować, czy wysyłać żądania asynchronicznie (czyli równolegle), czy synchronicznie (czyli sekwencyjnie).

Żądania synchroniczne vs asynchroniczne:

  • Synchroniczne: Każde żądanie tłumaczenia czeka na zakończenie poprzedniego przed rozpoczęciem. Wolniejsze, ale bezpieczniejsze przy limitach częstotliwości.
  • Asynchroniczne: Wszystkie żądania tłumaczenia są wysyłane jednocześnie. Szybsze, ale może prowadzić do przekroczenia limitów częstotliwości, jeśli jednocześnie wysłano zbyt wiele żądań.
Używanie trybu sync/async do tłumaczenia wielu języków jednocześnie
Używanie trybu sync/async do tłumaczenia wielu języków jednocześnie

Limity czasu żądania i połączenia

Tłumaczenie długiego dokumentu przez zewnętrznego dostawcę może być powolne, a zawieszony upstream zajmowałby wątek PHP aż do momentu, gdy sam PHP zakończyłby żądanie.

Twój serwer internetowy wymusza maksymalny czas wykonania dla każdego żądania PHP za pomocą dyrektywy max_execution_time (ustawionej w php.ini lub za pośrednictwem panelu sterowania hostingu — cPanel zazwyczaj udostępnia ją w "Select PHP Version" → "Options", a zarządzane hosty takie jak SiteGround / Kinsta Engine prezentują ją w swoich ustawieniach PHP).

Wtyczka udostępnia dwie opcje na stronie Ustawień, w sekcji Plugin Configuration > Translation:

  • Request timeout: maksymalny czas oczekiwania (w sekundach) na pełną odpowiedź od dostawcy tłumaczenia
  • Connection timeout: maksymalny czas oczekiwania (w sekundach) przy nawiązywaniu połączenia z dostawcą tłumaczenia
Ustawianie limitu czasu żądania i połączenia dla tłumaczenia
Ustawianie limitu czasu żądania i połączenia dla tłumaczenia

Wartości te powinny być niższe niż max_execution_time serwera, aby zawieszone tłumaczenie kończyło się w kontrolowany sposób z czytelnym komunikatem o błędzie, zamiast wyzwalać ogólny limit czasu serwera (HTTP 502 / 504 lub pusta strona "Maximum execution time of N seconds exceeded"). Jeśli tłumaczenia regularnie przekraczają limit czasu, zwiększ obie te wartości oraz max_execution_time serwera jednocześnie.

Debugowanie żądań API

Aby debugować żądania wysyłane do dostawców tłumaczeń (takich jak ChatGPT, Claude lub Google Translate) i ich odpowiedzi, możesz włączyć poziom ważności 🔵 Info w ustawieniach Logów.

Po włączeniu tej opcji logi będą zawierać wszystkie interakcje z dostawcami tłumaczeń, zapisane w pozycjach api-requests.

Żądania AI w Logach
Żądania AI w Logach

Co jest rejestrowane

W przypadku dostawców AI pozycja api-requests zawiera szczegółowe informacje na temat:

  • Promptu wysłanego do dostawcy tłumaczenia
  • Kompletnej otrzymanej odpowiedzi
  • Wszelkich błędów lub problemów podczas komunikacji
  • Użytego modelu
  • Liczby użytych tokenów
Szczegół żądania AI w Logach
Szczegół żądania AI w Logach

Na przykład poniższy JSON "Additional context" pokazuje szczegóły żądania wysłanego do ChatGPT i jego odpowiedź:

{
  "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"
  }
}