add LoadKV method on Iris.Application.I18N instance

This commit is contained in:
Gerasimos (Makis) Maropoulos 2023-03-18 15:43:18 +02:00
parent 41326d4ddd
commit 0954986a66
No known key found for this signature in database
GPG Key ID: B9839E9CD30B7B6B
9 changed files with 108 additions and 11 deletions

View File

@ -23,6 +23,8 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
Change applies to `master` branch.
- Add `LoadKV` method on `Iris.Application.I18N` instance. It should be used when no locale files are available. It loads locales via pure Go Map (or database decoded values).
- Remove [ace](https://github.com/eknkc/amber) template parser support, as it was discontinued by its author more than five years ago.
# Sa, 11 March 2023 | v12.2.0

View File

@ -13,6 +13,16 @@ var embeddedFS embed.FS
func main() {
app := newApp()
// http://localhost:8080
// http://localhost:8080?lang=el
// http://localhost:8080?lang=el
// http://localhost:8080?lang=el-GR
// http://localhost:8080?lang=en
// http://localhost:8080?lang=en-US
//
// http://localhost:8080/title
// http://localhost:8080/title?lang=el-GR
// ...
app.Listen(":8080")
}
@ -30,11 +40,14 @@ func newApp() *iris.Application {
// Instead of:
// err := app.I18n.Load("./locales/*/*.ini", "en-US", "el-GR")
// Apply the below in order to build with embedded locales inside your executable binary.
// apply the below in order to build with embedded locales inside your executable binary.
err := app.I18n.LoadFS(embeddedFS, "./embedded/locales/*/*.ini", "en-US", "el-GR")
if err != nil {
panic(err)
}
} // OR to load all languages by filename:
// app.I18n.LoadFS(embeddedFS, "./embedded/locales/*/*.ini")
// Then set the default language using:
// app.I18n.SetDefault("en-US")
app.Get("/", func(ctx iris.Context) {
text := ctx.Tr("forms.register") // en-US: prints "Become a MEMBER".

View File

@ -141,8 +141,8 @@ func (i *I18n) LoadAssets(assetNames func() []string, asset func(string) ([]byte
return i.Reset(Assets(assetNames, asset, i.Loader), languages...)
}
// LoadFS is a method shortcut to load files using `embed.FS` or `fs.FS` or
// `http.FileSystem` or `string` (local directory).
// LoadFS is a method shortcut to load files using
// an `embed.FS` or `fs.FS` or `http.FileSystem` value.
// The "pattern" is a classic glob pattern.
//
// See `New` and `FS` package-level functions for more.
@ -156,6 +156,13 @@ func (i *I18n) LoadFS(fileSystem fs.FS, pattern string, languages ...string) err
return i.Reset(loader, languages...)
}
// LoadKV is a method shortcut to load locales from a map of specified languages.
// See `KV` package-level function for more.
func (i *I18n) LoadKV(langMap LangMap, languages ...string) error {
loader := KV(langMap, i.Loader)
return i.Reset(loader, languages...)
}
// Reset sets the locales loader and languages.
// It is not meant to be used by users unless
// a custom `Loader` must be used instead of the default one.
@ -300,6 +307,16 @@ func parsePath(m *Matcher, path string) int {
return -1
}
func parseLanguageName(m *Matcher, name string) int {
if t, err := language.Parse(name); err == nil {
if _, index, conf := m.MatchOrAdd(t); conf > language.Low {
return index
}
}
return -1
}
func reverseStrings(s []string) []string {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]

View File

@ -5,6 +5,7 @@ import (
"text/template"
"github.com/kataras/iris/v12/context"
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/message/catalog"

View File

@ -73,6 +73,70 @@ func FS(fileSystem fs.FS, pattern string, options LoaderConfig) (Loader, error)
return load(assetNames, assetFunc, options), nil
}
// LangMap key as language (e.g. "el-GR") and value as a map of key-value pairs (e.g. "hello": "Γειά").
type LangMap = map[string]map[string]interface{}
// KV is a loader which accepts a map of language(key) and the available key-value pairs.
// Example Code:
//
// m := i18n.LangMap{
// "en-US": map[string]interface{}{
// "hello": "Hello",
// },
// "el-GR": map[string]interface{}{
// "hello": "Γειά",
// },
// }
//
// app := iris.New()
// [...]
// app.I18N.LoadKV(m)
// app.I18N.SetDefault("en-US")
func KV(langMap LangMap, opts ...LoaderConfig) Loader {
return func(m *Matcher) (Localizer, error) {
options := DefaultLoaderConfig
if len(opts) > 0 {
options = opts[0]
}
languageIndexes := make([]int, 0, len(langMap))
keyValuesMulti := make([]map[string]interface{}, 0, len(langMap))
for languageName, pairs := range langMap {
langIndex := parseLanguageName(m, languageName) // matches and adds the language tag to m.Languages.
languageIndexes = append(languageIndexes, langIndex)
keyValuesMulti = append(keyValuesMulti, pairs)
}
cat, err := internal.NewCatalog(m.Languages, options)
if err != nil {
return nil, err
}
for _, langIndex := range languageIndexes {
if langIndex == -1 {
// If loader has more languages than defined for use in New function,
// e.g. when New(KV(m), "en-US") contains el-GR and en-US but only "en-US" passed.
continue
}
kv := keyValuesMulti[langIndex]
err := cat.Store(langIndex, kv)
if err != nil {
return nil, err
}
}
if n := len(cat.Locales); n == 0 {
return nil, fmt.Errorf("locales not found in map")
} else if options.Strict && n < len(m.Languages) {
return nil, fmt.Errorf("locales expected to be %d but %d parsed", len(m.Languages), n)
}
return cat, nil
}
}
// DefaultLoaderConfig represents the default loader configuration.
var DefaultLoaderConfig = LoaderConfig{
Left: "{{",
@ -88,7 +152,7 @@ var DefaultLoaderConfig = LoaderConfig{
// and any Loader options.
// It returns a valid `Loader` which loads and maps the locale files.
//
// See `Glob`, `Assets` and `LoaderConfig` too.
// See `FS`, `Glob`, `Assets` and `LoaderConfig` too.
func load(assetNames []string, asset func(string) ([]byte, error), options LoaderConfig) Loader {
return func(m *Matcher) (Localizer, error) {
languageFiles, err := m.ParseLanguageFiles(assetNames)