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