summaryrefslogtreecommitdiffstats
path: root/resources
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-04-10 20:30:52 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-04-12 13:24:16 +0200
commit627eed1d620910f494056330733db6c6187b8fe9 (patch)
treea136a398e8f85b10d3de7b1781825453886435ed /resources
parent82ba634ed90186c756189a79b637559b28dd363e (diff)
Make string sorting (e.g. ByTitle, ByLinkTitle and ByParam) language aware
Fixes #2180
Diffstat (limited to 'resources')
-rw-r--r--resources/page/integration_test.go66
-rw-r--r--resources/page/pagegroup.go19
-rw-r--r--resources/page/pages_sort.go61
3 files changed, 133 insertions, 13 deletions
diff --git a/resources/page/integration_test.go b/resources/page/integration_test.go
index 285b14342..9dc322b4a 100644
--- a/resources/page/integration_test.go
+++ b/resources/page/integration_test.go
@@ -70,3 +70,69 @@ date: "2020-02-01"
b.AssertFileContent("public/en/index.html", "0|February, 2020|Pages(1)1|January, 2020|Pages(1)")
b.AssertFileContent("public/fr/index.html", "0|février, 2020|Pages(1)1|janvier, 2020|Pages(1)")
}
+
+func TestPagesSortCollation(t *testing.T) {
+
+ files := `
+-- config.toml --
+defaultContentLanguage = 'en'
+defaultContentLanguageInSubdir = true
+[languages]
+[languages.en]
+title = 'My blog'
+weight = 1
+[languages.fr]
+title = 'Mon blogue'
+weight = 2
+[languages.nn]
+title = 'Bloggen min'
+weight = 3
+-- content/p1.md --
+---
+title: "zulu"
+date: "2020-01-01"
+param1: "xylophone"
+tags: ["xylophone", "éclair", "zulu", "emma"]
+---
+-- content/p2.md --
+---
+title: "émotion"
+date: "2020-01-01"
+param1: "violin"
+---
+-- content/p3.md --
+---
+title: "alpha"
+date: "2020-01-01"
+param1: "éclair"
+---
+-- layouts/index.html --
+ByTitle: {{ range site.RegularPages.ByTitle }}{{ .Title }}|{{ end }}
+ByLinkTitle: {{ range site.RegularPages.ByLinkTitle }}{{ .Title }}|{{ end }}
+ByParam: {{ range site.RegularPages.ByParam "param1" }}{{ .Params.param1 }}|{{ end }}
+Tags Alphabetical: {{ range site.Taxonomies.tags.Alphabetical }}{{ .Term }}|{{ end }}
+GroupBy: {{ range site.RegularPages.GroupBy "Title" }}{{ .Key }}|{{ end }}
+{{ with (site.GetPage "p1").Params.tags }}
+Sort: {{ sort . }}
+ByWeight: {{ range site.RegularPages.ByWeight }}{{ .Title }}|{{ end }}
+{{ end }}
+
+ `
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ NeedsOsFS: true,
+ }).Build()
+
+ b.AssertFileContent("public/en/index.html", `
+ByTitle: alpha|émotion|zulu|
+ByLinkTitle: alpha|émotion|zulu|
+ByParam: éclair|violin|xylophone
+Tags Alphabetical: éclair|emma|xylophone|zulu|
+GroupBy: alpha|émotion|zulu|
+Sort: [éclair emma xylophone zulu]
+ByWeight: alpha|émotion|zulu|
+`)
+}
diff --git a/resources/page/pagegroup.go b/resources/page/pagegroup.go
index 601af606a..1d9827907 100644
--- a/resources/page/pagegroup.go
+++ b/resources/page/pagegroup.go
@@ -53,13 +53,16 @@ type mapKeyByInt struct{ mapKeyValues }
func (s mapKeyByInt) Less(i, j int) bool { return s.mapKeyValues[i].Int() < s.mapKeyValues[j].Int() }
-type mapKeyByStr struct{ mapKeyValues }
+type mapKeyByStr struct {
+ less func(a, b string) bool
+ mapKeyValues
+}
func (s mapKeyByStr) Less(i, j int) bool {
- return compare.LessStrings(s.mapKeyValues[i].String(), s.mapKeyValues[j].String())
+ return s.less(s.mapKeyValues[i].String(), s.mapKeyValues[j].String())
}
-func sortKeys(v []reflect.Value, order string) []reflect.Value {
+func sortKeys(examplePage Page, v []reflect.Value, order string) []reflect.Value {
if len(v) <= 1 {
return v
}
@@ -72,10 +75,12 @@ func sortKeys(v []reflect.Value, order string) []reflect.Value {
sort.Sort(mapKeyByInt{v})
}
case reflect.String:
+ stringLess, close := collatorStringLess(examplePage)
+ defer close()
if order == "desc" {
- sort.Sort(sort.Reverse(mapKeyByStr{v}))
+ sort.Sort(sort.Reverse(mapKeyByStr{stringLess, v}))
} else {
- sort.Sort(mapKeyByStr{v})
+ sort.Sort(mapKeyByStr{stringLess, v})
}
}
return v
@@ -161,7 +166,7 @@ func (p Pages) GroupBy(key string, order ...string) (PagesGroup, error) {
tmp.SetMapIndex(fv, reflect.Append(tmp.MapIndex(fv), ppv))
}
- sortedKeys := sortKeys(tmp.MapKeys(), direction)
+ sortedKeys := sortKeys(p[0], tmp.MapKeys(), direction)
r := make([]PageGroup, len(sortedKeys))
for i, k := range sortedKeys {
r[i] = PageGroup{Key: k.Interface(), Pages: tmp.MapIndex(k).Interface().(Pages)}
@@ -213,7 +218,7 @@ func (p Pages) GroupByParam(key string, order ...string) (PagesGroup, error) {
}
var r []PageGroup
- for _, k := range sortKeys(tmp.MapKeys(), direction) {
+ for _, k := range sortKeys(p[0], tmp.MapKeys(), direction) {
r = append(r, PageGroup{Key: k.Interface(), Pages: tmp.MapIndex(k).Interface().(Pages)})
}
diff --git a/resources/page/pages_sort.go b/resources/page/pages_sort.go
index 02096dadd..08cb34a32 100644
--- a/resources/page/pages_sort.go
+++ b/resources/page/pages_sort.go
@@ -17,6 +17,7 @@ import (
"sort"
"github.com/gohugoio/hugo/common/collections"
+ "github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/resources/resource"
@@ -72,7 +73,7 @@ var (
}
if p1.Weight() == p2.Weight() {
if p1.Date().Unix() == p2.Date().Unix() {
- c := compare.Strings(p1.LinkTitle(), p2.LinkTitle())
+ c := collatorStringCompare(func(p Page) string { return p.LinkTitle() }, p1, p2)
if c == 0 {
if p1.File().IsZero() || p2.File().IsZero() {
return p1.File().IsZero()
@@ -121,11 +122,11 @@ var (
}
lessPageTitle = func(p1, p2 Page) bool {
- return compare.LessStrings(p1.Title(), p2.Title())
+ return collatorStringCompare(func(p Page) string { return p.Title() }, p1, p2) < 0
}
lessPageLinkTitle = func(p1, p2 Page) bool {
- return compare.LessStrings(p1.LinkTitle(), p2.LinkTitle())
+ return collatorStringCompare(func(p Page) string { return p.LinkTitle() }, p1, p2) < 0
}
lessPageDate = func(p1, p2 Page) bool {
@@ -151,6 +152,46 @@ func (p Pages) Limit(n int) Pages {
return p
}
+var collatorStringSort = func(getString func(Page) string) func(p Pages) {
+ return func(p Pages) {
+ if len(p) == 0 {
+ return
+ }
+ // Pages may be a mix of multiple languages, so we need to use the language
+ // for the currently rendered Site.
+ currentSite := p[0].Site().Current()
+ coll := langs.GetCollator(currentSite.Language())
+ coll.Lock()
+ defer coll.Unlock()
+
+ sort.SliceStable(p, func(i, j int) bool {
+ return coll.CompareStrings(getString(p[i]), getString(p[j])) < 0
+ })
+ }
+}
+
+var collatorStringCompare = func(getString func(Page) string, p1, p2 Page) int {
+ currentSite := p1.Site().Current()
+ coll := langs.GetCollator(currentSite.Language())
+ coll.Lock()
+ c := coll.CompareStrings(getString(p1), getString(p2))
+ coll.Unlock()
+ return c
+}
+
+var collatorStringLess = func(p Page) (less func(s1, s2 string) bool, close func()) {
+ currentSite := p.Site().Current()
+ coll := langs.GetCollator(currentSite.Language())
+ coll.Lock()
+ return func(s1, s2 string) bool {
+ return coll.CompareStrings(s1, s2) < 1
+ },
+ func() {
+ coll.Unlock()
+ }
+
+}
+
// ByWeight sorts the Pages by weight and returns a copy.
//
// Adjacent invocations on the same receiver will return a cached result.
@@ -175,7 +216,8 @@ func SortByDefault(pages Pages) {
func (p Pages) ByTitle() Pages {
const key = "pageSort.ByTitle"
- pages, _ := spc.get(key, pageBy(lessPageTitle).Sort, p)
+ pages, _ := spc.get(key, collatorStringSort(func(p Page) string { return p.Title() }), p)
+
return pages
}
@@ -187,7 +229,7 @@ func (p Pages) ByTitle() Pages {
func (p Pages) ByLinkTitle() Pages {
const key = "pageSort.ByLinkTitle"
- pages, _ := spc.get(key, pageBy(lessPageLinkTitle).Sort, p)
+ pages, _ := spc.get(key, collatorStringSort(func(p Page) string { return p.LinkTitle() }), p)
return pages
}
@@ -323,9 +365,15 @@ func (p Pages) Reverse() Pages {
//
// This may safely be executed in parallel.
func (p Pages) ByParam(paramsKey any) Pages {
+ if len(p) < 2 {
+ return p
+ }
paramsKeyStr := cast.ToString(paramsKey)
key := "pageSort.ByParam." + paramsKeyStr
+ stringLess, close := collatorStringLess(p[0])
+ defer close()
+
paramsKeyComparator := func(p1, p2 Page) bool {
v1, _ := p1.Param(paramsKeyStr)
v2, _ := p2.Param(paramsKeyStr)
@@ -354,7 +402,8 @@ func (p Pages) ByParam(paramsKey any) Pages {
s1 := cast.ToString(v1)
s2 := cast.ToString(v2)
- return compare.LessStrings(s1, s2)
+ return stringLess(s1, s2)
+
}
pages, _ := spc.get(key, pageBy(paramsKeyComparator).Sort, p)