universal_translator.go raw

   1  package ut
   2  
   3  import (
   4  	"strings"
   5  
   6  	"github.com/go-playground/locales"
   7  )
   8  
   9  // UniversalTranslator holds all locale & translation data
  10  type UniversalTranslator struct {
  11  	translators map[string]Translator
  12  	fallback    Translator
  13  }
  14  
  15  // New returns a new UniversalTranslator instance set with
  16  // the fallback locale and locales it should support
  17  func New(fallback locales.Translator, supportedLocales ...locales.Translator) *UniversalTranslator {
  18  
  19  	t := &UniversalTranslator{
  20  		translators: make(map[string]Translator),
  21  	}
  22  
  23  	for _, v := range supportedLocales {
  24  
  25  		trans := newTranslator(v)
  26  		t.translators[strings.ToLower(trans.Locale())] = trans
  27  
  28  		if fallback.Locale() == v.Locale() {
  29  			t.fallback = trans
  30  		}
  31  	}
  32  
  33  	if t.fallback == nil && fallback != nil {
  34  		t.fallback = newTranslator(fallback)
  35  	}
  36  
  37  	return t
  38  }
  39  
  40  // FindTranslator trys to find a Translator based on an array of locales
  41  // and returns the first one it can find, otherwise returns the
  42  // fallback translator.
  43  func (t *UniversalTranslator) FindTranslator(locales ...string) (trans Translator, found bool) {
  44  
  45  	for _, locale := range locales {
  46  
  47  		if trans, found = t.translators[strings.ToLower(locale)]; found {
  48  			return
  49  		}
  50  	}
  51  
  52  	return t.fallback, false
  53  }
  54  
  55  // GetTranslator returns the specified translator for the given locale,
  56  // or fallback if not found
  57  func (t *UniversalTranslator) GetTranslator(locale string) (trans Translator, found bool) {
  58  
  59  	if trans, found = t.translators[strings.ToLower(locale)]; found {
  60  		return
  61  	}
  62  
  63  	return t.fallback, false
  64  }
  65  
  66  // GetFallback returns the fallback locale
  67  func (t *UniversalTranslator) GetFallback() Translator {
  68  	return t.fallback
  69  }
  70  
  71  // AddTranslator adds the supplied translator, if it already exists the override param
  72  // will be checked and if false an error will be returned, otherwise the translator will be
  73  // overridden; if the fallback matches the supplied translator it will be overridden as well
  74  // NOTE: this is normally only used when translator is embedded within a library
  75  func (t *UniversalTranslator) AddTranslator(translator locales.Translator, override bool) error {
  76  
  77  	lc := strings.ToLower(translator.Locale())
  78  	_, ok := t.translators[lc]
  79  	if ok && !override {
  80  		return &ErrExistingTranslator{locale: translator.Locale()}
  81  	}
  82  
  83  	trans := newTranslator(translator)
  84  
  85  	if t.fallback.Locale() == translator.Locale() {
  86  
  87  		// because it's optional to have a fallback, I don't impose that limitation
  88  		// don't know why you wouldn't but...
  89  		if !override {
  90  			return &ErrExistingTranslator{locale: translator.Locale()}
  91  		}
  92  
  93  		t.fallback = trans
  94  	}
  95  
  96  	t.translators[lc] = trans
  97  
  98  	return nil
  99  }
 100  
 101  // VerifyTranslations runs through all locales and identifies any issues
 102  // eg. missing plural rules for a locale
 103  func (t *UniversalTranslator) VerifyTranslations() (err error) {
 104  
 105  	for _, trans := range t.translators {
 106  		err = trans.VerifyTranslations()
 107  		if err != nil {
 108  			return
 109  		}
 110  	}
 111  
 112  	return
 113  }
 114