i18n

package
v1.10.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 31, 2024 License: MIT Imports: 3 Imported by: 905

Documentation

Overview

Package i18n supports string translations with variable substitution and CLDR pluralization. It is intended to be used in conjunction with the goi18n command, although that is not strictly required.

Initialization

Your Go program should load translations during its initialization.

i18n.MustLoadTranslationFile("path/to/fr-FR.all.json")

If your translations are in a file format not supported by (Must)?LoadTranslationFile, then you can use the AddTranslation function to manually add translations.

Fetching a translation

Use Tfunc or MustTfunc to fetch a TranslateFunc that will return the translated string for a specific language.

func handleRequest(w http.ResponseWriter, r *http.Request) {
    cookieLang := r.Cookie("lang")
    acceptLang := r.Header.Get("Accept-Language")
    defaultLang = "en-US"  // known valid language
    T, err := i18n.Tfunc(cookieLang, acceptLang, defaultLang)
    fmt.Println(T("Hello world"))
}

Usually it is a good idea to identify strings by a generic id rather than the English translation, but the rest of this documentation will continue to use the English translation for readability.

T("Hello world")     // ok
T("programGreeting") // better!

Variables

TranslateFunc supports strings that have variables using the text/template syntax.

T("Hello {{.Person}}", map[string]interface{}{
    "Person": "Bob",
})

Pluralization

TranslateFunc supports the pluralization of strings using the CLDR pluralization rules defined here: http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html

T("You have {{.Count}} unread emails.", 2)
T("I am {{.Count}} meters tall.", "1.7")

Plural strings may also have variables.

T("{{.Person}} has {{.Count}} unread emails", 2, map[string]interface{}{
    "Person": "Bob",
})

Sentences with multiple plural components can be supported with nesting.

T("{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.", 3, map[string]interface{}{
    "Person":    "Bob",
    "Timeframe": T("{{.Count}} days", 2),
})

Templates

You can use the .Funcs() method of a text/template or html/template to register a TranslateFunc for usage inside of that template.

Example
package main

import (
	"fmt"

	"github.com/nicksnyder/go-i18n/i18n"
)

func main() {
	i18n.MustLoadTranslationFile("../goi18n/testdata/expected/en-us.all.json")

	T, _ := i18n.Tfunc("en-US")

	bobMap := map[string]interface{}{"Person": "Bob"}
	bobStruct := struct{ Person string }{Person: "Bob"}

	fmt.Println(T("program_greeting"))
	fmt.Println(T("person_greeting", bobMap))
	fmt.Println(T("person_greeting", bobStruct))

	fmt.Println(T("your_unread_email_count", 0))
	fmt.Println(T("your_unread_email_count", 1))
	fmt.Println(T("your_unread_email_count", 2))
	fmt.Println(T("my_height_in_meters", "1.7"))

	fmt.Println(T("person_unread_email_count", 0, bobMap))
	fmt.Println(T("person_unread_email_count", 1, bobMap))
	fmt.Println(T("person_unread_email_count", 2, bobMap))
	fmt.Println(T("person_unread_email_count", 0, bobStruct))
	fmt.Println(T("person_unread_email_count", 1, bobStruct))
	fmt.Println(T("person_unread_email_count", 2, bobStruct))

	type Count struct{ Count int }
	fmt.Println(T("your_unread_email_count", Count{0}))
	fmt.Println(T("your_unread_email_count", Count{1}))
	fmt.Println(T("your_unread_email_count", Count{2}))

	fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": 0}))
	fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": "1"}))
	fmt.Println(T("your_unread_email_count", map[string]interface{}{"Count": "3.14"}))

	fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
		"Person":    "Bob",
		"Timeframe": T("d_days", 0),
	}))
	fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
		"Person":    "Bob",
		"Timeframe": T("d_days", 1),
	}))
	fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
		"Person":    "Bob",
		"Timeframe": T("d_days", 2),
	}))

	fmt.Println(T("person_unread_email_count_timeframe", 1, map[string]interface{}{
		"Count":     30,
		"Person":    "Bob",
		"Timeframe": T("d_days", 0),
	}))
	fmt.Println(T("person_unread_email_count_timeframe", 2, map[string]interface{}{
		"Count":     20,
		"Person":    "Bob",
		"Timeframe": T("d_days", 1),
	}))
	fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
		"Count":     10,
		"Person":    "Bob",
		"Timeframe": T("d_days", 2),
	}))

}
Output:

Hello world
Hello Bob
Hello Bob
You have 0 unread emails.
You have 1 unread email.
You have 2 unread emails.
I am 1.7 meters tall.
Bob has 0 unread emails.
Bob has 1 unread email.
Bob has 2 unread emails.
Bob has 0 unread emails.
Bob has 1 unread email.
Bob has 2 unread emails.
You have 0 unread emails.
You have 1 unread email.
You have 2 unread emails.
You have 0 unread emails.
You have 1 unread email.
You have 3.14 unread emails.
Bob has 3 unread emails in the past 0 days.
Bob has 3 unread emails in the past 1 day.
Bob has 3 unread emails in the past 2 days.
Bob has 1 unread email in the past 0 days.
Bob has 2 unread emails in the past 1 day.
Bob has 3 unread emails in the past 2 days.
Example (Template)
package main

import (
	"os"
	"text/template"

	"github.com/nicksnyder/go-i18n/i18n"
)

var funcMap = map[string]interface{}{
	"T": i18n.IdentityTfunc,
}

var tmpl = template.Must(template.New("").Funcs(funcMap).Parse(`
{{T "program_greeting"}}
{{T "person_greeting" .}}
{{T "your_unread_email_count" 0}}
{{T "your_unread_email_count" 1}}
{{T "your_unread_email_count" 2}}
{{T "person_unread_email_count" 0 .}}
{{T "person_unread_email_count" 1 .}}
{{T "person_unread_email_count" 2 .}}
`))

func main() {
	i18n.MustLoadTranslationFile("../goi18n/testdata/expected/en-us.all.json")

	T, _ := i18n.Tfunc("en-US")
	tmpl.Funcs(map[string]interface{}{
		"T": T,
	})

	tmpl.Execute(os.Stdout, map[string]interface{}{
		"Person":    "Bob",
		"Timeframe": T("d_days", 1),
	})

	tmpl.Execute(os.Stdout, struct {
		Person    string
		Timeframe string
	}{
		Person:    "Bob",
		Timeframe: T("d_days", 1),
	})

}
Output:

Hello world
Hello Bob
You have 0 unread emails.
You have 1 unread email.
You have 2 unread emails.
Bob has 0 unread emails.
Bob has 1 unread email.
Bob has 2 unread emails.

Hello world
Hello Bob
You have 0 unread emails.
You have 1 unread email.
You have 2 unread emails.
Bob has 0 unread emails.
Bob has 1 unread email.
Bob has 2 unread emails.
Example (Yaml)
package main

import (
	"fmt"

	"github.com/nicksnyder/go-i18n/i18n"
)

func main() {
	i18n.MustLoadTranslationFile("../goi18n/testdata/en-us.yaml")

	T, _ := i18n.Tfunc("en-US")

	bobMap := map[string]interface{}{"Person": "Bob"}
	bobStruct := struct{ Person string }{Person: "Bob"}

	fmt.Println(T("program_greeting"))
	fmt.Println(T("person_greeting", bobMap))
	fmt.Println(T("person_greeting", bobStruct))

	fmt.Println(T("your_unread_email_count", 0))
	fmt.Println(T("your_unread_email_count", 1))
	fmt.Println(T("your_unread_email_count", 2))
	fmt.Println(T("my_height_in_meters", "1.7"))

	fmt.Println(T("person_unread_email_count", 0, bobMap))
	fmt.Println(T("person_unread_email_count", 1, bobMap))
	fmt.Println(T("person_unread_email_count", 2, bobMap))
	fmt.Println(T("person_unread_email_count", 0, bobStruct))
	fmt.Println(T("person_unread_email_count", 1, bobStruct))
	fmt.Println(T("person_unread_email_count", 2, bobStruct))

	fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
		"Person":    "Bob",
		"Timeframe": T("d_days", 0),
	}))
	fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
		"Person":    "Bob",
		"Timeframe": T("d_days", 1),
	}))
	fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
		"Person":    "Bob",
		"Timeframe": T("d_days", 2),
	}))

}
Output:

Hello world
Hello Bob
Hello Bob
You have 0 unread emails.
You have 1 unread email.
You have 2 unread emails.
I am 1.7 meters tall.
Bob has 0 unread emails.
Bob has 1 unread email.
Bob has 2 unread emails.
Bob has 0 unread emails.
Bob has 1 unread email.
Bob has 2 unread emails.
Bob has 3 unread emails in the past 0 days.
Bob has 3 unread emails in the past 1 day.
Bob has 3 unread emails in the past 2 days.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddTranslation

func AddTranslation(lang *language.Language, translations ...translation.Translation)

AddTranslation adds translations for a language.

It is useful if your translations are in a format not supported by LoadTranslationFile.

func LanguageTags added in v1.3.0

func LanguageTags() []string

LanguageTags returns the tags of all languages that have been added.

func LanguageTranslationIDs added in v1.3.0

func LanguageTranslationIDs(languageTag string) []string

LanguageTranslationIDs returns the ids of all translations that have been added for a given language.

func LoadTranslationFile

func LoadTranslationFile(filename string) error

LoadTranslationFile loads the translations from filename into memory.

The language that the translations are associated with is parsed from the filename (e.g. en-US.json).

Generally you should load translation files once during your program's initialization.

func MustLoadTranslationFile

func MustLoadTranslationFile(filename string)

MustLoadTranslationFile is similar to LoadTranslationFile except it panics if an error happens.

func ParseTranslationFileBytes

func ParseTranslationFileBytes(filename string, buf []byte) error

ParseTranslationFileBytes is similar to LoadTranslationFile except it parses the bytes in buf.

It is useful for parsing translation files embedded with go-bindata.

Types

type TranslateFunc

type TranslateFunc func(translationID string, args ...interface{}) string

TranslateFunc returns the translation of the string identified by translationID.

If there is no translation for translationID, then the translationID itself is returned. This makes it easy to identify missing translations in your app.

If translationID is a non-plural form, then the first variadic argument may be a map[string]interface{} or struct that contains template data.

If translationID is a plural form, the function accepts two parameter signatures 1. T(count int, data struct{}) The first variadic argument must be an integer type (int, int8, int16, int32, int64) or a float formatted as a string (e.g. "123.45"). The second variadic argument may be a map[string]interface{} or struct{} that contains template data. 2. T(data struct{}) data must be a struct{} or map[string]interface{} that contains a Count field and the template data, Count field must be an integer type (int, int8, int16, int32, int64) or a float formatted as a string (e.g. "123.45").

func IdentityTfunc

func IdentityTfunc() TranslateFunc

IdentityTfunc returns a TranslateFunc that always returns the translationID passed to it.

It is a useful placeholder when parsing a text/template or html/template before the actual Tfunc is available.

func MustTfunc

func MustTfunc(languageSource string, languageSources ...string) TranslateFunc

MustTfunc is similar to Tfunc except it panics if an error happens.

func MustTfuncAndLanguage added in v1.1.0

func MustTfuncAndLanguage(languageSource string, languageSources ...string) (TranslateFunc, *language.Language)

MustTfuncAndLanguage is similar to TfuncAndLanguage except it panics if an error happens.

func Tfunc

func Tfunc(languageSource string, languageSources ...string) (TranslateFunc, error)

Tfunc returns a TranslateFunc that will be bound to the first language which has a non-zero number of translations.

It can parse languages from Accept-Language headers (RFC 2616).

func TfuncAndLanguage added in v1.1.0

func TfuncAndLanguage(languageSource string, languageSources ...string) (TranslateFunc, *language.Language, error)

TfuncAndLanguage is similar to Tfunc except it also returns the language which TranslateFunc is bound to.

Directories

Path Synopsis
Package bundle manages translations for multiple languages.
Package bundle manages translations for multiple languages.
Package language defines languages that implement CLDR pluralization.
Package language defines languages that implement CLDR pluralization.
Package translation defines the interface for a translation.
Package translation defines the interface for a translation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL