handlebars-i18n 1.6.4 → 1.7.1
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/ci.yml +15 -15
- package/.github/workflows/coveralls.yml +44 -0
- package/LICENSE +2 -1
- package/dist/handlebars-i18n.d.ts +187 -3
- package/dist/handlebars-i18n.js +229 -95
- package/dist/handlebars-i18n.min.js +1 -1
- package/examples/browser-example/index.html +109 -86
- package/examples/node-example/simple-example.js +89 -35
- package/examples/typescript/index.ts +11 -8
- package/examples/typescript/test.hbs +25 -7
- package/package.json +14 -9
- package/readme.md +136 -38
- package/test/handlebars-i18n.test.js +623 -185
package/dist/handlebars-i18n.js
CHANGED
|
@@ -2,32 +2,12 @@
|
|
|
2
2
|
* handlebars-i18n.js
|
|
3
3
|
*
|
|
4
4
|
* @author: Florian Walzel
|
|
5
|
-
* @date:
|
|
5
|
+
* @date: 2024-05
|
|
6
6
|
*
|
|
7
7
|
* handlebars-i18n adds features for localization/
|
|
8
8
|
* internationalization to handlebars.js
|
|
9
9
|
*
|
|
10
|
-
* Copyright (c) 2020 Florian Walzel
|
|
11
|
-
*
|
|
12
|
-
* Permission is hereby granted, free of charge, to any person
|
|
13
|
-
* obtaininga copy of this software and associated documentation
|
|
14
|
-
* files (the "Software"), to deal in the Software without restriction,
|
|
15
|
-
* including without limitation the rights to use, copy, modify, merge,
|
|
16
|
-
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
17
|
-
* and to permit persons to whom the Software is furnished to do so,
|
|
18
|
-
* subject to the following conditions:
|
|
19
|
-
*
|
|
20
|
-
* The above copyright notice and this permission notice shall be
|
|
21
|
-
* included in all copies or substantial portions of the Software.
|
|
22
|
-
*
|
|
23
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
24
|
-
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
25
|
-
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
26
|
-
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
27
|
-
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
28
|
-
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
29
|
-
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
30
|
-
* THE SOFTWARE.
|
|
10
|
+
* Copyright (c) 2020-24 Florian Walzel, MIT License
|
|
31
11
|
*
|
|
32
12
|
*********************************************************************/
|
|
33
13
|
|
|
@@ -36,10 +16,15 @@
|
|
|
36
16
|
if (typeof exports === 'object' && typeof module === 'object') {
|
|
37
17
|
const Handlebars = require('handlebars'),
|
|
38
18
|
i18next = require('i18next'),
|
|
39
|
-
Intl = require('intl')
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
19
|
+
Intl = require('intl'),
|
|
20
|
+
RelativeTimeFormat = require('relative-time-format');
|
|
21
|
+
module.exports = factory(
|
|
22
|
+
Handlebars,
|
|
23
|
+
i18next,
|
|
24
|
+
Intl,
|
|
25
|
+
RelativeTimeFormat,
|
|
26
|
+
process?.env?.NODE_ENV === 'TEST');
|
|
27
|
+
} else if (typeof define === 'function' && define.amd)
|
|
43
28
|
define(['Handlebars', 'i18next', 'Intl'], factory);
|
|
44
29
|
else if (typeof root.Handlebars === 'object'
|
|
45
30
|
&& typeof root.i18next === 'object'
|
|
@@ -50,15 +35,24 @@
|
|
|
50
35
|
return false;
|
|
51
36
|
}
|
|
52
37
|
|
|
53
|
-
})(this, function (handlebars, i18next, Intl) {
|
|
38
|
+
})(this, function (handlebars, i18next, Intl, RelativeTimePolyfill, isTest) {
|
|
54
39
|
|
|
55
40
|
'use strict';
|
|
56
41
|
|
|
57
|
-
|
|
42
|
+
// the object to store
|
|
43
|
+
// configurations for specific languages (standard)
|
|
44
|
+
// and custom settings.
|
|
45
|
+
const defaultConf = {
|
|
58
46
|
DateTimeFormat: {
|
|
59
47
|
standard: {},
|
|
60
48
|
custom: {}
|
|
61
49
|
},
|
|
50
|
+
RelativeTimeFormat: {
|
|
51
|
+
standard: {
|
|
52
|
+
all: {unit: 'hours'}
|
|
53
|
+
},
|
|
54
|
+
custom: {}
|
|
55
|
+
},
|
|
62
56
|
NumberFormat: {
|
|
63
57
|
standard: {},
|
|
64
58
|
custom: {}
|
|
@@ -71,8 +65,12 @@
|
|
|
71
65
|
}
|
|
72
66
|
};
|
|
73
67
|
|
|
74
|
-
// make a copy of default object
|
|
75
|
-
|
|
68
|
+
// make a copy of default object to hold (optional)
|
|
69
|
+
// custom configuration to be defined by the user
|
|
70
|
+
let optionsConf = JSON.parse(JSON.stringify(defaultConf));
|
|
71
|
+
|
|
72
|
+
// object for holding polyfill languages in node environment
|
|
73
|
+
const polyfillLangs = {};
|
|
76
74
|
|
|
77
75
|
|
|
78
76
|
/*************************************
|
|
@@ -87,21 +85,22 @@
|
|
|
87
85
|
* @private
|
|
88
86
|
*/
|
|
89
87
|
function __applyToConstructor(constructor, argArray) {
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
let args = [null].concat(argArray);
|
|
89
|
+
let factoryFunction = constructor.bind.apply(constructor, args);
|
|
92
90
|
return new factoryFunction();
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
/**
|
|
96
94
|
*
|
|
97
95
|
* @param hndlbrsOpts
|
|
96
|
+
* @param lang
|
|
98
97
|
* @param OCFormat
|
|
99
98
|
* @returns {*}
|
|
100
99
|
* @private
|
|
101
100
|
*/
|
|
102
101
|
function __configLookup(hndlbrsOpts, lang, OCFormat) {
|
|
103
102
|
|
|
104
|
-
// check if an options object with
|
|
103
|
+
// check if an options object with property hash exists, and holds some content
|
|
105
104
|
if (typeof hndlbrsOpts === 'object'
|
|
106
105
|
&& typeof hndlbrsOpts.hash === 'object'
|
|
107
106
|
&& Object.keys(hndlbrsOpts.hash).length > 0) {
|
|
@@ -113,19 +112,19 @@
|
|
|
113
112
|
if (typeof oh.format === 'undefined') {
|
|
114
113
|
return oh;
|
|
115
114
|
}
|
|
116
|
-
// when custom format is given, check if the configuration was set
|
|
115
|
+
// when custom format is given, check if the configuration was set ...
|
|
117
116
|
else if (typeof OCFormat.custom[oh.format] !== 'undefined'
|
|
118
117
|
&& typeof OCFormat.custom[oh.format][lang] !== 'undefined') {
|
|
119
118
|
return OCFormat.custom[oh.format][lang];
|
|
120
119
|
}
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
// when no options for custom formats given, first check whether
|
|
122
|
+
// ... when no options for custom formats given, first check whether
|
|
124
123
|
// the specific language has a generic definition
|
|
125
124
|
if (typeof OCFormat.standard[lang] !== 'undefined')
|
|
126
125
|
return OCFormat.standard[lang];
|
|
127
126
|
|
|
128
|
-
//
|
|
127
|
+
// ... then check if a universal format definition for all languages exists
|
|
129
128
|
if (typeof OCFormat.standard.all !== 'undefined')
|
|
130
129
|
return OCFormat.standard.all;
|
|
131
130
|
|
|
@@ -139,6 +138,7 @@
|
|
|
139
138
|
* @param lngShortcode
|
|
140
139
|
* @param typeOfFormat
|
|
141
140
|
* @param options
|
|
141
|
+
* @param customFormat
|
|
142
142
|
* @returns {boolean}
|
|
143
143
|
* @private
|
|
144
144
|
*/
|
|
@@ -150,12 +150,10 @@
|
|
|
150
150
|
return false;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
if (
|
|
154
|
-
&& typeOfFormat !== 'NumberFormat'
|
|
155
|
-
&& typeOfFormat !== 'PriceFormat') {
|
|
153
|
+
if (!['DateTimeFormat', 'RelativeTimeFormat', 'NumberFormat', 'PriceFormat'].includes(typeOfFormat)) {
|
|
156
154
|
console.error('@ handlebars-i18n.configure(): Invalid argument <' + typeOfFormat + '>. ' +
|
|
157
155
|
'Second argument must be a string with the options key. ' +
|
|
158
|
-
'Use either "DateTimeFormat", "NumberFormat" or "PriceFormat".');
|
|
156
|
+
'Use either "DateTimeFormat", "RelativeTimeFormat", "NumberFormat", or "PriceFormat".');
|
|
159
157
|
return false;
|
|
160
158
|
}
|
|
161
159
|
|
|
@@ -178,27 +176,127 @@
|
|
|
178
176
|
/**
|
|
179
177
|
*
|
|
180
178
|
* @param lang
|
|
181
|
-
* @param
|
|
179
|
+
* @param formatType
|
|
182
180
|
* @param options
|
|
183
181
|
* @param customFormat
|
|
184
182
|
* @returns {boolean}
|
|
185
183
|
* @private
|
|
186
184
|
*/
|
|
187
|
-
function __setArgs(lang,
|
|
185
|
+
function __setArgs(lang, formatType, options, customFormat) {
|
|
188
186
|
|
|
189
187
|
if (typeof customFormat !== 'undefined' && customFormat !== null) {
|
|
190
188
|
// create object node with name of the configuration if not already existing
|
|
191
|
-
if (typeof optionsConf[
|
|
192
|
-
optionsConf[
|
|
189
|
+
if (typeof optionsConf[formatType].custom[customFormat] === 'undefined')
|
|
190
|
+
optionsConf[formatType].custom[customFormat] = {};
|
|
193
191
|
|
|
194
|
-
optionsConf[
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
optionsConf[typeOfFormat].standard[lang] = options;
|
|
192
|
+
optionsConf[formatType].custom[customFormat][lang] = options;
|
|
193
|
+
} else
|
|
194
|
+
optionsConf[formatType].standard[lang] = options;
|
|
198
195
|
|
|
199
196
|
return true;
|
|
200
197
|
}
|
|
201
198
|
|
|
199
|
+
/**
|
|
200
|
+
*
|
|
201
|
+
* @param input
|
|
202
|
+
* @returns {boolean}
|
|
203
|
+
* @private
|
|
204
|
+
*/
|
|
205
|
+
function __isNumOrString(input) {
|
|
206
|
+
return typeof input === 'number' || (typeof input === 'string' && input !== '')
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
*
|
|
211
|
+
* @param dateInput
|
|
212
|
+
* @returns {Date}
|
|
213
|
+
* @private
|
|
214
|
+
*/
|
|
215
|
+
function __createDateObj(dateInput) {
|
|
216
|
+
|
|
217
|
+
let date;
|
|
218
|
+
|
|
219
|
+
if (typeof dateInput === 'number') {
|
|
220
|
+
// input as milliseconds since unix epoch, like: 1583922952743
|
|
221
|
+
date = new Date(dateInput);
|
|
222
|
+
} else if (typeof dateInput === 'string') {
|
|
223
|
+
|
|
224
|
+
if (dateInput.charAt(0) === '[' && dateInput.slice(-1) === ']') {
|
|
225
|
+
// input as array represented as string such as "[2020, 11]"
|
|
226
|
+
dateInput = dateInput.substring(1, dateInput.length - 1).replace(/ /g, '');
|
|
227
|
+
let dateArr = dateInput.split(',');
|
|
228
|
+
let dateFactory = __applyToConstructor.bind(null, Date);
|
|
229
|
+
date = dateFactory(dateArr);
|
|
230
|
+
} else if (dateInput.toLowerCase() === 'now' || dateInput.toLowerCase() === 'today') {
|
|
231
|
+
// input as word "now" or "today"
|
|
232
|
+
date = new Date();
|
|
233
|
+
} else {
|
|
234
|
+
// input as date string such as "1995-12-17T03:24:00"
|
|
235
|
+
date = new Date(dateInput);
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
// fallback: today’s date
|
|
239
|
+
date = new Date();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return date;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
*
|
|
247
|
+
* @param lang
|
|
248
|
+
* @param opts
|
|
249
|
+
* @returns {Intl.RelativeTimeFormat|*}
|
|
250
|
+
* @private
|
|
251
|
+
*/
|
|
252
|
+
function __getRelDateFormatPolyfill(lang, opts) {
|
|
253
|
+
if (typeof Intl.RelativeTimeFormat === 'function')
|
|
254
|
+
return new Intl.RelativeTimeFormat(lang, opts);
|
|
255
|
+
else {
|
|
256
|
+
if (typeof polyfillLangs[lang] === 'undefined') {
|
|
257
|
+
try {
|
|
258
|
+
polyfillLangs[lang] = require(`relative-time-format/locale/${lang}`);
|
|
259
|
+
} catch (e) {
|
|
260
|
+
console.error(e);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
RelativeTimePolyfill.addLocale(polyfillLangs[lang]);
|
|
264
|
+
return new RelativeTimePolyfill(lang, opts);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
*
|
|
270
|
+
* @param diff
|
|
271
|
+
* @param unit
|
|
272
|
+
* @returns {number}
|
|
273
|
+
* @private
|
|
274
|
+
*/
|
|
275
|
+
function __getDateDiff(diff, unit) {
|
|
276
|
+
|
|
277
|
+
const divisions = {
|
|
278
|
+
second: 1e3,
|
|
279
|
+
seconds: 1e3,
|
|
280
|
+
minute: 6e4,
|
|
281
|
+
minutes: 6e4,
|
|
282
|
+
hour: 3.6e6,
|
|
283
|
+
hours: 3.6e6,
|
|
284
|
+
day: 8.64e7,
|
|
285
|
+
days: 8.64e7,
|
|
286
|
+
week: 6.048e8,
|
|
287
|
+
weeks: 6.048e8,
|
|
288
|
+
month: 2.629746e9,
|
|
289
|
+
months: 2.629746e9,
|
|
290
|
+
quarter: 78894e5,
|
|
291
|
+
quarters: 78894e5,
|
|
292
|
+
year: 3.15576e10,
|
|
293
|
+
years: 3.15576e10,
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
unit = unit || 'hour';
|
|
297
|
+
return Math.trunc(diff / divisions[unit]);
|
|
298
|
+
}
|
|
299
|
+
|
|
202
300
|
|
|
203
301
|
/*************************************
|
|
204
302
|
* PUBLIC INTERFACE
|
|
@@ -213,11 +311,11 @@
|
|
|
213
311
|
* @param typeOfFormat : string - DateTimeFormat | NumberFormat | PriceFormat
|
|
214
312
|
* @param options : object - the options object
|
|
215
313
|
*/
|
|
216
|
-
configure: function (langOrArr, typeOfFormat, options,
|
|
314
|
+
configure: function (langOrArr, typeOfFormat, options, customFormatName) {
|
|
217
315
|
|
|
218
316
|
if (typeof langOrArr !== 'string' && !Array.isArray(langOrArr)) {
|
|
219
317
|
console.error('@ handlebars-i18n.configure(): Invalid argument <' + langOrArr + '> ' +
|
|
220
|
-
'First argument must be a string with language code such as "en" or an array with parameters.');
|
|
318
|
+
'First argument must be a string with language code such as "en" or an array with language parameters.');
|
|
221
319
|
return false;
|
|
222
320
|
}
|
|
223
321
|
|
|
@@ -233,10 +331,9 @@
|
|
|
233
331
|
else
|
|
234
332
|
return false;
|
|
235
333
|
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
__setArgs(langOrArr, typeOfFormat, options, customFormatname);
|
|
334
|
+
} else {
|
|
335
|
+
if (__validateArgs(langOrArr, typeOfFormat, options, customFormatName))
|
|
336
|
+
__setArgs(langOrArr, typeOfFormat, options, customFormatName);
|
|
240
337
|
else
|
|
241
338
|
return false;
|
|
242
339
|
}
|
|
@@ -245,7 +342,7 @@
|
|
|
245
342
|
},
|
|
246
343
|
|
|
247
344
|
/**
|
|
248
|
-
* resets the configuration to default state like it
|
|
345
|
+
* resets the configuration to default state like it was before configure() has been called
|
|
249
346
|
*/
|
|
250
347
|
reset: function () {
|
|
251
348
|
optionsConf = JSON.parse(JSON.stringify(defaultConf));
|
|
@@ -269,14 +366,14 @@
|
|
|
269
366
|
handlebars = overrideHndlbrs;
|
|
270
367
|
else if (typeof overrideHndlbrs !== 'undefined' && overrideHndlbrs !== null)
|
|
271
368
|
console.error('@ handlebars-i18n.init(): Invalid Argument [1] given for overrideHndlbrs. ' +
|
|
272
|
-
'Argument must be the Handlebars
|
|
369
|
+
'Argument must be the Handlebars object. Using generic Handlebars object instead.');
|
|
273
370
|
|
|
274
371
|
if (typeof overrideI18n === 'object' && overrideI18n !== null)
|
|
275
372
|
i18next = overrideI18n;
|
|
276
373
|
|
|
277
374
|
else if (typeof overrideI18n !== 'undefined' && overrideI18n !== null)
|
|
278
375
|
console.error('@ handlebars-i18n.init(): Invalid Argument [2] given for overrideI18n. ' +
|
|
279
|
-
'Argument must be the i18next
|
|
376
|
+
'Argument must be the i18next object. Using generic i18next object on module level instead.');
|
|
280
377
|
|
|
281
378
|
handlebars.registerHelper('__',
|
|
282
379
|
/**
|
|
@@ -289,7 +386,7 @@
|
|
|
289
386
|
* @returns {*}
|
|
290
387
|
*/
|
|
291
388
|
function (str, attributes) {
|
|
292
|
-
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));
|
|
293
390
|
}
|
|
294
391
|
);
|
|
295
392
|
handlebars.registerHelper('_locale',
|
|
@@ -316,7 +413,7 @@
|
|
|
316
413
|
);
|
|
317
414
|
handlebars.registerHelper('_date',
|
|
318
415
|
/**
|
|
319
|
-
* formats a
|
|
416
|
+
* formats a date according to the give internationalization options
|
|
320
417
|
*
|
|
321
418
|
* allows multiple input forms:
|
|
322
419
|
* {{_date}}
|
|
@@ -341,40 +438,63 @@
|
|
|
341
438
|
* @param options
|
|
342
439
|
*/
|
|
343
440
|
function (dateInput, options) {
|
|
441
|
+
const date = __createDateObj(dateInput);
|
|
442
|
+
const opts = __configLookup(options, i18next.language, optionsConf.DateTimeFormat);
|
|
443
|
+
const dateFormat = new Intl.DateTimeFormat(i18next.language, opts);
|
|
444
|
+
return dateFormat.format(date);
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
handlebars.registerHelper('_dateRel',
|
|
448
|
+
/**
|
|
449
|
+
* returns a relative date formatted according the options
|
|
450
|
+
* a positive dateValue will address a future date, like 'in 1 day'
|
|
451
|
+
* a negative dateValue will relate to a past date, like '1 day ago'
|
|
452
|
+
*
|
|
453
|
+
* _dateRel uses a polyfill in node environment because node’s Intl
|
|
454
|
+
* does not support relative date formats.
|
|
455
|
+
*
|
|
456
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat
|
|
457
|
+
* @link https://www.npmjs.com/package/relative-time-format
|
|
458
|
+
*
|
|
459
|
+
* @param dateValue
|
|
460
|
+
* @param options
|
|
461
|
+
* @returns {string}
|
|
462
|
+
*/
|
|
463
|
+
function (dateValue, options) {
|
|
464
|
+
const relDate = parseInt(dateValue);
|
|
465
|
+
const opts = __configLookup(options, i18next.language, optionsConf.RelativeTimeFormat);
|
|
466
|
+
const relDateFormat = __getRelDateFormatPolyfill(i18next.language, opts);
|
|
467
|
+
return relDateFormat.format(relDate, opts.unit);
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
handlebars.registerHelper('_dateDiff',
|
|
471
|
+
/**
|
|
472
|
+
*
|
|
473
|
+
* @param dateInputA
|
|
474
|
+
* @param dateInputB
|
|
475
|
+
* @param options
|
|
476
|
+
* @returns {string|null}
|
|
477
|
+
*/
|
|
478
|
+
function (dateInputA, dateInputB, options) {
|
|
344
479
|
|
|
345
|
-
|
|
480
|
+
let dateDiff;
|
|
481
|
+
let opts = __configLookup(options, i18next.language, optionsConf.RelativeTimeFormat);
|
|
346
482
|
|
|
347
|
-
if (
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
else if (typeof dateInput === 'string') {
|
|
352
|
-
|
|
353
|
-
if (dateInput.charAt(0) === '[' && dateInput.slice(-1) === ']') {
|
|
354
|
-
// input as array represented as string such as "[2020, 11]"
|
|
355
|
-
dateInput = dateInput.substring(1, dateInput.length - 1).replace(/ /g, '');
|
|
356
|
-
var dateArr = dateInput.split(',');
|
|
357
|
-
var dateFactory = __applyToConstructor.bind(null, Date);
|
|
358
|
-
date = dateFactory(dateArr);
|
|
359
|
-
}
|
|
360
|
-
else if (dateInput.toLowerCase() === 'now' || dateInput.toLowerCase() === 'today') {
|
|
361
|
-
// input as word "now" or "today"
|
|
362
|
-
date = new Date();
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
// input as date string such as "1995-12-17T03:24:00"
|
|
366
|
-
date = new Date(dateInput);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
// fallback: today's date
|
|
371
|
-
date = new Date();
|
|
483
|
+
if (!__isNumOrString(dateInputA)) {
|
|
484
|
+
console.error('@ handlebars-i18n: invalid first argument dateInputA was given for _dateDiff.');
|
|
485
|
+
return null;
|
|
372
486
|
}
|
|
373
487
|
|
|
374
|
-
|
|
488
|
+
dateInputB = dateInputB || 'now';
|
|
375
489
|
|
|
376
|
-
|
|
377
|
-
|
|
490
|
+
let dateA = __createDateObj(dateInputA);
|
|
491
|
+
let dateB = __createDateObj(dateInputB);
|
|
492
|
+
|
|
493
|
+
dateDiff = dateA - dateB;
|
|
494
|
+
|
|
495
|
+
const relDate = __getDateDiff(dateDiff, opts.unit);
|
|
496
|
+
const relDateFormat = __getRelDateFormatPolyfill(i18next.language, opts);
|
|
497
|
+
return relDateFormat.format(relDate, opts.unit);
|
|
378
498
|
}
|
|
379
499
|
);
|
|
380
500
|
handlebars.registerHelper('_num',
|
|
@@ -392,7 +512,7 @@
|
|
|
392
512
|
*/
|
|
393
513
|
function (number, options) {
|
|
394
514
|
|
|
395
|
-
|
|
515
|
+
let opts = __configLookup(options, i18next.language, optionsConf.NumberFormat);
|
|
396
516
|
|
|
397
517
|
const priceFormat = new Intl.NumberFormat(i18next.language, opts);
|
|
398
518
|
return priceFormat.format(number);
|
|
@@ -413,7 +533,7 @@
|
|
|
413
533
|
*/
|
|
414
534
|
function (price, options) {
|
|
415
535
|
|
|
416
|
-
|
|
536
|
+
let opts = __configLookup(options, i18next.language, optionsConf.PriceFormat);
|
|
417
537
|
|
|
418
538
|
// for convenience automatically add the object parameter style:'currency' if not given
|
|
419
539
|
if (typeof opts['style'] !== 'string' && typeof opts['currency'] === 'string')
|
|
@@ -425,9 +545,23 @@
|
|
|
425
545
|
);
|
|
426
546
|
|
|
427
547
|
return handlebars;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
|
|
548
|
+
},
|
|
433
549
|
|
|
550
|
+
/**
|
|
551
|
+
* we conditionally export the helpers to be able to test against them;
|
|
552
|
+
* in production they are not exported.
|
|
553
|
+
*/
|
|
554
|
+
...(isTest) && {
|
|
555
|
+
private: {
|
|
556
|
+
applyToConstructor: __applyToConstructor,
|
|
557
|
+
configLookup: __configLookup,
|
|
558
|
+
validateArgs: __validateArgs,
|
|
559
|
+
setArgs: __setArgs,
|
|
560
|
+
isNumOrString: __isNumOrString,
|
|
561
|
+
createDateObj: __createDateObj,
|
|
562
|
+
getRelDateFormatPolyfill: __getRelDateFormatPolyfill,
|
|
563
|
+
getDateDiff: __getDateDiff
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
}
|
|
567
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,r){if("object"==typeof exports&&"object"==typeof module){
|
|
1
|
+
!function(e,r){if("object"==typeof exports&&"object"==typeof module){const e=require("handlebars"),t=require("i18next"),n=require("intl"),a=require("relative-time-format");module.exports=r(e,t,n,a,"TEST"===process?.env?.NODE_ENV)}else if("function"==typeof define&&define.amd)define(["Handlebars","i18next","Intl"],r);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=r(e.Handlebars,e.i18next,e.Intl)}}(this,(function(e,r,t,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 u={};function s(e,r){let t=[null].concat(r);return new(e.bind.apply(e,t))}function l(e,r,t){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!==t.custom[n.format]&&void 0!==t.custom[n.format][r])return t.custom[n.format][r]}return void 0!==t.standard[r]?t.standard[r]:void 0!==t.standard.all?t.standard.all:{}}function c(e,r,t,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(r)?"object"!=typeof t?(console.error("@ handlebars-i18n.configure(): Invalid argument <"+t+"> 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 <"+r+'>. Second argument must be a string with the options key. Use either "DateTimeFormat", "RelativeTimeFormat", "NumberFormat", or "PriceFormat".'),!1)}function m(e,r,t,n){return null!=n?(void 0===i[r].custom[n]&&(i[r].custom[n]={}),i[r].custom[n][e]=t):i[r].standard[e]=t,!0}function f(e){return"number"==typeof e||"string"==typeof e&&""!==e}function g(e){let r;if("number"==typeof e)r=new Date(e);else if("string"==typeof e)if("["===e.charAt(0)&&"]"===e.slice(-1)){let t=(e=e.substring(1,e.length-1).replace(/ /g,"")).split(",");r=s.bind(null,Date)(t)}else r="now"===e.toLowerCase()||"today"===e.toLowerCase()?new Date:new Date(e);else r=new Date;return r}function d(e,r){if("function"==typeof t.RelativeTimeFormat)return new t.RelativeTimeFormat(e,r);if(void 0===u[e])try{u[e]=require(`relative-time-format/locale/${e}`)}catch(e){console.error(e)}return n.addLocale(u[e]),new n(e,r)}function b(e,r){return r=r||"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}[r])}return{configure:function(e,r,t,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,r,t,n))return!1;m(e,r,t,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?r=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(t,n){return new e.SafeString(void 0!==r?r.t(t,n.hash):t)})),e.registerHelper("_locale",(function(){return r.language})),e.registerHelper("localeIs",(function(e){return r.language===e})),e.registerHelper("_date",(function(e,n){const a=g(e),o=l(n,r.language,i.DateTimeFormat);return new t.DateTimeFormat(r.language,o).format(a)})),e.registerHelper("_dateRel",(function(e,t){const n=parseInt(e),a=l(t,r.language,i.RelativeTimeFormat);return d(r.language,a).format(n,a.unit)})),e.registerHelper("_dateDiff",(function(e,t,n){let a,o=l(n,r.language,i.RelativeTimeFormat);if(!f(e))return console.error("@ handlebars-i18n: invalid first argument dateInputA was given for _dateDiff."),null;t=t||"now",a=g(e)-g(t);const u=b(a,o.unit);return d(r.language,o).format(u,o.unit)})),e.registerHelper("_num",(function(e,n){let a=l(n,r.language,i.NumberFormat);return new t.NumberFormat(r.language,a).format(e)})),e.registerHelper("_price",(function(e,n){let a=l(n,r.language,i.PriceFormat);"string"!=typeof a.style&&"string"==typeof a.currency&&(a.style="currency");return new t.NumberFormat(r.language,a).format(e)})),e},...a&&{private:{applyToConstructor:s,configLookup:l,validateArgs:c,setArgs:m,isNumOrString:f,createDateObj:g,getRelDateFormatPolyfill:d,getDateDiff:b}}}}));
|