shithub: hugo

Download patch

ref: 06d12ab895a83fc8a9f94b23e533b25511bbb6d1
parent: ec33732fbe84f67c1164fb713d6cb738609f2e2e
author: Bjørn Erik Pedersen <[email protected]>
date: Sun Jul 24 09:58:27 EDT 2016

Add proper Language and Languages types

--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -493,9 +493,8 @@
 			helpers.HugoReleaseVersion(), minVersion)
 	}
 
-	readMultilingualConfiguration()
+	return readMultilingualConfiguration()
 
-	return nil
 }
 
 func flagChanged(flags *flag.FlagSet, key string) bool {
@@ -715,11 +714,11 @@
 
 	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 @@
 			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 @@
 
 	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()))
--- a/commands/multilingual.go
+++ b/commands/multilingual.go
@@ -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))
 
-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] }
+	for lang, langConf := range l {
+		langsMap, ok := langConf.(map[string]interface{})
 
-func weightForLang(lang string) int {
-	conf := langConfigs[lang]
-	if conf == nil {
-		return 0
+		if !ok {
+			return nil, fmt.Errorf("Language config is not a map: %v", langsMap)
+		}
+
+		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
 }
--- a/hugolib/multilingual.go
+++ b/hugolib/multilingual.go
@@ -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 (ml *Multilingual) GetString(key string) string { return cast.ToString(ml.Get(key)) }
-func (ml *Multilingual) GetStringMap(key string) map[string]interface{} {
+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 (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
@@ -45,4 +82,16 @@
 
 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)
 }
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -131,7 +131,7 @@
 	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 @@
 		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 @@
 		return
 	}
 
-	currentLang := s.Multilingual.GetString("CurrentLanguage")
+	currentLang := currentLanguageString()
 
 	allTranslations := pagesToTranslationsMap(s.AllPages)
 	assignTranslationsToPages(allTranslations, s.AllPages)
@@ -817,8 +817,28 @@
 }
 
 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") {
 		permalinks[k] = pathPattern(v)
@@ -826,24 +846,20 @@
 
 	languagePrefix := ""
 	if s.multilingualEnabled() {
-		languagePrefix = "/" + s.Multilingual.GetString("CurrentLanguage")
+		languagePrefix = "/" + lang.Lang
 	}
 
-	languages := []string{}
-	if s.Multilingual != nil {
-		languages = s.Multilingual.Languages
-	}
-
 	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) 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
 		}
--- a/hugolib/site_test.go
+++ b/hugolib/site_test.go
@@ -1402,13 +1402,13 @@
 	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")