From c53c5c2f368ae5c42e303631c3e17bc557ee8c5a Mon Sep 17 00:00:00 2001 From: Stephen Brown II Date: Thu, 12 Mar 2026 21:47:53 -0400 Subject: [PATCH] [AI] Normalize apostrophe-dot thousandsSeparator for consistency (#7179) * Normalize apostrophe-dot thousandsSeparator for consistency * Also normalize keyboard apostrophes on the input path --- packages/loot-core/src/shared/util.ts | 20 ++++++++++++++------ upcoming-release-notes/7179.md | 6 ++++++ 2 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 upcoming-release-notes/7179.md diff --git a/packages/loot-core/src/shared/util.ts b/packages/loot-core/src/shared/util.ts index b5efdcce9e..3d9b32cad0 100644 --- a/packages/loot-core/src/shared/util.ts +++ b/packages/loot-core/src/shared/util.ts @@ -220,12 +220,15 @@ export function reapplyThousandSeparators(amountText: string) { return amountText; } - const { decimalSeparator, thousandsSeparator } = getNumberFormat(); + const { decimalSeparator, thousandsSeparator, value } = getNumberFormat(); const [integerPartRaw, decimalPart = ''] = amountText.split(decimalSeparator); - const numericValue = Number( - integerPartRaw.replaceAll(thousandsSeparator, ''), - ); + // Apostrophe-dot: accept both U+2019 and keyboard U+0027 on input (see getNumberFormat formatter) + const stripThousands = + value === 'apostrophe-dot' + ? (s: string) => s.replaceAll(/[\u2019\u0027]/g, '') + : (s: string) => s.replaceAll(thousandsSeparator, ''); + const numericValue = Number(stripThousands(integerPartRaw)); if (isNaN(numericValue)) { return amountText; // Return original if parsing fails } @@ -342,7 +345,7 @@ export function getNumberFormat({ break; case 'apostrophe-dot': locale = 'de-CH'; - thousandsSeparator = "'"; + thousandsSeparator = '\u2019'; // Intl may return U+0027 (Node <24.13.1/ICU 77) decimalSeparator = '.'; break; case 'comma-dot-in': @@ -374,9 +377,14 @@ export function getNumberFormat({ const intlFormatter = new Intl.NumberFormat(locale, fractionDigitsOptions); // Wrapper to handle -0 edge case + // Normalize apostrophe-dot to U+2019 for consistency across + // Node/ICU versions (https://github.com/nodejs/node/issues/61861) const formatter = { format: (value: number) => { - const formatted = intlFormatter.format(value); + let formatted = intlFormatter.format(value); + if (currentFormat === 'apostrophe-dot') { + formatted = formatted.replace(/'/g, '\u2019'); + } return formatted === '-0' ? '0' : formatted; }, }; diff --git a/upcoming-release-notes/7179.md b/upcoming-release-notes/7179.md new file mode 100644 index 0000000000..e7c3c82633 --- /dev/null +++ b/upcoming-release-notes/7179.md @@ -0,0 +1,6 @@ +--- +category: Bugfixes +authors: [StephenBrown2] +--- + +Number formatting: normalize apostrophe-dot thousands separator to U+2019 for consistency across Node/ICU versions.