1package ut
2
3import (
4	"strings"
5
6	"github.com/go-playground/locales"
7)
8
9// UniversalTranslator holds all locale & translation data
10type 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
17func 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.
43func (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
57func (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
67func (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
75func (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
103func (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