Skip to content

Commit

Permalink
enable fallback for {locale}.json
Browse files Browse the repository at this point in the history
  • Loading branch information
kkumar-gcc committed Dec 25, 2023
1 parent e0ed50a commit 9168aa5
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 24 deletions.
40 changes: 16 additions & 24 deletions translation/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"strings"

"github.com/spf13/cast"
"golang.org/x/exp/slices"
"golang.org/x/text/cases"
"golang.org/x/text/language"

Expand Down Expand Up @@ -92,8 +91,7 @@ func (t *Translator) Get(key string, options ...translationcontract.Option) stri
}

Check warning on line 91 in translation/translator.go

View check run for this annotation

Codecov / codecov/patch

translation/translator.go#L89-L91

Added lines #L89 - L91 were not covered by tests

keyValue := getValue(t.loaded[locale]["*"], key)
// if the key is not found `{locale}.json` file, we will try to find it in
// the group files.
// If the key is found, return the translated line
if keyValue != nil {
line := cast.ToString(keyValue)
if line == "" {
Expand All @@ -110,25 +108,27 @@ func (t *Translator) Get(key string, options ...translationcontract.Option) stri
return line
}

// Parse the key into group and item.
// If the key is not found, parse it into a group and item and get the line.
group, item := parseKey(key)

// Here we will get the locale that should be used for the language line.
// If it doesn't exist, we will use the default locale which was given
// to us when the translator was instantiated.Then we can load the lines
// and return the value.
locales := []string{locale}
if fallback {
locales = t.appendFallbackLocale(locales)
line := t.getLine(locale, group, item, options...)
if line != "" {
return line
}

for _, loc := range locales {
line := t.getLine(loc, group, item, options...)
if line != "" {
return line
// If the key is not found in the current locale and fallback is enabled,
// try to load from fallback locale
fallbackLocale := t.GetFallback()
if (locale != fallbackLocale) && fallback && fallbackLocale != "" {
var fallbackOptions translationcontract.Option
if len(options) > 0 {
fallbackOptions = options[0]
}
fallbackOptions.Fallback = translationcontract.Bool(false)
fallbackOptions.Locale = fallbackLocale
return t.Get(key, fallbackOptions)
}

// Return the original key if no translation is found.
return t.key
}

Expand Down Expand Up @@ -206,14 +206,6 @@ func (t *Translator) load(locale string, group string) error {
return nil
}

func (t *Translator) appendFallbackLocale(locales []string) []string {
fallbackLocale := t.GetFallback()
if fallbackLocale != "" && !slices.Contains(locales, fallbackLocale) {
locales = append(locales, fallbackLocale)
}
return locales
}

func (t *Translator) isLoaded(locale string, group string) bool {
if _, ok := t.loaded[locale]; !ok {
return false
Expand Down
28 changes: 28 additions & 0 deletions translation/translator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ func (t *TranslatorTestSuite) TestGet() {
translator = NewTranslator(t.ctx, t.mockLoader, "en", "fr", t.mockLog)
t.mockLoader.On("Load", "en", "*").Once().Return(map[string]any{}, ErrFileNotExist)
t.mockLoader.On("Load", "en", "test").Once().Return(map[string]any{}, ErrFileNotExist)
t.mockLoader.On("Load", "fr", "*").Once().Return(map[string]any{}, ErrFileNotExist)
t.mockLoader.On("Load", "fr", "test").Once().Return(map[string]any{
"nonexistentKey": "French translation",
}, nil)
Expand All @@ -184,6 +185,33 @@ func (t *TranslatorTestSuite) TestGet() {
})
t.Equal("French translation", translation)

// Case: Fallback to a different locale with fallback disabled
translator = NewTranslator(t.ctx, t.mockLoader, "en", "fr", t.mockLog)
t.mockLoader.On("Load", "en", "*").Once().Return(map[string]any{}, ErrFileNotExist)
t.mockLoader.On("Load", "en", "test").Once().Return(map[string]any{}, ErrFileNotExist)
translation = translator.Get("test.nonexistentKey", translationcontract.Option{
Fallback: translationcontract.Bool(false),
Locale: "en",
})
t.Equal("test.nonexistentKey", translation)

// Case: use JSON file as fallback
translator = NewTranslator(t.ctx, t.mockLoader, "en", "fr", t.mockLog)
t.mockLoader.On("Load", "en", "*").Once().Return(map[string]any{
"nonexistentKey": "English translation",
}, nil)
t.mockLoader.On("Load", "en", "test").Once().Return(map[string]any{}, ErrFileNotExist)
t.mockLoader.On("Load", "fr", "*").Once().Return(map[string]any{
"test": map[string]any{
"nonexistentKey": "French translation",
},
}, nil)
translation = translator.Get("test.nonexistentKey", translationcontract.Option{
Fallback: translationcontract.Bool(true),
Locale: "en",
})
t.Equal("French translation", translation)

translator = NewTranslator(t.ctx, t.mockLoader, "en", "en", t.mockLog)
t.mockLoader.On("Load", "en", "*").Once().Return(map[string]any{}, ErrFileNotExist)
t.mockLoader.On("Load", "en", "test").Once().Return(map[string]any{}, nil)
Expand Down

0 comments on commit 9168aa5

Please sign in to comment.