159 lines
6.7 KiB
Go
159 lines
6.7 KiB
Go
|
// 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.
|
||
|
package i18n
|
||
|
|
||
|
import (
|
||
|
"github.com/nicksnyder/go-i18n/i18n/bundle"
|
||
|
"github.com/nicksnyder/go-i18n/i18n/language"
|
||
|
"github.com/nicksnyder/go-i18n/i18n/translation"
|
||
|
)
|
||
|
|
||
|
// 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").
|
||
|
type TranslateFunc func(translationID string, args ...interface{}) string
|
||
|
|
||
|
// 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 IdentityTfunc() TranslateFunc {
|
||
|
return func(translationID string, args ...interface{}) string {
|
||
|
return translationID
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var defaultBundle = bundle.New()
|
||
|
|
||
|
// MustLoadTranslationFile is similar to LoadTranslationFile
|
||
|
// except it panics if an error happens.
|
||
|
func MustLoadTranslationFile(filename string) {
|
||
|
defaultBundle.MustLoadTranslationFile(filename)
|
||
|
}
|
||
|
|
||
|
// 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 LoadTranslationFile(filename string) error {
|
||
|
return defaultBundle.LoadTranslationFile(filename)
|
||
|
}
|
||
|
|
||
|
// ParseTranslationFileBytes is similar to LoadTranslationFile except it parses the bytes in buf.
|
||
|
//
|
||
|
// It is useful for parsing translation files embedded with go-bindata.
|
||
|
func ParseTranslationFileBytes(filename string, buf []byte) error {
|
||
|
return defaultBundle.ParseTranslationFileBytes(filename, buf)
|
||
|
}
|
||
|
|
||
|
// AddTranslation adds translations for a language.
|
||
|
//
|
||
|
// It is useful if your translations are in a format not supported by LoadTranslationFile.
|
||
|
func AddTranslation(lang *language.Language, translations ...translation.Translation) {
|
||
|
defaultBundle.AddTranslation(lang, translations...)
|
||
|
}
|
||
|
|
||
|
// LanguageTags returns the tags of all languages that have been added.
|
||
|
func LanguageTags() []string {
|
||
|
return defaultBundle.LanguageTags()
|
||
|
}
|
||
|
|
||
|
// LanguageTranslationIDs returns the ids of all translations that have been added for a given language.
|
||
|
func LanguageTranslationIDs(languageTag string) []string {
|
||
|
return defaultBundle.LanguageTranslationIDs(languageTag)
|
||
|
}
|
||
|
|
||
|
// MustTfunc is similar to Tfunc except it panics if an error happens.
|
||
|
func MustTfunc(languageSource string, languageSources ...string) TranslateFunc {
|
||
|
return TranslateFunc(defaultBundle.MustTfunc(languageSource, languageSources...))
|
||
|
}
|
||
|
|
||
|
// 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 Tfunc(languageSource string, languageSources ...string) (TranslateFunc, error) {
|
||
|
tfunc, err := defaultBundle.Tfunc(languageSource, languageSources...)
|
||
|
return TranslateFunc(tfunc), err
|
||
|
}
|
||
|
|
||
|
// MustTfuncAndLanguage is similar to TfuncAndLanguage except it panics if an error happens.
|
||
|
func MustTfuncAndLanguage(languageSource string, languageSources ...string) (TranslateFunc, *language.Language) {
|
||
|
tfunc, lang := defaultBundle.MustTfuncAndLanguage(languageSource, languageSources...)
|
||
|
return TranslateFunc(tfunc), lang
|
||
|
}
|
||
|
|
||
|
// TfuncAndLanguage is similar to Tfunc except it also returns the language which TranslateFunc is bound to.
|
||
|
func TfuncAndLanguage(languageSource string, languageSources ...string) (TranslateFunc, *language.Language, error) {
|
||
|
tfunc, lang, err := defaultBundle.TfuncAndLanguage(languageSource, languageSources...)
|
||
|
return TranslateFunc(tfunc), lang, err
|
||
|
}
|