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/tpl/lang
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-07-28 13:28:52 +0300
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-07-29 17:40:06 +0300
commit7907d24ba16fc5a80930c1aabf5144e684ff7f29 (patch)
tree7f4a9500a0167f4ea5b9c41a1113288ffb8f1c95 /tpl/lang
parent726fe9c3c97a9c979dc7862e7f226fc5ec1341de (diff)
tpl/lang: Add new localized versions of lang.FormatNumber etc.
Fixes #8820
Diffstat (limited to 'tpl/lang')
-rw-r--r--tpl/lang/init.go44
-rw-r--r--tpl/lang/init_test.go7
-rw-r--r--tpl/lang/lang.go88
-rw-r--r--tpl/lang/lang_test.go53
4 files changed, 174 insertions, 18 deletions
diff --git a/tpl/lang/init.go b/tpl/lang/init.go
index 520eccb88..beb148ff6 100644
--- a/tpl/lang/init.go
+++ b/tpl/lang/init.go
@@ -15,6 +15,7 @@ package lang
import (
"github.com/gohugoio/hugo/deps"
+ "github.com/gohugoio/hugo/langs"
"github.com/gohugoio/hugo/tpl/internal"
)
@@ -22,7 +23,7 @@ const name = "lang"
func init() {
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
- ctx := New(d)
+ ctx := New(d, langs.GetTranslator(d.Language))
ns := &internal.TemplateFuncsNamespace{
Name: name,
@@ -34,16 +35,45 @@ func init() {
[][2]string{},
)
- ns.AddMethodMapping(ctx.NumFmt,
+ ns.AddMethodMapping(ctx.FormatNumber,
nil,
[][2]string{
- {`{{ lang.NumFmt 2 12345.6789 }}`, `12,345.68`},
- {`{{ lang.NumFmt 2 12345.6789 "- , ." }}`, `12.345,68`},
- {`{{ lang.NumFmt 6 -12345.6789 "- ." }}`, `-12345.678900`},
- {`{{ lang.NumFmt 0 -12345.6789 "- . ," }}`, `-12,346`},
- {`{{ -98765.4321 | lang.NumFmt 2 }}`, `-98,765.43`},
+ {`{{ 512.5032 | lang.FormatNumber 2 }}`, `512.50`},
},
)
+
+ ns.AddMethodMapping(ctx.FormatPercent,
+ nil,
+ [][2]string{
+ {`{{ 512.5032 | lang.FormatPercent 2 }}`, `512.50%`},
+ },
+ )
+
+ ns.AddMethodMapping(ctx.FormatCurrency,
+ nil,
+ [][2]string{
+ {`{{ 512.5032 | lang.FormatCurrency 2 "USD" }}`, `$512.50`},
+ },
+ )
+
+ ns.AddMethodMapping(ctx.FormatAccounting,
+ nil,
+ [][2]string{
+ {`{{ 512.5032 | lang.FormatAccounting 2 "NOK" }}`, `NOK512.50`},
+ },
+ )
+
+ ns.AddMethodMapping(ctx.FormatNumberCustom,
+ nil,
+ [][2]string{
+ {`{{ lang.FormatNumberCustom 2 12345.6789 }}`, `12,345.68`},
+ {`{{ lang.FormatNumberCustom 2 12345.6789 "- , ." }}`, `12.345,68`},
+ {`{{ lang.FormatNumberCustom 6 -12345.6789 "- ." }}`, `-12345.678900`},
+ {`{{ lang.FormatNumberCustom 0 -12345.6789 "- . ," }}`, `-12,346`},
+ {`{{ -98765.4321 | lang.FormatNumberCustom 2 }}`, `-98,765.43`},
+ },
+ )
+
return ns
}
diff --git a/tpl/lang/init_test.go b/tpl/lang/init_test.go
index 82def5523..61d7b5047 100644
--- a/tpl/lang/init_test.go
+++ b/tpl/lang/init_test.go
@@ -16,6 +16,9 @@ package lang
import (
"testing"
+ "github.com/gohugoio/hugo/config"
+ "github.com/gohugoio/hugo/langs"
+
"github.com/gohugoio/hugo/htesting/hqt"
qt "github.com/frankban/quicktest"
@@ -29,7 +32,9 @@ func TestInit(t *testing.T) {
var ns *internal.TemplateFuncsNamespace
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
- ns = nsf(&deps.Deps{})
+ ns = nsf(&deps.Deps{
+ Language: langs.NewDefaultLanguage(config.New()),
+ })
if ns.Name == name {
found = true
break
diff --git a/tpl/lang/lang.go b/tpl/lang/lang.go
index 4e6c9c70a..0cf448caa 100644
--- a/tpl/lang/lang.go
+++ b/tpl/lang/lang.go
@@ -20,6 +20,8 @@ import (
"strconv"
"strings"
+ translators "github.com/bep/gotranslators"
+ "github.com/go-playground/locales"
"github.com/pkg/errors"
"github.com/gohugoio/hugo/deps"
@@ -27,15 +29,17 @@ import (
)
// New returns a new instance of the lang-namespaced template functions.
-func New(deps *deps.Deps) *Namespace {
+func New(deps *deps.Deps, translator locales.Translator) *Namespace {
return &Namespace{
- deps: deps,
+ translator: translator,
+ deps: deps,
}
}
// Namespace provides template functions for the "lang" namespace.
type Namespace struct {
- deps *deps.Deps
+ translator locales.Translator
+ deps *deps.Deps
}
// Translate returns a translated string for id.
@@ -57,14 +61,81 @@ func (ns *Namespace) Translate(id interface{}, args ...interface{}) (string, err
return ns.deps.Translate(sid, templateData), nil
}
-// NumFmt formats a number with the given precision using the
+// FormatNumber formats number with the given precision for the current language.
+func (ns *Namespace) FormatNumber(precision, number interface{}) (string, error) {
+ p, n, err := ns.castPrecisionNumber(precision, number)
+ if err != nil {
+ return "", err
+ }
+ return ns.translator.FmtNumber(n, p), nil
+}
+
+// FormatPercent formats number with the given precision for the current language.
+// Note that the number is assumbed to be percent.
+func (ns *Namespace) FormatPercent(precision, number interface{}) (string, error) {
+ p, n, err := ns.castPrecisionNumber(precision, number)
+ if err != nil {
+ return "", err
+ }
+ return ns.translator.FmtPercent(n, p), nil
+}
+
+// FormatCurrency returns the currency reprecentation of number for the given currency and precision
+// for the current language.
+func (ns *Namespace) FormatCurrency(precision, currency, number interface{}) (string, error) {
+ p, n, err := ns.castPrecisionNumber(precision, number)
+ if err != nil {
+ return "", err
+ }
+ c := translators.GetCurrency(cast.ToString(currency))
+ if c < 0 {
+ return "", fmt.Errorf("unknown currency code: %q", currency)
+ }
+ return ns.translator.FmtCurrency(n, p, c), nil
+}
+
+// FormatAccounting returns the currency reprecentation of number for the given currency and precision
+// for the current language in accounting notation.
+func (ns *Namespace) FormatAccounting(precision, currency, number interface{}) (string, error) {
+ p, n, err := ns.castPrecisionNumber(precision, number)
+ if err != nil {
+ return "", err
+ }
+ c := translators.GetCurrency(cast.ToString(currency))
+ if c < 0 {
+ return "", fmt.Errorf("unknown currency code: %q", currency)
+ }
+ return ns.translator.FmtAccounting(n, p, c), nil
+}
+
+func (ns *Namespace) castPrecisionNumber(precision, number interface{}) (uint64, float64, error) {
+ p, err := cast.ToUint64E(precision)
+ if err != nil {
+ return 0, 0, err
+ }
+
+ // Sanity check.
+ if p > 20 {
+ return 0, 0, fmt.Errorf("invalid precision: %d", precision)
+ }
+
+ n, err := cast.ToFloat64E(number)
+ if err != nil {
+ return 0, 0, err
+ }
+ return p, n, nil
+}
+
+// FormatNumberCustom formats a number with the given precision using the
// negative, decimal, and grouping options. The `options`
// parameter is a string consisting of `<negative> <decimal> <grouping>`. The
// default `options` value is `- . ,`.
//
// Note that numbers are rounded up at 5 or greater.
// So, with precision set to 0, 1.5 becomes `2`, and 1.4 becomes `1`.
-func (ns *Namespace) NumFmt(precision, number interface{}, options ...interface{}) (string, error) {
+//
+// For a simpler function that adapts to the current language, see FormatNumberCustom.
+func (ns *Namespace) FormatNumberCustom(precision, number interface{}, options ...interface{}) (string, error) {
prec, err := cast.ToIntE(precision)
if err != nil {
return "", err
@@ -162,6 +233,13 @@ func (ns *Namespace) NumFmt(precision, number interface{}, options ...interface{
return string(b), nil
}
+// NumFmt is deprecated, use FormatNumberCustom.
+// We renamed this in Hugo 0.87.
+// Deprecated: Use FormatNumberCustom
+func (ns *Namespace) NumFmt(precision, number interface{}, options ...interface{}) (string, error) {
+ return ns.FormatNumberCustom(precision, number, options...)
+}
+
type pagesLanguageMerger interface {
MergeByLanguageInterface(other interface{}) (interface{}, error)
}
diff --git a/tpl/lang/lang_test.go b/tpl/lang/lang_test.go
index 3b3caeb62..782a0a69a 100644
--- a/tpl/lang/lang_test.go
+++ b/tpl/lang/lang_test.go
@@ -3,15 +3,16 @@ package lang
import (
"testing"
+ translators "github.com/bep/gotranslators"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/deps"
)
-func TestNumFormat(t *testing.T) {
+func TestNumFmt(t *testing.T) {
t.Parallel()
c := qt.New(t)
- ns := New(&deps.Deps{})
+ ns := New(&deps.Deps{}, nil)
cases := []struct {
prec int
@@ -49,12 +50,12 @@ func TestNumFormat(t *testing.T) {
var err error
if len(cas.runes) == 0 {
- s, err = ns.NumFmt(cas.prec, cas.n)
+ s, err = ns.FormatNumberCustom(cas.prec, cas.n)
} else {
if cas.delim == "" {
- s, err = ns.NumFmt(cas.prec, cas.n, cas.runes)
+ s, err = ns.FormatNumberCustom(cas.prec, cas.n, cas.runes)
} else {
- s, err = ns.NumFmt(cas.prec, cas.n, cas.runes, cas.delim)
+ s, err = ns.FormatNumberCustom(cas.prec, cas.n, cas.runes, cas.delim)
}
}
@@ -62,3 +63,45 @@ func TestNumFormat(t *testing.T) {
c.Assert(s, qt.Equals, cas.want)
}
}
+
+func TestFormatNumbers(t *testing.T) {
+
+ c := qt.New(t)
+
+ nsNn := New(&deps.Deps{}, translators.GetTranslator("nn"))
+ nsEn := New(&deps.Deps{}, translators.GetTranslator("en"))
+ pi := 3.14159265359
+
+ c.Run("FormatNumber", func(c *qt.C) {
+ c.Parallel()
+ got, err := nsNn.FormatNumber(3, pi)
+ c.Assert(err, qt.IsNil)
+ c.Assert(got, qt.Equals, "3,142")
+
+ got, err = nsEn.FormatNumber(3, pi)
+ c.Assert(err, qt.IsNil)
+ c.Assert(got, qt.Equals, "3.142")
+ })
+
+ c.Run("FormatPercent", func(c *qt.C) {
+ c.Parallel()
+ got, err := nsEn.FormatPercent(3, 67.33333)
+ c.Assert(err, qt.IsNil)
+ c.Assert(got, qt.Equals, "67.333%")
+ })
+
+ c.Run("FormatCurrency", func(c *qt.C) {
+ c.Parallel()
+ got, err := nsEn.FormatCurrency(2, "USD", 20000)
+ c.Assert(err, qt.IsNil)
+ c.Assert(got, qt.Equals, "$20,000.00")
+ })
+
+ c.Run("FormatAccounting", func(c *qt.C) {
+ c.Parallel()
+ got, err := nsEn.FormatAccounting(2, "USD", 20000)
+ c.Assert(err, qt.IsNil)
+ c.Assert(got, qt.Equals, "$20,000.00")
+ })
+
+}