Skip to content

Latest commit

 

History

History
344 lines (259 loc) · 9.82 KB

README.md

File metadata and controls

344 lines (259 loc) · 9.82 KB

i18n (Go)

build status report card godocs donate on Stripe

Efficient and easy to use localization and internationalization support for Go.

Installation

The only requirement is the Go Programming Language.

$ go get github.com/kataras/i18n@latest

Examples

Getting started

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")

Template variables & functions

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 the tr "Dog" returns the Dog:'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

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.

License

kataras/i18n is free and open-source software licensed under the MIT License.