From 90de511017f9dcc65cccd7d161c70f326df3ab5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Fri, 5 Aug 2016 13:10:58 +0200 Subject: [PATCH] Make taxonomies configurable per language See #2312 --- commands/hugo.go | 4 +- commands/multilingual.go | 75 -------------------------- docs/content/content/multilingual.md | 19 +++++++ hugolib/config_test.go | 4 +- hugolib/hugo_sites.go | 33 +++++++++++- hugolib/hugo_sites_test.go | 80 ++++++++++++++++++---------- hugolib/multilingual.go | 38 +++++++++++++ hugolib/site.go | 8 +-- hugolib/taxonomy_test.go | 2 +- 9 files changed, 150 insertions(+), 113 deletions(-) delete mode 100644 commands/multilingual.go diff --git a/commands/hugo.go b/commands/hugo.go index 9ad46b3bf..3c5236268 100644 --- a/commands/hugo.go +++ b/commands/hugo.go @@ -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 index 16f392acc..000000000 --- a/commands/multilingual.go +++ /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 -} diff --git a/docs/content/content/multilingual.md b/docs/content/content/multilingual.md index bfcd6c08a..1f73194ea 100644 --- a/docs/content/content/multilingual.md +++ b/docs/content/content/multilingual.md @@ -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. diff --git a/hugolib/config_test.go b/hugolib/config_test.go index db0cb7117..7bbb2670a 100644 --- a/hugolib/config_test.go +++ b/hugolib/config_test.go @@ -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")) diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 835603048..e7a033944 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -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 } diff --git a/hugolib/hugo_sites_test.go b/hugolib/hugo_sites_test.go index 8e5b6ae16..266a4adb8 100644 --- a/hugolib/hugo_sites_test.go +++ b/hugolib/hugo_sites_test.go @@ -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" - 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. @@ -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) diff --git a/hugolib/multilingual.go b/hugolib/multilingual.go index 0bcc2a697..8bc7bea33 100644 --- a/hugolib/multilingual.go +++ b/hugolib/multilingual.go @@ -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 +} diff --git a/hugolib/site.go b/hugolib/site.go index 06d7ed074..ad438e2e5 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -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) diff --git a/hugolib/taxonomy_test.go b/hugolib/taxonomy_test.go index 9b83f7627..1d3bbe932 100644 --- a/hugolib/taxonomy_test.go +++ b/hugolib/taxonomy_test.go @@ -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()