10 "github.com/go-playground/locales"
11 "github.com/go-playground/locales/currency"
12 "github.com/go-playground/locales/en"
13 "github.com/go-playground/locales/fr"
14 "github.com/go-playground/pure"
15 "github.com/go-playground/pure/examples/middleware/logging-recovery"
16 "github.com/go-playground/universal-translator"
20 tmpls *template.Template
21 utrans *ut.UniversalTranslator
29 // Translator wraps ut.Translator in order to handle errors transparently
30 // it is totally optional but recommended as it can now be used directly in
31 // templates and nobody can add translations where they're not supposed to.
32 type Translator interface {
35 // creates the translation for the locale given the 'key' and params passed in.
36 // wraps ut.Translator.T to handle errors
37 T(key interface{}, params ...string) string
39 // creates the cardinal translation for the locale given the 'key', 'num' and 'digit' arguments
40 // and param passed in.
41 // wraps ut.Translator.C to handle errors
42 C(key interface{}, num float64, digits uint64, param string) string
44 // creates the ordinal translation for the locale given the 'key', 'num' and 'digit' arguments
45 // and param passed in.
46 // wraps ut.Translator.O to handle errors
47 O(key interface{}, num float64, digits uint64, param string) string
49 // creates the range translation for the locale given the 'key', 'num1', 'digit1', 'num2' and
50 // 'digit2' arguments and 'param1' and 'param2' passed in
51 // wraps ut.Translator.R to handle errors
52 R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) string
54 // Currency returns the type used by the given locale.
55 Currency() currency.Type
58 // implements Translator interface definition above.
59 type translator struct {
64 var _ Translator = (*translator)(nil)
66 func (t *translator) T(key interface{}, params ...string) string {
68 s, err := t.trans.T(key, params...)
70 log.Printf("issue translating key: '%v' error: '%s'", key, err)
76 func (t *translator) C(key interface{}, num float64, digits uint64, param string) string {
78 s, err := t.trans.C(key, num, digits, param)
80 log.Printf("issue translating cardinal key: '%v' error: '%s'", key, err)
86 func (t *translator) O(key interface{}, num float64, digits uint64, param string) string {
88 s, err := t.trans.C(key, num, digits, param)
90 log.Printf("issue translating ordinal key: '%v' error: '%s'", key, err)
96 func (t *translator) R(key interface{}, num1 float64, digits1 uint64, num2 float64, digits2 uint64, param1, param2 string) string {
98 s, err := t.trans.R(key, num1, digits1, num2, digits2, param1, param2)
100 log.Printf("issue translating range key: '%v' error: '%s'", key, err)
106 func (t *translator) Currency() currency.Type {
108 // choose your own locale. The reason it isn't mapped for you is because many
109 // countries have multiple currencies; it's up to you and you're application how
110 // and which currencies to use. I recommend adding a function it to to your custon translator
111 // interface like defined above.
125 utrans = ut.New(en, en, fr.New())
128 tmpls, _ = template.ParseFiles("home.tmpl")
131 r.Use(middleware.LoggingAndRecovery(true), translatorMiddleware)
134 log.Println("Running on Port :8080")
135 log.Println("Try me with URL http://localhost:8080/?locale=en")
136 log.Println("and then http://localhost:8080/?locale=fr")
137 http.ListenAndServe(":8080", r.Serve())
140 func home(w http.ResponseWriter, r *http.Request) {
142 // get locale translator ( could be wrapped into a helper function )
143 t := r.Context().Value(transKey).(Translator)
154 PositiveNum: 1234576.45,
155 NegativeNum: -35900394.34,
159 if err := tmpls.ExecuteTemplate(w, "home", s); err != nil {
164 func translatorMiddleware(next http.HandlerFunc) http.HandlerFunc {
166 return func(w http.ResponseWriter, r *http.Request) {
168 // there are many ways to check, this is just checking for query param &
169 // Accept-Language header but can be expanded to Cookie's etc....
171 params := r.URL.Query()
173 locale := params.Get("locale")
180 if t, found = utrans.GetTranslator(locale); found {
185 // get and parse the "Accept-Language" http header and return an array
186 t, _ = utrans.FindTranslator(pure.AcceptedLanguages(r)...)
188 // I would normally wrap ut.Translator with one with my own functions in order
189 // to handle errors and be able to use all functions from translator within the templates.
190 r = r.WithContext(context.WithValue(r.Context(), transKey, &translator{trans: t, Translator: t.(locales.Translator)}))
198 err := utrans.Import(ut.FormatJSON, "translations")
203 err = utrans.VerifyTranslations()