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)
}
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()))

View 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))
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)
}
m := cast.ToStringMap(conf)
return cast.ToInt(m["weight"])
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)
}
sort.Sort(langs)
return langs, nil
}

View file

@ -1,43 +1,80 @@
package hugolib
import (
"sync"
"strings"
"github.com/spf13/cast"
"github.com/spf13/viper"
)
type Multilingual struct {
enabled bool
config *viper.Viper
Languages []string
type Language struct {
Lang string
Title string
Weight int
params map[string]interface{}
paramsInit sync.Once
}
func (ml *Multilingual) GetString(key string) string { return cast.ToString(ml.Get(key)) }
func (ml *Multilingual) GetStringMap(key string) map[string]interface{} {
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
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))
}
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)
}

View 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"),
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
}

View 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")