diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-04-10 20:30:52 +0200 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-04-12 13:24:16 +0200 |
commit | 627eed1d620910f494056330733db6c6187b8fe9 (patch) | |
tree | a136a398e8f85b10d3de7b1781825453886435ed /tpl | |
parent | 82ba634ed90186c756189a79b637559b28dd363e (diff) |
Make string sorting (e.g. ByTitle, ByLinkTitle and ByParam) language aware
Fixes #2180
Diffstat (limited to 'tpl')
-rw-r--r-- | tpl/collections/collections_test.go | 4 | ||||
-rw-r--r-- | tpl/collections/sort.go | 16 | ||||
-rw-r--r-- | tpl/collections/sort_test.go | 6 | ||||
-rw-r--r-- | tpl/compare/compare.go | 24 |
4 files changed, 40 insertions, 10 deletions
diff --git a/tpl/collections/collections_test.go b/tpl/collections/collections_test.go index 8fc43318d..bcc2855c7 100644 --- a/tpl/collections/collections_test.go +++ b/tpl/collections/collections_test.go @@ -133,7 +133,9 @@ func TestDelimit(t *testing.T) { t.Parallel() c := qt.New(t) - ns := New(&deps.Deps{}) + ns := New(&deps.Deps{ + Language: langs.NewDefaultLanguage(config.New()), + }) for i, test := range []struct { seq any diff --git a/tpl/collections/sort.go b/tpl/collections/sort.go index 305399eb8..ce7f27771 100644 --- a/tpl/collections/sort.go +++ b/tpl/collections/sort.go @@ -20,6 +20,7 @@ import ( "strings" "github.com/gohugoio/hugo/common/maps" + "github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/tpl/compare" "github.com/spf13/cast" ) @@ -47,8 +48,10 @@ func (ns *Namespace) Sort(seq any, args ...any) (any, error) { return nil, errors.New("can't sort " + reflect.ValueOf(seq).Type().String()) } + collator := langs.GetCollator(ns.deps.Language) + // Create a list of pairs that will be used to do the sort - p := pairList{SortAsc: true, SliceType: sliceType} + p := pairList{Collator: collator, SortAsc: true, SliceType: sliceType} p.Pairs = make([]pair, seqv.Len()) var sortByField string @@ -124,6 +127,10 @@ func (ns *Namespace) Sort(seq any, args ...any) (any, error) { } } } + + collator.Lock() + defer collator.Unlock() + return p.sort(), nil } @@ -137,6 +144,7 @@ type pair struct { // A slice of pairs that implements sort.Interface to sort by Value. type pairList struct { + Collator *langs.Collator Pairs []pair SortAsc bool SliceType reflect.Type @@ -151,16 +159,16 @@ func (p pairList) Less(i, j int) bool { if iv.IsValid() { if jv.IsValid() { // can only call Interface() on valid reflect Values - return sortComp.Lt(iv.Interface(), jv.Interface()) + return sortComp.LtCollate(p.Collator, iv.Interface(), jv.Interface()) } // if j is invalid, test i against i's zero value - return sortComp.Lt(iv.Interface(), reflect.Zero(iv.Type())) + return sortComp.LtCollate(p.Collator, iv.Interface(), reflect.Zero(iv.Type())) } if jv.IsValid() { // if i is invalid, test j against j's zero value - return sortComp.Lt(reflect.Zero(jv.Type()), jv.Interface()) + return sortComp.LtCollate(p.Collator, reflect.Zero(jv.Type()), jv.Interface()) } return false diff --git a/tpl/collections/sort_test.go b/tpl/collections/sort_test.go index 698118864..a4adccf51 100644 --- a/tpl/collections/sort_test.go +++ b/tpl/collections/sort_test.go @@ -19,6 +19,8 @@ import ( "testing" "github.com/gohugoio/hugo/common/maps" + "github.com/gohugoio/hugo/config" + "github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/deps" ) @@ -28,7 +30,9 @@ type stringsSlice []string func TestSort(t *testing.T) { t.Parallel() - ns := New(&deps.Deps{}) + ns := New(&deps.Deps{ + Language: langs.NewDefaultLanguage(config.New()), + }) type ts struct { MyInt int diff --git a/tpl/compare/compare.go b/tpl/compare/compare.go index 21b9c5bcd..3e9730dad 100644 --- a/tpl/compare/compare.go +++ b/tpl/compare/compare.go @@ -21,6 +21,7 @@ import ( "time" "github.com/gohugoio/hugo/compare" + "github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/common/types" ) @@ -188,10 +189,11 @@ func (n *Namespace) Le(first any, others ...any) bool { } // Lt returns the boolean truth of arg1 < arg2 && arg1 < arg3 && arg1 < arg4. -func (n *Namespace) Lt(first any, others ...any) bool { +// The provided collator will be used for string comparisons. +func (n *Namespace) LtCollate(collator *langs.Collator, first any, others ...any) bool { n.checkComparisonArgCount(1, others...) for _, other := range others { - left, right := n.compareGet(first, other) + left, right := n.compareGetWithCollator(collator, first, other) if !(left < right) { return false } @@ -199,6 +201,11 @@ func (n *Namespace) Lt(first any, others ...any) bool { return true } +// Lt returns the boolean truth of arg1 < arg2 && arg1 < arg3 && arg1 < arg4. +func (n *Namespace) Lt(first any, others ...any) bool { + return n.LtCollate(nil, first, others...) +} + func (n *Namespace) checkComparisonArgCount(min int, others ...any) bool { if len(others) < min { panic("missing arguments for comparison") @@ -216,6 +223,10 @@ func (n *Namespace) Conditional(condition bool, a, b any) any { } func (ns *Namespace) compareGet(a any, b any) (float64, float64) { + return ns.compareGetWithCollator(nil, a, b) +} + +func (ns *Namespace) compareGetWithCollator(collator *langs.Collator, a any, b any) (float64, float64) { if ac, ok := a.(compare.Comparer); ok { c := ac.Compare(b) if c < 0 { @@ -296,8 +307,13 @@ func (ns *Namespace) compareGet(a any, b any) (float64, float64) { } } - if ns.caseInsensitive && leftStr != nil && rightStr != nil { - c := compare.Strings(*leftStr, *rightStr) + if (ns.caseInsensitive || collator != nil) && leftStr != nil && rightStr != nil { + var c int + if collator != nil { + c = collator.CompareStrings(*leftStr, *rightStr) + } else { + c = compare.Strings(*leftStr, *rightStr) + } if c < 0 { return 0, 1 } else if c > 0 { |