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

ความเป็นมา

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

ระบบนิเวศของ gettext

GNU gettext เป็นวิธีที่ซอฟต์แวร์เสรีถูกแปลมาตั้งแต่กลางทศวรรษ 1990: ทำเครื่องหมายสตริงในโค้ด สกัดออกมาเป็นเทมเพลต ส่งไฟล์แคตตาล็อกหนึ่งไฟล์ต่อภาษาให้นักแปล คอมไพล์ แล้วโหลดขณะรันไทม์ รอบวงจรนี้ระบบนิเวศทั้งระบบได้เติบโตขึ้น — โปรแกรมแก้ไข PO ขั้นตอนการรีวิว และแพลตฟอร์มแปลภาษาที่ล้วนพูดรูปแบบไฟล์เดียวกัน — และ Python ก็ได้บรรจุ โมดูล gettext ไว้ในไลบรารีมาตรฐานมานานกว่าสองทศวรรษ ครึ่งที่เป็นรันไทม์ของงานแปลไม่เคยเป็นปัญหาเลย

ครึ่งที่ยังไม่ลงตัวคือ สตริงในแคตตาล็อกหน้าตาเป็นอย่างไร เสมอมา ข้อความแบบ %(name)s ยื่นไวยากรณ์ printf ให้นักแปล ซึ่งการลบตัวอักษรเพียงตัวเดียว ก็เปลี่ยนเป็นการแครชในระบบจริงได้ ส่วนข้อความแบบ .format() ยื่นสิทธิ์เข้าถึงแอตทริบิวต์บนอ็อบเจกต์จริงให้แก่แคตตาล็อก (ทำไมต้อง t-string ไล่ให้ดูทั้งสองแบบ พร้อมโชว์ความล้มเหลวให้เห็น) และ f-string — ไวยากรณ์ที่โค้ด Python ส่วนใหญ่ในปัจจุบันนิยมใช้ — เข้าร่วมไม่ได้เลย: กว่าไลบรารีใดจะได้เห็นมัน มันก็เป็นสตริงที่เสร็จสมบูรณ์ไปแล้ว ผู้คนก็ยังพยายามอยู่ดี บ่อยจนตัวติดตามปัญหาของ Babel สะสมความพยายามเหล่านั้นไว้ (#594, #715) ความล้มเหลวนี้เป็นเรื่องเชิงโครงสร้าง ไม่ใช่ฟีเจอร์ที่ขาดหายไป

สอง PEP ที่ห่างกันสิบปี

ในปี 2015 Alyssa Coghlan และ Nick Humrich เขียน PEP 501 เสนอเทมเพลตการแทรกค่าซึ่งมีแรงจูงใจข้อแรกที่ระบุไว้คือ i18n — "providing a cleaner syntax for i18n translation" ตามถ้อยคำของตัว PEP เอง ข้อเสนอถูกเลื่อนออกไป ส่วนหนึ่งเพราะการอภิปรายแสดงให้เห็นว่ากรณี i18n พ่วงข้อพิจารณาเพิ่มเติมที่สำคัญซึ่งกรณีใช้งานที่เรียบง่ายกว่าไม่มี

หนึ่งทศวรรษต่อมา PEP 750 — โดย Jim Baker, Guido van Rossum, Paul Everitt, Koudai Aono, Lysandros Nikolaou และ Dave Peck — ปลุกแนวคิดนี้ขึ้นมาใหม่ในชื่อ t-string ได้รับการยอมรับในเดือนเมษายน 2025 และออกมากับ Python 3.14 ในเดือนตุลาคม 2025 จากนั้น PEP 501 ก็ถูกถอนเพื่อหลีกทางให้ รายละเอียดหนึ่งสำคัญต่อหน้านี้: i18n ไม่ได้ อยู่ในแรงจูงใจที่ PEP 750 ระบุไว้ PEP นี้ทำให้กลไกเป็นเรื่องทั่วไป — ชนิดเทมเพลตที่ไลบรารีใดก็นำไปใช้ได้ — และทิ้งคำถามเรื่องการแปลไว้ตรงจุดเดียวกับที่ PEP 501 พักมันไว้เมื่อสิบปีก่อนพอดี: ยังเปิดอยู่

ดังนั้น ณ Python 3.14 ตัวภาษามีโครงสร้างข้อมูลที่แคตตาล็อกข้อความต้องการอย่างแม่นยำ แต่ไม่มีธรรมเนียมปฏิบัติสำหรับการใช้มันในบทบาทนั้น

การอภิปรายในไลบรารีมาตรฐาน

สองเดือนก่อน 3.14 ออก Adrian Mönnich (ThiefMaster ผู้ดูแลโปรเจกต์ Indico) เสนอให้ปิดช่องว่างนั้นในไลบรารีมาตรฐานเอง: เธรด Support t-strings in gettext (รองรับ t-string ใน gettext) บน discuss.python.org ซึ่งเปิดในเดือนสิงหาคม 2025 มาพร้อม pull request ที่ทำงานได้จริง ซึ่งเพิ่มการรองรับ t-string ให้ทั้ง gettext และ pygettext

เธรดนี้ควรค่าแก่การอ่านทั้งหมด เพราะมันเผยให้เห็นทุกคำถามยาก ๆ ที่ไลบรารีนี้ต้องตอบในภายหลัง:

  • การแทรกค่าเป็นอะไรได้บ้าง? ชื่ออย่างง่ายเท่านั้น หรือรวมแอตทริบิวต์และการเรียกฟังก์ชันพร้อมชื่อตัวยึดตำแหน่งที่อนุมานมา? ทุกคำตอบแลกความสะดวกกับความเสถียรของ msgid และความปลอดภัยของแคตตาล็อก
  • รูปพหูพจน์ต้องการอะไร เมื่อระบบพหูพจน์ของภาษาปลายทางแตกต่างจากของภาษาต้นทาง?
  • gettext เป็นเป้าหมายที่ถูกต้องหรือเปล่า? Barry Warsaw — ผู้เคยแย้งระหว่างการพัฒนา PEP 750 ว่า t-string ไม่เหมาะกับ i18n — ชี้ไปที่ flufl.i18n ของเขาและสไตล์ $-string ของมันในฐานะเครื่องมือที่เป็นมิตรกว่า ขณะที่คนอื่น ๆ เสนอให้ทิ้ง gettext ไปเลยเพื่อหันไปหาระบบที่ใหม่กว่าอย่าง Fluent
  • และคำถามระดับเมตา: ไม่ว่าไลบรารีมาตรฐานจะบรรจุอะไรออกไป มันแทบจะเปลี่ยนแปลงไม่ได้อีกเลย ธรรมเนียมปฏิบัติที่มีทางเลือกเปิดอยู่มากขนาดนี้ เป็นสิ่งที่เสี่ยงเกินกว่าจะแช่แข็งตั้งแต่ความพยายามครั้งแรก

ฉันทามติไม่เกิดขึ้น ประเด็นใน CPython ถูก ปิดในสถานะ "not planned" และ pull request ถูกปิดโดยไม่ถูกรวมเข้าไปในเดือนตุลาคม 2025 เพียงไม่กี่วันหลัง 3.14 ออก ความสามารถมีอยู่ในตัวภาษาแล้ว แต่ธรรมเนียมปฏิบัติไม่มีบ้านให้อยู่

ทำไมจึงเป็นแพ็กเกจก่อน

นั่นคือช่องว่างที่โปรเจกต์นี้เลือกจะเติมเต็มจากนอกไลบรารีมาตรฐาน บนการวางเดิมพันอย่างจงใจ: ธรรมเนียมปฏิบัติจะสุกงอมเร็วกว่าในที่ที่มันออกเวอร์ชันได้อย่างอิสระ และค่อย ๆ ได้รับการยอมรับทีละกรณี ส่วนไลบรารีมาตรฐาน — ซึ่งต้องถูกต้องตั้งแต่ครั้งแรก — คือที่ที่ธรรมเนียมปฏิบัติควร ไปจบลง ไม่ใช่ที่ที่มันควรถูกคิดค้นขึ้น

พูดอย่างเป็นรูปธรรม ทุกคำถามที่ถกเถียงกันในเธรดมีคำตอบเขียนไว้ที่นี่ แต่ละข้อบนหน้าของมันเอง:

  • การแทรกค่าเป็น ชื่ออย่างง่ายเท่านั้น เพื่อให้ msgid เสถียรและมีความหมาย — คู่มือ แสดงกฎ ส่วน หลักการทำงาน อธิบายเหตุผล
  • การจัดรูปแบบอยู่นอกแคตตาล็อก โดยสิ้นเชิง (ทำไมต้อง t-string)
  • พหูพจน์ เป็นไปตามกฎยูเนียน/อินเตอร์เซกชัน ที่อนุญาตให้ระบบพหูพจน์ของภาษาปลายทางแตกต่างจากของภาษาต้นทางได้ (spec §4)
  • แคตตาล็อกที่เสียหาย ถอยกลับแทนที่จะแครช รักษาสัญญาของ gettext เองไว้ (คู่มือ)
  • และธรรมเนียมปฏิบัติทั้งหมดเป็น ข้อกำหนดที่มีเวอร์ชันกำกับ พร้อมชุดทดสอบความสอดคล้องที่เครื่องอ่านได้ — เขียนไว้เพื่อให้อีกการอิมพลีเมนต์หนึ่ง รวมถึงเวอร์ชันไลบรารีมาตรฐานในอนาคต สามารถนำไปใช้ได้โดยไม่ต้องแก้ไขและทำงานร่วมกันได้

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

เส้นเวลา

เมื่อไร เกิดอะไรขึ้น
กลางทศวรรษ 1990 GNU gettext วางรากฐานเวิร์กโฟลว์ PO/POT/MO ที่นักแปลและแพลตฟอร์มยังคงใช้ร่วมกันจนถึงทุกวันนี้
2015 PEP 501 เสนอเทมเพลตการแทรกค่า โดยมี i18n เป็นแรงจูงใจข้อแรก ถูกเลื่อนออกไป
2016 f-string ออกมากับ Python 3.6 — การแทรกค่าได้ไวยากรณ์ของตัวเอง และงานแปลใช้มันไม่ได้
ก.ค. 2024 PEP 750 เสนอ t-string
เม.ย. 2025 PEP 750 ได้รับการยอมรับ PEP 501 ถูกถอนเพื่อหลีกทางให้
ส.ค. 2025 เธรด Support t-strings in gettext เปิดขึ้น พร้อม pull request สำหรับไลบรารีมาตรฐาน
ต.ค. 2025 Python 3.14 ออกพร้อม t-string ประเด็นในไลบรารีมาตรฐานปิดลงในสถานะ not planned
2026 gettext-tstrings ออกเป็นรุ่นอัลฟา พร้อม spec v1 และชุดทดสอบความสอดคล้องของมัน