handlebars-i18n 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/coveralls.yml +44 -0
- package/dist/handlebars-i18n.d.ts +3 -3
- package/dist/handlebars-i18n.js +88 -30
- package/dist/handlebars-i18n.min.js +1 -1
- package/examples/browser-example/index.html +17 -9
- package/examples/node-example/simple-example.js +87 -71
- package/examples/typescript/test.hbs +13 -7
- package/package.json +8 -7
- package/readme.md +50 -51
- package/test/handlebars-i18n.test.js +429 -250
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Test and Coverage
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ "master" ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ "master" ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
|
|
14
|
+
- uses: actions/checkout@v3
|
|
15
|
+
|
|
16
|
+
- name: Use Node.js 16.x
|
|
17
|
+
uses: actions/setup-node@v3
|
|
18
|
+
with:
|
|
19
|
+
node-version: 16.x
|
|
20
|
+
|
|
21
|
+
- name: npm install, make test-coverage
|
|
22
|
+
run: |
|
|
23
|
+
npm install
|
|
24
|
+
npm run test:coverage
|
|
25
|
+
sleep 2
|
|
26
|
+
|
|
27
|
+
- name: Report Coveralls (Linux)
|
|
28
|
+
if: startsWith(runner.os, 'Linux')
|
|
29
|
+
run: curl -sL https://coveralls.io/coveralls-linux.tar.gz | tar -xz && ./coveralls
|
|
30
|
+
env:
|
|
31
|
+
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
|
|
33
|
+
- name: Report Coveralls (Windows)
|
|
34
|
+
if: startsWith(runner.os, 'Windows')
|
|
35
|
+
run: curl -sL https://github.com/coverallsapp/coverage-reporter/releases/latest/download/coveralls-windows.zip | zcat > ./coveralls.exe && ./coveralls.exe
|
|
36
|
+
env:
|
|
37
|
+
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
38
|
+
|
|
39
|
+
- name: Report Coveralls (macOS)
|
|
40
|
+
if: startsWith(runner.os, 'macOS')
|
|
41
|
+
run: |
|
|
42
|
+
brew tap coverallsapp/coveralls --quiet
|
|
43
|
+
brew install coveralls --quiet
|
|
44
|
+
coveralls
|
|
@@ -18,7 +18,7 @@ type unitDisplay = "short" | "narrow" | "long";
|
|
|
18
18
|
type roundingPriority = "auto" | "morePrecision" | "lessPrecision";
|
|
19
19
|
|
|
20
20
|
type roundingMode =
|
|
21
|
-
|
|
21
|
+
"ceil"
|
|
22
22
|
| "floor"
|
|
23
23
|
| "expand"
|
|
24
24
|
| "trunc"
|
|
@@ -197,13 +197,13 @@ export type DateTimeFormatConfiguration = [
|
|
|
197
197
|
CustomFormatName?
|
|
198
198
|
];
|
|
199
199
|
|
|
200
|
-
|
|
201
200
|
type DateRelFormatOptions = {
|
|
202
201
|
localeMatcher?: localeMatcher,
|
|
203
202
|
numberingSystem?: numberingSystem,
|
|
204
203
|
numeric?: "always" | "auto",
|
|
205
204
|
style?: "long" | "short" | "narrow",
|
|
206
|
-
|
|
205
|
+
timeZone?: TimeZone,
|
|
206
|
+
unit?: "second" | "minute" | "hour" | "day" | "week" | "month" | "quarter" | "year"
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
export type RelativeTimeFormatConfiguration = [
|
package/dist/handlebars-i18n.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* handlebars-i18n.js
|
|
3
3
|
*
|
|
4
4
|
* @author: Florian Walzel
|
|
5
|
-
* @date: 2024-
|
|
5
|
+
* @date: 2024-08
|
|
6
6
|
*
|
|
7
7
|
* handlebars-i18n adds features for localization/
|
|
8
8
|
* internationalization to handlebars.js
|
|
@@ -17,15 +17,14 @@
|
|
|
17
17
|
const Handlebars = require('handlebars'),
|
|
18
18
|
i18next = require('i18next'),
|
|
19
19
|
Intl = require('intl'),
|
|
20
|
-
RelativeTimeFormat= require('relative-time-format');
|
|
20
|
+
RelativeTimeFormat = require('relative-time-format');
|
|
21
21
|
module.exports = factory(
|
|
22
22
|
Handlebars,
|
|
23
23
|
i18next,
|
|
24
24
|
Intl,
|
|
25
25
|
RelativeTimeFormat,
|
|
26
26
|
process?.env?.NODE_ENV === 'TEST');
|
|
27
|
-
}
|
|
28
|
-
else if (typeof define === 'function' && define.amd)
|
|
27
|
+
} else if (typeof define === 'function' && define.amd)
|
|
29
28
|
define(['Handlebars', 'i18next', 'Intl'], factory);
|
|
30
29
|
else if (typeof root.Handlebars === 'object'
|
|
31
30
|
&& typeof root.i18next === 'object'
|
|
@@ -151,7 +150,7 @@
|
|
|
151
150
|
return false;
|
|
152
151
|
}
|
|
153
152
|
|
|
154
|
-
if (!
|
|
153
|
+
if (!['DateTimeFormat', 'RelativeTimeFormat', 'NumberFormat', 'PriceFormat'].includes(typeOfFormat)) {
|
|
155
154
|
console.error('@ handlebars-i18n.configure(): Invalid argument <' + typeOfFormat + '>. ' +
|
|
156
155
|
'Second argument must be a string with the options key. ' +
|
|
157
156
|
'Use either "DateTimeFormat", "RelativeTimeFormat", "NumberFormat", or "PriceFormat".');
|
|
@@ -191,8 +190,7 @@
|
|
|
191
190
|
optionsConf[formatType].custom[customFormat] = {};
|
|
192
191
|
|
|
193
192
|
optionsConf[formatType].custom[customFormat][lang] = options;
|
|
194
|
-
}
|
|
195
|
-
else
|
|
193
|
+
} else
|
|
196
194
|
optionsConf[formatType].standard[lang] = options;
|
|
197
195
|
|
|
198
196
|
return true;
|
|
@@ -221,8 +219,7 @@
|
|
|
221
219
|
if (typeof dateInput === 'number') {
|
|
222
220
|
// input as milliseconds since unix epoch, like: 1583922952743
|
|
223
221
|
date = new Date(dateInput);
|
|
224
|
-
}
|
|
225
|
-
else if (typeof dateInput === 'string') {
|
|
222
|
+
} else if (typeof dateInput === 'string') {
|
|
226
223
|
|
|
227
224
|
if (dateInput.charAt(0) === '[' && dateInput.slice(-1) === ']') {
|
|
228
225
|
// input as array represented as string such as "[2020, 11]"
|
|
@@ -230,17 +227,14 @@
|
|
|
230
227
|
let dateArr = dateInput.split(',');
|
|
231
228
|
let dateFactory = __applyToConstructor.bind(null, Date);
|
|
232
229
|
date = dateFactory(dateArr);
|
|
233
|
-
}
|
|
234
|
-
else if (dateInput.toLowerCase() === 'now' || dateInput.toLowerCase() === 'today') {
|
|
230
|
+
} else if (dateInput.toLowerCase() === 'now' || dateInput.toLowerCase() === 'today') {
|
|
235
231
|
// input as word "now" or "today"
|
|
236
232
|
date = new Date();
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
233
|
+
} else {
|
|
239
234
|
// input as date string such as "1995-12-17T03:24:00"
|
|
240
235
|
date = new Date(dateInput);
|
|
241
236
|
}
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
237
|
+
} else {
|
|
244
238
|
// fallback: today’s date
|
|
245
239
|
date = new Date();
|
|
246
240
|
}
|
|
@@ -337,8 +331,7 @@
|
|
|
337
331
|
else
|
|
338
332
|
return false;
|
|
339
333
|
});
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
334
|
+
} else {
|
|
342
335
|
if (__validateArgs(langOrArr, typeOfFormat, options, customFormatName))
|
|
343
336
|
__setArgs(langOrArr, typeOfFormat, options, customFormatName);
|
|
344
337
|
else
|
|
@@ -393,7 +386,7 @@
|
|
|
393
386
|
* @returns {*}
|
|
394
387
|
*/
|
|
395
388
|
function (str, attributes) {
|
|
396
|
-
return new handlebars.SafeString((typeof(i18next) !== 'undefined' ? i18next.t(str, attributes.hash) : str));
|
|
389
|
+
return new handlebars.SafeString((typeof (i18next) !== 'undefined' ? i18next.t(str, attributes.hash) : str));
|
|
397
390
|
}
|
|
398
391
|
);
|
|
399
392
|
handlebars.registerHelper('_locale',
|
|
@@ -445,12 +438,77 @@
|
|
|
445
438
|
* @param options
|
|
446
439
|
*/
|
|
447
440
|
function (dateInput, options) {
|
|
448
|
-
const date= __createDateObj(dateInput);
|
|
441
|
+
const date = __createDateObj(dateInput);
|
|
449
442
|
const opts = __configLookup(options, i18next.language, optionsConf.DateTimeFormat);
|
|
450
443
|
const dateFormat = new Intl.DateTimeFormat(i18next.language, opts);
|
|
451
444
|
return dateFormat.format(date);
|
|
452
445
|
}
|
|
453
446
|
);
|
|
447
|
+
handlebars.registerHelper('_dateAdd',
|
|
448
|
+
/**
|
|
449
|
+
* adds a time offset in a given unit to a date
|
|
450
|
+
* -> returns the modified date
|
|
451
|
+
*
|
|
452
|
+
* @param dateInput
|
|
453
|
+
* @param offset
|
|
454
|
+
* @param options
|
|
455
|
+
* @returns {string}
|
|
456
|
+
*/
|
|
457
|
+
function (dateInput, offset, options) {
|
|
458
|
+
|
|
459
|
+
if (typeof dateInput !== 'number' && typeof dateInput !== 'string')
|
|
460
|
+
throw new Error('@ handlebars-i18n: invalid first argument "dateInput" was given for _dateAdd.');
|
|
461
|
+
|
|
462
|
+
if (typeof offset !== 'number')
|
|
463
|
+
throw new Error('@ handlebars-i18n: invalid second argument "offset" was given for _dateAdd.');
|
|
464
|
+
|
|
465
|
+
const date = __createDateObj(dateInput);
|
|
466
|
+
|
|
467
|
+
const opts = __configLookup(options, i18next.language, optionsConf.DateTimeFormat);
|
|
468
|
+
opts.unit = opts.unit || 'hour';
|
|
469
|
+
|
|
470
|
+
switch (opts.unit) {
|
|
471
|
+
case 'second':
|
|
472
|
+
case 'seconds':
|
|
473
|
+
date.setSeconds(date.getSeconds() + offset);
|
|
474
|
+
break;
|
|
475
|
+
case 'minute':
|
|
476
|
+
case 'minutes':
|
|
477
|
+
date.setMinutes(date.getMinutes() + offset);
|
|
478
|
+
break;
|
|
479
|
+
case 'hour':
|
|
480
|
+
case 'hours':
|
|
481
|
+
date.setHours(date.getHours() + offset);
|
|
482
|
+
break;
|
|
483
|
+
case 'day':
|
|
484
|
+
case 'days':
|
|
485
|
+
date.setDate(date.getDate() + offset);
|
|
486
|
+
break;
|
|
487
|
+
case 'week':
|
|
488
|
+
case 'weeks':
|
|
489
|
+
date.setDate(date.getDate() + offset * 7);
|
|
490
|
+
break;
|
|
491
|
+
case 'month':
|
|
492
|
+
case 'months':
|
|
493
|
+
date.setMonth(date.getMonth() + offset);
|
|
494
|
+
break;
|
|
495
|
+
case 'quarter':
|
|
496
|
+
case 'quarters':
|
|
497
|
+
date.setMonth(date.getMonth() + offset * 3);
|
|
498
|
+
break;
|
|
499
|
+
case 'year':
|
|
500
|
+
case 'years':
|
|
501
|
+
date.setFullYear(date.getFullYear() + offset);
|
|
502
|
+
break;
|
|
503
|
+
default:
|
|
504
|
+
throw new Error('@ handlebars-i18n: invalid argument "unit" was given for _dateAdd.' +
|
|
505
|
+
'Unit must be either "second" | "minute" | "hour" | "day" | "week" | "month" | "quarter" | "year".');
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const dateFormat = new Intl.DateTimeFormat(i18next.language, opts);
|
|
509
|
+
return dateFormat.format(date);
|
|
510
|
+
}
|
|
511
|
+
);
|
|
454
512
|
handlebars.registerHelper('_dateRel',
|
|
455
513
|
/**
|
|
456
514
|
* returns a relative date formatted according the options
|
|
@@ -468,7 +526,7 @@
|
|
|
468
526
|
* @returns {string}
|
|
469
527
|
*/
|
|
470
528
|
function (dateValue, options) {
|
|
471
|
-
const relDate= parseInt(dateValue);
|
|
529
|
+
const relDate = parseInt(dateValue);
|
|
472
530
|
const opts = __configLookup(options, i18next.language, optionsConf.RelativeTimeFormat);
|
|
473
531
|
const relDateFormat = __getRelDateFormatPolyfill(i18next.language, opts);
|
|
474
532
|
return relDateFormat.format(relDate, opts.unit);
|
|
@@ -485,20 +543,20 @@
|
|
|
485
543
|
function (dateInputA, dateInputB, options) {
|
|
486
544
|
|
|
487
545
|
let dateDiff;
|
|
546
|
+
let opts = __configLookup(options, i18next.language, optionsConf.RelativeTimeFormat);
|
|
488
547
|
|
|
489
|
-
if (!
|
|
548
|
+
if (!__isNumOrString(dateInputA)) {
|
|
549
|
+
console.error('@ handlebars-i18n: invalid first argument dateInputA was given for _dateDiff.');
|
|
490
550
|
return null;
|
|
491
|
-
else if (! __isNumOrString(dateInputB))
|
|
492
|
-
dateDiff = __createDateObj(dateInputA);
|
|
493
|
-
else if (! __isNumOrString(dateInputA))
|
|
494
|
-
dateDiff = __createDateObj(dateInputB);
|
|
495
|
-
else {
|
|
496
|
-
const dateA= __createDateObj(dateInputA);
|
|
497
|
-
const dateB= __createDateObj(dateInputB);
|
|
498
|
-
dateDiff = dateA - dateB;
|
|
499
551
|
}
|
|
500
552
|
|
|
501
|
-
|
|
553
|
+
dateInputB = dateInputB || 'now';
|
|
554
|
+
|
|
555
|
+
let dateA = __createDateObj(dateInputA);
|
|
556
|
+
let dateB = __createDateObj(dateInputB);
|
|
557
|
+
|
|
558
|
+
dateDiff = dateA - dateB;
|
|
559
|
+
|
|
502
560
|
const relDate = __getDateDiff(dateDiff, opts.unit);
|
|
503
561
|
const relDateFormat = __getRelDateFormatPolyfill(i18next.language, opts);
|
|
504
562
|
return relDateFormat.format(relDate, opts.unit);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,
|
|
1
|
+
!function(e,t){if("object"==typeof exports&&"object"==typeof module){const e=require("handlebars"),r=require("i18next"),n=require("intl"),a=require("relative-time-format");module.exports=t(e,r,n,a,"TEST"===process?.env?.NODE_ENV)}else if("function"==typeof define&&define.amd)define(["Handlebars","i18next","Intl"],t);else{if("object"!=typeof e.Handlebars||"object"!=typeof e.i18next||"object"!=typeof e.Intl)return console.error("@ handlebars-i18n: One or more dependencies are missing. Check for Handlebars, i18next and Intl."),!1;e.HandlebarsI18n=t(e.Handlebars,e.i18next,e.Intl)}}(this,(function(e,t,r,n,a){"use strict";const o={DateTimeFormat:{standard:{},custom:{}},RelativeTimeFormat:{standard:{all:{unit:"hours"}},custom:{}},NumberFormat:{standard:{},custom:{}},PriceFormat:{standard:{all:{style:"currency",currency:"EUR"}},custom:{}}};let i=JSON.parse(JSON.stringify(o));const s={};function u(e,t){let r=[null].concat(t);return new(e.bind.apply(e,r))}function l(e,t,r){if("object"==typeof e&&"object"==typeof e.hash&&Object.keys(e.hash).length>0){let n=e.hash;if(void 0===n.format)return n;if(void 0!==r.custom[n.format]&&void 0!==r.custom[n.format][t])return r.custom[n.format][t]}return void 0!==r.standard[t]?r.standard[t]:void 0!==r.standard.all?r.standard.all:{}}function c(e,t,r,n){return"string"!=typeof e?(console.error("@ handlebars-i18n.configure(): Invalid argument <"+e+'> First argument must be a string with language code such as "en".'),!1):["DateTimeFormat","RelativeTimeFormat","NumberFormat","PriceFormat"].includes(t)?"object"!=typeof r?(console.error("@ handlebars-i18n.configure(): Invalid argument <"+r+"> Third argument must be an object containing the configuration parameters."),!1):(null==n||"string"==typeof n)&&""!==n&&" "!==n||(console.error("@ handlebars-i18n.configure(): Invalid argument <"+n+"> Fourth argument (optional) must be a string naming your custom format configuration."),!1):(console.error("@ handlebars-i18n.configure(): Invalid argument <"+t+'>. Second argument must be a string with the options key. Use either "DateTimeFormat", "RelativeTimeFormat", "NumberFormat", or "PriceFormat".'),!1)}function m(e,t,r,n){return null!=n?(void 0===i[t].custom[n]&&(i[t].custom[n]={}),i[t].custom[n][e]=r):i[t].standard[e]=r,!0}function g(e){return"number"==typeof e||"string"==typeof e&&""!==e}function d(e){let t;if("number"==typeof e)t=new Date(e);else if("string"==typeof e)if("["===e.charAt(0)&&"]"===e.slice(-1)){let r=(e=e.substring(1,e.length-1).replace(/ /g,"")).split(",");t=u.bind(null,Date)(r)}else t="now"===e.toLowerCase()||"today"===e.toLowerCase()?new Date:new Date(e);else t=new Date;return t}function f(e,t){if("function"==typeof r.RelativeTimeFormat)return new r.RelativeTimeFormat(e,t);if(void 0===s[e])try{s[e]=require(`relative-time-format/locale/${e}`)}catch(e){console.error(e)}return n.addLocale(s[e]),new n(e,t)}function b(e,t){return t=t||"hour",Math.trunc(e/{second:1e3,seconds:1e3,minute:6e4,minutes:6e4,hour:36e5,hours:36e5,day:864e5,days:864e5,week:6048e5,weeks:6048e5,month:2629746e3,months:2629746e3,quarter:78894e5,quarters:78894e5,year:315576e5,years:315576e5}[t])}return{configure:function(e,t,r,n){if("string"!=typeof e&&!Array.isArray(e))return console.error("@ handlebars-i18n.configure(): Invalid argument <"+e+'> First argument must be a string with language code such as "en" or an array with language parameters.'),!1;if(Array.isArray(e)){if(e.length<1)return console.log("@ handlebars-i18n.configure(): You passed an empty array, no parameters taken."),!1;e.forEach((e=>{if(!c(e[0],e[1],e[2],e[3]))return!1;m(e[0],e[1],e[2],e[3])}))}else{if(!c(e,t,r,n))return!1;m(e,t,r,n)}return!0},reset:function(){return i=JSON.parse(JSON.stringify(o)),!0},init:function(n,a){return"object"==typeof n&&null!==n?e=n:null!=n&&console.error("@ handlebars-i18n.init(): Invalid Argument [1] given for overrideHndlbrs. Argument must be the Handlebars object. Using generic Handlebars object instead."),"object"==typeof a&&null!==a?t=a:null!=a&&console.error("@ handlebars-i18n.init(): Invalid Argument [2] given for overrideI18n. Argument must be the i18next object. Using generic i18next object on module level instead."),e.registerHelper("__",(function(r,n){return new e.SafeString(void 0!==t?t.t(r,n.hash):r)})),e.registerHelper("_locale",(function(){return t.language})),e.registerHelper("localeIs",(function(e){return t.language===e})),e.registerHelper("_date",(function(e,n){const a=d(e),o=l(n,t.language,i.DateTimeFormat);return new r.DateTimeFormat(t.language,o).format(a)})),e.registerHelper("_dateAdd",(function(e,n,a){if("number"!=typeof e&&"string"!=typeof e)throw new Error('@ handlebars-i18n: invalid first argument "dateInput" was given for _dateAdd.');if("number"!=typeof n)throw new Error('@ handlebars-i18n: invalid second argument "offset" was given for _dateAdd.');const o=d(e),s=l(a,t.language,i.DateTimeFormat);switch(s.unit=s.unit||"hour",s.unit){case"second":case"seconds":o.setSeconds(o.getSeconds()+n);break;case"minute":case"minutes":o.setMinutes(o.getMinutes()+n);break;case"hour":case"hours":o.setHours(o.getHours()+n);break;case"day":case"days":o.setDate(o.getDate()+n);break;case"week":case"weeks":o.setDate(o.getDate()+7*n);break;case"month":case"months":o.setMonth(o.getMonth()+n);break;case"quarter":case"quarters":o.setMonth(o.getMonth()+3*n);break;case"year":case"years":o.setFullYear(o.getFullYear()+n);break;default:throw new Error('@ handlebars-i18n: invalid argument "unit" was given for _dateAdd.Unit must be either "second" | "minute" | "hour" | "day" | "week" | "month" | "quarter" | "year".')}return new r.DateTimeFormat(t.language,s).format(o)})),e.registerHelper("_dateRel",(function(e,r){const n=parseInt(e),a=l(r,t.language,i.RelativeTimeFormat);return f(t.language,a).format(n,a.unit)})),e.registerHelper("_dateDiff",(function(e,r,n){let a,o=l(n,t.language,i.RelativeTimeFormat);if(!g(e))return console.error("@ handlebars-i18n: invalid first argument dateInputA was given for _dateDiff."),null;r=r||"now",a=d(e)-d(r);const s=b(a,o.unit);return f(t.language,o).format(s,o.unit)})),e.registerHelper("_num",(function(e,n){let a=l(n,t.language,i.NumberFormat);return new r.NumberFormat(t.language,a).format(e)})),e.registerHelper("_price",(function(e,n){let a=l(n,t.language,i.PriceFormat);"string"!=typeof a.style&&"string"==typeof a.currency&&(a.style="currency");return new r.NumberFormat(t.language,a).format(e)})),e},...a&&{private:{applyToConstructor:u,configLookup:l,validateArgs:c,setArgs:m,isNumOrString:g,createDateObj:d,getRelDateFormatPolyfill:f,getDateDiff:b}}}}));
|
|
@@ -218,6 +218,22 @@
|
|
|
218
218
|
|
|
219
219
|
<button onclick="changeLang()">{{__ "key0"}} {{#if (localeIs "en")}}German {{else}}Englisch {{/if}}</button>
|
|
220
220
|
|
|
221
|
+
<h4>Date with positive time offset:</h4>
|
|
222
|
+
<code>{{{{raw}}}} {{_dateAdd "December 17, 1995" 24 unit="hour"}} {{{{/raw}}}}</code>
|
|
223
|
+
<p>→ {{_dateAdd "December 17, 1995 08:00:00" 24 unit="hour"}}</p>
|
|
224
|
+
|
|
225
|
+
<h4>Date with negative time offset:</h4>
|
|
226
|
+
<code>{{{{raw}}}} {{_dateAdd "December 17, 1995" -10 unit="day"}} {{{{/raw}}}}</code>
|
|
227
|
+
<p>→ {{_dateAdd "December 17, 1995" -10 unit="day"}}</p>
|
|
228
|
+
|
|
229
|
+
<h4>Relative difference between two dates:</h4>
|
|
230
|
+
<code>{{{{raw}}}} {{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}} {{{{/raw}}}}</code>
|
|
231
|
+
<p>→ {{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}}</p>
|
|
232
|
+
|
|
233
|
+
<h4>Relative difference between two dates with custom configuration (subset "date-rel-spec"):</h4>
|
|
234
|
+
<code>{{{{raw}}}} {{_dateDiff myDate "1995-12-17T00:00:00" format="date-rel-spec"}} {{{{/raw}}}}</code>
|
|
235
|
+
<p>→ {{_dateDiff myDate "1995-12-17T00:00:00" format="date-rel-spec"}}</p>
|
|
236
|
+
|
|
221
237
|
<h4>Relative date event in the future:</h4>
|
|
222
238
|
<code>{{{{raw}}}} {{_dateRel 7 unit="hour"}} {{{{/raw}}}}</code>
|
|
223
239
|
<p>→ {{_dateRel 7 unit="hour"}}</p>
|
|
@@ -226,15 +242,7 @@
|
|
|
226
242
|
<code>{{{{raw}}}} {{_dateRel 7 unit="hour"}} {{{{/raw}}}}</code>
|
|
227
243
|
<p>→ {{_dateRel -7 unit="hour"}}</p>
|
|
228
244
|
|
|
229
|
-
<
|
|
230
|
-
<code>{{{{raw}}}} {{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}} {{{{/raw}}}}</code>
|
|
231
|
-
<p>→ {{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}}</p>
|
|
232
|
-
|
|
233
|
-
<h4>Date difference by custom configuration (subset "date-rel-spec"):</h4>
|
|
234
|
-
<code>{{{{raw}}}} {{_dateDiff mydate "1995-12-17T00:00:00" format="date-rel-spec"}} {{{{/raw}}}}</code>
|
|
235
|
-
<p>→ {{_dateDiff mydate "1995-12-17T00:00:00" format="date-rel-spec"}}</p>
|
|
236
|
-
|
|
237
|
-
<p> </p><button onclick="changeLang()">{{__ "key0"}} {{#if (localeIs "en")}}German {{else}}Englisch {{/if}}</button>`;
|
|
245
|
+
<button onclick="changeLang()">{{__ "key0"}} {{#if (localeIs "en")}}German {{else}}Englisch {{/if}}</button>`;
|
|
238
246
|
|
|
239
247
|
// -- Ignore this. It’s just a helper to display un-rendered {{handlebars code}} between the <code> Tags
|
|
240
248
|
Handlebars.registerHelper('raw', function(options) {
|
|
@@ -18,9 +18,9 @@ const htmlEntities = require('html-entities');
|
|
|
18
18
|
// -- The translation phrases for i18next
|
|
19
19
|
i18next
|
|
20
20
|
.init({
|
|
21
|
-
resources
|
|
22
|
-
'en'
|
|
23
|
-
translation
|
|
21
|
+
resources: {
|
|
22
|
+
'en': {
|
|
23
|
+
translation: {
|
|
24
24
|
'key0': 'Change Language to',
|
|
25
25
|
'key1': 'What is good?',
|
|
26
26
|
'key2': '{{what}} is good.',
|
|
@@ -29,7 +29,7 @@ i18next
|
|
|
29
29
|
'key4': 'Selected Language is:'
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
|
-
'de'
|
|
32
|
+
'de': {
|
|
33
33
|
translation: {
|
|
34
34
|
'key0': 'Sprache wechseln zu',
|
|
35
35
|
'key1': 'Was ist gut?',
|
|
@@ -40,16 +40,16 @@ i18next
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
-
lng
|
|
43
|
+
lng: 'en',
|
|
44
44
|
compatibilityJSON: 'v2'
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
// -- Handlebars' example data object
|
|
48
48
|
let data = {
|
|
49
|
-
sayWhat
|
|
50
|
-
holdKey3
|
|
51
|
-
holdKey4
|
|
52
|
-
mynumber
|
|
49
|
+
sayWhat: 'handlebars-i18n',
|
|
50
|
+
holdKey3: 'key3WithCount',
|
|
51
|
+
holdKey4: 'key4',
|
|
52
|
+
mynumber: 33.333,
|
|
53
53
|
myMmaxDigits: 1,
|
|
54
54
|
myPrice: 12.99,
|
|
55
55
|
myDate: '2020-03-11T03:24:00'
|
|
@@ -59,23 +59,30 @@ let data = {
|
|
|
59
59
|
HandlebarsI18n.init();
|
|
60
60
|
HandlebarsI18n.configure([
|
|
61
61
|
// generic configuration for all languages for number representation:
|
|
62
|
-
['all', 'NumberFormat', {
|
|
62
|
+
['all', 'NumberFormat', {minimumFractionDigits: 2}],
|
|
63
63
|
// generic configurations per language for price representation:
|
|
64
|
-
['en', 'PriceFormat', {
|
|
65
|
-
['de', 'PriceFormat', {
|
|
64
|
+
['en', 'PriceFormat', {currency: 'USD'}],
|
|
65
|
+
['de', 'PriceFormat', {currency: 'EUR'}],
|
|
66
66
|
// generic configurations per language for date representation:
|
|
67
|
-
['en', 'DateTimeFormat', {
|
|
68
|
-
['de', 'DateTimeFormat', {
|
|
67
|
+
['en', 'DateTimeFormat', {year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric'}],
|
|
68
|
+
['de', 'DateTimeFormat', {
|
|
69
|
+
year: 'numeric',
|
|
70
|
+
month: 'numeric',
|
|
71
|
+
day: 'numeric',
|
|
72
|
+
hour: 'numeric',
|
|
73
|
+
minute: 'numeric',
|
|
74
|
+
hour12: false
|
|
75
|
+
}],
|
|
69
76
|
// configurations per language with custom formats for date:
|
|
70
|
-
['en', 'DateTimeFormat', {
|
|
71
|
-
['de', 'DateTimeFormat', {
|
|
72
|
-
['en', 'DateTimeFormat', {
|
|
73
|
-
['de', 'DateTimeFormat', {
|
|
74
|
-
['en', 'DateTimeFormat', {
|
|
75
|
-
['de', 'DateTimeFormat', {
|
|
77
|
+
['en', 'DateTimeFormat', {year: 'numeric'}, 'custom-year-only'],
|
|
78
|
+
['de', 'DateTimeFormat', {year: 'numeric'}, 'custom-year-only'],
|
|
79
|
+
['en', 'DateTimeFormat', {year: 'numeric', month: 'numeric', day: 'numeric'}, 'custom-date-short'],
|
|
80
|
+
['de', 'DateTimeFormat', {year: 'numeric', month: 'numeric', day: 'numeric'}, 'custom-date-short'],
|
|
81
|
+
['en', 'DateTimeFormat', {hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: false}, 'custom-time'],
|
|
82
|
+
['de', 'DateTimeFormat', {hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: false}, 'custom-time'],
|
|
76
83
|
// custom formats for relative dates:
|
|
77
|
-
['en', 'RelativeTimeFormat', {
|
|
78
|
-
['de', 'RelativeTimeFormat', {
|
|
84
|
+
['en', 'RelativeTimeFormat', {style: 'short', unit: 'year'}, 'date-rel-spec'],
|
|
85
|
+
['de', 'RelativeTimeFormat', {style: 'short', unit: 'year'}, 'date-rel-spec']
|
|
79
86
|
]);
|
|
80
87
|
|
|
81
88
|
let template;
|
|
@@ -120,107 +127,116 @@ template += '{{__ "key1" lng="de"}}';
|
|
|
120
127
|
// ----------------------------------------
|
|
121
128
|
|
|
122
129
|
// Translation key given through handlebars variable and _locale output:
|
|
123
|
-
template += raw('{{__ holdKey4}} {{_locale}}');
|
|
124
|
-
template += '{{__ holdKey4}} {{_locale}}';
|
|
130
|
+
template += raw('{{__ holdKey4}} {{_locale}}');
|
|
131
|
+
template += '{{__ holdKey4}} {{_locale}}';
|
|
125
132
|
|
|
126
133
|
// Check against selected language:
|
|
127
|
-
template += raw('{{#if (localeIs "en")}}English {{else}}Deutsch {{/if}}');
|
|
128
|
-
template += '{{#if (localeIs "en")}}English {{else}}Deutsch {{/if}}';
|
|
134
|
+
template += raw('{{#if (localeIs "en")}}English {{else}}Deutsch {{/if}}');
|
|
135
|
+
template += '{{#if (localeIs "en")}}English {{else}}Deutsch {{/if}}';
|
|
129
136
|
|
|
130
137
|
|
|
131
138
|
// Number representation
|
|
132
139
|
// ----------------------------------------
|
|
133
140
|
|
|
134
141
|
// Number representation as configured for all languages:
|
|
135
|
-
template += raw('{{_num 7000}}');
|
|
136
|
-
template += '{{_num 7000}}';
|
|
142
|
+
template += raw('{{_num 7000}}');
|
|
143
|
+
template += '{{_num 7000}}';
|
|
137
144
|
|
|
138
145
|
// Number representation with specific format attribute:
|
|
139
|
-
template += raw('{{_num 3.1415926 maximumFractionDigits=0}}');
|
|
140
|
-
template += '{{_num 3.1415926 maximumFractionDigits=0}}';
|
|
146
|
+
template += raw('{{_num 3.1415926 maximumFractionDigits=0}}');
|
|
147
|
+
template += '{{_num 3.1415926 maximumFractionDigits=0}}';
|
|
141
148
|
|
|
142
149
|
// Number and attribute given through handlebars variables:
|
|
143
|
-
template += raw('{{_num mynumber maximumFractionDigits=myMaxDigits}}');
|
|
144
|
-
template += '{{_num mynumber maximumFractionDigits=myMaxDigits}}';
|
|
150
|
+
template += raw('{{_num mynumber maximumFractionDigits=myMaxDigits}}');
|
|
151
|
+
template += '{{_num mynumber maximumFractionDigits=myMaxDigits}}';
|
|
145
152
|
|
|
146
153
|
|
|
147
154
|
// Price representation
|
|
148
155
|
// ----------------------------------------
|
|
149
156
|
|
|
150
157
|
// Price representation as configured per language:
|
|
151
|
-
template += raw('{{_price 9999.99}}');
|
|
152
|
-
template += '{{_price 9999.99}}';
|
|
158
|
+
template += raw('{{_price 9999.99}}');
|
|
159
|
+
template += '{{_price 9999.99}}';
|
|
153
160
|
|
|
154
161
|
// Price representation with specific format attributes:
|
|
155
|
-
template += raw('{{_price 1000.99 currency="JPY" minimumFractionDigits=0}}');
|
|
156
|
-
template += '{{_price 1000.99 currency="JPY" minimumFractionDigits=0}}';
|
|
162
|
+
template += raw('{{_price 1000.99 currency="JPY" minimumFractionDigits=0}}');
|
|
163
|
+
template += '{{_price 1000.99 currency="JPY" minimumFractionDigits=0}}';
|
|
157
164
|
|
|
158
165
|
// Price given through handlebars variable and with specific format attribute:
|
|
159
|
-
template += raw('{{_price myPrice currency="DKK"}}');
|
|
160
|
-
template += '{{_price myPrice currency="DKK"}}';
|
|
166
|
+
template += raw('{{_price myPrice currency="DKK"}}');
|
|
167
|
+
template += '{{_price myPrice currency="DKK"}}';
|
|
161
168
|
|
|
162
169
|
|
|
163
170
|
// Date representation
|
|
164
171
|
// ----------------------------------------
|
|
165
172
|
|
|
166
173
|
// Todays’ date as configured per language:
|
|
167
|
-
template += raw('{{_date}}');
|
|
168
|
-
template += '{{_date}}';
|
|
174
|
+
template += raw('{{_date}}');
|
|
175
|
+
template += '{{_date}}';
|
|
169
176
|
|
|
170
177
|
// Date given as date string:
|
|
171
|
-
template += raw('{{_date "2020-03-11T03:24:00"}}');
|
|
172
|
-
template += '{{_date "2020-03-11T03:24:00"}}';
|
|
178
|
+
template += raw('{{_date "2020-03-11T03:24:00"}}');
|
|
179
|
+
template += '{{_date "2020-03-11T03:24:00"}}';
|
|
173
180
|
|
|
174
181
|
// Date given in milliseconds since begin of unix epoch:
|
|
175
|
-
template += raw('{{_date 1583922952743}}');
|
|
176
|
-
template += '{{_date 1583922952743}}';
|
|
182
|
+
template += raw('{{_date 1583922952743}}');
|
|
183
|
+
template += '{{_date 1583922952743}}';
|
|
177
184
|
|
|
178
185
|
// Date given as javascript date parameter array:
|
|
179
|
-
template += raw('{{_date "[2012, 11, 20, 3, 0, 0]"}}');
|
|
180
|
-
template += '{{_date "[2012, 11, 20, 3, 0, 0]"}}';
|
|
186
|
+
template += raw('{{_date "[2012, 11, 20, 3, 0, 0]"}}');
|
|
187
|
+
template += '{{_date "[2012, 11, 20, 3, 0, 0]"}}';
|
|
181
188
|
|
|
182
189
|
// Todays’ date with specific format attributes:
|
|
183
|
-
template += raw('{{_date "today" year="2-digit" month="2-digit" day="2-digit"}}');
|
|
184
|
-
template += '{{_date "today" year="2-digit" month="2-digit" day="2-digit"}}';
|
|
190
|
+
template += raw('{{_date "today" year="2-digit" month="2-digit" day="2-digit"}}');
|
|
191
|
+
template += '{{_date "today" year="2-digit" month="2-digit" day="2-digit"}}';
|
|
185
192
|
|
|
186
193
|
// Date given through handlebars variable:
|
|
187
|
-
template += raw('{{_date myDate}}');
|
|
188
|
-
template += '{{_date myDate}}';
|
|
194
|
+
template += raw('{{_date myDate}}');
|
|
195
|
+
template += '{{_date myDate}}';
|
|
189
196
|
|
|
190
197
|
// Date formatted by custom configuration (subset "custom-year-only"):
|
|
191
|
-
template += raw('{{_date myDate format="custom-year-only"}}');
|
|
192
|
-
template += '{{_date myDate format="custom-year-only"}}';
|
|
198
|
+
template += raw('{{_date myDate format="custom-year-only"}}');
|
|
199
|
+
template += '{{_date myDate format="custom-year-only"}}';
|
|
193
200
|
|
|
194
201
|
// Date formatted by custom configuration (subset "custom-date-short"):
|
|
195
|
-
template += raw('{{_date myDate format="custom-date-short"}}');
|
|
196
|
-
template += '{{_date myDate format="custom-date-short"}}';
|
|
202
|
+
template += raw('{{_date myDate format="custom-date-short"}}');
|
|
203
|
+
template += '{{_date myDate format="custom-date-short"}}';
|
|
197
204
|
|
|
198
205
|
// Date formatted by custom configuration (subset "custom-date-short"):
|
|
199
|
-
template += raw('{{_date myDate format="custom-time"}}');
|
|
200
|
-
template += '{{_date myDate format="custom-time"}}';
|
|
206
|
+
template += raw('{{_date myDate format="custom-time"}}');
|
|
207
|
+
template += '{{_date myDate format="custom-time"}}';
|
|
201
208
|
|
|
202
209
|
// Relative date representation
|
|
203
210
|
// ----------------------------------------
|
|
204
211
|
|
|
212
|
+
// Date with positive time offset:
|
|
213
|
+
template += raw('{{_dateAdd "December 17, 1995 08:00:00" 24 unit="hour"}}');
|
|
214
|
+
template += '{{_dateAdd "December 17, 1995 08:00:00" 24 unit="hour"}}';
|
|
215
|
+
|
|
216
|
+
// Date with negative time offset:
|
|
217
|
+
template += raw('{{_dateAdd "December 17, 1995" -10 unit="day"}}');
|
|
218
|
+
template += '{{_dateAdd "December 17, 1995" -10 unit="day"}}';
|
|
219
|
+
|
|
220
|
+
// Relative difference between two dates:
|
|
221
|
+
template += raw('{{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}}');
|
|
222
|
+
template += '{{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}}';
|
|
223
|
+
|
|
224
|
+
// Relative difference between two dates with custom configuration (subset "date-rel-spec"):
|
|
225
|
+
template += raw('{{_dateDiff myDate "1995-12-17T00:00:00" format="date-rel-spec"}}');
|
|
226
|
+
template += '{{_dateDiff myDate "1995-12-17T00:00:00" format="date-rel-spec"}}';
|
|
227
|
+
|
|
205
228
|
// Relative date event in the future:
|
|
206
|
-
template += raw('{{_dateRel 7 unit="hour"}}');
|
|
207
|
-
template += '{{_dateRel 7 unit="hour"}}';
|
|
229
|
+
template += raw('{{_dateRel 7 unit="hour"}}');
|
|
230
|
+
template += '{{_dateRel 7 unit="hour"}}';
|
|
208
231
|
|
|
209
232
|
// Relative date event in the past:
|
|
210
|
-
template += raw('{{_dateRel -7 unit="hour"}}');
|
|
211
|
-
template += '{{_dateRel -7 unit="hour"}}';
|
|
212
|
-
|
|
213
|
-
// Date difference:
|
|
214
|
-
template += raw('{{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}}');
|
|
215
|
-
template += '{{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}}';
|
|
233
|
+
template += raw('{{_dateRel -7 unit="hour"}}');
|
|
234
|
+
template += '{{_dateRel -7 unit="hour"}}';
|
|
216
235
|
|
|
217
|
-
|
|
218
|
-
template += raw('{{_dateDiff mydate "1995-12-17T00:00:00" format="date-rel-spec"}}');
|
|
219
|
-
template += '{{_dateDiff mydate "1995-12-17T00:00:00" format="date-rel-spec"}}';
|
|
236
|
+
const compiled = Handlebars.compile(template);
|
|
220
237
|
|
|
238
|
+
i18next.changeLanguage('de'); // --> Test the changes by replacing 'de' with 'en'
|
|
221
239
|
|
|
222
|
-
const
|
|
223
|
-
i18next.changeLanguage('de'); // --> Test the changes by replacing 'de' with 'en'
|
|
224
|
-
const decoded = htmlEntities.decode(compiled(data));
|
|
240
|
+
const decoded = htmlEntities.decode(compiled(data));
|
|
225
241
|
|
|
226
|
-
console.log('\x1b[36m%s\x1b[0m', decoded);
|
|
242
|
+
console.log('\x1b[36m%s\x1b[0m', decoded);
|
|
@@ -86,14 +86,20 @@ HandlebarsI18n example output from TS:
|
|
|
86
86
|
// Relative date representation
|
|
87
87
|
// ----------------------------------------
|
|
88
88
|
|
|
89
|
-
//
|
|
90
|
-
{{
|
|
89
|
+
// Date with positive time offset:
|
|
90
|
+
{{_dateAdd "December 17, 1995 08:00:00" 24 unit="hour"}}
|
|
91
91
|
|
|
92
|
-
//
|
|
93
|
-
{{
|
|
92
|
+
// Date with negative time offset:
|
|
93
|
+
{{_dateAdd "December 17, 1995" -10 unit="day"}}
|
|
94
94
|
|
|
95
|
-
//
|
|
95
|
+
// Relative difference between two dates:
|
|
96
96
|
{{_dateDiff "1996-12-07T00:00:00" "1996-12-08T00:00:00" unit="day"}}
|
|
97
97
|
|
|
98
|
-
//
|
|
99
|
-
{{_dateDiff
|
|
98
|
+
// Relative difference between two dates with custom configuration (subset "date-rel-spec"):
|
|
99
|
+
{{_dateDiff myDate "1995-12-17T00:00:00" format="date-rel-spec"}}
|
|
100
|
+
|
|
101
|
+
// Relative date event in the future:
|
|
102
|
+
{{_dateRel 7 unit="hour"}}
|
|
103
|
+
|
|
104
|
+
// Relative date event in the past:
|
|
105
|
+
{{_dateRel -7 unit="hour"}}
|