Skip to content

Commit

Permalink
fix(i18n): make use incremental (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
plastikfan committed Apr 24, 2023
1 parent 76545e6 commit cbb5fdd
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 116 deletions.
4 changes: 2 additions & 2 deletions i18n/localisation-errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
// which by definition means translated content can't be served to the client using
// the requested locale and therefore have to be displayed untranslated.

// ❌ CouldNotFindLocalizer
// ❌ Could Not Find Localizer

// NewFailedToCreateLocalizerNativeError creates an untranslated error to
// indicate the Translator already contains a localizer for the source
Expand All @@ -32,7 +32,7 @@ func NewCouldNotLoadTranslationsNativeError(tag language.Tag, path string, reaso
)
}

// ❌ FailedToCreateTranslator
// ❌ Failed To Create Translator

// NewFailedToCreateTranslatorNativeError creates an untranslated error to
// indicate failure to create a Translator instance
Expand Down
19 changes: 12 additions & 7 deletions i18n/localizer-factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/samber/lo"
"github.com/snivilised/extendio/xfs/utils"
"golang.org/x/text/language"
)

Expand All @@ -16,8 +17,8 @@ func createLocalizer(lang *LanguageInfo, sourceID string) (*i18n.Localizer, erro
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)

if lang.Tag != lang.Default {
name := lang.From.Sources[sourceID].Name
path := resolveBundlePath(lang, name)
txSource := lang.From.Sources[sourceID]
path := resolveBundlePath(lang, txSource)
_, err := bundle.LoadMessageFile(path)

if (err != nil) && (!lang.DefaultIsAcceptable) {
Expand All @@ -32,20 +33,24 @@ func createLocalizer(lang *LanguageInfo, sourceID string) (*i18n.Localizer, erro
return i18n.NewLocalizer(bundle, supported...), nil
}

func resolveBundlePath(lang *LanguageInfo, dependencyName string) string {
filename := lo.TernaryF(dependencyName == "",
func resolveBundlePath(lang *LanguageInfo, txSource TranslationSource) string {
filename := lo.TernaryF(txSource.Name == "",
func() string {
return fmt.Sprintf("active.%v.json", lang.Tag)
},
func() string {
return fmt.Sprintf("%v.active.%v.json", dependencyName, lang.Tag)
return fmt.Sprintf("%v.active.%v.json", txSource.Name, lang.Tag)
},
)

resolved, _ := filepath.Abs(lang.From.Path)
path := lo.Ternary(txSource.Path != "" && utils.FolderExists(txSource.Path),
txSource.Path,
lang.From.Path,
)

directory := lo.TernaryF(lang.From.Path != "",
directory := lo.TernaryF(path != "" && utils.FolderExists(path),
func() string {
resolved, _ := filepath.Abs(path)
return resolved
},
func() string {
Expand Down
14 changes: 7 additions & 7 deletions i18n/messages.error.nav.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func QueryInvalidResumeStrategyError(target error) bool {
return QueryGeneric[InvalidResumeStrategyErrorBehaviourQuery]("InvalidResumeStrategy", target)
}

// ❌ MissingCallback
// ❌ Missing Callback

// missing callback (internal)
type MissingCallbackTemplData struct {
Expand Down Expand Up @@ -344,7 +344,7 @@ func QueryMissingCallbackError(target error) bool {
return QueryGeneric[MissingCallbackBehaviourQuery]("MissingCallback", target)
}

// ❌ MissingCustomFilterDefinition
// ❌ Missing Custom Filter Definition

// Missing custom filter definition (config)
type MissingCustomFilterDefinitionTemplData struct {
Expand Down Expand Up @@ -395,7 +395,7 @@ func QueryMissingCustomFilterDefinitionError(target error) bool {
return QueryGeneric[MissingCustomFilterDefinitionBehaviourQuery]("MissingCustomFilterDefinition", target)
}

// ❌ NotADirectory
// ❌ Not A Directory

// NotADirectoryTemplData path is not a directory
type NotADirectoryTemplData struct {
Expand Down Expand Up @@ -444,7 +444,7 @@ func QueryNotADirectoryError(target error) bool {
return QueryGeneric[NotADirectoryErrorBehaviourQuery]("NotADirectory", target)
}

// ❌ SortFnFailed
// ❌ Sort Fn Failed

// sort function failed (internal)
type SortFnFailedTemplData struct {
Expand Down Expand Up @@ -490,7 +490,7 @@ func QuerySortFnFailedError(target error) bool {
return QueryGeneric[SortFnFailedBehaviourQuery]("SortFnFailed", target)
}

// ❌ TerminateTraverse
// ❌ Terminate Traverse

// terminate traverse
type TerminateTraverseTemplData struct {
Expand Down Expand Up @@ -538,7 +538,7 @@ func QueryTerminateTraverseError(target error) bool {
return QueryGeneric[SortFnFailedBehaviourQuery]("TerminateTraverse", target)
}

// ❌ ThirdPartyError
// ❌ Third Party Error

// ThirdPartyErrorTemplData third party un-translated error
type ThirdPartyErrorTemplData struct {
Expand Down Expand Up @@ -572,7 +572,7 @@ func NewThirdPartyErr(err error) ThirdPartyError {
}
}

// ❌ UnknownMarshalFormat
// ❌ Unknown Marshal Format

// UnknownMarshalFormatTemplData unknown marshall format specified in config by user
type UnknownMarshalFormatTemplData struct {
Expand Down
90 changes: 89 additions & 1 deletion i18n/text_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package i18n_test

import (
"errors"
"strings"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand All @@ -11,11 +12,44 @@ import (
"golang.org/x/text/language"
)

type textTE struct {
message string
path string
sourcePath string
name string
defaultAcceptable bool
}

const (
expectUS = "Found graffiti on sidewalk; primary color: 'Violet'"
expectGB = "Found graffiti on pavement; primary colour: 'Violet'"
)

func testTranslationPath(entry *textTE) string {
// this test form required, because DescribeTable can't be used
// due to not being able to setup state correctly, eg l10nPath
//
if err := xi18n.Use(func(o *xi18n.UseOptions) {
o.Tag = language.AmericanEnglish
o.DefaultIsAcceptable = entry.defaultAcceptable
o.From = xi18n.LoadFrom{
Path: entry.path,
Sources: xi18n.TranslationFiles{
GrafficoSourceID: xi18n.TranslationSource{
Path: entry.sourcePath,
Name: "test.graffico",
},
},
}
}); err != nil {
Fail(err.Error())
}

return xi18n.Text(PavementGraffitiReportTemplData{
Primary: "Violet",
})
}

var _ = Describe("Text", Ordered, func() {
var (
repo string
Expand All @@ -29,7 +63,7 @@ var _ = Describe("Text", Ordered, func() {
Expect(utils.FolderExists(l10nPath)).To(BeTrue())

testTranslationFile = xi18n.TranslationFiles{
xi18n.ExtendioSourceID: xi18n.TranslationSource{"test"},
xi18n.ExtendioSourceID: xi18n.TranslationSource{Name: "test"},
}
})

Expand Down Expand Up @@ -138,4 +172,58 @@ var _ = Describe("Text", Ordered, func() {
})
})
})

Context("translation source contains path", func() {
Context("Foreign Language", func() {
Context("given: source path exists", func() {
It("🧪 should: create localizer from source path", func() {
actual := testTranslationPath(&textTE{
sourcePath: l10nPath,
defaultAcceptable: true,
})

Expect(actual).To(Equal(expectUS))
})
})

Context("given: path exists", func() {
It("🧪 should: create localizer from path", func() {
actual := testTranslationPath(&textTE{
path: l10nPath,
defaultAcceptable: true,
})

Expect(actual).To(Equal(expectUS))
})
})

Context("given: neither path exists", func() {
It("🧪 should: create localizer using default language", func() {
actual := testTranslationPath(&textTE{
defaultAcceptable: true,
})

Expect(actual).To(Equal(expectGB))
})
})

Context("given: neither path exists", func() {
It("🧪 should: create localizer using default language", func() {
defer func() {
pe := recover()
if err, ok := pe.(error); !ok || !strings.Contains(err.Error(),
"could not load translations for") {
Fail("translation file not available with exe")
}
}()

_ = testTranslationPath(&textTE{
defaultAcceptable: false,
})

Fail("❌ expected panic due translation file not available with exe")
})
})
})
})
})
2 changes: 1 addition & 1 deletion i18n/translate-defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (lf *LoadFrom) AppendSources(appendFiles *TranslationFiles) []string {
type TranslationSource struct {
// Name of dependency's translation file
Name string
Path string
}

// TranslationFiles maps a source id to a TranslationSource
Expand Down Expand Up @@ -125,7 +126,6 @@ type localizerMultiplexor interface {
type LocalizerInfo struct {
// Localizer by default created internally, but can be overridden by
// the client if they provide a create function to the Translator Factory
// (either SingularTranslatorFactory or MultiTranslatorFactory)
//
Localizer *i18n.Localizer

Expand Down
35 changes: 2 additions & 33 deletions i18n/translator-factories.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package i18n

import (
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/samber/lo"
"github.com/snivilised/extendio/xfs/utils"
)

Expand All @@ -12,6 +11,7 @@ type LocalizerCreatorFn func(li *LanguageInfo, sourceID string) (*i18n.Localizer

type AbstractTranslatorFactory struct {
Create LocalizerCreatorFn
legacy Translator
}

func (f *AbstractTranslatorFactory) setup(lang *LanguageInfo) {
Expand All @@ -22,39 +22,8 @@ func (f *AbstractTranslatorFactory) setup(lang *LanguageInfo) {
}
}

// singularTranslatorFactory creates Translator with the single localizer which
// represents the client's package.
type singularTranslatorFactory struct {
AbstractTranslatorFactory
}

func (f *singularTranslatorFactory) New(lang *LanguageInfo) Translator {
f.setup(lang)

sourceID := lo.Keys(lang.From.Sources)[0]

liRef := utils.NewRoProp(*lang)
native, err := f.Create(lang, sourceID)

if err != nil {
panic(err)
}

single := &singularContainer{
localizer: native,
}

return &i18nTranslator{
mx: single,
languageInfoRef: liRef,
}
}

// multiTranslatorFactory creates a translator instance from the provided
// Localizers. If the client library needs to provide localizers for itself
// and at least 1 dependency, then they should use multiTranslatorFactory
// specify appropriate information concerning where to load the translation
// files from, otherwise SingularTranslatorFactory should be used.
// Localizers.
//
// Note, in the case where a source client wants to provide a localizer
// for a language that one of ite dependencies does not support, then
Expand Down
Loading

0 comments on commit cbb5fdd

Please sign in to comment.