用 Python 的 t-string
翻譯完整的訊息¶
gettext-tstrings 把 Python 3.14+ 的 t-string 接上標準的 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} 的位置。但如果它把佔位符
刪掉、改名或加上格式設定,目錄驗證就會回報這個錯誤。萬一有無效的條目仍然進了正式
環境,本函式庫會記錄一則警告並渲染原始訊息,而不是讓程式當掉。
Alpha · Python 3.14+ · 標準的 PO/MO 目錄 · 執行階段零第三方相依
本站身體力行自己所記載的內容:每一個語言版本——導覽、標籤,以及能處理複數的
建置報告——都由
gettext-tstrings 自己
從 PO 目錄渲染而成。
它適合你嗎?¶
現在就適合:你的應用程式跑在 Python 3.14 以上;你已經在用 gettext 與 Babel, 或想採用它們的 PO/MO 工作流程;而且你想要具名佔位符、並且在渲染之前就先被檢查過 的 t-string 語法。
目前還不適合:你需要 Python 3.13 或更舊的版本;你需要穩定的 Python API——本專案還是 alpha,其中已經定案的部分是規範;或者你幾乎所有可 翻譯的文字都寫在某種樣板語言裡,而不在 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() 與 $-string 相比,這帶來了什麼改變。
不過,gettext 和 Babel 都沒有規定 t-string 該如何變成一則訊息。本函式庫做出了 這個選擇,把它寫成有版本的規範,並附上一致性測試套件 供人驗證。
設計原則¶
- 永遠翻譯完整的訊息,不翻譯句子片段。
- 只接受
{name}這類單純的變數名稱。 - 讓
!r和:.2f留在應用程式手上,不進入目錄。 - 允許翻譯調換與重複已知的佔位符,同時擋住它存取屬性或加上格式化行為。
- 沿用一般的 POT、PO 與 MO 檔案,以及既有的相關工具。
與之對應的,是它刻意不碰的那份清單:它不在地化數字、貨幣或日期——請先 用 Babel 把它們格式化好;它不會為了 HTML、shell 或終端機而跳脫渲染結果;它也判斷不了一份譯文是否正確,只能判斷其中的佔位符是否 完好。
安裝¶
需要 Python 3.14 以上。渲染沒有任何相依套件——只用到標準函式庫的 gettext。
擷取與目錄驗證則透過 Babel 進行,因此請在會執行 pybabel 的地方安裝該
extra;那通常是開發或 CI 環境,而不是正式環境的映像檔:
接下來看什麼¶
從這裡開始——不預設你有 gettext 經驗:
- 教學 — 五個步驟,從一個空資料夾走到一份跑得起來的日文 翻譯,每道指令都附上輸出。
- 為什麼選擇 t-string — 同一則訊息的四種寫法,以及
%(name)s、.format()和$-string 各自交給目錄什麼東西。
實際採用——日常查閱的參考:
深入理解——從歷史到實作:
參考資料——各項契約:
專案狀態¶
| 套件版本 | 0.1.0a8 |
| API 穩定性 | alpha——Python API 仍可能變動 |
| 規範 | v1,附一致性測試套件 |
| Python | 3.14 以上;已在 3.14、3.14t(自由執行緒)與 3.15 上測試 |
| Babel | 2.18 以上,且僅在 pybabel 跑得動的地方需要 |
| 執行階段相依 | 無——只用標準函式庫的 gettext |
| 目錄格式 | 一般的 POT、PO 與 MO |
| 變更紀錄 | CHANGELOG |
目前是 alpha。契約刻意做得很小,其中穩定的部分是規範;Python API 還可能會變動。在正式釋出穩定版之前,還需要更廣的語言 fixture、持續的效能追蹤、 來自實際使用 gettext 與 Babel 的人的 API 審視,以及涵蓋所有受支援 Python 與 Babel 版本的相容性測試。
歡迎提出 Issue 與 Pull Request—— alpha 階段正是最值得為介面設計爭論的時候。
加入社群¶
- 挑一個範圍明確的 good first issue 來貢獻。
- 使用上的問題請到 Q&A Discussions 發問。
- 歡迎把正式環境的 gettext 工作流程與 API 想法帶到 Ideas Discussions。
- 開 Pull Request 之前,請先讀過 貢獻指南。