Efficient and easy to use localization and internationalization support for Go.
The only requirement is the Go Programming Language.
$ go get github.com/kataras/i18n@latest
Examples
Create a folder named ./locales
and put some YAML
, TOML
, JSON
or INI
files.
│ main.go
└───locales
├───el-GR
│ example.yml
├───en-US
│ example.yml
└───zh-CN
example.yml
Now, put the key-values content for each locale, e.g. ./locales/en-US/example.yml
hi: "Hi %s"
#
# Templates are supported
# hi: "Hi {{ .Name }}
#
# Template functions are supported
# hi: "Hi {{sayHi .Name}}
# ./locales/el-GR/example.yaml
hi: "Γειά σου %s"
# ./locales/zh-CN/example.yaml
hi: 您好 %s
Some other possible filename formats...
- page.en.yaml
- home.cart.el-GR.json
- /el/file.tml
The language code MUST be right before the file extension.
The Default I18n
instance will try to load locale files from ./locales
directory.
Use the Tr
package-level function to translate a text based on the given language code. Use the GetMessage
function to translate a text based on the incoming http.Request
. Use the Router
function to wrap an http.Handler
(i.e an http.ServeMux
) to set the language based on path prefix such as /zh-CN/some-path
and subdomains such as zh.domain.com
without the requirement of different routes per language.
Let's take a look at the simplest usage of this package.
package main
import (
"fmt"
"github.com/kataras/i18n"
)
type user struct {
Name string
Age int
}
func main() {
// i18n.SetDefaultLanguage("en-US")
// Fmt style.
enText := i18n.Tr("en", "hi", "John Doe") // or "en-US"
elText := i18n.Tr("el", "hi", "John Doe")
zhText := i18n.Tr("zh", "hi", "John Doe")
fmt.Println(enText)
fmt.Println(elText)
fmt.Println(zhText)
// Templates style.
templateData := user{
Name: "John Doe",
Age: 66,
}
enText = i18n.Tr("en-US", "intro", templateData) // or "en"
elText = i18n.Tr("el-GR", "intro", templateData)
zhText = i18n.Tr("zh-CN", "intro", templateData)
fmt.Println(enText)
fmt.Println(elText)
fmt.Println(zhText)
}
Load specific languages over a new I18n instance. The default language is the first registered, in that case is the "en-US".
I18n, err := i18n.New(i18n.Glob("./locales/*/*"), "en-US", "el-GR", "zh-CN")
Load embedded files through a go-bindata package:
I18n, err := i18n.New(i18n.Assets(AssetNames, Asset), "en-US", "el-GR", "zh-CN")
Load embedded files through Go's embed directive (recommended):
//go:embed static/locales/*
var staticFS embed.FS
loader, err := i18n.FS(staticFS, "./static/locales/*/*.yml")
// [handle error...]
I18n, err := i18n.New(loader, "en-US", "el-GR", "zh-CN")
Load through a simple Go map:
m := i18n.LangMap{
"en-US": i18n.Map{
"buy": `buy %d`,
"cart.checkout": `checkout - {{.Param}}`,
"cart.after.thanks": `thanks`,
//
"JSONTemplateExample": `value of {{.Value}}`,
"TypeOf": `type of %T`,
"KeyOnlyOnDefaultLang": `value`,
//
"title": `Title`,
"hi": `Hi {{.Name}}`,
"int": `1`,
"hello": `Hello %s`,
//
"welcome": `welcome`,
},
"el-GR": i18n.Map{
"buy": `αγοράστε %d`,
"cart.checkout": `ολοκλήρωση παραγγελίας - {{.Param}}`,
"cart.after.thanks": `ευχαριστούμε`,
//
"JSONTemplateExample": `τιμή του {{.Value}}`,
"TypeOf": `τύπος %T`,
//
"title": `Τίτλος`,
"hi": `Γειά σου {{.Name}}`,
"int": `1`,
//
"welcome": `καλώς ήρθατε`,
},
}
loader := i18n.KV(m)
i18N, err := i18n.New(loader, "en-US", "el-GR")
Using template variables & functions as values in your locale value entry via LoaderConfig
.
We are going to use a 3rd-party package for plural and singular words. Note that this is only for english dictionary, but you can use the "current"
Locale
and make a map with dictionaries to pluralize words based on the given language.
Before we get started, install the necessary packages:
$ go get github.com/kataras/i18n@master
$ go get github.com/gertd/go-pluralize@master
Let's create two simple translation files for our example. The ./locales/en-US/welcome.yml
and ./locales/el-GR/welcome.yml
respectfully:
Dog: "dog"
HiDogs: Hi {{plural (tr "Dog") .count }}
Dog: "σκυλί"
HiDogs: Γειά {{plural (tr "Dog") .count }}
The
tr
template function is a builtin function registered per locale. It returns the key's translated value. E.g. on english file thetr "Dog"
returns theDog:
's value:"dog"
and on greek file it returns"σκυλί"
. This function helps importing a key to another key to complete a sentence.
Now, create a main.go
file and store the following contents:
package main
import (
"fmt"
"text/template"
"github.com/kataras/i18n"
"github.com/gertd/go-pluralize"
)
var pluralizeClient = pluralize.NewClient()
func getFuncs(current *i18n.Locale) template.FuncMap {
return template.FuncMap{
"plural": func(word string, count int) string {
return pluralizeClient.Pluralize(word, count, true)
},
}
}
func main() {
I18n, err := i18n.New(i18n.Glob("./locales/*/*", i18n.LoaderConfig{
// Set custom functions per locale!
Funcs: getFuncs,
}), "en-US", "el-GR", "zh-CN")
if err != nil {
panic(err)
}
textEnglish := I18n.Tr("en", "HiDogs", map[string]interface{}{
"count": 2,
}) // prints "Hi 2 dogs".
fmt.Println(textEnglish)
textEnglishSingular := I18n.Tr("en", "HiDogs", map[string]interface{}{
"count": 1,
}) // prints "Hi 1 dog".
fmt.Println(textEnglishSingular)
textGreek := I18n.Tr("el", "HiDogs", map[string]interface{}{
"count": 1,
}) // prints "Γειά 1 σκυλί".
fmt.Println(textGreek)
}
Use go run main.go
to run our small Go program. The output should look like this:
Hi 2 dogs
Hi 1 dog
Γειά 1 σκυλί
HTTP, automatically searches for url parameter, cookie, custom function and headers for the current user language.
mux := http.NewServeMux()
I18n.URLParameter = "lang" // i.e https://domain.com?lang=el
I18n.Cookie = "lang"
I18n.ExtractFunc = func(r *http.Request) string { /* custom logic */ }
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
translated := I18n.GetMessage(r, "hi", "John Doe")
fmt.Fprintf(w, "Text: %s", translated)
})
Prefer GetLocale
if more than one GetMessage
call.
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
locale := I18n.GetLocale(r)
translated := locale.GetMessage("hi", "John Doe")
// [...some locale.GetMessage calls]
})
Optionally, identify the current language by subdomain or path prefix, e.g. en.domain.com and domain.com/en or domain.com/en-US and e.t.c.
I18n.Subdomain = true
http.ListenAndServe(":8080", I18n.Router(mux))
If the ContextKey
field is not empty then the Router
will set the current language.
I18n.ContextKey = "lang"
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
currentLang := r.Context().Value("lang").(string)
fmt.Fprintf(w, "Language: %s", currentLang)
})
Set the translate function as a key on a HTML Template
.
templates, _ := template.ParseGlob("./templates/*.html")
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// per-request.
translateFunc := I18n.GetLocale(r).GetMessage
templates.ExecuteTemplate(w, "index.html", map[string]interface{}{
"tr": translateFunc,
})
// {{ call .tr "hi" "John Doe" }}
})
Global function with the language as its first input argument.
translateLangFunc := I18n.Tr
templates.Funcs(template.FuncMap{
"tr": translateLangFunc,
})
// {{ tr "en" "hi" "John Doe" }}
For a more detailed technical documentation you can head over to our godocs. And for executable code you can always visit the _examples repository's subdirectory.
kataras/i18n is free and open-source software licensed under the MIT License.