github.com/gocaveman/caveman@v0.0.0-20191211162744-0ddf99dbdf6e/i18n/translator.go (about) 1 package i18n 2 3 import ( 4 "log" 5 "strings" 6 7 "github.com/gocaveman/caveman/webutil" 8 ) 9 10 // Translator translates text without knowledge of the target locale, it is provided in the call. 11 type Translator interface { 12 // Translate a string into the first locale found in the list. Note that the group 13 // and key are case sensitive but the locales are not. 14 // ErrNotFound must be returned if the key cannot be found in any of the locales given. 15 Translate(g, k string, locales ...string) (string, error) 16 } 17 18 // MapKey is the key for MapTranslator 19 type MapKey struct { 20 Group string 21 Key string 22 Locale string 23 } 24 25 // MapTranslator is a simple in-memory map Translator implementation. 26 type MapTranslator struct { 27 Values map[MapKey]string 28 } 29 30 // NewMapTranslator returns a new empty MapTranslator. 31 func NewMapTranslator() *MapTranslator { 32 return &MapTranslator{Values: make(map[MapKey]string)} 33 } 34 35 func MergeMapTranslators(mts ...*MapTranslator) *MapTranslator { 36 ret := NewMapTranslator() 37 for _, mt := range mts { 38 for k, v := range mt.Values { 39 ret.Values[k] = v 40 } 41 } 42 return ret 43 } 44 45 // SetEntry assigns a value by its group, key and locale. 46 func (mt *MapTranslator) SetEntry(g, k, l, v string) { 47 mt.Values[MapKey{Group: g, Key: k, Locale: strings.ToLower(l)}] = v 48 } 49 50 // GetEntry retrieves a value by its group, key and locale. Empty string if not there. 51 func (mt *MapTranslator) GetEntry(g, k, l string) string { 52 return mt.Values[MapKey{Group: g, Key: k, Locale: strings.ToLower(l)}] 53 } 54 55 // CheckEntry retrieves a value by its group, key and locale. Empty string if not there 56 // but also returns a bool as true if there or false if not. 57 func (mt *MapTranslator) CheckEntry(g, k, l string) (string, bool) { 58 ret, ok := mt.Values[MapKey{Group: g, Key: k, Locale: strings.ToLower(l)}] 59 return ret, ok 60 } 61 62 // Translate implements the Translator interface. 63 func (mt *MapTranslator) Translate(g, k string, locales ...string) (string, error) { 64 65 for _, l := range locales { 66 ret, ok := mt.CheckEntry(g, k, l) 67 if ok { 68 return ret, nil 69 } 70 } 71 72 return k, ErrNotFound 73 } 74 75 // NamedSequenceTranslator implements Translator using a NamedSequence of other translators 76 // to delegate to in sequence. If Debug is true it will produce detailed log output for every 77 // call to Translate and which item succeeded. 78 type NamedSequenceTranslator struct { 79 NamedSequence webutil.NamedSequence 80 Debug bool 81 } 82 83 func NewNamedSequenceTranslator(ns webutil.NamedSequence, debug bool) *NamedSequenceTranslator { 84 ns = ns.SortedCopy() 85 return &NamedSequenceTranslator{NamedSequence: ns, Debug: debug} 86 } 87 88 func (t *NamedSequenceTranslator) Translate(g, k string, locales ...string) (string, error) { 89 90 for _, nsi := range t.NamedSequence { 91 // TODO: look at optimizing this - if it's called a lot we might be able to squeeze some perf here 92 itemt := nsi.Value.(Translator) 93 ret, err := itemt.Translate(g, k, locales...) 94 if err == ErrNotFound { 95 continue 96 } 97 98 if t.Debug { 99 log.Printf("Translate(g=%q, k=%q, l=%q) returning (err=%v) for (sequence=%v, name=%q): %q", g, k, locales, err, nsi.Sequence, nsi.Name, ret) 100 } 101 102 return ret, err 103 } 104 105 if t.Debug { 106 log.Printf("Translate(g=%q, k=%q, l=%q) not found in named sequence", g, k, locales) 107 } 108 109 return k, ErrNotFound 110 }