Add proper Language and Languages types
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 24 Jul 2016 11:58:27 +0000 (13:58 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 6 Sep 2016 15:32:15 +0000 (18:32 +0300)
commands/hugo.go
commands/multilingual.go
hugolib/multilingual.go
hugolib/site.go
hugolib/site_test.go

index 57a4264587951727331a29021d569721e93e8dfd..c773ac5c4171063d91a511c4ec1af17ee3ce54d9 100644 (file)
@@ -493,9 +493,8 @@ func InitializeConfig(subCmdVs ...*cobra.Command) error {
                        helpers.HugoReleaseVersion(), minVersion)
        }
 
-       readMultilingualConfiguration()
+       return readMultilingualConfiguration()
 
-       return nil
 }
 
 func flagChanged(flags *flag.FlagSet, key string) bool {
@@ -715,11 +714,11 @@ func buildSite(watching ...bool) (err error) {
 
        for _, lang := range langConfigsList {
                t1 := time.Now()
-               mainSite, present := MainSites[lang]
+               mainSite, present := MainSites[lang.Lang]
                if !present {
                        mainSite = new(hugolib.Site)
-                       MainSites[lang] = mainSite
-                       mainSite.SetMultilingualConfig(lang, langConfigsList, langConfigs)
+                       MainSites[lang.Lang] = mainSite
+                       mainSite.SetMultilingualConfig(lang, langConfigsList)
                }
 
                if len(watching) > 0 && watching[0] {
@@ -730,7 +729,7 @@ func buildSite(watching ...bool) (err error) {
                        return err
                }
 
-               mainSite.Stats(lang, t1)
+               mainSite.Stats(lang.Lang, t1)
        }
 
        jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))
@@ -743,13 +742,13 @@ func rebuildSite(events []fsnotify.Event) error {
 
        for _, lang := range langConfigsList {
                t1 := time.Now()
-               mainSite := MainSites[lang]
+               mainSite := MainSites[lang.Lang]
 
                if err := mainSite.ReBuild(events); err != nil {
                        return err
                }
 
-               mainSite.Stats(lang, t1)
+               mainSite.Stats(lang.Lang, t1)
        }
 
        jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))
index 68da7c96d5100a5a1d21b6d3040be3d4ce4cafbb..983dc756dc8c8af810fe2c5a676b1ce417edf0e7 100644 (file)
@@ -1,41 +1,66 @@
 package commands
 
 import (
+       "fmt"
        "sort"
 
+       "strings"
+
        "github.com/spf13/cast"
+       "github.com/spf13/hugo/hugolib"
        "github.com/spf13/viper"
 )
 
-var langConfigs map[string]interface{}
-var langConfigsList langConfigsSortable
+var langConfigsList hugolib.Languages
 
-func readMultilingualConfiguration() {
+func readMultilingualConfiguration() error {
        multilingual := viper.GetStringMap("Multilingual")
        if len(multilingual) == 0 {
-               langConfigsList = append(langConfigsList, "")
-               return
+               // TODO(bep) multilingo langConfigsList = append(langConfigsList, hugolib.NewLanguage("en"))
+               return nil
        }
 
-       langConfigs = make(map[string]interface{})
-       for lang, config := range multilingual {
-               langConfigs[lang] = config
-               langConfigsList = append(langConfigsList, lang)
+       var err error
+
+       langConfigsList, err = toSortedLanguages(multilingual)
+
+       if err != nil {
+               return fmt.Errorf("Failed to parse multilingual config: %s", err)
        }
-       sort.Sort(langConfigsList)
+
+       return nil
 }
 
-type langConfigsSortable []string
+func toSortedLanguages(l map[string]interface{}) (hugolib.Languages, error) {
+       langs := make(hugolib.Languages, len(l))
+
+       for lang, langConf := range l {
+               langsMap, ok := langConf.(map[string]interface{})
 
-func (p langConfigsSortable) Len() int           { return len(p) }
-func (p langConfigsSortable) Less(i, j int) bool { return weightForLang(p[i]) < weightForLang(p[j]) }
-func (p langConfigsSortable) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+               if !ok {
+                       return nil, fmt.Errorf("Language config is not a map: %v", langsMap)
+               }
 
-func weightForLang(lang string) int {
-       conf := langConfigs[lang]
-       if conf == nil {
-               return 0
+               language := hugolib.NewLanguage(lang)
+
+               for k, v := range langsMap {
+                       loki := strings.ToLower(k)
+                       switch loki {
+                       case "title":
+                               language.Title = cast.ToString(v)
+                       case "weight":
+                               language.Weight = cast.ToInt(v)
+                       }
+
+                       // Put all into the Params map
+                       // TODO(bep) reconsile with the type handling etc. from other params handlers.
+                       language.SetParam(loki, v)
+               }
+
+               langs = append(langs, language)
        }
-       m := cast.ToStringMap(conf)
-       return cast.ToInt(m["weight"])
+
+       sort.Sort(langs)
+
+       return langs, nil
 }
index 2552bad4caa993148420b4e48d521d934c74b906..eebd43e3dcf7eb58d72a40f783fb23dae9fdae46 100644 (file)
@@ -1,43 +1,80 @@
 package hugolib
 
 import (
+       "sync"
+
+       "strings"
+
        "github.com/spf13/cast"
        "github.com/spf13/viper"
 )
 
+type Language struct {
+       Lang       string
+       Title      string
+       Weight     int
+       params     map[string]interface{}
+       paramsInit sync.Once
+}
+
+func NewLanguage(lang string) *Language {
+       return &Language{Lang: lang, params: make(map[string]interface{})}
+}
+
+type Languages []*Language
+
+func (l Languages) Len() int           { return len(l) }
+func (l Languages) Less(i, j int) bool { return l[i].Weight < l[j].Weight }
+func (l Languages) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
+
 type Multilingual struct {
        enabled bool
-       config  *viper.Viper
 
-       Languages []string
+       Languages Languages
+}
+
+func (l *Language) Params() map[string]interface{} {
+       l.paramsInit.Do(func() {
+               // Merge with global config.
+               // TODO(bep) consider making this part of a constructor func.
+               globalParams := viper.GetStringMap("Params")
+               for k, v := range globalParams {
+                       if _, ok := l.params[k]; !ok {
+                               l.params[k] = v
+                       }
+               }
+       })
+       return l.params
 }
 
-func (ml *Multilingual) GetString(key string) string { return cast.ToString(ml.Get(key)) }
-func (ml *Multilingual) GetStringMap(key string) map[string]interface{} {
+func (l *Language) SetParam(k string, v interface{}) {
+       l.params[k] = v
+}
+
+func (l *Language) GetString(key string) string { return cast.ToString(l.Get(key)) }
+func (ml *Language) GetStringMap(key string) map[string]interface{} {
        return cast.ToStringMap(ml.Get(key))
 }
 
-func (ml *Multilingual) GetStringMapString(key string) map[string]string {
-       return cast.ToStringMapString(ml.Get(key))
+func (l *Language) GetStringMapString(key string) map[string]string {
+       return cast.ToStringMapString(l.Get(key))
 }
 
-func (ml *Multilingual) Get(key string) interface{} {
-       if ml != nil && ml.config != nil && ml.config.IsSet(key) {
-               return ml.config.Get(key)
+func (l *Language) Get(key string) interface{} {
+       key = strings.ToLower(key)
+       if v, ok := l.params[key]; ok {
+               return v
        }
        return viper.Get(key)
 }
 
-func (s *Site) SetMultilingualConfig(currentLang string, orderedLanguages []string, langConfigs map[string]interface{}) {
-       conf := viper.New()
-       for k, val := range cast.ToStringMap(langConfigs[currentLang]) {
-               conf.Set(k, val)
-       }
-       conf.Set("CurrentLanguage", currentLang)
+func (s *Site) SetMultilingualConfig(currentLang *Language, languages Languages) {
+
+       // TODO(bep) multilingo evaluate
+       viper.Set("CurrentLanguage", currentLang)
        ml := &Multilingual{
-               enabled:   len(langConfigs) > 0,
-               config:    conf,
-               Languages: orderedLanguages,
+               enabled:   len(languages) > 0,
+               Languages: languages,
        }
        viper.Set("Multilingual", ml.enabled)
        s.Multilingual = ml
@@ -46,3 +83,15 @@ func (s *Site) SetMultilingualConfig(currentLang string, orderedLanguages []stri
 func (s *Site) multilingualEnabled() bool {
        return s.Multilingual != nil && s.Multilingual.enabled
 }
+
+func currentLanguageString() string {
+       return currentLanguage().Lang
+}
+
+func currentLanguage() *Language {
+       l := viper.Get("CurrentLanguage")
+       if l == nil {
+               panic("CurrentLanguage not set")
+       }
+       return l.(*Language)
+}
index 308e35c90a03d093d9a1495d11c71d9ee469153c..92ce485358b5335e773391712bb6c4922c96c757 100644 (file)
@@ -131,7 +131,7 @@ type SiteInfo struct {
        Multilingual    bool
        CurrentLanguage string
        LanguagePrefix  string
-       Languages       []string
+       Languages       Languages
 }
 
 // SiteSocial is a place to put social details on a site level. These are the
@@ -705,7 +705,7 @@ func (s *Site) Process() (err error) {
                i18nSources = []source.Input{&source.Filesystem{Base: themeI18nDir}, i18nSources[0]}
        }
 
-       if err = loadI18n(i18nSources, s.Multilingual.GetString("CurrentLanguage")); err != nil {
+       if err = loadI18n(i18nSources, currentLanguageString()); err != nil {
                return
        }
        s.timerStep("load i18n")
@@ -742,7 +742,7 @@ func (s *Site) setupTranslations() {
                return
        }
 
-       currentLang := s.Multilingual.GetString("CurrentLanguage")
+       currentLang := currentLanguageString()
 
        allTranslations := pagesToTranslationsMap(s.AllPages)
        assignTranslationsToPages(allTranslations, s.AllPages)
@@ -817,7 +817,27 @@ func (s *Site) initialize() (err error) {
 }
 
 func (s *Site) initializeSiteInfo() {
-       params := s.Multilingual.GetStringMap("Params")
+
+       var (
+               lang      *Language
+               languages Languages
+       )
+
+       cl := viper.Get("CurrentLanguage")
+       if cl == nil {
+               // Set default to english
+               // TODO(bep) multilingo this looks clumsy
+               lang = NewLanguage("en")
+               viper.Set("CurrentLanguage", lang)
+       } else {
+               lang = cl.(*Language)
+       }
+
+       if s.Multilingual != nil {
+               languages = s.Multilingual.Languages
+       }
+
+       params := lang.Params()
 
        permalinks := make(PermalinkOverrides)
        for k, v := range viper.GetStringMapString("Permalinks") {
@@ -826,24 +846,20 @@ func (s *Site) initializeSiteInfo() {
 
        languagePrefix := ""
        if s.multilingualEnabled() {
-               languagePrefix = "/" + s.Multilingual.GetString("CurrentLanguage")
-       }
-
-       languages := []string{}
-       if s.Multilingual != nil {
-               languages = s.Multilingual.Languages
+               languagePrefix = "/" + lang.Lang
        }
 
        s.Info = SiteInfo{
-               BaseURL:               template.URL(helpers.SanitizeURLKeepTrailingSlash(viper.GetString("BaseURL"))),
-               Title:                 s.Multilingual.GetString("Title"),
-               Author:                s.Multilingual.GetStringMap("author"),
-               Social:                s.Multilingual.GetStringMapString("social"),
-               LanguageCode:          s.Multilingual.GetString("languagecode"),
-               Copyright:             s.Multilingual.GetString("copyright"),
-               DisqusShortname:       s.Multilingual.GetString("DisqusShortname"),
+               BaseURL:         template.URL(helpers.SanitizeURLKeepTrailingSlash(viper.GetString("BaseURL"))),
+               Title:           lang.GetString("Title"),
+               Author:          lang.GetStringMap("author"),
+               Social:          lang.GetStringMapString("social"),
+               LanguageCode:    lang.GetString("languagecode"),
+               Copyright:       lang.GetString("copyright"),
+               DisqusShortname: lang.GetString("DisqusShortname"),
+               // TODO(bep) multilang, consolidate the below (make into methods etc.)
                Multilingual:          s.multilingualEnabled(),
-               CurrentLanguage:       s.Multilingual.GetString("CurrentLanguage"),
+               CurrentLanguage:       lang.Lang,
                LanguagePrefix:        languagePrefix,
                Languages:             languages,
                GoogleAnalytics:       viper.GetString("GoogleAnalytics"),
@@ -1594,7 +1610,7 @@ func (s *Site) newTaxonomyNode(t taxRenderInfo) (*Node, string) {
 func (s *Site) addMultilingualPrefix(basePath string) string {
        hadPrefix := strings.HasPrefix(basePath, "/")
        if s.multilingualEnabled() {
-               basePath = path.Join(s.Multilingual.GetString("CurrentLanguage"), basePath)
+               basePath = path.Join(currentLanguageString(), basePath)
                if hadPrefix {
                        basePath = "/" + basePath
                }
index 2f03dec973bfd2deca49bba3df171611c9dcd9ec..9f29bf376ac850e6dcf65e7eac227d7ea56acbd6 100644 (file)
@@ -1402,13 +1402,13 @@ NOTE: should use the "permalinks" configuration with :filename
        s := &Site{
                Source: &source.InMemorySource{ByteSource: sources},
                Multilingual: &Multilingual{
-                       config:  viper.New(),
                        enabled: true,
                },
        }
        // Multilingual settings
        viper.Set("Multilingual", true)
-       s.Multilingual.config.Set("CurrentLanguage", "en")
+       en := NewLanguage("en")
+       viper.Set("CurrentLanguage", en)
        viper.Set("DefaultContentLanguage", "fr")
        viper.Set("paginate", "2")