package internal import ( "fmt" "text/template" "github.com/kataras/iris/v12/context" "golang.org/x/text/language" "golang.org/x/text/message" "golang.org/x/text/message/catalog" ) // Locale is the default Locale. // Created by Catalog. // One Locale maps to one registered and loaded language. // Stores the translation variables and most importantly, the Messages (keys and their renderers). type Locale struct { // The index of the language registered by the user, starting from zero. index int tag language.Tag // ID is the tag.String(). ID string // Options given by the Catalog Options Options // Fields set by Catalog. FuncMap template.FuncMap Printer *message.Printer // // Fields set by this Load method. Messages map[string]Renderer Vars []Var // shared per-locale variables. } // Ensures that the Locale completes the context.Locale interface. var _ context.Locale = (*Locale)(nil) // Load sets the translation messages based on the Catalog's key values. func (loc *Locale) Load(c *Catalog, keyValues Map) error { return loc.setMap(c, "", keyValues) } func (loc *Locale) setMap(c *Catalog, key string, keyValues Map) error { // unique locals or the shared ones. isRoot := key == "" vars := getVars(loc, VarsKey, keyValues) if isRoot { loc.Vars = vars } else { vars = removeVarsDuplicates(append(vars, loc.Vars...)) } for k, v := range keyValues { form, isPlural := loc.Options.PluralFormDecoder(loc, k) if isPlural { k = key } else if !isRoot { k = key + "." + k } switch value := v.(type) { case string: if err := loc.setString(c, k, value, vars, form); err != nil { return fmt.Errorf("%s:%s parse string: %w", loc.ID, key, err) } case Map: // fmt.Printf("%s is map\n", fullKey) if err := loc.setMap(c, k, value); err != nil { return fmt.Errorf("%s:%s parse map: %w", loc.ID, key, err) } default: return fmt.Errorf("%s:%s unexpected type of %T as value", loc.ID, key, value) } } return nil } func (loc *Locale) setString(c *Catalog, key string, value string, vars []Var, form PluralForm) (err error) { isPlural := form != nil // fmt.Printf("setStringVars: %s=%s\n", key, value) msgs, vars := makeSelectfVars(value, vars, isPlural) msgs = append(msgs, catalog.String(value)) m := &Message{ Locale: loc, Key: key, Value: value, Vars: vars, Plural: isPlural, } var ( renderer, pluralRenderer Renderer = m, m ) if stringIsTemplateValue(value, loc.Options.Left, loc.Options.Right) { t, err := NewTemplate(c, m) if err != nil { return err } pluralRenderer = t if !isPlural { renderer = t } } else { if isPlural { pluralRenderer, err = newIndependentPluralRenderer(c, loc, key, msgs...) if err != nil { return fmt.Errorf("<%s = %s>: %w", key, value, err) } } else if err = c.Set(loc.tag, key, msgs...); err != nil { // let's make normal keys direct fire: // renderer = &simpleRenderer{key, loc.Printer} return fmt.Errorf("<%s = %s>: %w", key, value, err) } } if isPlural { if existingMsg, ok := loc.Messages[key]; ok { if msg, ok := existingMsg.(*Message); ok { msg.AddPlural(form, pluralRenderer) return } } m.AddPlural(form, pluralRenderer) } loc.Messages[key] = renderer return } /* context.Locale interface */ // Index returns the current locale index from the languages list. func (loc *Locale) Index() int { return loc.index } // Tag returns the full language Tag attached to this Locale, // it should be unique across different Locales. func (loc *Locale) Tag() *language.Tag { return &loc.tag } // Language should return the exact languagecode of this `Locale` //that the user provided on `New` function. // // Same as `Tag().String()` but it's static. func (loc *Locale) Language() string { return loc.ID } // GetMessage should return translated text based on the given "key". func (loc *Locale) GetMessage(key string, args ...interface{}) string { if msg, ok := loc.Messages[key]; ok { result, err := msg.Render(args...) if err != nil { result = err.Error() } return result } return "" }