Skip to content

Commit 86fcff1

Browse files
committed
Add "localizePrice" helper
1 parent d2a0b59 commit 86fcff1

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

helpers/lib/icu-detect.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
const hasFullICU = (() => {
4+
try {
5+
const january = new Date(9e8);
6+
const spanish = new Intl.DateTimeFormat('es', { month: 'long' });
7+
return spanish.format(january) === 'enero';
8+
} catch (err) {
9+
return false;
10+
}
11+
})();
12+
13+
module.exports = {
14+
hasFullICU
15+
};

helpers/localizePrice.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
const utils = require('handlebars-utils');
3+
// Detect ICU support
4+
const { hasFullICU } = require('./lib/icu-detect.js');
5+
6+
const factory = () => {
7+
return function(price, locale) {
8+
if (!utils.isObject(price) || !utils.isString(price.currency)
9+
|| isNaN(price.value) || !utils.isString(price.formatted)) {
10+
// Return empty string if this does not appear to be a price object
11+
return '';
12+
}
13+
14+
if (!utils.isString(locale) || locale.length < 2) {
15+
// Valid browser language strings are at least two characters
16+
// https://www.metamodpro.com/browser-language-codes
17+
// If provided locale is less than two characters (or not a string),
18+
// return the normal formatted price
19+
return price.formatted;
20+
}
21+
22+
// If the if full ICU is not installed, fall back to normal price
23+
if (!hasFullICU){
24+
return price.formatted;
25+
}
26+
27+
// Try to format the price to the provided locale,
28+
// but if anything goes wrong,
29+
// just return the usual price
30+
// Could happen if the full ICU is not installed,
31+
// or if an invalid locale is provided.
32+
try {
33+
return new Intl.NumberFormat(
34+
locale, { style: 'currency', currency: price.currency}
35+
).format(price.value);
36+
}
37+
catch (err){
38+
return price.formatted;
39+
}
40+
};
41+
};
42+
43+
module.exports = [{
44+
name: 'localizePrice',
45+
factory: factory,
46+
}];

spec/helpers.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ describe('helper registration', () => {
5050
'lang',
5151
'langJson',
5252
'limit',
53+
'localizePrice',
5354
'money',
5455
'nl2br',
5556
'occurrences',

spec/helpers/localizePrice.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
require('full-icu');
2+
3+
const Lab = require('lab'),
4+
lab = exports.lab = Lab.script(),
5+
describe = lab.experiment,
6+
it = lab.it,
7+
specHelpers = require('../spec-helpers'),
8+
testRunner = specHelpers.testRunner
9+
10+
describe('localizePrice helper', function() {
11+
const context = {
12+
"price": {
13+
"tax_label": "GST",
14+
"without_tax": {
15+
"currency": "USD",
16+
"formatted": "$123,456.78",
17+
"value": 123456.78
18+
}
19+
}
20+
};
21+
22+
const runTestCases = testRunner({context});
23+
24+
it('should return return correct prices across a number of locales', function(done) {
25+
runTestCases([
26+
{
27+
input: '{{localizePrice price.without_tax "en-US"}}',
28+
output: '$123,456.78',
29+
},
30+
{
31+
input: '{{localizePrice price.without_tax "ja-JP"}}',
32+
output: '$123,456.78',
33+
},
34+
{
35+
input: '{{localizePrice price.without_tax "de"}}',
36+
output: '123.456,78 $',
37+
},
38+
], done);
39+
});
40+
});

0 commit comments

Comments
 (0)