Tradução
TraduçãoTradução

Tradução

Diretiva @strTranslate para traduzir o valor de um campo usando a API de qualquer provedor.

Description

Adicione a diretiva @strTranslate a qualquer campo do tipo String, para traduzi-lo para o idioma desejado.

Por exemplo, esta query traduz os campos title e excerpt do post do inglês para o francês (usando o provedor de API padrão):

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

...produzindo:

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

A diretiva @strTranslate exige o fornecimento de três argumentos:

  • provider: o provedor a ser utilizado para a tradução
  • from: o código do idioma do texto de origem
  • to: o código do idioma para o qual traduzir

Podemos definir um valor padrão para essas propriedades na aba "Schema Configuration => Translation" da página de Configurações. Esses valores serão usados sempre que algum desses argumentos não for fornecido na query:

{
  posts {
    title @strTranslate
  }
}

Além disso, ao definir valores padrão, o argumento correspondente no schema GraphQL deixa de ser obrigatório.

Por padrão, o valor padrão de from é o idioma usado no WordPress.

Pelas Configurações

Insira os campos provider/from/to no campo de entrada correspondente na página de Configurações e clique em "Save Changes (All)":

Definindo o 'provider' padrão e os idiomas 'from' e 'to'
Definindo o 'provider' padrão e os idiomas 'from' e 'to'

Em wp-config.php

Adicione constantes em wp-config.php:

  • GATOGRAPHQL_TRANSLATION_DEFAULT_PROVIDER
  • GATOGRAPHQL_TRANSLATION_DEFAULT_FROM_LANG_CODE
  • GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE

Por exemplo:

define( 'GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE', 'fr' );

Por variável de ambiente

Defina variáveis de ambiente:

  • TRANSLATION_DEFAULT_PROVIDER
  • TRANSLATION_DEFAULT_FROM_LANG_CODE
  • TRANSLATION_DEFAULT_TO_LANG_CODE

Tradução multilíngue Sync/Async

A diretiva @strTranslate enviará uma requisição por idioma para traduzir. Ao traduzir para múltiplos idiomas, você pode decidir se deseja enviar as requisições de forma assíncrona (ou seja, em paralelo) ou síncrona (ou seja, em sequência).

Requisições Síncronas vs Assíncronas:

  • Síncrona: Cada requisição de tradução aguarda a conclusão da anterior antes de iniciar. Mais lenta, porém mais segura em relação a limites de taxa.
  • Assíncrona: Todas as requisições de tradução são enviadas simultaneamente. Mais rápida, porém pode atingir limites de taxa se muitas requisições forem enviadas de uma vez.
Usando o modo sync/async para traduzir múltiplos idiomas de uma vez
Usando o modo sync/async para traduzir múltiplos idiomas de uma vez

Timeouts de requisição e de conexão

Traduzir um documento longo via um provedor terceiro pode ser lento, e um upstream travado manteria um worker PHP ocupado até que o próprio PHP encerrasse a requisição.

Seu servidor web aplica um tempo máximo de execução para cada requisição PHP por meio da diretiva max_execution_time (definida em php.ini, ou via o painel de controle do seu hospedeiro — o cPanel geralmente a expõe em "Select PHP Version" → "Options", e hosts gerenciados como SiteGround / Kinsta Engine a apresentam em suas configurações de PHP).

O plugin expõe duas opções na página de Configurações, em Plugin Configuration > Translation:

  • Request timeout: o tempo máximo (em segundos) para aguardar a resposta completa do provedor de tradução
  • Connection timeout: o tempo máximo (em segundos) para aguardar ao estabelecer a conexão com o provedor de tradução
Definindo o Request timeout e o Connection timeout para tradução
Definindo o Request timeout e o Connection timeout para tradução

Esses valores devem ser mantidos abaixo do max_execution_time do seu servidor para que uma tradução travada falhe de forma limpa com uma mensagem de erro controlada, em vez de acionar o timeout genérico do servidor (HTTP 502 / 504, ou uma página em branco "Maximum execution time of N seconds exceeded"). Se suas traduções regularmente atingirem o timeout, aumente ambos esses valores e o max_execution_time do seu servidor em conjunto.

Depuração de requisições de API

Para depurar as requisições enviadas aos provedores de tradução (como ChatGPT, Claude ou Google Translate) e suas respostas, você pode habilitar o nível de severidade 🔵 Info nas configurações de Logs.

Ao fazer isso, os logs conterão todas as interações com os provedores de tradução, armazenadas sob as entradas api-requests.

Requisições de IA nos Logs
Requisições de IA nos Logs

O que é registrado

Para provedores de IA, a entrada api-requests contém informações detalhadas sobre:

  • O prompt enviado ao provedor de tradução
  • A resposta completa recebida
  • Quaisquer erros ou problemas durante a comunicação
  • O modelo utilizado
  • O número de tokens utilizados
Detalhe de uma requisição de IA nos Logs
Detalhe de uma requisição de IA nos Logs

Por exemplo, o seguinte JSON "Additional context" mostra os detalhes de uma requisição enviada ao ChatGPT e sua resposta:

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