mirror of
https://github.com/gohugoio/hugo.git
synced 2025-09-02 22:52:51 +02:00
Make string sorting (e.g. ByTitle, ByLinkTitle and ByParam) language aware
Fixes #2180
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user