Translation
TranslationTerjemahan

Terjemahan

Direktif @strTranslate untuk menerjemahkan nilai field menggunakan API dari provider mana pun.

Deskripsi

Tambahkan direktif @strTranslate ke field apa pun bertipe String, untuk menerjemahkannya ke bahasa yang diinginkan.

Misalnya, query ini menerjemahkan field title dan excerpt dari postingan dari bahasa Inggris ke bahasa Prancis (menggunakan provider API default):

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

...menghasilkan:

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

Direktif @strTranslate memerlukan tiga argumen:

  • provider: provider yang digunakan untuk terjemahan
  • from: kode bahasa dari teks sumber
  • to: kode bahasa tujuan terjemahan

Kita dapat mendefinisikan nilai default untuk properti-properti ini di tab "Schema Configuration => Translation" pada halaman Settings. Nilai-nilai ini akan digunakan setiap kali argumen tersebut tidak disediakan dalam query:

{
  posts {
    title @strTranslate
  }
}

Selain itu, saat mendefinisikan nilai default, argumen yang sesuai dalam skema GraphQL menjadi tidak wajib.

Secara default, nilai from default adalah bahasa yang digunakan di WordPress.

Melalui Settings

Masukkan field provider/from/to pada input yang sesuai di halaman Settings, lalu klik "Save Changes (All)":

Mengatur 'provider' default, serta bahasa 'from' dan 'to'
Mengatur 'provider' default, serta bahasa 'from' dan 'to'

Di wp-config.php

Tambahkan konstanta di wp-config.php:

  • GATOGRAPHQL_TRANSLATION_DEFAULT_PROVIDER
  • GATOGRAPHQL_TRANSLATION_DEFAULT_FROM_LANG_CODE
  • GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE

Misalnya:

define( 'GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE', 'fr' );

Melalui variabel lingkungan

Definisikan variabel lingkungan:

  • TRANSLATION_DEFAULT_PROVIDER
  • TRANSLATION_DEFAULT_FROM_LANG_CODE
  • TRANSLATION_DEFAULT_TO_LANG_CODE

Terjemahan multi-bahasa Sync/Async

Direktif @strTranslate akan mengirim satu permintaan per bahasa untuk diterjemahkan. Saat menerjemahkan ke beberapa bahasa, Anda dapat memilih apakah akan mengirim permintaan secara asinkron (yaitu secara paralel) atau secara sinkron (yaitu secara berurutan).

Permintaan Sinkron vs Asinkron:

  • Sinkron: Setiap permintaan terjemahan menunggu permintaan sebelumnya selesai sebelum dimulai. Lebih lambat tetapi lebih aman dengan batasan rate.
  • Asinkron: Semua permintaan terjemahan dikirim secara bersamaan. Lebih cepat tetapi dapat mencapai batasan rate jika terlalu banyak permintaan dikirim sekaligus.
Menggunakan mode sync/async untuk menerjemahkan beberapa bahasa sekaligus
Menggunakan mode sync/async untuk menerjemahkan beberapa bahasa sekaligus

Timeout Permintaan dan Koneksi

Menerjemahkan dokumen panjang melalui provider pihak ketiga bisa lambat, dan upstream yang tergantung sebaliknya akan menahan worker PHP hingga PHP sendiri menghentikan permintaan tersebut.

Server web Anda memberlakukan waktu eksekusi maksimum untuk setiap permintaan PHP melalui direktif max_execution_time (diatur di php.ini, atau melalui panel kontrol hosting Anda — cPanel biasanya menampilkannya di "Select PHP Version" → "Options", dan host terkelola seperti SiteGround / Kinsta Engine memperlihatkannya di pengaturan PHP mereka).

Plugin ini memperlihatkan dua opsi pada halaman Settings, di bawah Plugin Configuration > Translation:

  • Request timeout: waktu maksimum (dalam detik) untuk menunggu respons lengkap dari provider terjemahan
  • Connection timeout: waktu maksimum (dalam detik) untuk menunggu saat membuat koneksi ke provider terjemahan
Mengatur Request timeout dan Connection timeout untuk terjemahan
Mengatur Request timeout dan Connection timeout untuk terjemahan

Nilai-nilai ini sebaiknya dijaga di bawah max_execution_time server Anda agar terjemahan yang terhenti gagal dengan bersih menggunakan pesan error yang terkontrol, alih-alih memicu timeout server generik (HTTP 502 / 504, atau halaman kosong "Maximum execution time of N seconds exceeded"). Jika terjemahan Anda secara rutin mengalami timeout, naikkan kedua nilai ini beserta max_execution_time server Anda secara bersamaan.

Debugging Permintaan API

Untuk men-debug permintaan yang dikirim ke provider terjemahan (seperti ChatGPT, Claude atau Google Translate) dan respons mereka, Anda dapat mengaktifkan level keparahan 🔵 Info di pengaturan Logs.

Saat melakukan itu, log akan berisi semua interaksi dengan provider terjemahan, tersimpan di bawah entri api-requests.

Permintaan AI di Logs
Permintaan AI di Logs

Yang Dicatat

Untuk provider AI, entri api-requests berisi informasi rinci tentang:

  • Prompt yang dikirim ke provider terjemahan
  • Respons lengkap yang diterima
  • Kesalahan atau masalah apa pun selama komunikasi
  • Model yang digunakan
  • Jumlah token yang digunakan
Detail permintaan AI di Logs
Detail permintaan AI di Logs

Misalnya, JSON "Additional context" berikut menunjukkan detail permintaan yang dikirim ke ChatGPT, beserta responsnya:

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