ข้ามไปที่เนื้อหา

แปลข้อความที่สมบูรณ์
ด้วย t-string ของ Python

gettext-tstrings เชื่อม t-string ของ Python 3.14 ขึ้นไปเข้ากับแคตตาล็อก gettext มาตรฐานและเครื่องมือของ Babel ค่าและการจัดรูปแบบยังคงอยู่ในโค้ดแอปพลิเคชัน ส่วนนักแปลทำงานกับข้อความที่สมบูรณ์และตัวยึดตำแหน่ง {name} เรียบง่าย:

import gettext

from gettext_tstrings import Translator

_ = Translator(gettext.translation("messages", localedir="locales"))
name = "Ada"
print(_(t"Hello {name}"))  # with a Japanese catalog: こんにちは Ada

แคตตาล็อกบรรจุ Hello {name} คำแปลอาจย้ายที่หรือใช้ {name} ซ้ำได้ แต่ถ้ามันตัดตัวยึดตำแหน่งทิ้ง เปลี่ยนชื่อ หรือเปลี่ยนการจัดรูปแบบของมัน การตรวจสอบแคตตาล็อกจะรายงานข้อผิดพลาดนั้น และหากรายการที่ไม่ถูกต้อง ยังหลุดไปถึงระบบจริงจนได้ ไลบรารีจะบันทึกคำเตือน แล้วเรนเดอร์ข้อความต้นทางแทนที่จะแครช

เริ่มบทแนะนำห้านาที เทียบกับทางเลือกอื่น

อัลฟา · Python 3.14 ขึ้นไป · แคตตาล็อก PO/MO มาตรฐาน · ไม่มี dependency ตอนรันไทม์จากภายนอก

เว็บไซต์นี้ปฏิบัติจริงตามสิ่งที่ตัวเองสอน: เอกสารทุกภาษา — ทั้งเมนูนำทาง ป้ายกำกับ และรายงานการ build ที่รองรับรูปพหูพจน์ — ล้วนถูกเรนเดอร์จากแคตตาล็อก PO ด้วย gettext-tstrings เอง

นี่เหมาะกับคุณหรือไม่

เหมาะแล้วในวันนี้ ถ้า แอปพลิเคชันของคุณรันบน Python 3.14 ขึ้นไป คุณใช้ gettext และ Babel อยู่แล้วหรืออยากรับเวิร์กโฟลว์ PO/MO ของมันมาใช้ และคุณต้องการไวยากรณ์ t-string ที่มีตัวยึดตำแหน่งแบบมีชื่อซึ่งถูกตรวจสอบก่อนเรนเดอร์

ยังไม่เหมาะ ถ้า คุณต้องใช้ Python 3.13 หรือเก่ากว่า คุณต้องการ Python API ที่เสถียร — นี่ยังเป็นรุ่นอัลฟา และข้อกำหนดคือส่วนของมันที่นิ่งแล้ว — หรือข้อความที่ต้องแปลของคุณเกือบทั้งหมดอยู่ในภาษาเทมเพลตมากกว่าในซอร์ส Python

มีแคตตาล็อกอยู่แล้วใช่ไหม มันยังใช้งานได้ต่อไป _("Hello {name}").format(name=name) กับ tr(t"Hello {name}") ผลิต msgid เดียวกัน คำแปลที่มีอยู่จึงรอดผ่านการเปลี่ยนมาได้ — การย้ายระบบ พาเดินตลอดการย้าย

แคตตาล็อกพูดอะไรได้บ้าง

คำแปลเปลี่ยนโครงสร้างของประโยคที่มันแปลไม่ได้ นั่นคือทั้งหมดของคำสัญญา และทุกอย่างที่เหลือในเว็บไซต์นี้ล้วนสืบเนื่องมาจากมัน คำแปลอาจสลับลำดับหรือใช้ {name} ซ้ำได้ และเขียนคำอื่น ๆ รอบมันใหม่ทั้งหมดก็ได้ แต่จะตัดตัวยึดตำแหน่งทิ้ง เสกอันใหม่ขึ้นมา เอื้อมผ่านมันเข้าไปในอ็อบเจกต์ของคุณ หรือแนบการจัดรูปแบบของตัวเองไม่ได้

ไลบรารีตรวจสอบสิ่งนั้นตั้งแต่ขาเข้า — ตอนคอมไพล์แคตตาล็อก — และตรวจอีกครั้งตอนเรนเดอร์ ซึ่งนั่นคือความต่างระหว่างข้อผิดพลาด ที่ถูกพบตอนรีวิว กับข้อผิดพลาดที่ถูกพบโดยผู้ใช้

เพิ่งรู้จัก gettext? เวิร์กโฟลว์ทั้งหมดในสี่ประโยค

gettext คือวิธีมาตรฐานที่ซอฟต์แวร์ใช้ในการแปล ทั้งใน Python และไกลกว่านั้นมาก โค้ดของคุณทำเครื่องหมายสตริงที่ต้องแปล จากนั้น ตัวสกัดข้อความ จะรวบรวมมันเข้าไฟล์เทมเพลต (.pot) แล้วนักแปล — ซึ่งมักไม่ใช่โปรแกรมเมอร์ — จะเติมคำแปลลงในไฟล์แคตตาล็อก (.po) หนึ่งไฟล์ต่อหนึ่งภาษา ซึ่งจะถูกคอมไพล์เป็นไฟล์ไบนารี .mo ที่แอปพลิเคชันของคุณโหลดตอนรันไทม์ ชื่อตามธรรมเนียมของฟังก์ชันแปลคือ _ ดังนั้น _(t"Hello {name}") จึงอ่านได้ว่า "แปลประโยคนี้" บทแนะนำ จะพาเดินครบทั้งเส้นทาง — ทำเครื่องหมาย สกัด แปล คอมไพล์ รัน — ในเวลาราวห้านาที

ปัญหาที่มันแก้

f-string ถูกแทนค่าเสร็จเรียบร้อยก่อนที่ไลบรารีใดจะทันได้เห็นมัน — f"Hello {name}" กลายเป็น "Hello Ada" ไปแล้ว และการแปลเศษข้อความรอบ ๆ ค่าหนึ่ง ๆ จะทำลายไวยากรณ์ของภาษาส่วนใหญ่ ส่วน t-string (PEP 750) เก็บข้อความคงที่ ค่าที่ประเมินแล้ว นิพจน์ต้นทาง การแปลงค่า และตัวระบุรูปแบบแยกจากกัน — ซึ่งเป็นการแยกส่วนแบบที่แคตตาล็อกข้อความต้องการพอดี สิ่งที่เปลี่ยนไปจากเดิม เมื่อเทียบกับ %(name)s, .format() และ $-strings

อย่างไรก็ตาม ไม่มีส่วนใดใน gettext หรือ Babel ที่กำหนดว่า t-string จะกลายเป็นข้อความได้อย่างไร ไลบรารีนี้เป็นผู้ตัดสินใจเลือกแนวทางนั้น เขียนมันไว้เป็นข้อกำหนดที่มีการกำกับเวอร์ชัน และมาพร้อมชุดทดสอบความสอดคล้องสำหรับตรวจสอบ

กฎการออกแบบ

  • แปลข้อความทั้งประโยคเสมอ ไม่แปลเศษเสี้ยวของประโยค
  • รับเฉพาะชื่อตัวแปรอย่างง่ายเช่น {name}
  • เก็บ !r และ :.2f ไว้ใต้การควบคุมของแอปพลิเคชัน นอกแคตตาล็อก
  • ให้นักแปลสลับลำดับและใช้ตัวยึดตำแหน่งที่รู้จักซ้ำได้ — แต่เรียกแอตทริบิวต์ไม่ได้ และเพิ่มพฤติกรรมการจัดรูปแบบเองไม่ได้
  • ใช้ไฟล์ POT, PO และ MO แบบธรรมดา รวมถึงเครื่องมือที่อ่านไฟล์เหล่านี้ได้อยู่แล้ว

และนี่คือรายการคู่กันของสิ่งที่มันจงใจไม่ไปยุ่งด้วย: มันไม่แปลงตัวเลข สกุลเงิน หรือวันที่ให้เข้ากับท้องถิ่น — จงจัดรูปแบบสิ่งเหล่านั้นก่อน ด้วย Babel; มันไม่ escape ผลลัพธ์ที่เรนเดอร์แล้วสำหรับ HTML เชลล์ หรือเทอร์มินัล และมันตัดสินไม่ได้ว่าคำแปล ถูกต้อง หรือไม่ ตัดสินได้เพียงว่าตัวยึดตำแหน่งของมันยังครบถ้วน

การติดตั้ง

python -m pip install gettext-tstrings

ต้องใช้ Python 3.14 ขึ้นไป การเรนเดอร์ไม่มี dependency ใด ๆ — ใช้เพียง gettext จากไลบรารีมาตรฐานเท่านั้น ไม่มีอย่างอื่นอีก

การสกัดข้อความและการตรวจสอบแคตตาล็อกทำงานผ่าน Babel จึงควรติดตั้ง extra นี้ในที่ที่ pybabel ทำงาน ซึ่งมักเป็นสภาพแวดล้อมการพัฒนาหรือ CI มากกว่าอิมเมจสำหรับการใช้งานจริง:

python -m pip install "gettext-tstrings[babel]"

ขั้นตอนถัดไป

เริ่มต้นที่นี่ — ไม่ต้องมีประสบการณ์ gettext มาก่อน:

  • บทแนะนำ — จากไดเรกทอรีว่างเปล่าสู่คำแปลภาษาญี่ปุ่นที่ทำงานได้จริงในห้าขั้นตอน ทุกคำสั่งแสดงพร้อมผลลัพธ์ของมัน
  • ทำไมต้อง t-string — ข้อความเดียวกันเขียนสี่แบบ และสิ่งที่ %(name)s, .format() และ $-strings แต่ละแบบส่งต่อให้แคตตาล็อก

การใช้งาน — เอกสารอ้างอิงสำหรับการทำงาน:

  • คู่มือ — API ตอนรันไทม์: ควรใช้จุดเข้าไหน รูปพหูพจน์ ภาษาแบบต่อคำขอ สตริงแบบเลื่อนการแปล และสิ่งที่เกิดขึ้นเมื่อแคตตาล็อกผิดพลาด
  • การสกัดข้อความ — เอกสารอ้างอิง pybabel: การตั้งค่า ชื่อฟังก์ชันแบบกำหนดเอง และวิธีที่เครื่องมือที่มีอยู่แล้วช่วยตรวจสอบแคตตาล็อกเหล่านี้ให้ฟรี ๆ
  • การใช้งานจริง — ลูปเดียวกันในแบบที่ทีมใช้จริง: รอบการอัปเดต รายการ fuzzy เกต CI แพลตฟอร์มการแปล และการจัดส่ง
  • การย้ายระบบ — การรับสิ่งนี้มาใช้ในโปรเจกต์ที่มีแคตตาล็อกอยู่แล้ว ทีละจุดเรียกใช้
  • สำหรับนักแปล — หน้าเดียวที่ส่งมอบให้ใครก็ตามที่เป็นคนแก้ไขไฟล์ .po

ทำความเข้าใจ — จากประวัติศาสตร์ไปจนถึงการทำงานภายใน:

  • ความเป็นมา — เหตุผลที่ไลบรารีนี้ถือกำเนิดขึ้น: สามสิบปีของ gettext, PEP สองฉบับ และการอภิปรายเรื่อง stdlib ที่ปิดลงโดยไม่มีคำตอบ
  • หลุมพราง — สิ่งที่พังจริงจากการแปลเว็บไซต์นี้เป็นสามสิบห้าภาษา และครึ่งไหนที่เครื่องมือจับได้
  • หลักการทำงาน — จากอ็อบเจกต์เทมเพลตของ PEP 750 ไปจนถึงสตริงที่เรนเดอร์เสร็จ และแคชที่ทำให้การตรวจสอบมีต้นทุนต่ำ

เอกสารอ้างอิง — ตัวสัญญา:

  • API — ทุกอย่างที่แพ็กเกจนี้ export รวมไว้ในหน้าเดียว
  • ข้อกำหนด — ข้อตกลง t-string ↔ msgid ในฐานะสัญญาที่เสถียรและมีการกำกับเวอร์ชัน พร้อมชุดทดสอบความสอดคล้องที่เครื่องอ่านได้

สถานะ

เวอร์ชันแพ็กเกจ 0.1.0a8
ความเสถียรของ API อัลฟา — Python API อาจยังเปลี่ยนแปลงได้
ข้อกำหนด v1 พร้อมชุดทดสอบความสอดคล้อง
Python 3.14 ขึ้นไป ทดสอบบน 3.14, 3.14t (free-threaded) และ 3.15
Babel 2.18 ขึ้นไป และเฉพาะที่ซึ่ง pybabel ทำงานเท่านั้น
Dependency ตอนรันไทม์ ไม่มี — ใช้ gettext ของไลบรารีมาตรฐาน
รูปแบบแคตตาล็อก POT, PO และ MO แบบธรรมดา
การเปลี่ยนแปลง CHANGELOG

ยังเป็นรุ่นอัลฟา สัญญาถูกออกแบบให้เล็กโดยตั้งใจ และข้อกำหนดคือส่วนที่เสถียรของมัน ส่วน Python API อาจยังเปลี่ยนแปลงได้ ก่อนออกรุ่นเสถียร โปรเจกต์นี้ยังต้องการ fixture ภาษาที่หลากหลายขึ้น การติดตามประสิทธิภาพอย่างต่อเนื่อง การรีวิว API จากผู้ที่ใช้ gettext และ Babel อย่างจริงจัง และการทดสอบความเข้ากันได้กับ Python และ Babel ทุกรุ่นที่รองรับ

Issue และ pull request ยินดีต้อนรับเสมอ — ช่วงอัลฟาคือช่วงเวลาที่อินเทอร์เฟซยังคุ้มค่าแก่การถกเถียงที่สุด

เข้าร่วมชุมชน

  • เลือก good first issue สำหรับการมีส่วนร่วมที่มีขอบเขตชัดเจน
  • ถามคำถามเรื่องการใช้งานได้ใน Q&A Discussions
  • นำเวิร์กโฟลว์ gettext จากงานจริงและไอเดียเกี่ยวกับ API มาแลกเปลี่ยนใน Ideas Discussions
  • อ่าน คู่มือการมีส่วนร่วม ก่อนเปิด pull request