@bravobit/bb-foundation 0.22.4 → 0.23.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.
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 +11 -3
  12. package/esm2020/localize/lib/localize.pipe.mjs +4 -5
  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 +339 -167
  19. package/fesm2015/bravobit-bb-foundation-localize.mjs.map +1 -1
  20. package/fesm2020/bravobit-bb-foundation-localize.mjs +321 -160
  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 +1 -1
  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: {} };
528
+ return { token: tokenOrParams, optional: false, dictionary: null, data: {} };
322
529
  };
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);
337
- };
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);
544
+ }
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);
364
550
  }
365
- // Save the selected language in the storage.
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, {});
368
561
  }
562
+ const reload = options?.reload ?? false;
563
+ if (reload) {
564
+ this._window?.location?.reload?.();
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,8 +658,7 @@ 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
+ // Validate that the localize service exists in the pipe.
506
662
  if (!this._localize) {
507
663
  return tokenOrParams;
508
664
  }
@@ -514,7 +670,7 @@ class BbLocalize {
514
670
  }
515
671
  combineParamsWithOptions(tokenOrParams, args) {
516
672
  // Gather the extras.
517
- const extras = args || {};
673
+ const extras = args ?? {};
518
674
  // Loop through all the keys to find the set options.
519
675
  const options = Object.keys(extras).reduce((previous, current) => {
520
676
  if (typeof extras[current] === 'undefined') {
@@ -525,7 +681,7 @@ class BbLocalize {
525
681
  }, {});
526
682
  // Convert the string token to a params object.
527
683
  const params = typeof tokenOrParams === 'string'
528
- ? { token: tokenOrParams, optional: false, data: {} }
684
+ ? { token: tokenOrParams, optional: false, data: {}, dictionary: null }
529
685
  : tokenOrParams;
530
686
  // Return the combined params and options.
531
687
  return { ...params, ...options };
@@ -544,12 +700,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImpor
544
700
 
545
701
  class LocalizeModule {
546
702
  static forRoot(config) {
547
- const automatic = config?.automatic ?? true;
703
+ if (config?.languages?.length <= 0) {
704
+ throw new Error('One or more languages should be supplied.');
705
+ }
548
706
  return {
549
707
  ngModule: LocalizeModule,
550
708
  providers: [
551
709
  // Angular providers.
552
- ...(automatic ? [
710
+ ...(config?.mode === 'automatic' ? [
553
711
  { provide: APP_INITIALIZER, deps: [Localize], useFactory: initializeLocale, multi: true },
554
712
  { provide: LOCALE_ID, deps: [Localize], useFactory: getLocale }
555
713
  ] : []),
@@ -559,6 +717,9 @@ class LocalizeModule {
559
717
  { provide: LOCALIZE_FUNCTION, useClass: LocalizeLowercaseFunction, multi: true },
560
718
  { provide: LOCALIZE_FUNCTION, useClass: LocalizeUppercaseFunction, multi: true },
561
719
  { provide: LOCALIZE_FUNCTION, useClass: LocalizeDateFunction, multi: true },
720
+ // Transform providers.
721
+ { provide: LOCALIZE_TRANSFORM, useClass: LocalizeReferenceTransform, deps: [LocalizeConfig], multi: true },
722
+ { provide: LOCALIZE_TRANSFORM, useClass: LocalizeInterpolateTransform, deps: [LocalizeConfig, LOCALIZE_FUNCTION], multi: true },
562
723
  // Handler providers.
563
724
  { provide: LocalizeMissingHandler, useClass: LocalizeMissingHandler },
564
725
  // Service providers.
@@ -601,5 +762,5 @@ function getLocale(localize) {
601
762
  * Generated bundle index. Do not edit.
602
763
  */
603
764
 
604
- export { BbLocalize, BbLocalizeString, BbLocalizeTemplate, LOCALIZE_FUNCTION, Localize, LocalizeConfig, LocalizeDateFunction, LocalizeDictionary, LocalizeLowercaseFunction, LocalizeMissingHandler, LocalizeModule, LocalizeUppercaseFunction, extraDutchDictionary, extraEnglishDictionary, getLocale, initializeLocale };
765
+ 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
766
  //# sourceMappingURL=bravobit-bb-foundation-localize.mjs.map