taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

catalog.go (4077B)


      1 package internal
      2 
      3 import (
      4 	"fmt"
      5 	"text/template"
      6 
      7 	"golang.org/x/text/language"
      8 	"golang.org/x/text/message"
      9 	"golang.org/x/text/message/catalog"
     10 )
     11 
     12 // MessageFunc is the function type to modify the behavior when a key or language was not found.
     13 // All language inputs fallback to the default locale if not matched.
     14 // This is why this signature accepts both input and matched languages, so caller
     15 // can provide better messages.
     16 //
     17 // The first parameter is set to the client real input of the language,
     18 // the second one is set to the matched language (default one if input wasn't matched)
     19 // and the third and forth are the translation format/key and its optional arguments.
     20 //
     21 // Note: we don't accept the Context here because Tr method and template func {{ tr }}
     22 // have no direct access to it.
     23 type MessageFunc func(langInput, langMatched, key string, args ...interface{}) string
     24 
     25 // Catalog holds the locales and the variables message storage.
     26 type Catalog struct {
     27 	builder *catalog.Builder
     28 	Locales []*Locale
     29 }
     30 
     31 // The Options of the Catalog and its Locales.
     32 type Options struct {
     33 	// Left delimiter for template messages.
     34 	Left string
     35 	// Right delimeter for template messages.
     36 	Right string
     37 	// Enable strict mode.
     38 	Strict bool
     39 	// Optional functions for template messages per locale.
     40 	Funcs func(*Locale) template.FuncMap
     41 	// Optional function to be called when no message was found.
     42 	DefaultMessageFunc MessageFunc
     43 	// Customize the overall behavior of the plurazation feature.
     44 	PluralFormDecoder PluralFormDecoder
     45 }
     46 
     47 // NewCatalog returns a new Catalog based on the registered languages and the loader options.
     48 func NewCatalog(languages []language.Tag, opts Options) (*Catalog, error) { // ordered languages, the first should be the default one.
     49 	if len(languages) == 0 {
     50 		return nil, fmt.Errorf("catalog: empty languages")
     51 	}
     52 
     53 	if opts.Left == "" {
     54 		opts.Left = "{{"
     55 	}
     56 
     57 	if opts.Right == "" {
     58 		opts.Right = "}}"
     59 	}
     60 
     61 	if opts.PluralFormDecoder == nil {
     62 		opts.PluralFormDecoder = DefaultPluralFormDecoder
     63 	}
     64 
     65 	builder := catalog.NewBuilder(catalog.Fallback(languages[0]))
     66 
     67 	locales := make([]*Locale, 0, len(languages))
     68 	for idx, tag := range languages {
     69 		locale := &Locale{
     70 			tag:      tag,
     71 			index:    idx,
     72 			ID:       tag.String(),
     73 			Options:  opts,
     74 			Printer:  message.NewPrinter(tag, message.Catalog(builder)),
     75 			Messages: make(map[string]Renderer),
     76 		}
     77 		locale.FuncMap = getFuncs(locale)
     78 
     79 		locales = append(locales, locale)
     80 	}
     81 
     82 	c := &Catalog{
     83 		builder: builder,
     84 		Locales: locales,
     85 	}
     86 
     87 	return c, nil
     88 }
     89 
     90 // Set sets a simple translation message.
     91 func (c *Catalog) Set(tag language.Tag, key string, msgs ...catalog.Message) error {
     92 	// fmt.Printf("Catalog.Set[%s] %s:\n", tag.String(), key)
     93 	// for _, msg := range msgs {
     94 	// 	fmt.Printf("%#+v\n", msg)
     95 	// }
     96 	return c.builder.Set(tag, key, msgs...)
     97 }
     98 
     99 // Store stores the a map of values to the locale derives from the given "langIndex".
    100 func (c *Catalog) Store(langIndex int, kv Map) error {
    101 	loc := c.getLocale(langIndex)
    102 	if loc == nil {
    103 		return fmt.Errorf("expected language index to be lower or equal than %d but got %d", len(c.Locales), langIndex)
    104 	}
    105 	return loc.Load(c, kv)
    106 }
    107 
    108 /* Localizer interface. */
    109 
    110 // SetDefault changes the default language based on the "index".
    111 // See `I18n#SetDefault` method for more.
    112 func (c *Catalog) SetDefault(index int) bool {
    113 	if index < 0 {
    114 		index = 0
    115 	}
    116 
    117 	if maxIdx := len(c.Locales) - 1; index > maxIdx {
    118 		return false
    119 	}
    120 
    121 	// callers should protect with mutex if called at serve-time.
    122 	loc := c.Locales[index]
    123 	loc.index = 0
    124 	f := c.Locales[0]
    125 	c.Locales[0] = loc
    126 	f.index = index
    127 	c.Locales[index] = f
    128 	return true
    129 }
    130 
    131 // GetLocale returns a valid `Locale` based on the "index".
    132 func (c *Catalog) GetLocale(index int) *Locale {
    133 	return c.getLocale(index)
    134 }
    135 
    136 func (c *Catalog) getLocale(index int) *Locale {
    137 	if index < 0 {
    138 		index = 0
    139 	}
    140 
    141 	if maxIdx := len(c.Locales) - 1; index > maxIdx {
    142 		// panic("expected language index to be lower or equal than %d but got %d", maxIdx, langIndex)
    143 		return nil
    144 	}
    145 
    146 	loc := c.Locales[index]
    147 	return loc
    148 }