@mmstack/translate 21.1.12 → 21.1.14
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 +66 -16
- package/fesm2022/mmstack-translate.mjs +404 -79
- package/fesm2022/mmstack-translate.mjs.map +1 -1
- package/package.json +1 -1
- package/types/mmstack-translate.d.ts +300 -70
package/README.md
CHANGED
|
@@ -592,15 +592,7 @@ const valueThatNeedsProps = t('remote.myOtherKey', {
|
|
|
592
592
|
|
|
593
593
|
## Formatters
|
|
594
594
|
|
|
595
|
-
The library includes a set of reactive formatters that
|
|
596
|
-
|
|
597
|
-
**Note:** For reactivity, wrap them in a `computed()` if the input signals change or if you want them to react to dynamic locale changes.
|
|
598
|
-
|
|
599
|
-
**SSR note:** Formatters read the active locale from a process-level signal. This is safe for all client-side usage and for SSR on serverless platforms (Lambda, Vercel, Netlify Edge) or worker-thread pools, where each request runs in an isolated V8 context. If you run a traditional single-process Node.js SSR server and concurrently render pages for **different** locales, pass the locale explicitly via the `locale` option on each formatter to avoid a potential cross-request read:
|
|
600
|
-
|
|
601
|
-
```typescript
|
|
602
|
-
readonly displayDate = computed(() => formatDate(this.date, { locale: this.currentLocale() }));
|
|
603
|
-
```
|
|
595
|
+
The library includes a set of reactive formatters that wrap the standard `Intl.*` APIs and integrate with the dynamic locale signal.
|
|
604
596
|
|
|
605
597
|
Available formatters:
|
|
606
598
|
|
|
@@ -612,24 +604,82 @@ Available formatters:
|
|
|
612
604
|
- **`formatRelativeTime`**: Wraps `Intl.RelativeTimeFormat`
|
|
613
605
|
- **`formatDisplayName`**: Wraps `Intl.DisplayNames`
|
|
614
606
|
|
|
615
|
-
|
|
607
|
+
Each formatter ships in two flavors:
|
|
608
|
+
|
|
609
|
+
1. **Standalone function** (`formatDate`, `formatList`, …) — pass `locale` explicitly, either as a string or via the options object. Three overloads per formatter: `(value, locale)`, `(value, opt)` with a required `locale` field, and a deprecated unsafe form that omits the locale (kept for backwards compatibility, see SSR note below).
|
|
610
|
+
2. **`injectFormat*()` companion** (`injectFormatDate`, `injectFormatList`, …) — call inside an injection context to get a function that auto-resolves locale from `injectDynamicLocale()` and respects any defaults registered via `provideFormat*Defaults`. **This is the recommended path for components and services.**
|
|
611
|
+
|
|
612
|
+
You can grab them all at once via the `injectFormatters()` facade:
|
|
616
613
|
|
|
617
614
|
```typescript
|
|
618
615
|
import { computed, signal } from '@angular/core';
|
|
619
|
-
import {
|
|
616
|
+
import { injectFormatters } from '@mmstack/translate';
|
|
620
617
|
|
|
621
618
|
export class MyComponent {
|
|
619
|
+
private readonly fmt = injectFormatters();
|
|
620
|
+
|
|
622
621
|
readonly price = signal(1234.56);
|
|
623
622
|
readonly date = new Date();
|
|
624
623
|
|
|
625
|
-
// Reacts to price changes
|
|
626
|
-
readonly displayPrice = computed(() =>
|
|
627
|
-
|
|
628
|
-
// Reacts to locale changes
|
|
629
|
-
readonly displayDate = computed(() => formatDate(this.date));
|
|
624
|
+
// Reacts to price changes AND locale changes — no explicit locale needed
|
|
625
|
+
readonly displayPrice = computed(() => this.fmt.currency(this.price(), 'EUR'));
|
|
626
|
+
readonly displayDate = computed(() => this.fmt.date(this.date));
|
|
630
627
|
}
|
|
631
628
|
```
|
|
632
629
|
|
|
630
|
+
If you'd rather call the standalone forms (e.g. outside an injection context), pass the locale explicitly:
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
import { computed } from '@angular/core';
|
|
634
|
+
import { formatCurrency, formatDate, injectDynamicLocale } from '@mmstack/translate';
|
|
635
|
+
|
|
636
|
+
const locale = injectDynamicLocale();
|
|
637
|
+
|
|
638
|
+
readonly displayPrice = computed(() => formatCurrency(this.price(), 'EUR', { locale: locale() }));
|
|
639
|
+
readonly displayDate = computed(() => formatDate(this.date, locale()));
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Provider defaults
|
|
643
|
+
|
|
644
|
+
Each formatter has a paired `provideFormat*Defaults` provider, and they can be registered together via `provideFormatDefaults`:
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
import { provideFormatDefaults } from '@mmstack/translate';
|
|
648
|
+
|
|
649
|
+
bootstrapApplication(AppComponent, {
|
|
650
|
+
providers: [
|
|
651
|
+
provideFormatDefaults({
|
|
652
|
+
date: { format: 'mediumDate' },
|
|
653
|
+
number: { useGrouping: true, maxFractionDigits: 2 },
|
|
654
|
+
currency: { display: 'code' },
|
|
655
|
+
relativeTime: { numeric: 'auto' },
|
|
656
|
+
list: { type: 'disjunction' },
|
|
657
|
+
percent: { maxFractionDigits: 1 },
|
|
658
|
+
displayName: { style: 'short' },
|
|
659
|
+
}),
|
|
660
|
+
],
|
|
661
|
+
});
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
The injected formatter functions (`injectFormat*()`) automatically merge these defaults with the dynamic locale.
|
|
665
|
+
|
|
666
|
+
### SSR note
|
|
667
|
+
|
|
668
|
+
The deprecated unsafe overload (omitting `locale`) reads from a **process-level global signal**, which can cross-contaminate concurrent requests on a single-process Node.js SSR server rendering pages for different locales. The new overloads with required `locale` and the `injectFormat*()` companions are SSR-safe.
|
|
669
|
+
|
|
670
|
+
For SSR-bound code, prefer either:
|
|
671
|
+
|
|
672
|
+
```typescript
|
|
673
|
+
// 1. Recommended — let the injected formatter handle locale
|
|
674
|
+
private readonly formatDate = injectFormatDate();
|
|
675
|
+
readonly displayDate = computed(() => this.formatDate(this.date));
|
|
676
|
+
|
|
677
|
+
// 2. Or pass locale explicitly to the standalone function
|
|
678
|
+
readonly displayDate = computed(() => formatDate(this.date, this.currentLocale()));
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
The unsafe overload is kept for backwards compatibility and will be removed in a future release.
|
|
682
|
+
|
|
633
683
|
## Testing
|
|
634
684
|
|
|
635
685
|
When testing components that use `@mmstack/translate` (via `injectNamespaceT`, `Translate` directive, or `Translator` pipe), you don't need to configure actual translated namespaces or deal with Intl loading. Instead, use the provided `provideMockTranslations()` utility.
|