XUnity.AutoTranslator ไม่ยอมแปลข้อความ
XUnity.AutoTranslator คือตัวแปลตอนรันไทม์ที่ดีที่สุดเท่าที่ Unity มี และเวลามันเงียบไป สาเหตุแทบทุกครั้งคือหนึ่งในห้าเรื่องนี้: เกมเป็นบิลด์ IL2CPP, ข้อความถูกตั้งค่าผ่านเส้นทางที่ hook ไม่ได้ดักไว้, เฟรมเวิร์ก UI ที่วาดมันไม่ได้ถูกเปิดใช้งาน, บรรทัดยาวเกินเพดานจำนวนอักขระ หรือ endpoint ปิดตัวเองไปแล้ว นี่คือวิธีดูว่าคุณเจอข้อไหน
XUnity.AutoTranslator ฟรี ใช้ลิขสิทธิ์ MIT ยังพัฒนาต่อเนื่อง และเป็นเครื่องมือแปลตอนรันไทม์ที่ดีที่สุดเท่าที่ Unity มี มันทำงานด้วยการ hook จังหวะที่เกมส่งสตริงให้คอมโพเนนต์ข้อความ แล้วสลับคำแปลเข้าไปก่อนที่มันจะถูกวาด ดีไซน์แบบนั้นคือเหตุผลที่มันไม่ต้องรู้จักรูปแบบไฟล์ของเกมเลยแม้แต่น้อย — และเป็นเหตุผลเดียวกันที่เวลามันล้มเหลว มันล้มเหลว เงียบ ๆ ไม่มีอะไรแครช เกมแค่รันเป็นภาษาญี่ปุ่นต่อไป
ห้าข้อด้านล่างครอบคลุมรายงาน "มันไม่แปล" เกือบทั้งหมด ไล่ไปตามลำดับ แต่ละข้อมีวิธีแก้ต่างกัน และการเดาสุ่มไปมาระหว่างข้อเหล่านั้นกินเวลาไปหลายค่ำคืน
อย่างแรก: อ่านล็อก ไม่ใช่อ่านหน้าจอ
ปลั๊กอินบอกสิ่งที่มันทำอย่างละเอียด และล็อกคือที่เดียวที่มันบอก ถ้าติดตั้งผ่าน BepInEx ให้ดูที่ BepInEx/LogOutput.log ล็อกของ Unity เองอยู่ข้าง ๆ กันที่ <Game>_Data/output_log.txt บนบิลด์เก่า หรือ %APPDATA%/../LocalLow/<Company>/<Game>/Player.log บนบิลด์ใหม่
- ล็อกพูดถึงการโหลด XUnity.AutoTranslator บ้างไหม? ถ้าไม่ ปัญหาอยู่ที่ ตัวโหลด ไม่ใช่ตัวแปล — คุณอยู่ที่โหมดความล้มเหลวข้อหนึ่ง
- มันบอกว่ามี endpoint ถูกเริ่มต้นไหม และภายหลังระบุว่ามีตัวหนึ่งถูกปิดลงหลังเกิดข้อผิดพลาดซ้ำ ๆ ไหม? นั่นคือโหมดความล้มเหลวข้อห้า
- มีคำแปลถูกเขียนลง
BepInEx/Translation/<lang>/Text/_AutoGeneratedTranslations.txtไหม? ถ้าไฟล์นั้นเต็มไปด้วยคำแปลที่ถูกต้องแต่ไม่เคยโผล่บนจอ ฝั่งเครือข่ายไม่มีปัญหา ฝั่ง การแสดงผล ต่างหากที่มี - กด ALT+1 ในเกมเพื่อเปิดหน้าต่างรวมคำแปล ถ้ามันแสดงบรรทัดที่คุณกำลังมองอยู่ แปลว่า hook เห็นบรรทัดนั้น ถ้ามันว่างเปล่า แปลว่า hook ไม่เคยเห็นมันเลย
การแยกข้อสุดท้ายนั้น — "แปลแล้วแต่ไม่แสดง" กับ "ไม่เคยเห็น" — คือทางแยกของเรื่องทั้งหมด ทุกอย่างด้านล่างแขวนอยู่กับมัน
1. เกมเป็นบิลด์ IL2CPP
Unity ส่งเกมออกมาด้วยรันไทม์สองแบบที่ต่างกันมาก Mono เก็บโค้ด C# ของเกมไว้เป็นแอสเซมบลี .NET ธรรมดาใน <Game>_Data/Managed/ ซึ่งมี Assembly-CSharp.dll รวมอยู่ด้วย พร้อมชื่อชนิดและชื่อเมธอดครบถ้วน ส่วน IL2CPP แปลง C# นั้นเป็น C++ ล่วงหน้าแล้วคอมไพล์เข้าไปใน GameAssembly.dll แบบเนทีฟ สิ่งที่เหลือรอดจากระบบชนิดข้อมูลถูกอัดไว้ใน <Game>_Data/il2cpp_data/Metadata/global-metadata.dat
hook ตอนรันไทม์ต้องหาเมธอดให้เจอแล้วแทนที่มัน บน Mono นั่นคือปัญหา reflection ธรรมดา บน IL2CPP ไม่มีเมธอดแบบ managed ให้ reflect เลย — โค้ดเป็นเนทีฟ และทางเดียวที่จะย้อนกลับไปหาชื่อ ฟิลด์ และแอดเดรสของเมธอด คือแยกวิเคราะห์ global-metadata.dat แล้วประกอบเลย์เอาต์ขึ้นใหม่ นั่นคือตัวโหลดคนละตัวโดยสิ้นเชิง ไม่ใช่การตั้งค่า
- วิธีดูใน 5 วินาที: มี
GameAssembly.dllอยู่ข้างไฟล์ exe ของเกม บวกโฟลเดอร์il2cpp_dataแปลว่า IL2CPP ส่วนโฟลเดอร์Managed/ที่เต็มไปด้วย DLL แปลว่า Mono - IL2CPP ต้องใช้ BepInEx รุ่นสำหรับ IL2CPP และ XUnity.AutoTranslator รุ่นที่บิลด์มาคู่กัน รุ่น Mono จะไม่โหลด — มันจะไม่ปรากฏในล็อกเฉย ๆ ซึ่งอ่านแล้วเหมือน "ปลั๊กอินพัง" ทุกประการ
- ความกว้างบิตก็สำคัญ เกม 64 บิตต้องใช้ตัวโหลด 64 บิต คู่ที่ไม่ตรงกันล้มเหลวแบบเงียบ ๆ เหมือนกัน
- บางเกมส่งไฟล์เมทาดาทาที่แยกวิเคราะห์ไม่ได้มา ตัวแพ็กเกอร์และชั้นป้องกันการดัดแปลงเข้ารหัสหรือจัดโครงสร้าง
global-metadata.datใหม่ และเครื่องมือทุกตัวที่ต้องอ่านมัน — รวมถึง hook — ก็หยุดอยู่ตรงนั้น
2. ปลั๊กอินโหลดขึ้น แต่ข้อความไม่เคยปรากฏ
ปลั๊กอินอยู่ในล็อก endpoint เริ่มต้นแล้ว _AutoGeneratedTranslations.txt โตขึ้นเรื่อย ๆ — แต่หน้าจอไม่เปลี่ยน hook กำลังแปลสตริงที่เกมโยนทิ้งทีหลัง หรือเกมกำลังตั้งค่าข้อความผ่านเส้นทางที่ hook ไม่ได้ดักไว้
TextGetterCompatibilityMode
เกมจำนวนมาก อ่านกลับ ข้อความที่เพิ่งตั้งค่าไป — เพื่อวัดขนาด เพื่อต่อท้าย หรือเพื่อเทียบกับอย่างอื่น เมื่อคอมโพเนนต์ถือสตริงที่แปลแล้ว การอ่านกลับนั้นได้คำแปลไป ตรรกะของเกมเองจึงทำงานกับข้อความที่มันไม่ได้เขียน ผลลัพธ์มีตั้งแต่บรรทัดเด้งกลับไปเป็นต้นฉบับ ไปจนถึงเลย์เอาต์ที่พังทั้งหน้า TextGetterCompatibilityMode ใน AutoTranslatorConfig.ini ทำให้ getter คืนสตริง ต้นฉบับ ให้เกม ในขณะที่ผู้เล่นยังเห็นตัวที่แปลแล้ว มันปิดไว้ตามค่าเริ่มต้นเพราะมีต้นทุนทุกครั้งที่มีการอ่าน และมันคือสวิตช์แรกที่ควรลองเมื่อข้อความกะพริบ เด้งกลับ หรือไม่ยอมติดค้าง
อีกครึ่งหนึ่งของกลุ่มนี้คือข้อความที่ไม่เคยถูกตั้งค่าผ่าน API ที่ถูก hook ตั้งแต่แรก: เกมที่เรนเดอร์ผ่านเอนจินข้อความของตัวเอง สตรีมอักขระลงเมชโดยตรง หรืออบบทสนทนาลงไปในสไปรต์ ไม่มีการตั้งค่าใดแก้เรื่องนี้ได้ — จุดดักไม่มีอยู่จริง ข้อความที่ถูกอบลงในงานศิลป์เป็นคนละปัญหาโดยสิ้นเชิง และต้องใช้การแปลรูปภาพ ไม่ใช่ hook ใด ๆ
3. ข้อความแปลแค่บางส่วน
เมนูแปล แต่บทสนทนาไม่แปล หรือบทสนทนาแปลแต่ปุ่มทุกปุ่มยังเป็นภาษาญี่ปุ่น เกือบทุกครั้งนี่คือเฟรมเวิร์ก UI ที่ไม่ได้ถูกเปิดใช้งาน เพราะปลั๊กอิน hook แต่ละตัวแยกกัน และไม่ได้เปิดครบทุกตัวตามค่าเริ่มต้น
- เปิดตามค่าเริ่มต้น: UGUI (UI ในตัวของ Unity), NGUI, TextMeshPro และ UIElements (
EnableUGUI,EnableNGUI,EnableTextMeshPro,EnableUIElements) รวมกันแล้วครอบคลุมเกมสมัยใหม่ส่วนใหญ่ รวมถึงเฟรมเวิร์กวิชวลโนเวลอย่าง Utage ที่วาดผ่านเฟรมเวิร์กเหล่านี้แทนที่จะมีสวิตช์ของตัวเอง - ปิดตามค่าเริ่มต้น: IMGUI และคอมโพเนนต์
TextMeshรุ่นเก่า IMGUI คือ GUI แบบ immediate-mode ของ Unity — มันวาดใหม่ทุกเฟรม การ hook มันจึงหมายถึงการแปลทุกเฟรม และมันถูกปิดไว้เพราะประสิทธิภาพ ไม่ใช่เพราะมันใช้ไม่ได้ - แฟล็กอยู่ใน `AutoTranslatorConfig.ini` ในชื่อ
EnableIMGUI,EnableTextMeshและตัวอื่นในกลุ่มเดียวกัน ตั้งตัวที่เกมของคุณใช้เป็นTrueแล้วรีสตาร์ต - เกม Unity รุ่นเก่าและเกมโดจินญี่ปุ่นคือเคส IMGUI ที่พบบ่อย เกมที่เมนูดูเหมือนกล่องสีเทาเรียบ ๆ แบบสไตล์ดีฟอลต์เป็นสัญญาณที่ชัดเจน
ถ้าเปิดทุกอย่างแล้วไม่มีอะไรเปลี่ยน แปลว่าข้อความไม่ได้ผ่านคอมโพเนนต์ข้อความของ Unity เลย — กลับไปที่โหมดความล้มเหลวข้อสอง
4. บรรทัดยาวถูกข้าม ไม่ใช่ถูกแปล
MaxCharactersPerTranslation มีค่าเริ่มต้นที่ 200 อะไรที่ยาวกว่านั้นจะถูกข้าม ไม่ใช่ถูกตัดให้สั้น ไม่ใช่ถูกลองใหม่ ไม่ได้ถูกบันทึกล็อกในแบบที่คุณจะสังเกตเห็นระหว่างเล่น — แค่ถูกข้าม บรรทัดนั้นจึงเรนเดอร์เป็นภาษาต้นฉบับ และไม่มีอะไรดูเหมือนพัง
นี่คือโหมดความล้มเหลวที่คนตามล่ากันนานที่สุด เพราะหลักฐานอ่อนมาก: เกมส่วนใหญ่แปลได้ แล้วมีอยู่ย่อหน้าหนึ่งที่ไม่แปล วิชวลโนเวลคือเหยื่อประจำ — บล็อกบรรยายยาว ๆ หรือบทพูดคนเดียวที่ไม่มีการขึ้นบรรทัดใหม่ทะลุ 200 อักขระได้ง่าย ๆ และมันคือข้อความที่คุณอยากให้แปลที่สุดพอดี
เพิ่มค่านั้นใน AutoTranslatorConfig.ini แล้วรีสตาร์ต จำไว้ว่าคุณกำลังเพิ่มต้นทุนของแต่ละคำขอไปด้วย: endpoint ฟรีมีเพดานความยาวต่อคำขอของตัวเอง และจะเริ่มปฏิเสธคำขอที่ยาวเกินเพดานนั้น ค่าที่ใหญ่มากจึงเป็นการแลกการข้ามแบบเงียบ ๆ กับข้อผิดพลาดของ endpoint ที่มองเห็นได้ ราว 500–1000 ครอบคลุมงานร้อยแก้วใน VN ทั่วไป
5. endpoint ล้มเหลวหรือจำกัดอัตราคุณ
endpoint เริ่มต้นของ XUnity คือบริการแปลสาธารณะที่ใช้ฟรี เข้าถึงในแบบเดียวกับที่เบราว์เซอร์เข้าถึง มันไม่มีสัญญาผูกพัน และมันเปลี่ยนแปลงได้ เมื่อคำขอล้มเหลวติดกันเป็นชุด ปลั๊กอินจะ ปิด endpoint นั้นตลอดเซสชันที่เหลือ แทนที่จะกระหน่ำต่อ — เป็นการตัดสินใจที่ตั้งใจและถูกต้อง ซึ่งก็แปลว่าทุกอย่างหลังจุดนั้นจะไม่ถูกแปลแบบเงียบ ๆ จนกว่าคุณจะรีสตาร์ตเกม
- หาบรรทัดปิด endpoint ในล็อก ถ้ามันอยู่ตรงนั้น วิธีแก้คือรีสตาร์ตบวกกับการเปลี่ยนอะไรบางอย่าง ไม่ใช่การรอต่อไป
- ชะลอคิวลง
MaxTranslationsQueuedPerSecondและการตั้งค่าหน่วงเวลามีอยู่เพราะการยิงรัวคือสิ่งที่ทำให้ชนลิมิต การกดข้ามผ่าน VN เร็ว ๆ ส่งคำขอหลายร้อยครั้งในไม่กี่วินาที - เปลี่ยน endpoint ถ้าบริการฟรีตัวหนึ่งกำลังมีปัญหา อีกตัวมักจะไม่มี
- ใช้ endpoint ที่มีคีย์ คีย์ DeepL จริงหรือ API แบบเสียเงินตัดปัญหาทั้งหมวดนี้ทิ้ง แลกกับการต้องมีคีย์ API แบบเสียเงิน
- อัปเดตปลั๊กอิน เมื่อโปรโตคอลของ endpoint ฟรีเปลี่ยน วิธีแก้จะมาในรูปของรีลีสใหม่ การรันบิลด์อายุสองปีกับบริการที่ขยับไปแล้วคือสาเหตุยอดฮิตของ "เมื่อก่อนมันเคยใช้ได้"
โบนัส: ข้อความแปลแล้ว แต่แสดงเป็นกล่องสี่เหลี่ยม
ข้อนี้ไม่ใช่ความล้มเหลวของการแปลเลย เกมส่งมาพร้อมฟอนต์แอตลาสที่มีเฉพาะกลิฟที่ภาษาต้นฉบับต้องใช้ และภาษาปลายทางของคุณต้องใช้กลิฟที่ไม่มีอยู่ในนั้น อักขระที่หายไปทุกตัวจึงวาดออกมาเป็นกล่องหรือช่องว่าง XUnity มี OverrideFont และ OverrideFontTextMeshPro ไว้สำหรับเรื่องนี้โดยเฉพาะ สังเกตลายนิ้วมือให้ดี: กล่องสี่เหลี่ยมแปลว่ากลิฟหายไป ส่วนอักขระ `?` ตรง ๆ แปลว่ามีปัญหาการเข้ารหัส ที่ไหนสักแห่งก่อนหน้านั้นในสายงาน มันคนละบั๊กกัน และการตั้งค่าฟอนต์แก้ได้แค่อย่างแรก
ลำดับที่ควรไล่ตรวจ
- ยืนยันว่าเป็น Mono หรือ IL2CPP โดยมองหา
GameAssembly.dllแล้วยืนยันว่าคุณติดตั้งตัวโหลดที่ตรงกัน - เปิด
BepInEx/LogOutput.logแล้วยืนยันว่าปลั๊กอินโหลดขึ้นและมี endpoint เริ่มต้นแล้ว - กด ALT+0 ในเกมเพื่อเปิดหน้าต่างของตัวปลั๊กอินเอง — ถ้าไม่มีอะไรขึ้นมา แปลว่าปลั๊กอินไม่ได้ถูกโหลด ALT+1 จะเปิด Translation Aggregator: ว่างเปล่าแปลว่า hook ไม่เคยเห็นข้อความ ถ้ามีข้อมูลอยู่แปลว่ามันเห็น
- ถ้า hook เห็นแต่หน้าจอไม่เปลี่ยน ให้เปิด
TextGetterCompatibilityMode - ถ้าเกมแปลแค่บางส่วน ให้เปิด IMGUI และ TextMesh รุ่นเก่า
- ถ้าบรรทัดยาวบางบรรทัดยังไม่ถูกแปล ให้เพิ่ม
MaxCharactersPerTranslationจากค่าเริ่มต้น 200 - ถ้าทุกอย่างหยุดกลางเซสชัน ให้หาบรรทัดปิด endpoint แล้วรีสตาร์ตด้วยคิวที่ช้าลงหรือ endpoint อื่น
เมื่อ hook ไม่ใช่รูปทรงที่เหมาะกับงาน
ความล้มเหลวทุกข้อข้างบนย้อนกลับไปที่รากเดียวกัน: hook ตอนรันไทม์แปลได้เฉพาะข้อความที่มันอยู่ตรงนั้นเพื่อดักเท่านั้น ถ้าเกมไม่ได้ตั้งค่าสตริงผ่าน API ที่ปลั๊กอินรู้จัก หรือข้อความถูกวาดไปก่อนที่ปลั๊กอินจะโหลด หรือรันไทม์ไม่เปิดเผยเมธอดให้ hook ก็ไม่มีอะไรให้ตั้งค่า เครื่องมือทำงานถูกต้องแล้ว ข้อความอยู่นอกระยะเอื้อมเฉย ๆ
ทางเลือกเชิงโครงสร้างคือทำงานกับไฟล์แทนที่จะทำงานกับเฟรม เครื่องมือระดับไฟล์เปิดแอสเซ็ตของเกมเอง ดึงสตริงออกมา แปล แล้วเขียนสำเนาเกมที่แปลแล้วออกมา — ข้อความจึงอยู่ในภาษาปลายทางแล้วก่อนที่เอนจินจะโหลดมันด้วยซ้ำ ไม่มี hook ไม่มีจุดดัก ไม่มีแฟล็กต่อเฟรมเวิร์ก และขีดจำกัดจำนวนอักขระคือเท่าที่รูปแบบไฟล์รองรับ นั่นคือสิ่งที่ RuneTranslate ทำ บน Unity และอีก 16 เอนจินและรูปแบบ
ข้อแลกเปลี่ยนมีจริงและไปคนละทาง เครื่องมือระดับไฟล์เข้าถึงได้เฉพาะข้อความที่ อยู่ในไฟล์ — สำหรับ Unity นั่นหมายถึง TextAsset, ฟิลด์สตริง MonoBehaviour, ไฟล์สคริปต์ StreamingAssets, ตารางโลคัลไลเซชัน และแอสเซ็ตบันเดิล รวมถึง Addressable bundle ที่เข้ารหัส AES มันต้องมีขั้นตอนส่งออกก่อนคุณจะเล่น แทนที่จะแปลไปเล่นไป และมันทำอะไรกับข้อความที่เกมสร้างขึ้นตอนรันไทม์จากชิ้นส่วนย่อยไม่ได้ Unity เป็นเอนจินแบบพยายามอย่างเต็มที่ด้วยเหตุผลนี้พอดี: แต่ละเกมดึงข้อความออกภายนอกไม่เท่ากันเลย และการเปิดโปรเจกต์คือสิ่งที่บอกคุณว่าคุณถือเกมแบบไหนอยู่
- ข้อความที่คอมไพล์เข้าไปในโค้ด C# คือเส้นแบ่งที่แข็งที่สุด บนบิลด์ Mono RuneTranslate อ่านลิเทอรัลสตริงออกจากแอสเซมบลีของเกมด้วย sidecar ที่รวมมา โดยตัดสินจากสิ่งที่จุดเรียกใช้ทำกับมัน มันจึงไม่แปลชื่อฉากหรือพารามิเตอร์แอนิเมเตอร์ ส่วนบนบิลด์ IL2CPP โค้ดที่คอมไพล์แล้วอยู่นอกขอบเขต
- แต่ข้อความในแอสเซ็ตของ IL2CPP ไม่มีปัญหา ฟิลด์สตริงของคอมโพเนนต์ถูกอ่านบน IL2CPP ด้วยการประกอบข้อมูลชนิดขึ้นใหม่จากเมทาดาทาของเกม —
global-metadata.datตัวเดียวกับที่ hook ต้องใช้ แค่ใช้เพื่อจุดประสงค์อื่น - มันอ่านผลลัพธ์ของ XUnity เองได้ ถ้าคุณมี
_AutoGeneratedTranslations.txtที่มีข้อมูลอยู่แล้ว RuneTranslate แยกวิเคราะห์ไฟล์นั้นและแปลค่าในนั้นได้โดยไม่แตะคีย์ งานที่คุณทำไว้แล้วจึงไม่ถูกทิ้ง - ฟอนต์ถูกจัดการตอนส่งออก ด้วยการฉีดแอสเซ็ตฟอนต์สำรองเข้าไปในเกม ภาษาปลายทางที่ฟอนต์เดิมไม่เคยครอบคลุมจึงยังเรนเดอร์ออกมาได้
ผู้ให้บริการเก้าราย โดยสามรายไม่ต้องใช้คีย์ API เลย — Google, DeepL ฟรี และโมเดล Classic / Next-gen ของ DeepL — บวก API ของ DeepL, OpenAI, Anthropic, DeepSeek, endpoint ใดก็ได้ที่เข้ากันได้กับ OpenAI และโมเดลบนเครื่องผ่าน Ollama หรือ LM Studio ระดับฟรีปลดล็อกทุกเอนจินและทุกผู้ให้บริการ มันจำกัดปริมาณงานและถือได้ครั้งละหนึ่งโปรเจกต์ ใช้ได้บน Windows 10/11 หรือบน Linux และ Steam Deck ผ่าน Wine หรือ Proton ต้องลงชื่อเข้าใช้ Patreon แบบฟรีตอนเปิดครั้งแรก ผลลัพธ์คือบิลด์ที่แปลแล้วซึ่งเล่นได้และเป็นของคุณ
ไม่มีแนวทางไหนถูกต้องเสมอไป เกมที่บทพูดทั้งเรื่องอยู่ในตาราง JSON ที่บันเดิลมาไฟล์เดียวคืองานระดับไฟล์ และเป็นแบบนั้นมาตลอด เกมที่ประกอบบทสนทนาขึ้นในโค้ดตอนรันไทม์คืองานของ hook และจะเป็นแบบนั้นตลอดไป การรู้ว่าคุณถืออันไหนอยู่คือเนื้องานส่วนใหญ่แล้ว
ไปต่อที่ไหน
- วิธีแปลเกม Unity — คู่มือฉบับเต็ม รวมถึงว่า Unity ดึงอะไรออกภายนอกและไม่ดึงอะไร
- หน้าเอนจิน Unity — รูปแบบที่รองรับและข้อจำกัดปัจจุบันรวมไว้ที่เดียว
- RuneTranslate vs XUnity.AutoTranslator — สองแนวทางวางเทียบกัน พร้อมกรณีที่แต่ละฝ่ายชนะ
- การเลือกผู้ให้บริการแปล — เอนจินไหนรับมือร้อยแก้วญี่ปุ่นได้ดี และตัวไหนไม่มีค่าใช้จ่าย
- พื้นฐานอภิธานศัพท์ — รักษาชื่อตัวละครและคำศัพท์ให้สม่ำเสมอทั่วทั้งสคริปต์
- เอนจินที่รองรับทั้งหมด — เผื่อว่าเกมนั้นกลับกลายเป็นว่าไม่ใช่ Unity
พร้อมลอง RuneTranslate ไหม
ระดับฟรีปลดล็อกทุกเอนจิน + ทุกผู้ให้บริการแปล Supporter ($3/mo) ปลดล็อกความเร็วเต็ม
ดาวน์โหลดสำหรับ Windows
