@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.
- package/elements/lib/pipes/relative-time.pipe.d.ts +1 -1
- package/esm2020/localize/lib/dictionary/dictionary.class.mjs +92 -0
- package/esm2020/localize/lib/dictionary/dictionary.context.mjs +26 -0
- package/esm2020/localize/lib/dictionary/dictionary.data.mjs +6 -0
- package/esm2020/localize/lib/functions/lowercase.function.mjs +2 -2
- package/esm2020/localize/lib/functions/uppercase.function.mjs +2 -2
- package/esm2020/localize/lib/handlers/missing.handler.mjs +2 -2
- package/esm2020/localize/lib/interfaces/config.interfaces.mjs +1 -1
- package/esm2020/localize/lib/interfaces/options.interfaces.mjs +1 -1
- package/esm2020/localize/lib/interfaces/transforms.interfaces.mjs +3 -0
- package/esm2020/localize/lib/localize.module.mjs +12 -3
- package/esm2020/localize/lib/localize.pipe.mjs +9 -12
- package/esm2020/localize/lib/localize.service.mjs +84 -128
- package/esm2020/localize/lib/transforms/abstract.transform.mjs +30 -0
- package/esm2020/localize/lib/transforms/interpolate.transform.mjs +54 -0
- package/esm2020/localize/lib/transforms/reference.transform.mjs +25 -0
- package/esm2020/localize/public_api.mjs +8 -2
- package/fesm2015/bravobit-bb-foundation-localize.mjs +347 -175
- package/fesm2015/bravobit-bb-foundation-localize.mjs.map +1 -1
- package/fesm2020/bravobit-bb-foundation-localize.mjs +327 -167
- package/fesm2020/bravobit-bb-foundation-localize.mjs.map +1 -1
- package/localize/lib/dictionary/dictionary.class.d.ts +28 -0
- package/localize/lib/dictionary/dictionary.context.d.ts +7 -0
- package/localize/lib/dictionary/dictionary.data.d.ts +7 -0
- package/localize/lib/interfaces/config.interfaces.d.ts +4 -6
- package/localize/lib/interfaces/options.interfaces.d.ts +1 -0
- package/localize/lib/interfaces/transforms.interfaces.d.ts +3 -0
- package/localize/lib/localize.module.d.ts +1 -1
- package/localize/lib/localize.pipe.d.ts +3 -3
- package/localize/lib/localize.service.d.ts +25 -21
- package/localize/lib/transforms/abstract.transform.d.ts +13 -0
- package/localize/lib/transforms/interpolate.transform.d.ts +14 -0
- package/localize/lib/transforms/reference.transform.d.ts +10 -0
- package/localize/public_api.d.ts +7 -1
- package/package.json +1 -1
- package/esm2020/localize/lib/localize.dictionary.mjs +0 -24
- 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,
|
|
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
|
|
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
|
|
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(`
|
|
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,
|
|
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.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
this.
|
|
311
|
-
this.
|
|
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.
|
|
357
|
-
}
|
|
358
|
-
async
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
if (this.
|
|
363
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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:
|
|
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:
|
|
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: [
|
|
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
|
-
//
|
|
505
|
-
|
|
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
|
|
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]
|
|
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
|
-
|
|
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
|