@mmstack/translate 21.1.11 → 21.1.13
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/README.md +148 -26
- package/fesm2022/mmstack-translate.mjs +591 -143
- package/fesm2022/mmstack-translate.mjs.map +1 -1
- package/package.json +1 -1
- package/types/mmstack-translate.d.ts +396 -83
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { computed, inject, InjectionToken, LOCALE_ID, signal, isDevMode, effect, resource,
|
|
2
|
+
import { computed, inject, InjectionToken, LOCALE_ID, signal, untracked, isDevMode, effect, resource, Injectable, isSignal, input, Renderer2, ElementRef, afterRenderEffect, Directive, ChangeDetectorRef } from '@angular/core';
|
|
3
3
|
import { createIntlCache, createIntl } from '@formatjs/intl';
|
|
4
4
|
import { toSignal } from '@angular/core/rxjs-interop';
|
|
5
5
|
import { Router, ActivatedRoute } from '@angular/router';
|
|
6
|
+
import { inject as inject$1 } from '@angular/core/primitives/di';
|
|
6
7
|
|
|
7
8
|
const KEY_DELIM = '::MMT_DELIM::';
|
|
8
9
|
function prependDelim(prefix, key) {
|
|
@@ -132,9 +133,27 @@ function injectSupportedLocales() {
|
|
|
132
133
|
* the actual locale signal used to store the current locale string
|
|
133
134
|
*/
|
|
134
135
|
const STORE_LOCALE = signal('en-US', ...(ngDevMode ? [{ debugName: "STORE_LOCALE" }] : /* istanbul ignore next */ []));
|
|
136
|
+
/**
|
|
137
|
+
* @internal
|
|
138
|
+
* @deprecated will be removed when ng23 drops
|
|
139
|
+
*/
|
|
140
|
+
function readLocaleUnsafe() {
|
|
141
|
+
return STORE_LOCALE();
|
|
142
|
+
}
|
|
135
143
|
function injectLocaleInternal() {
|
|
136
144
|
return STORE_LOCALE;
|
|
137
145
|
}
|
|
146
|
+
function proxyToGlobalSignleton(src) {
|
|
147
|
+
const originalSet = src.set;
|
|
148
|
+
src.set = (next) => {
|
|
149
|
+
originalSet(next);
|
|
150
|
+
STORE_LOCALE.set(next);
|
|
151
|
+
};
|
|
152
|
+
src.update = (updater) => {
|
|
153
|
+
src.set(updater(untracked(src)));
|
|
154
|
+
};
|
|
155
|
+
return src;
|
|
156
|
+
}
|
|
138
157
|
function isDynamicConfig(cfg) {
|
|
139
158
|
return !!cfg && 'localeStorage' in cfg && !!cfg.localeStorage;
|
|
140
159
|
}
|
|
@@ -230,7 +249,7 @@ class TranslationStore {
|
|
|
230
249
|
messages: this.messages(),
|
|
231
250
|
}, this.cache), ...(ngDevMode ? [{ debugName: "intl" }] : /* istanbul ignore next */ []));
|
|
232
251
|
constructor() {
|
|
233
|
-
this.locale = initLocale(
|
|
252
|
+
this.locale = proxyToGlobalSignleton(initLocale(signal('en-US')));
|
|
234
253
|
const paramName = this.config?.localeParamName;
|
|
235
254
|
if (paramName) {
|
|
236
255
|
const param = pathParam(paramName);
|
|
@@ -320,10 +339,10 @@ class TranslationStore {
|
|
|
320
339
|
hasLocaleLoaders(locale) {
|
|
321
340
|
return Array.from(this.onDemandLoaders.values()).some((loaders) => loaders[locale]);
|
|
322
341
|
}
|
|
323
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
324
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
342
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TranslationStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
343
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TranslationStore, providedIn: 'root' });
|
|
325
344
|
}
|
|
326
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
345
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TranslationStore, decorators: [{
|
|
327
346
|
type: Injectable,
|
|
328
347
|
args: [{
|
|
329
348
|
providedIn: 'root',
|
|
@@ -380,6 +399,96 @@ function injectDynamicLocale() {
|
|
|
380
399
|
source.isLoading = store.dynamicLocaleLoader.isLoading;
|
|
381
400
|
return source;
|
|
382
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* Power-user escape hatch for adding translations imperatively (e.g. content
|
|
404
|
+
* loaded from a remote API after bootstrap). Returns a function that registers
|
|
405
|
+
* a flat per-locale map of keys under a given namespace
|
|
406
|
+
*
|
|
407
|
+
* Pair with {@link injectUnsafeT} to read the added keys without compile-time
|
|
408
|
+
* constraints.
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* ```ts
|
|
412
|
+
* const addTranslations = injectAddTranslations();
|
|
413
|
+
* addTranslations('remote', {
|
|
414
|
+
* 'en-US': { greeting: 'Hi {name}' },
|
|
415
|
+
* 'sl-SI': { greeting: 'Zdravo {name}' },
|
|
416
|
+
* });
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
function injectAddTranslations() {
|
|
420
|
+
const store = inject(TranslationStore);
|
|
421
|
+
const supportedLocales = injectIntlConfig()?.supportedLocales;
|
|
422
|
+
const supportedLocalesSet = supportedLocales
|
|
423
|
+
? new Set(supportedLocales)
|
|
424
|
+
: null;
|
|
425
|
+
const validate = supportedLocalesSet
|
|
426
|
+
? (translations) => {
|
|
427
|
+
const clean = {};
|
|
428
|
+
const invalidLocales = [];
|
|
429
|
+
for (const [locale, translation] of Object.entries(translations)) {
|
|
430
|
+
if (!supportedLocalesSet.has(locale)) {
|
|
431
|
+
invalidLocales.push(locale);
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
clean[locale] = translation;
|
|
435
|
+
}
|
|
436
|
+
if (isDevMode() && invalidLocales.length > 0)
|
|
437
|
+
console.warn(`[Translate] Attempted to add translations for unsupported locales: ${invalidLocales.join(', ')}. These translations were ignored. Supported locales are: ${(supportedLocales ?? []).join(', ')}.`);
|
|
438
|
+
return clean;
|
|
439
|
+
}
|
|
440
|
+
: (translations) => translations;
|
|
441
|
+
return (ns, translations) => {
|
|
442
|
+
store.register(ns, validate(translations));
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function equalLocale(a, b) {
|
|
447
|
+
return a.locale === b.locale;
|
|
448
|
+
}
|
|
449
|
+
function createFormatterProvider(formatterName, libraryDefaults, nonLocaleEqual) {
|
|
450
|
+
const token = new InjectionToken(`@mmstack/translate:format-${formatterName}-config`, {
|
|
451
|
+
factory: () => {
|
|
452
|
+
const loc = injectDynamicLocale();
|
|
453
|
+
return computed(() => ({
|
|
454
|
+
...libraryDefaults,
|
|
455
|
+
locale: loc(),
|
|
456
|
+
}), { equal: equalLocale });
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
const provider = (valueOrFn) => {
|
|
460
|
+
const fnProvider = typeof valueOrFn === 'function'
|
|
461
|
+
? valueOrFn
|
|
462
|
+
: () => valueOrFn;
|
|
463
|
+
return {
|
|
464
|
+
provide: token,
|
|
465
|
+
useFactory: () => {
|
|
466
|
+
const loc = injectDynamicLocale();
|
|
467
|
+
const providedDefaultsOrSignal = fnProvider();
|
|
468
|
+
if (isSignal(providedDefaultsOrSignal))
|
|
469
|
+
return computed(() => ({
|
|
470
|
+
...libraryDefaults,
|
|
471
|
+
...providedDefaultsOrSignal(),
|
|
472
|
+
locale: loc(),
|
|
473
|
+
}), {
|
|
474
|
+
equal: (a, b) => equalLocale(a, b) && nonLocaleEqual(a, b),
|
|
475
|
+
});
|
|
476
|
+
const defaults = {
|
|
477
|
+
...libraryDefaults,
|
|
478
|
+
...providedDefaultsOrSignal,
|
|
479
|
+
};
|
|
480
|
+
return computed(() => ({
|
|
481
|
+
...defaults,
|
|
482
|
+
locale: loc(),
|
|
483
|
+
}), {
|
|
484
|
+
equal: equalLocale,
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
};
|
|
489
|
+
const injectFn = () => inject$1(token);
|
|
490
|
+
return [provider, injectFn];
|
|
491
|
+
}
|
|
383
492
|
|
|
384
493
|
function unwrap(value) {
|
|
385
494
|
return isSignal(value) ? value() : value;
|
|
@@ -407,32 +516,68 @@ function validDateOrNull(date) {
|
|
|
407
516
|
}
|
|
408
517
|
const cache$4 = new Map();
|
|
409
518
|
function getFormatter$4(locale, format, timeZone) {
|
|
410
|
-
const cacheKey = `${locale}|${format}|${timeZone ?? ''}`;
|
|
519
|
+
const cacheKey = `${locale}|${typeof format === 'string' ? format : JSON.stringify(format)}|${timeZone ?? ''}`;
|
|
411
520
|
let formatter = cache$4.get(cacheKey);
|
|
412
521
|
if (!formatter) {
|
|
413
522
|
formatter = new Intl.DateTimeFormat(locale, {
|
|
414
|
-
...FORMAT_PRESETS[format],
|
|
523
|
+
...(typeof format === 'string' ? FORMAT_PRESETS[format] : format),
|
|
415
524
|
timeZone,
|
|
416
525
|
});
|
|
417
526
|
cache$4.set(cacheKey, formatter);
|
|
418
527
|
}
|
|
419
528
|
return formatter;
|
|
420
529
|
}
|
|
421
|
-
|
|
422
|
-
* Format a date using the current or provided locale & timezone
|
|
423
|
-
* By default it is reactive to the global dynamic locale, works best when wrapped in a computed() if you need to react to locale changes
|
|
424
|
-
*
|
|
425
|
-
* @param date - Date to format
|
|
426
|
-
* @param opt - Options for formatting
|
|
427
|
-
* @returns Formatted date string
|
|
428
|
-
*/
|
|
429
|
-
function formatDate(date, opt) {
|
|
530
|
+
function formatDate(date, optOrLocale) {
|
|
430
531
|
const validDate = validDateOrNull(unwrap(date));
|
|
431
532
|
if (validDate === null)
|
|
432
533
|
return '';
|
|
433
|
-
const
|
|
434
|
-
|
|
435
|
-
|
|
534
|
+
const unwrappedArgs = unwrap(optOrLocale);
|
|
535
|
+
let locale;
|
|
536
|
+
let format = 'medium';
|
|
537
|
+
let tz;
|
|
538
|
+
if (typeof unwrappedArgs === 'string') {
|
|
539
|
+
locale = unwrappedArgs;
|
|
540
|
+
}
|
|
541
|
+
else if (unwrappedArgs && typeof unwrappedArgs === 'object') {
|
|
542
|
+
locale = unwrappedArgs.locale ?? readLocaleUnsafe();
|
|
543
|
+
format = unwrappedArgs.format ?? 'medium';
|
|
544
|
+
tz = unwrappedArgs.tz;
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
locale = readLocaleUnsafe();
|
|
548
|
+
}
|
|
549
|
+
return getFormatter$4(locale, format, tz).format(validDate);
|
|
550
|
+
}
|
|
551
|
+
const [provideFormatDateDefaults, injectFormatDateOptions] = createFormatterProvider('date', {
|
|
552
|
+
format: 'medium',
|
|
553
|
+
}, (a, b) => {
|
|
554
|
+
if (a.tz !== b.tz)
|
|
555
|
+
return false;
|
|
556
|
+
if (a.format === b.format)
|
|
557
|
+
return true;
|
|
558
|
+
return JSON.stringify(a.format) === JSON.stringify(b.format);
|
|
559
|
+
});
|
|
560
|
+
/**
|
|
561
|
+
* Inject a context-safe date formatting function tied to the current injector.
|
|
562
|
+
* Uses the libraries locale signal & provided default configuration to react to locale/config changes
|
|
563
|
+
* @example
|
|
564
|
+
* const formatDate = injectFormatDate();
|
|
565
|
+
* readonly displayDate = computed(() => formatDate(this.date()));
|
|
566
|
+
*/
|
|
567
|
+
function injectFormatDate() {
|
|
568
|
+
const defaults = injectFormatDateOptions();
|
|
569
|
+
return (date, optOrLocale) => {
|
|
570
|
+
if (!optOrLocale)
|
|
571
|
+
return formatDate(date, defaults());
|
|
572
|
+
const unwrapped = unwrap(optOrLocale);
|
|
573
|
+
const opt = typeof unwrapped === 'object'
|
|
574
|
+
? { ...defaults(), ...unwrapped }
|
|
575
|
+
: {
|
|
576
|
+
...defaults(),
|
|
577
|
+
locale: unwrapped,
|
|
578
|
+
};
|
|
579
|
+
return formatDate(date, opt);
|
|
580
|
+
};
|
|
436
581
|
}
|
|
437
582
|
|
|
438
583
|
const cache$3 = new Map();
|
|
@@ -450,21 +595,48 @@ function getFormatter$3(locale, type, style) {
|
|
|
450
595
|
}
|
|
451
596
|
/**
|
|
452
597
|
* Format a display name using the current or provided locale
|
|
453
|
-
* By default it is reactive to the global dynamic locale, works best when wrapped in a computed() if you need to react to locale changes
|
|
454
598
|
*
|
|
455
599
|
* @param value - The code to format
|
|
456
600
|
* @param type - The type of display name to format
|
|
457
601
|
* @param opt - Options for formatting
|
|
458
602
|
* @returns Formatted display name string
|
|
459
603
|
*/
|
|
460
|
-
function formatDisplayName(value, type,
|
|
461
|
-
const
|
|
462
|
-
if (!
|
|
604
|
+
function formatDisplayName(value, type, localeOrOpt) {
|
|
605
|
+
const unwrappedValue = unwrap(value);
|
|
606
|
+
if (!unwrappedValue?.trim())
|
|
463
607
|
return '';
|
|
464
608
|
const unwrappedType = unwrap(type);
|
|
465
|
-
const
|
|
466
|
-
const locale =
|
|
467
|
-
|
|
609
|
+
const unwrapped = unwrap(localeOrOpt);
|
|
610
|
+
const locale = typeof unwrapped === 'string'
|
|
611
|
+
? unwrapped
|
|
612
|
+
: (unwrapped?.locale ?? readLocaleUnsafe());
|
|
613
|
+
const opt = typeof unwrapped === 'object' ? unwrapped : undefined;
|
|
614
|
+
return (getFormatter$3(locale, unwrappedType, opt?.style ?? 'long').of(unwrappedValue) ?? '');
|
|
615
|
+
}
|
|
616
|
+
const [provideFormatDisplayNameDefaults, injectFormatDisplayNameDefaults] = createFormatterProvider('displayName', {
|
|
617
|
+
style: 'long',
|
|
618
|
+
}, (a, b) => a.style === b.style);
|
|
619
|
+
/**
|
|
620
|
+
* Inject a context-safe date formatting function tied to the current injector.
|
|
621
|
+
* Uses the libraries locale signal & provided default configuration to react to locale/config changes
|
|
622
|
+
* @example
|
|
623
|
+
* const formatDisplayName = injectFormatDisplayName();
|
|
624
|
+
* readonly region = computed(() => formatDisplayName('US', 'region'));
|
|
625
|
+
*/
|
|
626
|
+
function injectFormatDisplayName() {
|
|
627
|
+
const defaults = injectFormatDisplayNameDefaults();
|
|
628
|
+
return (value, type, localeOrOpt) => {
|
|
629
|
+
if (!localeOrOpt)
|
|
630
|
+
return formatDisplayName(value, type, defaults());
|
|
631
|
+
const unwrapped = unwrap(localeOrOpt);
|
|
632
|
+
const opt = typeof unwrapped === 'object'
|
|
633
|
+
? { ...defaults, ...unwrapped }
|
|
634
|
+
: {
|
|
635
|
+
...defaults,
|
|
636
|
+
locale: unwrapped,
|
|
637
|
+
};
|
|
638
|
+
return formatDisplayName(value, type, opt);
|
|
639
|
+
};
|
|
468
640
|
}
|
|
469
641
|
|
|
470
642
|
const cache$2 = new Map();
|
|
@@ -482,21 +654,52 @@ function getFormatter$2(locale, type, style) {
|
|
|
482
654
|
}
|
|
483
655
|
return formatter;
|
|
484
656
|
}
|
|
657
|
+
function formatList(value, optOrLocale) {
|
|
658
|
+
const unwrappedValue = unwrapList(value);
|
|
659
|
+
if (unwrappedValue.length === 0)
|
|
660
|
+
return '';
|
|
661
|
+
const unwrappedArgs = unwrap(optOrLocale);
|
|
662
|
+
let locale;
|
|
663
|
+
let type = 'conjunction';
|
|
664
|
+
let style = 'long';
|
|
665
|
+
if (typeof unwrappedArgs === 'string') {
|
|
666
|
+
locale = unwrappedArgs;
|
|
667
|
+
}
|
|
668
|
+
else if (unwrappedArgs && typeof unwrappedArgs === 'object') {
|
|
669
|
+
locale = unwrappedArgs.locale ?? readLocaleUnsafe();
|
|
670
|
+
type = unwrappedArgs.type ?? 'conjunction';
|
|
671
|
+
style = unwrappedArgs.style ?? 'long';
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
locale = readLocaleUnsafe();
|
|
675
|
+
}
|
|
676
|
+
return getFormatter$2(locale, type, style).format(unwrappedValue);
|
|
677
|
+
}
|
|
678
|
+
const [provideFormatListDefaults, injectFormatListOptions] = createFormatterProvider('list', {
|
|
679
|
+
type: 'conjunction',
|
|
680
|
+
style: 'long',
|
|
681
|
+
}, (a, b) => a.type === b.type && a.style === b.style);
|
|
485
682
|
/**
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
* @returns Formatted list string
|
|
683
|
+
* Inject a context-safe list formatting function tied to the current injector.
|
|
684
|
+
* Uses the libraries locale signal & provided default configuration to react to locale/config changes
|
|
685
|
+
* @example
|
|
686
|
+
* const formatList = injectFormatList();
|
|
687
|
+
* readonly displayList = computed(() => formatList(this.items()));
|
|
492
688
|
*/
|
|
493
|
-
function
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
689
|
+
function injectFormatList() {
|
|
690
|
+
const defaults = injectFormatListOptions();
|
|
691
|
+
return (value, optOrLocale) => {
|
|
692
|
+
if (!optOrLocale)
|
|
693
|
+
return formatList(value, defaults());
|
|
694
|
+
const unwrapped = unwrap(optOrLocale);
|
|
695
|
+
const opt = typeof unwrapped === 'object'
|
|
696
|
+
? { ...defaults(), ...unwrapped }
|
|
697
|
+
: {
|
|
698
|
+
...defaults(),
|
|
699
|
+
locale: unwrapped,
|
|
700
|
+
};
|
|
701
|
+
return formatList(value, opt);
|
|
702
|
+
};
|
|
500
703
|
}
|
|
501
704
|
|
|
502
705
|
const cache$1 = new Map();
|
|
@@ -523,45 +726,151 @@ function getFormatter$1(locale, minFractionDigits, maxFractionDigits, useGroupin
|
|
|
523
726
|
}
|
|
524
727
|
return formatter;
|
|
525
728
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
* @param opt - Options for formatting
|
|
532
|
-
* @returns Formatted number string
|
|
533
|
-
*/
|
|
534
|
-
function formatNumber(value, opt) {
|
|
535
|
-
const unwrappedOpt = unwrap(opt);
|
|
536
|
-
const unwrappedNumber = unwrapValue(value, unwrappedOpt?.fallbackToZero);
|
|
729
|
+
function formatNumber(value, optOrLocale) {
|
|
730
|
+
const unwrappedArgs = unwrap(optOrLocale);
|
|
731
|
+
const isOpt = unwrappedArgs != null && typeof unwrappedArgs === 'object';
|
|
732
|
+
const fallbackToZero = isOpt ? unwrappedArgs.fallbackToZero : undefined;
|
|
733
|
+
const unwrappedNumber = unwrapValue(value, fallbackToZero);
|
|
537
734
|
if (unwrappedNumber === null)
|
|
538
735
|
return '';
|
|
539
|
-
|
|
540
|
-
|
|
736
|
+
let locale;
|
|
737
|
+
let notation;
|
|
738
|
+
let minFractionDigits;
|
|
739
|
+
let maxFractionDigits;
|
|
740
|
+
let useGrouping = true;
|
|
741
|
+
if (typeof unwrappedArgs === 'string') {
|
|
742
|
+
locale = unwrappedArgs;
|
|
743
|
+
}
|
|
744
|
+
else if (isOpt) {
|
|
745
|
+
locale = unwrappedArgs.locale ?? readLocaleUnsafe();
|
|
746
|
+
notation = unwrappedArgs.notation ?? 'standard';
|
|
747
|
+
minFractionDigits = unwrappedArgs.minFractionDigits;
|
|
748
|
+
maxFractionDigits = unwrappedArgs.maxFractionDigits;
|
|
749
|
+
useGrouping = unwrappedArgs.useGrouping ?? true;
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
locale = readLocaleUnsafe();
|
|
753
|
+
notation = 'standard';
|
|
754
|
+
}
|
|
755
|
+
return getFormatter$1(locale, minFractionDigits, maxFractionDigits, useGrouping, notation).format(unwrappedNumber);
|
|
541
756
|
}
|
|
757
|
+
const [provideFormatNumberDefaults, injectFormatNumberOptions] = createFormatterProvider('number', {
|
|
758
|
+
notation: 'standard',
|
|
759
|
+
useGrouping: true,
|
|
760
|
+
}, (a, b) => a.notation === b.notation &&
|
|
761
|
+
a.minFractionDigits === b.minFractionDigits &&
|
|
762
|
+
a.maxFractionDigits === b.maxFractionDigits &&
|
|
763
|
+
a.useGrouping === b.useGrouping &&
|
|
764
|
+
a.fallbackToZero === b.fallbackToZero);
|
|
542
765
|
/**
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
* @returns Formatted percentage string
|
|
766
|
+
* Inject a context-safe number formatting function tied to the current injector.
|
|
767
|
+
* Uses the libraries locale signal & provided default configuration to react to locale/config changes
|
|
768
|
+
* @example
|
|
769
|
+
* const formatNumber = injectFormatNumber();
|
|
770
|
+
* readonly display = computed(() => formatNumber(this.value()));
|
|
549
771
|
*/
|
|
550
|
-
function
|
|
551
|
-
const
|
|
552
|
-
|
|
772
|
+
function injectFormatNumber() {
|
|
773
|
+
const defaults = injectFormatNumberOptions();
|
|
774
|
+
return (value, optOrLocale) => {
|
|
775
|
+
if (!optOrLocale)
|
|
776
|
+
return formatNumber(value, defaults());
|
|
777
|
+
const unwrapped = unwrap(optOrLocale);
|
|
778
|
+
const opt = typeof unwrapped === 'object'
|
|
779
|
+
? { ...defaults(), ...unwrapped }
|
|
780
|
+
: {
|
|
781
|
+
...defaults(),
|
|
782
|
+
locale: unwrapped,
|
|
783
|
+
};
|
|
784
|
+
return formatNumber(value, opt);
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function formatPercent(value, optOrLocale) {
|
|
788
|
+
const unwrappedArgs = unwrap(optOrLocale);
|
|
789
|
+
const isOpt = unwrappedArgs != null && typeof unwrappedArgs === 'object';
|
|
790
|
+
const fallbackToZero = isOpt ? unwrappedArgs.fallbackToZero : undefined;
|
|
791
|
+
const unwrappedNumber = unwrapValue(value, fallbackToZero);
|
|
553
792
|
if (unwrappedNumber === null)
|
|
554
793
|
return '';
|
|
555
|
-
|
|
556
|
-
|
|
794
|
+
let locale;
|
|
795
|
+
let minFractionDigits;
|
|
796
|
+
let maxFractionDigits;
|
|
797
|
+
if (typeof unwrappedArgs === 'string') {
|
|
798
|
+
locale = unwrappedArgs;
|
|
799
|
+
}
|
|
800
|
+
else if (isOpt) {
|
|
801
|
+
locale = unwrappedArgs.locale ?? readLocaleUnsafe();
|
|
802
|
+
minFractionDigits = unwrappedArgs.minFractionDigits;
|
|
803
|
+
maxFractionDigits = unwrappedArgs.maxFractionDigits;
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
locale = readLocaleUnsafe();
|
|
807
|
+
}
|
|
808
|
+
return getFormatter$1(locale, minFractionDigits, maxFractionDigits, undefined, undefined, undefined, undefined, 'percent').format(unwrappedNumber);
|
|
557
809
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
810
|
+
const [provideFormatPercentDefaults, injectFormatPercentOptions] = createFormatterProvider('percent', {}, (a, b) => a.minFractionDigits === b.minFractionDigits &&
|
|
811
|
+
a.maxFractionDigits === b.maxFractionDigits &&
|
|
812
|
+
a.fallbackToZero === b.fallbackToZero);
|
|
813
|
+
/**
|
|
814
|
+
* Inject a context-safe percent formatting function tied to the current injector.
|
|
815
|
+
* Uses the libraries locale signal & provided default configuration to react to locale/config changes
|
|
816
|
+
*/
|
|
817
|
+
function injectFormatPercent() {
|
|
818
|
+
const defaults = injectFormatPercentOptions();
|
|
819
|
+
return (value, optOrLocale) => {
|
|
820
|
+
if (!optOrLocale)
|
|
821
|
+
return formatPercent(value, defaults());
|
|
822
|
+
const unwrapped = unwrap(optOrLocale);
|
|
823
|
+
const opt = typeof unwrapped === 'object'
|
|
824
|
+
? { ...defaults(), ...unwrapped }
|
|
825
|
+
: {
|
|
826
|
+
...defaults(),
|
|
827
|
+
locale: unwrapped,
|
|
828
|
+
};
|
|
829
|
+
return formatPercent(value, opt);
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
function formatCurrency(value, currency, optOrLocale) {
|
|
833
|
+
const unwrappedArgs = unwrap(optOrLocale);
|
|
834
|
+
const isOpt = unwrappedArgs != null && typeof unwrappedArgs === 'object';
|
|
835
|
+
const fallbackToZero = isOpt ? unwrappedArgs.fallbackToZero : undefined;
|
|
836
|
+
const unwrappedValue = unwrapValue(value, fallbackToZero);
|
|
561
837
|
if (unwrappedValue === null)
|
|
562
838
|
return '';
|
|
563
|
-
|
|
564
|
-
|
|
839
|
+
let locale;
|
|
840
|
+
let display = 'symbol';
|
|
841
|
+
if (typeof unwrappedArgs === 'string') {
|
|
842
|
+
locale = unwrappedArgs;
|
|
843
|
+
}
|
|
844
|
+
else if (isOpt) {
|
|
845
|
+
locale = unwrappedArgs.locale ?? readLocaleUnsafe();
|
|
846
|
+
display = unwrappedArgs.display ?? 'symbol';
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
locale = readLocaleUnsafe();
|
|
850
|
+
}
|
|
851
|
+
return getFormatter$1(locale, undefined, undefined, undefined, undefined, unwrap(currency), display, 'currency').format(unwrappedValue);
|
|
852
|
+
}
|
|
853
|
+
const [provideFormatCurrencyDefaults, injectFormatCurrencyOptions] = createFormatterProvider('currency', {
|
|
854
|
+
display: 'symbol',
|
|
855
|
+
}, (a, b) => a.display === b.display && a.fallbackToZero === b.fallbackToZero);
|
|
856
|
+
/**
|
|
857
|
+
* Inject a context-safe currency formatting function tied to the current injector.
|
|
858
|
+
* Uses the libraries locale signal & provided default configuration to react to locale/config changes
|
|
859
|
+
*/
|
|
860
|
+
function injectFormatCurrency() {
|
|
861
|
+
const defaults = injectFormatCurrencyOptions();
|
|
862
|
+
return (value, currency, optOrLocale) => {
|
|
863
|
+
if (!optOrLocale)
|
|
864
|
+
return formatCurrency(value, currency, defaults());
|
|
865
|
+
const unwrapped = unwrap(optOrLocale);
|
|
866
|
+
const opt = typeof unwrapped === 'object'
|
|
867
|
+
? { ...defaults(), ...unwrapped }
|
|
868
|
+
: {
|
|
869
|
+
...defaults(),
|
|
870
|
+
locale: unwrapped,
|
|
871
|
+
};
|
|
872
|
+
return formatCurrency(value, currency, opt);
|
|
873
|
+
};
|
|
565
874
|
}
|
|
566
875
|
|
|
567
876
|
const cache = new Map();
|
|
@@ -574,16 +883,7 @@ function getFormatter(locale, style, numeric) {
|
|
|
574
883
|
}
|
|
575
884
|
return formatter;
|
|
576
885
|
}
|
|
577
|
-
|
|
578
|
-
* Format a relative time using the current or provided locale
|
|
579
|
-
* By default it is reactive to the global dynamic locale, works best when wrapped in a computed() if you need to react to locale changes
|
|
580
|
-
*
|
|
581
|
-
* @param value - The numeric value to use in the relative time internationalization message
|
|
582
|
-
* @param unit - The unit to use in the relative time internationalization message
|
|
583
|
-
* @param opt - Options for formatting
|
|
584
|
-
* @returns Formatted relative time string
|
|
585
|
-
*/
|
|
586
|
-
function formatRelativeTime(value, unit, opt) {
|
|
886
|
+
function formatRelativeTime(value, unit, optOrLocale) {
|
|
587
887
|
const unwrappedValue = unwrap(value);
|
|
588
888
|
if (unwrappedValue === null ||
|
|
589
889
|
unwrappedValue === undefined ||
|
|
@@ -592,9 +892,78 @@ function formatRelativeTime(value, unit, opt) {
|
|
|
592
892
|
const unwrappedUnit = unwrap(unit);
|
|
593
893
|
if (!unwrappedUnit)
|
|
594
894
|
return '';
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
895
|
+
const unwrappedArgs = unwrap(optOrLocale);
|
|
896
|
+
let locale;
|
|
897
|
+
let style = 'long';
|
|
898
|
+
let numeric = 'always';
|
|
899
|
+
if (typeof unwrappedArgs === 'string') {
|
|
900
|
+
locale = unwrappedArgs;
|
|
901
|
+
}
|
|
902
|
+
else if (unwrappedArgs && typeof unwrappedArgs === 'object') {
|
|
903
|
+
locale = unwrappedArgs.locale ?? readLocaleUnsafe();
|
|
904
|
+
style = unwrappedArgs.style ?? 'long';
|
|
905
|
+
numeric = unwrappedArgs.numeric ?? 'always';
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
locale = readLocaleUnsafe();
|
|
909
|
+
}
|
|
910
|
+
return getFormatter(locale, style, numeric).format(unwrappedValue, unwrappedUnit);
|
|
911
|
+
}
|
|
912
|
+
const [provideFormatRelativeTimeDefaults, injectFormatRelativeTimeOptions] = createFormatterProvider('relativeTime', {
|
|
913
|
+
style: 'long',
|
|
914
|
+
numeric: 'always',
|
|
915
|
+
}, (a, b) => a.style === b.style && a.numeric === b.numeric);
|
|
916
|
+
/**
|
|
917
|
+
* Inject a context-safe relative time formatting function tied to the current injector.
|
|
918
|
+
* Uses the libraries locale signal & provided default configuration to react to locale/config changes
|
|
919
|
+
* @example
|
|
920
|
+
* const formatRelativeTime = injectFormatRelativeTime();
|
|
921
|
+
* readonly relativeAge = computed(() => formatRelativeTime(this.delta(), 'day'));
|
|
922
|
+
*/
|
|
923
|
+
function injectFormatRelativeTime() {
|
|
924
|
+
const defaults = injectFormatRelativeTimeOptions();
|
|
925
|
+
return (value, unit, optOrLocale) => {
|
|
926
|
+
if (!optOrLocale)
|
|
927
|
+
return formatRelativeTime(value, unit, defaults());
|
|
928
|
+
const unwrapped = unwrap(optOrLocale);
|
|
929
|
+
const opt = typeof unwrapped === 'object'
|
|
930
|
+
? { ...defaults(), ...unwrapped }
|
|
931
|
+
: {
|
|
932
|
+
...defaults(),
|
|
933
|
+
locale: unwrapped,
|
|
934
|
+
};
|
|
935
|
+
return formatRelativeTime(value, unit, opt);
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
function provideFormatDefaults(cfg) {
|
|
940
|
+
const providers = [];
|
|
941
|
+
if (cfg.date)
|
|
942
|
+
providers.push(provideFormatDateDefaults(cfg.date));
|
|
943
|
+
if (cfg.displayName)
|
|
944
|
+
providers.push(provideFormatDisplayNameDefaults(cfg.displayName));
|
|
945
|
+
if (cfg.list)
|
|
946
|
+
providers.push(provideFormatListDefaults(cfg.list));
|
|
947
|
+
if (cfg.relativeTime)
|
|
948
|
+
providers.push(provideFormatRelativeTimeDefaults(cfg.relativeTime));
|
|
949
|
+
if (cfg.number)
|
|
950
|
+
providers.push(provideFormatNumberDefaults(cfg.number));
|
|
951
|
+
if (cfg.percent)
|
|
952
|
+
providers.push(provideFormatPercentDefaults(cfg.percent));
|
|
953
|
+
if (cfg.currency)
|
|
954
|
+
providers.push(provideFormatCurrencyDefaults(cfg.currency));
|
|
955
|
+
return providers;
|
|
956
|
+
}
|
|
957
|
+
function injectFormatters() {
|
|
958
|
+
return {
|
|
959
|
+
date: injectFormatDate(),
|
|
960
|
+
displayName: injectFormatDisplayName(),
|
|
961
|
+
list: injectFormatList(),
|
|
962
|
+
relativeTime: injectFormatRelativeTime(),
|
|
963
|
+
number: injectFormatNumber(),
|
|
964
|
+
percent: injectFormatPercent(),
|
|
965
|
+
currency: injectFormatCurrency(),
|
|
966
|
+
};
|
|
598
967
|
}
|
|
599
968
|
|
|
600
969
|
function injectResolveParamLocale(snapshot) {
|
|
@@ -807,6 +1176,58 @@ function registerRemoteNamespace(ns, defaultTranslation, other) {
|
|
|
807
1176
|
resolveNamespaceTranslation: resolver,
|
|
808
1177
|
};
|
|
809
1178
|
}
|
|
1179
|
+
class UnsafeTKeyMap {
|
|
1180
|
+
map = new Map();
|
|
1181
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UnsafeTKeyMap, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1182
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UnsafeTKeyMap, providedIn: 'root' });
|
|
1183
|
+
}
|
|
1184
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: UnsafeTKeyMap, decorators: [{
|
|
1185
|
+
type: Injectable,
|
|
1186
|
+
args: [{
|
|
1187
|
+
providedIn: 'root',
|
|
1188
|
+
}]
|
|
1189
|
+
}] });
|
|
1190
|
+
/**
|
|
1191
|
+
* Power-user escape hatch that returns a fully untyped translation function.
|
|
1192
|
+
* Intended for use alongside {@link injectAddTranslations} when translations
|
|
1193
|
+
* are added imperatively (e.g. from a remote API), or for cross-namespace
|
|
1194
|
+
* lookups where the typed API would be impractical.
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```ts
|
|
1198
|
+
* const t = injectUnsafeT();
|
|
1199
|
+
* t('any.namespace.key', { name: 'Alice', count: 3 });
|
|
1200
|
+
* const sig = t.asSignal('any.namespace.key', () => ({ name: name() }));
|
|
1201
|
+
* ```
|
|
1202
|
+
*/
|
|
1203
|
+
function injectUnsafeT() {
|
|
1204
|
+
const store = inject(TranslationStore);
|
|
1205
|
+
const map = inject(UnsafeTKeyMap).map;
|
|
1206
|
+
const fn = (key, params) => {
|
|
1207
|
+
let k = map.get(key);
|
|
1208
|
+
if (k === undefined) {
|
|
1209
|
+
k = replaceWithDelim(key);
|
|
1210
|
+
map.set(key, k);
|
|
1211
|
+
}
|
|
1212
|
+
return store.formatMessage(k, params);
|
|
1213
|
+
};
|
|
1214
|
+
fn.asSignal = (key, params) => {
|
|
1215
|
+
let k = map.get(key);
|
|
1216
|
+
if (k === undefined) {
|
|
1217
|
+
k = replaceWithDelim(key);
|
|
1218
|
+
map.set(key, k);
|
|
1219
|
+
}
|
|
1220
|
+
if (!params)
|
|
1221
|
+
return store.buildSimpleKeySignal(k);
|
|
1222
|
+
const paramsSignal = isSignal(params)
|
|
1223
|
+
? params
|
|
1224
|
+
: computed(() => params(), {
|
|
1225
|
+
equal: createEqualsRecord(Object.keys(params())),
|
|
1226
|
+
});
|
|
1227
|
+
return computed(() => store.formatMessage(k, paramsSignal()));
|
|
1228
|
+
};
|
|
1229
|
+
return fn;
|
|
1230
|
+
}
|
|
810
1231
|
|
|
811
1232
|
/**
|
|
812
1233
|
* Guard that validates the locale parameter against supported locales.
|
|
@@ -837,6 +1258,72 @@ function canMatchLocale(prefixSegments = []) {
|
|
|
837
1258
|
};
|
|
838
1259
|
}
|
|
839
1260
|
|
|
1261
|
+
/**
|
|
1262
|
+
* Provides an isolated mock `TranslationStore` usable across testing modules that use components
|
|
1263
|
+
* depending on `@mmstack/translate` APIs (like `Translate` directive, `Translator` pipe, or `injectNamespaceT`).
|
|
1264
|
+
*
|
|
1265
|
+
* This provider intercepts all translation logic, bypassing chunk loaders and Intl.
|
|
1266
|
+
* When a custom configuration isn't provided, formatMessage simply echoes the translation key, using dots `.`.
|
|
1267
|
+
*
|
|
1268
|
+
* ### Usage
|
|
1269
|
+
* ```typescript
|
|
1270
|
+
* TestBed.configureTestingModule({
|
|
1271
|
+
* providers: [provideMockTranslations()]
|
|
1272
|
+
* });
|
|
1273
|
+
* ```
|
|
1274
|
+
*/
|
|
1275
|
+
function provideMockTranslations(options) {
|
|
1276
|
+
// We compile the mock strings to flat delimiters just like the internal compile module.
|
|
1277
|
+
const mappedMocks = {};
|
|
1278
|
+
if (options?.translations) {
|
|
1279
|
+
for (const [namespace, translationObj] of Object.entries(options.translations)) {
|
|
1280
|
+
const compiled = compileTranslation(translationObj, namespace);
|
|
1281
|
+
for (const [key, val] of Object.entries(compiled.flat)) {
|
|
1282
|
+
// e.g. from 'home::MMT_DELIM::title'
|
|
1283
|
+
const fullKey = `${namespace}::MMT_DELIM::${key}`;
|
|
1284
|
+
mappedMocks[fullKey] = val;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
const locale = options?.locale ?? 'en-US';
|
|
1289
|
+
let intl;
|
|
1290
|
+
if (options?.formatValues) {
|
|
1291
|
+
intl = createIntl({ locale, messages: mappedMocks }, createIntlCache());
|
|
1292
|
+
}
|
|
1293
|
+
return [
|
|
1294
|
+
{
|
|
1295
|
+
provide: TranslationStore,
|
|
1296
|
+
useValue: {
|
|
1297
|
+
locale: signal(locale),
|
|
1298
|
+
formatMessage: (key, values) => {
|
|
1299
|
+
const message = mappedMocks[key];
|
|
1300
|
+
if (!message) {
|
|
1301
|
+
// Fallback to echoing the key back in dot notation (more readable for unit assertions).
|
|
1302
|
+
return key.replaceAll('::MMT_DELIM::', '.');
|
|
1303
|
+
}
|
|
1304
|
+
if (intl) {
|
|
1305
|
+
return intl.formatMessage({ id: key, defaultMessage: message }, values);
|
|
1306
|
+
}
|
|
1307
|
+
return message;
|
|
1308
|
+
},
|
|
1309
|
+
hasLocaleLoaders: () => false,
|
|
1310
|
+
register: () => {
|
|
1311
|
+
// noop
|
|
1312
|
+
},
|
|
1313
|
+
registerOnDemandLoaders: () => {
|
|
1314
|
+
// noop
|
|
1315
|
+
},
|
|
1316
|
+
dynamicLocaleLoader: {
|
|
1317
|
+
isLoading: signal(false),
|
|
1318
|
+
value: signal(null),
|
|
1319
|
+
error: signal(null),
|
|
1320
|
+
},
|
|
1321
|
+
loadQueue: signal([]),
|
|
1322
|
+
},
|
|
1323
|
+
},
|
|
1324
|
+
];
|
|
1325
|
+
}
|
|
1326
|
+
|
|
840
1327
|
function compareObjects(a, b) {
|
|
841
1328
|
if (!a && !b)
|
|
842
1329
|
return true;
|
|
@@ -875,10 +1362,10 @@ class Translate {
|
|
|
875
1362
|
},
|
|
876
1363
|
});
|
|
877
1364
|
}
|
|
878
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
879
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.
|
|
1365
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: Translate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1366
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.12", type: Translate, isStandalone: true, inputs: { translate: { classPropertyName: "translate", publicName: "translate", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
880
1367
|
}
|
|
881
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1368
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: Translate, decorators: [{
|
|
882
1369
|
type: Directive
|
|
883
1370
|
}], ctorParameters: () => [], propDecorators: { translate: [{ type: i0.Input, args: [{ isSignal: true, alias: "translate", required: true }] }] } });
|
|
884
1371
|
|
|
@@ -906,74 +1393,35 @@ class Translator {
|
|
|
906
1393
|
}
|
|
907
1394
|
|
|
908
1395
|
/**
|
|
909
|
-
*
|
|
910
|
-
*
|
|
1396
|
+
* Power-user escape hatch for ICU messages whose parameters can't be inferred
|
|
1397
|
+
* from the message string — typically variables nested inside `plural` /
|
|
1398
|
+
* `select` / `selectordinal` arms, which the type-level extractor skips.
|
|
911
1399
|
*
|
|
912
|
-
*
|
|
913
|
-
*
|
|
1400
|
+
* Declared params are merged with auto-extracted ones; on key conflict, the
|
|
1401
|
+
* declared params win. Non-default locales for a key wrapped with `withParams`
|
|
1402
|
+
* may be plain strings — they don't need to repeat the wrapper.
|
|
914
1403
|
*
|
|
915
|
-
*
|
|
916
|
-
* ```
|
|
917
|
-
*
|
|
918
|
-
*
|
|
1404
|
+
* @example
|
|
1405
|
+
* ```ts
|
|
1406
|
+
* const ns = createNamespace('quote', {
|
|
1407
|
+
* // auto-extracts `count`; `name` is declared explicitly because it
|
|
1408
|
+
* // lives inside the plural arms and can't be inferred
|
|
1409
|
+
* stats: withParams<{ name: string }>(
|
|
1410
|
+
* '{count, plural, one {1 quote from {name}} other {# quotes from {name}}}',
|
|
1411
|
+
* ),
|
|
919
1412
|
* });
|
|
1413
|
+
*
|
|
1414
|
+
* // t inferred as: (key, { count: number; name: string }) => string
|
|
1415
|
+
* t('quote.stats', { count: 3, name: 'Alice' });
|
|
920
1416
|
* ```
|
|
921
1417
|
*/
|
|
922
|
-
function
|
|
923
|
-
|
|
924
|
-
const mappedMocks = {};
|
|
925
|
-
if (options?.translations) {
|
|
926
|
-
for (const [namespace, translationObj] of Object.entries(options.translations)) {
|
|
927
|
-
const compiled = compileTranslation(translationObj, namespace);
|
|
928
|
-
for (const [key, val] of Object.entries(compiled.flat)) {
|
|
929
|
-
// e.g. from 'home::MMT_DELIM::title'
|
|
930
|
-
const fullKey = `${namespace}::MMT_DELIM::${key}`;
|
|
931
|
-
mappedMocks[fullKey] = val;
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
const locale = options?.locale ?? 'en-US';
|
|
936
|
-
let intl;
|
|
937
|
-
if (options?.formatValues) {
|
|
938
|
-
intl = createIntl({ locale, messages: mappedMocks }, createIntlCache());
|
|
939
|
-
}
|
|
940
|
-
return [
|
|
941
|
-
{
|
|
942
|
-
provide: TranslationStore,
|
|
943
|
-
useValue: {
|
|
944
|
-
locale: signal(locale),
|
|
945
|
-
formatMessage: (key, values) => {
|
|
946
|
-
const message = mappedMocks[key];
|
|
947
|
-
if (!message) {
|
|
948
|
-
// Fallback to echoing the key back in dot notation (more readable for unit assertions).
|
|
949
|
-
return key.replaceAll('::MMT_DELIM::', '.');
|
|
950
|
-
}
|
|
951
|
-
if (intl) {
|
|
952
|
-
return intl.formatMessage({ id: key, defaultMessage: message }, values);
|
|
953
|
-
}
|
|
954
|
-
return message;
|
|
955
|
-
},
|
|
956
|
-
hasLocaleLoaders: () => false,
|
|
957
|
-
register: () => {
|
|
958
|
-
// noop
|
|
959
|
-
},
|
|
960
|
-
registerOnDemandLoaders: () => {
|
|
961
|
-
// noop
|
|
962
|
-
},
|
|
963
|
-
dynamicLocaleLoader: {
|
|
964
|
-
isLoading: signal(false),
|
|
965
|
-
value: signal(null),
|
|
966
|
-
error: signal(null),
|
|
967
|
-
},
|
|
968
|
-
loadQueue: signal([]),
|
|
969
|
-
},
|
|
970
|
-
},
|
|
971
|
-
];
|
|
1418
|
+
function withParams(message) {
|
|
1419
|
+
return message;
|
|
972
1420
|
}
|
|
973
1421
|
|
|
974
1422
|
/**
|
|
975
1423
|
* Generated bundle index. Do not edit.
|
|
976
1424
|
*/
|
|
977
1425
|
|
|
978
|
-
export { Translate, Translator, canMatchLocale, compileTranslation, createNamespace, formatCurrency, formatDate, formatDisplayName, formatList, formatNumber, formatPercent, formatRelativeTime, injectDynamicLocale, injectIntl, injectResolveParamLocale, injectSupportedLocales, provideIntlConfig, provideMockTranslations, registerNamespace, registerRemoteNamespace };
|
|
1426
|
+
export { Translate, Translator, canMatchLocale, compileTranslation, createNamespace, formatCurrency, formatDate, formatDisplayName, formatList, formatNumber, formatPercent, formatRelativeTime, injectAddTranslations, injectDynamicLocale, injectFormatCurrency, injectFormatDate, injectFormatDisplayName, injectFormatList, injectFormatNumber, injectFormatPercent, injectFormatRelativeTime, injectFormatters, injectIntl, injectResolveParamLocale, injectSupportedLocales, injectUnsafeT, provideFormatCurrencyDefaults, provideFormatDateDefaults, provideFormatDefaults, provideFormatDisplayNameDefaults, provideFormatListDefaults, provideFormatNumberDefaults, provideFormatPercentDefaults, provideFormatRelativeTimeDefaults, provideIntlConfig, provideMockTranslations, registerNamespace, registerRemoteNamespace, withParams };
|
|
979
1427
|
//# sourceMappingURL=mmstack-translate.mjs.map
|