Make taxonomies configurable per language
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Fri, 5 Aug 2016 11:10:58 +0000 (13:10 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 6 Sep 2016 15:32:17 +0000 (18:32 +0300)
See #2312

commands/hugo.go
commands/multilingual.go [deleted file]
docs/content/content/multilingual.md
hugolib/config_test.go
hugolib/hugo_sites.go
hugolib/hugo_sites_test.go
hugolib/multilingual.go
hugolib/site.go
hugolib/taxonomy_test.go

index 9ad46b3bf27406b3a11251913f9f86f7eb0677de..3c5236268cf95f2e44b12418b57d8b10b586ba75 100644 (file)
@@ -493,12 +493,12 @@ func InitializeConfig(subCmdVs ...*cobra.Command) error {
                        helpers.HugoReleaseVersion(), minVersion)
        }
 
-       h, err := readMultilingualConfiguration()
+       h, err := hugolib.NewHugoSitesFromConfiguration()
 
        if err != nil {
                return err
        }
-       //TODO(bep) refactor ...
+       //TODO(bep) ml refactor ...
        Hugo = h
 
        return nil
diff --git a/commands/multilingual.go b/commands/multilingual.go
deleted file mode 100644 (file)
index 16f392a..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-package commands
-
-import (
-       "fmt"
-       "sort"
-
-       "strings"
-
-       "github.com/spf13/cast"
-       "github.com/spf13/hugo/hugolib"
-       "github.com/spf13/viper"
-)
-
-func readMultilingualConfiguration() (*hugolib.HugoSites, error) {
-       sites := make([]*hugolib.Site, 0)
-       multilingual := viper.GetStringMap("Languages")
-       if len(multilingual) == 0 {
-               // TODO(bep) multilingo langConfigsList = append(langConfigsList, hugolib.NewLanguage("en"))
-               sites = append(sites, hugolib.NewSite(hugolib.NewLanguage("en")))
-       }
-
-       if len(multilingual) > 0 {
-               var err error
-
-               languages, err := toSortedLanguages(multilingual)
-
-               if err != nil {
-                       return nil, fmt.Errorf("Failed to parse multilingual config: %s", err)
-               }
-
-               for _, lang := range languages {
-                       sites = append(sites, hugolib.NewSite(lang))
-               }
-
-       }
-
-       return hugolib.NewHugoSites(sites...)
-
-}
-
-func toSortedLanguages(l map[string]interface{}) (hugolib.Languages, error) {
-       langs := make(hugolib.Languages, len(l))
-       i := 0
-
-       for lang, langConf := range l {
-               langsMap, ok := langConf.(map[string]interface{})
-
-               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[i] = language
-               i++
-       }
-
-       sort.Sort(langs)
-
-       return langs, nil
-}
index bfcd6c08af3bd4f154011fc20baf002a45f8437e..1f73194eab877a00e60c1b4bb8de6bd25b926ba7 100644 (file)
@@ -38,6 +38,25 @@ and taxonomy pages will be rendered below `/en` in English, and below `/fr` in F
 
 Only the obvious non-global options can be overridden per language. Examples of global options are `BaseURL`, `BuildDrafts`, etc.
 
+Taxonomies configuration can also be set per language, example:
+
+```
+[Taxonomies]
+tag = "tags"
+
+[Languages]
+[Languages.en]
+weight = 1
+title = "English"
+
+[Languages.fr]
+weight = 2
+title = "Français"
+[Languages.fr.Taxonomies]
+plaque = "plaques"
+```
+
+
 ### Translating your content
 
 Translated articles are identified by the name of the content file.
index db0cb7117b18ec44d6d5b3297265caac59dbf63c..7bbb2670a415c974cc2e171c04990b9a584833bc 100644 (file)
@@ -28,9 +28,9 @@ func TestLoadGlobalConfig(t *testing.T) {
        PaginatePath = "side"
        `
 
-       writeSource(t, "config.toml", configContent)
+       writeSource(t, "hugo.toml", configContent)
 
-       require.NoError(t, LoadGlobalConfig("", "config.toml"))
+       require.NoError(t, LoadGlobalConfig("", "hugo.toml"))
        assert.Equal(t, "side", viper.GetString("PaginatePath"))
        // default
        assert.Equal(t, "layouts", viper.GetString("LayoutDir"))
index 8356030485ec98373f843fbc4b890b7ef1589cb1..e7a03394428ab7381cd759f1c36c5742de9a2b67 100644 (file)
@@ -15,6 +15,7 @@ package hugolib
 
 import (
        "errors"
+       "fmt"
        "strings"
        "sync"
        "time"
@@ -53,6 +54,34 @@ func NewHugoSites(sites ...*Site) (*HugoSites, error) {
        return &HugoSites{Multilingual: langConfig, Sites: sites}, nil
 }
 
+// NewHugoSitesFromConfiguration creates HugoSites from the global Viper config.
+func NewHugoSitesFromConfiguration() (*HugoSites, error) {
+       sites := make([]*Site, 0)
+       multilingual := viper.GetStringMap("Languages")
+       if len(multilingual) == 0 {
+               // TODO(bep) multilingo langConfigsList = append(langConfigsList, NewLanguage("en"))
+               sites = append(sites, NewSite(NewLanguage("en")))
+       }
+
+       if len(multilingual) > 0 {
+               var err error
+
+               languages, err := toSortedLanguages(multilingual)
+
+               if err != nil {
+                       return nil, fmt.Errorf("Failed to parse multilingual config: %s", err)
+               }
+
+               for _, lang := range languages {
+                       sites = append(sites, NewSite(lang))
+               }
+
+       }
+
+       return NewHugoSites(sites...)
+
+}
+
 // Reset resets the sites, making it ready for a full rebuild.
 // TODO(bep) multilingo
 func (h HugoSites) Reset() {
@@ -61,7 +90,7 @@ func (h HugoSites) Reset() {
        }
 }
 
-func (h HugoSites) siteInfos() []*SiteInfo {
+func (h HugoSites) toSiteInfos() []*SiteInfo {
        infos := make([]*SiteInfo, len(h.Sites))
        for i, s := range h.Sites {
                infos[i] = &s.Info
@@ -220,7 +249,7 @@ func (h *HugoSites) render() error {
        smLayouts := []string{"sitemapindex.xml", "_default/sitemapindex.xml", "_internal/_default/sitemapindex.xml"}
 
        if err := s.renderAndWriteXML("sitemapindex", sitemapDefault.Filename,
-               h.siteInfos(), s.appendThemeTemplates(smLayouts)...); err != nil {
+               h.toSiteInfos(), s.appendThemeTemplates(smLayouts)...); err != nil {
                return err
        }
 
index 8e5b6ae16be6259e211a65c60e8fafd43e7d37fb..266a4adb882c50a1519baf703c7edc163042892f 100644 (file)
@@ -22,8 +22,7 @@ import (
 
 func init() {
        testCommonResetState()
-       jww.SetStdoutThreshold(jww.LevelError)
-
+       jww.SetStdoutThreshold(jww.LevelCritical)
 }
 
 func testCommonResetState() {
@@ -38,8 +37,8 @@ func testCommonResetState() {
 
 }
 
-func TestMultiSites(t *testing.T) {
-
+func TestMultiSitesBuild(t *testing.T) {
+       testCommonResetState()
        sites := createMultiTestSites(t)
 
        err := sites.Build(BuildCfg{})
@@ -128,10 +127,20 @@ func TestMultiSites(t *testing.T) {
        sitemapFr := readDestination(t, "public/fr/sitemap.xml")
        require.True(t, strings.Contains(sitemapEn, "http://example.com/blog/en/sect/doc2/"), sitemapEn)
        require.True(t, strings.Contains(sitemapFr, "http://example.com/blog/fr/sect/doc1/"), sitemapFr)
+
+       // Check taxonomies
+       enTags := enSite.Taxonomies["tags"]
+       frTags := frSite.Taxonomies["plaques"]
+       require.Len(t, enTags, 2, fmt.Sprintf("Tags in en: %=v", enTags))
+       require.Len(t, frTags, 2, fmt.Sprintf("Tags in fr: %=v", frTags))
+       require.NotNil(t, enTags["tag1"])
+       require.NotNil(t, frTags["frtag1"])
+       readDestination(t, "public/fr/plaques/frtag1/index.html")
+       readDestination(t, "public/en/tags/tag1/index.html")
 }
 
 func TestMultiSitesRebuild(t *testing.T) {
-
+       testCommonResetState()
        sites := createMultiTestSites(t)
        cfg := BuildCfg{}
 
@@ -294,16 +303,6 @@ func TestMultiSitesRebuild(t *testing.T) {
 }
 
 func createMultiTestSites(t *testing.T) *HugoSites {
-       // General settings
-       hugofs.InitMemFs()
-
-       viper.Set("DefaultExtension", "html")
-       viper.Set("baseurl", "http://example.com/blog")
-       viper.Set("DisableSitemap", false)
-       viper.Set("DisableRSS", false)
-       viper.Set("RSSUri", "index.xml")
-       viper.Set("Taxonomies", map[string]string{"tag": "tags"})
-       viper.Set("Permalinks", map[string]string{"other": "/somewhere/else/:filename"})
 
        // Add some layouts
        if err := afero.WriteFile(hugofs.Source(),
@@ -362,9 +361,9 @@ NOTE: slug should be used as URL
 `)},
                {filepath.FromSlash("sect/doc1.fr.md"), []byte(`---
 title: doc1
-tags:
- - tag1
- - tag2
+plaques:
+ - frtag1
+ - frtag2
 publishdate: "2000-01-04"
 ---
 # doc1
@@ -393,8 +392,8 @@ NOTE: third 'en' doc, should trigger pagination on home page.
 `)},
                {filepath.FromSlash("sect/doc4.md"), []byte(`---
 title: doc4
-tags:
- - tag1
+plaques:
+ - frtag1
 publishdate: "2000-01-05"
 ---
 # doc4
@@ -446,13 +445,39 @@ draft: true
 `)},
        }
 
-       // Multilingual settings
-       viper.Set("Multilingual", true)
-       en := NewLanguage("en")
-       viper.Set("DefaultContentLanguage", "fr")
-       viper.Set("paginate", "2")
+       tomlConfig := `
+DefaultExtension = "html"
+baseurl = "http://example.com/blog"
+DisableSitemap = false
+DisableRSS = false
+RSSUri = "index.xml"
+
+paginate = 2
+DefaultContentLanguage = "fr"
+
+
+[permalinks]
+  other = "/somewhere/else/:filename"
+
+[Taxonomies]
+tag = "tags"
 
-       languages := NewLanguages(en, NewLanguage("fr"))
+[Languages]
+[Languages.en]
+weight = 1
+title = "English"
+
+[Languages.fr]
+weight = 2
+title = "Français"
+[Languages.fr.Taxonomies]
+plaque = "plaques"
+`
+
+       writeSource(t, "multilangconfig.toml", tomlConfig)
+       if err := LoadGlobalConfig("", "multilangconfig.toml"); err != nil {
+               t.Fatalf("Failed to load config: %s", err)
+       }
 
        // Hugo support using ByteSource's directly (for testing),
        // but to make it more real, we write them to the mem file system.
@@ -466,7 +491,8 @@ draft: true
        if err != nil {
                t.Fatalf("Unable to locate file")
        }
-       sites, err := newHugoSitesFromLanguages(languages)
+
+       sites, err := NewHugoSitesFromConfiguration()
 
        if err != nil {
                t.Fatalf("Failed to create sites: %s", err)
index 0bcc2a6972e7b7771f47c7db3f2b368fe361e7a5..8bc7bea3396b266299feb1c5dd5ed6a302f8988a 100644 (file)
@@ -6,6 +6,8 @@ import (
        "sort"
        "strings"
 
+       "fmt"
+
        "github.com/spf13/cast"
        "github.com/spf13/viper"
 )
@@ -112,3 +114,39 @@ func (s *Site) currentLanguageString() string {
 func (s *Site) currentLanguage() *Language {
        return s.Language
 }
+
+func toSortedLanguages(l map[string]interface{}) (Languages, error) {
+       langs := make(Languages, len(l))
+       i := 0
+
+       for lang, langConf := range l {
+               langsMap, ok := langConf.(map[string]interface{})
+
+               if !ok {
+                       return nil, fmt.Errorf("Language config is not a map: %v", langsMap)
+               }
+
+               language := 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[i] = language
+               i++
+       }
+
+       sort.Sort(langs)
+
+       return langs, nil
+}
index 06d7ed0743c114d07e7e8b86c25f03a040f9c6b9..ad438e2e51c73bf8e4fa56ed6d441abbd45a15c2 100644 (file)
@@ -1325,7 +1325,7 @@ func (s *Site) assembleMenus() {
 func (s *Site) assembleTaxonomies() {
        s.Taxonomies = make(TaxonomyList)
 
-       taxonomies := viper.GetStringMapString("Taxonomies")
+       taxonomies := s.Language.GetStringMapString("Taxonomies")
        jww.INFO.Printf("found taxonomies: %#v\n", taxonomies)
 
        for _, plural := range taxonomies {
@@ -1563,7 +1563,7 @@ func (s *Site) renderTaxonomiesLists() error {
 
        go errorCollator(results, errs)
 
-       taxonomies := viper.GetStringMapString("Taxonomies")
+       taxonomies := s.Language.GetStringMapString("Taxonomies")
        for singular, plural := range taxonomies {
                for key, pages := range s.Taxonomies[plural] {
                        taxes <- taxRenderInfo{key, pages, singular, plural}
@@ -1693,7 +1693,7 @@ func taxonomyRenderer(s *Site, taxes <-chan taxRenderInfo, results chan<- error,
 
 // renderListsOfTaxonomyTerms renders a page per taxonomy that lists the terms for that taxonomy
 func (s *Site) renderListsOfTaxonomyTerms() (err error) {
-       taxonomies := viper.GetStringMapString("Taxonomies")
+       taxonomies := s.Language.GetStringMapString("Taxonomies")
        for singular, plural := range taxonomies {
                n := s.newNode()
                n.Title = strings.Title(plural)
@@ -1969,7 +1969,7 @@ func (s *Site) Stats() {
        jww.FEEDBACK.Printf("%d pages created\n", len(s.Pages))
        jww.FEEDBACK.Printf("%d non-page files copied\n", len(s.Files))
        jww.FEEDBACK.Printf("%d paginator pages created\n", s.Info.paginationPageCount)
-       taxonomies := viper.GetStringMapString("Taxonomies")
+       taxonomies := s.Language.GetStringMapString("Taxonomies")
 
        for _, pl := range taxonomies {
                jww.FEEDBACK.Printf("%d %s created\n", len(s.Taxonomies[pl]), pl)
index 9b83f7627ad592a909407aa845a0cfddc96e89c1..1d3bbe932a992dfeb8abf0ab7bf8cbcb24cbc3fc 100644 (file)
@@ -30,7 +30,7 @@ func TestByCountOrderOfTaxonomies(t *testing.T) {
 
        viper.Set("taxonomies", taxonomies)
 
-       site := new(Site)
+       site := newSiteDefaultLang()
        page, _ := NewPageFrom(strings.NewReader(pageYamlWithTaxonomiesA), "path/to/page")
        site.Pages = append(site.Pages, page)
        site.assembleTaxonomies()