如何翻譯 PO 檔案而不影響你的應用程式
TABLE OF CONTENTS
PO 檔案看起來就像一般的文字檔,直到一個被翻譯的 %s、缺少的複數形式,或被修改的 msgid 讓你的應用程式出錯。請依照這個工作流程翻譯面向使用者的字串,同時保持 gettext 結構不變。
不要把整個檔案貼到一般的文字翻譯器裡。PO 檔案接近原始碼:文字可以翻譯,但檔案結構、佔位符、註解和複數索引必須完全保留。
方法一:使用 PO 檔案翻譯工具
如果你想要最快速且安全的初稿,又不想手動編輯 msgid / msgstr 配對,請選擇這個方法。
-
備份原始
.po檔案。 在將檔案交給翻譯人員前,請先在你的版本庫中保留一份乾淨的副本。如果翻譯後的檔案出錯,你需要一個已知沒問題的版本來比對。 -
打開支援 PO 的翻譯工具。 使用專為 gettext 檔案設計的工具,例如 OpenL PO Translator,這是一個按次付費的文件翻譯工具。支援 PO 的工具會翻譯目標字串,同時保留原始字串、註解、佔位符和檔案結構。如果你還在選擇工具,可以參考我們的最佳 PO 翻譯工具指南進行比較。
-
上傳
.po檔案。 請使用包含msgid和msgstr條目的語言檔案。如果你只有.pot樣板,請先從它建立目標語言的.po檔案,再上傳.po檔。 -
選擇來源語言和目標語言。 來源語言要對應
msgid內的文字,而不是你的管理介面語言。例如,如果檔案內的msgid是英文、你需要西班牙文輸出,請選擇英文到西班牙文。 -
下載翻譯後的檔案。 儲存時請依照你的框架所需的語系命名規則。WordPress 外掛通常使用文字網域加語系的格式,而 Django 則多半將檔案放在
locale/<language>/LC_MESSAGES/目錄下。 -
優先檢查高風險字串。 在翻譯後的檔案中搜尋
%、{、}、<、>、msgid_plural、msgctxt和#, fuzzy。這些條目最有可能影響執行時的行為。 -
在應用程式中測試翻譯檔案。 將語言檔案載入本地,並點擊所有使用到翻譯字串的畫面。PO 檔案並非翻譯完成就算結束,只有當應用程式依然能正確顯示時,才算真正完成。
方法二:在 Poedit 中翻譯 PO 檔案
當你需要人工審核、WordPress 相容性,或是逐條細緻翻譯流程時,請選擇此方法。
-
在 Poedit 中開啟檔案。 Poedit 是專為 PO 及其他在地化格式設計的翻譯編輯器;基本編輯器免費,進階工作流程則有付費 Pro 版本。對於 WordPress,官方 Polyglots 手冊說明 Poedit 可從 POT 檔建立
.po和.mo檔,並支援複數型態與 UTF-8。 -
若原始內容有變更,請從 POT 樣板更新。 如果開發者修改了應用程式文字,請在翻譯前,先用最新的
.pot檔更新.po檔。這樣可以讓新增、移除或模糊的字串明確顯示,避免過時的介面文字被悄悄釋出。 -
只翻譯
msgstr欄位。msgid是應用程式用來查找翻譯的原文字串。在一般 gettext 工作流程中,譯者應只編輯msgstr,不要動msgid。 -
佔位符必須完全保留。 請勿翻譯或更動像
%s、%d、%1$s、{name}、%(count)s、:name或 HTML 標籤等變數。如果語序需要調整,請整個佔位符一起移動。 -
複數型態需分開翻譯。 複數條目會包含
msgid、msgid_plural及多個msgstr[n]欄位。請根據目標語言的需求,完整填寫每個複數欄位,而不是每一欄都複製同一句話。 -
儲存並編譯
.mo檔案(如應用程式需要)。 有些技術棧在開發期間會直接讀取.po檔案,但 WordPress 及多數 gettext 架構在執行時會使用編譯後的.mo檔案。Poedit 可以在儲存時自動編譯.mo;Django 則可用django-admin compilemessages來編譯訊息。 -
上傳前先解決所有警告。 在 Poedit 中,警告圖示通常代表佔位符錯誤、變數遺漏或複數型態不符。請在將翻譯匯入 WordPress、Django、Drupal 或發行分支前,先修正這些問題。
方法三:使用在地化平台
當有多位譯者、審核者或發行管理員需要協作同一份 PO 檔時,建議選用此法。
-
將 PO 檔匯入支援 gettext 的平台。 Weblate 及類似的在地化平台都支援 PO 工作流程。團隊型在地化平台多為付費產品,但 Weblate 也有開源自架版。各平台對註解、標頭、模糊字串及佔位符的處理方式不同,上傳正式檔案前請先檢查格式設定。
-
啟用佔位符與標籤檢查。 開啟 QA 規則,檢查 printf 風格佔位符、命名變數、HTML/XML 標籤及複數型態。這些檢查能發現一般拼字檢查無法察覺的錯誤。
-
讓開發者註解保持可見。 PO 註解可包含來源參考、開發者備註、標記及前一版原文等資訊。當像「Open」這樣的短介面標籤可能是動詞、形容詞或選單指令時,譯者需要這些註解來釐清語境。
-
搭配審核使用翻譯記憶庫。 翻譯記憶庫對於重複的介面字串很有幫助,但有時會將舊譯文套用到新語境。當
msgctxt、來源參考或周邊介面有變化時,請務必審核重用的字串。 -
匯出 PO 檔並進行本地檢查。 匯出後請勿直接信任結果。將翻譯檔重新放回應用程式,必要時編譯,並實際測試畫面後再合併。
PO 檔案絕不可違反的規則
| PO 項目 | 需要翻譯嗎? | 安全範例 | 為什麼這很重要 |
|---|---|---|---|
msgid | 否 | msgid "Save changes" | 應用程式在許多 gettext 工作流程中會用這個原文字串作為查找鍵。 |
msgstr | 是 | msgstr "Guardar cambios" | 這是使用者實際看到的目標語言文字。 |
msgctxt | 否 | msgctxt "button" | 上下文可釐清相同原文的不同用途。 |
%s, %d, %1$s | 否 | Hello, %s -> Hola, %s | 執行時程式會用即時值取代這些佔位符。 |
{name}, %(count)s, :name | 否 | Welcome, {name} | 命名變數必須與應用程式程式碼一致。 |
| HTML 標籤 | 通常不翻譯 | <strong>Warning</strong> | 只翻譯標籤內的文字,不要改動標籤語法。 |
msgid_plural | 否 | msgid_plural "%d files" | 原文複數形式屬於原始程式碼流程。 |
msgstr[0], msgstr[1] | 是,但要小心 | msgstr[0] "%d file" | 每種目標語言有自己的複數規則。 |
#, fuzzy | 先檢查 | #, fuzzy | fuzzy 代表翻譯可能過時或尚未確認。 |
#. 開發者註解 | 通常不翻譯 | #. Button label | 這些註解協助譯者理解上下文。 |
快速範例:安全 vs. 出錯的 PO 翻譯
以下是一個正常的 gettext 條目:
#. %s is the user's display name.
#, c-format
msgid "Welcome back, %s"
msgstr ""
一個安全的西班牙語翻譯會保留 %s 不變:
#. %s is the user's display name.
#, c-format
msgid "Welcome back, %s"
msgstr "Bienvenido de nuevo, %s"
一個出錯的翻譯則改動了佔位符:
msgid "Welcome back, %s"
msgstr "Bienvenido de nuevo, % s"
那個小小的空格就可能造成問題。GNU msgfmt --check-format 就是用來檢查像是錯誤 % 佔位符這類格式字串不符的情況,Poedit 也會針對常見的佔位符問題發出警告。若要查閱更多應保持不變的字串,請參考我們的不可翻譯內容指南。
如何檢查已翻譯的 PO 檔案
- 如果你已安裝 gettext,請執行 gettext 驗證。
msgfmt --check --check-format -o /tmp/messages.mo path/to/messages.po
這個指令會檢查語法、標頭和格式字串,若檔案有效,則會寫入一個暫時編譯的 catalog。
- 依照你的框架需求編譯檔案。
django-admin compilemessages
對於 Django 專案來說,compilemessages 會將由 makemessages 產生的 .po 檔案編譯成 .mo 檔案,以支援 gettext。
- 搜尋空白翻譯。
grep -n 'msgstr ""' path/to/messages.po
空的 msgstr 欄位可能是尚未翻譯的條目,這通常是有意為之,但在發佈時不應讓你感到意外。
- 搜尋模糊翻譯字串。
grep -n '#, fuzzy' path/to/messages.po
模糊(fuzzy)字串應在發佈前由人工審查。預設情況下,msgfmt 不會使用模糊翻譯,除非你用 --use-fuzzy 編譯,因此模糊條目在最終 catalog 中會像未翻譯字串一樣處理。
- 實際測試 UI。 請開啟包含表單、複數計數、錯誤訊息、帳號選單及付款流程的畫面。PO 檔驗證能抓出檔案問題,只有 UI 測試才能發現用詞不自然、文字溢出或語境缺失等問題。
你該用哪一種方法?
| 情境 | 最佳方法 | 原因 |
|---|---|---|
| 你需要為單一 PO 檔案快速產出初稿 | PO 檔案翻譯器 | 最快且能保留結構 |
| 你維護 WordPress 外掛或佈景主題 | Poedit | 熟悉的 WordPress 工作流程,並可編譯 .mo 檔 |
| 你維護 Django 應用程式 | PO 翻譯器或 Poedit,然後執行 compilemessages | 翻譯可快速完成,但仍需框架編譯 |
| 你有多種語言及多位審核者 | 在地化平台 | 更佳的指派、歷史紀錄、品質控管與審核管理 |
| 你在翻譯開發者相關字串 | 機器翻譯後進行人工審核 | 程式碼術語、佔位符與語境更為重要 |
| 你也要在地化 JSON 或前端 i18n 檔案 | 使用對應格式的工作流程 | PO 的規則不一定適用於 JSON、YAML 或 ICU 訊息 |
如果你的專案同時包含 gettext PO 檔與 JSON 語系檔,請分別使用能理解其結構的工具來翻譯。PO 檔以 msgid 和 msgstr 為核心;JSON 在地化則以鍵值對為主。這類工作流程,請參考我們的2026 年最佳 JSON 翻譯工具指南。
常見問題
我可以用 Google 翻譯來翻譯 PO 檔嗎?
你可以將單一 msgstr 值複製到一般翻譯器中,但將整個 PO 檔上傳或貼到純文字翻譯器中風險很高。一般翻譯器可能會改動 msgid、註解、引號跳脫、複數索引或佔位符。建議改用支援 PO 格式的翻譯器、Poedit 或在地化平台。
.po、.pot 和 .mo 有什麼不同?
.pot 是從原始碼擷取出來的範本,通常只包含原文字串,沒有翻譯內容。.po 是針對單一目標語言可編輯的翻譯檔案。.mo 則是編譯後的二進位目錄,許多基於 gettext 的應用程式在執行時會載入它。
我應該翻譯 msgid 嗎?
不,正常工作流程中不是这样操作的。请翻译 msgstr。GNU gettext 手册将 msgid 描述为原始未翻译字符串,而 msgstr 则是翻译内容;msgid 字符串由 gettext 工具生成和管理。
如何檢查 PO 檔案是否有效?
如果有安裝 gettext,可以執行 msgfmt --check --check-format,也可以用 Poedit 開啟檔案,或利用你的在地化平台的 QA 檢查功能。然後將檔案編譯並在應用程式內測試。驗證是必要步驟,但不能取代 UI 測試。
如果我破壞了一個佔位符會怎樣?
最好的情況是,應用程式顯示奇怪的字串。更糟的情況是,執行時格式化器會拋出錯誤,因為翻譯後的字串已經和程式碼傳入的變數不符。佔位符只能作為完整的標記移動,絕不能翻譯或部分編輯。
OpenL 可以翻譯 PO 檔案嗎?
可以。OpenL PO Translator 專為 gettext .po 檔案設計,並聲稱在翻譯超過 100 種語言時,會保持佔位符和變數不變。它採用按次計費的文件翻譯流程,因此當你需要快速產出初稿、又必須保留 PO 結構時,可以考慮使用。如果你只有 .pot 範本,請先建立目標語言的 .po 檔案再用 OpenL。
來源
- GNU gettext 手冊:PO 檔案 — 官方 gettext 關於 PO 檔案格式的說明。
- GNU gettext 手冊:PO 檔案條目 — 關於
msgid、msgstr、註解、標記與條目結構的來源。 - GNU gettext 手冊:含複數形式的條目 — 關於複數形式條目結構的來源。
- GNU gettext 手冊:msgfmt 執行 — 關於
msgfmt --check及格式字串驗證的來源。 - OpenL PO Translator — OpenL 產品頁,支援翻譯
.po檔案並保留佔位符與變數。 - Poedit — 官方 Poedit 網站,提供 PO 翻譯編輯器及 Pro 版本。
- WordPress Polyglots 手冊:Poedit — WordPress 關於使用 Poedit、POT 檔案、PO 檔案、MO 編譯及佔位符警告的指引。
- Django 文件:翻譯 — Django 訊息檔案與翻譯的工作流程。
- Django 文件:compilemessages — Django 指令參考,說明如何將
.po檔案編譯成.mo檔案。 - Drupal 文件:PO 與 POT 檔案 — Drupal 關於
.po、.pot、語境、複數形式、註解與變數的說明。 - Weblate 文件:GNU gettext PO — 本地化平台說明 PO 標頭、先前原文、已廢棄字串及生成 MO 檔案的注意事項。