Fix auto-creation of root sections in multilingual sites

Fixes #14681

Co-authored-by: Joe Mooring <joe@mooring.com>
This commit is contained in:
Bjørn Erik Pedersen
2026-04-06 18:01:22 +02:00
parent 0755872424
commit ce009e3aa9
2 changed files with 109 additions and 5 deletions
+50 -5
View File
@@ -497,14 +497,14 @@ func (a *allPagesAssembler) doCreatePages(prefix string, depth int) error {
isTaxonomy := !a.h.getFirstTaxonomyConfig(s).IsZero()
isRootSection := !isTaxonomy && level == 1 && cnh.isBranchNode(n)
if isRootSection {
// This is a root section.
a.seenRootSections.SetIfAbsent(cnh.PathInfo(n).Section(), true)
} else if !isTaxonomy {
if !isTaxonomy {
p := cnh.PathInfo(n)
rootSection := p.Section()
_, err := a.seenRootSections.GetOrCreate(rootSection, func() (bool, error) {
if isRootSection {
return true, nil
}
// Try to preserve the original casing if possible.
sectionUnnormalized := p.Unnormalized().Section()
rootSectionPath := a.h.Conf.PathParser().Parse(files.ComponentFolderContent, "/"+sectionUnnormalized+"/_index.md")
@@ -520,6 +520,51 @@ func (a *allPagesAssembler) doCreatePages(prefix string, depth int) error {
return true, err
}
treePages.InsertRaw(rootSectionPath.Base(), rootSectionPages)
// Collect vectors from descendant pages to create section
// pages for all languages that have content in this section.
nm, replaced := contentNodeToContentNodesPage(rootSectionPages)
if replaced {
treePages.InsertRaw(rootSectionPath.Base(), nm)
}
missingVectors := sitesmatrix.Vectors{}
pw.WalkContext.AddEventListener("sitesmatrix", rootSectionPath.Base(),
func(e *doctree.Event[contentNode]) {
if cnh.isBranchNode(e.Source) && !a.h.getFirstTaxonomyConfig(e.Path).IsZero() {
return
}
n := e.Source
e.StopPropagation()
n.forEeachContentNode(
func(vec sitesmatrix.Vector, nn contentNode) bool {
if _, found := nm[vec]; !found {
missingVectors[vec] = struct{}{}
}
return true
})
},
)
pw.WalkContext.HooksPost().Push(
func() error {
if len(missingVectors) > 0 {
vec := missingVectors.VectorSample()
nm[vec] = &pageMetaSource{
pathInfo: rootSectionPath,
sitesMatrixBase: missingVectors,
sitesMatrixBaseOnly: true,
pageConfigSource: &pagemeta.PageConfigEarly{
Kind: kinds.KindSection,
},
}
_, _, err := transformPages(rootSectionPath.Base(), nm, cascades)
if err != nil {
return err
}
}
return nil
},
)
return true, nil
})
if err != nil {
+59
View File
@@ -171,6 +171,65 @@ title: "p4 theme (nl)"
b.AssertFileContent("public/en/index.html", `home (en): en: p1 (en)|p2 (en)|p3 (en)|:END`)
}
// Issue 14681
func TestPublishMultilingualSectionCreation(t *testing.T) {
t.Parallel()
files := `
-- hugo.toml --
capitalizeListTitles = false
pluralizeListTitles = false
disableKinds = ['rss','sitemap','taxonomy','term']
defaultContentLanguage = "fr"
defaultContentLanguageInSubdir = true
[languages.fr]
contentDir = "content/fr"
weight = 1
[languages.en]
contentDir = "content/en"
weight = 2
[languages.de]
contentDir = "content/de"
weight = 3
-- layouts/home.html --
HOME {{ .Language.Name }}
-- layouts/page.html --
{{ .Title }} {{ .Language.Name }}
-- layouts/section.html --
{{ .Title }} {{ .Language.Name }}
-- content/de/s1/p1.md --
---
title: p1
---
-- content/en/s1/p2.md --
---
title: p2
---
-- content/fr/s1/p3.md --
---
title: p3
---
`
b := Test(t, files)
b.AssertFileContent("public/de/index.html", "HOME de")
b.AssertFileContent("public/de/s1/index.html", "s1 de")
b.AssertFileContent("public/de/s1/p1/index.html", "p1 de")
b.AssertFileContent("public/en/index.html", "HOME en")
b.AssertFileContent("public/en/s1/index.html", "s1 en") // fail (file does not exist)
b.AssertFileContent("public/en/s1/p2/index.html", "p2 en")
b.AssertFileContent("public/fr/index.html", "HOME fr")
b.AssertFileContent("public/fr/s1/index.html", "s1 fr") // fail (file does not exist)
b.AssertFileContent("public/fr/s1/p3/index.html", "p3 fr")
}
// Issue 13993
func TestIssue13993(t *testing.T) {
t.Parallel()