mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-18 21:11:19 +02:00
tpl: Fix indeterminate template lookup with templates with and without lang
Close #13636
This commit is contained in:
@@ -56,6 +56,7 @@ func (a aliasHandler) renderAlias(permalink string, p page.Page) (io.Reader, err
|
|||||||
templateDesc.LayoutFromUser = ""
|
templateDesc.LayoutFromUser = ""
|
||||||
templateDesc.Kind = ""
|
templateDesc.Kind = ""
|
||||||
templateDesc.OutputFormat = output.AliasHTMLFormat.Name
|
templateDesc.OutputFormat = output.AliasHTMLFormat.Name
|
||||||
|
templateDesc.MediaType = output.AliasHTMLFormat.MediaType.Type
|
||||||
|
|
||||||
q := tplimpl.TemplateQuery{
|
q := tplimpl.TemplateQuery{
|
||||||
Path: base,
|
Path: base,
|
||||||
|
@@ -139,7 +139,7 @@ weight = 1
|
|||||||
languageName = "English"
|
languageName = "English"
|
||||||
[languages.nn]
|
[languages.nn]
|
||||||
weight = 2
|
weight = 2
|
||||||
-- layouts/_default/list.xml --
|
-- layouts/list.xml --
|
||||||
Site: {{ .Site.Title }}|
|
Site: {{ .Site.Title }}|
|
||||||
-- layouts/home --
|
-- layouts/home --
|
||||||
Home.
|
Home.
|
||||||
|
@@ -64,7 +64,7 @@ func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool
|
|||||||
return weightNoMatch
|
return weightNoMatch
|
||||||
}
|
}
|
||||||
|
|
||||||
w := this.doCompare(category, isEmbedded, other)
|
w := this.doCompare(category, isEmbedded, s.opts.DefaultContentLanguage, other)
|
||||||
|
|
||||||
if w.w1 <= 0 {
|
if w.w1 <= 0 {
|
||||||
if category == CategoryMarkup && (this.Variant1 == other.Variant1) && (this.Variant2 == other.Variant2 || this.Variant2 != "" && other.Variant2 == "") {
|
if category == CategoryMarkup && (this.Variant1 == other.Variant1) && (this.Variant2 == other.Variant2 || this.Variant2 != "" && other.Variant2 == "") {
|
||||||
@@ -82,7 +82,7 @@ func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
//lint:ignore ST1006 this vs other makes it easier to reason about.
|
//lint:ignore ST1006 this vs other makes it easier to reason about.
|
||||||
func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, other TemplateDescriptor) weight {
|
func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, defaultContentLanguage string, other TemplateDescriptor) weight {
|
||||||
w := weightNoMatch
|
w := weightNoMatch
|
||||||
|
|
||||||
// HTML in plain text is OK, but not the other way around.
|
// HTML in plain text is OK, but not the other way around.
|
||||||
@@ -124,6 +124,10 @@ func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, oth
|
|||||||
// Continue.
|
// Continue.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if other.MediaType != this.MediaType {
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
// One example of variant1 and 2 is for render codeblocks:
|
// One example of variant1 and 2 is for render codeblocks:
|
||||||
// variant1=codeblock, variant2=go (language).
|
// variant1=codeblock, variant2=go (language).
|
||||||
if other.Variant1 != "" && other.Variant1 != this.Variant1 {
|
if other.Variant1 != "" && other.Variant1 != this.Variant1 {
|
||||||
@@ -142,14 +146,15 @@ func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, oth
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
weightKind = 3 // page, home, section, taxonomy, term (and only those)
|
weightKind = 5 // page, home, section, taxonomy, term (and only those)
|
||||||
weightcustomLayout = 4 // custom layout (mylayout, set in e.g. front matter)
|
weightcustomLayout = 6 // custom layout (mylayout, set in e.g. front matter)
|
||||||
weightLayoutStandard = 2 // standard layouts (single,list,all)
|
weightLayoutStandard = 4 // standard layouts (single,list)
|
||||||
weightOutputFormat = 2 // a configured output format (e.g. rss, html, json)
|
weightLayoutAll = 2 // the "all" layout
|
||||||
|
weightOutputFormat = 4 // a configured output format (e.g. rss, html, json)
|
||||||
weightMediaType = 1 // a configured media type (e.g. text/html, text/plain)
|
weightMediaType = 1 // a configured media type (e.g. text/html, text/plain)
|
||||||
weightLang = 1 // a configured language (e.g. en, nn, fr, ...)
|
weightLang = 1 // a configured language (e.g. en, nn, fr, ...)
|
||||||
weightVariant1 = 4 // currently used for render hooks, e.g. "link", "image"
|
weightVariant1 = 6 // currently used for render hooks, e.g. "link", "image"
|
||||||
weightVariant2 = 2 // currently used for render hooks, e.g. the language "go" in code blocks.
|
weightVariant2 = 4 // currently used for render hooks, e.g. the language "go" in code blocks.
|
||||||
|
|
||||||
// We will use the values for group 2 and 3
|
// We will use the values for group 2 and 3
|
||||||
// if the distance up to the template is shorter than
|
// if the distance up to the template is shorter than
|
||||||
@@ -173,10 +178,12 @@ func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, oth
|
|||||||
w.w2 = weight2Group1
|
w.w2 = weight2Group1
|
||||||
}
|
}
|
||||||
|
|
||||||
if other.LayoutFromTemplate != "" && (other.LayoutFromTemplate == this.LayoutFromTemplate || other.LayoutFromTemplate == layoutAll) {
|
if other.LayoutFromTemplate != "" && (other.LayoutFromTemplate == this.LayoutFromTemplate) {
|
||||||
w.w1 += weightLayoutStandard
|
w.w1 += weightLayoutStandard
|
||||||
w.w2 = weight2Group1
|
w.w2 = weight2Group1
|
||||||
|
} else if other.LayoutFromTemplate == layoutAll {
|
||||||
|
w.w1 += weightLayoutAll
|
||||||
|
w.w2 = weight2Group1
|
||||||
}
|
}
|
||||||
|
|
||||||
// LayoutCustom is only set in this (usually from Page.Layout).
|
// LayoutCustom is only set in this (usually from Page.Layout).
|
||||||
@@ -185,7 +192,7 @@ func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, oth
|
|||||||
w.w2 = weight2Group2
|
w.w2 = weight2Group2
|
||||||
}
|
}
|
||||||
|
|
||||||
if other.Lang != "" && other.Lang == this.Lang {
|
if (other.Lang != "" && other.Lang == this.Lang) || (other.Lang == "" && this.Lang == defaultContentLanguage) {
|
||||||
w.w1 += weightLang
|
w.w1 += weightLang
|
||||||
w.w3 += weight3
|
w.w3 += weight3
|
||||||
}
|
}
|
||||||
|
@@ -1842,7 +1842,9 @@ func (best *bestMatch) isBetter(w weight, ti *TemplInfo) bool {
|
|||||||
// Anything is better than nothing.
|
// Anything is better than nothing.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.w1 <= 0 {
|
if w.w1 <= 0 {
|
||||||
|
|
||||||
if best.w.w1 <= 0 {
|
if best.w.w1 <= 0 {
|
||||||
return ti.PathInfo.Path() < best.templ.PathInfo.Path()
|
return ti.PathInfo.Path() < best.templ.PathInfo.Path()
|
||||||
}
|
}
|
||||||
@@ -1885,11 +1887,7 @@ func (best *bestMatch) isBetter(w weight, ti *TemplInfo) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if ti.D.LayoutFromTemplate != "" && best.desc.LayoutFromTemplate != "" {
|
return ti.PathInfo.Path() < best.templ.PathInfo.Path()
|
||||||
return ti.D.LayoutFromTemplate != layoutAll
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.distance < best.w.distance || ti.PathInfo.Path() < best.templ.PathInfo.Path()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@@ -3,6 +3,7 @@ package tplimpl_test
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
@@ -684,6 +685,102 @@ layout: mylayout
|
|||||||
b.AssertFileContent("public/en/foo/index.xml", "layouts/list.xml")
|
b.AssertFileContent("public/en/foo/index.xml", "layouts/list.xml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLookupOrderIssue13636(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
filesTemplate := `
|
||||||
|
-- hugo.toml --
|
||||||
|
defaultContentLanguage = "en"
|
||||||
|
defaultContentLanguageInSubdir = true
|
||||||
|
[languages]
|
||||||
|
[languages.en]
|
||||||
|
weight = 1
|
||||||
|
[languages.nn]
|
||||||
|
weight = 2
|
||||||
|
-- content/s1/p1.en.md --
|
||||||
|
---
|
||||||
|
outputs: ["html", "amp", "json"]
|
||||||
|
---
|
||||||
|
-- content/s1/p1.nn.md --
|
||||||
|
---
|
||||||
|
outputs: ["html", "amp", "json"]
|
||||||
|
---
|
||||||
|
-- layouts/L1 --
|
||||||
|
L1
|
||||||
|
-- layouts/L2 --
|
||||||
|
L2
|
||||||
|
-- layouts/L3 --
|
||||||
|
L3
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
Lang string
|
||||||
|
L1 string
|
||||||
|
L2 string
|
||||||
|
L3 string
|
||||||
|
ExpectHTML string
|
||||||
|
ExpectAmp string
|
||||||
|
ExpectJSON string
|
||||||
|
}{
|
||||||
|
{"en", "all.en.html", "all.html", "single.html", "single.html", "single.html", ""},
|
||||||
|
{"en", "all.amp.html", "all.html", "page.html", "page.html", "all.amp.html", ""},
|
||||||
|
{"en", "all.amp.html", "all.html", "list.html", "all.html", "all.amp.html", ""},
|
||||||
|
{"en", "all.en.html", "all.json", "single.html", "single.html", "single.html", "all.json"},
|
||||||
|
{"en", "all.en.html", "single.json", "single.html", "single.html", "single.html", "single.json"},
|
||||||
|
{"en", "all.en.html", "all.html", "list.html", "all.en.html", "all.en.html", ""},
|
||||||
|
{"en", "list.en.html", "list.html", "list.en.html", "", "", ""},
|
||||||
|
{"nn", "all.en.html", "all.html", "single.html", "single.html", "single.html", ""},
|
||||||
|
{"nn", "all.en.html", "all.nn.html", "single.html", "single.html", "single.html", ""},
|
||||||
|
{"nn", "all.en.html", "all.nn.html", "single.nn.html", "single.nn.html", "single.nn.html", ""},
|
||||||
|
{"nn", "single.json", "single.nn.json", "all.json", "", "", "single.nn.json"},
|
||||||
|
{"nn", "single.json", "single.en.json", "all.nn.json", "", "", "single.json"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
if i != 8 {
|
||||||
|
// continue
|
||||||
|
}
|
||||||
|
files := strings.ReplaceAll(filesTemplate, "L1", test.L1)
|
||||||
|
files = strings.ReplaceAll(files, "L2", test.L2)
|
||||||
|
files = strings.ReplaceAll(files, "L3", test.L3)
|
||||||
|
t.Logf("Test %d: %s %s %s %s", i, test.Lang, test.L1, test.L2, test.L3)
|
||||||
|
|
||||||
|
for range 3 {
|
||||||
|
b := hugolib.Test(t, files)
|
||||||
|
b.Assert(len(b.H.Sites), qt.Equals, 2)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pubhHTML = "public/LANG/s1/p1/index.html"
|
||||||
|
pubhAmp = "public/LANG/amp/s1/p1/index.html"
|
||||||
|
pubhJSON = "public/LANG/s1/p1/index.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
pubhHTML = strings.ReplaceAll(pubhHTML, "LANG", test.Lang)
|
||||||
|
pubhAmp = strings.ReplaceAll(pubhAmp, "LANG", test.Lang)
|
||||||
|
pubhJSON = strings.ReplaceAll(pubhJSON, "LANG", test.Lang)
|
||||||
|
|
||||||
|
if test.ExpectHTML != "" {
|
||||||
|
b.AssertFileContent(pubhHTML, test.ExpectHTML)
|
||||||
|
} else {
|
||||||
|
b.AssertFileExists(pubhHTML, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if test.ExpectAmp != "" {
|
||||||
|
b.AssertFileContent(pubhAmp, test.ExpectAmp)
|
||||||
|
} else {
|
||||||
|
b.AssertFileExists(pubhAmp, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if test.ExpectJSON != "" {
|
||||||
|
b.AssertFileContent(pubhJSON, test.ExpectJSON)
|
||||||
|
} else {
|
||||||
|
b.AssertFileExists(pubhJSON, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLookupShortcodeDepth(t *testing.T) {
|
func TestLookupShortcodeDepth(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user