i18n
This module is mainly used for i18n of sites and applications, which provides multiple-language options to users, improve user experience.
You can use the following command to install this module:
go get github.com/beego/i18n@latest
i18n Usage
First of all, you have to import this package:
import (
"github.com/beego/i18n"
)
The format of locale files is very much like the INI format configuration file, which is basically key-value pairs. But this module has some improvements. Every language corresponds to a locale file, for example, under conf
folder of beego.vip, there are two files called locale_en-US.ini
and locale_zh-CN.ini
.
The name and extensions of locale files can be anything.
Minimal example
Here are two simplest locale file examples:
File locale_en-US.ini
:
hi = hello
bye = goodbye
File locale_zh-CN.ini
:
hi = 您好
bye = 再见
Use in controller
For every request, Beego uses individual goroutines to handle the request; therefore, you can embed an i18n.Locale
as an anonymous field to process locale operations of the current request. This requires that you understand the idea of baseController
and Prepare
method. See source file routers/router.go
of beego.vip for more details.
After accepting the request, use the Prepare
method of baseController
to do language operations, which you only need to write the same code once and use it in all the upper level controllers.
Register locale files
The following code is from beego.vip source file routers/init.go
:
// Initialized language type list.
langs := strings.Split(beego.AppConfig.String("lang::types"), "|")
names := strings.Split(beego.AppConfig.String("lang::names"), "|")
langTypes = make([]*langType, 0, len(langs))
for i, v := range langs {
langTypes = append(langTypes, &langType{
Lang: v,
Name: names[i],
})
}
for _, lang := range langs {
beego.Trace("Loading language: " + lang)
if err := i18n.SetMessage(lang, "conf/"+"locale_"+lang+".ini"); err != nil {
beego.Error("Fail to set message file: " + err.Error())
return
}
}
In this piece of code, we get languages that we want to support in the configuration file, in this case, we have en-US
and zh-CN
. Then we initialize a slice for users to change language option(not discussed here). Finally, we call the i18n.SetMessage
function in a loop to load all the locale files. Here you can see why we recommend the you use the naming conventions of beego.vip for locale files.
Initialize controller language
The following code is from the beego.vip source file routers/router.go
, which decides on which user language option to use in the following order: 1: URL specified 2: Cookies and 3: browser Accept-Language
.
// setLangVer sets site language version.
func (this *baseRouter) setLangVer() bool {
isNeedRedir := false
hasCookie := false
// 1. Check URL arguments.
lang := this.Input().Get("lang")
// 2. Get language information from cookies.
if len(lang) == 0 {
lang = this.Ctx.GetCookie("lang")
hasCookie = true
} else {
isNeedRedir = true
}
// Check again in case someone modify on purpose.
if !i18n.IsExist(lang) {
lang = ""
isNeedRedir = false
hasCookie = false
}
// 3. Get language information from 'Accept-Language'.
if len(lang) == 0 {
al := this.Ctx.Request.Header.Get("Accept-Language")
if len(al) > 4 {
al = al[:5] // Only compare first 5 letters.
if i18n.IsExist(al) {
lang = al
}
}
}
// 4. Default language is English.
if len(lang) == 0 {
lang = "en-US"
isNeedRedir = false
}
curLang := langType{
Lang: lang,
}
// Save language information in cookies.
if !hasCookie {
this.Ctx.SetCookie("lang", curLang.Lang, 1<<31-1, "/")
}
restLangs := make([]*langType, 0, len(langTypes)-1)
for _, v := range langTypes {
if lang != v.Lang {
restLangs = append(restLangs, v)
} else {
curLang.Name = v.Name
}
}
// Set language properties.
this.Lang = lang
this.Data["Lang"] = curLang.Lang
this.Data["CurLang"] = curLang.Name
this.Data["RestLangs"] = restLangs
return isNeedRedir
}
The variable isNeedRedir
indicates whether user uses URL to specify the language option. To keep the URL clean, beego.vip automatically sets the value in cookies and redirect.
The line this.Data["Lang"] = curLang.Lang
sets user language option to template variable Lang
so that we can handle language in template files.
Following two lines:
this.Data["CurLang"] = curLang.Name
this.Data["RestLangs"] = restLangs
For users to change language option, see beego.vip source code for more details.
Handle language in controller
While the i18n.Locale
is an anonymous field to be embedded in baseController
, we can use this.Tr(format string, args ...interface{})
to handle language in controller.
Handle language in template
By passing template variable Lang
to indicate language option, you are able to do localization in template. But before that, you need to register a template function.
Following code is from beego.vip source file beeweb.go
:
beego.AddFuncMap("i18n", i18n.Tr)
After that, do the following with Lang
to handle language:
{{i18n .Lang "hi%d" 12}}
Code above will produce:
- English
en-US
:hello12
- Chinese
zh-CN
:您好12
Section
For different pages, one key may map to different values. Therefore, i18n module also uses the section feature of INI format configuration to achieve section separation.
For example, the key name is about
, and we want to show About
in the home page and About Us
in about page. Then you can do following:
Content in locale file:
about = About
[about]
about = About Us
Get about
in home page:
{{i18n .Lang "about"}}
Get about
in about page:
{{i18n .Lang "about.about"}}
Ambiguity
Because dot .
denotes a section in both INI parser and locale files, when your key name contains .
this will cause ambiguity. To avoid ambiguity, you just need to add one more .
in front of the key.
For example, the key name is about.
, then we can use:
{{i18n .Lang ".about."}}
to get the desired result.
Helper tool
Module i18n provides a command line helper tool beei18n to simplify the steps in your development. You can install it as follows:
go get github.com/beego/i18n/beei18n
Sync locale files
Command sync
allows you use a exist local file as the template to create or sync other locale files:
beei18n sync source_file.ini other1.ini other2.ini
This command can operate on 1 or more files in one command.
More information
If the key does not exist, then i18n will return the key string to caller. For instance, when key name is hi
and it does not exist in locale file, it will simply return hi
as output.