mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
tpl/lang: Add new localized versions of lang.FormatNumber etc.
Fixes #8820
This commit is contained in:
parent
726fe9c3c9
commit
7907d24ba1
16 changed files with 385 additions and 59 deletions
|
@ -28,7 +28,7 @@ func TestTimeFormatter(t *testing.T) {
|
||||||
june06 = june06.Add(7777 * time.Second)
|
june06 = june06.Add(7777 * time.Second)
|
||||||
|
|
||||||
c.Run("Norsk nynorsk", func(c *qt.C) {
|
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, "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")
|
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) {
|
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_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_long"), qt.Equals, "6. juni 2018")
|
||||||
|
@ -51,7 +51,7 @@ func TestTimeFormatter(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("Custom layouts English", func(c *qt.C) {
|
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_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_long"), qt.Equals, "June 6, 2018")
|
||||||
|
@ -66,7 +66,7 @@ func TestTimeFormatter(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
c.Run("English", func(c *qt.C) {
|
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, "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")
|
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) {
|
b.Run("Localized", func(b *testing.B) {
|
||||||
f := NewTimeFormatter(translators.Get("nn"))
|
f := NewTimeFormatter(translators.GetTranslator("nn"))
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
got := f.Format(june06, "Monday Jan 2 2006")
|
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) {
|
b.Run("Localized Custom", func(b *testing.B) {
|
||||||
f := NewTimeFormatter(translators.Get("nn"))
|
f := NewTimeFormatter(translators.GetTranslator("nn"))
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
got := f.Format(june06, ":date_medium")
|
got := f.Format(june06, ":date_medium")
|
||||||
|
|
|
@ -134,7 +134,7 @@ Or individually access EXIF data with dot access, e.g.:
|
||||||
{{ end }}
|
{{ 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
|
#### Exif fields
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
---
|
---
|
||||||
title: lang.NumFmt
|
title: lang
|
||||||
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>`."
|
package: lang
|
||||||
godocref: ""
|
description: "TODO.."
|
||||||
date: 2017-02-01
|
date: 2021-07-28
|
||||||
publishdate: 2017-02-01
|
|
||||||
lastmod: 2017-08-21
|
|
||||||
categories: [functions]
|
categories: [functions]
|
||||||
keywords: [numbers]
|
keywords: [numbers]
|
||||||
menu:
|
menu:
|
||||||
|
@ -12,18 +10,13 @@ menu:
|
||||||
parent: "functions"
|
parent: "functions"
|
||||||
toc: false
|
toc: false
|
||||||
signature: ["lang.NumFmt PRECISION NUMBER [OPTIONS [DELIMITER]]"]
|
signature: ["lang.NumFmt PRECISION NUMBER [OPTIONS [DELIMITER]]"]
|
||||||
workson: []
|
aliases: ['/functions/numfmt/']
|
||||||
hugoversion:
|
type: 'template-func'
|
||||||
relatedfuncs: []
|
|
||||||
deprecated: false
|
|
||||||
draft: false
|
|
||||||
aliases: []
|
|
||||||
comments:
|
|
||||||
---
|
---
|
||||||
|
|
||||||
The default options value is `- . ,`. The default delimiter within the options
|
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
|
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`.
|
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`.
|
||||||
|
|
|
@ -19,6 +19,7 @@ deprecated: false
|
||||||
aliases: []
|
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:
|
`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:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -1677,6 +1677,9 @@
|
||||||
"caches": {
|
"caches": {
|
||||||
"_merge": "none"
|
"_merge": "none"
|
||||||
},
|
},
|
||||||
|
"cascade": {
|
||||||
|
"_merge": "none"
|
||||||
|
},
|
||||||
"frontmatter": {
|
"frontmatter": {
|
||||||
"_merge": "none"
|
"_merge": "none"
|
||||||
},
|
},
|
||||||
|
@ -1745,7 +1748,7 @@
|
||||||
"keepDocumentTags": true,
|
"keepDocumentTags": true,
|
||||||
"keepEndTags": true,
|
"keepEndTags": true,
|
||||||
"keepQuotes": false,
|
"keepQuotes": false,
|
||||||
"keepWhitespace": false
|
"keepWhitespace": true
|
||||||
},
|
},
|
||||||
"css": {
|
"css": {
|
||||||
"keepCSS2": true,
|
"keepCSS2": true,
|
||||||
|
@ -1756,7 +1759,8 @@
|
||||||
"keepVarNames": false
|
"keepVarNames": false
|
||||||
},
|
},
|
||||||
"json": {
|
"json": {
|
||||||
"precision": 0
|
"precision": 0,
|
||||||
|
"keepNumbers": false
|
||||||
},
|
},
|
||||||
"svg": {
|
"svg": {
|
||||||
"precision": 0
|
"precision": 0
|
||||||
|
@ -3898,14 +3902,52 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lang": {
|
"lang": {
|
||||||
"Merge": {
|
"FormatAccounting": {
|
||||||
"Description": "",
|
"Description": "FormatAccounting returns the currency reprecentation of number for the given currency and precision\nfor the current language in accounting notation.",
|
||||||
"Args": null,
|
"Args": [
|
||||||
|
"precision",
|
||||||
|
"currency",
|
||||||
|
"number"
|
||||||
|
],
|
||||||
"Aliases": null,
|
"Aliases": null,
|
||||||
"Examples": null
|
"Examples": [
|
||||||
|
[
|
||||||
|
"{{ 512.5032 | lang.FormatAccounting 2 \"NOK\" }}",
|
||||||
|
"NOK512.50"
|
||||||
|
]
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"NumFmt": {
|
"FormatCurrency": {
|
||||||
"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`.",
|
"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": [
|
"Args": [
|
||||||
"precision",
|
"precision",
|
||||||
"number",
|
"number",
|
||||||
|
@ -3914,19 +3956,19 @@
|
||||||
"Aliases": null,
|
"Aliases": null,
|
||||||
"Examples": [
|
"Examples": [
|
||||||
[
|
[
|
||||||
"{{ lang.NumFmt 2 12345.6789 }}",
|
"{{ lang.FormatNumberCustom 2 12345.6789 }}",
|
||||||
"12,345.68"
|
"12,345.68"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"{{ lang.NumFmt 2 12345.6789 \"- , .\" }}",
|
"{{ lang.FormatNumberCustom 2 12345.6789 \"- , .\" }}",
|
||||||
"12.345,68"
|
"12.345,68"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"{{ lang.NumFmt 6 -12345.6789 \"- .\" }}",
|
"{{ lang.FormatNumberCustom 6 -12345.6789 \"- .\" }}",
|
||||||
"-12345.678900"
|
"-12345.678900"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"{{ lang.NumFmt 0 -12345.6789 \"- . ,\" }}",
|
"{{ lang.FormatNumberCustom 0 -12345.6789 \"- . ,\" }}",
|
||||||
"-12,346"
|
"-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": {
|
"Translate": {
|
||||||
"Description": "Translate returns a translated string for id.",
|
"Description": "Translate returns a translated string for id.",
|
||||||
"Args": [
|
"Args": [
|
||||||
|
|
54
docs/layouts/template-func/page.html
Normal file
54
docs/layouts/template-func/page.html
Normal file
|
@ -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 }}
|
2
go.mod
2
go.mod
|
@ -12,7 +12,7 @@ require (
|
||||||
github.com/bep/gitmap v1.1.2
|
github.com/bep/gitmap v1.1.2
|
||||||
github.com/bep/godartsass v0.12.0
|
github.com/bep/godartsass v0.12.0
|
||||||
github.com/bep/golibsass v1.0.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/gowebp v0.1.0
|
||||||
github.com/bep/tmc v0.5.1
|
github.com/bep/tmc v0.5.1
|
||||||
github.com/cli/safeexec v1.0.0
|
github.com/cli/safeexec v1.0.0
|
||||||
|
|
2
go.sum
2
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/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 h1:FuOr7TE02FmHwf0HbOzfN0UyQfHoZd1R3PVuYduFU6U=
|
||||||
github.com/bep/gotranslators v0.0.0-20210726170149-50377fc92c80/go.mod h1:/tUOv4Jdczp4ZggwBAQriNN97HsQdG1Gm+yV0PsIGD8=
|
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 h1:4/iQpfnxHyXs3x/aTxMMdOpLEQQhFmF6G7EieWPTQyo=
|
||||||
github.com/bep/gowebp v0.1.0/go.mod h1:ZhFodwdiFp8ehGJpF4LdPl6unxZm9lLFjxD3z2h2AgI=
|
github.com/bep/gowebp v0.1.0/go.mod h1:ZhFodwdiFp8ehGJpF4LdPl6unxZm9lLFjxD3z2h2AgI=
|
||||||
github.com/bep/tmc v0.5.1 h1:CsQnSC6MsomH64gw0cT5f+EwQDcvZz4AazKunFwTpuI=
|
github.com/bep/tmc v0.5.1 h1:CsQnSC6MsomH64gw0cT5f+EwQDcvZz4AazKunFwTpuI=
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
@ -97,11 +97,11 @@ func NewLanguage(lang string, cfg config.Provider) *Language {
|
||||||
|
|
||||||
localCfg := config.New()
|
localCfg := config.New()
|
||||||
compositeConfig := config.NewCompositeConfig(cfg, localCfg)
|
compositeConfig := config.NewCompositeConfig(cfg, localCfg)
|
||||||
translator := translators.Get(lang)
|
translator := translators.GetTranslator(lang)
|
||||||
if translator == nil {
|
if translator == nil {
|
||||||
translator = translators.Get(cfg.GetString("defaultContentLanguage"))
|
translator = translators.GetTranslator(cfg.GetString("defaultContentLanguage"))
|
||||||
if translator == nil {
|
if translator == nil {
|
||||||
translator = translators.Get("en")
|
translator = translators.GetTranslator("en")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/gohugoio/hugo/config"
|
"github.com/gohugoio/hugo/config"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
"github.com/gohugoio/hugo/docshelper"
|
"github.com/gohugoio/hugo/docshelper"
|
||||||
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/resources/page"
|
"github.com/gohugoio/hugo/resources/page"
|
||||||
"github.com/gohugoio/hugo/tpl/internal"
|
"github.com/gohugoio/hugo/tpl/internal"
|
||||||
)
|
)
|
||||||
|
@ -25,10 +26,12 @@ import (
|
||||||
// This file provides documentation support and is randomly put into this package.
|
// This file provides documentation support and is randomly put into this package.
|
||||||
func init() {
|
func init() {
|
||||||
docsProvider := func() docshelper.DocProvider {
|
docsProvider := func() docshelper.DocProvider {
|
||||||
|
cfg := config.New()
|
||||||
d := &deps.Deps{
|
d := &deps.Deps{
|
||||||
Cfg: config.New(),
|
Cfg: cfg,
|
||||||
Log: loggers.NewErrorLogger(),
|
Log: loggers.NewErrorLogger(),
|
||||||
BuildStartListeners: &deps.Listeners{},
|
BuildStartListeners: &deps.Listeners{},
|
||||||
|
Language: langs.NewDefaultLanguage(cfg),
|
||||||
Site: page.NewDummyHugoSite(newTestConfig()),
|
Site: page.NewDummyHugoSite(newTestConfig()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ package lang
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
"github.com/gohugoio/hugo/langs"
|
||||||
"github.com/gohugoio/hugo/tpl/internal"
|
"github.com/gohugoio/hugo/tpl/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ const name = "lang"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
f := func(d *deps.Deps) *internal.TemplateFuncsNamespace {
|
||||||
ctx := New(d)
|
ctx := New(d, langs.GetTranslator(d.Language))
|
||||||
|
|
||||||
ns := &internal.TemplateFuncsNamespace{
|
ns := &internal.TemplateFuncsNamespace{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
@ -34,16 +35,45 @@ func init() {
|
||||||
[][2]string{},
|
[][2]string{},
|
||||||
)
|
)
|
||||||
|
|
||||||
ns.AddMethodMapping(ctx.NumFmt,
|
ns.AddMethodMapping(ctx.FormatNumber,
|
||||||
nil,
|
nil,
|
||||||
[][2]string{
|
[][2]string{
|
||||||
{`{{ lang.NumFmt 2 12345.6789 }}`, `12,345.68`},
|
{`{{ 512.5032 | lang.FormatNumber 2 }}`, `512.50`},
|
||||||
{`{{ 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`},
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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
|
return ns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@ package lang
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gohugoio/hugo/config"
|
||||||
|
"github.com/gohugoio/hugo/langs"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/htesting/hqt"
|
"github.com/gohugoio/hugo/htesting/hqt"
|
||||||
|
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
|
@ -29,7 +32,9 @@ func TestInit(t *testing.T) {
|
||||||
var ns *internal.TemplateFuncsNamespace
|
var ns *internal.TemplateFuncsNamespace
|
||||||
|
|
||||||
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
|
for _, nsf := range internal.TemplateFuncsNamespaceRegistry {
|
||||||
ns = nsf(&deps.Deps{})
|
ns = nsf(&deps.Deps{
|
||||||
|
Language: langs.NewDefaultLanguage(config.New()),
|
||||||
|
})
|
||||||
if ns.Name == name {
|
if ns.Name == name {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
|
|
|
@ -20,6 +20,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
translators "github.com/bep/gotranslators"
|
||||||
|
"github.com/go-playground/locales"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
|
@ -27,15 +29,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// New returns a new instance of the lang-namespaced template functions.
|
// 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{
|
return &Namespace{
|
||||||
deps: deps,
|
translator: translator,
|
||||||
|
deps: deps,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Namespace provides template functions for the "lang" namespace.
|
// Namespace provides template functions for the "lang" namespace.
|
||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
deps *deps.Deps
|
translator locales.Translator
|
||||||
|
deps *deps.Deps
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate returns a translated string for id.
|
// 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
|
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`
|
// negative, decimal, and grouping options. The `options`
|
||||||
// parameter is a string consisting of `<negative> <decimal> <grouping>`. The
|
// parameter is a string consisting of `<negative> <decimal> <grouping>`. The
|
||||||
// default `options` value is `- . ,`.
|
// default `options` value is `- . ,`.
|
||||||
//
|
//
|
||||||
// Note that numbers are rounded up at 5 or greater.
|
// 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`.
|
// 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)
|
prec, err := cast.ToIntE(precision)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -162,6 +233,13 @@ func (ns *Namespace) NumFmt(precision, number interface{}, options ...interface{
|
||||||
return string(b), nil
|
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 {
|
type pagesLanguageMerger interface {
|
||||||
MergeByLanguageInterface(other interface{}) (interface{}, error)
|
MergeByLanguageInterface(other interface{}) (interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,16 @@ package lang
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
translators "github.com/bep/gotranslators"
|
||||||
qt "github.com/frankban/quicktest"
|
qt "github.com/frankban/quicktest"
|
||||||
"github.com/gohugoio/hugo/deps"
|
"github.com/gohugoio/hugo/deps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNumFormat(t *testing.T) {
|
func TestNumFmt(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
c := qt.New(t)
|
c := qt.New(t)
|
||||||
|
|
||||||
ns := New(&deps.Deps{})
|
ns := New(&deps.Deps{}, nil)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
prec int
|
prec int
|
||||||
|
@ -49,12 +50,12 @@ func TestNumFormat(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if len(cas.runes) == 0 {
|
if len(cas.runes) == 0 {
|
||||||
s, err = ns.NumFmt(cas.prec, cas.n)
|
s, err = ns.FormatNumberCustom(cas.prec, cas.n)
|
||||||
} else {
|
} else {
|
||||||
if cas.delim == "" {
|
if cas.delim == "" {
|
||||||
s, err = ns.NumFmt(cas.prec, cas.n, cas.runes)
|
s, err = ns.FormatNumberCustom(cas.prec, cas.n, cas.runes)
|
||||||
} else {
|
} 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)
|
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")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestTimeLocation(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
loc, _ := time.LoadLocation("America/Antigua")
|
loc, _ := time.LoadLocation("America/Antigua")
|
||||||
ns := New(translators.Get("en"), loc)
|
ns := New(translators.GetTranslator("en"), loc)
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
value string
|
value string
|
||||||
|
@ -67,7 +67,7 @@ func TestTimeLocation(t *testing.T) {
|
||||||
func TestFormat(t *testing.T) {
|
func TestFormat(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
ns := New(translators.Get("en"), time.UTC)
|
ns := New(translators.GetTranslator("en"), time.UTC)
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
layout string
|
layout string
|
||||||
|
@ -107,7 +107,7 @@ func TestFormat(t *testing.T) {
|
||||||
func TestDuration(t *testing.T) {
|
func TestDuration(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
ns := New(translators.Get("en"), time.UTC)
|
ns := New(translators.GetTranslator("en"), time.UTC)
|
||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
unit interface{}
|
unit interface{}
|
||||||
|
|
Loading…
Reference in a new issue