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  }