shithub: hugo

Download patch

ref: 90de511017f9dcc65cccd7d161c70f326df3ab5b
parent: 36f2a1f676c6e8821d2d1600c696dcb2658d1cc9
author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
date: Fri Aug 5 09:10:58 EDT 2016

Make taxonomies configurable per language

See #2312

--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -493,12 +493,12 @@
 			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
--- a/commands/multilingual.go
+++ /dev/null
@@ -1,75 +1,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
-}
--- a/docs/content/content/multilingual.md
+++ b/docs/content/content/multilingual.md
@@ -38,6 +38,25 @@
 
 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.
--- a/hugolib/config_test.go
+++ b/hugolib/config_test.go
@@ -28,9 +28,9 @@
 	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"))
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -15,6 +15,7 @@
 
 import (
 	"errors"
+	"fmt"
 	"strings"
 	"sync"
 	"time"
@@ -53,6 +54,34 @@
 	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) 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 @@
 	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
 	}
 
--- a/hugolib/hugo_sites_test.go
+++ b/hugolib/hugo_sites_test.go
@@ -22,8 +22,7 @@
 
 func init() {
 	testCommonResetState()
-	jww.SetStdoutThreshold(jww.LevelError)
-
+	jww.SetStdoutThreshold(jww.LevelCritical)
 }
 
 func testCommonResetState() {
@@ -38,8 +37,8 @@
 
 }
 
-func TestMultiSites(t *testing.T) {
-
+func TestMultiSitesBuild(t *testing.T) {
+	testCommonResetState()
 	sites := createMultiTestSites(t)
 
 	err := sites.Build(BuildCfg{})
@@ -128,10 +127,20 @@
 	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,17 +303,7 @@
 }
 
 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(),
 		filepath.Join("layouts", "_default/single.html"),
@@ -362,9 +361,9 @@
 `)},
 		{filepath.FromSlash("sect/doc1.fr.md"), []byte(`---
 title: doc1
-tags:
- - tag1
- - tag2
+plaques:
+ - frtag1
+ - frtag2
 publishdate: "2000-01-04"
 ---
 # doc1
@@ -393,8 +392,8 @@
 `)},
 		{filepath.FromSlash("sect/doc4.md"), []byte(`---
 title: doc4
-tags:
- - tag1
+plaques:
+ - frtag1
 publishdate: "2000-01-05"
 ---
 # doc4
@@ -446,14 +445,40 @@
 `)},
 	}
 
-	// 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"
 
-	languages := NewLanguages(en, NewLanguage("fr"))
+paginate = 2
+DefaultContentLanguage = "fr"
 
+
+[permalinks]
+  other = "/somewhere/else/:filename"
+
+[Taxonomies]
+tag = "tags"
+
+[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.
 	for _, s := range sources {
@@ -466,7 +491,8 @@
 	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)
--- a/hugolib/multilingual.go
+++ b/hugolib/multilingual.go
@@ -6,6 +6,8 @@
 	"sort"
 	"strings"
 
+	"fmt"
+
 	"github.com/spf13/cast"
 	"github.com/spf13/viper"
 )
@@ -111,4 +113,40 @@
 
 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
 }
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -1325,7 +1325,7 @@
 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 @@
 
 	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 @@
 
 // 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 @@
 	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)
--- a/hugolib/taxonomy_test.go
+++ b/hugolib/taxonomy_test.go
@@ -30,7 +30,7 @@
 
 	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()
--