mirror of
https://github.com/kataras/iris.git
synced 2026-01-09 04:51:56 +00:00
New: i18n pluralization and variables support and more...
fixes: #1649, #1648, #1641, #1650 relative to: #1597
This commit is contained in:
149
i18n/internal/catalog.go
Normal file
149
i18n/internal/catalog.go
Normal file
@@ -0,0 +1,149 @@
|
||||
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"
|
||||
)
|
||||
|
||||
// MessageFunc is the function type to modify the behavior when a key or language was not found.
|
||||
// All language inputs fallback to the default locale if not matched.
|
||||
// This is why this signature accepts both input and matched languages, so caller
|
||||
// can provide better messages.
|
||||
//
|
||||
// The first parameter is set to the client real input of the language,
|
||||
// the second one is set to the matched language (default one if input wasn't matched)
|
||||
// and the third and forth are the translation format/key and its optional arguments.
|
||||
//
|
||||
// Note: we don't accept the Context here because Tr method and template func {{ tr }}
|
||||
// have no direct access to it.
|
||||
type MessageFunc func(langInput, langMatched, key string, args ...interface{}) string
|
||||
|
||||
// Catalog holds the locales and the variables message storage.
|
||||
type Catalog struct {
|
||||
builder *catalog.Builder
|
||||
Locales []*Locale
|
||||
}
|
||||
|
||||
// The Options of the Catalog and its Locales.
|
||||
type Options struct {
|
||||
// Left delimiter for template messages.
|
||||
Left string
|
||||
// Right delimeter for template messages.
|
||||
Right string
|
||||
// Enable strict mode.
|
||||
Strict bool
|
||||
// Optional functions for template messages per locale.
|
||||
Funcs func(context.Locale) template.FuncMap
|
||||
// Optional function to be called when no message was found.
|
||||
DefaultMessageFunc MessageFunc
|
||||
// Customize the overall behavior of the plurazation feature.
|
||||
PluralFormDecoder PluralFormDecoder
|
||||
}
|
||||
|
||||
// NewCatalog returns a new Catalog based on the registered languages and the loader options.
|
||||
func NewCatalog(languages []language.Tag, opts Options) (*Catalog, error) { // ordered languages, the first should be the default one.
|
||||
if len(languages) == 0 {
|
||||
return nil, fmt.Errorf("catalog: empty languages")
|
||||
}
|
||||
|
||||
if opts.Left == "" {
|
||||
opts.Left = "{{"
|
||||
}
|
||||
|
||||
if opts.Right == "" {
|
||||
opts.Right = "}}"
|
||||
}
|
||||
|
||||
if opts.PluralFormDecoder == nil {
|
||||
opts.PluralFormDecoder = DefaultPluralFormDecoder
|
||||
}
|
||||
|
||||
builder := catalog.NewBuilder(catalog.Fallback(languages[0]))
|
||||
|
||||
locales := make([]*Locale, 0, len(languages))
|
||||
for idx, tag := range languages {
|
||||
locale := &Locale{
|
||||
tag: tag,
|
||||
index: idx,
|
||||
ID: tag.String(),
|
||||
Options: opts,
|
||||
Printer: message.NewPrinter(tag, message.Catalog(builder)),
|
||||
Messages: make(map[string]Renderer),
|
||||
}
|
||||
locale.FuncMap = getFuncs(locale)
|
||||
|
||||
locales = append(locales, locale)
|
||||
}
|
||||
|
||||
c := &Catalog{
|
||||
builder: builder,
|
||||
Locales: locales,
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Set sets a simple translation message.
|
||||
func (c *Catalog) Set(tag language.Tag, key string, msgs ...catalog.Message) error {
|
||||
// fmt.Printf("Catalog.Set[%s] %s:\n", tag.String(), key)
|
||||
// for _, msg := range msgs {
|
||||
// fmt.Printf("%#+v\n", msg)
|
||||
// }
|
||||
return c.builder.Set(tag, key, msgs...)
|
||||
}
|
||||
|
||||
// Store stores the a map of values to the locale derives from the given "langIndex".
|
||||
func (c *Catalog) Store(langIndex int, kv Map) error {
|
||||
loc := c.getLocale(langIndex)
|
||||
if loc == nil {
|
||||
return fmt.Errorf("expected language index to be lower or equal than %d but got %d", len(c.Locales), langIndex)
|
||||
}
|
||||
return loc.Load(c, kv)
|
||||
}
|
||||
|
||||
/* Localizer interface. */
|
||||
|
||||
// SetDefault changes the default language based on the "index".
|
||||
// See `I18n#SetDefault` method for more.
|
||||
func (c *Catalog) SetDefault(index int) bool {
|
||||
if index < 0 {
|
||||
index = 0
|
||||
}
|
||||
|
||||
if maxIdx := len(c.Locales) - 1; index > maxIdx {
|
||||
return false
|
||||
}
|
||||
|
||||
// callers should protect with mutex if called at serve-time.
|
||||
loc := c.Locales[index]
|
||||
loc.index = 0
|
||||
f := c.Locales[0]
|
||||
c.Locales[0] = loc
|
||||
f.index = index
|
||||
c.Locales[index] = f
|
||||
return true
|
||||
}
|
||||
|
||||
// GetLocale returns a valid `Locale` based on the "index".
|
||||
func (c *Catalog) GetLocale(index int) context.Locale {
|
||||
return c.getLocale(index)
|
||||
}
|
||||
|
||||
func (c *Catalog) getLocale(index int) *Locale {
|
||||
if index < 0 {
|
||||
index = 0
|
||||
}
|
||||
|
||||
if maxIdx := len(c.Locales) - 1; index > maxIdx {
|
||||
// panic("expected language index to be lower or equal than %d but got %d", maxIdx, langIndex)
|
||||
return nil
|
||||
}
|
||||
|
||||
loc := c.Locales[index]
|
||||
return loc
|
||||
}
|
||||
Reference in New Issue
Block a user