ความเป็นมา¶
ไลบรารีนี้ตั้งอยู่ ณ จุดบรรจบของเรื่องราวยาวนานสองเรื่อง — เรื่องหนึ่งว่าด้วยวิธีที่ซอฟต์แวร์ถูกแปล อีกเรื่องว่าด้วยวิธีที่ 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 และชุดทดสอบความสอดคล้องของมัน |