使用 gettext(PO 檔)進行在地化

除了匯入 CSV 格式 的翻譯外,Godot 也支援載入 GNU gettext 格式的翻譯檔(文字型的 .po 與自 Godot 4.0 起支援的編譯型 .mo)。

備註

如需 gettext 的基礎介紹,請參考 A Quick Gettext Tutorial。雖然該教學以 C 專案為例,但大多數內容同樣適用於 Godot(除了 xgettext 相關部分)。

完整文件請參閱 GNU Gettext

優點

  • gettext 是標準格式,可用任意文字編輯器或如 Poedit 等圖形介面編輯器進行編輯。這點相當重要,因為它為譯者提供許多工具,例如標記過時字串、找出尚未翻譯的字串等。

  • gettext 支援複數與語境(context)。

  • TransifexWeblate 等翻譯平台也支援 gettext,讓多人協作在地化更加便利。

  • 與 CSV 相比,gettext 檔更適合搭配 Git 等版本控制系統使用,因為每個語系都有獨立的訊息檔。

  • 在 gettext PO 檔中編輯多行字串比在 CSV 檔中更為便利。

缺點

  • gettext PO 的格式比 CSV 複雜,對在地化新手來說較不易上手。

  • 維護在地化檔案的人員需要在系統上安裝 gettext 工具。不過,由於 Godot 支援以文字為基礎的 .po 檔案,譯者無需安裝 gettext 工具也可直接測試翻譯成果。

  • gettext PO 檔通常以英文作為基底語言,譯者會以此作為來源翻譯至其他語言。你也可以使用其他語言作為基底語言,但並不常見。

安裝 gettext 工具

部分維護操作(如更新訊息檔案)需使用命令列 gettext 工具,因此強烈建議安裝。

  • Windows: 請從 此頁面 下載安裝程式。各種架構與二進位型式(動態或靜態)皆可使用;若不確定,建議選擇 64 位元靜態安裝程式。

  • macOS: 可透過 Homebrew 使用 brew install gettext 指令安裝,或使用 MacPortssudo port install gettext 指令。

  • Linux: 在大多數發行版上,請透過套件管理器安裝 gettext 套件。

若需圖形介面工具,可自其 官方網站 取得 Poedit。基本版本為開源並以 MIT 授權提供。

建立 PO 範本

用編輯器自動產生

自 Godot 4.0 起,編輯器可根據指定的場景與 GDScript 檔案自動產生 PO 範本。此 POT 產生亦支援翻譯語境與複數形式(如於腳本中使用 tr() 的第二參數或 tr_n() 方法)。

開啟專案設定的 在地化 > POT 產生 分頁,點選 新增… 按鈕,指定專案中含有可在地化字串的場景與腳本路徑:

於專案設定的「在地化 > POT 產生」分頁中建立 PO 範本

於專案設定的 在地化 > POT 產生 分頁中建立 PO 範本

新增至少一個場景或腳本後,請點選右上角的 產生 POT,再指定輸出檔案的路徑。該檔案可存放於專案目錄任一位置,但建議集中於如 locale 的子目錄,因每種語言環境將有獨立檔案。

關於在 GDScript 檔案中加入譯者註解或排除特定字串不加入 PO 範本,請參閱下方 從 GDScript 檔案擷取可在地化字串

接著,請參考 如何從 PO 範本建立訊息檔

備註

每當你變更可在地化字串、或新增場景、腳本後,請記得重新產生 PO 範本。否則,新字串將無法在地化,且舊有字串的翻譯也無法及時更新。

手動建立

如果自動產生無法滿足需求,你也可以用文字編輯器手動建立 PO 範本。檔案可放在專案目錄任意位置,但建議集中於子目錄,以利各語言版本管理。

在專案目錄下建立名為 locale 的資料夾,並於該資料夾內儲存名為 messages.pot 的檔案,內容如下:

# Don't remove the two lines below, they're required for gettext to work correctly.
msgid ""
msgstr ""

# Example of a regular string.
msgid "Hello world!"
msgstr ""

# Example of a string with pluralization.
msgid "There is %d apple."
msgid_plural "There are %d apples."
msgstr[0] ""
msgstr[1] ""

# Example of a string with a translation context.
msgctxt "Actions"
msgid "Close"
msgstr ""

gettext 的訊息由 msgidmsgstr 配對組成。msgid 是原文(通常為英文),msgstr 則是對應的譯文。

警告

PO 範本檔(.pot)裡的 msgstr 值應 一律 保持空白。在地化內容則會填寫於產生的 .po 檔案中。

從 PO 範本建立訊息檔案

msginit 指令可將 PO 範本轉換為訊息檔案。例如,若要建立法文翻譯檔,請在 locale 目錄下執行以下指令:

msginit --no-translator --input=messages.pot --locale=fr

上述指令會在同目錄下產生名為 fr.po 的檔案。

你也可以用 Poedit 圖形介面操作,或將 POT 檔上傳至你選用的協作平台來建立。

在 Godot 載入訊息檔案

若要將訊息檔註冊為專案翻譯,請打開 專案設定,進入 在地化 分頁。在 翻譯 區域點選 新增...,於檔案對話框選擇 .po.mo 檔案。語言區域會根據訊息檔中的 "Language: <code>\n" 屬性自動判斷。

備註

更多關於在 Godot 匯入與測試翻譯的資訊,請參閱 將遊戲國際化

依照 PO 範本更新訊息檔案

更新 PO 範本後,也要同步更新各語言訊息檔,以包含新字串並移除已不存在的字串。此操作可用 msgmerge 工具自動完成:

# The order matters: specify the message file *then* the PO template!
msgmerge --update --backup=none fr.po messages.pot

若需保留原始訊息檔備份(如本例將備份為 fr.po~),請移除 --backup=none 參數。

備註

執行 msgmerge 後,若原文有改動,則對應譯文前會自動添加 "fuzzy" 註解。這表示翻譯需檢查修正,否則可能已不精確。

帶有「fuzzy」註解的字串將**不會**被 Godot 讀取,直到翻譯被更新且「fuzzy」註解被移除。

檢查 PO 檔案或範本有效性

可以檢查 gettext 檔案的語法是否有效。

若用 Poedit 開啟,若有語法錯誤會顯示相應警告。你也可以藉由執行下列 gettext 指令來驗證:

msgfmt fr.po --check

如有語法錯誤或警告,將顯示於終端機,否則 msgfmt 不會有任何輸出。

使用二進位 MO 檔案(僅適用於大型專案)

若你的專案有成千上萬條需翻譯字串,建議使用二進位(編譯後)MO 檔案取代文字型 PO 檔案。MO 檔案體積更小、讀取速度更快。

可用下列指令產生 MO 檔案:

msgfmt fr.po --no-hash -o fr.mo

若 PO 檔有效,此指令會在同目錄下產生 fr.mo。之後即可如上所述在 Godot 中載入該 MO 檔。

建議將原始 PO 檔案納入版本控制,便於日後維護翻譯。若遺失原始 PO 檔需將 MO 檔反編譯回文字 PO 檔,可用下列指令:

msgunfmt fr.mo > fr.po

反編譯回來的檔案不會包含註解或 fuzzy 標記,因為這些資訊原本就不會被編入 MO 檔案中。

從 GDScript 檔案擷取可在地化字串

內建的 編輯器外掛 可識別多種原始碼模式,從 GDScript 檔案中擷取可在地化字串,包含但不限於下列類型:

  • tr()tr_n()atr()atr_n() 呼叫;

  • 設定 textplaceholder_texttooltip_text 屬性時;

  • 呼叫 add_tab()add_item()set_tab_title() 等方法;

  • FileDialog 篩選字串,如 "*.png ; PNG Images"

備註

參數或右側運算元必須是常數字串,否則編輯器外掛將無法解析並會忽略該表達式。

若外掛擷取了不需翻譯的字串,可在其前方加上 NO_TRANSLATE 註解來忽略。你也可以用 TRANSLATORS: 註解提供補充說明給譯者。這些註解必須與被識別的程式碼在同一行或直接前一行。

$CharacterName.text = "???" # NO_TRANSLATE

# NO_TRANSLATE: Language name.
$TabContainer.set_tab_title(0, "Python")

item.text = "Tool" # TRANSLATORS: Up to 10 characters.

# TRANSLATORS: This is a reference to Lewis Carroll's poem "Jabberwocky",
# make sure to keep this as it is important to the plot.
say(tr("He took his vorpal sword in hand. The end?"))

使用語境(context)

可以使用 context 參數來區分譯文使用的情境,或區分同形異義詞(多重意義的詞)。

例如:

tr("Start", "Main Menu")
tr("End", "Main Menu")
tr("Shop", "Main Menu")
tr("Shop", "In Game")

更新 PO 檔

隨著時間推進,你會替遊戲加入新內容,也就會出現需要翻譯的新字串。此時需要更新現有的 PO 檔以包含這些新字串。

首先,產生一個包含所有既有字串與新加入字串的 POT 檔。接著,將現有的 PO 檔與新的 POT 檔合併。有兩種作法:

  • 使用 gettext 編輯器,它通常會提供從 POT 檔更新 PO 檔的選項。

  • 使用 gettext 的 msgmerge 工具:

# The order matters: specify the message file *then* the PO template!
msgmerge --update --backup=none fr.po messages.pot

若需保留原始訊息檔備份(如本例將備份為 fr.po~),請移除 --backup=none 參數。

自訂 POT 產生外掛

如果你需要處理額外的檔案格式,可以撰寫自訂外掛來剖析並擷取自訂檔案中的字串。當你按下 Generate POT 時,這個自訂外掛會擷取字串並寫入 POT 檔。要了解如何建立翻譯剖析器外掛,請參考 EditorTranslationParserPlugin