mirror of
https://github.com/kataras/iris.git
synced 2025-03-21 11:16:28 +01:00
i18n: respect fallback language when Strict is false and no DefaultMessageFunc was provided
This commit is contained in:
parent
5b983800ec
commit
5017e3c986
|
@ -1254,14 +1254,8 @@ func (ctx *Context) GetLocale() Locale {
|
||||||
// See `GetLocale` too.
|
// See `GetLocale` too.
|
||||||
//
|
//
|
||||||
// Example: https://github.com/kataras/iris/tree/master/_examples/i18n
|
// Example: https://github.com/kataras/iris/tree/master/_examples/i18n
|
||||||
func (ctx *Context) Tr(message string, values ...interface{}) string {
|
func (ctx *Context) Tr(key string, args ...interface{}) string {
|
||||||
if locale := ctx.GetLocale(); locale != nil {
|
return ctx.app.I18nReadOnly().TrContext(ctx, key, args...)
|
||||||
return locale.GetMessageContext(ctx, message, values...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should never happen as the locale fallbacks to
|
|
||||||
// the default.
|
|
||||||
return message
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// +------------------------------------------------------------+
|
// +------------------------------------------------------------+
|
||||||
|
|
|
@ -7,7 +7,8 @@ import "golang.org/x/text/language"
|
||||||
type I18nReadOnly interface {
|
type I18nReadOnly interface {
|
||||||
Tags() []language.Tag
|
Tags() []language.Tag
|
||||||
GetLocale(ctx *Context) Locale
|
GetLocale(ctx *Context) Locale
|
||||||
Tr(lang string, format string, args ...interface{}) string
|
Tr(lang string, key string, args ...interface{}) string
|
||||||
|
TrContext(ctx *Context, key string, args ...interface{}) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locale is the interface which returns from a `Localizer.GetLocale` method.
|
// Locale is the interface which returns from a `Localizer.GetLocale` method.
|
||||||
|
@ -25,10 +26,4 @@ type Locale interface {
|
||||||
Language() string
|
Language() string
|
||||||
// GetMessage should return translated text based on the given "key".
|
// GetMessage should return translated text based on the given "key".
|
||||||
GetMessage(key string, args ...interface{}) string
|
GetMessage(key string, args ...interface{}) string
|
||||||
// GetMessageContext same as GetMessage
|
|
||||||
// but it accepts the Context as its first input.
|
|
||||||
// If DefaultMessageFunc was not nil then this Context
|
|
||||||
// will provide the real language input instead of the locale's which
|
|
||||||
// may be the default language one.
|
|
||||||
GetMessageContext(ctx *Context, key string, args ...interface{}) string
|
|
||||||
}
|
}
|
||||||
|
|
71
i18n/i18n.go
71
i18n/i18n.go
|
@ -79,8 +79,11 @@ type I18n struct {
|
||||||
//
|
//
|
||||||
// Defaults to true.
|
// Defaults to true.
|
||||||
Subdomain bool
|
Subdomain bool
|
||||||
// If true then it will return empty string when translation for a a specific language's key was not found.
|
// If a DefaultMessageFunc is NOT set:
|
||||||
|
// If true then it will return empty string when translation for a
|
||||||
|
// specific language's key was not found.
|
||||||
// Defaults to false, fallback defaultLang:key will be used.
|
// Defaults to false, fallback defaultLang:key will be used.
|
||||||
|
// Otherwise, DefaultMessageFunc is called in either case.
|
||||||
Strict bool
|
Strict bool
|
||||||
|
|
||||||
// If true then Iris will wrap its router with the i18n router wrapper on its Build state.
|
// If true then Iris will wrap its router with the i18n router wrapper on its Build state.
|
||||||
|
@ -96,6 +99,8 @@ var _ context.I18nReadOnly = (*I18n)(nil)
|
||||||
|
|
||||||
// makeTags converts language codes to language Tags.
|
// makeTags converts language codes to language Tags.
|
||||||
func makeTags(languages ...string) (tags []language.Tag) {
|
func makeTags(languages ...string) (tags []language.Tag) {
|
||||||
|
languages = removeDuplicates(languages)
|
||||||
|
|
||||||
for _, lang := range languages {
|
for _, lang := range languages {
|
||||||
tag, err := language.Parse(lang)
|
tag, err := language.Parse(lang)
|
||||||
if err == nil && tag != language.Und {
|
if err == nil && tag != language.Und {
|
||||||
|
@ -324,31 +329,43 @@ func (i *I18n) TryMatchString(s string) (language.Tag, int, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tr returns a translated message based on the "lang" language code
|
// Tr returns a translated message based on the "lang" language code
|
||||||
// and its key(format) with any optional arguments attached to it.
|
// and its key with any optional arguments attached to it.
|
||||||
//
|
//
|
||||||
// It returns an empty string if "lang" not matched, unless DefaultMessageFunc.
|
// It returns an empty string if "lang" not matched, unless DefaultMessageFunc.
|
||||||
// It returns the default language's translation if "key" not matched, unless DefaultMessageFunc.
|
// It returns the default language's translation if "key" not matched, unless DefaultMessageFunc.
|
||||||
func (i *I18n) Tr(lang, format string, args ...interface{}) (msg string) {
|
func (i *I18n) Tr(lang, key string, args ...interface{}) string {
|
||||||
_, index, ok := i.TryMatchString(lang)
|
_, index, ok := i.TryMatchString(lang)
|
||||||
if !ok {
|
if !ok {
|
||||||
index = 0
|
index = 0
|
||||||
}
|
}
|
||||||
|
loc := i.localizer.GetLocale(index)
|
||||||
|
return i.getLocaleMessage(loc, lang, key, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrContext returns the localized text message for this Context.
|
||||||
|
// It returns an empty string if context's locale not matched, unless DefaultMessageFunc.
|
||||||
|
// It returns the default language's translation if "key" not matched, unless DefaultMessageFunc.
|
||||||
|
func (i *I18n) TrContext(ctx *context.Context, key string, args ...interface{}) string {
|
||||||
|
loc := ctx.GetLocale()
|
||||||
|
langInput := ctx.Values().GetString(ctx.Application().ConfigurationReadOnly().GetLanguageInputContextKey())
|
||||||
|
return i.getLocaleMessage(loc, langInput, key, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *I18n) getLocaleMessage(loc context.Locale, langInput string, key string, args ...interface{}) (msg string) {
|
||||||
langMatched := ""
|
langMatched := ""
|
||||||
|
|
||||||
loc := i.localizer.GetLocale(index)
|
|
||||||
if loc != nil {
|
if loc != nil {
|
||||||
langMatched = loc.Language()
|
langMatched = loc.Language()
|
||||||
|
|
||||||
msg = loc.GetMessage(format, args...)
|
msg = loc.GetMessage(key, args...)
|
||||||
if msg == "" && i.DefaultMessageFunc == nil && !i.Strict && index > 0 {
|
if msg == "" && i.DefaultMessageFunc == nil && !i.Strict && loc.Index() > 0 {
|
||||||
// it's not the default/fallback language and not message found for that lang:key.
|
// it's not the default/fallback language and not message found for that lang:key.
|
||||||
msg = i.localizer.GetLocale(0).GetMessage(format, args...)
|
msg = i.localizer.GetLocale(0).GetMessage(key, args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg == "" && i.DefaultMessageFunc != nil {
|
if msg == "" && i.DefaultMessageFunc != nil {
|
||||||
msg = i.DefaultMessageFunc(lang, langMatched, format, args)
|
msg = i.DefaultMessageFunc(langInput, langMatched, key, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -447,30 +464,6 @@ func (i *I18n) GetLocale(ctx *context.Context) context.Locale {
|
||||||
return locale
|
return locale
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMessage returns the localized text message for this "r" request based on the key "format".
|
|
||||||
// It returns an empty string if context's locale not matched, unless DefaultMessageFunc.
|
|
||||||
// It returns the default language's translation if "key" not matched, unless DefaultMessageFunc.
|
|
||||||
func (i *I18n) GetMessage(ctx *context.Context, format string, args ...interface{}) (msg string) {
|
|
||||||
loc := i.GetLocale(ctx)
|
|
||||||
langMatched := ""
|
|
||||||
if loc != nil {
|
|
||||||
langMatched = loc.Language()
|
|
||||||
// it's not the default/fallback language and not message found for that lang:key.
|
|
||||||
msg = loc.GetMessage(format, args...)
|
|
||||||
if msg == "" && i.DefaultMessageFunc == nil && !i.Strict && loc.Index() > 0 {
|
|
||||||
return i.localizer.GetLocale(0).GetMessage(format, args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg == "" && i.DefaultMessageFunc != nil {
|
|
||||||
langInput := ctx.Values().GetString(ctx.Application().ConfigurationReadOnly().GetLanguageInputContextKey())
|
|
||||||
|
|
||||||
msg = i.DefaultMessageFunc(langInput, langMatched, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *I18n) setLangWithoutContext(w http.ResponseWriter, r *http.Request, lang string) {
|
func (i *I18n) setLangWithoutContext(w http.ResponseWriter, r *http.Request, lang string) {
|
||||||
if i.Cookie != "" {
|
if i.Cookie != "" {
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
|
@ -541,3 +534,17 @@ func (i *I18n) Wrapper() router.WrapperFunc {
|
||||||
next(w, r)
|
next(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeDuplicates(elements []string) (result []string) {
|
||||||
|
seen := make(map[string]struct{})
|
||||||
|
|
||||||
|
for v := range elements {
|
||||||
|
val := elements[v]
|
||||||
|
if _, ok := seen[val]; !ok {
|
||||||
|
seen[val] = struct{}{}
|
||||||
|
result = append(result, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
@ -163,20 +163,6 @@ func (loc *Locale) Language() string {
|
||||||
|
|
||||||
// GetMessage should return translated text based on the given "key".
|
// GetMessage should return translated text based on the given "key".
|
||||||
func (loc *Locale) GetMessage(key string, args ...interface{}) string {
|
func (loc *Locale) GetMessage(key string, args ...interface{}) string {
|
||||||
return loc.getMessage(loc.ID, key, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMessageContext same as GetMessage
|
|
||||||
// but it accepts the Context as its first input.
|
|
||||||
// If DefaultMessageFunc was not nil then this Context
|
|
||||||
// will provide the real language input instead of the locale's which
|
|
||||||
// may be the default language one.
|
|
||||||
func (loc *Locale) GetMessageContext(ctx *context.Context, key string, args ...interface{}) string {
|
|
||||||
langInput := ctx.Values().GetString(ctx.Application().ConfigurationReadOnly().GetLanguageInputContextKey())
|
|
||||||
return loc.getMessage(langInput, key, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (loc *Locale) getMessage(langInput, key string, args ...interface{}) string {
|
|
||||||
if msg, ok := loc.Messages[key]; ok {
|
if msg, ok := loc.Messages[key]; ok {
|
||||||
result, err := msg.Render(args...)
|
result, err := msg.Render(args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -186,10 +172,5 @@ func (loc *Locale) getMessage(langInput, key string, args ...interface{}) string
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
if fn := loc.Options.DefaultMessageFunc; fn != nil {
|
|
||||||
// let langInput to be empty if that's the case.
|
|
||||||
return fn(langInput, loc.ID, key, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user