Add proper Language and Languages types

This commit is contained in:
Bjørn Erik Pedersen 2016-07-24 13:58:27 +02:00
parent ec33732fbe
commit 06d12ab895
5 changed files with 159 additions and 70 deletions

View file

@ -493,9 +493,8 @@ func InitializeConfig(subCmdVs ...*cobra.Command) error {
helpers.HugoReleaseVersion(), minVersion) helpers.HugoReleaseVersion(), minVersion)
} }
readMultilingualConfiguration() return readMultilingualConfiguration()
return nil
} }
func flagChanged(flags *flag.FlagSet, key string) bool { func flagChanged(flags *flag.FlagSet, key string) bool {
@ -715,11 +714,11 @@ func buildSite(watching ...bool) (err error) {
for _, lang := range langConfigsList { for _, lang := range langConfigsList {
t1 := time.Now() t1 := time.Now()
mainSite, present := MainSites[lang] mainSite, present := MainSites[lang.Lang]
if !present { if !present {
mainSite = new(hugolib.Site) mainSite = new(hugolib.Site)
MainSites[lang] = mainSite MainSites[lang.Lang] = mainSite
mainSite.SetMultilingualConfig(lang, langConfigsList, langConfigs) mainSite.SetMultilingualConfig(lang, langConfigsList)
} }
if len(watching) > 0 && watching[0] { if len(watching) > 0 && watching[0] {
@ -730,7 +729,7 @@ func buildSite(watching ...bool) (err error) {
return err 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())) 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 { for _, lang := range langConfigsList {
t1 := time.Now() t1 := time.Now()
mainSite := MainSites[lang] mainSite := MainSites[lang.Lang]
if err := mainSite.ReBuild(events); err != nil { if err := mainSite.ReBuild(events); err != nil {
return err 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())) jww.FEEDBACK.Printf("total in %v ms\n", int(1000*time.Since(t0).Seconds()))

View file

@ -1,41 +1,66 @@
package commands package commands
import ( import (
"fmt"
"sort" "sort"
"strings"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/spf13/hugo/hugolib"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
var langConfigs map[string]interface{} var langConfigsList hugolib.Languages
var langConfigsList langConfigsSortable
func readMultilingualConfiguration() { func readMultilingualConfiguration() error {
multilingual := viper.GetStringMap("Multilingual") multilingual := viper.GetStringMap("Multilingual")
if len(multilingual) == 0 { if len(multilingual) == 0 {
langConfigsList = append(langConfigsList, "") // TODO(bep) multilingo langConfigsList = append(langConfigsList, hugolib.NewLanguage("en"))
return return nil
} }
langConfigs = make(map[string]interface{}) var err error
for lang, config := range multilingual {
langConfigs[lang] = config langConfigsList, err = toSortedLanguages(multilingual)
langConfigsList = append(langConfigsList, lang)
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) } for lang, langConf := range l {
func (p langConfigsSortable) Less(i, j int) bool { return weightForLang(p[i]) < weightForLang(p[j]) } langsMap, ok := langConf.(map[string]interface{})
func (p langConfigsSortable) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func weightForLang(lang string) int { if !ok {
conf := langConfigs[lang] return nil, fmt.Errorf("Language config is not a map: %v", langsMap)
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
} }

View file

@ -1,43 +1,80 @@
package hugolib package hugolib
import ( import (
"sync"
"strings"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
type Multilingual struct { type Language struct {
enabled bool Lang string
config *viper.Viper Title string
Weight int
Languages []string params map[string]interface{}
paramsInit sync.Once
} }
func (ml *Multilingual) GetString(key string) string { return cast.ToString(ml.Get(key)) } func NewLanguage(lang string) *Language {
func (ml *Multilingual) GetStringMap(key string) map[string]interface{} { 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
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 (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)) return cast.ToStringMap(ml.Get(key))
} }
func (ml *Multilingual) GetStringMapString(key string) map[string]string { func (l *Language) GetStringMapString(key string) map[string]string {
return cast.ToStringMapString(ml.Get(key)) return cast.ToStringMapString(l.Get(key))
} }
func (ml *Multilingual) Get(key string) interface{} { func (l *Language) Get(key string) interface{} {
if ml != nil && ml.config != nil && ml.config.IsSet(key) { key = strings.ToLower(key)
return ml.config.Get(key) if v, ok := l.params[key]; ok {
return v
} }
return viper.Get(key) return viper.Get(key)
} }
func (s *Site) SetMultilingualConfig(currentLang string, orderedLanguages []string, langConfigs map[string]interface{}) { func (s *Site) SetMultilingualConfig(currentLang *Language, languages Languages) {
conf := viper.New()
for k, val := range cast.ToStringMap(langConfigs[currentLang]) { // TODO(bep) multilingo evaluate
conf.Set(k, val) viper.Set("CurrentLanguage", currentLang)
}
conf.Set("CurrentLanguage", currentLang)
ml := &Multilingual{ ml := &Multilingual{
enabled: len(langConfigs) > 0, enabled: len(languages) > 0,
config: conf, Languages: languages,
Languages: orderedLanguages,
} }
viper.Set("Multilingual", ml.enabled) viper.Set("Multilingual", ml.enabled)
s.Multilingual = ml s.Multilingual = ml
@ -46,3 +83,15 @@ func (s *Site) SetMultilingualConfig(currentLang string, orderedLanguages []stri
func (s *Site) multilingualEnabled() bool { func (s *Site) multilingualEnabled() bool {
return s.Multilingual != nil && s.Multilingual.enabled 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)
}

View file

@ -131,7 +131,7 @@ type SiteInfo struct {
Multilingual bool Multilingual bool
CurrentLanguage string CurrentLanguage string
LanguagePrefix string LanguagePrefix string
Languages []string Languages Languages
} }
// SiteSocial is a place to put social details on a site level. These are the // 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]} 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 return
} }
s.timerStep("load i18n") s.timerStep("load i18n")
@ -742,7 +742,7 @@ func (s *Site) setupTranslations() {
return return
} }
currentLang := s.Multilingual.GetString("CurrentLanguage") currentLang := currentLanguageString()
allTranslations := pagesToTranslationsMap(s.AllPages) allTranslations := pagesToTranslationsMap(s.AllPages)
assignTranslationsToPages(allTranslations, s.AllPages) assignTranslationsToPages(allTranslations, s.AllPages)
@ -817,7 +817,27 @@ func (s *Site) initialize() (err error) {
} }
func (s *Site) initializeSiteInfo() { 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) permalinks := make(PermalinkOverrides)
for k, v := range viper.GetStringMapString("Permalinks") { for k, v := range viper.GetStringMapString("Permalinks") {
@ -826,24 +846,20 @@ func (s *Site) initializeSiteInfo() {
languagePrefix := "" languagePrefix := ""
if s.multilingualEnabled() { if s.multilingualEnabled() {
languagePrefix = "/" + s.Multilingual.GetString("CurrentLanguage") languagePrefix = "/" + lang.Lang
}
languages := []string{}
if s.Multilingual != nil {
languages = s.Multilingual.Languages
} }
s.Info = SiteInfo{ s.Info = SiteInfo{
BaseURL: template.URL(helpers.SanitizeURLKeepTrailingSlash(viper.GetString("BaseURL"))), BaseURL: template.URL(helpers.SanitizeURLKeepTrailingSlash(viper.GetString("BaseURL"))),
Title: s.Multilingual.GetString("Title"), Title: lang.GetString("Title"),
Author: s.Multilingual.GetStringMap("author"), Author: lang.GetStringMap("author"),
Social: s.Multilingual.GetStringMapString("social"), Social: lang.GetStringMapString("social"),
LanguageCode: s.Multilingual.GetString("languagecode"), LanguageCode: lang.GetString("languagecode"),
Copyright: s.Multilingual.GetString("copyright"), Copyright: lang.GetString("copyright"),
DisqusShortname: s.Multilingual.GetString("DisqusShortname"), DisqusShortname: lang.GetString("DisqusShortname"),
// TODO(bep) multilang, consolidate the below (make into methods etc.)
Multilingual: s.multilingualEnabled(), Multilingual: s.multilingualEnabled(),
CurrentLanguage: s.Multilingual.GetString("CurrentLanguage"), CurrentLanguage: lang.Lang,
LanguagePrefix: languagePrefix, LanguagePrefix: languagePrefix,
Languages: languages, Languages: languages,
GoogleAnalytics: viper.GetString("GoogleAnalytics"), GoogleAnalytics: viper.GetString("GoogleAnalytics"),
@ -1594,7 +1610,7 @@ func (s *Site) newTaxonomyNode(t taxRenderInfo) (*Node, string) {
func (s *Site) addMultilingualPrefix(basePath string) string { func (s *Site) addMultilingualPrefix(basePath string) string {
hadPrefix := strings.HasPrefix(basePath, "/") hadPrefix := strings.HasPrefix(basePath, "/")
if s.multilingualEnabled() { if s.multilingualEnabled() {
basePath = path.Join(s.Multilingual.GetString("CurrentLanguage"), basePath) basePath = path.Join(currentLanguageString(), basePath)
if hadPrefix { if hadPrefix {
basePath = "/" + basePath basePath = "/" + basePath
} }

View file

@ -1402,13 +1402,13 @@ NOTE: should use the "permalinks" configuration with :filename
s := &Site{ s := &Site{
Source: &source.InMemorySource{ByteSource: sources}, Source: &source.InMemorySource{ByteSource: sources},
Multilingual: &Multilingual{ Multilingual: &Multilingual{
config: viper.New(),
enabled: true, enabled: true,
}, },
} }
// Multilingual settings // Multilingual settings
viper.Set("Multilingual", true) viper.Set("Multilingual", true)
s.Multilingual.config.Set("CurrentLanguage", "en") en := NewLanguage("en")
viper.Set("CurrentLanguage", en)
viper.Set("DefaultContentLanguage", "fr") viper.Set("DefaultContentLanguage", "fr")
viper.Set("paginate", "2") viper.Set("paginate", "2")