Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## main

### ✨ Features and improvements
- Add `unit` option to `number-format` expression to allow formatting quantities depending on the locale.
- _...Add new stuff here..._

### 🐞 Bug fixes
Expand Down
1 change: 1 addition & 0 deletions build/generate-style-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ export type ExpressionSpecification =
| ['literal', unknown]
| ['number', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // number
| ['number-format', number | ExpressionSpecification, {'locale'?: string | ExpressionSpecification, 'currency'?: string | ExpressionSpecification, 'min-fraction-digits'?: number | ExpressionSpecification, 'max-fraction-digits'?: number | ExpressionSpecification}] // string
| ['number-format', number | ExpressionSpecification, {'locale'?: string | ExpressionSpecification, 'unit'?: string | ExpressionSpecification, 'min-fraction-digits'?: number | ExpressionSpecification, 'max-fraction-digits'?: number | ExpressionSpecification}] // string
| ['object', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // object
| ['string', unknown | ExpressionSpecification, ...(unknown | ExpressionSpecification)[]] // string
| ['to-boolean', unknown | ExpressionSpecification] // boolean
Expand Down
21 changes: 19 additions & 2 deletions src/expression/definitions/number_format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@ export class NumberFormat implements Expression {
number: Expression;
locale: Expression | null; // BCP 47 language tag
currency: Expression | null; // ISO 4217 currency code, required if style=currency
unit: Expression | null; // CLDR or ECMA-402 unit specifier, required if style=unit
minFractionDigits: Expression | null; // Default 0
maxFractionDigits: Expression | null; // Default 3

constructor(number: Expression,
locale: Expression | null,
currency: Expression | null,
unit: Expression | null,
minFractionDigits: Expression | null,
maxFractionDigits: Expression | null) {
this.type = StringType;
this.number = number;
this.locale = locale;
this.currency = currency;
this.unit = unit;
this.minFractionDigits = minFractionDigits;
this.maxFractionDigits = maxFractionDigits;
}
Expand Down Expand Up @@ -49,6 +52,16 @@ export class NumberFormat implements Expression {
if (!currency) return null;
}

let unit = null;
if (options['unit']) {
unit = context.parse(options['unit'], 1, StringType);
if (!unit) return null;
}

if (currency && unit) {
return context.error('NumberFormat options `currency` and `unit` are mutually exclusive') as null;
}

let minFractionDigits = null;
if (options['min-fraction-digits']) {
minFractionDigits = context.parse(options['min-fraction-digits'], 1, NumberType);
Expand All @@ -61,14 +74,15 @@ export class NumberFormat implements Expression {
if (!maxFractionDigits) return null;
}

return new NumberFormat(number, locale, currency, minFractionDigits, maxFractionDigits);
return new NumberFormat(number, locale, currency, unit, minFractionDigits, maxFractionDigits);
}

evaluate(ctx: EvaluationContext) {
return new Intl.NumberFormat(this.locale ? this.locale.evaluate(ctx) : [],
{
style: this.currency ? 'currency' : 'decimal',
style: this.currency ? 'currency' : this.unit ? 'unit' : 'decimal',
currency: this.currency ? this.currency.evaluate(ctx) : undefined,
unit: this.unit ? this.unit.evaluate(ctx) : undefined,
minimumFractionDigits: this.minFractionDigits ? this.minFractionDigits.evaluate(ctx) : undefined,
maximumFractionDigits: this.maxFractionDigits ? this.maxFractionDigits.evaluate(ctx) : undefined,
}).format(this.number.evaluate(ctx));
Expand All @@ -82,6 +96,9 @@ export class NumberFormat implements Expression {
if (this.currency) {
fn(this.currency);
}
if (this.unit) {
fn(this.unit);
}
if (this.minFractionDigits) {
fn(this.minFractionDigits);
}
Expand Down
4 changes: 2 additions & 2 deletions src/reference/v8.json
Original file line number Diff line number Diff line change
Expand Up @@ -3827,7 +3827,7 @@
}
},
"number-format": {
"doc": "Converts the input number into a string representation using the providing formatting rules. If set, the `locale` argument specifies the locale to use, as a BCP 47 language tag. If set, the `currency` argument specifies an ISO 4217 code to use for currency-style formatting. If set, the `min-fraction-digits` and `max-fraction-digits` arguments specify the minimum and maximum number of fractional digits to include.\n\n - [Display HTML clusters with custom properties](https://maplibre.org/maplibre-gl-js/docs/examples/display-html-clusters-with-custom-properties/)",
"doc": "Converts the input number into a string representation using the providing formatting rules. If set, the `locale` argument specifies the locale to use, as a BCP 47 language tag. If set, the `currency` argument specifies an ISO 4217 code to use for currency-style formatting. If set `unit` argument specifies a CLDR or ECMA-402 unit to use for quantity-style formatting. If set, the `min-fraction-digits` and `max-fraction-digits` arguments specify the minimum and maximum number of fractional digits to include.\n\n - [Display HTML clusters with custom properties](https://maplibre.org/maplibre-gl-js/docs/examples/display-html-clusters-with-custom-properties/)",
"syntax": {
"overloads": [
{
Expand All @@ -3842,7 +3842,7 @@
},
{
"name": "format_options",
"type": "{ \"locale\"?: string, \"currency\"?: string, \"min-fraction-digits\"?: number, \"max-fraction-digits\"?: number }"
"type": "{ \"locale\"?: string, \"currency\"?: string, \"unit\"?: string, \"min-fraction-digits\"?: number, \"max-fraction-digits\"?: number }"
}
]
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"expression": [
"number-format",
1234.567,
{
"locale": [
"get",
"locale"
],
"currency": [
"get",
"currency"
],
"unit": [
"get",
"unit"
]
}
],
"inputs": [
[
{},
{
"properties": {
"locale": "en-US",
"currency": "EUR",
"unit": "meter"
}
}
]
],
"expected": {
"compiled": {
"result": "error",
"errors": [
{
"key": "",
"error": "NumberFormat options `currency` and `unit` are mutually exclusive"
}
]
}
}
}
58 changes: 58 additions & 0 deletions test/integration/expression/tests/number-format/unit/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"expression": [
"number-format",
1234.567,
{
"locale": [
"get",
"locale"
],
"unit": [
"get",
"unit"
]
}
],
"inputs": [
[
{},
{
"properties": {
"locale": "en-US",
"unit": "meter"
}
}
],
[
{},
{
"properties": {
"locale": "en-US",
"unit": "celsius"
}
}
],
[
{},
{
"properties": {
"locale": "en-US",
"unit": "kilobyte"
}
}
]
],
"expected": {
"compiled": {
"result": "success",
"isFeatureConstant": false,
"isZoomConstant": true,
"type": "string"
},
"outputs": [
"1,234.567 m",
"1,234.567°C",
"1,234.567 kB"
]
}
}