การแปล WordPress JSON: การแปล JavaScript ของ Block Editor

คุณได้แปลปลั๊กอินของคุณแล้ว สตริง PHP แสดงผลได้อย่างสมบูรณ์ในการตั้งค่าผู้ดูแลระบบ, เทมเพลตส่วนหน้า, การแจ้งเตือนทางอีเมล — ทั้งหมดเป็นภาษาท้องถิ่น จากนั้นเมื่อคุณเปิด Block editor ทุกป้ายกำกับใน Gutenberg block ที่กำหนดเองของคุณยังคงเป็นภาษาอังกฤษอย่างดื้อรั้นและน่าหงุดหงิด ปุ่ม "Add Item", ส่วนหัวของแผงตรวจสอบ, ข้อความตัวยึด ไฟล์ .mo ของคุณโหลดแล้ว แล้วทำไมสตริงเหล่านี้ถึงไม่ถูกแปล?
เนื่องจาก WordPress 5.0 และการมาของ Gutenberg สตริง JavaScript ไม่ได้มาจากไฟล์ .mo ของคุณเลย พวกมันต้องการไฟล์ WordPress JSON translation แยกต่างหากสำหรับแต่ละสคริปต์ — และหากคุณไม่สร้างไฟล์นี้ Block editor ของคุณก็จะยังคงเป็นภาษาอังกฤษไม่ว่าไฟล์ .po ของคุณจะสมบูรณ์แค่ไหนก็ตาม นี่คือหนึ่งในช่องว่างของการแปลภาษาที่พบบ่อยและสร้างความสับสนมากที่สุดในการพัฒนา WordPress สมัยใหม่ คู่มือนี้จะอธิบายอย่างละเอียดว่าทำไมถึงเกิดเหตุการณ์นี้ขึ้น ระบบการแปล JSON ทำงานอย่างไร ชื่อไฟล์ที่แฮชด้วย MD5 ที่ทำให้ทุกคนสับสน และชุดเครื่องมือทั้งหมดเพื่อแก้ไขปัญหานี้
ทำไมสตริงใน Block Editor ของคุณถึงยังคงเป็นภาษาอังกฤษ
คำตอบสั้นๆ: PHP และ JavaScript ใช้ระบบการส่งการแปลที่แตกต่างกันอย่างสิ้นเชิงใน WordPress และไฟล์ .mo ของคุณจะใช้ได้กับ PHP เท่านั้น
สองระบบการแปล, หนึ่งปลั๊กอิน
เมื่อ WordPress รัน load_plugin_textdomain() มันจะอ่านไฟล์ .mo ที่คอมไพล์แล้วของคุณเข้าสู่หน่วยความจำ PHP การเรียกใช้ฟังก์ชัน __(), _e(), และ _x() ทุกครั้งในโค้ด PHP ของคุณจะค้นหาคำแปลที่นั่น นี่เป็นเพราะ PHP ทำงานบนฝั่งเซิร์ฟเวอร์ — ข้อมูล .mo อยู่ในกระบวนการเดียวกัน
JavaScript แตกต่างออกไป โค้ดบล็อกของคุณทำงานในเบราว์เซอร์ หลังจาก PHP ทำงานเสร็จสิ้นไปนานแล้ว มันไม่สามารถเข้าถึงไฟล์ .mo ที่อยู่บนฝั่งเซิร์ฟเวอร์ได้ แต่แพ็กเกจ @wordpress/i18n — ซึ่งเป็น Gettext เทียบเท่าสำหรับ JS, ที่เปิดเผยฟังก์ชัน __(), _x(), และ sprintf() ให้กับสคริปต์ของคุณ — คาดหวังว่าการแปลจะถูกส่งมาในรูปแบบ JSON payload ที่แนบมากับสคริปต์เฉพาะที่ต้องการ
จะเกิดอะไรขึ้นกับสตริง JS ที่ไม่ถูกแปล
ดังนั้นบล็อกที่มีสตริงเช่นนี้:
import { __ } from '@wordpress/i18n';
registerBlockType( 'myplugin/feature-box', {
title: __( 'Feature Box', 'myplugin' ),
edit: () => {
return <Button>{ __( 'Add Item', 'myplugin' ) }</Button>;
},
} );
จะไม่มีทางพบ "Feature Box" หรือ "Add Item" ในไฟล์ .mo ของคุณ เพราะเบราว์เซอร์ไม่เคยอ่านไฟล์ .mo สตริงเหล่านั้นจำเป็นต้องมาถึงในรูปแบบ JSON ซึ่งเชื่อมโยงกับ script handle นี้โดยเฉพาะ หากคุณยังไม่ได้ตั้งค่าดังกล่าว การเรียกใช้ __() ของ JS ก็จะคืนค่าเป็นภาษาอังกฤษต้นฉบับ — อย่างเงียบๆ โดยไม่มีข้อผิดพลาดในคอนโซล
การเชื่อมโยงการแปล JSON ด้วย wp_set_script_translations()
สะพานเชื่อมระหว่างสคริปต์ของคุณและการแปล JSON คือฟังก์ชัน PHP เพียงฟังก์ชันเดียว: wp_set_script_translations() คำตอบสำหรับคำถามที่ว่า "WordPress รู้ได้อย่างไรว่าไฟล์ JSON ใดเป็นของสคริปต์ใด" คือ: คุณเป็นคนบอกโดยการลงทะเบียนสคริปต์ จากนั้นจึงประกาศ text domain และโฟลเดอร์ที่ไฟล์ JSON อยู่
การลงทะเบียนสคริปต์และโฟลเดอร์การแปล
add_action( 'init', function () {
wp_register_script(
'myplugin-editor',
plugins_url( 'build/index.js', __FILE__ ),
array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
'1.0.0'
);
// Tell WordPress where this script's JSON translations live
wp_set_script_translations(
'myplugin-editor', // the registered script handle
'myplugin', // text domain
plugin_dir_path( __FILE__ ) . 'languages'
);
} );
เมื่อ editor โหลด myplugin-editor ตอนนี้ WordPress จะรู้ว่าต้องค้นหาไฟล์ JSON ที่ตรงกับสคริปต์นี้และ locale ของผู้ใช้ปัจจุบันในโฟลเดอร์ languages/ ของคุณ หากพบไฟล์ดังกล่าว WordPress จะแทรกคำแปลก่อนที่สคริปต์ของคุณจะทำงาน และการเรียกใช้ __() ของ JS ก็จะทำงานได้อย่างถูกต้อง handle ที่คุณส่งต้องตรงกับสคริปต์ที่ลงทะเบียนไว้อย่างแน่นอน — handle ที่ไม่ตรงหรือไม่พบเป็นสาเหตุอันดับสองที่พบบ่อยที่สุดที่ทำให้การแปลล้มเหลวโดยไม่มีข้อผิดพลาด
ชื่อไฟล์ที่แฮชด้วย MD5 ที่ไม่มีใครคาดคิด
นี่คือรายละเอียดที่ทำให้เกือบทุกคนหลงทาง ไฟล์ JSON ที่ WordPress ค้นหาไม่ได้มีชื่อที่เรียบร้อยอย่าง myplugin-fr_FR.json แต่มีชื่อเป็น MD5 hash ของเส้นทางต้นฉบับของสคริปต์:
การถอดรหัสรูปแบบชื่อไฟล์
myplugin-fr_FR-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.json
รูปแบบคือ {textdomain}-{locale}-{md5}.json โดยที่ hash คือ MD5 ของเส้นทางสัมพัทธ์ไปยังไฟล์สคริปต์ (เช่น build/index.js) ตามที่ลงทะเบียนไว้ WordPress จะคำนวณ hash นี้ในขณะรันไทม์เพื่อค้นหาไฟล์ JSON ที่ถูกต้องสำหรับสคริปต์ที่ถูกต้อง หากคุณตั้งชื่อไฟล์ด้วยตัวเอง WordPress จะไม่พบไฟล์นั้น และคุณจะสาบานว่าระบบเสีย ทั้งที่มันแค่กำลังมองหาชื่อไฟล์ที่แตกต่างออกไป
คุณไม่จำเป็นต้องคำนวณ hash ด้วยตัวเอง คำสั่ง wp i18n ของ WP-CLI ทำหน้าที่นี้ให้คุณ ซึ่งเป็นเหตุผลว่าทำไมคุณต้องใช้เครื่องมือเหล่านี้แทนที่จะสร้างไฟล์เหล่านี้ด้วยตัวเอง อย่างไรก็ตาม การเข้าใจว่า hash มีอยู่จริงนั้นช่วยประหยัดเวลาได้หลายชั่วโมงเมื่อไฟล์ JSON อยู่ใน languages/ แต่ยังคงถูกละเว้น — เกือบตลอดเวลาเป็นเพราะ hash ของชื่อไฟล์ไม่ตรงกันเนื่องจากเส้นทางสคริปต์เปลี่ยนไป
เวิร์กโฟลว์เต็มรูปแบบ: จาก make-pot ไปยัง make-json
ข่าวดีคือคุณยังคงเก็บคำแปลของคุณไว้ในไฟล์ .po เดียวกันที่คุณใช้อยู่แล้ว ไฟล์ JSON เป็นผลลัพธ์ที่ได้จากการประมวลผลซึ่งสร้างขึ้นในขั้นตอนสุดท้าย คำตอบสำหรับคำถามที่ว่า "ฉันต้องแยกดูแลสตริง JS ต่างหากหรือไม่" คือไม่ — พวกมันอยู่ในไฟล์ .pot/.po เดียวกันกับสตริง PHP ของคุณ และมีคำสั่งพิเศษอีกหนึ่งคำสั่งที่จะแยกสตริง JS ออกมาเป็น JSON
ขั้นตอนการทำงานด้วยสี่คำสั่ง
นี่คือขั้นตอนการทำงานที่สมบูรณ์:
# 1. Extract ALL translatable strings (PHP and JS) into one template
wp i18n make-pot . languages/myplugin.pot
# 2. Translate languages/myplugin-fr_FR.po as usual (Poedit, AI, etc.)
# 3. Compile the .mo for PHP strings (server-side, as always)
wp i18n make-mo languages/
# 4. Generate the MD5-hashed JSON files for JS strings
wp i18n make-json languages/ --no-purge
คำสั่ง make-pot ในขั้นตอนที่ 1 ฉลาดพอที่จะสแกนทั้งไฟล์ .php และแหล่งที่มา .js/.jsx ของคุณ ดังนั้นไฟล์ .po เพียงไฟล์เดียวต่อ locale ก็จะเก็บทุกอย่างไว้ได้ คำสั่ง make-json ในขั้นตอนที่ 4 จะอ่านไฟล์ .po ที่แปลแล้วแต่ละไฟล์ ค้นหารายการที่มาจากไฟล์ JavaScript และเขียนไฟล์ JSON ที่มีการแฮชอย่างถูกต้องหนึ่งไฟล์ต่อสคริปต์ แฟล็ก --no-purge จะเก็บสตริง JS ไว้ในไฟล์ .po ของคุณด้วย ดังนั้น make-mo ในภายหลังจะไม่สูญเสียพวกมันไป — หากไม่มีแฟล็กนี้ make-json จะลบรายการ JS ออกจากไฟล์ .po ซึ่งสร้างความประหลาดใจให้กับผู้ที่รันคำสั่งผิดลำดับ
ไฟล์ JSON ที่สร้างขึ้นจะมีลักษณะเหมือนชุดการแปลในรูปแบบ Jed:
{
"translation-revision-date": "2026-06-12 10:00+0000",
"generator": "WP-CLI/2.x",
"domain": "messages",
"locale_data": {
"messages": {
"": { "domain": "messages", "lang": "fr_FR" },
"Feature Box": [ "Bloc fonctionnalité" ],
"Add Item": [ "Ajouter un élément" ]
}
}
}
WordPress จะอ่าน locale_data และส่งไปยัง @wordpress/i18n ก่อนที่สคริปต์ของคุณจะทำงาน ตอนนี้ __( 'Add Item', 'myplugin' ) ในเบราว์เซอร์จะคืนค่าเป็น Ajouter un élément และ Block editor ของคุณก็ได้รับการแปลเป็นภาษาท้องถิ่นเรียบร้อยแล้ว
ความแตกต่างจาก i18next JSON
ทั้งสองระบบใช้ JSON ทั้งคู่มุ่งเป้าไปที่ JavaScript และความคล้ายคลึงกันภายนอกนี้ทำให้เกิดความสับสนอย่างมาก พวกมันไม่สามารถใช้แทนกันได้ WordPress block-editor JSON เป็น payload ที่ได้มาจาก Gettext, แฮชด้วย MD5, สำหรับแต่ละสคริปต์ที่ @wordpress/i18n ใช้ i18next JSON เป็นไฟล์ key-value แบบ flat หรือ nested ที่ react-i18next หรือ next-intl ใช้ โดยมีไวยากรณ์ {{interpolation}} และข้อตกลงเกี่ยวกับ plural key ของตัวเอง
หากคุณกำลังทำงานใน React หรือ Next.js ธรรมดานอก WordPress คุณต้องการแนวทางของ i18next ซึ่งเราได้กล่าวถึงใน การแปล i18next JSON ใน React และ Next.js ภายใน WordPress คุณต้องการเวิร์กโฟลว์ make-json ที่กล่าวมาข้างต้น การสลับปนกัน — ตัวอย่างเช่น การเขียน JSON สไตล์ i18next แบบ flat ด้วยมือ และคาดหวังให้ wp_set_script_translations() โหลดไฟล์นั้น — จะไม่ทำงานเลย เพราะ WordPress กำลังมองหารูปแบบ Jed ที่มีการแฮช ไม่ใช่คู่ key-value แบบสุ่ม
หนึ่งแหล่งที่มา, ทุกรูปแบบที่คุณต้องการ
ความเปราะบางของทั้งหมดนี้คือขั้นตอนการแปลที่อยู่ตรงกลาง ไฟล์ .po ของคุณส่งข้อมูลให้ทั้ง .mo (PHP) และ JSON (JavaScript) ดังนั้นการแปลที่ผิดพลาดเพียงครั้งเดียว — เช่น %s ที่เสียหาย, แท็ก <strong> ที่เสีย, หรือ plural form ที่เปลี่ยนชื่อ — จะส่งผลเสียต่อผลลัพธ์ทั้งสองพร้อมกัน และเนื่องจากสตริง JS ถูกโหลดแบบอะซิงโครนัสในเบราว์เซอร์ ข้อผิดพลาดเชิงโครงสร้างจึงมักจะปรากฏเป็นป้ายกำกับว่างเปล่าหรือเกิดข้อขัดข้องอย่างรุนแรง แทนที่จะเป็นข้อผิดพลาดที่สามารถแก้ไขได้
อัปโหลดครั้งเดียว, ครอบคลุมทั้ง PHP และ JavaScript
นี่คือจุดที่กระบวนการแปลที่เข้าใจโครงสร้าง Gettext เข้ามามีบทบาทสำคัญ SimplePoTranslate รับไฟล์ .po หรือ .pot ต้นฉบับหนึ่งไฟล์ และสร้างเอาต์พุตที่แปลแล้วอย่างสะอาดตาใน หลายรูปแบบจากการอัปโหลดครั้งเดียว — .po, .mo, .json, .php, และ .xliff — ดังนั้นคุณจึงไม่ต้องเชื่อมต่อเครื่องมือแยกกันสำหรับเลเยอร์ PHP และ JavaScript ของคุณ คุณสมบัติ Syntax Locking ของมันจะรักษา %s, %1$s, {count}, และ HTML แบบอินไลน์ให้อยู่ในตำแหน่ง ซึ่งมีความสำคัญเป็นสองเท่าสำหรับสตริงใน Block editor ที่ placeholder ที่เสียหายอาจทำให้แผง editor ทั้งหมดล่มได้ เราจะเจาะลึกรูปแบบหนึ่งแหล่งที่มา หลายเอาต์พุตใน หนึ่งไฟล์เข้า, ห้ารูปแบบออก
คุณยังคงรัน make-json เพื่อสร้างไฟล์ที่แฮชตามที่ WordPress คาดหวัง — ขั้นตอนนี้เป็นเฉพาะของ WordPress และคงอยู่ในบิลด์ของคุณ แต่การแปลเอง ซึ่งเป็นส่วนที่มีแนวโน้มที่จะทำให้สตริง JS ของคุณเสียหายมากที่สุด จะถูกจัดการโดยเอนจินที่รู้บริบทแทนที่จะเป็นสคริปต์ค้นหาและแทนที่
สรุป
เหตุผลที่ Block editor ของคุณยังคงเป็นภาษาอังกฤษนั้นเป็นเรื่องของโครงสร้าง ไม่ใช่ข้อผิดพลาด: การแปล WordPress JSON เป็นระบบการส่งข้อมูลแยกต่างหากจากไฟล์ .mo ซึ่งสร้างขึ้นโดยเฉพาะเนื่องจากเบราว์เซอร์ไม่สามารถอ่านข้อมูล Gettext บนฝั่งเซิร์ฟเวอร์ได้ เมื่อคุณเข้าใจว่าสตริง JavaScript ต้องการไฟล์ JSON ที่แฮชด้วย MD5 สำหรับแต่ละสคริปต์ ซึ่งสร้างโดย wp i18n make-json และเชื่อมโยงด้วย wp_set_script_translations() การแก้ไขปัญหาก็เป็นไปตามกลไก เก็บสตริงของคุณไว้ในไฟล์ .po เดียวกัน คอมไพล์ .mo สำหรับ PHP และรัน make-json สำหรับ JS
หากทำขั้นตอนการแปลได้ถูกต้อง ผลลัพธ์ทั้งสองก็จะตามมา หากทำผิด คุณจะต้องใช้เวลาช่วงบ่ายเพื่อดีบักแผง editor ที่ว่างเปล่า
พร้อมที่จะแปลสตริง WordPress JSON และ PHP ของคุณจากแหล่งที่มาที่สะอาดแล้วหรือยัง? ลองใช้ SimplePoTranslate ฟรี — ไม่ต้องใช้บัตรเครดิต. ระดับฟรีแปลไฟล์
.poและ.potจริงพร้อม Syntax Locking ที่ปลอดภัยสำหรับ placeholder ทำให้สตริง Block editor ของคุณทำงานได้อย่างถูกต้อง