Repository: gohugoio/hugo (language: go)

Issue:
Revert the Resource.Name normalization
I don't think it's needed. I'm not totally sure about that, but I need to have a look before people start using this new method.


Discussion / hints:
It would be useful to obtain "Sunrise in Bryce Canyon.jpg" instead of "sunrise-in-bryce-canyon.jpg", where the file name is the meta data. An alternative (without additional front matter) is to do:

```text
{{ path.Base .Key | something.QueryUnescape }}
```


I mainly created this issue to "think about this" before committing to this new API. 
We scratched this particular user itch by running exiftool recursively before each build, stuffing the file name (less extension) in the ImageDescription EXIF tag.

Fix patch:
diff --git a/hugolib/content_map_page.go b/hugolib/content_map_page.go
index ee7f2267615..ba0c858fea7 100644
--- a/hugolib/content_map_page.go
+++ b/hugolib/content_map_page.go
@@ -542,7 +542,7 @@ func (m *pageMap) getOrCreateResourcesForPage(ps *pageState) resource.Resources
 				for _, r := range res2 {
 					var found bool
 					for _, r2 := range res {
-						if r2.Name() == r.Name() {
+						if r2.(resource.NameNormalizedProvider).NameNormalized() == r.(resource.NameNormalizedProvider).NameNormalized() {
 							found = true
 							break
 						}
@@ -1633,7 +1633,7 @@ func (sa *sitePagesAssembler) assembleResources() error {
 						TargetBasePaths:      targetBasePaths,
 						BasePathRelPermalink: targetPaths.SubResourceBaseLink,
 						BasePathTargetPath:   baseTarget,
-						Name:                 relPath,
+						NameNormalized:       relPath,
 						NameOriginal:         relPathOriginal,
 						LazyPublish:          !ps.m.pageConfig.Build.PublishResources,
 					}
diff --git a/resources/image.go b/resources/image.go
index 2e351bd28d0..78a57bb533d 100644
--- a/resources/image.go
+++ b/resources/image.go
@@ -48,10 +48,10 @@ import (
 )
 
 var (
-	_ images.ImageResource          = (*imageResource)(nil)
-	_ resource.Source               = (*imageResource)(nil)
-	_ resource.Cloner               = (*imageResource)(nil)
-	_ resource.NameOriginalProvider = (*imageResource)(nil)
+	_ images.ImageResource            = (*imageResource)(nil)
+	_ resource.Source                 = (*imageResource)(nil)
+	_ resource.Cloner                 = (*imageResource)(nil)
+	_ resource.NameNormalizedProvider = (*imageResource)(nil)
 )
 
 // imageResource represents an image resource.
diff --git a/resources/resource.go b/resources/resource.go
index 73a0ad56e58..867b262fb02 100644
--- a/resources/resource.go
+++ b/resources/resource.go
@@ -59,8 +59,8 @@ type ResourceSourceDescriptor struct {
 	// The canonical source path.
 	Path *paths.Path
 
-	// The name of the resource.
-	Name string
+	// The normalized name of the resource.
+	NameNormalized string
 
 	// The name of the resource as it was read from the source.
 	NameOriginal string
@@ -135,12 +135,12 @@ func (fd *ResourceSourceDescriptor) init(r *Spec) error {
 		fd.TargetBasePaths[i] = dir
 	}
 
-	if fd.Name == "" {
-		fd.Name = fd.TargetPath
+	if fd.NameNormalized == "" {
+		fd.NameNormalized = fd.TargetPath
 	}
 
 	if fd.NameOriginal == "" {
-		fd.NameOriginal = fd.Name
+		fd.NameOriginal = fd.NameNormalized
 	}
 
 	mediaType := fd.MediaType
@@ -228,7 +228,7 @@ type baseResourceResource interface {
 
 type baseResourceInternal interface {
 	resource.Source
-	resource.NameOriginalProvider
+	resource.NameNormalizedProvider
 
 	fileInfo
 	mediaTypeAssigner
@@ -457,8 +457,8 @@ func (l *genericResource) Name() string {
 	return l.name
 }
 
-func (l *genericResource) NameOriginal() string {
-	return l.sd.NameOriginal
+func (l *genericResource) NameNormalized() string {
+	return l.sd.NameNormalized
 }
 
 func (l *genericResource) Params() maps.Params {
diff --git a/resources/resource/resources.go b/resources/resource/resources.go
index fb5f9a5ee13..aa01d4ce27d 100644
--- a/resources/resource/resources.go
+++ b/resources/resource/resources.go
@@ -18,7 +18,6 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/gohugoio/hugo/common/paths"
 	"github.com/gohugoio/hugo/hugofs/glob"
 	"github.com/spf13/cast"
 )
@@ -73,10 +72,10 @@ func (r Resources) Get(name any) Resource {
 		}
 	}
 
-	// Finally, check the original name.
+	// Finally, check the normalized name.
 	for _, resource := range r {
-		if nop, ok := resource.(NameOriginalProvider); ok {
-			if strings.EqualFold(namestr, nop.NameOriginal()) {
+		if nop, ok := resource.(NameNormalizedProvider); ok {
+			if strings.EqualFold(namestr, nop.NameNormalized()) {
 				return resource
 			}
 		}
@@ -93,23 +92,21 @@ func (r Resources) GetMatch(pattern any) Resource {
 		panic(err)
 	}
 
-	patternstr = paths.NormalizePathStringBasic(patternstr)
-
 	g, err := glob.GetGlob(patternstr)
 	if err != nil {
 		panic(err)
 	}
 
 	for _, resource := range r {
-		if g.Match(paths.NormalizePathStringBasic(resource.Name())) {
+		if g.Match(resource.Name()) {
 			return resource
 		}
 	}
 
 	// Finally, check the original name.
 	for _, resource := range r {
-		if nop, ok := resource.(NameOriginalProvider); ok {
-			if g.Match(paths.NormalizePathStringBasic(nop.NameOriginal())) {
+		if nop, ok := resource.(NameNormalizedProvider); ok {
+			if g.Match(nop.NameNormalized()) {
 				return resource
 			}
 		}
@@ -140,15 +137,15 @@ func (r Resources) Match(pattern any) Resources {
 
 	var matches Resources
 	for _, resource := range r {
-		if g.Match(strings.ToLower(resource.Name())) {
+		if g.Match(resource.Name()) {
 			matches = append(matches, resource)
 		}
 	}
 	if len(matches) == 0 {
-		// 	Fall back to the original name.
+		// 	Fall back to the normalized name.
 		for _, resource := range r {
-			if nop, ok := resource.(NameOriginalProvider); ok {
-				if g.Match(strings.ToLower(nop.NameOriginal())) {
+			if nop, ok := resource.(NameNormalizedProvider); ok {
+				if g.Match(nop.NameNormalized()) {
 					matches = append(matches, resource)
 				}
 			}
diff --git a/resources/resource/resourcetypes.go b/resources/resource/resourcetypes.go
index 6b437023ab8..0766fe232c1 100644
--- a/resources/resource/resourcetypes.go
+++ b/resources/resource/resourcetypes.go
@@ -127,20 +127,16 @@ type ResourceNameTitleProvider interface {
 	// So, for the image "/some/path/sunset.jpg" this will be "sunset.jpg".
 	// The value returned by this method will be used in the GetByPrefix and ByPrefix methods
 	// on Resources.
-	// Note that for bundled content resources with language code in the filename, this will
-	// be the name without the language code.
 	Name() string
 
 	// Title returns the title if set in front matter. For content pages, this will be the expected value.
 	Title() string
 }
 
-type NameOriginalProvider interface {
-	// NameOriginal is the original name of this resource.
-	// Note that for bundled content resources with language code in the filename, this will
-	// be the name with the language code.
+type NameNormalizedProvider interface {
+	// NameNormalized is the normalized name of this resource.
 	// For internal use (for now).
-	NameOriginal() string
+	NameNormalized() string
 }
 
 type ResourceParamsProvider interface {
diff --git a/resources/resource_metadata.go b/resources/resource_metadata.go
index 869fc11bf5e..659ce81f84f 100644
--- a/resources/resource_metadata.go
+++ b/resources/resource_metadata.go
@@ -28,10 +28,10 @@ import (
 )
 
 var (
-	_ mediaTypeAssigner             = (*genericResource)(nil)
-	_ mediaTypeAssigner             = (*imageResource)(nil)
-	_ resource.Staler               = (*genericResource)(nil)
-	_ resource.NameOriginalProvider = (*genericResource)(nil)
+	_ mediaTypeAssigner               = (*genericResource)(nil)
+	_ mediaTypeAssigner               = (*imageResource)(nil)
+	_ resource.Staler                 = (*genericResource)(nil)
+	_ resource.NameNormalizedProvider = (*genericResource)(nil)
 )
 
 // metaAssigner allows updating metadata in resources that supports it.
diff --git a/resources/resource_spec.go b/resources/resource_spec.go
index 0bb507083c4..bd04846ed6e 100644
--- a/resources/resource_spec.go
+++ b/resources/resource_spec.go
@@ -170,8 +170,8 @@ func (r *Spec) NewResource(rd ResourceSourceDescriptor) (resource.Resource, erro
 		spec:        r,
 		sd:          rd,
 		params:      make(map[string]any),
-		name:        rd.Name,
-		title:       rd.Name,
+		name:        rd.NameOriginal,
+		title:       rd.NameOriginal,
 	}
 
 	if rd.MediaType.MainType == "image" {
diff --git a/resources/transform.go b/resources/transform.go
index b9cbab8242d..39a8aaccc40 100644
--- a/resources/transform.go
+++ b/resources/transform.go
@@ -55,7 +55,7 @@ var (
 	_ resource.WithResourceMetaProvider  = (*resourceAdapter)(nil)
 	_ identity.DependencyManagerProvider = (*resourceAdapter)(nil)
 	_ identity.IdentityGroupProvider     = (*resourceAdapter)(nil)
-	_ resource.NameOriginalProvider      = (*resourceAdapter)(nil)
+	_ resource.NameNormalizedProvider    = (*resourceAdapter)(nil)
 )
 
 // These are transformations that need special support in Hugo that may not
@@ -282,9 +282,9 @@ func (r *resourceAdapter) Name() string {
 	return r.metaProvider.Name()
 }
 
-func (r *resourceAdapter) NameOriginal() string {
+func (r *resourceAdapter) NameNormalized() string {
 	r.init(false, false)
-	return r.target.(resource.NameOriginalProvider).NameOriginal()
+	return r.target.(resource.NameNormalizedProvider).NameNormalized()
 }
 
 func (r *resourceAdapter) Params() maps.Params {


Test patch:
diff --git a/hugolib/pagebundler_test.go b/hugolib/pagebundler_test.go
index ff7998ed933..a46ef0b5643 100644
--- a/hugolib/pagebundler_test.go
+++ b/hugolib/pagebundler_test.go
@@ -871,7 +871,7 @@ RegularPages: {{ range .RegularPages }}{{ .RelPermalink }}|File LogicalName: {{
 	b := Test(t, files)
 
 	// Note that the sort order gives us the most specific data file for the en language (the data.en.json).
-	b.AssertFileContent("public/mysection/mybundle/index.html", `Single:|/mysection/mybundle|File LogicalName: index.md||/mysection/mybundle/|page|Resources: data.json: Data JSON.|foo/p1.html: |p1.html: |p1.md: |data.txt: Data en txt.|$`)
+	b.AssertFileContent("public/mysection/mybundle/index.html", `Single:|/mysection/mybundle|File LogicalName: index.md||/mysection/mybundle/|page|Resources: data.en.txt: Data en txt.|data.json: Data JSON.|foo/p1.html: |p1.html: |p1.md: |$`)
 	b.AssertFileContent("public/mysection/index.html",
 		"List: |/mysection|File LogicalName: _index.md|/mysection/|section|Resources: sectiondata.json: Secion data JSON.|sectiondata.txt: Section data TXT.|$",
 		"RegularPages: /mysection/foo/p2/|File LogicalName: p2.md|/mysection/mybundle/|File LogicalName: index.md|/mysection/p2/|File LogicalName: p2.md|$")
@@ -886,12 +886,12 @@ baseURL = "https://example.com"
 F1.
 -- layouts/_default/single.html --
 GetMatch: {{ with .Resources.GetMatch "f1.en.*" }}{{ .Name }}: {{ .Content }}|{{ end }}
-Match: {{ range .Resources.Match "f1.en.*" }}{{ .Name }}: {{ .Content }}|{{ end }}
+Match: {{ range .Resources.Match "f1.En.*" }}{{ .Name }}: {{ .Content }}|{{ end }}
 `
 
 	b := Test(t, files)
 
-	b.AssertFileContent("public/mybundle/index.html", "GetMatch: f1.txt: F1.|", "Match: f1.txt: F1.|")
+	b.AssertFileContent("public/mybundle/index.html", "GetMatch: f1.en.txt: F1.|", "Match: f1.en.txt: F1.|")
 }
 
 func TestBundleResourcesWhenLanguageVariantIsDraft(t *testing.T) {
@@ -917,5 +917,5 @@ GetMatch: {{ with .Resources.GetMatch "f1.*" }}{{ .Name }}: {{ .Content }}|{{ en
 
 	b := Test(t, files)
 
-	b.AssertFileContent("public/mybundle/index.html", "GetMatch: f1.txt: F1.|")
+	b.AssertFileContent("public/mybundle/index.html", "GetMatch: f1.en.txt: F1.|")
 }
diff --git a/resources/testhelpers_test.go b/resources/testhelpers_test.go
index 02852461990..60cfae0c520 100644
--- a/resources/testhelpers_test.go
+++ b/resources/testhelpers_test.go
@@ -117,8 +117,8 @@ func fetchResourceForSpec(spec *resources.Spec, c *qt.C, name string, targetPath
 	targetPath := name
 	base := "/a/"
 	r, err := spec.NewResource(resources.ResourceSourceDescriptor{
-		LazyPublish: true,
-		Name:        name, TargetPath: targetPath, BasePathRelPermalink: base, BasePathTargetPath: base, OpenReadSeekCloser: open,
+		LazyPublish:    true,
+		NameNormalized: name, TargetPath: targetPath, BasePathRelPermalink: base, BasePathTargetPath: base, OpenReadSeekCloser: open,
 		GroupIdentity: identity.Anonymous,
 	})
 	c.Assert(err, qt.IsNil)