歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Go語言的國際化支持(基於gettext-go)

hello, world!

假設有以下的程序, 輸出: “Hello, world!”.

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, world!")
}

現在要讓改程序支持不同語言的用戶, 然後以本地語言輸出相同意思的信息. 這就是很多程序面臨的國際化問題.

Go 語言的國際化思路

程序的國際化一般涉及到編碼和翻譯兩個概念. 其中編碼一般采用 UTF8 編碼標准, Go 語言已經完美支持. 而目前常見翻譯技術是 Qt 的 tr 函數和 GNU gettext 提供的 gettext 函數, 另外微軟的 MFC 也有自己的多國語言支持方式.

Go 語言目前還沒有標准的多國語言翻譯方式. 不過筆者已經初步將 gettext 的運行時環境移植到了 Go 語言(采用純 Go 實現, 無其他依賴). Go 語言版的 gettext 名字為 gettext-go, 項目地址在: http://code.google.com/p/gettext-go.

gettext-go 同時也借鑒了 Qt 的翻譯上下文特性. 在 GNU gettext 的 pomo 翻譯文件中都是含有 msgctxt 上下文信息的, 但是 C/C++ 的翻譯接口函數並沒有上下文的參數, 因此 傳統的 gettext 函數沒有設置上下文的參數.

可以去 godoc.org 或 gowalker.org 查看 gettext-go 的文檔.

Go 語言的多國語言支持

基於 gettext-go , 我們可以很容易給 Go 程序增加多國語言的支持:

package main

import (
    "fmt"

    "code.google.com/p/gettext-go/gettext"
)

func main() {
    gettext.BindTextdomain("hello", "local")
    gettext.Textdomain("hello")

    fmt.Println(gettext.Gettext("Hello, world!"))
}

其中 gettext.BindTextdomain 是綁定翻譯的空間, 其中 "hello" 是對應翻譯一類信息的翻譯, "local" 為翻譯文件的所在路徑(這裡當前目錄下的”local”)子目錄.

按照 GNU gettext 的習慣, 簡體中文對應的翻譯文件為 "local/zh_CN/LC_MESSAGES/hello.mo". 不同語言的命名有一個國際規范, 比如繁體中文對應 "zh_TW", 美國英文對應 "en_US" 等等. 但是 gettext-go 對名字並沒有特殊的要求.

gettext.BindTextdomain 可以綁定多個翻譯空間, 但是同一個時刻只能使用一個翻譯空間.

這裡我們使用 gettext.Textdomain 指定當前的翻譯空間為 "hello" .

運行新的程序程序, 發現輸出還是: “Hello, world!”.

這是因為缺少翻譯文件…

生成翻譯文件

未來, gettext-go 會開發一個 GNU gettext 工具集 中 的 xgettext 類似工具, 用於從程序中提取要翻譯的字符串.

不過目前, 我們只能手工支持翻譯文件了(還好這個例子只有一個字符串需要翻譯).

創建 "local/zh_CN/LC_MESSAGES/hello.po" 文件, 內容如下:

msgid ""
msgstr ""

msgctxt "main.main"
msgid "Hello, world!"
msgstr "你好, 世界!"

保存為UTF8編碼格式.

然後用 GNU gettext 工具集中的 msgfmt 命令將 hello.po 文件編譯為 hello.mo 文件:

msgfmt -o hello.mo hello.po

如果是 Windows 用戶, 可以下載 poedit 翻譯工具. 然後用 poedit 打開 hello.po 文件, 點擊保存後會自動生成 hello.mo 文件(也是 poedit 的bin目錄下自帶的msgfmt 命令生成的).

重新運行新的程序程序, 還是輸出: “Hello, world!” ?

本地的語言環境

在上一節, 我們已經制作了簡體中文的翻譯文件 "local/zh_CN/LC_MESSAGES/hello.mo", 然後輸出依然是英文.

這是因為 gettext-go 翻譯時不僅要依賴對應語言的翻譯文件, 還需要知道要范圍為哪種語言(和網上翻譯類似, 需要知道翻譯的目標語言).

如果沒有指定翻譯語言, gettext-go 會嘗試獲取本地的默認語言環境, 主要是通過檢查 $(LC_MESSAGES)$(LANG) 兩個環境變量. 如果兩個環境變量都沒有設置, 那麼默認是不進行翻譯的.

我們設置環境變量後重新運行程序(Windows):

set LANG=zh_CN
go run hello.go

這裡時候應該可以輸出中文了.

動態切換語言

如果不想使用默認的本地語言環境, 也可以用 gettext.SetLocale 接口設置本地語言環境.

func main() {
    gettext.SetLocale("zh_CN")
    gettext.BindTextdomain("hello", "local")
    gettext.Textdomain("hello")

    fmt.Println(gettext.Gettext("Hello, world!"))
}

這樣可以可以需要采用合適的語言翻譯文件.

翻譯的上下文

Go 語言版的 gettext-go 的每個 gettext.Gettext 調用都有一個隱含的上下文信息(如果想自己指定上下文可以使用 gettext.PGettext).

默認的上下文為包含 gettext.Gettext 調用的函數名稱, 比如:

  • 如果是 main 包的全局函數初始化調用, 則為 main.init
  • 如果是 main 包的 init 函數調用, 則為 main.init
  • 如果是 main 包的 main 函數調用, 則為 main.main
  • 如果是 main 包中的閉包調用, 則為 main.func
  • 如果是非 main 包的函數, 則還需要包含包的完全路徑名

上下文對應 Go 的運行時調用者名稱, 具體實現在這裡: caller.go .

練習題

  1. 給前面的程序增加 繁體/日文/韓文/克林貢語 等語言的支持
  2. 增加一個 -local 參數, 用於設置本地語言
  3. 提交改進建議或其他反饋意見

comments powered by Disqus

Copyright © Linux教程網 All Rights Reserved