]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
tpl: Fix indeterminate template lookup with templates with and without lang
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 21 Apr 2025 16:02:50 +0000 (18:02 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 22 Apr 2025 15:29:39 +0000 (17:29 +0200)
Close #13636

hugolib/alias.go
hugolib/sitemap_test.go
tpl/tplimpl/templatedescriptor.go
tpl/tplimpl/templatestore.go
tpl/tplimpl/templatestore_integration_test.go

index 0bb3165c7333f37666e6e5c8e5cf81df82eeff11..7b252c6131aba2f1e15f2c36cd6f2b64e07c0fda 100644 (file)
@@ -56,6 +56,7 @@ func (a aliasHandler) renderAlias(permalink string, p page.Page) (io.Reader, err
        templateDesc.LayoutFromUser = ""
        templateDesc.Kind = ""
        templateDesc.OutputFormat = output.AliasHTMLFormat.Name
+       templateDesc.MediaType = output.AliasHTMLFormat.MediaType.Type
 
        q := tplimpl.TemplateQuery{
                Path:     base,
index 1c2642468a25783e2a5e68a120bb741714c24fd5..922ecbc12e3980fca3b9b867bdbda8b996592123 100644 (file)
@@ -139,7 +139,7 @@ weight = 1
 languageName = "English"
 [languages.nn]
 weight = 2
--- layouts/_default/list.xml --
+-- layouts/list.xml --
 Site: {{ .Site.Title }}|
 -- layouts/home --
 Home.
index 8b50605ac8fbd65aefa8aea000b75982556a61b1..f65ad3943104fc444785a2f084a3c5c08c15edc9 100644 (file)
@@ -64,7 +64,7 @@ func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool
                return weightNoMatch
        }
 
-       w := this.doCompare(category, isEmbedded, other)
+       w := this.doCompare(category, isEmbedded, s.opts.DefaultContentLanguage, other)
 
        if w.w1 <= 0 {
                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.
-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
 
        // 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.
        }
 
+       if other.MediaType != this.MediaType {
+               return w
+       }
+
        // One example of variant1 and 2 is for render codeblocks:
        // variant1=codeblock, variant2=go (language).
        if other.Variant1 != "" && other.Variant1 != this.Variant1 {
@@ -142,14 +146,15 @@ func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, oth
        }
 
        const (
-               weightKind           = 3 // page, home, section, taxonomy, term (and only those)
-               weightcustomLayout   = 4 // custom layout (mylayout, set in e.g. front matter)
-               weightLayoutStandard = 2 // standard layouts (single,list,all)
-               weightOutputFormat   = 2 // a configured output format (e.g. rss, html, json)
+               weightKind           = 5 // page, home, section, taxonomy, term (and only those)
+               weightcustomLayout   = 6 // custom layout (mylayout, set in e.g. front matter)
+               weightLayoutStandard = 4 // standard layouts (single,list)
+               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)
                weightLang           = 1 // a configured language (e.g. en, nn, fr, ...)
-               weightVariant1       = 4 // currently used for render hooks, e.g. "link", "image"
-               weightVariant2       = 2 // currently used for render hooks, e.g. the language "go" in code blocks.
+               weightVariant1       = 6 // currently used for render hooks, e.g. "link", "image"
+               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
                // 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
        }
 
-       if other.LayoutFromTemplate != "" && (other.LayoutFromTemplate == this.LayoutFromTemplate || other.LayoutFromTemplate == layoutAll) {
+       if other.LayoutFromTemplate != "" && (other.LayoutFromTemplate == this.LayoutFromTemplate) {
                w.w1 += weightLayoutStandard
                w.w2 = weight2Group1
-
+       } else if other.LayoutFromTemplate == layoutAll {
+               w.w1 += weightLayoutAll
+               w.w2 = weight2Group1
        }
 
        // 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
        }
 
-       if other.Lang != "" && other.Lang == this.Lang {
+       if (other.Lang != "" && other.Lang == this.Lang) || (other.Lang == "" && this.Lang == defaultContentLanguage) {
                w.w1 += weightLang
                w.w3 += weight3
        }
index 7770d053bf2ae515bd2c9bd9c58473f3d940cc0e..5be65f874f2ee3449de19fd13c5f02ce73172e85 100644 (file)
@@ -1842,7 +1842,9 @@ func (best *bestMatch) isBetter(w weight, ti *TemplInfo) bool {
                // Anything is better than nothing.
                return true
        }
+
        if w.w1 <= 0 {
+
                if best.w.w1 <= 0 {
                        return ti.PathInfo.Path() < best.templ.PathInfo.Path()
                }
@@ -1885,11 +1887,7 @@ func (best *bestMatch) isBetter(w weight, ti *TemplInfo) bool {
                        return true
                }
 
-               if ti.D.LayoutFromTemplate != "" && best.desc.LayoutFromTemplate != "" {
-                       return ti.D.LayoutFromTemplate != layoutAll
-               }
-
-               return w.distance < best.w.distance || ti.PathInfo.Path() < best.templ.PathInfo.Path()
+               return ti.PathInfo.Path() < best.templ.PathInfo.Path()
        }
 
        return true
index 51b28754fa09824648f7ce19cf774b7174657140..06cb00212b131b3a8713471229dbe089ac2940f3 100644 (file)
@@ -3,6 +3,7 @@ package tplimpl_test
 import (
        "context"
        "io"
+       "strings"
        "testing"
 
        qt "github.com/frankban/quicktest"
@@ -684,6 +685,102 @@ layout: mylayout
        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) {
        t.Parallel()