使用 GNU gettext 來翻譯軟體

GNU gettext 是自由軟體國際化最廣泛使用的工具之一。它提供了簡單與彈性的方式來進行軟體在地化。它有完善的支援複數格式,可以為翻譯字串增加更多的上下文內容與相當多的工具為它所打造。當然它也有 Weblate 的強力支援(參閱 GNU gettext PO (Portable Object) 檔案格式說明)。

備註

如果打算在私有軟件中使用它,那麼請首先諮詢許可,它可能不適合您。

GNU gettext 可以在大量語言中使用(C、Python、PHP、Ruby、JavaScript 以及更多),並且一些 UI 框架通常已經為它帶有一些支援。標準使用是通過 gettext() 函數呼叫,這通常具有 _() 別名,使代碼更簡單且更容易閱讀。

此外,它提供 pgettext() 呼叫而為翻譯者提供另外的文本,以及提供 ngettext(),可以處理目標語言定義的附屬類型。

作為廣泛傳播的工具,它具有很多封裝,使其使用相當簡單,您也許會想嘗試其中之一,例如 intltool,而非下面描述的對 gettext 的手動呼叫。

工作流程概覽

GNU gettext 使用幾個檔案來管理在地化工作:

  • PACKAGE.pot 包含從您的來源碼中提取的字串,典型地使用 xgettext 或一些高級包裝器,如 intltool

  • LANGUAGE.po 包含翻譯為單一語言的字串。一旦 PACKAGE.pot 更新,那麼必須由 msgmerge 來更新它。您可以使用 msginit 或在 Weblate 內新建新的語言文件。

  • LANGUAGE.mo 包含 LANGUAGE.po 的二進製表達,並且應用執行時使用。基本上它並不保持在版本控制之中,但在編譯時使用 msgfmt 產生。如果您想要將它放到版本控制中,可以使用 產生 MO 檔案 附加元件在 Weblate 中產生它。

GNU gettext 總體工作流程看起來像這樣:

digraph translations { graph [fontname = "sans-serif", fontsize=10]; node [fontname = "sans-serif", fontsize=10, shape=note, margin=0.1, height=0]; edge [fontname = "monospace", fontsize=10]; "Source code" -> "PACKAGE.pot" [label=" xgettext "]; "PACKAGE.pot" -> "LANGUAGE.po" [label=" msgmerge "]; "LANGUAGE.po" -> "LANGUAGE.mo" [label=" msgfmt "]; }

也參考

GNU gettext 概覽

樣本程式

使用 gettext 的 C 語言簡單程序看起來會像後面這樣:

#include <libintl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int count = 1;
    setlocale(LC_ALL, "");
    bindtextdomain("hello", "/usr/share/locale");
    textdomain("hello");
    printf(
        ngettext(
            "Orangutan has %d banana.\n",
            "Orangutan has %d bananas.\n",
            count
        ),
        count
    );
    printf("%s\n", gettext("Thank you for using Weblate."));
    exit(0);
}

提取可翻譯的字串

一旦您具有了使用 gettext 呼叫的程式碼,您可以使用 xgettext 從中提取訊息,並將它們儲存在 .pot 中:

$ xgettext main.c -o po/hello.pot

備註

有另外的程序從代碼中提取字串,例如 pybabel

這新建了模板文件,您可以用它來開始新的翻譯(使用`msginit`_),或在代碼更改後更新現有的翻譯(為此您將使用 msgmerge)。結果文件是簡單的結構化文本文件:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-10-23 11:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#: main.c:14
#, c-format
msgid "Orangutan has %d banana.\n"
msgid_plural "Orangutan has %d bananas.\n"
msgstr[0] ""
msgstr[1] ""

#: main.c:20
msgid "Thank you for using Weblate."
msgstr ""

每個 msgid 行定義了要翻譯的字串,在開始的特殊空字串是包含關於翻譯的元資料的文件標頭。

開始新的翻譯

在模板就位後,我們就可以開始我們的第一個翻譯了:

$ msginit -i po/hello.pot -l cs --no-translator -o po/cs.po
Created cs.po.

剛剛新建的 cs.po 已經有一些資訊填充進去了。最重要的是它獲得了所選擇的語言的適當複數形式定義,並且您可以看到幾種複數已經根據它更改了:

# Czech translations for PACKAGE package.
# Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Automatically generated, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-10-23 11:02+0200\n"
"PO-Revision-Date: 2015-10-23 11:02+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"

#: main.c:14
#, c-format
msgid "Orangutan has %d banana.\n"
msgid_plural "Orangutan has %d bananas.\n"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""

#: main.c:20
msgid "Thank you for using Weblate."
msgstr ""

這個文件被編譯為優化的二進制形式,.mo 文件,由`GNU gettext`_ 函數在執行時使用。時使用。

更新字串

一旦在您的程序中新增了更多的字串或更改了一些字串,您再次執行 xgettext,生成模板文件:

$ xgettext main.c -o po/hello.pot

然後您可以更新各自的翻譯文件來匹配新建的模板(這包括重新排序字串,賴於新的模板匹配):

$ msgmerge --previous --update po/cs.po po/hello.pot

導入到 Weblate

為了將這樣的翻譯導入 Weblate,當新建組件時,所有需要您定義的是後面的字段(字段的具體描述請參見 組件組態):

欄位

數值

來源碼儲存庫

您的項目的版本控制系統(VCS)倉儲的 URL

檔案遮罩

po/*.po

新翻譯的模板

po/hello.pot

檔案格式

Choose gettext PO file

新增語言

選擇 :guilabel:`Create new language file`(新建新語言文件)

就是這樣,現在您已經準備號開始翻譯您的軟件了!

也參考

您可以在 GitHub: <https://github.com/WeblateOrg/hello> 上的 Weblate Hello 項目中找到帶有很多語言的 gettext 示例。