GNU 有一個名為 GNU gettext 的函式庫,可以輕鬆地將程式中的訊息翻譯成各種語言。您應該在每個程式中使用這個函式庫。程式中出現的訊息請使用英文,並讓 gettext 提供將它們翻譯成其他語言的方法。
使用 GNU gettext 涉及在每個可能需要翻譯的字串周圍放置一個對 gettext
巨集的呼叫,就像這樣
printf (gettext ("Processing file '%s'..."), file);
這允許 GNU gettext 將字串 "Processing file '%s'..."
替換為翻譯後的版本。
一旦程式使用了 gettext,當您新增需要翻譯的新字串時,請務必記得呼叫 gettext
。
在套件中使用 GNU gettext 涉及為該套件指定一個文本域名稱。文本域名稱用於將此套件的翻譯與其他套件的翻譯分開。通常,文本域名稱應與套件的名稱相同,例如,GNU 核心工具程式的 ‘coreutils’。
為了使 gettext 能夠良好運作,請避免編寫會對單字或句子的結構做出假設的程式碼。當您希望句子的精確文本根據資料而變化時,請使用兩個或多個替代字串常數,每個常數都包含完整的句子,而不是將條件化的單字或片語插入到單一句子框架中。
以下是一個不應該這樣做的例子
printf ("%s is full", capacity > 5000000 ? "disk" : "floppy disk");
如果您像這樣對所有字串應用 gettext,
printf (gettext ("%s is full"), capacity > 5000000 ? gettext ("disk") : gettext ("floppy disk"));
翻譯人員幾乎無法知道 "disk" 和 "floppy disk" 是要替換到另一個字串中。更糟的是,在某些語言(如法語)中,這種結構將無法運作:單字 "full" 的翻譯取決於句子第一部分的性別;而 "disk" 和 "floppy disk" 的情況恰好不同。
完整的句子可以毫無問題地翻譯
printf (capacity > 5000000 ? gettext ("disk is full") : gettext ("floppy disk is full"));
類似的問題也出現在句子結構層面,以下程式碼就是一個例子
printf ("# Implicit rule search has%s been done.\n", f->tried_implicit ? "" : " not");
對此程式碼新增 gettext
呼叫無法為所有語言提供正確的結果,因為某些語言中的否定需要在句子中的多個位置新增單字。相比之下,如果程式碼一開始像這樣,新增 gettext
呼叫就可以直接完成工作
printf (f->tried_implicit ? "# Implicit rule search has been done.\n", : "# Implicit rule search has not been done.\n");
另一個例子是這個
printf ("%d file%s processed", nfiles, nfiles != 1 ? "s" : "");
這個例子的問題在於它假設複數是透過新增 ‘s’ 來構成的。如果您像這樣對格式字串應用 gettext,
printf (gettext ("%d file%s processed"), nfiles, nfiles != 1 ? "s" : "");
訊息可以使用不同的單字,但它仍然會被迫使用 ‘s’ 來表示複數。以下是一個更好的方法,將 gettext 獨立地應用於兩個字串
printf ((nfiles != 1 ? gettext ("%d files processed") : gettext ("%d file processed")), nfiles);
但是這仍然不適用於像波蘭語這樣的語言,波蘭語有三種複數形式:一種用於 nfiles == 1,一種用於 nfiles == 2、3、4、22、23、24、...,另一種用於其餘情況。GNU ngettext
函數解決了這個問題
printf (ngettext ("%d files processed", "%d file processed", nfiles), nfiles);