Move to new locales library and upgrade CLDR from v36.1 to v48.1

* I had all kinds of issues upgrading CLDR on the old library, so I decided to start fresh in github.com/bep/golocales
* It shaves off about 3 MB of the binary, and package init cost is zero compared to the old localescompressed (5000x faster).
* We will probably move to the `text/**` packages at this point, but this will have to do for now.
This commit is contained in:
Bjørn Erik Pedersen
2026-03-05 12:39:43 +01:00
parent 4eafd9eb7b
commit 4652ae4a44
10 changed files with 77 additions and 103 deletions
+18 -18
View File
@@ -18,10 +18,10 @@ import (
"strings"
"time"
"github.com/bep/golocales"
"github.com/bep/clocks"
"github.com/spf13/cast"
"github.com/gohugoio/locales"
)
var (
@@ -78,9 +78,9 @@ var (
Clock = clocks.System()
)
func NewTimeFormatter(ltr locales.Translator) TimeFormatter {
func NewTimeFormatter(ltr golocales.Translator) TimeFormatter {
if ltr == nil {
panic("must provide a locales.Translator")
panic("must provide a golocales.Translator")
}
return TimeFormatter{
ltr: ltr,
@@ -89,7 +89,7 @@ func NewTimeFormatter(ltr locales.Translator) TimeFormatter {
// TimeFormatter is locale aware.
type TimeFormatter struct {
ltr locales.Translator
ltr golocales.Translator
}
func (f TimeFormatter) Format(t time.Time, layout string) string {
@@ -101,39 +101,39 @@ func (f TimeFormatter) Format(t time.Time, layout string) string {
// It may be one of Hugo's custom layouts.
switch strings.ToLower(layout[1:]) {
case "date_full":
return f.ltr.FmtDateFull(t)
return f.ltr.FormatDateFull(t)
case "date_long":
return f.ltr.FmtDateLong(t)
return f.ltr.FormatDateLong(t)
case "date_medium":
return f.ltr.FmtDateMedium(t)
return f.ltr.FormatDateMedium(t)
case "date_short":
return f.ltr.FmtDateShort(t)
return f.ltr.FormatDateShort(t)
case "time_full":
return f.ltr.FmtTimeFull(t)
return f.ltr.FormatTimeFull(t)
case "time_long":
return f.ltr.FmtTimeLong(t)
return f.ltr.FormatTimeLong(t)
case "time_medium":
return f.ltr.FmtTimeMedium(t)
return f.ltr.FormatTimeMedium(t)
case "time_short":
return f.ltr.FmtTimeShort(t)
return f.ltr.FormatTimeShort(t)
}
}
s := t.Format(layout)
monthIdx := t.Month() - 1 // Month() starts at 1.
monthIdx := t.Month() - 1 // time.Month is 1-based, but our month name slices are 0-based.
dayIdx := t.Weekday()
if strings.Contains(layout, "January") {
s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthWide(t.Month()))
s = strings.ReplaceAll(s, longMonthNames[monthIdx], f.ltr.MonthsWide()[monthIdx])
} else if strings.Contains(layout, "Jan") {
s = strings.ReplaceAll(s, shortMonthNames[monthIdx], f.ltr.MonthAbbreviated(t.Month()))
s = strings.ReplaceAll(s, shortMonthNames[monthIdx], f.ltr.MonthsAbbreviated()[monthIdx])
}
if strings.Contains(layout, "Monday") {
s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdayWide(t.Weekday()))
s = strings.ReplaceAll(s, longDayNames[dayIdx], f.ltr.WeekdaysWide()[dayIdx])
} else if strings.Contains(layout, "Mon") {
s = strings.ReplaceAll(s, shortDayNames[dayIdx], f.ltr.WeekdayAbbreviated(t.Weekday()))
s = strings.ReplaceAll(s, shortDayNames[dayIdx], f.ltr.WeekdaysAbbreviated()[dayIdx])
}
return s
+19 -18
View File
@@ -17,8 +17,9 @@ import (
"testing"
"time"
"github.com/bep/golocales"
qt "github.com/frankban/quicktest"
translators "github.com/gohugoio/localescompressed"
)
func TestTimeFormatter(t *testing.T) {
@@ -34,7 +35,7 @@ func TestTimeFormatter(t *testing.T) {
mondayNovemberFirst = mondayNovemberFirst.Add(33 * time.Second)
c.Run("Norsk nynorsk", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
f := NewTimeFormatter(golocales.New("nn"))
c.Assert(f.Format(june06, "Monday Jan 2 2006"), qt.Equals, "onsdag juni 6 2018")
c.Assert(f.Format(june06, "Mon January 2 2006"), qt.Equals, "on. juni 6 2018")
@@ -42,35 +43,35 @@ func TestTimeFormatter(t *testing.T) {
})
c.Run("Custom layouts Norsk nynorsk", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
f := NewTimeFormatter(golocales.New("nn"))
c.Assert(f.Format(june06, ":date_full"), qt.Equals, "onsdag 6. juni 2018")
c.Assert(f.Format(june06, ":date_long"), qt.Equals, "6. juni 2018")
c.Assert(f.Format(june06, ":date_medium"), qt.Equals, "6. juni 2018")
c.Assert(f.Format(june06, ":date_short"), qt.Equals, "06.06.2018")
c.Assert(f.Format(june06, ":date_short"), qt.Equals, "06.06.18")
c.Assert(f.Format(june06, ":time_full"), qt.Equals, "kl. 02:09:37 UTC")
c.Assert(f.Format(june06, ":time_full"), qt.Equals, "02:09:37 UTC")
c.Assert(f.Format(june06, ":time_long"), qt.Equals, "02:09:37 UTC")
c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "02:09:37")
c.Assert(f.Format(june06, ":time_short"), qt.Equals, "02:09")
})
c.Run("Custom layouts English", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("en"))
f := NewTimeFormatter(golocales.New("en"))
c.Assert(f.Format(june06, ":date_full"), qt.Equals, "Wednesday, June 6, 2018")
c.Assert(f.Format(june06, ":date_long"), qt.Equals, "June 6, 2018")
c.Assert(f.Format(june06, ":date_medium"), qt.Equals, "Jun 6, 2018")
c.Assert(f.Format(june06, ":date_short"), qt.Equals, "6/6/18")
c.Assert(f.Format(june06, ":time_full"), qt.Equals, "2:09:37 am UTC")
c.Assert(f.Format(june06, ":time_long"), qt.Equals, "2:09:37 am UTC")
c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "2:09:37 am")
c.Assert(f.Format(june06, ":time_short"), qt.Equals, "2:09 am")
c.Assert(f.Format(june06, ":time_full"), qt.Equals, "2:09:37\u202fam UTC")
c.Assert(f.Format(june06, ":time_long"), qt.Equals, "2:09:37\u202fam UTC")
c.Assert(f.Format(june06, ":time_medium"), qt.Equals, "2:09:37\u202fam")
c.Assert(f.Format(june06, ":time_short"), qt.Equals, "2:09\u202fam")
})
c.Run("English", func(c *qt.C) {
f := NewTimeFormatter(translators.GetTranslator("en"))
f := NewTimeFormatter(golocales.New("en"))
c.Assert(f.Format(june06, "Monday Jan 2 2006"), qt.Equals, "Wednesday Jun 6 2018")
c.Assert(f.Format(june06, "Mon January 2 2006"), qt.Equals, "Wed June 6 2018")
@@ -78,31 +79,31 @@ func TestTimeFormatter(t *testing.T) {
})
c.Run("Weekdays German", func(c *qt.C) {
tr := translators.GetTranslator("de")
tr := golocales.New("de")
f := NewTimeFormatter(tr)
// Issue #9107
for i, weekDayWideGerman := range []string{"Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"} {
date := mondayNovemberFirst.Add(time.Duration(i*24) * time.Hour)
c.Assert(tr.WeekdayWide(date.Weekday()), qt.Equals, weekDayWideGerman)
c.Assert(tr.WeekdaysWide()[date.Weekday()], qt.Equals, weekDayWideGerman)
c.Assert(f.Format(date, "Monday"), qt.Equals, weekDayWideGerman)
}
for i, weekDayAbbreviatedGerman := range []string{"Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa.", "So."} {
date := mondayNovemberFirst.Add(time.Duration(i*24) * time.Hour)
c.Assert(tr.WeekdayAbbreviated(date.Weekday()), qt.Equals, weekDayAbbreviatedGerman)
c.Assert(tr.WeekdaysAbbreviated()[date.Weekday()], qt.Equals, weekDayAbbreviatedGerman)
c.Assert(f.Format(date, "Mon"), qt.Equals, weekDayAbbreviatedGerman)
}
})
c.Run("Months German", func(c *qt.C) {
tr := translators.GetTranslator("de")
tr := golocales.New("de")
f := NewTimeFormatter(tr)
// Issue #9107
for i, monthWideNorway := range []string{"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli"} {
date := jan06.Add(time.Duration(i*24*31) * time.Hour)
c.Assert(tr.MonthWide(date.Month()), qt.Equals, monthWideNorway)
c.Assert(tr.MonthsWide()[date.Month()-1], qt.Equals, monthWideNorway)
c.Assert(f.Format(date, "January"), qt.Equals, monthWideNorway)
}
})
@@ -121,7 +122,7 @@ func BenchmarkTimeFormatter(b *testing.B) {
})
b.Run("Localized", func(b *testing.B) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
f := NewTimeFormatter(golocales.New("nn"))
b.ResetTimer()
for b.Loop() {
got := f.Format(june06, "Monday Jan 2 2006")
@@ -132,7 +133,7 @@ func BenchmarkTimeFormatter(b *testing.B) {
})
b.Run("Localized Custom", func(b *testing.B) {
f := NewTimeFormatter(translators.GetTranslator("nn"))
f := NewTimeFormatter(golocales.New("nn"))
b.ResetTimer()
for b.Loop() {
got := f.Format(june06, ":date_medium")