handlebars-i18n 1.6.3 → 1.7.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/ci.yml +15 -15
- package/LICENSE +2 -1
- package/dist/handlebars-i18n.d.ts +187 -3
- package/dist/handlebars-i18n.js +229 -88
- 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 +11 -8
- package/readme.md +150 -45
- package/test/handlebars-i18n.test.js +467 -53
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,8 +16,14 @@
|
|
|
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
|
-
|
|
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');
|
|
41
27
|
}
|
|
42
28
|
else if (typeof define === 'function' && define.amd)
|
|
43
29
|
define(['Handlebars', 'i18next', 'Intl'], factory);
|
|
@@ -50,15 +36,24 @@
|
|
|
50
36
|
return false;
|
|
51
37
|
}
|
|
52
38
|
|
|
53
|
-
})(this, function (handlebars, i18next, Intl) {
|
|
39
|
+
})(this, function (handlebars, i18next, Intl, RelativeTimePolyfill, isTest) {
|
|
54
40
|
|
|
55
41
|
'use strict';
|
|
56
42
|
|
|
57
|
-
|
|
43
|
+
// the object to store
|
|
44
|
+
// configurations for specific languages (standard)
|
|
45
|
+
// and custom settings.
|
|
46
|
+
const defaultConf = {
|
|
58
47
|
DateTimeFormat: {
|
|
59
48
|
standard: {},
|
|
60
49
|
custom: {}
|
|
61
50
|
},
|
|
51
|
+
RelativeTimeFormat: {
|
|
52
|
+
standard: {
|
|
53
|
+
all: {unit: 'hours'}
|
|
54
|
+
},
|
|
55
|
+
custom: {}
|
|
56
|
+
},
|
|
62
57
|
NumberFormat: {
|
|
63
58
|
standard: {},
|
|
64
59
|
custom: {}
|
|
@@ -71,8 +66,12 @@
|
|
|
71
66
|
}
|
|
72
67
|
};
|
|
73
68
|
|
|
74
|
-
// make a copy of default object
|
|
75
|
-
|
|
69
|
+
// make a copy of default object to hold (optional)
|
|
70
|
+
// custom configuration to be defined by the user
|
|
71
|
+
let optionsConf = JSON.parse(JSON.stringify(defaultConf));
|
|
72
|
+
|
|
73
|
+
// object for holding polyfill languages in node environment
|
|
74
|
+
const polyfillLangs = {};
|
|
76
75
|
|
|
77
76
|
|
|
78
77
|
/*************************************
|
|
@@ -87,21 +86,22 @@
|
|
|
87
86
|
* @private
|
|
88
87
|
*/
|
|
89
88
|
function __applyToConstructor(constructor, argArray) {
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
let args = [null].concat(argArray);
|
|
90
|
+
let factoryFunction = constructor.bind.apply(constructor, args);
|
|
92
91
|
return new factoryFunction();
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
/**
|
|
96
95
|
*
|
|
97
96
|
* @param hndlbrsOpts
|
|
97
|
+
* @param lang
|
|
98
98
|
* @param OCFormat
|
|
99
99
|
* @returns {*}
|
|
100
100
|
* @private
|
|
101
101
|
*/
|
|
102
102
|
function __configLookup(hndlbrsOpts, lang, OCFormat) {
|
|
103
103
|
|
|
104
|
-
// check if an options object with
|
|
104
|
+
// check if an options object with property hash exists, and holds some content
|
|
105
105
|
if (typeof hndlbrsOpts === 'object'
|
|
106
106
|
&& typeof hndlbrsOpts.hash === 'object'
|
|
107
107
|
&& Object.keys(hndlbrsOpts.hash).length > 0) {
|
|
@@ -113,19 +113,19 @@
|
|
|
113
113
|
if (typeof oh.format === 'undefined') {
|
|
114
114
|
return oh;
|
|
115
115
|
}
|
|
116
|
-
// when custom format is given, check if the configuration was set
|
|
116
|
+
// when custom format is given, check if the configuration was set ...
|
|
117
117
|
else if (typeof OCFormat.custom[oh.format] !== 'undefined'
|
|
118
118
|
&& typeof OCFormat.custom[oh.format][lang] !== 'undefined') {
|
|
119
119
|
return OCFormat.custom[oh.format][lang];
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
// when no options for custom formats given, first check whether
|
|
123
|
+
// ... when no options for custom formats given, first check whether
|
|
124
124
|
// the specific language has a generic definition
|
|
125
125
|
if (typeof OCFormat.standard[lang] !== 'undefined')
|
|
126
126
|
return OCFormat.standard[lang];
|
|
127
127
|
|
|
128
|
-
//
|
|
128
|
+
// ... then check if a universal format definition for all languages exists
|
|
129
129
|
if (typeof OCFormat.standard.all !== 'undefined')
|
|
130
130
|
return OCFormat.standard.all;
|
|
131
131
|
|
|
@@ -139,6 +139,7 @@
|
|
|
139
139
|
* @param lngShortcode
|
|
140
140
|
* @param typeOfFormat
|
|
141
141
|
* @param options
|
|
142
|
+
* @param customFormat
|
|
142
143
|
* @returns {boolean}
|
|
143
144
|
* @private
|
|
144
145
|
*/
|
|
@@ -150,12 +151,10 @@
|
|
|
150
151
|
return false;
|
|
151
152
|
}
|
|
152
153
|
|
|
153
|
-
if (
|
|
154
|
-
&& typeOfFormat !== 'NumberFormat'
|
|
155
|
-
&& typeOfFormat !== 'PriceFormat') {
|
|
154
|
+
if (! ['DateTimeFormat', 'RelativeTimeFormat', 'NumberFormat', 'PriceFormat'].includes(typeOfFormat)) {
|
|
156
155
|
console.error('@ handlebars-i18n.configure(): Invalid argument <' + typeOfFormat + '>. ' +
|
|
157
156
|
'Second argument must be a string with the options key. ' +
|
|
158
|
-
'Use either "DateTimeFormat", "NumberFormat" or "PriceFormat".');
|
|
157
|
+
'Use either "DateTimeFormat", "RelativeTimeFormat", "NumberFormat", or "PriceFormat".');
|
|
159
158
|
return false;
|
|
160
159
|
}
|
|
161
160
|
|
|
@@ -178,27 +177,132 @@
|
|
|
178
177
|
/**
|
|
179
178
|
*
|
|
180
179
|
* @param lang
|
|
181
|
-
* @param
|
|
180
|
+
* @param formatType
|
|
182
181
|
* @param options
|
|
183
182
|
* @param customFormat
|
|
184
183
|
* @returns {boolean}
|
|
185
184
|
* @private
|
|
186
185
|
*/
|
|
187
|
-
function __setArgs(lang,
|
|
186
|
+
function __setArgs(lang, formatType, options, customFormat) {
|
|
188
187
|
|
|
189
188
|
if (typeof customFormat !== 'undefined' && customFormat !== null) {
|
|
190
189
|
// create object node with name of the configuration if not already existing
|
|
191
|
-
if (typeof optionsConf[
|
|
192
|
-
optionsConf[
|
|
190
|
+
if (typeof optionsConf[formatType].custom[customFormat] === 'undefined')
|
|
191
|
+
optionsConf[formatType].custom[customFormat] = {};
|
|
193
192
|
|
|
194
|
-
optionsConf[
|
|
193
|
+
optionsConf[formatType].custom[customFormat][lang] = options;
|
|
195
194
|
}
|
|
196
195
|
else
|
|
197
|
-
optionsConf[
|
|
196
|
+
optionsConf[formatType].standard[lang] = options;
|
|
198
197
|
|
|
199
198
|
return true;
|
|
200
199
|
}
|
|
201
200
|
|
|
201
|
+
/**
|
|
202
|
+
*
|
|
203
|
+
* @param input
|
|
204
|
+
* @returns {boolean}
|
|
205
|
+
* @private
|
|
206
|
+
*/
|
|
207
|
+
function __isNumOrString(input) {
|
|
208
|
+
return typeof input === 'number' || (typeof input === 'string' && input !== '')
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
*
|
|
213
|
+
* @param dateInput
|
|
214
|
+
* @returns {Date}
|
|
215
|
+
* @private
|
|
216
|
+
*/
|
|
217
|
+
function __createDateObj(dateInput) {
|
|
218
|
+
|
|
219
|
+
let date;
|
|
220
|
+
|
|
221
|
+
if (typeof dateInput === 'number') {
|
|
222
|
+
// input as milliseconds since unix epoch, like: 1583922952743
|
|
223
|
+
date = new Date(dateInput);
|
|
224
|
+
}
|
|
225
|
+
else if (typeof dateInput === 'string') {
|
|
226
|
+
|
|
227
|
+
if (dateInput.charAt(0) === '[' && dateInput.slice(-1) === ']') {
|
|
228
|
+
// input as array represented as string such as "[2020, 11]"
|
|
229
|
+
dateInput = dateInput.substring(1, dateInput.length - 1).replace(/ /g, '');
|
|
230
|
+
let dateArr = dateInput.split(',');
|
|
231
|
+
let dateFactory = __applyToConstructor.bind(null, Date);
|
|
232
|
+
date = dateFactory(dateArr);
|
|
233
|
+
}
|
|
234
|
+
else if (dateInput.toLowerCase() === 'now' || dateInput.toLowerCase() === 'today') {
|
|
235
|
+
// input as word "now" or "today"
|
|
236
|
+
date = new Date();
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// input as date string such as "1995-12-17T03:24:00"
|
|
240
|
+
date = new Date(dateInput);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
// fallback: today’s date
|
|
245
|
+
date = new Date();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return date;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
*
|
|
253
|
+
* @param lang
|
|
254
|
+
* @param opts
|
|
255
|
+
* @returns {Intl.RelativeTimeFormat|*}
|
|
256
|
+
* @private
|
|
257
|
+
*/
|
|
258
|
+
function __getRelDateFormatPolyfill(lang, opts) {
|
|
259
|
+
if (typeof Intl.RelativeTimeFormat === 'function')
|
|
260
|
+
return new Intl.RelativeTimeFormat(lang, opts);
|
|
261
|
+
else {
|
|
262
|
+
if (typeof polyfillLangs[lang] === 'undefined') {
|
|
263
|
+
try {
|
|
264
|
+
polyfillLangs[lang] = require(`relative-time-format/locale/${lang}`);
|
|
265
|
+
} catch (e) {
|
|
266
|
+
console.error(e);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
RelativeTimePolyfill.addLocale(polyfillLangs[lang]);
|
|
270
|
+
return new RelativeTimePolyfill(lang, opts);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
*
|
|
276
|
+
* @param diff
|
|
277
|
+
* @param unit
|
|
278
|
+
* @returns {number}
|
|
279
|
+
* @private
|
|
280
|
+
*/
|
|
281
|
+
function __getDateDiff(diff, unit) {
|
|
282
|
+
|
|
283
|
+
const divisions = {
|
|
284
|
+
second: 1e3,
|
|
285
|
+
seconds: 1e3,
|
|
286
|
+
minute: 6e4,
|
|
287
|
+
minutes: 6e4,
|
|
288
|
+
hour: 3.6e6,
|
|
289
|
+
hours: 3.6e6,
|
|
290
|
+
day: 8.64e7,
|
|
291
|
+
days: 8.64e7,
|
|
292
|
+
week: 6.048e8,
|
|
293
|
+
weeks: 6.048e8,
|
|
294
|
+
month: 2.629746e9,
|
|
295
|
+
months: 2.629746e9,
|
|
296
|
+
quarter: 78894e5,
|
|
297
|
+
quarters: 78894e5,
|
|
298
|
+
year: 3.15576e10,
|
|
299
|
+
years: 3.15576e10,
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
unit = unit || 'hour';
|
|
303
|
+
return Math.trunc(diff / divisions[unit]);
|
|
304
|
+
}
|
|
305
|
+
|
|
202
306
|
|
|
203
307
|
/*************************************
|
|
204
308
|
* PUBLIC INTERFACE
|
|
@@ -213,11 +317,11 @@
|
|
|
213
317
|
* @param typeOfFormat : string - DateTimeFormat | NumberFormat | PriceFormat
|
|
214
318
|
* @param options : object - the options object
|
|
215
319
|
*/
|
|
216
|
-
configure: function (langOrArr, typeOfFormat, options,
|
|
320
|
+
configure: function (langOrArr, typeOfFormat, options, customFormatName) {
|
|
217
321
|
|
|
218
322
|
if (typeof langOrArr !== 'string' && !Array.isArray(langOrArr)) {
|
|
219
323
|
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.');
|
|
324
|
+
'First argument must be a string with language code such as "en" or an array with language parameters.');
|
|
221
325
|
return false;
|
|
222
326
|
}
|
|
223
327
|
|
|
@@ -235,8 +339,8 @@
|
|
|
235
339
|
});
|
|
236
340
|
}
|
|
237
341
|
else {
|
|
238
|
-
if (__validateArgs(langOrArr, typeOfFormat, options,
|
|
239
|
-
__setArgs(langOrArr, typeOfFormat, options,
|
|
342
|
+
if (__validateArgs(langOrArr, typeOfFormat, options, customFormatName))
|
|
343
|
+
__setArgs(langOrArr, typeOfFormat, options, customFormatName);
|
|
240
344
|
else
|
|
241
345
|
return false;
|
|
242
346
|
}
|
|
@@ -245,7 +349,7 @@
|
|
|
245
349
|
},
|
|
246
350
|
|
|
247
351
|
/**
|
|
248
|
-
* resets the configuration to default state like it
|
|
352
|
+
* resets the configuration to default state like it was before configure() has been called
|
|
249
353
|
*/
|
|
250
354
|
reset: function () {
|
|
251
355
|
optionsConf = JSON.parse(JSON.stringify(defaultConf));
|
|
@@ -269,14 +373,14 @@
|
|
|
269
373
|
handlebars = overrideHndlbrs;
|
|
270
374
|
else if (typeof overrideHndlbrs !== 'undefined' && overrideHndlbrs !== null)
|
|
271
375
|
console.error('@ handlebars-i18n.init(): Invalid Argument [1] given for overrideHndlbrs. ' +
|
|
272
|
-
'Argument must be the Handlebars
|
|
376
|
+
'Argument must be the Handlebars object. Using generic Handlebars object instead.');
|
|
273
377
|
|
|
274
378
|
if (typeof overrideI18n === 'object' && overrideI18n !== null)
|
|
275
379
|
i18next = overrideI18n;
|
|
276
380
|
|
|
277
381
|
else if (typeof overrideI18n !== 'undefined' && overrideI18n !== null)
|
|
278
382
|
console.error('@ handlebars-i18n.init(): Invalid Argument [2] given for overrideI18n. ' +
|
|
279
|
-
'Argument must be the i18next
|
|
383
|
+
'Argument must be the i18next object. Using generic i18next object on module level instead.');
|
|
280
384
|
|
|
281
385
|
handlebars.registerHelper('__',
|
|
282
386
|
/**
|
|
@@ -316,7 +420,7 @@
|
|
|
316
420
|
);
|
|
317
421
|
handlebars.registerHelper('_date',
|
|
318
422
|
/**
|
|
319
|
-
* formats a
|
|
423
|
+
* formats a date according to the give internationalization options
|
|
320
424
|
*
|
|
321
425
|
* allows multiple input forms:
|
|
322
426
|
* {{_date}}
|
|
@@ -341,40 +445,63 @@
|
|
|
341
445
|
* @param options
|
|
342
446
|
*/
|
|
343
447
|
function (dateInput, options) {
|
|
448
|
+
const date= __createDateObj(dateInput);
|
|
449
|
+
const opts = __configLookup(options, i18next.language, optionsConf.DateTimeFormat);
|
|
450
|
+
const dateFormat = new Intl.DateTimeFormat(i18next.language, opts);
|
|
451
|
+
return dateFormat.format(date);
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
handlebars.registerHelper('_dateRel',
|
|
455
|
+
/**
|
|
456
|
+
* returns a relative date formatted according the options
|
|
457
|
+
* a positive dateValue will address a future date, like 'in 1 day'
|
|
458
|
+
* a negative dateValue will relate to a past date, like '1 day ago'
|
|
459
|
+
*
|
|
460
|
+
* _dateRel uses a polyfill in node environment because node’s Intl
|
|
461
|
+
* does not support relative date formats.
|
|
462
|
+
*
|
|
463
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat
|
|
464
|
+
* @link https://www.npmjs.com/package/relative-time-format
|
|
465
|
+
*
|
|
466
|
+
* @param dateValue
|
|
467
|
+
* @param options
|
|
468
|
+
* @returns {string}
|
|
469
|
+
*/
|
|
470
|
+
function (dateValue, options) {
|
|
471
|
+
const relDate= parseInt(dateValue);
|
|
472
|
+
const opts = __configLookup(options, i18next.language, optionsConf.RelativeTimeFormat);
|
|
473
|
+
const relDateFormat = __getRelDateFormatPolyfill(i18next.language, opts);
|
|
474
|
+
return relDateFormat.format(relDate, opts.unit);
|
|
475
|
+
}
|
|
476
|
+
);
|
|
477
|
+
handlebars.registerHelper('_dateDiff',
|
|
478
|
+
/**
|
|
479
|
+
*
|
|
480
|
+
* @param dateInputA
|
|
481
|
+
* @param dateInputB
|
|
482
|
+
* @param options
|
|
483
|
+
* @returns {string|null}
|
|
484
|
+
*/
|
|
485
|
+
function (dateInputA, dateInputB, options) {
|
|
344
486
|
|
|
345
|
-
|
|
487
|
+
let dateDiff;
|
|
346
488
|
|
|
347
|
-
if (
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
else if (
|
|
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
|
-
}
|
|
489
|
+
if (! __isNumOrString(dateInputA) && ! __isNumOrString(dateInputB))
|
|
490
|
+
return null;
|
|
491
|
+
else if (! __isNumOrString(dateInputB))
|
|
492
|
+
dateDiff = __createDateObj(dateInputA);
|
|
493
|
+
else if (! __isNumOrString(dateInputA))
|
|
494
|
+
dateDiff = __createDateObj(dateInputB);
|
|
369
495
|
else {
|
|
370
|
-
|
|
371
|
-
|
|
496
|
+
const dateA= __createDateObj(dateInputA);
|
|
497
|
+
const dateB= __createDateObj(dateInputB);
|
|
498
|
+
dateDiff = dateA - dateB;
|
|
372
499
|
}
|
|
373
500
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
const
|
|
377
|
-
return
|
|
501
|
+
const opts = __configLookup(options, i18next.language, optionsConf.RelativeTimeFormat);
|
|
502
|
+
const relDate = __getDateDiff(dateDiff, opts.unit);
|
|
503
|
+
const relDateFormat = __getRelDateFormatPolyfill(i18next.language, opts);
|
|
504
|
+
return relDateFormat.format(relDate, opts.unit);
|
|
378
505
|
}
|
|
379
506
|
);
|
|
380
507
|
handlebars.registerHelper('_num',
|
|
@@ -392,7 +519,7 @@
|
|
|
392
519
|
*/
|
|
393
520
|
function (number, options) {
|
|
394
521
|
|
|
395
|
-
|
|
522
|
+
let opts = __configLookup(options, i18next.language, optionsConf.NumberFormat);
|
|
396
523
|
|
|
397
524
|
const priceFormat = new Intl.NumberFormat(i18next.language, opts);
|
|
398
525
|
return priceFormat.format(number);
|
|
@@ -413,7 +540,7 @@
|
|
|
413
540
|
*/
|
|
414
541
|
function (price, options) {
|
|
415
542
|
|
|
416
|
-
|
|
543
|
+
let opts = __configLookup(options, i18next.language, optionsConf.PriceFormat);
|
|
417
544
|
|
|
418
545
|
// for convenience automatically add the object parameter style:'currency' if not given
|
|
419
546
|
if (typeof opts['style'] !== 'string' && typeof opts['currency'] === 'string')
|
|
@@ -425,9 +552,23 @@
|
|
|
425
552
|
);
|
|
426
553
|
|
|
427
554
|
return handlebars;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
|
|
555
|
+
},
|
|
433
556
|
|
|
557
|
+
/**
|
|
558
|
+
* we conditionally export the helpers to be able to test against them;
|
|
559
|
+
* in production they are not exported.
|
|
560
|
+
*/
|
|
561
|
+
...(isTest) && {
|
|
562
|
+
private: {
|
|
563
|
+
applyToConstructor: __applyToConstructor,
|
|
564
|
+
configLookup: __configLookup,
|
|
565
|
+
validateArgs: __validateArgs,
|
|
566
|
+
setArgs: __setArgs,
|
|
567
|
+
isNumOrString: __isNumOrString,
|
|
568
|
+
createDateObj: __createDateObj,
|
|
569
|
+
getRelDateFormatPolyfill: __getRelDateFormatPolyfill,
|
|
570
|
+
getDateDiff: __getDateDiff
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
}
|
|
574
|
+
});
|
|
@@ -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;if(!f(e)&&!f(t))return null;if(f(t))if(f(e)){a=g(e)-g(t)}else a=g(t);else a=g(e);const o=l(n,r.language,i.RelativeTimeFormat),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}}}}));
|