[Golang] Internationalization (i18n) of Go Application by GNU gettext Tools


GNU gettext tools are great for creating i18n (web) applications. In this post, assume that PO and MO files are ready and we will use the PO and MO files to let Go applications speak local languages. If you do not know what PO or MO files are, or you do not know how to create them by gettext tools, please read my previous post [1] first. If you want to know how to render HTML by html/template with the translated texts in PO and MO files in your Go web application, please refer to [12].

PO and MO files

I will show how to use MO and PO files by example. In the example, we support two locale, zh_TW (Traditional Chinese) and vi_VN (Vietnamese). The zh_TW PO file are located at locale/zh_TW/LC_MESSAGES/messages.po and vi_VN PO file are located at locale/vi_VN/LC_MESSAGES/messages.po.

zh_TW PO file locale/zh_TW/LC_MESSAGES/messages.po:

messages.po | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Chinese translations for PACKAGE package.
# Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Automatically generated, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-06-04 10:20+0800\n"
"PO-Revision-Date: 2013-03-10 05:19+0800\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: zh_TW\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Home"
msgstr "首頁"

msgid "Canon"
msgstr "經典"

msgid "About"
msgstr "關於"

msgid "Setting"
msgstr "設定"

msgid "Translation"
msgstr "翻譯"

vi_VN PO file locale/vi_VN/LC_MESSAGES/messages.po:

messages.po | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Vietnamese translations for PACKAGE package.
# Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Automatically generated, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-06-06 23:05+0800\n"
"PO-Revision-Date: 2013-06-06 22:50+0800\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: vi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"

msgid "Home"
msgstr "Trang chính"

msgid "Canon"
msgstr "Kinh điển"

msgid "About"
msgstr "Giới thiệu"

msgid "Setting"
msgstr "Thiết lập"

msgid "Translation"
msgstr "Dịch"

Generate corresponding MO files by msgfmt. Put MO files together with PO files. So we have two PO files and two MO files:

locale/zh_TW/LC_MESSAGES/messages.po
locale/zh_TW/LC_MESSAGES/messages.mo
locale/vi_VN/LC_MESSAGES/messages.po
locale/vi_VN/LC_MESSAGES/messages.mo

Source Code

Next, we need the gettext-go package to handle the PO and MO files for us. Install gettext-go by:

$ go get github.com/chai2010/gettext-go/gettext

Now we can let Go application speak local language:

gettext.go | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package mylib

import "github.com/chai2010/gettext-go/gettext"

func setup(locale string, domain string, dir string) {
	gettext.SetLocale(locale)
	gettext.Textdomain(domain)

	gettext.BindTextdomain(domain, dir, nil)
}

func changeLocale(locale string) {
	gettext.SetLocale(locale)
}

func translate(input string) string {
	return gettext.PGettext("", input)
}

Note

In line 17 of above code, we use gettext.PGettext("", input) instead of gettext.Gettext(input) because no msgctxt in our PO file (only msgid and msgstr), so specify context as "" in PGettext. If you use Gettext in this case, original string will be returned. For furthur detail, see issue #1 of gettext-go on GitHub.

gettext_test.go | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package mylib

import "testing"

func TestAll(t *testing.T) {
	setup("zh_TW", "messages", "locale")
	setup("vi_VN", "messages", "locale")

	changeLocale("zh_TW")
	t.Log(translate("Home"))
	t.Log(translate("Canon"))
	t.Log(translate("About"))
	t.Log(translate("Setting"))
	t.Log(translate("Translation"))

	changeLocale("vi_VN")
	t.Log(translate("Home"))
	t.Log(translate("Canon"))
	t.Log(translate("About"))
	t.Log(translate("Setting"))
	t.Log(translate("Translation"))
}

Note

The domain in this case is messages. If you name your PO and MO file as hello, the domain becomes hello.

locale/zh_TW/LC_MESSAGES/hello.po
locale/zh_TW/LC_MESSAGES/hello.mo
locale/vi_VN/LC_MESSAGES/hello.po
locale/vi_VN/LC_MESSAGES/hello.mo

Output of Above Code

=== RUN   TestAll
--- PASS: TestAll (0.00s)
        gettext_test.go:10: 首頁
        gettext_test.go:11: 經典
        gettext_test.go:12: 關於
        gettext_test.go:13: 設定
        gettext_test.go:14: 翻譯
        gettext_test.go:17: Trang chính
        gettext_test.go:18: Kinh điển
        gettext_test.go:19: Giới thiệu
        gettext_test.go:20: Thiết lập
        gettext_test.go:21: Dịch
PASS

Tested on: Ubuntu Linux 15.10, Go 1.5.2.


References:

[1]Internationalization (i18n) of Web Application by GNU gettext Tools
[2]Google Search go gettext
[3]chai2010/gettext-go · GitHub godoc1-png
[4]Go语言的国际化支持(资源文件翻译) - CHAI2010
[5]Go语言的国际化支持(基于gettext-go) - CHAI2010
[6]localization - I18n strategies for Go with App Engine - Stack Overflow
[7]samuel/go-gettext · GitHub godoc2-png
[8]Google Search go i18n
[9][Python] Internationalization (i18n) of Python Application by GNU gettext Tools
[10]i18n Python Web Application by gettext and Jinja2
[11]gosexy/gettext · GitHub
[12]i18n Golang Web Application by gettext and html/template