From 14db37459f18be99f70a371d55af2f5149c92133 Mon Sep 17 00:00:00 2001 From: Josh McCarty Date: Fri, 30 Oct 2020 14:58:52 -0700 Subject: [PATCH] Formats number state with selected language in compute_state_display (#7516) --- src/common/entity/compute_state_display.ts | 5 ++++- src/common/string/number-format.ts | 22 +++++++++++++++++++ .../common/entity/compute_state_display.ts | 14 ++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/common/string/number-format.ts diff --git a/src/common/entity/compute_state_display.ts b/src/common/entity/compute_state_display.ts index 2a437901e..d588cd168 100644 --- a/src/common/entity/compute_state_display.ts +++ b/src/common/entity/compute_state_display.ts @@ -5,6 +5,7 @@ import { formatDateTime } from "../datetime/format_date_time"; import { formatTime } from "../datetime/format_time"; import { LocalizeFunc } from "../translations/localize"; import { computeStateDomain } from "./compute_state_domain"; +import { numberFormat } from "../string/number-format"; export const computeStateDisplay = ( localize: LocalizeFunc, @@ -19,7 +20,9 @@ export const computeStateDisplay = ( } if (stateObj.attributes.unit_of_measurement) { - return `${compareState} ${stateObj.attributes.unit_of_measurement}`; + return `${numberFormat(compareState, language)} ${ + stateObj.attributes.unit_of_measurement + }`; } const domain = computeStateDomain(stateObj); diff --git a/src/common/string/number-format.ts b/src/common/string/number-format.ts new file mode 100644 index 000000000..39d20e47a --- /dev/null +++ b/src/common/string/number-format.ts @@ -0,0 +1,22 @@ +/** + * Formats a number based on the specified language with thousands separator(s) and decimal character for better legibility. + * + * @param num The number to format + * @param language The language to use when formatting the number + */ +export const numberFormat = ( + num: string | number, + language: string +): string => { + // Polyfill for Number.isNaN, which is more reliable that the global isNaN() + Number.isNaN = + Number.isNaN || + function isNaN(input) { + return typeof input === "number" && isNaN(input); + }; + + if (!Number.isNaN(Number(num)) && Intl) { + return new Intl.NumberFormat(language).format(Number(num)); + } + return num.toString(); +}; diff --git a/test-mocha/common/entity/compute_state_display.ts b/test-mocha/common/entity/compute_state_display.ts index e8663c5a1..b4822774f 100644 --- a/test-mocha/common/entity/compute_state_display.ts +++ b/test-mocha/common/entity/compute_state_display.ts @@ -64,6 +64,20 @@ describe("computeStateDisplay", () => { assert.strictEqual(computeStateDisplay(localize, stateObj, "en"), "123 m"); }); + it("Localizes and formats numeric sensor value with units", () => { + const stateObj: any = { + entity_id: "sensor.test", + state: "1234.5", + attributes: { + unit_of_measurement: "m", + }, + }; + assert.strictEqual( + computeStateDisplay(localize, stateObj, "en"), + "1,234.5 m" + ); + }); + it("Localizes unknown sensor value with units", () => { const altLocalize = (message, ...args) => { if (message === "state.sensor.unknown") {