Skip to content

Commit

Permalink
ONL-4443: fix: Fixed the way how decimal separator and group separato…
Browse files Browse the repository at this point in the history
…r are detected (#156)

* ONL-4443: fix: Fixed the way how decimal separator and group separator are detected.

* ONL-4443: pr: Changed se to sv.

* ONL-4443: pr: Updated README.

* 0.1.87
  • Loading branch information
mcibique authored May 5, 2020
1 parent 025a621 commit ea3cc65
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 22 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ Checkout the list of possible variables in the [storybook colors story](https://

A few examples of a theme can be found in the [src/styles/themes/](src/styles/themes/) folder.

## I18n

Some components, e.g. `ec-amount-input` or `ec-donut` require `Intl` API to format values properly or to detect
what is the decimal/grouping separator for a current locale. They both do that via [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat)
which might have issues in some browsers for not having all locales set up properly. See the issues we discovered in this [PR](https://github.com/Ebury/chameleon/pull/156#issuecomment-623705733).
If you need to support every single locale on the planet, we recommend to polyfill the Intl API using [intl](https://www.npmjs.com/package/intl) package
so it's consistent across all browsers.

```html
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.en|always"></script>
```

### CSS variables polyfill

If you support **IE11** browser, you have to include the [CSS vars ponyfill](https://jhildenbiddle.github.io/css-vars-ponyfill/#/) when using our components.
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ebury/chameleon-components",
"version": "0.1.86",
"version": "0.1.87",
"main": "src/main.js",
"sideEffects": false,
"author": "Ebury Team (http://labs.ebury.rocks/)",
Expand Down
1 change: 0 additions & 1 deletion src/components/ec-amount-input/ec-amount-input.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,3 @@ describe('EcAmountInput', () => {
expect(wrapper.vm.valueAmount).toBe(null);
});
});

2 changes: 1 addition & 1 deletion src/components/ec-amount-input/ec-amount-input.story.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ stories
default: boolean('Is Masked', false),
},
locale: {
default: select('Locale', ['en', 'es', 'de-ch', 'jp'], 'en'),
default: select('Locale', ['en', 'es', 'de-ch', 'jp', 'sv'], 'en'),
},
currency: {
default: select('Currency', ['GBP', 'EUR', 'JPY', 'INR', 'USD', 'CAD'], 'GBP'),
Expand Down
28 changes: 11 additions & 17 deletions src/components/ec-amount-input/ec-amount-input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import EcInputField from '../ec-input-field';
import EcAmount from '../../directives/ec-amount/ec-amount';
import { format, unFormat } from '../../directives/ec-amount/utils';
import { getDecimalSeparator, getGroupingSeparator } from '../../utils/number-format';
export default {
components: { EcInputField },
Expand Down Expand Up @@ -61,12 +62,6 @@ export default {
const options = new Intl.NumberFormat(this.locale, { style: 'currency', currency: this.currency || 'XYZ' }).resolvedOptions();
return options.maximumFractionDigits;
},
groupingSeparator() {
return this.getSeparator('group');
},
decimalSeparator() {
return this.getSeparator('decimal');
},
},
watch: {
value: {
Expand All @@ -78,7 +73,7 @@ export default {
}
this.formattedValue = newValue;
this.unformattedValue = +(unFormat(newValue, this.groupingSeparator, this.decimalSeparator));
this.unformattedValue = +(unFormat(newValue, this.getGroupingSeparator(), this.getDecimalSeparator()));
} else {
if (newValue === this.unformattedValue) {
return;
Expand All @@ -102,7 +97,7 @@ export default {
},
formattedValue(newValue) {
if (newValue) {
this.unformattedValue = +(unFormat(newValue, this.groupingSeparator, this.decimalSeparator));
this.unformattedValue = +(unFormat(newValue, this.getGroupingSeparator(), this.getDecimalSeparator()));
} else {
this.unformattedValue = null;
}
Expand All @@ -113,20 +108,19 @@ export default {
},
},
methods: {
getSeparator(type) {
const numberWithDecimalSeparator = 11111.1;
return new Intl.NumberFormat(this.locale)
.formatToParts(numberWithDecimalSeparator)
.find(part => part.type === type)
.value;
},
getFormattingOptions() {
return {
precision: this.precision,
decimalSeparator: this.decimalSeparator,
groupingSeparator: this.groupingSeparator,
decimalSeparator: this.getDecimalSeparator(),
groupingSeparator: this.getGroupingSeparator(),
};
},
getGroupingSeparator() {
return getGroupingSeparator(this.locale);
},
getDecimalSeparator() {
return getDecimalSeparator(this.locale);
},
},
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ stories
default: text('note', 'Select currency and set amount'),
},
locale: {
default: select('locale', ['en', 'es', 'de-ch', 'jp'], 'en'),
default: select('locale', ['en', 'es', 'de-ch', 'jp', 'sv'], 'en'),
},
currenciesAreLoading: {
default: boolean('currencies are loading', false),
Expand Down
46 changes: 46 additions & 0 deletions src/utils/number-format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export function getDecimalSeparator(locale) {
// we could just use formatToParts function but it's not supported on IE11
// and there's no polyfill for NumberFormat, only for DateTimeFormat
//
// return new Intl.NumberFormat(locale)
// .formatToParts(1111.1)
// .find(part => part.type === 'decimal')
// .value;
//
// so we have to improvised and force the formatter to format number 0.1 in the format
// 0<decimal separator>1 and then get the 2nd character from the string

const formatted = new Intl.NumberFormat(locale, {
useGrouping: false,
minimumIntegerDigits: 1,
minimumFractionDigits: 1,
maximumFractionDigits: 1,
minimumSignificantDigits: 1,
maximumSignificantDigits: 1,
}).format(0.1);
return formatted[1];
}

export function getGroupingSeparator(locale) {
// we could just use formatToParts function but it's not supported on IE11
// and there's no polyfill for NumberFormat, only for DateTimeFormat
//
// return new Intl.NumberFormat(locale)
// .formatToParts(1111.1)
// .find(part => part.type === 'group')
// .value;
//
// so we have to improvised and force the formatter to format number 1000 in the format
// 1<group separator>000 and then get the 2nd character from the string

const formatted = new Intl.NumberFormat(locale, {
useGrouping: true,
minimumIntegerDigits: 5,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
minimumSignificantDigits: 5,
maximumSignificantDigits: 5,
}).format(10000);
return formatted[2];
}

38 changes: 38 additions & 0 deletions src/utils/number-format.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import fs from 'fs';
import { getDecimalSeparator, getGroupingSeparator } from './number-format';

describe('Utils', () => {
// get list of all locales in the world from intl polyfill.
const locales = fs.readdirSync('./node_modules/intl/locale-data/jsonp')
.filter(fileName => fileName.match(/\.js$/))
.map(fileName => fileName.replace(/\.js$/, ''));

function getExpectedSeparator(locale, type) {
return new Intl.NumberFormat(locale)
.formatToParts(1111.1)
.find(part => part.type === type)
.value;
}

describe('getDecimalSeparator ', () => {
for (const locale of locales) {
it(`should get decimal separator for locale ${locale}`, () => {
const expected = getExpectedSeparator(locale, 'decimal'); // get the decimal separator using method that works in every modern browser
const separator = getDecimalSeparator(locale); // get the decimal separator using our method
expect(separator.length).toBe(1);
expect(separator).toBe(expected);
});
}
});

describe('getGroupingSeparator', () => {
for (const locale of locales) {
it(`should get group separator for locale ${locale}`, () => {
const expected = getExpectedSeparator(locale, 'group'); // get the group separator using method that works in every modern browser
const separator = getGroupingSeparator(locale); // get the group separator using our method
expect(separator.length).toBe(1);
expect(separator).toBe(expected);
});
}
});
});

1 comment on commit ea3cc65

@vercel
Copy link

@vercel vercel bot commented on ea3cc65 May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.