Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gohugoio/hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/langs
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-04-10 21:30:52 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-04-12 14:24:16 +0300
commit627eed1d620910f494056330733db6c6187b8fe9 (patch)
treea136a398e8f85b10d3de7b1781825453886435ed /langs
parent82ba634ed90186c756189a79b637559b28dd363e (diff)
Make string sorting (e.g. ByTitle, ByLinkTitle and ByParam) language aware
Fixes #2180
Diffstat (limited to 'langs')
-rw-r--r--langs/language.go39
-rw-r--r--langs/language_test.go59
2 files changed, 96 insertions, 2 deletions
diff --git a/langs/language.go b/langs/language.go
index 0df2914a1..244f6a743 100644
--- a/langs/language.go
+++ b/langs/language.go
@@ -19,6 +19,9 @@ import (
"sync"
"time"
+ "golang.org/x/text/collate"
+ "golang.org/x/text/language"
+
"github.com/pkg/errors"
"github.com/gohugoio/hugo/common/htime"
@@ -80,8 +83,9 @@ type Language struct {
// TODO(bep) do the same for some of the others.
translator locales.Translator
timeFormatter htime.TimeFormatter
-
- location *time.Location
+ tag language.Tag
+ collator *Collator
+ location *time.Location
// Error during initialization. Will fail the buld.
initErr error
@@ -111,6 +115,18 @@ func NewLanguage(lang string, cfg config.Provider) *Language {
}
}
+ var coll *Collator
+ tag, err := language.Parse(lang)
+ if err == nil {
+ coll = &Collator{
+ c: collate.New(tag),
+ }
+ } else {
+ coll = &Collator{
+ c: collate.New(language.English),
+ }
+ }
+
l := &Language{
Lang: lang,
ContentDir: cfg.GetString("contentDir"),
@@ -119,6 +135,8 @@ func NewLanguage(lang string, cfg config.Provider) *Language {
params: params,
translator: translator,
timeFormatter: htime.NewTimeFormatter(translator),
+ tag: tag,
+ collator: coll,
}
if err := l.loadLocation(cfg.GetString("timeZone")); err != nil {
@@ -275,6 +293,10 @@ func GetLocation(l *Language) *time.Location {
return l.location
}
+func GetCollator(l *Language) *Collator {
+ return l.collator
+}
+
func (l *Language) loadLocation(tzStr string) error {
location, err := time.LoadLocation(tzStr)
if err != nil {
@@ -284,3 +306,16 @@ func (l *Language) loadLocation(tzStr string) error {
return nil
}
+
+type Collator struct {
+ sync.Mutex
+ c *collate.Collator
+}
+
+// CompareStrings compares a and b.
+// It returns -1 if a < b, 1 if a > b and 0 if a == b.
+// Note that the Collator is not thread safe, so you may want
+// to aquire a lock on it before calling this method.
+func (c *Collator) CompareStrings(a, b string) int {
+ return c.c.CompareString(a, b)
+}
diff --git a/langs/language_test.go b/langs/language_test.go
index e6ef94824..264e813a0 100644
--- a/langs/language_test.go
+++ b/langs/language_test.go
@@ -14,10 +14,13 @@
package langs
import (
+ "sync"
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/config"
+ "golang.org/x/text/collate"
+ "golang.org/x/text/language"
)
func TestGetGlobalOnlySetting(t *testing.T) {
@@ -47,3 +50,59 @@ func TestLanguageParams(t *testing.T) {
c.Assert(lang.Params()["p1"], qt.Equals, "p1p")
c.Assert(lang.Get("p1"), qt.Equals, "p1cfg")
}
+
+func TestCollator(t *testing.T) {
+
+ c := qt.New(t)
+
+ var wg sync.WaitGroup
+
+ coll := &Collator{c: collate.New(language.English, collate.Loose)}
+
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ coll.Lock()
+ defer coll.Unlock()
+ defer wg.Done()
+ for j := 0; j < 10; j++ {
+ k := coll.CompareStrings("abc", "def")
+ c.Assert(k, qt.Equals, -1)
+ }
+ }()
+ }
+ wg.Wait()
+
+}
+
+func BenchmarkCollator(b *testing.B) {
+ s := []string{"foo", "bar", "éntre", "baz", "qux", "quux", "corge", "grault", "garply", "waldo", "fred", "plugh", "xyzzy", "thud"}
+
+ doWork := func(coll *Collator) {
+ for i := 0; i < len(s); i++ {
+ for j := i + 1; j < len(s); j++ {
+ _ = coll.CompareStrings(s[i], s[j])
+ }
+ }
+ }
+
+ b.Run("Single", func(b *testing.B) {
+ coll := &Collator{c: collate.New(language.English, collate.Loose)}
+ for i := 0; i < b.N; i++ {
+ doWork(coll)
+ }
+ })
+
+ b.Run("Para", func(b *testing.B) {
+ b.RunParallel(func(pb *testing.PB) {
+ coll := &Collator{c: collate.New(language.English, collate.Loose)}
+
+ for pb.Next() {
+ coll.Lock()
+ doWork(coll)
+ coll.Unlock()
+ }
+ })
+ })
+
+}