From 7907d24ba16fc5a80930c1aabf5144e684ff7f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Wed, 28 Jul 2021 12:28:52 +0200 Subject: [PATCH] tpl/lang: Add new localized versions of lang.FormatNumber etc. Fixes #8820 --- common/htime/time_test.go | 12 +-- .../image-processing/index.md | 2 +- .../en/functions/{NumFmt.md => lang.md} | 21 ++--- docs/content/en/functions/time.md | 1 + docs/data/docs.json | 92 ++++++++++++++++--- docs/layouts/template-func/page.html | 54 +++++++++++ go.mod | 2 +- go.sum | 2 + hugolib/language_test.go | 49 ++++++++++ langs/language.go | 6 +- tpl/cast/docshelper.go | 5 +- tpl/lang/init.go | 44 +++++++-- tpl/lang/init_test.go | 7 +- tpl/lang/lang.go | 88 +++++++++++++++++- tpl/lang/lang_test.go | 53 ++++++++++- tpl/time/time_test.go | 6 +- 16 files changed, 385 insertions(+), 59 deletions(-) rename docs/content/en/functions/{NumFmt.md => lang.md} (65%) create mode 100644 docs/layouts/template-func/page.html diff --git a/common/htime/time_test.go b/common/htime/time_test.go index 38302775..e8aec015 100644 --- a/common/htime/time_test.go +++ b/common/htime/time_test.go @@ -28,7 +28,7 @@ func TestTimeFormatter(t *testing.T) { june06 = june06.Add(7777 * time.Second) c.Run("Norsk nynorsk", func(c *qt.C) { - f := NewTimeFormatter(translators.Get("nn")) + f := NewTimeFormatter(translators.GetTranslator("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") @@ -36,7 +36,7 @@ func TestTimeFormatter(t *testing.T) { }) c.Run("Custom layouts Norsk nynorsk", func(c *qt.C) { - f := NewTimeFormatter(translators.Get("nn")) + f := NewTimeFormatter(translators.GetTranslator("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") @@ -51,7 +51,7 @@ func TestTimeFormatter(t *testing.T) { }) c.Run("Custom layouts English", func(c *qt.C) { - f := NewTimeFormatter(translators.Get("en")) + f := NewTimeFormatter(translators.GetTranslator("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") @@ -66,7 +66,7 @@ func TestTimeFormatter(t *testing.T) { }) c.Run("English", func(c *qt.C) { - f := NewTimeFormatter(translators.Get("en")) + f := NewTimeFormatter(translators.GetTranslator("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") @@ -88,7 +88,7 @@ func BenchmarkTimeFormatter(b *testing.B) { }) b.Run("Localized", func(b *testing.B) { - f := NewTimeFormatter(translators.Get("nn")) + f := NewTimeFormatter(translators.GetTranslator("nn")) b.ResetTimer() for i := 0; i < b.N; i++ { got := f.Format(june06, "Monday Jan 2 2006") @@ -99,7 +99,7 @@ func BenchmarkTimeFormatter(b *testing.B) { }) b.Run("Localized Custom", func(b *testing.B) { - f := NewTimeFormatter(translators.Get("nn")) + f := NewTimeFormatter(translators.GetTranslator("nn")) b.ResetTimer() for i := 0; i < b.N; i++ { got := f.Format(june06, ":date_medium") diff --git a/docs/content/en/content-management/image-processing/index.md b/docs/content/en/content-management/image-processing/index.md index 76679717..e2e96415 100644 --- a/docs/content/en/content-management/image-processing/index.md +++ b/docs/content/en/content-management/image-processing/index.md @@ -134,7 +134,7 @@ Or individually access EXIF data with dot access, e.g.: {{ end }} ``` -Some fields may need to be formatted with [`lang.NumFmt`]({{< relref "functions/numfmt" >}}) function to prevent display like `Aperture: 2.278934289` instead of `Aperture: 2.28`. +Some fields may need to be formatted with [`lang.FormatNumberCustom`]({{< relref "functions/lang" >}}) function to prevent display like `Aperture: 2.278934289` instead of `Aperture: 2.28`. #### Exif fields diff --git a/docs/content/en/functions/NumFmt.md b/docs/content/en/functions/lang.md similarity index 65% rename from docs/content/en/functions/NumFmt.md rename to docs/content/en/functions/lang.md index 9b51f597..7b810c9b 100644 --- a/docs/content/en/functions/NumFmt.md +++ b/docs/content/en/functions/lang.md @@ -1,10 +1,8 @@ --- -title: lang.NumFmt -description: "Formats a number with a given precision using the requested `negative`, `decimal`, and `grouping` options. The `options` parameter is a string consisting of ` `." -godocref: "" -date: 2017-02-01 -publishdate: 2017-02-01 -lastmod: 2017-08-21 +title: lang +package: lang +description: "TODO.." +date: 2021-07-28 categories: [functions] keywords: [numbers] menu: @@ -12,18 +10,13 @@ menu: parent: "functions" toc: false signature: ["lang.NumFmt PRECISION NUMBER [OPTIONS [DELIMITER]]"] -workson: [] -hugoversion: -relatedfuncs: [] -deprecated: false -draft: false -aliases: [] -comments: +aliases: ['/functions/numfmt/'] +type: 'template-func' --- The default options value is `- . ,`. The default delimiter within the options value is a space. If you need to use a space as one of the options, set a -custom delimiter. +custom delimiter.s Numbers greater than or equal to 5 are rounded up. For example, if precision is set to `0`, `1.5` becomes `2`, and `1.4` becomes `1`. diff --git a/docs/content/en/functions/time.md b/docs/content/en/functions/time.md index 6c7f5aec..e1f24a40 100644 --- a/docs/content/en/functions/time.md +++ b/docs/content/en/functions/time.md @@ -19,6 +19,7 @@ deprecated: false aliases: [] --- + `time` converts a timestamp string with an optional default location into a [`time.Time`](https://godoc.org/time#Time) structure so you can access its fields: ``` diff --git a/docs/data/docs.json b/docs/data/docs.json index d0edcb67..9925a57e 100644 --- a/docs/data/docs.json +++ b/docs/data/docs.json @@ -1677,6 +1677,9 @@ "caches": { "_merge": "none" }, + "cascade": { + "_merge": "none" + }, "frontmatter": { "_merge": "none" }, @@ -1745,7 +1748,7 @@ "keepDocumentTags": true, "keepEndTags": true, "keepQuotes": false, - "keepWhitespace": false + "keepWhitespace": true }, "css": { "keepCSS2": true, @@ -1756,7 +1759,8 @@ "keepVarNames": false }, "json": { - "precision": 0 + "precision": 0, + "keepNumbers": false }, "svg": { "precision": 0 @@ -3898,14 +3902,52 @@ } }, "lang": { - "Merge": { - "Description": "", - "Args": null, + "FormatAccounting": { + "Description": "FormatAccounting returns the currency reprecentation of number for the given currency and precision\nfor the current language in accounting notation.", + "Args": [ + "precision", + "currency", + "number" + ], "Aliases": null, - "Examples": null + "Examples": [ + [ + "{{ 512.5032 | lang.FormatAccounting 2 \"NOK\" }}", + "NOK512.50" + ] + ] }, - "NumFmt": { - "Description": "NumFmt formats a number with the given precision using the\nnegative, decimal, and grouping options. The `options`\nparameter is a string consisting of `\u003cnegative\u003e \u003cdecimal\u003e \u003cgrouping\u003e`. The\ndefault `options` value is `- . ,`.\n\nNote that numbers are rounded up at 5 or greater.\nSo, with precision set to 0, 1.5 becomes `2`, and 1.4 becomes `1`.", + "FormatCurrency": { + "Description": "FormatCurrency returns the currency reprecentation of number for the given currency and precision\nfor the current language.", + "Args": [ + "precision", + "currency", + "number" + ], + "Aliases": null, + "Examples": [ + [ + "{{ 512.5032 | lang.FormatCurrency 2 \"USD\" }}", + "$512.50" + ] + ] + }, + "FormatNumber": { + "Description": "FormatNumber formats number with the given precision for the current language.", + "Args": [ + "precision", + "number" + ], + "Aliases": null, + "Examples": [ + [ + "{{ 512.5032 | lang.FormatNumber 2 }}", + "512.50" + ] + ] + }, + "FormatNumberCustom": { + "Description": "FormatNumberCustom formats a number with the given precision using the\nnegative, decimal, and grouping options. The `options`\nparameter is a string consisting of `\u003cnegative\u003e \u003cdecimal\u003e \u003cgrouping\u003e`. The\ndefault `options` value is `- . ,`.\n\nNote that numbers are rounded up at 5 or greater.\nSo, with precision set to 0, 1.5 becomes `2`, and 1.4 becomes `1`.\n\nFor a simpler function that adapts to the current language, see FormatNumberCustom.", "Args": [ "precision", "number", @@ -3914,19 +3956,19 @@ "Aliases": null, "Examples": [ [ - "{{ lang.NumFmt 2 12345.6789 }}", + "{{ lang.FormatNumberCustom 2 12345.6789 }}", "12,345.68" ], [ - "{{ lang.NumFmt 2 12345.6789 \"- , .\" }}", + "{{ lang.FormatNumberCustom 2 12345.6789 \"- , .\" }}", "12.345,68" ], [ - "{{ lang.NumFmt 6 -12345.6789 \"- .\" }}", + "{{ lang.FormatNumberCustom 6 -12345.6789 \"- .\" }}", "-12345.678900" ], [ - "{{ lang.NumFmt 0 -12345.6789 \"- . ,\" }}", + "{{ lang.FormatNumberCustom 0 -12345.6789 \"- . ,\" }}", "-12,346" ], [ @@ -3935,6 +3977,32 @@ ] ] }, + "FormatPercent": { + "Description": "FormatPercent formats number with the given precision for the current language.\nNote that the number is assumbed to be percent.", + "Args": [ + "precision", + "number" + ], + "Aliases": null, + "Examples": [ + [ + "{{ 512.5032 | lang.FormatPercent 2 }}", + "512.50%" + ] + ] + }, + "Merge": { + "Description": "", + "Args": null, + "Aliases": null, + "Examples": null + }, + "NumFmt": { + "Description": "", + "Args": null, + "Aliases": null, + "Examples": null + }, "Translate": { "Description": "Translate returns a translated string for id.", "Args": [ diff --git a/docs/layouts/template-func/page.html b/docs/layouts/template-func/page.html new file mode 100644 index 00000000..f08018e4 --- /dev/null +++ b/docs/layouts/template-func/page.html @@ -0,0 +1,54 @@ +{{ $pkg := .Params.package}} +{{ $funcs := index site.Data.docs.tpl.funcs $pkg }} + +{{ range $k, $v := $funcs }} + {{ if $v.Description }} + {{ $func := printf "%s.%s" $pkg $k }} +

+ + + + + + + {{ $func }} +

+ {{ with $v.Description }} +

+ {{ . | $.RenderString | safeHTML }} +

+ {{ end }} +

+ Syntax +

+
+ {{ $pkg }}.{{ $k }} + {{ with $v.Args }} + + {{ delimit $v.Args ", "}} + + {{ end }} + +
+ {{ if $v.Examples }} +

+ Examples +

+ {{ end }} + {{ range $v.Examples }} + {{ $input := index . 0 }} + {{ $result := index . 1 }} + {{ $example := printf "%s ---> %s" $input $result }} + + {{ highlight $example "go-html-template" "" }} + {{ end }} + {{ with $v.Aliases }} +

+ Aliases +

+

+ {{ delimit . ", "}} +

+ {{ end }} + {{ end }} +{{ end }} diff --git a/go.mod b/go.mod index aa2eb76d..5ceaaca1 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/bep/gitmap v1.1.2 github.com/bep/godartsass v0.12.0 github.com/bep/golibsass v1.0.0 - github.com/bep/gotranslators v0.0.0-20210726170149-50377fc92c80 + github.com/bep/gotranslators v0.2.0 github.com/bep/gowebp v0.1.0 github.com/bep/tmc v0.5.1 github.com/cli/safeexec v1.0.0 diff --git a/go.sum b/go.sum index 31c16e23..491bad20 100644 --- a/go.sum +++ b/go.sum @@ -136,6 +136,8 @@ github.com/bep/golibsass v1.0.0 h1:gNguBMSDi5yZEZzVZP70YpuFQE3qogJIGUlrVILTmOw= github.com/bep/golibsass v1.0.0/go.mod h1:DL87K8Un/+pWUS75ggYv41bliGiolxzDKWJAq3eJ1MA= github.com/bep/gotranslators v0.0.0-20210726170149-50377fc92c80 h1:FuOr7TE02FmHwf0HbOzfN0UyQfHoZd1R3PVuYduFU6U= github.com/bep/gotranslators v0.0.0-20210726170149-50377fc92c80/go.mod h1:/tUOv4Jdczp4ZggwBAQriNN97HsQdG1Gm+yV0PsIGD8= +github.com/bep/gotranslators v0.2.0 h1:GW0mGPivOY4drd4HwWpn44HXBo5zc5iHdDJZj3yWb/k= +github.com/bep/gotranslators v0.2.0/go.mod h1:fbo6ptvCVYarnHjBm4BvOJX0o18VEvA0slN7xKvqXzc= github.com/bep/gowebp v0.1.0 h1:4/iQpfnxHyXs3x/aTxMMdOpLEQQhFmF6G7EieWPTQyo= github.com/bep/gowebp v0.1.0/go.mod h1:ZhFodwdiFp8ehGJpF4LdPl6unxZm9lLFjxD3z2h2AgI= github.com/bep/tmc v0.5.1 h1:CsQnSC6MsomH64gw0cT5f+EwQDcvZz4AazKunFwTpuI= diff --git a/hugolib/language_test.go b/hugolib/language_test.go index da8ecd22..1de42262 100644 --- a/hugolib/language_test.go +++ b/hugolib/language_test.go @@ -79,3 +79,52 @@ name = "foo-a" }) } + +func TestLanguageNumberFormatting(t *testing.T) { + + b := newTestSitesBuilder(t) + b.WithConfigFile("toml", ` +baseURL = "https://example.org" + +defaultContentLanguage = "en" +defaultContentLanguageInSubDir = true + +[languages] +[languages.en] +timeZone="UTC" +weight=10 +[languages.nn] +weight=20 + +`) + + b.WithTemplates("index.html", ` + +FormatNumber: {{ 512.5032 | lang.FormatNumber 2 }} +FormatPercent: {{ 512.5032 | lang.FormatPercent 2 }} +FormatCurrency: {{ 512.5032 | lang.FormatCurrency 2 "USD" }} +FormatAccounting: {{ 512.5032 | lang.FormatAccounting 2 "NOK" }} +FormatNumberCustom: {{ lang.FormatNumberCustom 2 12345.6789 }} + +# We renamed this to FormatNumberCustom in 0.87.0. +NumFmt: {{ -98765.4321 | lang.NumFmt 2 }} + + +`) + b.WithContent("p1.md", "") + + b.Build(BuildCfg{}) + + b.AssertFileContent("public/en/index.html", ` +FormatNumber: 512.50 +FormatPercent: 512.50% +FormatCurrency: $512.50 +FormatAccounting: NOK512.50 +FormatNumberCustom: 12,345.68 + +NumFmt: -98,765.43 +`, + ) + + b.AssertFileContent("public/nn/index.html", "FormatNumber: 512,50\nFormatPercent: 512,50\u00a0%\nFormatCurrency: 512,50\u00a0USD\nFormatAccounting: 512,50\u00a0kr") +} diff --git a/langs/language.go b/langs/language.go index 6f39848c..758729c2 100644 --- a/langs/language.go +++ b/langs/language.go @@ -97,11 +97,11 @@ func NewLanguage(lang string, cfg config.Provider) *Language { localCfg := config.New() compositeConfig := config.NewCompositeConfig(cfg, localCfg) - translator := translators.Get(lang) + translator := translators.GetTranslator(lang) if translator == nil { - translator = translators.Get(cfg.GetString("defaultContentLanguage")) + translator = translators.GetTranslator(cfg.GetString("defaultContentLanguage")) if translator == nil { - translator = translators.Get("en") + translator = translators.GetTranslator("en") } } diff --git a/tpl/cast/docshelper.go b/tpl/cast/docshelper.go index a3cc26de..9a5d55b3 100644 --- a/tpl/cast/docshelper.go +++ b/tpl/cast/docshelper.go @@ -18,6 +18,7 @@ import ( "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/deps" "github.com/gohugoio/hugo/docshelper" + "github.com/gohugoio/hugo/langs" "github.com/gohugoio/hugo/resources/page" "github.com/gohugoio/hugo/tpl/internal" ) @@ -25,10 +26,12 @@ import ( // This file provides documentation support and is randomly put into this package. func init() { docsProvider := func() docshelper.DocProvider { + cfg := config.New() d := &deps.Deps{ - Cfg: config.New(), + Cfg: cfg, Log: loggers.NewErrorLogger(), BuildStartListeners: &deps.Listeners{}, + Language: langs.NewDefaultLanguage(cfg), Site: page.NewDummyHugoSite(newTestConfig()), } diff --git a/tpl/lang/init.go b/tpl/lang/init.go index 520eccb8..beb148ff 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 82def552..61d7b504 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 4e6c9c70..0cf448ca 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 ` `. 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 3b3caeb6..782a0a69 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") + }) + +} diff --git a/tpl/time/time_test.go b/tpl/time/time_test.go index 71899cc6..22cbc9bc 100644 --- a/tpl/time/time_test.go +++ b/tpl/time/time_test.go @@ -24,7 +24,7 @@ func TestTimeLocation(t *testing.T) { t.Parallel() loc, _ := time.LoadLocation("America/Antigua") - ns := New(translators.Get("en"), loc) + ns := New(translators.GetTranslator("en"), loc) for i, test := range []struct { value string @@ -67,7 +67,7 @@ func TestTimeLocation(t *testing.T) { func TestFormat(t *testing.T) { t.Parallel() - ns := New(translators.Get("en"), time.UTC) + ns := New(translators.GetTranslator("en"), time.UTC) for i, test := range []struct { layout string @@ -107,7 +107,7 @@ func TestFormat(t *testing.T) { func TestDuration(t *testing.T) { t.Parallel() - ns := New(translators.Get("en"), time.UTC) + ns := New(translators.GetTranslator("en"), time.UTC) for i, test := range []struct { unit interface{}