Translation
Translationการแปลภาษา

การแปลภาษา

Directive @strTranslate สำหรับแปลค่าของฟิลด์โดยใช้ API ของผู้ให้บริการใดก็ได้

คำอธิบาย

เพิ่ม directive @strTranslate ลงในฟิลด์ประเภท String ใดก็ได้ เพื่อแปลฟิลด์นั้นไปยังภาษาที่ต้องการ

ตัวอย่างเช่น queries นี้แปลฟิลด์ title และ excerpt ของโพสต์จากภาษาอังกฤษเป็นภาษาฝรั่งเศส (โดยใช้ผู้ให้บริการ API เริ่มต้น):

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

...ได้ผลลัพธ์:

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

Directive @strTranslate ต้องการอาร์กิวเมนต์สามตัว:

  • provider: ผู้ให้บริการที่ใช้สำหรับการแปล
  • from: รหัสภาษาของข้อความต้นฉบับ
  • to: รหัสภาษาที่ต้องการแปลไป

เราสามารถกำหนดค่าเริ่มต้นสำหรับคุณสมบัติเหล่านี้ได้ในแท็บ "Schema Configuration => Translation" บนหน้าการตั้งค่า ค่าเหล่านี้จะถูกใช้เมื่อไม่ได้ระบุอาร์กิวเมนต์ใดอาร์กิวเมนต์หนึ่งใน queries:

{
  posts {
    title @strTranslate
  }
}

นอกจากนี้ เมื่อกำหนดค่าเริ่มต้น อาร์กิวเมนต์ที่สอดคล้องกันใน GraphQL schema จะกลายเป็นฟิลด์ที่ไม่บังคับ

ค่าเริ่มต้นของ from คือภาษาที่ใช้ใน WordPress

การตั้งค่าผ่าน Settings

ป้อนฟิลด์ provider/from/to ในช่องป้อนข้อมูลที่เกี่ยวข้องในหน้าการตั้งค่า แล้วคลิก "Save Changes (All)":

การตั้งค่า 'provider' และภาษา 'from' และ 'to' เริ่มต้น
การตั้งค่า 'provider' และภาษา 'from' และ 'to' เริ่มต้น

ใน wp-config.php

เพิ่มค่าคงที่ใน wp-config.php:

  • GATOGRAPHQL_TRANSLATION_DEFAULT_PROVIDER
  • GATOGRAPHQL_TRANSLATION_DEFAULT_FROM_LANG_CODE
  • GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE

ตัวอย่างเช่น:

define( 'GATOGRAPHQL_TRANSLATION_DEFAULT_TO_LANG_CODE', 'fr' );

ผ่านตัวแปรสภาพแวดล้อม

กำหนดตัวแปรสภาพแวดล้อม:

  • TRANSLATION_DEFAULT_PROVIDER
  • TRANSLATION_DEFAULT_FROM_LANG_CODE
  • TRANSLATION_DEFAULT_TO_LANG_CODE

การแปลหลายภาษาแบบ Sync/Async

Directive @strTranslate จะส่งคำขอต่อหนึ่งภาษาสำหรับการแปล เมื่อแปลเป็นหลายภาษา คุณสามารถเลือกได้ว่าจะส่งคำขอแบบ asynchronous (คือแบบขนาน) หรือ synchronous (คือแบบลำดับ)

คำขอแบบ Synchronous กับ Asynchronous:

  • Synchronous: แต่ละคำขอการแปลจะรอให้คำขอก่อนหน้าเสร็จสิ้นก่อนจึงจะเริ่ม ช้ากว่าแต่ปลอดภัยกว่ากับข้อจำกัดอัตราการส่งคำขอ
  • Asynchronous: คำขอการแปลทั้งหมดถูกส่งพร้อมกัน เร็วกว่าแต่อาจถึงขีดจำกัดอัตราการส่งคำขอหากมีการส่งคำขอจำนวนมากพร้อมกัน
การใช้โหมด sync/async เพื่อแปลหลายภาษาพร้อมกัน
การใช้โหมด sync/async เพื่อแปลหลายภาษาพร้อมกัน

การหมดเวลาของคำขอและการเชื่อมต่อ

การแปลเอกสารยาวผ่านผู้ให้บริการบุคคลที่สามอาจใช้เวลานาน และหากเซิร์ฟเวอร์ต้นทางค้างอยู่ก็จะทำให้ PHP worker ถูกครอบครองจนกว่า PHP จะยุติคำขอเอง

เว็บเซิร์ฟเวอร์ของคุณบังคับใช้เวลาสูงสุดสำหรับทุกคำขอ PHP ผ่าน directive max_execution_time (ตั้งค่าใน php.ini หรือผ่านแผงควบคุมของโฮสติ้ง — cPanel มักแสดงภายใต้ "Select PHP Version" → "Options" และโฮสต์แบบ managed อย่าง SiteGround / Kinsta Engine จะแสดงภายใต้การตั้งค่า PHP)

ปลั๊กอินนี้มีตัวเลือกสองรายการในหน้าการตั้งค่า ภายใต้ Plugin Configuration > Translation:

  • Request timeout: เวลาสูงสุด (เป็นวินาที) ที่รอการตอบกลับครบถ้วนจากผู้ให้บริการแปล
  • Connection timeout: เวลาสูงสุด (เป็นวินาที) ที่รอการเชื่อมต่อกับผู้ให้บริการแปล
การตั้งค่า Request timeout และ Connection timeout สำหรับการแปล
การตั้งค่า Request timeout และ Connection timeout สำหรับการแปล

ค่าเหล่านี้ควรถูกเก็บให้ต่ำกว่า max_execution_time ของเซิร์ฟเวอร์ เพื่อให้การแปลที่ค้างอยู่ล้มเหลวอย่างสวยงามพร้อมข้อความแสดงข้อผิดพลาดที่ควบคุมได้ แทนที่จะทำให้เกิด timeout ของเซิร์ฟเวอร์ทั่วไป (HTTP 502 / 504 หรือหน้าว่างที่ระบุว่า "Maximum execution time of N seconds exceeded") หากการแปลหมดเวลาบ่อยครั้ง ให้เพิ่มค่า ทั้งสอง นี้และ max_execution_time ของเซิร์ฟเวอร์พร้อมกัน

การดีบัก API Requests

เพื่อดีบักคำขอที่ส่งไปยังผู้ให้บริการแปล (เช่น ChatGPT, Claude หรือ Google Translate) และการตอบกลับของพวกเขา คุณสามารถเปิดใช้งานระดับความรุนแรง 🔵 Info ในการตั้งค่า Logs

เมื่อเปิดใช้งาน บันทึกจะมีการโต้ตอบทั้งหมดกับผู้ให้บริการแปล เก็บไว้ภายใต้รายการ api-requests

AI requests ในบันทึก
AI requests ในบันทึก

สิ่งที่ถูกบันทึก

สำหรับผู้ให้บริการ AI รายการ api-requests ประกอบด้วยข้อมูลโดยละเอียดเกี่ยวกับ:

  • Prompt ที่ส่งไปยังผู้ให้บริการแปล
  • การตอบกลับครบถ้วนที่ได้รับ
  • ข้อผิดพลาดหรือปัญหาที่เกิดขึ้นระหว่างการสื่อสาร
  • โมเดลที่ใช้
  • จำนวน tokens ที่ใช้
รายละเอียด AI request ในบันทึก
รายละเอียด AI request ในบันทึก

ตัวอย่างเช่น JSON "Additional context" ต่อไปนี้แสดงรายละเอียดของคำขอที่ส่งไปยัง ChatGPT และการตอบกลับ:

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