summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/nicksnyder/go-i18n/v2/i18n/localizer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/nicksnyder/go-i18n/v2/i18n/localizer.go')
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/v2/i18n/localizer.go198
1 files changed, 198 insertions, 0 deletions
diff --git a/vendor/github.com/nicksnyder/go-i18n/v2/i18n/localizer.go b/vendor/github.com/nicksnyder/go-i18n/v2/i18n/localizer.go
new file mode 100644
index 000000000..f9d516fa6
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/v2/i18n/localizer.go
@@ -0,0 +1,198 @@
+package i18n
+
+import (
+ "fmt"
+
+ "text/template"
+
+ "github.com/nicksnyder/go-i18n/v2/internal"
+ "github.com/nicksnyder/go-i18n/v2/internal/plural"
+ "golang.org/x/text/language"
+)
+
+// Localizer provides Localize and MustLocalize methods that return localized messages.
+type Localizer struct {
+ // bundle contains the messages that can be returned by the Localizer.
+ bundle *Bundle
+
+ // tags is the list of language tags that the Localizer checks
+ // in order when localizing a message.
+ tags []language.Tag
+}
+
+// NewLocalizer returns a new Localizer that looks up messages
+// in the bundle according to the language preferences in langs.
+// It can parse Accept-Language headers as defined in http://www.ietf.org/rfc/rfc2616.txt.
+func NewLocalizer(bundle *Bundle, langs ...string) *Localizer {
+ bundle.init()
+ return &Localizer{
+ bundle: bundle,
+ tags: parseTags(langs),
+ }
+}
+
+func parseTags(langs []string) []language.Tag {
+ tags := []language.Tag{}
+ for _, lang := range langs {
+ t, _, err := language.ParseAcceptLanguage(lang)
+ if err != nil {
+ continue
+ }
+ tags = append(tags, t...)
+ }
+ return tags
+}
+
+// LocalizeConfig configures a call to the Localize method on Localizer.
+type LocalizeConfig struct {
+ // MessageID is the id of the message to lookup.
+ // This field is ignored if DefaultMessage is set.
+ MessageID string
+
+ // TemplateData is the data passed when executing the message's template.
+ // If TemplateData is nil and PluralCount is not nil, then the message template
+ // will be executed with data that contains the plural count.
+ TemplateData interface{}
+
+ // PluralCount determines which plural form of the message is used.
+ PluralCount interface{}
+
+ // DefaultMessage is used if the message is not found in any message files.
+ DefaultMessage *Message
+
+ // Funcs is used to extend the Go template engines built in functions
+ Funcs template.FuncMap
+}
+
+type invalidPluralCountErr struct {
+ messageID string
+ pluralCount interface{}
+ err error
+}
+
+func (e *invalidPluralCountErr) Error() string {
+ return fmt.Sprintf("invalid plural count %#v for message id %q: %s", e.pluralCount, e.messageID, e.err)
+}
+
+type messageNotFoundErr struct {
+ messageID string
+}
+
+func (e *messageNotFoundErr) Error() string {
+ return fmt.Sprintf("message %q not found", e.messageID)
+}
+
+type pluralizeErr struct {
+ messageID string
+ tag language.Tag
+}
+
+func (e *pluralizeErr) Error() string {
+ return fmt.Sprintf("unable to pluralize %q because there no plural rule for %q", e.messageID, e.tag)
+}
+
+// Localize returns a localized message.
+func (l *Localizer) Localize(lc *LocalizeConfig) (string, error) {
+ messageID := lc.MessageID
+ if lc.DefaultMessage != nil {
+ messageID = lc.DefaultMessage.ID
+ }
+
+ var operands *plural.Operands
+ templateData := lc.TemplateData
+ if lc.PluralCount != nil {
+ var err error
+ operands, err = plural.NewOperands(lc.PluralCount)
+ if err != nil {
+ return "", &invalidPluralCountErr{messageID: messageID, pluralCount: lc.PluralCount, err: err}
+ }
+ if templateData == nil {
+ templateData = map[string]interface{}{
+ "PluralCount": lc.PluralCount,
+ }
+ }
+ }
+ tag, template := l.getTemplate(messageID, lc.DefaultMessage)
+ if template == nil {
+ return "", &messageNotFoundErr{messageID: messageID}
+ }
+ pluralForm := l.pluralForm(tag, operands)
+ if pluralForm == plural.Invalid {
+ return "", &pluralizeErr{messageID: messageID, tag: tag}
+ }
+ return template.Execute(pluralForm, templateData, lc.Funcs)
+}
+
+func (l *Localizer) getTemplate(id string, defaultMessage *Message) (language.Tag, *internal.MessageTemplate) {
+ // Fast path.
+ // Optimistically assume this message id is defined in each language.
+ fastTag, template := l.matchTemplate(id, l.bundle.matcher, l.bundle.tags)
+ if template != nil {
+ return fastTag, template
+ }
+ if fastTag == l.bundle.DefaultLanguage {
+ if defaultMessage == nil {
+ return fastTag, nil
+ }
+ return fastTag, internal.NewMessageTemplate(defaultMessage)
+ }
+ if len(l.bundle.tags) > 1 {
+ // Slow path.
+ // We didn't find a translation for the tag suggested by the default matcher
+ // so we need to create a new matcher that contains only the tags in the bundle
+ // that have this message.
+ foundTags := make([]language.Tag, 0, len(l.bundle.messageTemplates))
+ if l.bundle.DefaultLanguage != fastTag {
+ foundTags = append(foundTags, l.bundle.DefaultLanguage)
+ }
+ for t, templates := range l.bundle.messageTemplates {
+ if t == fastTag {
+ // We already tried this tag in the fast path
+ continue
+ }
+ template := templates[id]
+ if template == nil || template.Other == "" {
+ continue
+ }
+ foundTags = append(foundTags, t)
+ }
+ tag, template := l.matchTemplate(id, language.NewMatcher(foundTags), foundTags)
+ if template != nil {
+ return tag, template
+ }
+ }
+ if defaultMessage == nil {
+ return l.bundle.DefaultLanguage, nil
+ }
+ return l.bundle.DefaultLanguage, internal.NewMessageTemplate(defaultMessage)
+}
+
+func (l *Localizer) matchTemplate(id string, matcher language.Matcher, tags []language.Tag) (language.Tag, *internal.MessageTemplate) {
+ _, i, _ := matcher.Match(l.tags...)
+ tag := tags[i]
+ templates := l.bundle.messageTemplates[tag]
+ if templates != nil && templates[id] != nil {
+ return tag, templates[id]
+ }
+ return tag, nil
+}
+
+func (l *Localizer) pluralForm(tag language.Tag, operands *plural.Operands) plural.Form {
+ if operands == nil {
+ return plural.Other
+ }
+ pluralRule := l.bundle.pluralRules.Rule(tag)
+ if pluralRule == nil {
+ return plural.Invalid
+ }
+ return pluralRule.PluralFormFunc(operands)
+}
+
+// MustLocalize is similar to Localize, except it panics if an error happens.
+func (l *Localizer) MustLocalize(lc *LocalizeConfig) string {
+ localized, err := l.Localize(lc)
+ if err != nil {
+ panic(err)
+ }
+ return localized
+}