mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 01:02:58 +00:00
Polyfill inadequate Intl support
Ensure that formatting is balanced with parsing to avoid truncating numbers.
This commit is contained in:
@@ -424,9 +424,20 @@ export function coreLocalizer() {
|
||||
return code; // if not found, use the code
|
||||
};
|
||||
|
||||
localizer.floatFormatter = (locale) => {
|
||||
if (!('Intl' in window && 'NumberFormat' in Intl &&
|
||||
'formatToParts' in Intl.NumberFormat.prototype)) {
|
||||
return (number) => number.toString();
|
||||
} else {
|
||||
return (number) => number.toLocaleString(locale);
|
||||
}
|
||||
};
|
||||
localizer.floatParser = (locale) => {
|
||||
// https://stackoverflow.com/a/55366435/4585461
|
||||
const polyfill = (string) => parseFloat(string, 10);
|
||||
if (!('Intl' in window && 'NumberFormat' in Intl)) return polyfill;
|
||||
const format = new Intl.NumberFormat(locale);
|
||||
if (!('formatToParts' in format)) return polyfill;
|
||||
const parts = format.formatToParts(12345.6);
|
||||
const numerals = Array.from({ length: 10 }).map((_, i) => format.format(i));
|
||||
const index = new Map(numerals.map((d, i) => [d, i]));
|
||||
|
||||
@@ -32,6 +32,7 @@ export function uiFieldText(field, context) {
|
||||
var _tags;
|
||||
var _phoneFormats = {};
|
||||
const isDirectionField = field.key.split(':').some(keyPart => keyPart === 'direction');
|
||||
const formatFloat = localizer.floatFormatter(localizer.languageCode());
|
||||
const parseLocaleFloat = localizer.floatParser(localizer.languageCode());
|
||||
|
||||
if (field.type === 'tel') {
|
||||
@@ -155,7 +156,7 @@ export function uiFieldText(field, context) {
|
||||
}
|
||||
// make sure no extra decimals are introduced
|
||||
const numDecimals = v.includes('.') ? v.split('.')[1].length : 0;
|
||||
return clamped(num).toFixed(numDecimals).toLocaleString(localizer.languageCode());
|
||||
return formatFloat(clamped(num).toFixed(numDecimals));
|
||||
});
|
||||
input.node().value = vals.join(';');
|
||||
change()();
|
||||
@@ -434,7 +435,7 @@ export function uiFieldText(field, context) {
|
||||
v = v.trim();
|
||||
var num = parseFloat(v, 10);
|
||||
if (!isFinite(num)) return v;
|
||||
return clamped(num).toLocaleString(localizer.languageCode());
|
||||
return formatFloat(clamped(num));
|
||||
});
|
||||
val = vals.join(';');
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export function uiFieldRoadheight(field, context) {
|
||||
var _entityIDs = [];
|
||||
var _tags;
|
||||
var _isImperial;
|
||||
var formatFloat = localizer.floatFormatter(localizer.languageCode());
|
||||
var parseLocaleFloat = localizer.floatParser(localizer.languageCode());
|
||||
|
||||
var primaryUnits = [
|
||||
@@ -164,18 +165,18 @@ export function uiFieldRoadheight(field, context) {
|
||||
if (primaryValue && (primaryValue.indexOf('\'') >= 0 || primaryValue.indexOf('"') >= 0)) {
|
||||
secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
|
||||
if (secondaryValue !== null) {
|
||||
secondaryValue = parseFloat(secondaryValue[1], 10).toLocaleString(localizer.languageCode());
|
||||
secondaryValue = formatFloat(parseFloat(secondaryValue[1], 10));
|
||||
}
|
||||
primaryValue = primaryValue.match(/(-?[\d.]+)'/);
|
||||
if (primaryValue !== null) {
|
||||
primaryValue = parseFloat(primaryValue[1], 10).toLocaleString(localizer.languageCode());
|
||||
primaryValue = formatFloat(parseFloat(primaryValue[1], 10));
|
||||
}
|
||||
_isImperial = true;
|
||||
} else if (primaryValue) {
|
||||
var rawValue = primaryValue;
|
||||
primaryValue = parseFloat(rawValue, 10);
|
||||
if (isNaN(primaryValue)) primaryValue = rawValue;
|
||||
primaryValue = primaryValue.toLocaleString(localizer.languageCode());
|
||||
primaryValue = formatFloat(primaryValue);
|
||||
_isImperial = false;
|
||||
}
|
||||
}
|
||||
@@ -183,7 +184,7 @@ export function uiFieldRoadheight(field, context) {
|
||||
setUnitSuggestions();
|
||||
|
||||
// If feet are specified but inches are omitted, assume zero inches.
|
||||
var inchesPlaceholder = (0).toLocaleString(localizer.languageCode());
|
||||
var inchesPlaceholder = formatFloat(0);
|
||||
|
||||
utilGetSetValue(primaryInput, typeof primaryValue === 'string' ? primaryValue : '')
|
||||
.attr('title', isMixed ? primaryValue.filter(Boolean).join('\n') : null)
|
||||
|
||||
@@ -14,6 +14,7 @@ export function uiFieldRoadspeed(field, context) {
|
||||
var _entityIDs = [];
|
||||
var _tags;
|
||||
var _isImperial;
|
||||
var formatFloat = localizer.floatFormatter(localizer.languageCode());
|
||||
var parseLocaleFloat = localizer.floatParser(localizer.languageCode());
|
||||
|
||||
var speedCombo = uiCombobox(context, 'roadspeed');
|
||||
@@ -92,8 +93,8 @@ export function uiFieldRoadspeed(field, context) {
|
||||
|
||||
function comboValues(d) {
|
||||
return {
|
||||
value: d.toLocaleString(localizer.languageCode()),
|
||||
title: d.toLocaleString(localizer.languageCode())
|
||||
value: formatFloat(d),
|
||||
title: formatFloat(d)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -137,7 +138,7 @@ export function uiFieldRoadspeed(field, context) {
|
||||
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) value = rawValue;
|
||||
value = value.toLocaleString(localizer.languageCode());
|
||||
value = formatFloat(value);
|
||||
}
|
||||
|
||||
setUnitSuggestions();
|
||||
|
||||
@@ -9,35 +9,39 @@ describe('iD.coreLocalizer', function() {
|
||||
describe('#floatParser', function () {
|
||||
it('roundtrips English numbers', function () {
|
||||
var localizer = iD.coreLocalizer();
|
||||
var formatFloat = localizer.floatFormatter('en');
|
||||
var parseFloat = localizer.floatParser('en');
|
||||
expect(parseFloat((-0.1).toLocaleString(localizer.languageCode()))).to.eql(-0.1);
|
||||
expect(parseFloat((1.234).toLocaleString(localizer.languageCode()))).to.eql(1.234);
|
||||
expect(parseFloat(1234).toLocaleString(localizer.languageCode())).to.eql(1234);
|
||||
expect(parseFloat(1234.56).toLocaleString(localizer.languageCode())).to.eql(1234.56);
|
||||
expect(parseFloat(formatFloat(-0.1))).to.eql(-0.1);
|
||||
expect(parseFloat(formatFloat(1.234))).to.eql(1.234);
|
||||
expect(parseFloat(formatFloat(1234))).to.eql(1234);
|
||||
expect(parseFloat(formatFloat(1234.56))).to.eql(1234.56);
|
||||
});
|
||||
it('roundtrips Spanish numbers', function () {
|
||||
var localizer = iD.coreLocalizer();
|
||||
var formatFloat = localizer.floatFormatter('es');
|
||||
var parseFloat = localizer.floatParser('es');
|
||||
expect(parseFloat((-0.1).toLocaleString(localizer.languageCode()))).to.eql(-0.1);
|
||||
expect(parseFloat((1.234).toLocaleString(localizer.languageCode()))).to.eql(1.234);
|
||||
expect(parseFloat(1234).toLocaleString(localizer.languageCode())).to.eql(1234);
|
||||
expect(parseFloat(1234.56).toLocaleString(localizer.languageCode())).to.eql(1234.56);
|
||||
expect(parseFloat(formatFloat(-0.1))).to.eql(-0.1);
|
||||
expect(parseFloat(formatFloat(1.234))).to.eql(1.234);
|
||||
expect(parseFloat(formatFloat(1234))).to.eql(1234);
|
||||
expect(parseFloat(formatFloat(1234.56))).to.eql(1234.56);
|
||||
});
|
||||
it('roundtrips Arabic numbers', function () {
|
||||
var localizer = iD.coreLocalizer();
|
||||
var formatFloat = localizer.floatFormatter('ar-EG');
|
||||
var parseFloat = localizer.floatParser('ar-EG');
|
||||
expect(parseFloat((-0.1).toLocaleString(localizer.languageCode()))).to.eql(-0.1);
|
||||
expect(parseFloat((1.234).toLocaleString(localizer.languageCode()))).to.eql(1.234);
|
||||
expect(parseFloat(1234).toLocaleString(localizer.languageCode())).to.eql(1234);
|
||||
expect(parseFloat(1234.56).toLocaleString(localizer.languageCode())).to.eql(1234.56);
|
||||
expect(parseFloat(formatFloat(-0.1))).to.eql(-0.1);
|
||||
expect(parseFloat(formatFloat(1.234))).to.eql(1.234);
|
||||
expect(parseFloat(formatFloat(1234))).to.eql(1234);
|
||||
expect(parseFloat(formatFloat(1234.56))).to.eql(1234.56);
|
||||
});
|
||||
it('roundtrips Bengali numbers', function () {
|
||||
var localizer = iD.coreLocalizer();
|
||||
var formatFloat = localizer.floatFormatter('bn');
|
||||
var parseFloat = localizer.floatParser('bn');
|
||||
expect(parseFloat((-0.1).toLocaleString(localizer.languageCode()))).to.eql(-0.1);
|
||||
expect(parseFloat((1.234).toLocaleString(localizer.languageCode()))).to.eql(1.234);
|
||||
expect(parseFloat(1234).toLocaleString(localizer.languageCode())).to.eql(1234);
|
||||
expect(parseFloat(1234.56).toLocaleString(localizer.languageCode())).to.eql(1234.56);
|
||||
expect(parseFloat(formatFloat(-0.1))).to.eql(-0.1);
|
||||
expect(parseFloat(formatFloat(1.234))).to.eql(1.234);
|
||||
expect(parseFloat(formatFloat(1234))).to.eql(1234);
|
||||
expect(parseFloat(formatFloat(1234.56))).to.eql(1234.56);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user