Repository: gohugoio/hugo
Pull request #12233 (2024-03-11 12:06:35)

build(deps): bump chroma github.com/alecthomas/chroma/v2 to v2.13.0
(see commit message)

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/gohugoio/hugo?pullRequest=12233) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/gohugoio/hugo?pullRequest=12233) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/gohugoio/hugo?pullRequest=12233) it.</sub>
jmooring: This would resolve https://github.com/gohugoio/hugo/issues/11862 as well.
myitcv: I'm happy to return to this PR to look at the build failures, but if in the meantime someone more familiar with what's failing wants to take it over that's fine with me.
myitcv: @jmooring - the build failures look like a genuine bug to me, and appear to have been introduced by https://github.com/alecthomas/chroma/commit/6dd9f269efaa029531b198c3c803f07dc7343c77. Thankfully the CUE change I need is the commit immediately prior to that, so I'll use that as the basis for the pseudo-version for now.
myitcv: @jmooring - I've force-pushed a revised commit for this PR, and raised https://github.com/alecthomas/chroma/issues/945 for what I think is a bug in chroma. 
myitcv: https://github.com/alecthomas/chroma/issues/945 is now resolved; I totally missed/messed up my analysis, and somehow failed to see the line in the actual output, only with a minor space difference. So I've now revised this PR to use a pseudo version for the current tip of chroma.

@jmooring - this PR is now ready for the workflows to be re-run, and for review please!

Patch:
diff --git a/commands/server.go b/commands/server.go
index 0ce655c51..afc539c44 100644
--- a/commands/server.go
+++ b/commands/server.go
@@ -617,9 +617,9 @@ func (c *serverCommand) setBaseURLsInConfig() error {
 	}
 	return c.withConfE(func(conf *commonConfig) error {
 		for i, language := range conf.configs.Languages {
-			isMultiHost := conf.configs.IsMultihost
+			isMultihost := conf.configs.IsMultihost
 			var serverPort int
-			if isMultiHost {
+			if isMultihost {
 				serverPort = c.serverPorts[i].p
 			} else {
 				serverPort = c.serverPorts[0].p
@@ -737,9 +737,9 @@ func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
 	flags := cd.CobraCommand.Flags()
 	var cerr error
 	c.withConf(func(conf *commonConfig) {
-		isMultiHost := conf.configs.IsMultihost
+		isMultihost := conf.configs.IsMultihost
 		c.serverPorts = make([]serverPortListener, 1)
-		if isMultiHost {
+		if isMultihost {
 			if !c.serverAppend {
 				cerr = errors.New("--appendPort=false not supported when in multihost mode")
 				return
@@ -852,7 +852,7 @@ func (c *serverCommand) serve() error {
 		h        *hugolib.HugoSites
 	)
 	err := c.withConfE(func(conf *commonConfig) error {
-		isMultiHost := conf.configs.IsMultihost
+		isMultihost := conf.configs.IsMultihost
 		var err error
 		h, err = c.r.HugFromConfig(conf)
 		if err != nil {
@@ -862,7 +862,7 @@ func (c *serverCommand) serve() error {
 		// We need the server to share the same logger as the Hugo build (for error counts etc.)
 		c.r.logger = h.Log
 
-		if isMultiHost {
+		if isMultihost {
 			for _, l := range conf.configs.ConfigLangs() {
 				baseURLs = append(baseURLs, l.BaseURL())
 				roots = append(roots, l.Language().Lang)
@@ -1005,7 +1005,6 @@ func (c *serverCommand) serve() error {
 			}
 		}
 	}()
-
 	if err != nil {
 		c.r.Println("Error:", err)
 	}
diff --git a/common/hugo/hugo.go b/common/hugo/hugo.go
index a3d1a7bfc..0589ac9a3 100644
--- a/common/hugo/hugo.go
+++ b/common/hugo/hugo.go
@@ -111,14 +111,20 @@ func (i HugoInfo) Deps() []*Dependency {
 	return i.deps
 }
 
-// IsMultiHost reports whether each configured language has a unique baseURL.
+// Deprecated: Use hugo.IsMultihost instead.
 func (i HugoInfo) IsMultiHost() bool {
+	Deprecate("hugo.IsMultiHost", "Use hugo.IsMultihost instead.", "v0.124.0")
 	return i.conf.IsMultihost()
 }
 
-// IsMultiLingual reports whether there are two or more configured languages.
-func (i HugoInfo) IsMultiLingual() bool {
-	return i.conf.IsMultiLingual()
+// IsMultihost reports whether each configured language has a unique baseURL.
+func (i HugoInfo) IsMultihost() bool {
+	return i.conf.IsMultihost()
+}
+
+// IsMultilingual reports whether there are two or more configured languages.
+func (i HugoInfo) IsMultilingual() bool {
+	return i.conf.IsMultilingual()
 }
 
 // ConfigProvider represents the config options that are relevant for HugoInfo.
@@ -127,7 +133,7 @@ type ConfigProvider interface {
 	Running() bool
 	WorkingDir() string
 	IsMultihost() bool
-	IsMultiLingual() bool
+	IsMultilingual() bool
 }
 
 // NewInfo creates a new Hugo Info object.
diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go
index 9cafc876e..590f2ba60 100644
--- a/config/allconfig/allconfig.go
+++ b/config/allconfig/allconfig.go
@@ -826,7 +826,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
 	langConfigMap := make(map[string]*Config)
 
 	languagesConfig := cfg.GetStringMap("languages")
-	var isMultiHost bool
+	var isMultihost bool
 
 	if err := all.CompileConfig(logger); err != nil {
 		return nil, err
@@ -863,7 +863,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
 				}
 				if kk == "baseurl" {
 					// baseURL configure don the language level is a multihost setup.
-					isMultiHost = true
+					isMultihost = true
 				}
 				mergedConfig.Set(kk, vv)
 				rootv := cfg.Get(kk)
@@ -913,7 +913,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
 			}
 
 			// Adjust Goldmark config defaults for multilingual, single-host sites.
-			if len(languagesConfig) > 1 && !isMultiHost && !clone.Markup.Goldmark.DuplicateResourceFiles {
+			if len(languagesConfig) > 1 && !isMultihost && !clone.Markup.Goldmark.DuplicateResourceFiles {
 				if !clone.Markup.Goldmark.DuplicateResourceFiles {
 					if clone.Markup.Goldmark.RenderHooks.Link.EnableDefault == nil {
 						clone.Markup.Goldmark.RenderHooks.Link.EnableDefault = types.NewBool(true)
@@ -943,7 +943,7 @@ func fromLoadConfigResult(fs afero.Fs, logger loggers.Logger, res config.LoadCon
 		Base:              all,
 		LanguageConfigMap: langConfigMap,
 		LoadingInfo:       res,
-		IsMultihost:       isMultiHost,
+		IsMultihost:       isMultihost,
 	}
 
 	return cm, nil
diff --git a/config/allconfig/configlanguage.go b/config/allconfig/configlanguage.go
index 9971be65f..900db75ce 100644
--- a/config/allconfig/configlanguage.go
+++ b/config/allconfig/configlanguage.go
@@ -52,7 +52,7 @@ func (c ConfigLanguage) LanguagePrefix() string {
 		return c.Language().Lang
 	}
 
-	if !c.IsMultiLingual() || c.DefaultContentLanguage() == c.Language().Lang {
+	if !c.IsMultilingual() || c.DefaultContentLanguage() == c.Language().Lang {
 		return ""
 	}
 	return c.Language().Lang
@@ -78,7 +78,7 @@ func (c ConfigLanguage) FastRenderMode() bool {
 	return c.config.Internal.FastRenderMode
 }
 
-func (c ConfigLanguage) IsMultiLingual() bool {
+func (c ConfigLanguage) IsMultilingual() bool {
 	return len(c.m.Languages) > 1
 }
 
diff --git a/config/configProvider.go b/config/configProvider.go
index 586a9b758..8f74202ab 100644
--- a/config/configProvider.go
+++ b/config/configProvider.go
@@ -35,7 +35,7 @@ type AllProvider interface {
 	PathParser() *paths.PathParser
 	Environment() string
 	IsMultihost() bool
-	IsMultiLingual() bool
+	IsMultilingual() bool
 	NoBuildLock() bool
 	BaseConfig() BaseConfig
 	Dirs() CommonDirs
diff --git a/go.mod b/go.mod
index 839838b2b..5f22fbad3 100644
--- a/go.mod
+++ b/go.mod
@@ -2,7 +2,7 @@ module github.com/gohugoio/hugo
 
 require (
 	github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69
-	github.com/alecthomas/chroma/v2 v2.12.0
+	github.com/alecthomas/chroma/v2 v2.13.0
 	github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c
 	github.com/aws/aws-sdk-go-v2 v1.24.1
 	github.com/aws/aws-sdk-go-v2/service/cloudfront v1.32.6
@@ -72,7 +72,7 @@ require (
 	gocloud.dev v0.36.0
 	golang.org/x/exp v0.0.0-20221031165847-c99f073a8326
 	golang.org/x/image v0.15.0
-	golang.org/x/mod v0.15.0
+	golang.org/x/mod v0.16.0
 	golang.org/x/net v0.21.0
 	golang.org/x/sync v0.6.0
 	golang.org/x/text v0.14.0
@@ -114,7 +114,7 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect
 	github.com/aws/smithy-go v1.19.0 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
-	github.com/dlclark/regexp2 v1.10.0 // indirect
+	github.com/dlclark/regexp2 v1.11.0 // indirect
 	github.com/go-openapi/jsonpointer v0.20.2 // indirect
 	github.com/go-openapi/swag v0.22.8 // indirect
 	github.com/golang-jwt/jwt/v5 v5.1.0 // indirect
diff --git a/go.sum b/go.sum
index 33f0ededc..d2a901fe1 100644
--- a/go.sum
+++ b/go.sum
@@ -66,10 +66,10 @@ github.com/BurntSushi/locker v0.0.0-20171006230638-a6e239ea1c69/go.mod h1:L1AbZd
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
-github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
-github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
-github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
+github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
+github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI=
+github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk=
+github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
 github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M=
 github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/aws/aws-sdk-go v1.50.7 h1:odKb+uneeGgF2jgAerKjFzpljiyZxleV4SHB7oBK+YA=
@@ -168,8 +168,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/disintegration/gift v1.2.1 h1:Y005a1X4Z7Uc+0gLpSAsKhWi4qLtsdEcMIbbdvdZ6pc=
 github.com/disintegration/gift v1.2.1/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI=
-github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
-github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
@@ -508,8 +508,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
-golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
+golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
diff --git a/hugolib/content_map_page.go b/hugolib/content_map_page.go
index 764078623..906fced77 100644
--- a/hugolib/content_map_page.go
+++ b/hugolib/content_map_page.go
@@ -1778,7 +1778,7 @@ func (sa *sitePagesAssembler) addStandalonePages() error {
 
 	if sitemapEnabled {
 		addStandalone("/_sitemap", kinds.KindSitemap, output.SitemapFormat)
-		skipSitemapIndex := s.Conf.IsMultihost() || !(s.Conf.DefaultContentLanguageInSubdir() || s.Conf.IsMultiLingual())
+		skipSitemapIndex := s.Conf.IsMultihost() || !(s.Conf.DefaultContentLanguageInSubdir() || s.Conf.IsMultilingual())
 
 		if !skipSitemapIndex {
 			addStandalone("/_sitemapindex", kinds.KindSitemapIndex, output.SitemapIndexFormat)
diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
index 99dc88b10..671785f44 100644
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -269,7 +269,7 @@ func (h *HugoSites) pickOneAndLogTheRest(errors []error) error {
 	return errors[i]
 }
 
-func (h *HugoSites) isMultiLingual() bool {
+func (h *HugoSites) isMultilingual() bool {
 	return len(h.Sites) > 1
 }
 
diff --git a/hugolib/hugo_sites_build.go b/hugolib/hugo_sites_build.go
index 382b1eed0..ddc712a2d 100644
--- a/hugolib/hugo_sites_build.go
+++ b/hugolib/hugo_sites_build.go
@@ -792,6 +792,8 @@ func (h *HugoSites) processPartial(ctx context.Context, l logg.LevelLogger, conf
 			// It's hard to determine the exact change set of this,
 			// so be very coarse grained for now.
 			changes = append(changes, identity.GenghisKhan)
+		case files.ComponentFolderArchetypes:
+			// Ignore for now.
 		default:
 			panic(fmt.Sprintf("unknown component: %q", pathInfo.Component()))
 		}
diff --git a/hugolib/site.go b/hugolib/site.go
index 5a58e8373..117e10144 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -297,7 +297,6 @@ func (s *siteRefLinker) refLink(ref string, source any, relative bool, outputFor
 	ref = filepath.ToSlash(ref)
 
 	refURL, err = url.Parse(ref)
-
 	if err != nil {
 		return s.notFoundURL, err
 	}
@@ -681,7 +680,7 @@ func (s *Site) getLanguagePermalinkLang(alwaysInSubDir bool) string {
 		return ""
 	}
 
-	if s.h.Conf.IsMultiLingual() && alwaysInSubDir {
+	if s.h.Conf.IsMultilingual() && alwaysInSubDir {
 		return s.Language().Lang
 	}
 
diff --git a/hugolib/site_new.go b/hugolib/site_new.go
index 5a5811958..21d5ace96 100644
--- a/hugolib/site_new.go
+++ b/hugolib/site_new.go
@@ -484,10 +484,10 @@ func (s *Site) BuildDrafts() bool {
 	return s.conf.BuildDrafts
 }
 
-// Deprecated: Use hugo.IsMultiLingual instead.
+// Deprecated: Use hugo.IsMultilingual instead.
 func (s *Site) IsMultiLingual() bool {
-	hugo.Deprecate(".Site.IsMultiLingual", "Use hugo.IsMultiLingual instead.", "v0.124.0")
-	return s.h.isMultiLingual()
+	hugo.Deprecate(".Site.IsMultiLingual", "Use hugo.IsMultilingual instead.", "v0.124.0")
+	return s.h.isMultilingual()
 }
 
 func (s *Site) LanguagePrefix() string {
diff --git a/hugolib/site_render.go b/hugolib/site_render.go
index 1cf4b9a61..86be897fa 100644
--- a/hugolib/site_render.go
+++ b/hugolib/site_render.go
@@ -334,7 +334,7 @@ func (s *Site) renderAliases() error {
 // renderMainLanguageRedirect creates a redirect to the main language home,
 // depending on if it lives in sub folder (e.g. /en) or not.
 func (s *Site) renderMainLanguageRedirect() error {
-	if s.h.Conf.IsMultihost() || !(s.h.Conf.DefaultContentLanguageInSubdir() || s.h.Conf.IsMultiLingual()) {
+	if s.h.Conf.IsMultihost() || !(s.h.Conf.DefaultContentLanguageInSubdir() || s.h.Conf.IsMultilingual()) {
 		// No need for a redirect
 		return nil
 	}
diff --git a/modules/config.go b/modules/config.go
index 62671613c..abb938ac0 100644
--- a/modules/config.go
+++ b/modules/config.go
@@ -86,7 +86,7 @@ func ApplyProjectConfigDefaults(mod Module, cfgs ...config.AllProvider) error {
 
 		first := cfgs[0]
 		dirsBase := first.DirsBase()
-		isMultiHost := first.IsMultihost()
+		isMultihost := first.IsMultihost()
 
 		for i, cfg := range cfgs {
 			dirs := cfg.Dirs()
@@ -113,7 +113,7 @@ func ApplyProjectConfigDefaults(mod Module, cfgs ...config.AllProvider) error {
 				dir = dirs.AssetDir
 			case files.ComponentFolderStatic:
 				// For static dirs, we only care about the language in multihost setups.
-				dropLang = !isMultiHost
+				dropLang = !isMultihost
 			}
 
 			var perLang bool
diff --git a/resources/page/pagemeta/page_frontmatter.go b/resources/page/pagemeta/page_frontmatter.go
index 8abd3807f..4e412c666 100644
--- a/resources/page/pagemeta/page_frontmatter.go
+++ b/resources/page/pagemeta/page_frontmatter.go
@@ -421,18 +421,22 @@ func (f *frontmatterFieldHandlers) newDateFieldHandler(key string, setter func(d
 			return false, nil
 		}
 
-		date, err := htime.ToTimeInDefaultLocationE(v, d.Location)
-		if err != nil {
-			return false, nil
+		var date time.Time
+		if vt, ok := v.(time.Time); ok && vt.Location() == d.Location {
+			date = vt
+		} else {
+			var err error
+			date, err = htime.ToTimeInDefaultLocationE(v, d.Location)
+			if err != nil {
+				return false, nil
+			}
+			d.PageConfig.Params[key] = date
 		}
 
 		// We map several date keys to one, so, for example,
 		// "expirydate", "unpublishdate" will all set .ExpiryDate (first found).
 		setter(d, date)
 
-		// This is the params key as set in front matter.
-		d.PageConfig.Params[key] = date
-
 		return true, nil
 	}
 }
diff --git a/resources/page/site.go b/resources/page/site.go
index d9f3d967b..8f268091f 100644
--- a/resources/page/site.go
+++ b/resources/page/site.go
@@ -126,7 +126,7 @@ type Site interface {
 	// BuildDrafts is deprecated and will be removed in a future release.
 	BuildDrafts() bool
 
-	// Deprecated: Use hugo.IsMultiLingual instead.
+	// Deprecated: Use hugo.IsMultilingual instead.
 	IsMultiLingual() bool
 
 	// LanguagePrefix returns the language prefix for this site.
@@ -292,7 +292,7 @@ func (s *siteWrapper) BuildDrafts() bool {
 	return s.s.BuildDrafts()
 }
 
-// Deprecated: Use hugo.IsMultiLingual instead.
+// Deprecated: Use hugo.IsMultilingual instead.
 func (s *siteWrapper) IsMultiLingual() bool {
 	return s.s.IsMultiLingual()
 }
@@ -453,7 +453,7 @@ func (s testSite) BuildDrafts() bool {
 	return false
 }
 
-// Deprecated: Use hugo.IsMultiLingual instead.
+// Deprecated: Use hugo.IsMultilingual instead.
 func (s testSite) IsMultiLingual() bool {
 	return false
 }
diff --git a/resources/resource/resources.go b/resources/resource/resources.go
index aa01d4ce2..32bcdbb08 100644
--- a/resources/resource/resources.go
+++ b/resources/resource/resources.go
@@ -18,6 +18,7 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/gohugoio/hugo/common/paths"
 	"github.com/gohugoio/hugo/hugofs/glob"
 	"github.com/spf13/cast"
 )
@@ -61,13 +62,14 @@ func (r Resources) Get(name any) Resource {
 	if err != nil {
 		panic(err)
 	}
-	namestr = strings.ToLower(namestr)
+
+	namestr = paths.AddLeadingSlash(namestr)
 
 	// First check the Name.
 	// Note that this can be modified by the user in the front matter,
 	// also, it does not contain any language code.
 	for _, resource := range r {
-		if strings.EqualFold(namestr, resource.Name()) {
+		if strings.EqualFold(namestr, paths.AddLeadingSlash(resource.Name())) {
 			return resource
 		}
 	}
@@ -75,7 +77,7 @@ func (r Resources) Get(name any) Resource {
 	// Finally, check the normalized name.
 	for _, resource := range r {
 		if nop, ok := resource.(NameNormalizedProvider); ok {
-			if strings.EqualFold(namestr, nop.NameNormalized()) {
+			if strings.EqualFold(namestr, paths.AddLeadingSlash(nop.NameNormalized())) {
 				return resource
 			}
 		}
@@ -92,21 +94,21 @@ func (r Resources) GetMatch(pattern any) Resource {
 		panic(err)
 	}
 
-	g, err := glob.GetGlob(patternstr)
+	g, err := glob.GetGlob(paths.AddLeadingSlash(patternstr))
 	if err != nil {
 		panic(err)
 	}
 
 	for _, resource := range r {
-		if g.Match(resource.Name()) {
+		if g.Match(paths.AddLeadingSlash(resource.Name())) {
 			return resource
 		}
 	}
 
-	// Finally, check the original name.
+	// Finally, check the normalized name.
 	for _, resource := range r {
 		if nop, ok := resource.(NameNormalizedProvider); ok {
-			if g.Match(nop.NameNormalized()) {
+			if g.Match(paths.AddLeadingSlash(nop.NameNormalized())) {
 				return resource
 			}
 		}
@@ -130,14 +132,14 @@ func (r Resources) Match(pattern any) Resources {
 		panic(err)
 	}
 
-	g, err := glob.GetGlob(patternstr)
+	g, err := glob.GetGlob(paths.AddLeadingSlash(patternstr))
 	if err != nil {
 		panic(err)
 	}
 
 	var matches Resources
 	for _, resource := range r {
-		if g.Match(resource.Name()) {
+		if g.Match(paths.AddLeadingSlash(resource.Name())) {
 			matches = append(matches, resource)
 		}
 	}
@@ -145,7 +147,7 @@ func (r Resources) Match(pattern any) Resources {
 		// 	Fall back to the normalized name.
 		for _, resource := range r {
 			if nop, ok := resource.(NameNormalizedProvider); ok {
-				if g.Match(nop.NameNormalized()) {
+				if g.Match(paths.AddLeadingSlash(nop.NameNormalized())) {
 					matches = append(matches, resource)
 				}
 			}
diff --git a/resources/resource_factories/create/create.go b/resources/resource_factories/create/create.go
index 1ecc4652d..061ecf1e7 100644
--- a/resources/resource_factories/create/create.go
+++ b/resources/resource_factories/create/create.go
@@ -134,8 +134,8 @@ func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource)
 				OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
 					return meta.Open()
 				},
-				NameNormalized: meta.PathInfo.Name(),
-				NameOriginal:   meta.PathInfo.Unnormalized().Name(),
+				NameNormalized: meta.PathInfo.Path(),
+				NameOriginal:   meta.PathInfo.Unnormalized().Path(),
 				GroupIdentity:  meta.PathInfo,
 				TargetPath:     meta.PathInfo.Unnormalized().Path(),
 			})
diff --git a/tpl/tplimpl/embedded/templates/shortcodes/figure.html b/tpl/tplimpl/embedded/templates/shortcodes/figure.html
index afe784c19..a0b93a437 100644
--- a/tpl/tplimpl/embedded/templates/shortcodes/figure.html
+++ b/tpl/tplimpl/embedded/templates/shortcodes/figure.html
@@ -1,29 +1,38 @@
 <figure{{ with .Get "class" }} class="{{ . }}"{{ end }}>
-    {{- if .Get "link" -}}
-        <a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>
+  {{- if .Get "link" -}}
+    <a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>
+  {{- end -}}
+
+  {{- $u := urls.Parse (.Get "src") -}}
+  {{- $src := $u.String -}}
+  {{- if not $u.IsAbs -}}
+    {{- with or (.Page.Resources.Get $u.Path) (resources.Get $u.Path) -}}
+      {{- $src = .RelPermalink -}}
     {{- end -}}
-    <img src="{{ .Get "src" }}"
-         {{- if or (.Get "alt") (.Get "caption") }}
-         alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
-         {{- end -}}
-         {{- with .Get "width" }} width="{{ . }}"{{ end -}}
-         {{- with .Get "height" }} height="{{ . }}"{{ end -}}
-         {{- with .Get "loading" }} loading="{{ . }}"{{ end -}}
-    /><!-- Closing img tag -->
-    {{- if .Get "link" }}</a>{{ end -}}
-    {{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
-        <figcaption>
-            {{ with (.Get "title") -}}
-                <h4>{{ . }}</h4>
-            {{- end -}}
-            {{- if or (.Get "caption") (.Get "attr") -}}<p>
-                {{- .Get "caption" | markdownify -}}
-                {{- with .Get "attrlink" }}
-                    <a href="{{ . }}">
-                {{- end -}}
-                {{- .Get "attr" | markdownify -}}
-                {{- if .Get "attrlink" }}</a>{{ end }}</p>
-            {{- end }}
-        </figcaption>
-    {{- end }}
+  {{- end -}}
+
+  <img src="{{ $src }}"
+    {{- if or (.Get "alt") (.Get "caption") }}
+    alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
+    {{- end -}}
+    {{- with .Get "width" }} width="{{ . }}"{{ end -}}
+    {{- with .Get "height" }} height="{{ . }}"{{ end -}}
+    {{- with .Get "loading" }} loading="{{ . }}"{{ end -}}
+  ><!-- Closing img tag -->
+  {{- if .Get "link" }}</a>{{ end -}}
+  {{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
+    <figcaption>
+      {{ with (.Get "title") -}}
+        <h4>{{ . }}</h4>
+      {{- end -}}
+      {{- if or (.Get "caption") (.Get "attr") -}}<p>
+        {{- .Get "caption" | markdownify -}}
+        {{- with .Get "attrlink" }}
+          <a href="{{ . }}">
+        {{- end -}}
+        {{- .Get "attr" | markdownify -}}
+        {{- if .Get "attrlink" }}</a>{{ end }}</p>
+      {{- end }}
+    </figcaption>
+  {{- end }}
 </figure>


Test patch:
diff --git a/common/hugo/hugo_integration_test.go b/common/hugo/hugo_integration_test.go
index 9fcfb95cf..77dbb5c91 100644
--- a/common/hugo/hugo_integration_test.go
+++ b/common/hugo/hugo_integration_test.go
@@ -20,7 +20,7 @@ import (
 	"github.com/gohugoio/hugo/hugolib"
 )
 
-func TestIsMultiLingualAndIsMultiHost(t *testing.T) {
+func TestIsMultilingualAndIsMultihost(t *testing.T) {
 	t.Parallel()
 
 	files := `
@@ -36,8 +36,8 @@ baseURL = 'https://en.example.org/'
 title: home
 ---
 -- layouts/index.html --
-multilingual={{ hugo.IsMultiLingual }}
-multihost={{ hugo.IsMultiHost }}
+multilingual={{ hugo.IsMultilingual }}
+multihost={{ hugo.IsMultihost }}
   `
 
 	b := hugolib.Test(t, files)
diff --git a/common/hugo/hugo_test.go b/common/hugo/hugo_test.go
index e1d907158..6e8b2620e 100644
--- a/common/hugo/hugo_test.go
+++ b/common/hugo/hugo_test.go
@@ -88,6 +88,6 @@ func (c testConfig) IsMultihost() bool {
 	return c.multihost
 }
 
-func (c testConfig) IsMultiLingual() bool {
+func (c testConfig) IsMultilingual() bool {
 	return c.multilingual
 }
diff --git a/hugolib/config_test.go b/hugolib/config_test.go
index 7914dda45..22beea655 100644
--- a/hugolib/config_test.go
+++ b/hugolib/config_test.go
@@ -508,12 +508,12 @@ func TestLoadConfigFromThemeDir(t *testing.T) {
 theme = "test-theme"
 
 [params]
-m1 = "mv1"	
+m1 = "mv1"
 `
 
 	themeConfig := `
 [params]
-t1 = "tv1"	
+t1 = "tv1"
 t2 = "tv2"
 `
 
@@ -885,9 +885,9 @@ ThisIsAParam: {{ site.Params.thisIsAParam }}
 	).BuildE()
 
 	b.Assert(err, qt.IsNil)
-	b.AssertFileContent("public/index.html", `		
+	b.AssertFileContent("public/index.html", `
 MyParam: enParamValue
-ThisIsAParam: thisIsAParamValue	
+ThisIsAParam: thisIsAParamValue
 `)
 }
 
@@ -919,7 +919,7 @@ title: "My Swedish Section"
 -- layouts/index.html --
 LanguageCode: {{ eq site.LanguageCode site.Language.LanguageCode }}|{{ site.Language.LanguageCode }}|
 {{ range $i, $e := (slice site .Site) }}
-{{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultiLingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|Language string: {{ .Language }}|Languages: {{ .Languages }}
+{{ $i }}|AllPages: {{ len .AllPages }}|Sections: {{ if .Sections }}true{{ end }}| Author: {{ .Authors }}|BuildDrafts: {{ .BuildDrafts }}|IsMultilingual: {{ .IsMultiLingual }}|Param: {{ .Language.Params.myparam }}|Language string: {{ .Language }}|Languages: {{ .Languages }}
 {{ end }}
 
 
@@ -939,9 +939,9 @@ LanguageCode: {{ eq site.LanguageCode site.Language.LanguageCode }}|{{ site.Lang
 	b.AssertFileContent("public/index.html", `
 AllPages: 4|
 Sections: true|
-Param: enParamValue	
-Param: enParamValue	
-IsMultiLingual: true
+Param: enParamValue
+Param: enParamValue
+IsMultilingual: true
 LanguageCode: true|en-US|
 `)
 
@@ -1062,7 +1062,7 @@ Home
 	).BuildE()
 
 	b.Assert(err, qt.IsNil)
-	b.AssertFileContent("public/index.html", `		
+	b.AssertFileContent("public/index.html", `
 Home
 `)
 
@@ -1095,7 +1095,7 @@ HTML.
 HTACCESS.
 
 
-	
+
 `
 	b := Test(t, files)
 
@@ -1111,7 +1111,7 @@ languageCode = "en-US"
 -- layouts/index.html --
 LanguageCode: {{ .Site.LanguageCode }}|{{ site.Language.LanguageCode }}|
 
-	
+
 `
 	b := Test(t, files)
 
@@ -1137,7 +1137,7 @@ suffixes = ["bar"]
 -- layouts/index.html --
 Home.
 
-	
+
 `
 	b := Test(t, files)
 
@@ -1164,8 +1164,8 @@ func TestConfigMiscPanics(t *testing.T) {
 params:
 -- layouts/index.html --
 Foo: {{ site.Params.foo }}|
-	
-		
+
+
 	`
 		b := Test(t, files)
 
@@ -1188,8 +1188,8 @@ defaultContentLanguage = "en"
 	weight = 1
 -- layouts/index.html --
 Foo: {{ site.Params.foo }}|
-	
-		
+
+
 	`
 		b, err := NewIntegrationTestBuilder(
 			IntegrationTestConfig{
@@ -1215,8 +1215,8 @@ languageCode = "en"
 languageName = "English"
 weight = 1
 
-	
-		
+
+
 	`
 		b, err := NewIntegrationTestBuilder(
 			IntegrationTestConfig{
@@ -1241,7 +1241,7 @@ contentDir = "mycontent"
 -- layouts/index.html --
 Home.
 
-	
+
 `
 	b := Test(t, files)
 
@@ -1343,7 +1343,7 @@ disabled = true
 -- layouts/index.html --
 Home.
 
-	
+
 `
 	b := Test(t, files)
 
@@ -1438,7 +1438,7 @@ home = ["html"]
 -- hugo.toml --
 baseURL = "https://example.com"
 disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"]
-		
+
 		`
 
 		runVariant(t, files, nil)
diff --git a/hugolib/filesystems/basefs_test.go b/hugolib/filesystems/basefs_test.go
index 10b4a4cb2..e39709386 100644
--- a/hugolib/filesystems/basefs_test.go
+++ b/hugolib/filesystems/basefs_test.go
@@ -315,7 +315,7 @@ func TestStaticFs(t *testing.T) {
 	checkFileContent(sfs, "f2.txt", c, "Hugo Themes Still Rocks!")
 }
 
-func TestStaticFsMultiHost(t *testing.T) {
+func TestStaticFsMultihost(t *testing.T) {
 	c := qt.New(t)
 	v := config.New()
 	workDir := "mywork"
@@ -537,7 +537,7 @@ SCSS Match: {{ with resources.Match "**.scss" }}{{ . | len }}|{{ range .}}{{ .Re
 
 	b := hugolib.Test(t, files)
 
-	b.AssertFileContent("public/index.html", `	
+	b.AssertFileContent("public/index.html", `
 SCSS: /scss/app.scss|body { color: blue; }|
 SCSS Match: 2|
 `)
diff --git a/hugolib/hugo_sites_multihost_test.go b/hugolib/hugo_sites_multihost_test.go
index 4b779ee92..937166146 100644
--- a/hugolib/hugo_sites_multihost_test.go
+++ b/hugolib/hugo_sites_multihost_test.go
@@ -66,12 +66,12 @@ robots|{{ site.Language.Lang }}
 404|{{ site.Language.Lang }}
 
 
-	
+
 `
 
 	b := Test(t, files)
 
-	b.Assert(b.H.Conf.IsMultiLingual(), qt.Equals, true)
+	b.Assert(b.H.Conf.IsMultilingual(), qt.Equals, true)
 	b.Assert(b.H.Conf.IsMultihost(), qt.Equals, true)
 
 	// helpers.PrintFs(b.H.Fs.PublishDir, "", os.Stdout)
diff --git a/hugolib/mount_filters_test.go b/hugolib/mount_filters_test.go
index eec2e713d..16b062ec6 100644
--- a/hugolib/mount_filters_test.go
+++ b/hugolib/mount_filters_test.go
@@ -112,6 +112,6 @@ Template: false
 Resource1: /js/include.js:END
 Resource2: :END
 Resource3: :END
-Resources: [include.js]
+Resources: [/js/include.js]
 `)
 }
diff --git a/hugolib/page_test.go b/hugolib/page_test.go
index b6236ca5f..b0ab7f09c 100644
--- a/hugolib/page_test.go
+++ b/hugolib/page_test.go
@@ -709,7 +709,7 @@ func TestPageWithShortCodeInSummary(t *testing.T) {
 	assertFunc := func(t *testing.T, ext string, pages page.Pages) {
 		p := pages[0]
 		checkPageTitle(t, p, "Simple")
-		checkPageContent(t, p, normalizeExpected(ext, "<p>Summary Next Line. <figure><img src=\"/not/real\"/> </figure> . More text here.</p><p>Some more text</p>"))
+		checkPageContent(t, p, normalizeExpected(ext, "<p>Summary Next Line. <figure><img src=\"/not/real\"> </figure> . More text here.</p><p>Some more text</p>"))
 		checkPageSummary(t, p, "Summary Next Line.  . More text here. Some more text")
 		checkPageType(t, p, "page")
 	}
diff --git a/hugolib/rebuild_test.go b/hugolib/rebuild_test.go
index 98a8d0949..f3b10cf18 100644
--- a/hugolib/rebuild_test.go
+++ b/hugolib/rebuild_test.go
@@ -1472,3 +1472,21 @@ all: {{ $ab.RelPermalink }}
 	b.AddFiles("assets/common/c3.css", "c3").Build()
 	b.AssertFileContent("public/ab.css", "abc1c2 editedc3")
 }
+
+func TestRebuildEditArchetypeFile(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+baseURL = "https://example.com"
+disableLiveReload = true
+-- archetypes/default.md --
+---
+title: "Default"
+---
+`
+
+	b := TestRunning(t, files)
+	// Just make sure that it doesn't panic.
+	b.EditFileReplaceAll("archetypes/default.md", "Default", "Default Edited").Build()
+}
diff --git a/resources/page/page_matcher_test.go b/resources/page/page_matcher_test.go
index 3ab68e8af..dfb479d5e 100644
--- a/resources/page/page_matcher_test.go
+++ b/resources/page/page_matcher_test.go
@@ -180,7 +180,7 @@ func (c testConfig) IsMultihost() bool {
 	return c.multihost
 }
 
-func (c testConfig) IsMultiLingual() bool {
+func (c testConfig) IsMultilingual() bool {
 	return c.multilingual
 }
 
diff --git a/resources/page/pagemeta/pagemeta_integration_test.go b/resources/page/pagemeta/pagemeta_integration_test.go
new file mode 100644
index 000000000..4d195b7f0
--- /dev/null
+++ b/resources/page/pagemeta/pagemeta_integration_test.go
@@ -0,0 +1,45 @@
+// Copyright 2024 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pagemeta_test
+
+import (
+	"testing"
+
+	"github.com/gohugoio/hugo/hugolib"
+)
+
+func TestLastModEq(t *testing.T) {
+	files := `
+-- hugo.toml --
+timeZone = "Europe/London"
+-- content/p1.md --
+---
+title: p1
+date: 2024-03-13T06:00:00
+---
+-- layouts/_default/single.html --
+Date: {{ .Date }}
+Lastmod: {{ .Lastmod }}
+Eq: {{ eq .Date .Lastmod }}
+
+`
+
+	b := hugolib.Test(t, files)
+
+	b.AssertFileContent("public/p1/index.html", `
+Date: 2024-03-13 06:00:00 &#43;0000 GMT
+Lastmod: 2024-03-13 06:00:00 &#43;0000 GMT
+Eq: true
+`)
+}
diff --git a/testscripts/commands/gen.txt b/testscripts/commands/gen.txt
index e11ba0642..2ab90e5be 100644
--- a/testscripts/commands/gen.txt
+++ b/testscripts/commands/gen.txt
@@ -16,4 +16,4 @@ checkfilecount $NUM_COMMANDS manpages
 hugo gen chromastyles -h
 stdout 'Generate CSS stylesheet for the Chroma code highlighter'
 hugo gen chromastyles --style monokai
-stdout '/\* LineHighlight \*/ \.chroma \.hl \{ background-color: #3c3d38 \}'
+stdout '/\* LineHighlight \*/ \.chroma \.hl \{ background-color:#3c3d38 \}'
diff --git a/tpl/resources/resources_integration_test.go b/tpl/resources/resources_integration_test.go
index b4630b6a2..6bc872bca 100644
--- a/tpl/resources/resources_integration_test.go
+++ b/tpl/resources/resources_integration_test.go
@@ -171,3 +171,70 @@ Home.
 	b.AssertFileExists("public/a.txt", true) // failing test
 	b.AssertFileExists("public/b.txt", true) // failing test
 }
+
+func TestGlobalResourcesNotPublishedRegressionIssue12214(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+disableKinds = ['page','rss','section','sitemap','taxonomy','term']
+-- assets/files/a.txt --
+I am a.txt
+-- assets/files/b.txt --
+I am b.txt
+-- assets/files/c.txt --
+I am c.txt
+-- assets/files/C.txt --
+I am C.txt
+-- layouts/index.html --
+Home.
+{{ with resources.ByType "text" }}
+  {{ with .Get "files/a.txt" }}
+    {{ .Publish }}
+	files/a.txt: {{ .Name }}
+  {{ end }}
+  {{ with .Get "/files/a.txt" }}
+	/files/a.txt: {{ .Name }}
+  {{ end }}
+  {{ with .GetMatch "files/*b*" }}
+    {{ .Publish }}
+	files/*b*: {{ .Name }}
+  {{ end }}
+  {{ with .GetMatch "files/C*" }}
+    {{ .Publish }}
+    files/C*: {{ .Name }}
+  {{ end }}
+  {{ with .GetMatch "files/c*" }}
+	{{ .Publish }}
+	files/c*: {{ .Name }}
+  {{ end }}
+  {{ with .GetMatch "/files/c*" }}
+    /files/c*: {{ .Name }}
+  {{ end }}
+  {{ with .Match "files/C*" }}
+	match files/C*: {{ len . }}|
+  {{ end }}
+  {{ with .Match "/files/C*" }}
+  match /files/C*: {{ len . }}|
+{{ end }}
+{{ end }}
+`
+
+	b := hugolib.Test(t, files)
+
+	b.AssertFileContent("public/index.html", `
+files/a.txt: /files/a.txt
+# There are both C.txt and c.txt in the assets, but the Glob matching is case insensitive, so GetMatch returns the first.
+files/C*: /files/C.txt
+files/c*: /files/C.txt
+files/*b*: /files/b.txt
+/files/c*: /files/C.txt
+/files/a.txt: /files/a.txt
+match files/C*: 2|
+match /files/C*: 2|
+	`)
+
+	b.AssertFileContent("public/files/a.txt", "I am a.txt")
+	b.AssertFileContent("public/files/b.txt", "I am b.txt")
+	b.AssertFileContent("public/files/C.txt", "I am C.txt")
+}