@bravobit/bb-foundation 0.22.4 → 0.23.2

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.
Files changed (37) hide show
  1. package/elements/lib/pipes/relative-time.pipe.d.ts +1 -1
  2. package/esm2020/localize/lib/dictionary/dictionary.class.mjs +92 -0
  3. package/esm2020/localize/lib/dictionary/dictionary.context.mjs +26 -0
  4. package/esm2020/localize/lib/dictionary/dictionary.data.mjs +6 -0
  5. package/esm2020/localize/lib/functions/lowercase.function.mjs +2 -2
  6. package/esm2020/localize/lib/functions/uppercase.function.mjs +2 -2
  7. package/esm2020/localize/lib/handlers/missing.handler.mjs +2 -2
  8. package/esm2020/localize/lib/interfaces/config.interfaces.mjs +1 -1
  9. package/esm2020/localize/lib/interfaces/options.interfaces.mjs +1 -1
  10. package/esm2020/localize/lib/interfaces/transforms.interfaces.mjs +3 -0
  11. package/esm2020/localize/lib/localize.module.mjs +12 -3
  12. package/esm2020/localize/lib/localize.pipe.mjs +9 -12
  13. package/esm2020/localize/lib/localize.service.mjs +84 -128
  14. package/esm2020/localize/lib/transforms/abstract.transform.mjs +30 -0
  15. package/esm2020/localize/lib/transforms/interpolate.transform.mjs +54 -0
  16. package/esm2020/localize/lib/transforms/reference.transform.mjs +25 -0
  17. package/esm2020/localize/public_api.mjs +8 -2
  18. package/fesm2015/bravobit-bb-foundation-localize.mjs +347 -175
  19. package/fesm2015/bravobit-bb-foundation-localize.mjs.map +1 -1
  20. package/fesm2020/bravobit-bb-foundation-localize.mjs +327 -167
  21. package/fesm2020/bravobit-bb-foundation-localize.mjs.map +1 -1
  22. package/localize/lib/dictionary/dictionary.class.d.ts +28 -0
  23. package/localize/lib/dictionary/dictionary.context.d.ts +7 -0
  24. package/localize/lib/dictionary/dictionary.data.d.ts +7 -0
  25. package/localize/lib/interfaces/config.interfaces.d.ts +4 -6
  26. package/localize/lib/interfaces/options.interfaces.d.ts +1 -0
  27. package/localize/lib/interfaces/transforms.interfaces.d.ts +3 -0
  28. package/localize/lib/localize.module.d.ts +1 -1
  29. package/localize/lib/localize.pipe.d.ts +3 -3
  30. package/localize/lib/localize.service.d.ts +25 -21
  31. package/localize/lib/transforms/abstract.transform.d.ts +13 -0
  32. package/localize/lib/transforms/interpolate.transform.d.ts +14 -0
  33. package/localize/lib/transforms/reference.transform.d.ts +10 -0
  34. package/localize/public_api.d.ts +7 -1
  35. package/package.json +1 -1
  36. package/esm2020/localize/lib/localize.dictionary.mjs +0 -24
  37. package/localize/lib/localize.dictionary.d.ts +0 -7
@@ -1,14 +1,15 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Directive, Input, Component, ChangeDetectionStrategy, ViewEncapsulation, ContentChildren, Injectable, Optional, Inject, Pipe, APP_INITIALIZER, LOCALE_ID, NgModule } from '@angular/core';
2
+ import { InjectionToken, Optional, Inject, Directive, Input, Component, ChangeDetectionStrategy, ViewEncapsulation, ContentChildren, Injectable, Pipe, APP_INITIALIZER, LOCALE_ID, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { formatDate, DOCUMENT, CommonModule } from '@angular/common';
5
+ import { __awaiter, __decorate, __param } from 'tslib';
5
6
  import { startWith } from 'rxjs/operators';
6
7
  import { Subscription } from 'rxjs';
7
8
  import * as i2 from '@bravobit/bb-foundation/utils';
8
9
  import { UtilsModule } from '@bravobit/bb-foundation/utils';
9
- import { __awaiter } from 'tslib';
10
- import * as i1$1 from '@bravobit/bb-foundation/storage';
11
10
  import * as i2$1 from '@bravobit/bb-foundation';
11
+ import { WINDOW } from '@bravobit/bb-foundation';
12
+ import * as i1$1 from '@bravobit/bb-foundation/storage';
12
13
 
13
14
  //
14
15
  // The configuration that can be passed when
@@ -24,6 +25,8 @@ class LocalizeConfig {
24
25
  //
25
26
  const LOCALIZE_FUNCTION = new InjectionToken('localize_function');
26
27
 
28
+ const LOCALIZE_TRANSFORM = new InjectionToken('localize_transform');
29
+
27
30
  //
28
31
  // This function transform the value
29
32
  // to a lowercase variant of the value.
@@ -33,7 +36,7 @@ class LocalizeLowercaseFunction {
33
36
  return 'lowercase';
34
37
  }
35
38
  transform(value) {
36
- return (value || '').toLowerCase();
39
+ return (value !== null && value !== void 0 ? value : '').toLowerCase();
37
40
  }
38
41
  }
39
42
 
@@ -46,7 +49,7 @@ class LocalizeUppercaseFunction {
46
49
  return 'uppercase';
47
50
  }
48
51
  transform(value) {
49
- return (value || '').toUpperCase();
52
+ return (value !== null && value !== void 0 ? value : '').toUpperCase();
50
53
  }
51
54
  }
52
55
 
@@ -166,13 +169,250 @@ class LocalizeMissingHandler {
166
169
  // Log to the console when the token was not found
167
170
  // if the user did not mark it as optional.
168
171
  if (!(params === null || params === void 0 ? void 0 : params.optional)) {
169
- this.log(`Localize: The token with name: "${params === null || params === void 0 ? void 0 : params.token}" was not found.`);
172
+ this.log(`The token with name: "${params === null || params === void 0 ? void 0 : params.token}" was not found.`);
170
173
  }
171
174
  // Return the default token back.
172
175
  return (_a = params === null || params === void 0 ? void 0 : params.token) !== null && _a !== void 0 ? _a : null;
173
176
  }
174
177
  }
175
178
 
179
+ class LocalizeDictionaryData {
180
+ constructor(data) {
181
+ this.data = data;
182
+ }
183
+ }
184
+
185
+ class LocalizeDictionaryContext {
186
+ constructor() {
187
+ this.regexp = /^.*$/;
188
+ }
189
+ pattern(regexp) {
190
+ this.regexp = regexp;
191
+ return this;
192
+ }
193
+ matches(value) {
194
+ const formatted = this.formatValue(value);
195
+ const regex = (formatted !== null && formatted !== void 0 ? formatted : '')
196
+ .replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
197
+ .replace(/\\\*/g, '.*');
198
+ return this.pattern(new RegExp(`^${regex}$`));
199
+ }
200
+ group(value) {
201
+ const formatted = this.formatValue(value);
202
+ return this.matches([formatted, '*']);
203
+ }
204
+ formatValue(value) {
205
+ return Array.isArray(value)
206
+ ? value.filter(item => !!item).join('.')
207
+ : value;
208
+ }
209
+ }
210
+
211
+ class LocalizeDictionary {
212
+ constructor(_id, _locale, _supported, _dataValues, _localize) {
213
+ this._id = _id;
214
+ this._locale = _locale;
215
+ this._supported = _supported;
216
+ this._dataValues = _dataValues;
217
+ this._localize = _localize;
218
+ this._data = this.formatData(this._dataValues);
219
+ }
220
+ get id() {
221
+ var _a;
222
+ return (_a = this._id) !== null && _a !== void 0 ? _a : null;
223
+ }
224
+ get locale() {
225
+ var _a;
226
+ return (_a = this._locale) !== null && _a !== void 0 ? _a : null;
227
+ }
228
+ get supported() {
229
+ var _a;
230
+ return (_a = this._supported) !== null && _a !== void 0 ? _a : [];
231
+ }
232
+ get(token) {
233
+ var _a, _b;
234
+ const key = Array.isArray(token) ? token.join('.') : token;
235
+ return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a[key]) !== null && _b !== void 0 ? _b : null;
236
+ }
237
+ has(token) {
238
+ return !!this.get(token);
239
+ }
240
+ all() {
241
+ return this.some(context => context);
242
+ }
243
+ some(callback) {
244
+ var _a;
245
+ const defaultContext = new LocalizeDictionaryContext();
246
+ const context = !!callback ? callback(defaultContext) : defaultContext;
247
+ return Object.keys((_a = this._data) !== null && _a !== void 0 ? _a : {})
248
+ .filter(key => context.regexp.test(key))
249
+ .reduce((previous, current) => ([
250
+ ...previous,
251
+ { token: current, value: this.get(current) }
252
+ ]), []);
253
+ }
254
+ compare(to) {
255
+ var _a, _b;
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ if ((typeof ngDevMode === 'undefined' || ngDevMode)) {
258
+ const dictionaryIds = (Array.isArray(to) ? to : [to]);
259
+ const dictionaries = [];
260
+ for (const dictionaryId of dictionaryIds) {
261
+ console.log(`Making sure dictionary "${dictionaryId}" is loaded.`);
262
+ const dictionary = yield this._localize.load(dictionaryId);
263
+ dictionaries.push(dictionary);
264
+ }
265
+ const warnings = [];
266
+ const items = this.all();
267
+ for (const item of items) {
268
+ for (const dictionary of dictionaries) {
269
+ if (!dictionary.has(item === null || item === void 0 ? void 0 : item.token)) {
270
+ warnings.push({ dictionary: dictionary === null || dictionary === void 0 ? void 0 : dictionary.id, value: item === null || item === void 0 ? void 0 : item.token });
271
+ }
272
+ }
273
+ }
274
+ for (const dictionary of dictionaries) {
275
+ const items = dictionary.all();
276
+ for (const item of items) {
277
+ if (!this.has(item === null || item === void 0 ? void 0 : item.token)) {
278
+ warnings.push({ dictionary: this.id, value: item === null || item === void 0 ? void 0 : item.token });
279
+ }
280
+ }
281
+ }
282
+ const compareDictionaryIds = dictionaries.map(dictionary => dictionary === null || dictionary === void 0 ? void 0 : dictionary.id).join(', ');
283
+ console.log(`Comparing currency dictionary [${this.id}] with [${compareDictionaryIds}]...`);
284
+ for (const warning of warnings) {
285
+ (_a = console === null || console === void 0 ? void 0 : console.warn) === null || _a === void 0 ? void 0 : _a.call(console, `Dictionary "${warning.dictionary}" is missing token "${warning.value}"`);
286
+ }
287
+ (_b = console === null || console === void 0 ? void 0 : console.warn) === null || _b === void 0 ? void 0 : _b.call(console, `Total of ${warnings.length} warning(s) found.`);
288
+ }
289
+ });
290
+ }
291
+ count() {
292
+ var _a;
293
+ return Object.keys((_a = this._data) !== null && _a !== void 0 ? _a : {}).length;
294
+ }
295
+ formatData(data, scope = null) {
296
+ return Object.keys(data !== null && data !== void 0 ? data : {}).reduce((previous, current) => {
297
+ var _a;
298
+ const value = data === null || data === void 0 ? void 0 : data[current];
299
+ if (typeof value === 'object' && value !== null) {
300
+ const reformatted = this.formatData(value, current);
301
+ return Object.assign(Object.assign({}, previous), reformatted);
302
+ }
303
+ const token = [scope, current].filter(item => !!item).join('.');
304
+ if (previous[token] && (typeof ngDevMode === 'undefined' || ngDevMode)) {
305
+ (_a = console === null || console === void 0 ? void 0 : console.warn) === null || _a === void 0 ? void 0 : _a.call(console, `Duplicate key "${token}" was found, please verify your translation files.`);
306
+ }
307
+ return Object.assign(Object.assign({}, previous), { [token]: value });
308
+ }, {});
309
+ }
310
+ }
311
+
312
+ class LocalizeTransform {
313
+ getMatches(value, substitutions) {
314
+ // Validate our value exists, else return zero matches.
315
+ if (value === undefined || value === null) {
316
+ return [];
317
+ }
318
+ // Get the matching substitutions.
319
+ const { start, end } = this.getSubstitutions(substitutions);
320
+ // Compose a regex that will find the matches.
321
+ const regex = new RegExp(`${start}([^${end}]+)${end}`, 'g');
322
+ // Execute the regex to find matches.
323
+ let match = regex.exec(value);
324
+ const matches = [];
325
+ while (match !== null) {
326
+ matches.push({ match: match[0], token: match[1] });
327
+ match = regex.exec(value);
328
+ }
329
+ // Return the processed value.
330
+ return matches.filter(item => !!item);
331
+ }
332
+ getSubstitutions(value) {
333
+ // Escape both substitutions so that they can be used.
334
+ const escape = /[.*+?^${}()|[\]\\]/g;
335
+ const start = value[0].replace(escape, '\\$&');
336
+ const end = value[1].replace(escape, '\\$&');
337
+ // Return the substitutions.
338
+ return { start, end };
339
+ }
340
+ }
341
+
342
+ let LocalizeInterpolateTransform = class LocalizeInterpolateTransform extends LocalizeTransform {
343
+ constructor(config, functions) {
344
+ var _a, _b, _c, _d;
345
+ super();
346
+ this.config = config;
347
+ this.functions = functions;
348
+ this.substitutions = (_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.substitutions) === null || _b === void 0 ? void 0 : _b.references) !== null && _c !== void 0 ? _c : ['{{', '}}'];
349
+ this.functionsMap = ((_d = this.functions) !== null && _d !== void 0 ? _d : []).reduce((previous, current) => {
350
+ previous[current === null || current === void 0 ? void 0 : current.keyword()] = current;
351
+ return previous;
352
+ }, {});
353
+ }
354
+ execute(value, data, localize) {
355
+ const matches = this.getMatches(value, this.substitutions);
356
+ // Replace all matches with the translated value.
357
+ return matches.reduce((previous, current) => {
358
+ // Try to parse the token.
359
+ const interpolatedToken = this.parseInterpolationToken(current === null || current === void 0 ? void 0 : current.token, data, localize);
360
+ // Replace the match with the translated token.
361
+ return previous.replace(current === null || current === void 0 ? void 0 : current.match, interpolatedToken);
362
+ }, value);
363
+ }
364
+ parseInterpolationToken(value, data, localize) {
365
+ var _a;
366
+ // Get the token and the methods by splitting
367
+ // on the pipe symbol.
368
+ const [token, ...methods] = (value !== null && value !== void 0 ? value : '').split('|').map(item => item.trim());
369
+ // Get the value for the token from
370
+ // the interpolation data.
371
+ const interpolationValue = (_a = data === null || data === void 0 ? void 0 : data[token]) !== null && _a !== void 0 ? _a : 'null';
372
+ // Loop through all the middleware methods and try to
373
+ // conform the string to the given parameters.
374
+ return methods.reduce((string, middlewareName) => {
375
+ var _a, _b;
376
+ // Try to retrieve the middleware from the collection.
377
+ const middleware = (_a = this.functionsMap) === null || _a === void 0 ? void 0 : _a[middlewareName];
378
+ // If the middleware is missing return an error
379
+ // so that the user knows it was not found.
380
+ if (!middleware) {
381
+ return string;
382
+ }
383
+ // Execute the middleware function with the string.
384
+ return middleware.transform(string, (_b = localize === null || localize === void 0 ? void 0 : localize.current) === null || _b === void 0 ? void 0 : _b.locale);
385
+ }, `${interpolationValue}`);
386
+ }
387
+ };
388
+ LocalizeInterpolateTransform = __decorate([
389
+ __param(0, Optional()),
390
+ __param(1, Optional()),
391
+ __param(1, Inject(LOCALIZE_FUNCTION))
392
+ ], LocalizeInterpolateTransform);
393
+
394
+ let LocalizeReferenceTransform = class LocalizeReferenceTransform extends LocalizeTransform {
395
+ constructor(config) {
396
+ var _a, _b, _c;
397
+ super();
398
+ this.config = config;
399
+ this.substitutions = (_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.substitutions) === null || _b === void 0 ? void 0 : _b.references) !== null && _c !== void 0 ? _c : ['#(', ')'];
400
+ }
401
+ execute(value, _, localize) {
402
+ const matches = this.getMatches(value, this.substitutions);
403
+ // Replace all matches with the translated value.
404
+ return matches.reduce((previous, current) => {
405
+ // Try to translate the token.
406
+ const translatedToken = localize.translate(current === null || current === void 0 ? void 0 : current.token);
407
+ // Replace the match with the translated token.
408
+ return previous.replace(current === null || current === void 0 ? void 0 : current.match, translatedToken);
409
+ }, value);
410
+ }
411
+ };
412
+ LocalizeReferenceTransform = __decorate([
413
+ __param(0, Optional())
414
+ ], LocalizeReferenceTransform);
415
+
176
416
  class BbLocalizeTemplate {
177
417
  constructor(templateRef) {
178
418
  this.templateRef = templateRef;
@@ -276,82 +516,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImpor
276
516
  type: Input
277
517
  }] } });
278
518
 
279
- class LocalizeDictionary {
280
- constructor(data) {
281
- this._data = this.formatData(data);
282
- }
283
- get(token) {
284
- var _a, _b;
285
- const key = Array.isArray(token) ? token.join('.') : token;
286
- return (_b = (_a = this._data) === null || _a === void 0 ? void 0 : _a[key]) !== null && _b !== void 0 ? _b : null;
287
- }
288
- formatData(data, scope = null) {
289
- return Object.keys(data).reduce((previous, current) => {
290
- var _a;
291
- const value = data === null || data === void 0 ? void 0 : data[current];
292
- if (typeof value === 'object' && value !== null) {
293
- const reformatted = this.formatData(value, current);
294
- return Object.assign(Object.assign({}, previous), reformatted);
295
- }
296
- const token = [scope, current].filter(item => !!item).join('.');
297
- if (previous[token] && (typeof ngDevMode === 'undefined' || ngDevMode)) {
298
- (_a = console === null || console === void 0 ? void 0 : console.warn) === null || _a === void 0 ? void 0 : _a.call(console, `Localize: Duplicate key "${token}" was found, please verify your translation files.`);
299
- }
300
- return Object.assign(Object.assign({}, previous), { [token]: value });
301
- }, {});
302
- }
303
- }
304
-
305
519
  class Localize {
306
- constructor(_storage, _languages, _config, _missingHandler, _document, _functions) {
520
+ constructor(_storage, _languages, _missingHandler, _config, _window, _document, _transforms) {
521
+ var _a, _b, _c, _d;
307
522
  this._storage = _storage;
308
523
  this._languages = _languages;
309
- this._config = _config;
310
524
  this._missingHandler = _missingHandler;
525
+ this._config = _config;
526
+ this._window = _window;
311
527
  this._document = _document;
312
- this._functions = _functions;
313
- this._storageToken = 'bb-language-dictionary-id';
314
- // Current language dictionary.
315
- this._currentLanguage = null;
316
- this._currentDictionary = null;
528
+ this._transforms = _transforms;
529
+ // Readonly data.
530
+ this._storageToken = (_b = (_a = this._config) === null || _a === void 0 ? void 0 : _a.storageToken) !== null && _b !== void 0 ? _b : 'bb-language-dictionary-id';
531
+ this._availableLanguages = (_d = (_c = this === null || this === void 0 ? void 0 : this._config) === null || _c === void 0 ? void 0 : _c.languages) !== null && _d !== void 0 ? _d : [];
532
+ this._bestMatchingLanguage = this.retrieveBestMatchingLanguage();
533
+ this._loadedDictionaries = new Map();
534
+ // Current dictionary.
535
+ this._current = null;
317
536
  this.convertToParams = (tokenOrParams) => {
318
537
  if (typeof tokenOrParams !== 'string') {
319
538
  // Destruct the params from the object.
320
- const { token, optional, data } = tokenOrParams;
539
+ const { token, optional, dictionary, data } = tokenOrParams;
321
540
  // Make sure all parameters are valid
322
541
  // by type safe adding them.
323
- return { token: token, optional: optional !== null && optional !== void 0 ? optional : false, data: data !== null && data !== void 0 ? data : {} };
542
+ return { token: token, optional: optional !== null && optional !== void 0 ? optional : false, dictionary: dictionary !== null && dictionary !== void 0 ? dictionary : null, data: data !== null && data !== void 0 ? data : {} };
324
543
  }
325
544
  // If the parameter is a string fill in the blanks.
326
- return { token: tokenOrParams, optional: false, data: {} };
545
+ return { token: tokenOrParams, optional: false, dictionary: null, data: {} };
327
546
  };
328
- this.getMatches = (value, substitutions) => {
329
- // Get the matching substitutions.
330
- const { start, end } = substitutions;
331
- // Compose a regex that will find the matches.
332
- const regex = new RegExp(`${start}([^${end}]+)${end}`, 'g');
333
- // Execute the regex to find matches.
334
- let match = regex.exec(value);
335
- const matches = [];
336
- while (match !== null) {
337
- matches.push({ match: match[0], token: match[1] });
338
- match = regex.exec(value);
339
- }
340
- // Return the processed value.
341
- return matches.filter(item => !!item);
342
- };
343
- // Check if at least one language was passed in the config.
344
- this._availableLanguages = this._config.languages;
345
- if (this._availableLanguages.length < 1) {
346
- throw new Error('Localize: one or more languages should be supplied.');
347
- }
348
- // Gather all the localize functions.
349
- this._functionMiddleware = this._functions.reduce((previous, current) => {
350
- previous[current.keyword()] = current;
351
- return previous;
352
- }, {});
353
- // Save the best matching current dictionary.
354
- this._bestMatchingLanguage = this.retrieveBestMatchingLanguage();
355
547
  this.renderDocumentLanguage();
356
548
  }
357
549
  get languages() {
@@ -359,115 +551,77 @@ class Localize {
359
551
  return (_a = this._availableLanguages) !== null && _a !== void 0 ? _a : [];
360
552
  }
361
553
  get current() {
362
- return this._currentLanguage;
554
+ return this._current;
363
555
  }
364
- set(language, cache = true) {
365
- var _a, _b;
556
+ load(id) {
557
+ var _a, _b, _c, _d, _e, _f;
366
558
  return __awaiter(this, void 0, void 0, function* () {
367
- // Await the language data and set the current
368
- // dictionary to the loaded data.
369
- this._currentLanguage = language !== null && language !== void 0 ? language : (_a = this._availableLanguages) === null || _a === void 0 ? void 0 : _a[0];
370
- if (this._currentLanguage) {
371
- this._currentDictionary = yield this._currentLanguage.data();
559
+ if (id === null || id === undefined) {
560
+ throw new Error(`Cannot load language with id: "${id}".`);
561
+ }
562
+ if (this._loadedDictionaries.has(id)) {
563
+ return this._loadedDictionaries.get(id);
564
+ }
565
+ const language = (_a = this.languages) === null || _a === void 0 ? void 0 : _a.find(language => (language === null || language === void 0 ? void 0 : language.id) === id);
566
+ if (!language || !(language === null || language === void 0 ? void 0 : language.data)) {
567
+ (_b = console === null || console === void 0 ? void 0 : console.warn) === null || _b === void 0 ? void 0 : _b.call(console, `No language was found with id: "${id}"; Defaulting to first available language.`);
568
+ const languageId = (_e = (_d = (_c = this.languages) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : null;
569
+ return this.load(languageId);
372
570
  }
373
- // Save the selected language in the storage.
571
+ const dictionaryDataValues = yield ((_f = language === null || language === void 0 ? void 0 : language.data) === null || _f === void 0 ? void 0 : _f.call(language));
572
+ const dictionary = this.createDictionary(dictionaryDataValues, language);
573
+ this._loadedDictionaries.set(id, dictionary);
574
+ return dictionary;
575
+ });
576
+ }
577
+ switch(id, options) {
578
+ var _a, _b, _c, _d, _e, _f;
579
+ return __awaiter(this, void 0, void 0, function* () {
580
+ this._current = yield this.load(id);
581
+ const cache = (_a = options === null || options === void 0 ? void 0 : options.cache) !== null && _a !== void 0 ? _a : true;
374
582
  if (cache) {
375
- this._storage.cookie.set(this._storageToken, (_b = this._currentLanguage) === null || _b === void 0 ? void 0 : _b.id, {});
583
+ this._storage.cookie.set(this._storageToken, (_b = this._current) === null || _b === void 0 ? void 0 : _b.id, {});
376
584
  }
585
+ const reload = (_c = options === null || options === void 0 ? void 0 : options.reload) !== null && _c !== void 0 ? _c : false;
586
+ if (reload) {
587
+ (_f = (_e = (_d = this._window) === null || _d === void 0 ? void 0 : _d.location) === null || _e === void 0 ? void 0 : _e.reload) === null || _f === void 0 ? void 0 : _f.call(_e);
588
+ }
589
+ return this._current;
377
590
  });
378
591
  }
592
+ select(id) {
593
+ if (!this._loadedDictionaries.has(id)) {
594
+ throw new Error(`Dictionary with id: "${id}" not loaded; Load dictionary first before using .select(:id).`);
595
+ }
596
+ return this._loadedDictionaries.get(id);
597
+ }
379
598
  initialize() {
380
- return () => __awaiter(this, void 0, void 0, function* () { return this.set(this._bestMatchingLanguage, false); });
599
+ return () => __awaiter(this, void 0, void 0, function* () { var _a; return this.switch((_a = this._bestMatchingLanguage) === null || _a === void 0 ? void 0 : _a.id, { reload: false, cache: false }); });
381
600
  }
382
601
  clear() {
383
602
  this._storage.cookie.remove(this._storageToken);
384
603
  }
604
+ transform(value, data = {}) {
605
+ var _a;
606
+ return ((_a = this._transforms) !== null && _a !== void 0 ? _a : []).reduce((previous, current) => {
607
+ return current.execute(previous, data, this);
608
+ }, value);
609
+ }
385
610
  translate(tokenOrParams) {
386
611
  // 1. Convert to the params.
387
612
  const params = this.convertToParams(tokenOrParams);
388
613
  // 2. Try to find the translation in the dictionary.
389
- const searchResult = this._currentDictionary.get(params === null || params === void 0 ? void 0 : params.token);
614
+ const dictionary = this.getDictionary(params === null || params === void 0 ? void 0 : params.dictionary);
615
+ const searchResult = !!dictionary ? dictionary.get(params === null || params === void 0 ? void 0 : params.token) : null;
390
616
  // 3. Verify the translation was found.
391
617
  if (!searchResult) {
392
618
  return this._missingHandler.handle(params);
393
619
  }
394
- // 4. Find references in the translation that need to be translated as well.
395
- const processResult = this.findReferencesInTranslation(searchResult);
396
- // 5. Parse the interpolation data.
397
- return this.parseInterpolationData(processResult, params === null || params === void 0 ? void 0 : params.data);
398
- }
399
- parseInterpolationData(value, data) {
400
- // Get the interpolation substitutions.
401
- const substitutions = this.getSubstitutions('interpolation', ['{{', '}}']);
402
- // Get all matches in the value.
403
- const matches = this.getMatches(value, substitutions);
404
- // Replace all matches with the parsed value.
405
- return matches.reduce((previous, current) => {
406
- // Try to parse the token.
407
- const interpolatedToken = this.interpolateFunctionData(current === null || current === void 0 ? void 0 : current.token, data);
408
- // Replace the match with the parsed token.
409
- return previous.replace(current === null || current === void 0 ? void 0 : current.match, interpolatedToken);
410
- }, `${value}`);
411
- }
412
- interpolateFunctionData(value, interpolationData) {
413
- var _a;
414
- // Get the token and the methods by splitting
415
- // on the pipe symbol.
416
- const [token, ...methods] = value.split('|').map(item => item.trim());
417
- // Get the value for the token from
418
- // the interpolation data.
419
- const interpolationValue = (_a = interpolationData === null || interpolationData === void 0 ? void 0 : interpolationData[token]) !== null && _a !== void 0 ? _a : token;
420
- // Loop through all the middleware methods and try to
421
- // conform the string to the given parameters.
422
- return methods.reduce((string, middlewareName) => {
423
- var _a;
424
- // Try to retrieve the middleware from the collection.
425
- const middleware = this._functionMiddleware[middlewareName];
426
- // If the middleware is missing return an error
427
- // so that the user knows it was not found.
428
- if (!middleware) {
429
- return string;
430
- }
431
- // Execute the middleware function with the string.
432
- return middleware.transform(string, (_a = this.current) === null || _a === void 0 ? void 0 : _a.locale);
433
- }, `${interpolationValue}`);
434
- }
435
- findReferencesInTranslation(value) {
436
- // Get the reference substitutions.
437
- const substitutions = this.getSubstitutions('references', ['#(', ')']);
438
- // Get all matches in the value.
439
- const matches = this.getMatches(value, substitutions);
440
- // Replace all matches with the translated value.
441
- return matches.reduce((previous, current) => {
442
- // Try to translate the token.
443
- const translatedToken = this.translate(current === null || current === void 0 ? void 0 : current.token);
444
- // Replace the match with the translated token.
445
- return previous.replace(current === null || current === void 0 ? void 0 : current.match, translatedToken);
446
- }, value);
447
- }
448
- getSubstitutions(type, defaultValue) {
449
- var _a, _b, _c;
450
- // Get the substitutions.
451
- const substitutions = (_c = (_b = (_a = this._config) === null || _a === void 0 ? void 0 : _a.substitutions) === null || _b === void 0 ? void 0 : _b[type]) !== null && _c !== void 0 ? _c : null;
452
- const value = (!substitutions || substitutions.length !== 2)
453
- ? defaultValue
454
- : substitutions;
455
- // Escape both substitutions so that they
456
- // can be used.
457
- const escape = /[.*+?^${}()|[\]\\]/g;
458
- const start = value[0].replace(escape, '\\$&');
459
- const end = value[1].replace(escape, '\\$&');
460
- // Return the substitutions.
461
- return { start, end };
620
+ return this.transform(searchResult, params === null || params === void 0 ? void 0 : params.data);
462
621
  }
463
622
  retrieveBestMatchingLanguage() {
464
- var _a, _b;
465
- // Get the language based on storage.
466
- const storageLanguage = this.getLanguageFromStorage();
467
- // Get the language based on the supported languages of the browser.
468
- const browserLanguage = this.getBestBrowserMatchLanguage();
469
- // Return the best matching language.
470
- return (_a = storageLanguage !== null && storageLanguage !== void 0 ? storageLanguage : browserLanguage) !== null && _a !== void 0 ? _a : (_b = this._availableLanguages) === null || _b === void 0 ? void 0 : _b[0];
623
+ var _a, _b, _c;
624
+ return (_b = (_a = this.getLanguageFromStorage()) !== null && _a !== void 0 ? _a : this.getBestBrowserMatchLanguage()) !== null && _b !== void 0 ? _b : (_c = this._availableLanguages) === null || _c === void 0 ? void 0 : _c[0];
471
625
  }
472
626
  getLanguageFromStorage() {
473
627
  // Get id from the storage.
@@ -483,6 +637,15 @@ class Localize {
483
637
  return this._availableLanguages.find(item => { var _a; return (_a = item === null || item === void 0 ? void 0 : item.supported) === null || _a === void 0 ? void 0 : _a.includes(languageCode); });
484
638
  }).filter(item => !!item).find((_, index) => index === 0);
485
639
  }
640
+ createDictionary(data, language) {
641
+ return new LocalizeDictionary(language === null || language === void 0 ? void 0 : language.id, language === null || language === void 0 ? void 0 : language.locale, language === null || language === void 0 ? void 0 : language.supported, data === null || data === void 0 ? void 0 : data.data, this);
642
+ }
643
+ getDictionary(id) {
644
+ if (id === null || id === undefined) {
645
+ return this._current;
646
+ }
647
+ return this.select(id);
648
+ }
486
649
  renderDocumentLanguage() {
487
650
  var _a, _b, _c, _d, _e;
488
651
  const element = (_a = this._document) === null || _a === void 0 ? void 0 : _a.documentElement;
@@ -492,14 +655,19 @@ class Localize {
492
655
  element.lang = (_d = (_c = (_b = this._bestMatchingLanguage) === null || _b === void 0 ? void 0 : _b.supported) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : (_e = this._bestMatchingLanguage) === null || _e === void 0 ? void 0 : _e.locale;
493
656
  }
494
657
  }
495
- Localize.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: Localize, deps: [{ token: i1$1.Storage }, { token: i2$1.Languages }, { token: LocalizeConfig, optional: true }, { token: LocalizeMissingHandler }, { token: DOCUMENT, optional: true }, { token: LOCALIZE_FUNCTION, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
658
+ Localize.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: Localize, deps: [{ token: i1$1.Storage }, { token: i2$1.Languages }, { token: LocalizeMissingHandler }, { token: LocalizeConfig, optional: true }, { token: WINDOW, optional: true }, { token: DOCUMENT, optional: true }, { token: LOCALIZE_TRANSFORM, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
496
659
  Localize.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: Localize });
497
660
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: Localize, decorators: [{
498
661
  type: Injectable
499
662
  }], ctorParameters: function () {
500
- return [{ type: i1$1.Storage }, { type: i2$1.Languages }, { type: LocalizeConfig, decorators: [{
663
+ return [{ type: i1$1.Storage }, { type: i2$1.Languages }, { type: LocalizeMissingHandler }, { type: LocalizeConfig, decorators: [{
664
+ type: Optional
665
+ }] }, { type: Window, decorators: [{
501
666
  type: Optional
502
- }] }, { type: LocalizeMissingHandler }, { type: Document, decorators: [{
667
+ }, {
668
+ type: Inject,
669
+ args: [WINDOW]
670
+ }] }, { type: Document, decorators: [{
503
671
  type: Optional
504
672
  }, {
505
673
  type: Inject,
@@ -508,7 +676,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImpor
508
676
  type: Optional
509
677
  }, {
510
678
  type: Inject,
511
- args: [LOCALIZE_FUNCTION]
679
+ args: [LOCALIZE_TRANSFORM]
512
680
  }] }];
513
681
  } });
514
682
 
@@ -517,31 +685,29 @@ class BbLocalize {
517
685
  this._localize = _localize;
518
686
  }
519
687
  transform(tokenOrParams, args) {
520
- // Validate that the localize service
521
- // exists in the pipe.
688
+ var _a;
689
+ // Combine the params with the options to form the localize params.
690
+ const params = this.combineParamsWithOptions(tokenOrParams, args);
691
+ // Validate that the localize service exists in the pipe.
522
692
  if (!this._localize) {
523
- return tokenOrParams;
693
+ return (_a = params === null || params === void 0 ? void 0 : params.token) !== null && _a !== void 0 ? _a : null;
524
694
  }
525
- // Combine the params with the options
526
- // to form the localize params.
527
- const params = this.combineParamsWithOptions(tokenOrParams, args);
528
695
  // Try to localize the value.
529
696
  return this._localize.translate(params);
530
697
  }
531
698
  combineParamsWithOptions(tokenOrParams, args) {
532
699
  // Gather the extras.
533
- const extras = args || {};
700
+ const extras = args !== null && args !== void 0 ? args : {};
534
701
  // Loop through all the keys to find the set options.
535
702
  const options = Object.keys(extras).reduce((previous, current) => {
536
- if (typeof extras[current] === 'undefined') {
703
+ if (typeof (extras === null || extras === void 0 ? void 0 : extras[current]) === 'undefined') {
537
704
  return previous;
538
705
  }
539
- previous[current] = extras[current];
540
- return previous;
706
+ return Object.assign(Object.assign({}, previous), { [current]: extras === null || extras === void 0 ? void 0 : extras[current] });
541
707
  }, {});
542
708
  // Convert the string token to a params object.
543
709
  const params = typeof tokenOrParams === 'string'
544
- ? { token: tokenOrParams, optional: false, data: {} }
710
+ ? { token: tokenOrParams, optional: false, data: {}, dictionary: null }
545
711
  : tokenOrParams;
546
712
  // Return the combined params and options.
547
713
  return Object.assign(Object.assign({}, params), options);
@@ -562,13 +728,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImpor
562
728
 
563
729
  class LocalizeModule {
564
730
  static forRoot(config) {
565
- var _a;
566
- const automatic = (_a = config === null || config === void 0 ? void 0 : config.automatic) !== null && _a !== void 0 ? _a : true;
731
+ var _a, _b;
732
+ if (((_a = config === null || config === void 0 ? void 0 : config.languages) === null || _a === void 0 ? void 0 : _a.length) <= 0) {
733
+ throw new Error('One or more languages should be supplied.');
734
+ }
735
+ const mode = (_b = config === null || config === void 0 ? void 0 : config.mode) !== null && _b !== void 0 ? _b : 'automatic';
567
736
  return {
568
737
  ngModule: LocalizeModule,
569
738
  providers: [
570
739
  // Angular providers.
571
- ...(automatic ? [
740
+ ...(mode === 'automatic' ? [
572
741
  { provide: APP_INITIALIZER, deps: [Localize], useFactory: initializeLocale, multi: true },
573
742
  { provide: LOCALE_ID, deps: [Localize], useFactory: getLocale }
574
743
  ] : []),
@@ -578,6 +747,9 @@ class LocalizeModule {
578
747
  { provide: LOCALIZE_FUNCTION, useClass: LocalizeLowercaseFunction, multi: true },
579
748
  { provide: LOCALIZE_FUNCTION, useClass: LocalizeUppercaseFunction, multi: true },
580
749
  { provide: LOCALIZE_FUNCTION, useClass: LocalizeDateFunction, multi: true },
750
+ // Transform providers.
751
+ { provide: LOCALIZE_TRANSFORM, useClass: LocalizeReferenceTransform, deps: [LocalizeConfig], multi: true },
752
+ { provide: LOCALIZE_TRANSFORM, useClass: LocalizeInterpolateTransform, deps: [LocalizeConfig, LOCALIZE_FUNCTION], multi: true },
581
753
  // Handler providers.
582
754
  { provide: LocalizeMissingHandler, useClass: LocalizeMissingHandler },
583
755
  // Service providers.
@@ -621,5 +793,5 @@ function getLocale(localize) {
621
793
  * Generated bundle index. Do not edit.
622
794
  */
623
795
 
624
- export { BbLocalize, BbLocalizeString, BbLocalizeTemplate, LOCALIZE_FUNCTION, Localize, LocalizeConfig, LocalizeDateFunction, LocalizeDictionary, LocalizeLowercaseFunction, LocalizeMissingHandler, LocalizeModule, LocalizeUppercaseFunction, extraDutchDictionary, extraEnglishDictionary, getLocale, initializeLocale };
796
+ export { BbLocalize, BbLocalizeString, BbLocalizeTemplate, LOCALIZE_FUNCTION, LOCALIZE_TRANSFORM, Localize, LocalizeConfig, LocalizeDateFunction, LocalizeDictionary, LocalizeDictionaryContext, LocalizeDictionaryData, LocalizeInterpolateTransform, LocalizeLowercaseFunction, LocalizeMissingHandler, LocalizeModule, LocalizeReferenceTransform, LocalizeTransform, LocalizeUppercaseFunction, extraDutchDictionary, extraEnglishDictionary, getLocale, initializeLocale };
625
797
  //# sourceMappingURL=bravobit-bb-foundation-localize.mjs.map