URI: 
       tpl/lang: Add new localized versions of lang.FormatNumber etc. - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 7907d24ba16fc5a80930c1aabf5144e684ff7f29
   DIR parent 726fe9c3c97a9c979dc7862e7f226fc5ec1341de
  HTML Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
       Date:   Wed, 28 Jul 2021 12:28:52 +0200
       
       tpl/lang: Add new localized versions of lang.FormatNumber etc.
       
       Fixes #8820
       
       Diffstat:
         M common/htime/time_test.go           |      12 ++++++------
         M docs/content/en/content-management… |       2 +-
         D docs/content/en/functions/NumFmt.md |      37 -------------------------------
         A docs/content/en/functions/lang.md   |      30 ++++++++++++++++++++++++++++++
         M docs/content/en/functions/time.md   |       1 +
         M docs/data/docs.json                 |      92 +++++++++++++++++++++++++++----
         A docs/layouts/template-func/page.ht… |      54 +++++++++++++++++++++++++++++++
         M go.mod                              |       2 +-
         M go.sum                              |       2 ++
         M hugolib/language_test.go            |      49 +++++++++++++++++++++++++++++++
         M langs/language.go                   |       6 +++---
         M tpl/cast/docshelper.go              |       5 ++++-
         M tpl/lang/init.go                    |      44 ++++++++++++++++++++++++++-----
         M tpl/lang/init_test.go               |       7 ++++++-
         M tpl/lang/lang.go                    |      88 +++++++++++++++++++++++++++++--
         M tpl/lang/lang_test.go               |      53 ++++++++++++++++++++++++++++---
         M tpl/time/time_test.go               |       6 +++---
       
       17 files changed, 408 insertions(+), 82 deletions(-)
       ---
   DIR diff --git 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")
   DIR diff --git 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
        
   DIR diff --git a/docs/content/en/functions/NumFmt.md b/docs/content/en/functions/NumFmt.md
       @@ -1,37 +0,0 @@
       ----
       -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 `<negative> <decimal> <grouping>`."
       -godocref: ""
       -date: 2017-02-01
       -publishdate: 2017-02-01
       -lastmod: 2017-08-21
       -categories: [functions]
       -keywords: [numbers]
       -menu:
       -  docs:
       -    parent: "functions"
       -toc: false
       -signature: ["lang.NumFmt PRECISION NUMBER [OPTIONS [DELIMITER]]"]
       -workson: []
       -hugoversion:
       -relatedfuncs: []
       -deprecated: false
       -draft: false
       -aliases: []
       -comments:
       ----
       -
       -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.
       -
       -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`.
       -
       -```
       -{{ lang.NumFmt 2 12345.6789 }} → 12,345.68
       -{{ lang.NumFmt 2 12345.6789 "- , ." }} → 12.345,68
       -{{ lang.NumFmt 0 -12345.6789 "- . ," }} → -12,346
       -{{ lang.NumFmt 6 -12345.6789 "- ." }} → -12345.678900
       -{{ lang.NumFmt 6 -12345.6789 "-|.| " "|" }} → -1 2345.678900
       -{{ -98765.4321 | lang.NumFmt 2 }} → -98,765.43
       -```
   DIR diff --git a/docs/content/en/functions/lang.md b/docs/content/en/functions/lang.md
       @@ -0,0 +1,30 @@
       +---
       +title: lang
       +package: lang
       +description: "TODO.."
       +date: 2021-07-28
       +categories: [functions]
       +keywords: [numbers]
       +menu:
       +  docs:
       +    parent: "functions"
       +toc: false
       +signature: ["lang.NumFmt PRECISION NUMBER [OPTIONS [DELIMITER]]"]
       +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.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`.
       +
       +```
       +{{ lang.NumFmt 2 12345.6789 }} → 12,345.68
       +{{ lang.NumFmt 2 12345.6789 "- , ." }} → 12.345,68
       +{{ lang.NumFmt 0 -12345.6789 "- . ," }} → -12,346
       +{{ lang.NumFmt 6 -12345.6789 "- ." }} → -12345.678900
       +{{ lang.NumFmt 6 -12345.6789 "-|.| " "|" }} → -1 2345.678900
       +{{ -98765.4321 | lang.NumFmt 2 }} → -98,765.43
       +```
   DIR diff --git 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:
        
        ```
   DIR diff --git 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": [
   DIR diff --git a/docs/layouts/template-func/page.html 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 }}
       +    <h2>
       +      <a class="header-link" href="#{{ $func | anchorize | safeURL }}">
       +        <svg class="fill-current o-60 hover-accent-color-light" height="22px" viewBox="0 0 24 24" width="22px" xmlns="http://www.w3.org/2000/svg">
       +          <path d="M0 0h24v24H0z" fill="none"/>
       +          <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/>
       +        </svg>
       +      </a>
       +      {{ $func }}
       +    </h2>
       +    {{ with  $v.Description }}
       +      <p class="f4 lh-copy">
       +        {{ . |  $.RenderString | safeHTML }}
       +      </p>
       +    {{ end }}
       +    <h4 class="minor mb3 pt2 primary-color-dark">
       +      Syntax
       +    </h4>
       +    <div class="f5 mb4 ph3 pv2 bg-light-gray" style="border-left:4px solid #0594CB;">
       +      {{ $pkg }}.{{ $k }}
       +      {{ with $v.Args }}
       +        <span class="ttu">
       +          {{ delimit $v.Args ", "}}
       +        </span>
       +      {{ end }}
       +      <span></span>
       +    </div>
       +    {{ if $v.Examples }}
       +      <h4 class="minor mb3 pt2 primary-color-dark">
       +        Examples
       +      </h4>
       +    {{ 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 }}
       +      <h4 class="minor mb3 pt2 primary-color-dark">
       +        Aliases
       +      </h4>
       +      <p>
       +        {{ delimit . ", "}}
       +      </p>
       +    {{ end }}
       +  {{ end }}
       +{{ end }}
   DIR diff --git 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
   DIR diff --git 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=
   DIR diff --git 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")
       +}
   DIR diff --git 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")
                        }
                }
        
   DIR diff --git 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()),
                        }
        
   DIR diff --git 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
                }
        
   DIR diff --git 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
   DIR diff --git 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)
        }
   DIR diff --git 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")
       +        })
       +
       +}
   DIR diff --git 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{}