diff --git a/deps/deps.go b/deps/deps.go index 2b66a153f4b..2ed357b5b0a 100644 --- a/deps/deps.go +++ b/deps/deps.go @@ -55,7 +55,7 @@ type Deps struct { Cfg config.Provider `json:"-"` // The translation func to use - Translate func(translationID string, args ...interface{}) string `json:"-"` + Translate func(translationID string, templateData interface{}) string `json:"-"` Language *langs.Language diff --git a/go.mod b/go.mod index 62f22531fff..fa047cee297 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/gohugoio/hugo require ( github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 - github.com/BurntSushi/toml v0.0.0-20170626110600-a368813c5e64 + github.com/BurntSushi/toml v0.3.0 github.com/PuerkitoBio/purell v1.1.0 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 @@ -37,6 +37,7 @@ require ( github.com/muesli/smartcrop v0.0.0-20180228075044-f6ebaa786a12 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nicksnyder/go-i18n v1.10.0 + github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5.0.20180809142456-e786c8873251 github.com/olekukonko/tablewriter v0.0.0-20180506121414-d4647c9c7a84 github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday v0.0.0-20180804101149-46c73eb196ba diff --git a/go.sum b/go.sum index 5a71e5d7690..51a9da28804 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69 h1:+tu3HOoMXB7RX github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZdiDllfyYH5l5OkAaZtk7VkWe89bPJFmnDBNHxg= github.com/BurntSushi/toml v0.0.0-20170626110600-a368813c5e64 h1:BuYewlQyh/jroxY8qx41SrzD8Go17GkyCyAeVmprvQI= github.com/BurntSushi/toml v0.0.0-20170626110600-a368813c5e64/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY= +github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -83,6 +85,10 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nicksnyder/go-i18n v1.10.0 h1:5AzlPKvXBH4qBzmZ09Ua9Gipyruv6uApMcrNZdo96+Q= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= +github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5 h1:/TjjTS4kg7vC+05gD0LE4+97f/+PRFICnK/7wJPk7kE= +github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5/go.mod h1:4Opqa6/HIv0lhG3WRAkqzO0afezkRhxXI0P8EJkqeRU= +github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5.0.20180809142456-e786c8873251 h1:t+H3wc9GR6DQNaSNfYnfAQnQSf7EM9CwxsOpYuEyXCM= +github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5.0.20180809142456-e786c8873251/go.mod h1:4Opqa6/HIv0lhG3WRAkqzO0afezkRhxXI0P8EJkqeRU= github.com/olekukonko/tablewriter v0.0.0-20180506121414-d4647c9c7a84 h1:fiKJgB4JDUd43CApkmCeTSQlWjtTtABrU2qsgbuP0BI= github.com/olekukonko/tablewriter v0.0.0-20180506121414-d4647c9c7a84/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= @@ -133,6 +139,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6Zh golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992 h1:BH3eQWeGbwRU2+wxxuuPOdFBmaiBH81O8BugSjHeTFg= golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.0.0-20171214130843-f21a4dfb5e38/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/i18n/i18n.go b/i18n/i18n.go index 73417fb3240..190875a30bc 100644 --- a/i18n/i18n.go +++ b/i18n/i18n.go @@ -14,33 +14,37 @@ package i18n import ( + "fmt" + "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/helpers" - "github.com/nicksnyder/go-i18n/i18n/bundle" + "github.com/nicksnyder/go-i18n/v2/i18n" jww "github.com/spf13/jwalterweatherman" ) +type translateFunc func(translationID string, templateData interface{}) string + var ( i18nWarningLogger = helpers.NewDistinctFeedbackLogger() ) // Translator handles i18n translations. type Translator struct { - translateFuncs map[string]bundle.TranslateFunc + translateFuncs map[string]translateFunc cfg config.Provider logger *jww.Notepad } // NewTranslator creates a new Translator for the given language bundle and configuration. -func NewTranslator(b *bundle.Bundle, cfg config.Provider, logger *jww.Notepad) Translator { - t := Translator{cfg: cfg, logger: logger, translateFuncs: make(map[string]bundle.TranslateFunc)} +func NewTranslator(b *i18n.Bundle, cfg config.Provider, logger *jww.Notepad) Translator { + t := Translator{cfg: cfg, logger: logger, translateFuncs: make(map[string]translateFunc)} t.initFuncs(b) return t } // Func gets the translate func for the given language, or for the default // configured language if not found. -func (t Translator) Func(lang string) bundle.TranslateFunc { +func (t Translator) Func(lang string) translateFunc { if f, ok := t.translateFuncs[lang]; ok { return f } @@ -49,34 +53,35 @@ func (t Translator) Func(lang string) bundle.TranslateFunc { return f } t.logger.WARN.Println("i18n not initialized, check that you have language file (in i18n) that matches the site language or the default language.") - return func(translationID string, args ...interface{}) string { + return func(translationID string, args interface{}) string { return "" } } -func (t Translator) initFuncs(bndl *bundle.Bundle) { - defaultContentLanguage := t.cfg.GetString("defaultContentLanguage") +var defaultMessage = &i18n.Message{ + ID: "___I18N_DEFAULT", + Other: "I18N_MISSING", +} - defaultT, err := bndl.Tfunc(defaultContentLanguage) - if err != nil { - jww.WARN.Printf("No translation bundle found for default language %q", defaultContentLanguage) - } +func (t Translator) initFuncs(bndl *i18n.Bundle) { + // TODO(bep) i18n defaultContentLanguage := t.cfg.GetString("defaultContentLanguage") enableMissingTranslationPlaceholders := t.cfg.GetBool("enableMissingTranslationPlaceholders") for _, lang := range bndl.LanguageTags() { - currentLang := lang + currentLang := lang.String() - t.translateFuncs[currentLang] = func(translationID string, args ...interface{}) string { - tFunc, err := bndl.Tfunc(currentLang) - if err != nil { - jww.WARN.Printf("could not load translations for language %q (%s), will use default content language.\n", lang, err) - } + t.translateFuncs[currentLang] = func(translationID string, templateData interface{}) string { + localizer := i18n.NewLocalizer(bndl, currentLang) + + translated, err := localizer.Localize(&i18n.LocalizeConfig{ + //DefaultMessage: defaultMessage, + MessageID: translationID, + TemplateData: templateData, + }) + + fmt.Printf(">>>%v %T %s %s %s\n", err, err, currentLang, translationID, translated) - translated := tFunc(translationID, args...) - if translated != translationID { - return translated - } // If there is no translation for translationID, // then Tfunc returns translationID itself. // But if user set same translationID and translation, we should check @@ -91,15 +96,17 @@ func (t Translator) initFuncs(bndl *bundle.Bundle) { if enableMissingTranslationPlaceholders { return "[i18n] " + translationID } - if defaultT != nil { - translated := defaultT(translationID, args...) - if translated != translationID { - return translated - } - if isIDTranslated(defaultContentLanguage, translationID, bndl) { - return translated - } - } + /* + TODO(bep) i18n + if defaultT != nil { + translated := defaultT(translationID, args...) + if translated != translationID { + return translated + } + if isIDTranslated(defaultContentLanguage, translationID, bndl) { + return translated + } + }*/ return "" } } @@ -107,7 +114,7 @@ func (t Translator) initFuncs(bndl *bundle.Bundle) { // If bndl contains the translationID for specified currentLang, // then the translationID is actually translated. -func isIDTranslated(lang, id string, b *bundle.Bundle) bool { - _, contains := b.Translations()[lang][id] - return contains +func isIDTranslated(lang, id string, b *i18n.Bundle) bool { + // _, contains := b.Translations()[lang][id] + return true // TODO(bep) i18n } diff --git a/i18n/translationProvider.go b/i18n/translationProvider.go index 5f90895aab9..15f01da0e11 100644 --- a/i18n/translationProvider.go +++ b/i18n/translationProvider.go @@ -14,15 +14,15 @@ package i18n import ( - "errors" "fmt" + "github.com/BurntSushi/toml" "github.com/gohugoio/hugo/helpers" + "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/gohugoio/hugo/deps" "github.com/gohugoio/hugo/source" - "github.com/nicksnyder/go-i18n/i18n/bundle" - "github.com/nicksnyder/go-i18n/i18n/language" + "golang.org/x/text/language" ) // TranslationProvider provides translation handling, i.e. loading @@ -41,37 +41,20 @@ func (tp *TranslationProvider) Update(d *deps.Deps) error { sp := source.NewSourceSpec(d.PathSpec, d.BaseFs.SourceFilesystems.I18n.Fs) src := sp.NewFilesystem("") - i18nBundle := bundle.New() - - en := language.GetPluralSpec("en") - if en == nil { - return errors.New("the English language has vanished like an old oak table") - } - var newLangs []string - - for _, r := range src.Files() { - currentSpec := language.GetPluralSpec(r.BaseFileName()) - if currentSpec == nil { - // This may is a language code not supported by go-i18n, it may be - // Klingon or ... not even a fake language. Make sure it works. - newLangs = append(newLangs, r.BaseFileName()) - } - } - - if len(newLangs) > 0 { - language.RegisterPluralSpec(newLangs, en) - } + bundle := &i18n.Bundle{DefaultLanguage: language.English} + bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) + //localizer := i18n.NewLocalizer(bundle, "en") // The source files are ordered so the most important comes first. Since this is a // last key win situation, we have to reverse the iteration order. files := src.Files() for i := len(files) - 1; i >= 0; i-- { - if err := addTranslationFile(i18nBundle, files[i]); err != nil { + if err := addTranslationFile(bundle, files[i]); err != nil { return err } } - tp.t = NewTranslator(i18nBundle, d.Cfg, d.Log) + tp.t = NewTranslator(bundle, d.Cfg, d.Log) d.Translate = tp.t.Func(d.Language.Lang) @@ -79,13 +62,13 @@ func (tp *TranslationProvider) Update(d *deps.Deps) error { } -func addTranslationFile(bundle *bundle.Bundle, r source.ReadableFile) error { +func addTranslationFile(bundle *i18n.Bundle, r source.ReadableFile) error { f, err := r.Open() if err != nil { return fmt.Errorf("Failed to open translations file %q: %s", r.LogicalName(), err) } defer f.Close() - err = bundle.ParseTranslationFileBytes(r.LogicalName(), helpers.ReaderToBytes(f)) + _, err = bundle.ParseMessageFileBytes(helpers.ReaderToBytes(f), r.LogicalName()) if err != nil { return fmt.Errorf("Failed to load translations in file %q: %s", r.LogicalName(), err) } diff --git a/tpl/lang/lang.go b/tpl/lang/lang.go index 430b5e442d5..7491a43135b 100644 --- a/tpl/lang/lang.go +++ b/tpl/lang/lang.go @@ -37,13 +37,13 @@ type Namespace struct { } // Translate returns a translated string for id. -func (ns *Namespace) Translate(id interface{}, args ...interface{}) (string, error) { +func (ns *Namespace) Translate(id interface{}, templateData interface{}) (string, error) { sid, err := cast.ToStringE(id) if err != nil { return "", nil } - return ns.deps.Translate(sid, args...), nil + return ns.deps.Translate(sid, templateData), nil } // NumFmt formats a number with the given precision using the