@mmstack/translate 21.0.1 → 21.0.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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025-present Miha J. Mulec
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025-present Miha J. Mulec
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,349 +1,349 @@
1
- # @mmstack/translate
2
-
3
- **Type-Safe & modular localization for Modern Angular.**
4
-
5
- [![npm version](https://badge.fury.io/js/%40mmstack%2Ftranslate.svg)](https://badge.fury.io/js/%40mmstack%2Ftranslate)
6
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/mihajm/mmstack/blob/master/LICENSE)
7
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](CONTRIBUTING.md)
8
-
9
- `@mmstack/translate` is an opinionated internationalization (i18n) library for Angular applications built with three core priorities:
10
-
11
- 1. **Maximum Type Safety:** Catch errors related to missing keys or incorrect/missing parameters at compile time.
12
- 2. **Simplified Build Process:** Lazily load translations at runtime, requiring only a **single application build** regardless of the number of supported locales.
13
- 3. **Scalable Modularity:** Organize translations into **namespaces** (typically aligned with feature libraries) and load them on demand.
14
-
15
- It uses the robust **FormatJS** Intl runtime (`@formatjs/intl`) for ICU message formatting, and integrates with Angular's dependency injection and routing.
16
-
17
- ## Features
18
-
19
- - ✅ **End-to-End Type Safety:** Compile-time checks for:
20
- - Translation key existence (within a namespace).
21
- - Correct parameter names and types.
22
- - Required vs. optional parameters based on ICU message.
23
- - Structural consistency check when defining non-default locales.
24
- - 🚀 **Single Build Artifact:** Runtime translation loading.
25
- - 📦 **Namespacing:** Organize translations by feature/library (e.g., 'quotes', 'userProfile', 'common').
26
- - 🔄 **Dynamic Language Switching:** Change locales at runtime with automatic translation loading.
27
- - ⏳ **Lazy Loading:** Load namespaced translations on demand using Route Resolvers.
28
- - ✨ **Reactive API:** Includes `t.asSignal()` for creating computed translation signals based on signal parameters.
29
- - 🌍 **ICU Message Syntax:** Uses FormatJS runtime for robust support of variables (`{name}`), `plural`, `select`, and `selectordinal`. (Note: Complex inline date/number formats are not the focus; use Angular's built in Pipes/format functions & use the result as variables in your translation.)
30
- - 🔗 **Shared Namespace Support:** Define common translations (e.g., 'Save', 'Cancel') in one namespace and make them type-safely accessible from others.
31
- - 🛠️ **Template Helpers:** Includes abstract `Translator` pipe and `Translate` directive for easy, type-safe templating.
32
-
33
- ### Comparison
34
-
35
- While Angular offers excellent i18n solutions like `@angular/localize` and `transloco`, `@mmstack/translate` aims to fill a specific niche.
36
-
37
- | Feature | `@mmstack/translate` | `@angular/localize` | `transloco` | `ngx-translate` |
38
- | :----------------------- | :----------------------------------: | :----------------------: | :---------------------------: | :------------------------: |
39
- | **Build Process** | ✅ Single Build | ❌ Multi-Build (Typical) | ✅ Single Build | ✅ Single Build |
40
- | **Translation Timing** | Runtime | Compile Time | Runtime | Runtime |
41
- | **Type Safety (Keys)** | ✅ Strong (Inferred from structure) | 🟡 via extraction | 🟡 Tooling/TS Files | 🟡 OK Manual/Tooling |
42
- | **Type Safety (Params)** | ✅ Strong (Inferred from ICU) | ❌ None | 🟡 Manual | 🟡 Manual |
43
- | **Locale Switching** | ✅ Dynamic (Runtime) or Page refresh | 🔄 Page Refresh Required | ✅ Dynamic (Runtime) | ✅ Dynamic (Runtime) |
44
- | **Lazy Loading** | ✅ Built-in (Namespaces/Resolvers) | N/A (Compile Time) | ✅ Built-in (Scopes) | ✅ Yes (Custom Loaders) |
45
- | **Namespacing/Scopes** | ✅ Built-in | ❌ None | ✅ Built-in (Scopes) | 🟡 Manual (File Structure) |
46
- | **ICU Support** | ✅ Subset (via FormatJS Runtime) | ✅ Yes (Compile Time) | ✅ Yes (Runtime Intl/Plugins) | 🟡 Via Extensions |
47
- | **Signal Integration** | ✅ Good (`t.asSignal()`) | N/A | ✅ Good (`translateSignal()`) | ❌ Minimal/None |
48
- | **Maturity / Community** | ✨ New | Core Angular | ✅ Mature / Active | ✅ Mature |
49
-
50
- ## Installation & Configuration
51
-
52
- Install the library & its peer dependency, `@formatjs/intl`.
53
-
54
- ```bash
55
- npm install @mmstack/translate @formatjs/intl
56
- ```
57
-
58
- If you'd like to setup @formatjs with custom properties & setup a different default locale then 'en-US' you can define these options at the root of your application.
59
-
60
- ```typescript
61
- import { provideIntlConfig } from '@mmstack/translate';
62
-
63
- const appConfig: Providers = [
64
- provideIntlConfig({
65
- defaultLocale: 'en-US', // defaults to 'en-US' if nothing is provided
66
- }),
67
- ];
68
- ```
69
-
70
- ```typescript
71
- // DEMO impl, how you actually provide LOCALE_ID & what it's based on is up to you, it just has to be available when the resolvers are called
72
-
73
- import { Component, LOCALE_ID } from '@angular/core';
74
-
75
- @Component({
76
- selector: 'app-locale-shell',
77
- template: `<router-outlet />`,
78
- })
79
- export class LocaleShellComponent {}
80
-
81
- // app.routes.ts
82
- import { Routes, ActivatedRouteSnapshot } from '@angular/router';
83
- import { Injectable, LOCALE_ID } from '@angular/core';
84
- import { QuoteComponent } from './quote.component';
85
-
86
- @Injectable({
87
- providedIn: 'root',
88
- })
89
- export class LocaleStore {
90
- locale = 'en-US';
91
- }
92
-
93
- export const routes: Routes = [
94
- {
95
- path: ':locale',
96
- component: LocaleShellComponent,
97
- resolve: {
98
- localeId: (route: ActivatedRouteSnapshot) => {
99
- const locale = route.params['locale'] || 'en-US';
100
-
101
- return route.params['locale'] || 'en-US';
102
- },
103
- },
104
- providers: [
105
- {
106
- provide: LOCALE_ID,
107
- useFactory: (store: LocaleStore) => {
108
- return store.locale;
109
- },
110
- deps: [LocaleStore],
111
- },
112
- ],
113
- loadChildren: () => import('./quote.routes').then((m) => m.QUOTE_ROUTES),
114
- },
115
- ];
116
- ```
117
-
118
- _Note:_ `@mmstack/translate` relies on Angular's `LOCALE_ID` provider for its default. You should provide a value for it. How you determine this value (e.g., hardcoded, from server config, from URL segment via a factory provider) is up to your application's architecture.
119
-
120
- By default the library assumes this `LOCALE_ID` is static for the duration of the application session and requires a page refresh to change. You can however opt in to dynamic locale switching via `injectDynamicLocale`. see usage note 5 for details :)
121
-
122
- ## Usage
123
-
124
- The core workflow involves defining namespaces, registering them (often via lazy loading), and then using the injected translation function (t), pipe, or directive.
125
-
126
- ### 1. Define Namespace & Translations
127
-
128
- Define your default locale translations (e.g., 'en-US') as a `const` TypeScript object. Use createNamespace to process it and generate helpers.
129
-
130
- ```typescript
131
- // Example: packages/quote/src/lib/quote.namespace.ts
132
- import { createNamespace } from '@mmstack/translate';
133
-
134
- // Create the namespace definition object
135
- const ns = createNamespace('quote', {
136
- pageTitle: 'Famous Quotes',
137
- greeting: 'Hello {name}!',
138
- detail: {
139
- authorLabel: 'Author',
140
- },
141
- errors: {
142
- minLength: 'Quote must be at least {min} characters long.',
143
- },
144
- stats: '{count, plural, one {# quote} other {# quotes}} available',
145
- });
146
-
147
- export default ns.translation;
148
-
149
- export type QuoteLocale = (typeof ns)['translation'];
150
-
151
- export const createQuoteTranslation = ns.createTranslation;
152
-
153
- // Note the translations should be in separate files, if you are using import() to lazy load them.
154
- // packages/quote/src/lib/quote-sl.translation.ts
155
-
156
- import { createQuoteTranslation } from './quote.namespace';
157
-
158
- // shape is typesafe (errors if you have missing or additional keys)
159
- export default createQuoteTranslation('sl-SI', {
160
- pageTitle: 'Znani Citati',
161
- greeting: 'Zdravo {name}!',
162
- detail: {
163
- authorLabel: 'Avtor',
164
- },
165
- errors: {
166
- minLength: 'Citat mora imeti vsaj {min} znakov.', // If original has variables, the translation must contain a subset of used variables (min 1)
167
- },
168
- stats: '{count, plural, =1 {# citat} =2 {# citata} few {# citati} other {# citatov}} na voljo', // also guarenteed for "complex" variables, so {count} must be used in this translation
169
- });
170
- ```
171
-
172
- ### 2. Register the namespace & load
173
-
174
- Use registerNamespace to prepare your namespace definition and obtain the injectNamespaceT function and the resolveNamespaceTranslation resolver function. Use the resolver in your Angular routes.
175
-
176
- ```typescript
177
- import { registerNamespace } from '@mmstack/translate';
178
-
179
- // Register the namespace
180
- // Example: packages/quote/src/lib/quote.t.ts
181
- const r = registerNamespace(
182
- // you can also fetch from a server if you prefer, as long as the shape is the same
183
- () => import('./quote.namespace').then((m) => m.default), // Default locale's compiled translation (functions as fallback if no locale of type provided)
184
- {
185
- // Map other locales to promise factories (dynamic imports)
186
- 'sl-SI': () => import('./quote-sl.translation').then((m) => m.default),
187
- },
188
- );
189
-
190
- export const injectQuoteT = r.injectNamespaceT;
191
- export const resolveQuoteTranslations = r.resolveNamespaceTranslation;
192
-
193
- // in the main quote route add the provided resolver
194
-
195
- import { type Routes } from '@angular/router';
196
- import { resolveQuoteTranslations } from './quote.t';
197
-
198
- // quote.routes.ts
199
- export const QUOTE_ROUTES: Routes = [
200
- {
201
- // ... component at or above where the translations need to be available
202
- resolve: {
203
- resolveQuoteTranslations,
204
- },
205
- },
206
- ];
207
- ```
208
-
209
- #### 2b. [OPTIONAL] Configure the translation pipe and/or directive
210
-
211
- ```typescript
212
- import { Pipe, Directive } from '@angular/core';
213
- import { Translator, Translate } from '@mmstack/translate';
214
- import { type QuoteLocale } from './quote.namespace';
215
-
216
- @Pipe({
217
- name: 'translate',
218
- })
219
- export class QuoteTranslator extends Translator<QuoteLocale> {}
220
-
221
- @Directive({
222
- selector: '[translate]', // input in Translate is named 'translate'
223
- })
224
- // TInput is necessary to correctly infer the variables to the key
225
- export class QuoteTranslate<TInput extends string> extends Translate<TInput, QuoteLocale> {}
226
- ```
227
-
228
- ### 3. Have fun :)
229
-
230
- ```typescript
231
- @Component({
232
- selector: 'app-quote',
233
- imports: [QuoteTranslator, QuoteTranslate],
234
- template: `
235
- <!-- Pipe validates key & variables match -->
236
- <h1>{{ 'quote.pageTitle' | translate }}</h1>
237
- <!-- Non pluralized params must be string -->
238
- <span>{{ 'quote.errors.minLength' | translate: { min: '5' } }}</span>
239
-
240
- <!-- Directive replaces innerHTML of el -->
241
- <h1 translate="quote.pageTitle"></h1>
242
- <span [translate]="['quote.errors.minLength', { min: '5' }]"></span>
243
- `,
244
- })
245
- export class QuoteComponent {
246
- protected readonly count = signal(0);
247
- private readonly t = injectQuoteT();
248
-
249
- private readonly author = this.t('quote.detail.authorLabel'); // static translation
250
-
251
- private readonly stats = this.t.asSignal('quote.stats', () => ({
252
- count: this.count(), // must be object with count parameter & type number
253
- }));
254
- }
255
- ```
256
-
257
- ### 4. [OPTIONAL] - Creating a shared/common namespace
258
-
259
- _Note:_ A shared namespace allows you to use it within other `t` functions. You are however responsible for loading it before those `t` functions initialize, usually for a shared namespace that would be at the top route.
260
-
261
- #### 4a. Define a shared namespace
262
-
263
- Same as quote example, but this time also export the `createMergedNamespace` function. This will be your new factory for other namespaces.
264
-
265
- ```typescript
266
- // Example: packages/common-locales/src/lib/common.namespace.ts
267
- import { createNamespace } from '@mmstack/translate';
268
-
269
- const ns = createNamespace('common', {
270
- yes: 'Yes',
271
- no: 'No',
272
- });
273
-
274
- // ... rest
275
-
276
- export const createAppNamespace = ns.createMergedNamespace;
277
- ```
278
-
279
- ### 4b. Use the common namespace factory instead of the library one
280
-
281
- ```typescript
282
- // Example: packages/quote/src/lib/quote.namespace.ts
283
- import { createAppNamespace } from '@org/common/locale'; // replace with your library import path
284
-
285
- // Create the namespace definition object
286
- const ns = createAppNamespace('quote', {
287
- pageTitle: 'Famous Quotes',
288
- });
289
-
290
- // registration & other stuff remains the same
291
- ```
292
-
293
- ### 4c. Have even more fun!
294
-
295
- ```typescript
296
- @Component({
297
- //...
298
- })
299
- export class QuoteComponent {
300
- private readonly t = injectQuoteT();
301
-
302
- // t function is now 'aware' of the common namespace & its translations
303
- private readonly yes = this.t('common.yes');
304
-
305
- // quote translations also work the same
306
- private readonly author = this.t('quote.detail.authorLabel');
307
- }
308
- ```
309
-
310
- ### 5 [OPTIONAl] - Add dynamic language switching
311
-
312
- `LOCALE_ID` is always used as the initial value, but you can dynamically switch that & `@mmstack/translate` will load the new translations on demand, updating as necessary.
313
-
314
- ```typescript
315
- import { injectDynamicLocale } from '@mmstack/translate';
316
-
317
- @Component({...})
318
- export class LanguageSwitcher {
319
- private readonly locale = injectDynamicLocale();
320
-
321
- switchToSlovene() {
322
- this.locale.set('sl-SI'); // Automatically loads missing translations
323
- }
324
-
325
- // Template can react to loading state
326
- @if (locale.isLoading()) {
327
- <div>Loading translations...</div>
328
- }
329
- }
330
- ```
331
-
332
- _Note:_ Due to Angular memo-izing the transform function, custom Pipe's used will not update on dynamic local switches automatically. To resolve this you can:
333
-
334
- ```typescript
335
-
336
- // Add the locale as the last parameter when calling the pipe
337
- {{'common.yes' | translate : locale()}}
338
-
339
- // or set pure to false (not recommended)
340
- @Pipe({
341
- name: 'translate',
342
- pure: false
343
- })
344
- export class QuoteTranslator extends Translator<QuoteLocale> {}
345
- ```
346
-
347
- ## Contributing
348
-
349
- Contributions, issues, and feature requests are welcome!
1
+ # @mmstack/translate
2
+
3
+ **Type-Safe & modular localization for Modern Angular.**
4
+
5
+ [![npm version](https://badge.fury.io/js/%40mmstack%2Ftranslate.svg)](https://badge.fury.io/js/%40mmstack%2Ftranslate)
6
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/mihajm/mmstack/blob/master/LICENSE)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](CONTRIBUTING.md)
8
+
9
+ `@mmstack/translate` is an opinionated internationalization (i18n) library for Angular applications built with three core priorities:
10
+
11
+ 1. **Maximum Type Safety:** Catch errors related to missing keys or incorrect/missing parameters at compile time.
12
+ 2. **Simplified Build Process:** Lazily load translations at runtime, requiring only a **single application build** regardless of the number of supported locales.
13
+ 3. **Scalable Modularity:** Organize translations into **namespaces** (typically aligned with feature libraries) and load them on demand.
14
+
15
+ It uses the robust **FormatJS** Intl runtime (`@formatjs/intl`) for ICU message formatting, and integrates with Angular's dependency injection and routing.
16
+
17
+ ## Features
18
+
19
+ - ✅ **End-to-End Type Safety:** Compile-time checks for:
20
+ - Translation key existence (within a namespace).
21
+ - Correct parameter names and types.
22
+ - Required vs. optional parameters based on ICU message.
23
+ - Structural consistency check when defining non-default locales.
24
+ - 🚀 **Single Build Artifact:** Runtime translation loading.
25
+ - 📦 **Namespacing:** Organize translations by feature/library (e.g., 'quotes', 'userProfile', 'common').
26
+ - 🔄 **Dynamic Language Switching:** Change locales at runtime with automatic translation loading.
27
+ - ⏳ **Lazy Loading:** Load namespaced translations on demand using Route Resolvers.
28
+ - ✨ **Reactive API:** Includes `t.asSignal()` for creating computed translation signals based on signal parameters.
29
+ - 🌍 **ICU Message Syntax:** Uses FormatJS runtime for robust support of variables (`{name}`), `plural`, `select`, and `selectordinal`. (Note: Complex inline date/number formats are not the focus; use Angular's built in Pipes/format functions & use the result as variables in your translation.)
30
+ - 🔗 **Shared Namespace Support:** Define common translations (e.g., 'Save', 'Cancel') in one namespace and make them type-safely accessible from others.
31
+ - 🛠️ **Template Helpers:** Includes abstract `Translator` pipe and `Translate` directive for easy, type-safe templating.
32
+
33
+ ### Comparison
34
+
35
+ While Angular offers excellent i18n solutions like `@angular/localize` and `transloco`, `@mmstack/translate` aims to fill a specific niche.
36
+
37
+ | Feature | `@mmstack/translate` | `@angular/localize` | `transloco` | `ngx-translate` |
38
+ | :----------------------- | :----------------------------------: | :----------------------: | :---------------------------: | :------------------------: |
39
+ | **Build Process** | ✅ Single Build | ❌ Multi-Build (Typical) | ✅ Single Build | ✅ Single Build |
40
+ | **Translation Timing** | Runtime | Compile Time | Runtime | Runtime |
41
+ | **Type Safety (Keys)** | ✅ Strong (Inferred from structure) | 🟡 via extraction | 🟡 Tooling/TS Files | 🟡 OK Manual/Tooling |
42
+ | **Type Safety (Params)** | ✅ Strong (Inferred from ICU) | ❌ None | 🟡 Manual | 🟡 Manual |
43
+ | **Locale Switching** | ✅ Dynamic (Runtime) or Page refresh | 🔄 Page Refresh Required | ✅ Dynamic (Runtime) | ✅ Dynamic (Runtime) |
44
+ | **Lazy Loading** | ✅ Built-in (Namespaces/Resolvers) | N/A (Compile Time) | ✅ Built-in (Scopes) | ✅ Yes (Custom Loaders) |
45
+ | **Namespacing/Scopes** | ✅ Built-in | ❌ None | ✅ Built-in (Scopes) | 🟡 Manual (File Structure) |
46
+ | **ICU Support** | ✅ Subset (via FormatJS Runtime) | ✅ Yes (Compile Time) | ✅ Yes (Runtime Intl/Plugins) | 🟡 Via Extensions |
47
+ | **Signal Integration** | ✅ Good (`t.asSignal()`) | N/A | ✅ Good (`translateSignal()`) | ❌ Minimal/None |
48
+ | **Maturity / Community** | ✨ New | Core Angular | ✅ Mature / Active | ✅ Mature |
49
+
50
+ ## Installation & Configuration
51
+
52
+ Install the library & its peer dependency, `@formatjs/intl`.
53
+
54
+ ```bash
55
+ npm install @mmstack/translate @formatjs/intl
56
+ ```
57
+
58
+ If you'd like to setup @formatjs with custom properties & setup a different default locale then 'en-US' you can define these options at the root of your application.
59
+
60
+ ```typescript
61
+ import { provideIntlConfig } from '@mmstack/translate';
62
+
63
+ const appConfig: Providers = [
64
+ provideIntlConfig({
65
+ defaultLocale: 'en-US', // defaults to 'en-US' if nothing is provided
66
+ }),
67
+ ];
68
+ ```
69
+
70
+ ```typescript
71
+ // DEMO impl, how you actually provide LOCALE_ID & what it's based on is up to you, it just has to be available when the resolvers are called
72
+
73
+ import { Component, LOCALE_ID } from '@angular/core';
74
+
75
+ @Component({
76
+ selector: 'app-locale-shell',
77
+ template: `<router-outlet />`,
78
+ })
79
+ export class LocaleShellComponent {}
80
+
81
+ // app.routes.ts
82
+ import { Routes, ActivatedRouteSnapshot } from '@angular/router';
83
+ import { Injectable, LOCALE_ID } from '@angular/core';
84
+ import { QuoteComponent } from './quote.component';
85
+
86
+ @Injectable({
87
+ providedIn: 'root',
88
+ })
89
+ export class LocaleStore {
90
+ locale = 'en-US';
91
+ }
92
+
93
+ export const routes: Routes = [
94
+ {
95
+ path: ':locale',
96
+ component: LocaleShellComponent,
97
+ resolve: {
98
+ localeId: (route: ActivatedRouteSnapshot) => {
99
+ const locale = route.params['locale'] || 'en-US';
100
+
101
+ return route.params['locale'] || 'en-US';
102
+ },
103
+ },
104
+ providers: [
105
+ {
106
+ provide: LOCALE_ID,
107
+ useFactory: (store: LocaleStore) => {
108
+ return store.locale;
109
+ },
110
+ deps: [LocaleStore],
111
+ },
112
+ ],
113
+ loadChildren: () => import('./quote.routes').then((m) => m.QUOTE_ROUTES),
114
+ },
115
+ ];
116
+ ```
117
+
118
+ _Note:_ `@mmstack/translate` relies on Angular's `LOCALE_ID` provider for its default. You should provide a value for it. How you determine this value (e.g., hardcoded, from server config, from URL segment via a factory provider) is up to your application's architecture.
119
+
120
+ By default the library assumes this `LOCALE_ID` is static for the duration of the application session and requires a page refresh to change. You can however opt in to dynamic locale switching via `injectDynamicLocale`. see usage note 5 for details :)
121
+
122
+ ## Usage
123
+
124
+ The core workflow involves defining namespaces, registering them (often via lazy loading), and then using the injected translation function (t), pipe, or directive.
125
+
126
+ ### 1. Define Namespace & Translations
127
+
128
+ Define your default locale translations (e.g., 'en-US') as a `const` TypeScript object. Use createNamespace to process it and generate helpers.
129
+
130
+ ```typescript
131
+ // Example: packages/quote/src/lib/quote.namespace.ts
132
+ import { createNamespace } from '@mmstack/translate';
133
+
134
+ // Create the namespace definition object
135
+ const ns = createNamespace('quote', {
136
+ pageTitle: 'Famous Quotes',
137
+ greeting: 'Hello {name}!',
138
+ detail: {
139
+ authorLabel: 'Author',
140
+ },
141
+ errors: {
142
+ minLength: 'Quote must be at least {min} characters long.',
143
+ },
144
+ stats: '{count, plural, one {# quote} other {# quotes}} available',
145
+ });
146
+
147
+ export default ns.translation;
148
+
149
+ export type QuoteLocale = (typeof ns)['translation'];
150
+
151
+ export const createQuoteTranslation = ns.createTranslation;
152
+
153
+ // Note the translations should be in separate files, if you are using import() to lazy load them.
154
+ // packages/quote/src/lib/quote-sl.translation.ts
155
+
156
+ import { createQuoteTranslation } from './quote.namespace';
157
+
158
+ // shape is typesafe (errors if you have missing or additional keys)
159
+ export default createQuoteTranslation('sl-SI', {
160
+ pageTitle: 'Znani Citati',
161
+ greeting: 'Zdravo {name}!',
162
+ detail: {
163
+ authorLabel: 'Avtor',
164
+ },
165
+ errors: {
166
+ minLength: 'Citat mora imeti vsaj {min} znakov.', // If original has variables, the translation must contain a subset of used variables (min 1)
167
+ },
168
+ stats: '{count, plural, =1 {# citat} =2 {# citata} few {# citati} other {# citatov}} na voljo', // also guarenteed for "complex" variables, so {count} must be used in this translation
169
+ });
170
+ ```
171
+
172
+ ### 2. Register the namespace & load
173
+
174
+ Use registerNamespace to prepare your namespace definition and obtain the injectNamespaceT function and the resolveNamespaceTranslation resolver function. Use the resolver in your Angular routes.
175
+
176
+ ```typescript
177
+ import { registerNamespace } from '@mmstack/translate';
178
+
179
+ // Register the namespace
180
+ // Example: packages/quote/src/lib/quote.t.ts
181
+ const r = registerNamespace(
182
+ // you can also fetch from a server if you prefer, as long as the shape is the same
183
+ () => import('./quote.namespace').then((m) => m.default), // Default locale's compiled translation (functions as fallback if no locale of type provided)
184
+ {
185
+ // Map other locales to promise factories (dynamic imports)
186
+ 'sl-SI': () => import('./quote-sl.translation').then((m) => m.default),
187
+ },
188
+ );
189
+
190
+ export const injectQuoteT = r.injectNamespaceT;
191
+ export const resolveQuoteTranslations = r.resolveNamespaceTranslation;
192
+
193
+ // in the main quote route add the provided resolver
194
+
195
+ import { type Routes } from '@angular/router';
196
+ import { resolveQuoteTranslations } from './quote.t';
197
+
198
+ // quote.routes.ts
199
+ export const QUOTE_ROUTES: Routes = [
200
+ {
201
+ // ... component at or above where the translations need to be available
202
+ resolve: {
203
+ resolveQuoteTranslations,
204
+ },
205
+ },
206
+ ];
207
+ ```
208
+
209
+ #### 2b. [OPTIONAL] Configure the translation pipe and/or directive
210
+
211
+ ```typescript
212
+ import { Pipe, Directive } from '@angular/core';
213
+ import { Translator, Translate } from '@mmstack/translate';
214
+ import { type QuoteLocale } from './quote.namespace';
215
+
216
+ @Pipe({
217
+ name: 'translate',
218
+ })
219
+ export class QuoteTranslator extends Translator<QuoteLocale> {}
220
+
221
+ @Directive({
222
+ selector: '[translate]', // input in Translate is named 'translate'
223
+ })
224
+ // TInput is necessary to correctly infer the variables to the key
225
+ export class QuoteTranslate<TInput extends string> extends Translate<TInput, QuoteLocale> {}
226
+ ```
227
+
228
+ ### 3. Have fun :)
229
+
230
+ ```typescript
231
+ @Component({
232
+ selector: 'app-quote',
233
+ imports: [QuoteTranslator, QuoteTranslate],
234
+ template: `
235
+ <!-- Pipe validates key & variables match -->
236
+ <h1>{{ 'quote.pageTitle' | translate }}</h1>
237
+ <!-- Non pluralized params must be string -->
238
+ <span>{{ 'quote.errors.minLength' | translate: { min: '5' } }}</span>
239
+
240
+ <!-- Directive replaces innerHTML of el -->
241
+ <h1 translate="quote.pageTitle"></h1>
242
+ <span [translate]="['quote.errors.minLength', { min: '5' }]"></span>
243
+ `,
244
+ })
245
+ export class QuoteComponent {
246
+ protected readonly count = signal(0);
247
+ private readonly t = injectQuoteT();
248
+
249
+ private readonly author = this.t('quote.detail.authorLabel'); // static translation
250
+
251
+ private readonly stats = this.t.asSignal('quote.stats', () => ({
252
+ count: this.count(), // must be object with count parameter & type number
253
+ }));
254
+ }
255
+ ```
256
+
257
+ ### 4. [OPTIONAL] - Creating a shared/common namespace
258
+
259
+ _Note:_ A shared namespace allows you to use it within other `t` functions. You are however responsible for loading it before those `t` functions initialize, usually for a shared namespace that would be at the top route.
260
+
261
+ #### 4a. Define a shared namespace
262
+
263
+ Same as quote example, but this time also export the `createMergedNamespace` function. This will be your new factory for other namespaces.
264
+
265
+ ```typescript
266
+ // Example: packages/common-locales/src/lib/common.namespace.ts
267
+ import { createNamespace } from '@mmstack/translate';
268
+
269
+ const ns = createNamespace('common', {
270
+ yes: 'Yes',
271
+ no: 'No',
272
+ });
273
+
274
+ // ... rest
275
+
276
+ export const createAppNamespace = ns.createMergedNamespace;
277
+ ```
278
+
279
+ ### 4b. Use the common namespace factory instead of the library one
280
+
281
+ ```typescript
282
+ // Example: packages/quote/src/lib/quote.namespace.ts
283
+ import { createAppNamespace } from '@org/common/locale'; // replace with your library import path
284
+
285
+ // Create the namespace definition object
286
+ const ns = createAppNamespace('quote', {
287
+ pageTitle: 'Famous Quotes',
288
+ });
289
+
290
+ // registration & other stuff remains the same
291
+ ```
292
+
293
+ ### 4c. Have even more fun!
294
+
295
+ ```typescript
296
+ @Component({
297
+ //...
298
+ })
299
+ export class QuoteComponent {
300
+ private readonly t = injectQuoteT();
301
+
302
+ // t function is now 'aware' of the common namespace & its translations
303
+ private readonly yes = this.t('common.yes');
304
+
305
+ // quote translations also work the same
306
+ private readonly author = this.t('quote.detail.authorLabel');
307
+ }
308
+ ```
309
+
310
+ ### 5 [OPTIONAl] - Add dynamic language switching
311
+
312
+ `LOCALE_ID` is always used as the initial value, but you can dynamically switch that & `@mmstack/translate` will load the new translations on demand, updating as necessary.
313
+
314
+ ```typescript
315
+ import { injectDynamicLocale } from '@mmstack/translate';
316
+
317
+ @Component({...})
318
+ export class LanguageSwitcher {
319
+ private readonly locale = injectDynamicLocale();
320
+
321
+ switchToSlovene() {
322
+ this.locale.set('sl-SI'); // Automatically loads missing translations
323
+ }
324
+
325
+ // Template can react to loading state
326
+ @if (locale.isLoading()) {
327
+ <div>Loading translations...</div>
328
+ }
329
+ }
330
+ ```
331
+
332
+ _Note:_ Due to Angular memo-izing the transform function, custom Pipe's used will not update on dynamic local switches automatically. To resolve this you can:
333
+
334
+ ```typescript
335
+
336
+ // Add the locale as the last parameter when calling the pipe
337
+ {{'common.yes' | translate : locale()}}
338
+
339
+ // or set pure to false (not recommended)
340
+ @Pipe({
341
+ name: 'translate',
342
+ pure: false
343
+ })
344
+ export class QuoteTranslator extends Translator<QuoteLocale> {}
345
+ ```
346
+
347
+ ## Contributing
348
+
349
+ Contributions, issues, and feature requests are welcome!
@@ -171,10 +171,10 @@ class TranslationStore {
171
171
  hasLocaleLoaders(locale) {
172
172
  return Array.from(this.onDemandLoaders.values()).some((loaders) => loaders[locale]);
173
173
  }
174
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TranslationStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
175
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TranslationStore, providedIn: 'root' });
174
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TranslationStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
175
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TranslationStore, providedIn: 'root' });
176
176
  }
177
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TranslationStore, decorators: [{
177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TranslationStore, decorators: [{
178
178
  type: Injectable,
179
179
  args: [{
180
180
  providedIn: 'root',
@@ -347,10 +347,10 @@ class Translate {
347
347
  },
348
348
  });
349
349
  }
350
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Translate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
351
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.6", type: Translate, isStandalone: true, inputs: { translate: { classPropertyName: "translate", publicName: "translate", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
350
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Translate, deps: [], target: i0.ɵɵFactoryTarget.Directive });
351
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: Translate, isStandalone: true, inputs: { translate: { classPropertyName: "translate", publicName: "translate", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
352
352
  }
353
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Translate, decorators: [{
353
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: Translate, decorators: [{
354
354
  type: Directive
355
355
  }], ctorParameters: () => [], propDecorators: { translate: [{ type: i0.Input, args: [{ isSignal: true, alias: "translate", required: true }] }] } });
356
356
 
@@ -1 +1 @@
1
- {"version":3,"file":"mmstack-translate.mjs","sources":["../../../../packages/translate/src/lib/delim.ts","../../../../packages/translate/src/lib/compile.ts","../../../../packages/translate/src/lib/create-namespace.ts","../../../../packages/translate/src/lib/translation-store.ts","../../../../packages/translate/src/lib/register-namespace.ts","../../../../packages/translate/src/lib/translate.ts","../../../../packages/translate/src/lib/translator.ts","../../../../packages/translate/src/mmstack-translate.ts"],"sourcesContent":["const KEY_DELIM = '::MMT_DELIM::';\r\n\r\nexport function prependDelim(prefix: string, key: string): string {\r\n return `${prefix}${KEY_DELIM}${key}`;\r\n}\r\n\r\nexport function replaceWithDelim(str: string, repl = '.'): string {\r\n return str.replaceAll(repl, KEY_DELIM);\r\n}\r\n","import { prependDelim } from './delim';\r\nimport type {\r\n inferTranslationParamMap,\r\n inferTranslationShape,\r\n} from './parameterize.type';\r\nimport type { UnknownStringKeyObject } from './string-key-object.type';\r\n\r\nconst INTERNAL_SYMBOL = Symbol.for('mmstack-translate-internal');\r\n\r\ntype InternalSymbol = typeof INTERNAL_SYMBOL;\r\n\r\nexport type CompiledTranslation<\r\n T extends UnknownStringKeyObject,\r\n TNS extends string,\r\n TLocale extends string = string,\r\n> = {\r\n flat: Record<string, string>;\r\n locale?: TLocale;\r\n namespace: TNS;\r\n [INTERNAL_SYMBOL]: {\r\n shape: inferTranslationShape<T>;\r\n map: inferTranslationParamMap<TNS, T>;\r\n };\r\n};\r\n\r\nexport type mergeTranslationMaps<\r\n TMain extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n TOther extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n> = Omit<TMain, InternalSymbol> & {\r\n [INTERNAL_SYMBOL]: {\r\n shape: inferCompiledTranslationShape<TMain>;\r\n map: inferCompiledTranslationMap<TOther> &\r\n inferCompiledTranslationMap<TMain>;\r\n };\r\n};\r\n\r\nexport type inferCompiledTranslationNamespace<\r\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n> = T['namespace'];\r\n\r\nexport type inferCompiledTranslationShape<\r\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n> = T[InternalSymbol]['shape'];\r\n\r\nexport type inferCompiledTranslationMap<\r\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n> = T[InternalSymbol]['map'];\r\n\r\nfunction isTranslationObject(t: unknown): t is UnknownStringKeyObject {\r\n return typeof t === 'object' && t !== null;\r\n}\r\n\r\nfunction flattenTranslation<T extends UnknownStringKeyObject>(obj: T) {\r\n return Object.entries(obj).reduce(\r\n (acc, [key, value]) => {\r\n if (typeof value === 'string') {\r\n acc[key] = value;\r\n } else if (isTranslationObject(value)) {\r\n Object.entries(flattenTranslation(value)).forEach(\r\n ([nestedKey, nestedValue]) => {\r\n acc[prependDelim(key, nestedKey)] = nestedValue;\r\n },\r\n );\r\n }\r\n\r\n return acc;\r\n },\r\n {} as Record<string, string>,\r\n );\r\n}\r\n\r\nexport function compileTranslation<\r\n T extends UnknownStringKeyObject,\r\n TNS extends string,\r\n TLocale extends string = string,\r\n>(\r\n translation: T,\r\n ns: TNS,\r\n locale?: TLocale,\r\n): CompiledTranslation<T, TNS, TLocale> {\r\n type $Shape = inferTranslationShape<T>;\r\n type $Map = inferTranslationParamMap<TNS, T>;\r\n\r\n return {\r\n locale,\r\n flat: flattenTranslation(translation),\r\n namespace: ns,\r\n [INTERNAL_SYMBOL]: {\r\n shape: {} as $Shape,\r\n map: {} as $Map,\r\n },\r\n };\r\n}\r\n","import {\r\n CompiledTranslation,\r\n compileTranslation,\r\n inferCompiledTranslationShape,\r\n mergeTranslationMaps,\r\n} from './compile';\r\nimport { UnknownStringKeyObject } from './string-key-object.type';\r\n\r\ntype TranslationNamespace<\r\n TNS extends string,\r\n T extends CompiledTranslation<UnknownStringKeyObject, TNS>,\r\n TShape extends UnknownStringKeyObject,\r\n> = {\r\n translation: T;\r\n createTranslation: <TLocale extends string>(\r\n locale: TLocale,\r\n translation: TShape,\r\n ) => CompiledTranslation<TShape, TNS, TLocale>;\r\n createMergedNamespace: <\r\n TOtherNS extends string,\r\n const TOther extends UnknownStringKeyObject,\r\n TOtherCompiled extends CompiledTranslation<TOther, TOtherNS>,\r\n >(\r\n ns: TOtherNS,\r\n translation: TOther,\r\n ) => TranslationNamespace<\r\n TOtherNS,\r\n mergeTranslationMaps<TOtherCompiled, T>,\r\n inferCompiledTranslationShape<TOtherCompiled>\r\n >;\r\n};\r\n\r\nexport function createNamespace<\r\n const T extends UnknownStringKeyObject,\r\n TNS extends string,\r\n>(ns: TNS, translation: T) {\r\n const compiled = compileTranslation<T, TNS>(translation, ns);\r\n\r\n type TCompiled = typeof compiled;\r\n type TShape = inferCompiledTranslationShape<typeof compiled>;\r\n\r\n const namespace: TranslationNamespace<TNS, TCompiled, TShape> = {\r\n translation: compileTranslation(translation, ns),\r\n createTranslation: <TLocale extends string>(\r\n locale: TLocale,\r\n translation: TShape,\r\n ) => {\r\n return compileTranslation(translation, ns, locale);\r\n },\r\n createMergedNamespace: <\r\n TOther extends UnknownStringKeyObject,\r\n TOtherNS extends string,\r\n TOtherCompiled extends CompiledTranslation<\r\n TOther,\r\n TOtherNS\r\n > = CompiledTranslation<TOther, TOtherNS>,\r\n >(\r\n otherNs: TOtherNS,\r\n otherTranslation: TOther,\r\n ) => {\r\n return createNamespace(otherNs, otherTranslation) as TranslationNamespace<\r\n TOtherNS,\r\n mergeTranslationMaps<TOtherCompiled, TCompiled>,\r\n inferCompiledTranslationShape<TOtherCompiled>\r\n > as unknown as any;\r\n },\r\n };\r\n\r\n return namespace;\r\n}\r\n","import {\r\n computed,\r\n effect,\r\n inject,\r\n Injectable,\r\n InjectionToken,\r\n isDevMode,\r\n LOCALE_ID,\r\n Provider,\r\n resource,\r\n Signal,\r\n signal,\r\n untracked,\r\n WritableSignal,\r\n} from '@angular/core';\r\nimport { createIntl, createIntlCache, type IntlConfig } from '@formatjs/intl';\r\nimport { CompiledTranslation } from './compile';\r\nimport { prependDelim } from './delim';\r\nimport { UnknownStringKeyObject } from './string-key-object.type';\r\n\r\nconst CONFIG_TOKEN = new InjectionToken<\r\n Omit<IntlConfig, 'locale' | 'messages'>\r\n>('mmstack-intl-config');\r\n\r\nexport function provideIntlConfig(\r\n config: Omit<IntlConfig, 'locale' | 'messages'>,\r\n): Provider {\r\n return {\r\n useValue: config,\r\n provide: CONFIG_TOKEN,\r\n };\r\n}\r\n\r\nexport function injectIntlConfig() {\r\n return inject(CONFIG_TOKEN, { optional: true }) ?? undefined;\r\n}\r\n\r\nexport function injectDefaultLocale() {\r\n return injectIntlConfig()?.defaultLocale ?? 'en-US';\r\n}\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class TranslationStore {\r\n private readonly cache = createIntlCache();\r\n private readonly config = injectIntlConfig();\r\n readonly loadQueue = signal<string[]>([]);\r\n readonly locale = signal(inject(LOCALE_ID));\r\n private readonly defaultLocale = injectDefaultLocale();\r\n private readonly translations = signal<\r\n Record<string, Record<string, string>>\r\n >({\r\n [this.defaultLocale]: {},\r\n });\r\n\r\n private readonly onDemandLoaders = new Map<\r\n string,\r\n Record<\r\n string,\r\n () => Promise<CompiledTranslation<UnknownStringKeyObject, string>>\r\n >\r\n >();\r\n\r\n private readonly nonMessageConfig = computed(() => ({\r\n ...this.config,\r\n locale: this.locale(),\r\n }));\r\n\r\n private readonly messages = computed(\r\n () =>\r\n this.translations()[this.locale()] ??\r\n this.translations()[this.defaultLocale] ??\r\n {},\r\n );\r\n\r\n readonly dynamicLocaleLoader = resource({\r\n params: computed(() => this.loadQueue().at(0) ?? null),\r\n loader: async ({ params: newLocale, abortSignal }) => {\r\n if (!newLocale) return;\r\n\r\n const currentTranslations = untracked(this.translations);\r\n\r\n const loadPromises: Promise<{\r\n namespace: string;\r\n flat: Record<string, string>;\r\n } | null>[] = [];\r\n\r\n for (const [namespace, loaders] of this.onDemandLoaders.entries()) {\r\n const loader = loaders[newLocale];\r\n if (loader) {\r\n const hasNamespaceForLocale =\r\n currentTranslations[newLocale] &&\r\n Object.keys(currentTranslations[newLocale]).some((key) =>\r\n key.startsWith(`${prependDelim(namespace, '').slice(0, -1)}`),\r\n );\r\n\r\n if (!hasNamespaceForLocale) {\r\n loadPromises.push(\r\n loader()\r\n .then((translation) => {\r\n if (abortSignal.aborted) return null;\r\n return {\r\n namespace: translation.namespace,\r\n flat: translation.flat,\r\n };\r\n })\r\n .catch((err) => {\r\n if (isDevMode()) {\r\n console.error(\r\n '[Translate] Failed to load',\r\n namespace,\r\n newLocale,\r\n err,\r\n );\r\n }\r\n\r\n return null;\r\n }),\r\n );\r\n }\r\n }\r\n }\r\n\r\n return Promise.all(loadPromises)\r\n .then((res) => res.filter((r) => r !== null))\r\n .then((res) => ({\r\n locales: res,\r\n locale: newLocale,\r\n }));\r\n },\r\n });\r\n\r\n readonly intl = computed(() =>\r\n createIntl(\r\n {\r\n ...this.nonMessageConfig(),\r\n messages: this.messages(),\r\n },\r\n this.cache,\r\n ),\r\n );\r\n\r\n constructor() {\r\n effect(() => {\r\n if (\r\n // should never be in error state, but best to check in case something throws\r\n this.dynamicLocaleLoader.error() ||\r\n this.dynamicLocaleLoader.isLoading()\r\n )\r\n return;\r\n const dynamicLocales = this.dynamicLocaleLoader.value();\r\n\r\n if (!dynamicLocales) return;\r\n for (const locale of dynamicLocales.locales) {\r\n this.register(locale.namespace, {\r\n [dynamicLocales.locale]: locale.flat,\r\n });\r\n }\r\n this.loadQueue.update((q) =>\r\n q.filter((l) => l !== dynamicLocales.locale),\r\n );\r\n this.locale.set(dynamicLocales.locale);\r\n });\r\n }\r\n\r\n formatMessage(key: string, values?: Record<string, string | number>) {\r\n const message = this.translations()[this.locale()]?.[key] ?? '';\r\n\r\n if (!message) return '';\r\n\r\n return this.intl().formatMessage(\r\n { id: key, defaultMessage: message },\r\n values,\r\n );\r\n }\r\n\r\n register(\r\n namespace: string,\r\n flat: Partial<Record<string, Record<string, string>>>,\r\n ) {\r\n this.translations.update((cur) => {\r\n return Object.entries(flat).reduce(\r\n (acc, [locale, translation]) => {\r\n const localeTranslation = acc[locale] ?? {};\r\n\r\n const withNS = Object.entries(translation ?? {}).reduce(\r\n (acc, [key, value]) => {\r\n acc[prependDelim(namespace, key)] = value;\r\n return acc;\r\n },\r\n {} as Record<string, string>,\r\n );\r\n\r\n acc[locale] = {\r\n ...localeTranslation,\r\n ...withNS,\r\n };\r\n\r\n return acc;\r\n },\r\n { ...cur },\r\n );\r\n });\r\n }\r\n\r\n registerOnDemandLoaders(\r\n namespace: string,\r\n loaders: Record<string, () => Promise<any>>,\r\n ) {\r\n this.onDemandLoaders.set(namespace, loaders);\r\n }\r\n\r\n hasLocaleLoaders(locale: string): boolean {\r\n return Array.from(this.onDemandLoaders.values()).some(\r\n (loaders) => loaders[locale],\r\n );\r\n }\r\n}\r\n\r\nexport function injectIntl() {\r\n return inject(TranslationStore).intl;\r\n}\r\n\r\n/**\r\n * Inject a dynamic locale signal that supports runtime language switching.\r\n *\r\n * @returns A writable signal with the current locale and loading state.\r\n * Only allows switching to locales that have registered loaders.\r\n *\r\n * @example\r\n * ```typescript\r\n * const locale = injectDynamicLocale();\r\n *\r\n * // Switch language (triggers automatic translation loading)\r\n * locale.set('sl-SI');\r\n *\r\n * // Check loading state\r\n * if (locale.isLoading()) {\r\n * // Show spinner\r\n * }\r\n * ```\r\n */\r\nexport function injectDynamicLocale(): WritableSignal<string> & {\r\n isLoading: Signal<boolean>;\r\n} {\r\n const store = inject(TranslationStore);\r\n\r\n const source = computed(() => store.locale()) as WritableSignal<string> & {\r\n isLoading: Signal<boolean>;\r\n };\r\n\r\n const set = (value: string) => {\r\n if (\r\n value === untracked(source) ||\r\n !store.hasLocaleLoaders(value) ||\r\n untracked(store.loadQueue).includes(value)\r\n )\r\n return;\r\n store.loadQueue.update((q) => [...q, value]);\r\n };\r\n source.set = set;\r\n source.update = (updater: (value: string) => string) => {\r\n const next = updater(untracked(source));\r\n source.set(next);\r\n };\r\n source.asReadonly = () => source;\r\n\r\n source.isLoading = store.dynamicLocaleLoader.isLoading;\r\n\r\n return source;\r\n}\r\n","import {\r\n computed,\r\n inject,\r\n isDevMode,\r\n isSignal,\r\n Signal,\r\n untracked,\r\n} from '@angular/core';\r\nimport {\r\n CompiledTranslation,\r\n inferCompiledTranslationMap,\r\n inferCompiledTranslationNamespace,\r\n} from './compile';\r\nimport { replaceWithDelim } from './delim';\r\nimport { UnknownStringKeyObject } from './string-key-object.type';\r\nimport { injectDefaultLocale, TranslationStore } from './translation-store';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ntype AnyStringRecord = Record<string, any>;\r\n\r\nfunction createEqualsRecord<T extends AnyStringRecord>(keys: (keyof T)[] = []) {\r\n let keyMatcher: (a: T, b: T) => boolean;\r\n\r\n if (keys.length === 0) {\r\n keyMatcher = () => true;\r\n } else if (keys.length === 1) {\r\n const key = keys[0];\r\n keyMatcher = (a, b) => a[key] === b[key];\r\n } else {\r\n keyMatcher = (a, b) => {\r\n return keys.every((k) => a[k] === b[k]);\r\n };\r\n }\r\n\r\n return (a?: T, b?: T): boolean => {\r\n if (!a && !b) return true;\r\n if (!a || !b) return false;\r\n return keyMatcher(a, b);\r\n };\r\n}\r\n\r\ntype TFunction<TMap extends AnyStringRecord> = <\r\n TKey extends keyof TMap & string,\r\n>(\r\n key: TKey,\r\n ...args: TMap[TKey] extends void ? [] : [TMap[TKey]]\r\n) => string;\r\n\r\ntype SignalTFunction<TMap extends AnyStringRecord> = <\r\n TKey extends keyof TMap & string,\r\n>(\r\n key: TKey,\r\n ...args: TMap[TKey] extends void ? [] : [() => TMap[TKey]]\r\n) => Signal<string>;\r\n\r\ntype TFunctionWithSignalConstructor<\r\n TMap extends AnyStringRecord,\r\n TFN extends TFunction<TMap>,\r\n> = TFN & {\r\n asSignal: SignalTFunction<TMap>;\r\n};\r\n\r\nfunction addSignalFn<TMap extends AnyStringRecord, TFn extends TFunction<TMap>>(\r\n fn: TFn,\r\n store: TranslationStore,\r\n): TFunctionWithSignalConstructor<TMap, TFn> {\r\n const withSig = fn as TFunctionWithSignalConstructor<TMap, TFn>;\r\n\r\n const asSignal = <TKey extends keyof TMap & string>(\r\n key: TKey,\r\n ...args: TMap[TKey] extends void ? [] : [() => TMap[TKey]]\r\n ): Signal<string> => {\r\n const variables = args[0] as () => AnyStringRecord | undefined;\r\n const stringKey = key as string;\r\n\r\n const flatPath = replaceWithDelim(stringKey);\r\n\r\n const varsFn = variables ?? (() => undefined);\r\n const varsSignal = isSignal(varsFn)\r\n ? varsFn\r\n : computed(varsFn, {\r\n equal: createEqualsRecord(Object.keys(varsFn() ?? {})),\r\n });\r\n\r\n return computed(() => store.formatMessage(flatPath, varsSignal()));\r\n };\r\n\r\n withSig.asSignal = asSignal;\r\n\r\n return withSig;\r\n}\r\n\r\nexport function createT<TMap extends AnyStringRecord>(\r\n store: TranslationStore,\r\n): TFunction<TMap> {\r\n return <TKey extends keyof TMap & string>(\r\n key: TKey,\r\n ...args: TMap[TKey] extends void ? [] : [TMap[TKey]]\r\n ): string => {\r\n const variables = args[0] as AnyStringRecord | undefined;\r\n const stringKey = key as string;\r\n\r\n return store.formatMessage(replaceWithDelim(stringKey), variables);\r\n };\r\n}\r\n\r\nexport function registerNamespace<\r\n TDefault extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n>(\r\n defaultTranslation: () => Promise<TDefault>,\r\n other: Record<\r\n string,\r\n () => Promise<\r\n CompiledTranslation<\r\n UnknownStringKeyObject,\r\n inferCompiledTranslationNamespace<TDefault>,\r\n string\r\n >\r\n >\r\n >,\r\n) {\r\n type $Map = inferCompiledTranslationMap<TDefault>;\r\n type $BaseTFN = TFunction<$Map>;\r\n type $TFN = TFunctionWithSignalConstructor<$Map, $BaseTFN>;\r\n\r\n const injectT = (): $TFN => {\r\n const store = inject(TranslationStore);\r\n\r\n return addSignalFn(createT(store), store);\r\n };\r\n\r\n let defaultTranslationLoaded = false;\r\n const resolver = async () => {\r\n const store = inject(TranslationStore);\r\n const locale = untracked(store.locale);\r\n const defaultLocale = injectDefaultLocale();\r\n const tPromise = other[locale] as (typeof other)[string] | undefined;\r\n\r\n const promise = tPromise ?? defaultTranslation;\r\n if (!promise && isDevMode()) {\r\n return console.warn(`No translation found for locale: ${locale}`);\r\n }\r\n\r\n if (promise === defaultTranslation && defaultTranslationLoaded) return;\r\n\r\n try {\r\n const translation = await promise();\r\n\r\n if (\r\n promise !== defaultTranslation &&\r\n translation.locale !== locale &&\r\n isDevMode()\r\n ) {\r\n return console.warn(\r\n `Expected locale to be ${locale} but got ${translation.locale}`,\r\n );\r\n }\r\n\r\n store.registerOnDemandLoaders(translation.namespace, {\r\n ...other,\r\n [defaultLocale]: defaultTranslation,\r\n });\r\n\r\n store.register(translation.namespace, {\r\n [locale]: translation.flat,\r\n });\r\n if (promise === defaultTranslation) {\r\n defaultTranslationLoaded = true;\r\n }\r\n } catch {\r\n if (isDevMode()) {\r\n console.warn(`Failed to load translation for locale: ${locale}`);\r\n }\r\n }\r\n };\r\n\r\n return {\r\n injectNamespaceT: injectT,\r\n resolveNamespaceTranslation: resolver,\r\n };\r\n}\r\n","import {\r\n afterRenderEffect,\r\n computed,\r\n Directive,\r\n ElementRef,\r\n inject,\r\n input,\r\n Renderer2,\r\n} from '@angular/core';\r\nimport { CompiledTranslation, inferCompiledTranslationMap } from './compile';\r\nimport { createT } from './register-namespace';\r\nimport { UnknownStringKeyObject } from './string-key-object.type';\r\nimport { TranslationStore } from './translation-store';\r\n\r\n@Directive()\r\nexport abstract class Translate<\r\n TInput extends string,\r\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n TMap extends inferCompiledTranslationMap<T> = inferCompiledTranslationMap<T>,\r\n TKey extends TInput & keyof TMap & string = TInput & keyof TMap & string,\r\n> {\r\n private readonly t = createT(inject(TranslationStore));\r\n\r\n readonly translate =\r\n input.required<\r\n TMap[TKey] extends void\r\n ? TKey | [key: TKey]\r\n : [key: TKey, vars: TMap[TKey]]\r\n >();\r\n\r\n constructor() {\r\n const key = computed(() => {\r\n const vars = this.translate();\r\n return (Array.isArray(vars) ? vars[0] : vars) as TKey;\r\n });\r\n\r\n const args = computed(\r\n () => {\r\n const vars = this.translate();\r\n return (Array.isArray(vars) ? vars[1] : undefined) as TMap[TKey];\r\n },\r\n {\r\n equal: (a, b) => {\r\n if (a === undefined && b === undefined) return true;\r\n if (a === undefined || b === undefined) return false;\r\n\r\n const aObj = a as Record<string, string>;\r\n const keys = Object.keys(aObj);\r\n const bObj = b as Record<string, string>;\r\n\r\n if (!keys.length) return !Object.keys(bObj).length;\r\n\r\n return keys.every((key) => aObj[key] === bObj[key]);\r\n },\r\n },\r\n );\r\n\r\n const translation = computed(() => this.t(key(), args()));\r\n\r\n const renderer = inject(Renderer2);\r\n const el = inject<ElementRef<HTMLElement>>(ElementRef);\r\n\r\n afterRenderEffect({\r\n write: () => {\r\n renderer.setProperty(el.nativeElement, 'textContent', translation());\r\n },\r\n });\r\n }\r\n}\r\n","import { ChangeDetectorRef, effect, inject } from '@angular/core';\r\nimport { CompiledTranslation, inferCompiledTranslationMap } from './compile';\r\nimport { createT } from './register-namespace';\r\nimport { UnknownStringKeyObject } from './string-key-object.type';\r\nimport { TranslationStore } from './translation-store';\r\n\r\nexport abstract class Translator<\r\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\r\n TMap extends inferCompiledTranslationMap<T> = inferCompiledTranslationMap<T>,\r\n> {\r\n private readonly store = inject(TranslationStore);\r\n private readonly t = createT<TMap>(this.store);\r\n\r\n constructor() {\r\n const cdr = inject(ChangeDetectorRef);\r\n\r\n effect(() => {\r\n this.store.locale();\r\n cdr.markForCheck();\r\n });\r\n }\r\n\r\n transform<K extends keyof TMap & string>(\r\n key: K,\r\n ...args: TMap[K] extends void\r\n ? [locale?: string]\r\n : [TMap[K], locale?: string]\r\n ): string {\r\n const actualArgs = args.filter(\r\n (a) => typeof a === 'object',\r\n ) as TMap[K] extends void ? [] : [TMap[K]];\r\n\r\n return this.t(key, ...actualArgs);\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mmstack-translate.mjs","sources":["../../../../packages/translate/src/lib/delim.ts","../../../../packages/translate/src/lib/compile.ts","../../../../packages/translate/src/lib/create-namespace.ts","../../../../packages/translate/src/lib/translation-store.ts","../../../../packages/translate/src/lib/register-namespace.ts","../../../../packages/translate/src/lib/translate.ts","../../../../packages/translate/src/lib/translator.ts","../../../../packages/translate/src/mmstack-translate.ts"],"sourcesContent":["const KEY_DELIM = '::MMT_DELIM::';\n\nexport function prependDelim(prefix: string, key: string): string {\n return `${prefix}${KEY_DELIM}${key}`;\n}\n\nexport function replaceWithDelim(str: string, repl = '.'): string {\n return str.replaceAll(repl, KEY_DELIM);\n}\n","import { prependDelim } from './delim';\nimport type {\n inferTranslationParamMap,\n inferTranslationShape,\n} from './parameterize.type';\nimport type { UnknownStringKeyObject } from './string-key-object.type';\n\nconst INTERNAL_SYMBOL = Symbol.for('mmstack-translate-internal');\n\ntype InternalSymbol = typeof INTERNAL_SYMBOL;\n\nexport type CompiledTranslation<\n T extends UnknownStringKeyObject,\n TNS extends string,\n TLocale extends string = string,\n> = {\n flat: Record<string, string>;\n locale?: TLocale;\n namespace: TNS;\n [INTERNAL_SYMBOL]: {\n shape: inferTranslationShape<T>;\n map: inferTranslationParamMap<TNS, T>;\n };\n};\n\nexport type mergeTranslationMaps<\n TMain extends CompiledTranslation<UnknownStringKeyObject, string>,\n TOther extends CompiledTranslation<UnknownStringKeyObject, string>,\n> = Omit<TMain, InternalSymbol> & {\n [INTERNAL_SYMBOL]: {\n shape: inferCompiledTranslationShape<TMain>;\n map: inferCompiledTranslationMap<TOther> &\n inferCompiledTranslationMap<TMain>;\n };\n};\n\nexport type inferCompiledTranslationNamespace<\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\n> = T['namespace'];\n\nexport type inferCompiledTranslationShape<\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\n> = T[InternalSymbol]['shape'];\n\nexport type inferCompiledTranslationMap<\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\n> = T[InternalSymbol]['map'];\n\nfunction isTranslationObject(t: unknown): t is UnknownStringKeyObject {\n return typeof t === 'object' && t !== null;\n}\n\nfunction flattenTranslation<T extends UnknownStringKeyObject>(obj: T) {\n return Object.entries(obj).reduce(\n (acc, [key, value]) => {\n if (typeof value === 'string') {\n acc[key] = value;\n } else if (isTranslationObject(value)) {\n Object.entries(flattenTranslation(value)).forEach(\n ([nestedKey, nestedValue]) => {\n acc[prependDelim(key, nestedKey)] = nestedValue;\n },\n );\n }\n\n return acc;\n },\n {} as Record<string, string>,\n );\n}\n\nexport function compileTranslation<\n T extends UnknownStringKeyObject,\n TNS extends string,\n TLocale extends string = string,\n>(\n translation: T,\n ns: TNS,\n locale?: TLocale,\n): CompiledTranslation<T, TNS, TLocale> {\n type $Shape = inferTranslationShape<T>;\n type $Map = inferTranslationParamMap<TNS, T>;\n\n return {\n locale,\n flat: flattenTranslation(translation),\n namespace: ns,\n [INTERNAL_SYMBOL]: {\n shape: {} as $Shape,\n map: {} as $Map,\n },\n };\n}\n","import {\n CompiledTranslation,\n compileTranslation,\n inferCompiledTranslationShape,\n mergeTranslationMaps,\n} from './compile';\nimport { UnknownStringKeyObject } from './string-key-object.type';\n\ntype TranslationNamespace<\n TNS extends string,\n T extends CompiledTranslation<UnknownStringKeyObject, TNS>,\n TShape extends UnknownStringKeyObject,\n> = {\n translation: T;\n createTranslation: <TLocale extends string>(\n locale: TLocale,\n translation: TShape,\n ) => CompiledTranslation<TShape, TNS, TLocale>;\n createMergedNamespace: <\n TOtherNS extends string,\n const TOther extends UnknownStringKeyObject,\n TOtherCompiled extends CompiledTranslation<TOther, TOtherNS>,\n >(\n ns: TOtherNS,\n translation: TOther,\n ) => TranslationNamespace<\n TOtherNS,\n mergeTranslationMaps<TOtherCompiled, T>,\n inferCompiledTranslationShape<TOtherCompiled>\n >;\n};\n\nexport function createNamespace<\n const T extends UnknownStringKeyObject,\n TNS extends string,\n>(ns: TNS, translation: T) {\n const compiled = compileTranslation<T, TNS>(translation, ns);\n\n type TCompiled = typeof compiled;\n type TShape = inferCompiledTranslationShape<typeof compiled>;\n\n const namespace: TranslationNamespace<TNS, TCompiled, TShape> = {\n translation: compileTranslation(translation, ns),\n createTranslation: <TLocale extends string>(\n locale: TLocale,\n translation: TShape,\n ) => {\n return compileTranslation(translation, ns, locale);\n },\n createMergedNamespace: <\n TOther extends UnknownStringKeyObject,\n TOtherNS extends string,\n TOtherCompiled extends CompiledTranslation<\n TOther,\n TOtherNS\n > = CompiledTranslation<TOther, TOtherNS>,\n >(\n otherNs: TOtherNS,\n otherTranslation: TOther,\n ) => {\n return createNamespace(otherNs, otherTranslation) as TranslationNamespace<\n TOtherNS,\n mergeTranslationMaps<TOtherCompiled, TCompiled>,\n inferCompiledTranslationShape<TOtherCompiled>\n > as unknown as any;\n },\n };\n\n return namespace;\n}\n","import {\n computed,\n effect,\n inject,\n Injectable,\n InjectionToken,\n isDevMode,\n LOCALE_ID,\n Provider,\n resource,\n Signal,\n signal,\n untracked,\n WritableSignal,\n} from '@angular/core';\nimport { createIntl, createIntlCache, type IntlConfig } from '@formatjs/intl';\nimport { CompiledTranslation } from './compile';\nimport { prependDelim } from './delim';\nimport { UnknownStringKeyObject } from './string-key-object.type';\n\nconst CONFIG_TOKEN = new InjectionToken<\n Omit<IntlConfig, 'locale' | 'messages'>\n>('mmstack-intl-config');\n\nexport function provideIntlConfig(\n config: Omit<IntlConfig, 'locale' | 'messages'>,\n): Provider {\n return {\n useValue: config,\n provide: CONFIG_TOKEN,\n };\n}\n\nexport function injectIntlConfig() {\n return inject(CONFIG_TOKEN, { optional: true }) ?? undefined;\n}\n\nexport function injectDefaultLocale() {\n return injectIntlConfig()?.defaultLocale ?? 'en-US';\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class TranslationStore {\n private readonly cache = createIntlCache();\n private readonly config = injectIntlConfig();\n readonly loadQueue = signal<string[]>([]);\n readonly locale = signal(inject(LOCALE_ID));\n private readonly defaultLocale = injectDefaultLocale();\n private readonly translations = signal<\n Record<string, Record<string, string>>\n >({\n [this.defaultLocale]: {},\n });\n\n private readonly onDemandLoaders = new Map<\n string,\n Record<\n string,\n () => Promise<CompiledTranslation<UnknownStringKeyObject, string>>\n >\n >();\n\n private readonly nonMessageConfig = computed(() => ({\n ...this.config,\n locale: this.locale(),\n }));\n\n private readonly messages = computed(\n () =>\n this.translations()[this.locale()] ??\n this.translations()[this.defaultLocale] ??\n {},\n );\n\n readonly dynamicLocaleLoader = resource({\n params: computed(() => this.loadQueue().at(0) ?? null),\n loader: async ({ params: newLocale, abortSignal }) => {\n if (!newLocale) return;\n\n const currentTranslations = untracked(this.translations);\n\n const loadPromises: Promise<{\n namespace: string;\n flat: Record<string, string>;\n } | null>[] = [];\n\n for (const [namespace, loaders] of this.onDemandLoaders.entries()) {\n const loader = loaders[newLocale];\n if (loader) {\n const hasNamespaceForLocale =\n currentTranslations[newLocale] &&\n Object.keys(currentTranslations[newLocale]).some((key) =>\n key.startsWith(`${prependDelim(namespace, '').slice(0, -1)}`),\n );\n\n if (!hasNamespaceForLocale) {\n loadPromises.push(\n loader()\n .then((translation) => {\n if (abortSignal.aborted) return null;\n return {\n namespace: translation.namespace,\n flat: translation.flat,\n };\n })\n .catch((err) => {\n if (isDevMode()) {\n console.error(\n '[Translate] Failed to load',\n namespace,\n newLocale,\n err,\n );\n }\n\n return null;\n }),\n );\n }\n }\n }\n\n return Promise.all(loadPromises)\n .then((res) => res.filter((r) => r !== null))\n .then((res) => ({\n locales: res,\n locale: newLocale,\n }));\n },\n });\n\n readonly intl = computed(() =>\n createIntl(\n {\n ...this.nonMessageConfig(),\n messages: this.messages(),\n },\n this.cache,\n ),\n );\n\n constructor() {\n effect(() => {\n if (\n // should never be in error state, but best to check in case something throws\n this.dynamicLocaleLoader.error() ||\n this.dynamicLocaleLoader.isLoading()\n )\n return;\n const dynamicLocales = this.dynamicLocaleLoader.value();\n\n if (!dynamicLocales) return;\n for (const locale of dynamicLocales.locales) {\n this.register(locale.namespace, {\n [dynamicLocales.locale]: locale.flat,\n });\n }\n this.loadQueue.update((q) =>\n q.filter((l) => l !== dynamicLocales.locale),\n );\n this.locale.set(dynamicLocales.locale);\n });\n }\n\n formatMessage(key: string, values?: Record<string, string | number>) {\n const message = this.translations()[this.locale()]?.[key] ?? '';\n\n if (!message) return '';\n\n return this.intl().formatMessage(\n { id: key, defaultMessage: message },\n values,\n );\n }\n\n register(\n namespace: string,\n flat: Partial<Record<string, Record<string, string>>>,\n ) {\n this.translations.update((cur) => {\n return Object.entries(flat).reduce(\n (acc, [locale, translation]) => {\n const localeTranslation = acc[locale] ?? {};\n\n const withNS = Object.entries(translation ?? {}).reduce(\n (acc, [key, value]) => {\n acc[prependDelim(namespace, key)] = value;\n return acc;\n },\n {} as Record<string, string>,\n );\n\n acc[locale] = {\n ...localeTranslation,\n ...withNS,\n };\n\n return acc;\n },\n { ...cur },\n );\n });\n }\n\n registerOnDemandLoaders(\n namespace: string,\n loaders: Record<string, () => Promise<any>>,\n ) {\n this.onDemandLoaders.set(namespace, loaders);\n }\n\n hasLocaleLoaders(locale: string): boolean {\n return Array.from(this.onDemandLoaders.values()).some(\n (loaders) => loaders[locale],\n );\n }\n}\n\nexport function injectIntl() {\n return inject(TranslationStore).intl;\n}\n\n/**\n * Inject a dynamic locale signal that supports runtime language switching.\n *\n * @returns A writable signal with the current locale and loading state.\n * Only allows switching to locales that have registered loaders.\n *\n * @example\n * ```typescript\n * const locale = injectDynamicLocale();\n *\n * // Switch language (triggers automatic translation loading)\n * locale.set('sl-SI');\n *\n * // Check loading state\n * if (locale.isLoading()) {\n * // Show spinner\n * }\n * ```\n */\nexport function injectDynamicLocale(): WritableSignal<string> & {\n isLoading: Signal<boolean>;\n} {\n const store = inject(TranslationStore);\n\n const source = computed(() => store.locale()) as WritableSignal<string> & {\n isLoading: Signal<boolean>;\n };\n\n const set = (value: string) => {\n if (\n value === untracked(source) ||\n !store.hasLocaleLoaders(value) ||\n untracked(store.loadQueue).includes(value)\n )\n return;\n store.loadQueue.update((q) => [...q, value]);\n };\n source.set = set;\n source.update = (updater: (value: string) => string) => {\n const next = updater(untracked(source));\n source.set(next);\n };\n source.asReadonly = () => source;\n\n source.isLoading = store.dynamicLocaleLoader.isLoading;\n\n return source;\n}\n","import {\n computed,\n inject,\n isDevMode,\n isSignal,\n Signal,\n untracked,\n} from '@angular/core';\nimport {\n CompiledTranslation,\n inferCompiledTranslationMap,\n inferCompiledTranslationNamespace,\n} from './compile';\nimport { replaceWithDelim } from './delim';\nimport { UnknownStringKeyObject } from './string-key-object.type';\nimport { injectDefaultLocale, TranslationStore } from './translation-store';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyStringRecord = Record<string, any>;\n\nfunction createEqualsRecord<T extends AnyStringRecord>(keys: (keyof T)[] = []) {\n let keyMatcher: (a: T, b: T) => boolean;\n\n if (keys.length === 0) {\n keyMatcher = () => true;\n } else if (keys.length === 1) {\n const key = keys[0];\n keyMatcher = (a, b) => a[key] === b[key];\n } else {\n keyMatcher = (a, b) => {\n return keys.every((k) => a[k] === b[k]);\n };\n }\n\n return (a?: T, b?: T): boolean => {\n if (!a && !b) return true;\n if (!a || !b) return false;\n return keyMatcher(a, b);\n };\n}\n\ntype TFunction<TMap extends AnyStringRecord> = <\n TKey extends keyof TMap & string,\n>(\n key: TKey,\n ...args: TMap[TKey] extends void ? [] : [TMap[TKey]]\n) => string;\n\ntype SignalTFunction<TMap extends AnyStringRecord> = <\n TKey extends keyof TMap & string,\n>(\n key: TKey,\n ...args: TMap[TKey] extends void ? [] : [() => TMap[TKey]]\n) => Signal<string>;\n\ntype TFunctionWithSignalConstructor<\n TMap extends AnyStringRecord,\n TFN extends TFunction<TMap>,\n> = TFN & {\n asSignal: SignalTFunction<TMap>;\n};\n\nfunction addSignalFn<TMap extends AnyStringRecord, TFn extends TFunction<TMap>>(\n fn: TFn,\n store: TranslationStore,\n): TFunctionWithSignalConstructor<TMap, TFn> {\n const withSig = fn as TFunctionWithSignalConstructor<TMap, TFn>;\n\n const asSignal = <TKey extends keyof TMap & string>(\n key: TKey,\n ...args: TMap[TKey] extends void ? [] : [() => TMap[TKey]]\n ): Signal<string> => {\n const variables = args[0] as () => AnyStringRecord | undefined;\n const stringKey = key as string;\n\n const flatPath = replaceWithDelim(stringKey);\n\n const varsFn = variables ?? (() => undefined);\n const varsSignal = isSignal(varsFn)\n ? varsFn\n : computed(varsFn, {\n equal: createEqualsRecord(Object.keys(varsFn() ?? {})),\n });\n\n return computed(() => store.formatMessage(flatPath, varsSignal()));\n };\n\n withSig.asSignal = asSignal;\n\n return withSig;\n}\n\nexport function createT<TMap extends AnyStringRecord>(\n store: TranslationStore,\n): TFunction<TMap> {\n return <TKey extends keyof TMap & string>(\n key: TKey,\n ...args: TMap[TKey] extends void ? [] : [TMap[TKey]]\n ): string => {\n const variables = args[0] as AnyStringRecord | undefined;\n const stringKey = key as string;\n\n return store.formatMessage(replaceWithDelim(stringKey), variables);\n };\n}\n\nexport function registerNamespace<\n TDefault extends CompiledTranslation<UnknownStringKeyObject, string>,\n>(\n defaultTranslation: () => Promise<TDefault>,\n other: Record<\n string,\n () => Promise<\n CompiledTranslation<\n UnknownStringKeyObject,\n inferCompiledTranslationNamespace<TDefault>,\n string\n >\n >\n >,\n) {\n type $Map = inferCompiledTranslationMap<TDefault>;\n type $BaseTFN = TFunction<$Map>;\n type $TFN = TFunctionWithSignalConstructor<$Map, $BaseTFN>;\n\n const injectT = (): $TFN => {\n const store = inject(TranslationStore);\n\n return addSignalFn(createT(store), store);\n };\n\n let defaultTranslationLoaded = false;\n const resolver = async () => {\n const store = inject(TranslationStore);\n const locale = untracked(store.locale);\n const defaultLocale = injectDefaultLocale();\n const tPromise = other[locale] as (typeof other)[string] | undefined;\n\n const promise = tPromise ?? defaultTranslation;\n if (!promise && isDevMode()) {\n return console.warn(`No translation found for locale: ${locale}`);\n }\n\n if (promise === defaultTranslation && defaultTranslationLoaded) return;\n\n try {\n const translation = await promise();\n\n if (\n promise !== defaultTranslation &&\n translation.locale !== locale &&\n isDevMode()\n ) {\n return console.warn(\n `Expected locale to be ${locale} but got ${translation.locale}`,\n );\n }\n\n store.registerOnDemandLoaders(translation.namespace, {\n ...other,\n [defaultLocale]: defaultTranslation,\n });\n\n store.register(translation.namespace, {\n [locale]: translation.flat,\n });\n if (promise === defaultTranslation) {\n defaultTranslationLoaded = true;\n }\n } catch {\n if (isDevMode()) {\n console.warn(`Failed to load translation for locale: ${locale}`);\n }\n }\n };\n\n return {\n injectNamespaceT: injectT,\n resolveNamespaceTranslation: resolver,\n };\n}\n","import {\n afterRenderEffect,\n computed,\n Directive,\n ElementRef,\n inject,\n input,\n Renderer2,\n} from '@angular/core';\nimport { CompiledTranslation, inferCompiledTranslationMap } from './compile';\nimport { createT } from './register-namespace';\nimport { UnknownStringKeyObject } from './string-key-object.type';\nimport { TranslationStore } from './translation-store';\n\n@Directive()\nexport abstract class Translate<\n TInput extends string,\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\n TMap extends inferCompiledTranslationMap<T> = inferCompiledTranslationMap<T>,\n TKey extends TInput & keyof TMap & string = TInput & keyof TMap & string,\n> {\n private readonly t = createT(inject(TranslationStore));\n\n readonly translate =\n input.required<\n TMap[TKey] extends void\n ? TKey | [key: TKey]\n : [key: TKey, vars: TMap[TKey]]\n >();\n\n constructor() {\n const key = computed(() => {\n const vars = this.translate();\n return (Array.isArray(vars) ? vars[0] : vars) as TKey;\n });\n\n const args = computed(\n () => {\n const vars = this.translate();\n return (Array.isArray(vars) ? vars[1] : undefined) as TMap[TKey];\n },\n {\n equal: (a, b) => {\n if (a === undefined && b === undefined) return true;\n if (a === undefined || b === undefined) return false;\n\n const aObj = a as Record<string, string>;\n const keys = Object.keys(aObj);\n const bObj = b as Record<string, string>;\n\n if (!keys.length) return !Object.keys(bObj).length;\n\n return keys.every((key) => aObj[key] === bObj[key]);\n },\n },\n );\n\n const translation = computed(() => this.t(key(), args()));\n\n const renderer = inject(Renderer2);\n const el = inject<ElementRef<HTMLElement>>(ElementRef);\n\n afterRenderEffect({\n write: () => {\n renderer.setProperty(el.nativeElement, 'textContent', translation());\n },\n });\n }\n}\n","import { ChangeDetectorRef, effect, inject } from '@angular/core';\nimport { CompiledTranslation, inferCompiledTranslationMap } from './compile';\nimport { createT } from './register-namespace';\nimport { UnknownStringKeyObject } from './string-key-object.type';\nimport { TranslationStore } from './translation-store';\n\nexport abstract class Translator<\n T extends CompiledTranslation<UnknownStringKeyObject, string>,\n TMap extends inferCompiledTranslationMap<T> = inferCompiledTranslationMap<T>,\n> {\n private readonly store = inject(TranslationStore);\n private readonly t = createT<TMap>(this.store);\n\n constructor() {\n const cdr = inject(ChangeDetectorRef);\n\n effect(() => {\n this.store.locale();\n cdr.markForCheck();\n });\n }\n\n transform<K extends keyof TMap & string>(\n key: K,\n ...args: TMap[K] extends void\n ? [locale?: string]\n : [TMap[K], locale?: string]\n ): string {\n const actualArgs = args.filter(\n (a) => typeof a === 'object',\n ) as TMap[K] extends void ? [] : [TMap[K]];\n\n return this.t(key, ...actualArgs);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAAA,MAAM,SAAS,GAAG,eAAe;AAE3B,SAAU,YAAY,CAAC,MAAc,EAAE,GAAW,EAAA;AACtD,IAAA,OAAO,GAAG,MAAM,CAAA,EAAG,SAAS,CAAA,EAAG,GAAG,EAAE;AACtC;SAEgB,gBAAgB,CAAC,GAAW,EAAE,IAAI,GAAG,GAAG,EAAA;IACtD,OAAO,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC;AACxC;;ACDA,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC;AAyChE,SAAS,mBAAmB,CAAC,CAAU,EAAA;IACrC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;AAC5C;AAEA,SAAS,kBAAkB,CAAmC,GAAM,EAAA;AAClE,IAAA,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAC/B,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;AACpB,QAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,YAAA,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK;QAClB;AAAO,aAAA,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE;AACrC,YAAA,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAC/C,CAAC,CAAC,SAAS,EAAE,WAAW,CAAC,KAAI;gBAC3B,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,GAAG,WAAW;AACjD,YAAA,CAAC,CACF;QACH;AAEA,QAAA,OAAO,GAAG;IACZ,CAAC,EACD,EAA4B,CAC7B;AACH;SAEgB,kBAAkB,CAKhC,WAAc,EACd,EAAO,EACP,MAAgB,EAAA;IAKhB,OAAO;QACL,MAAM;AACN,QAAA,IAAI,EAAE,kBAAkB,CAAC,WAAW,CAAC;AACrC,QAAA,SAAS,EAAE,EAAE;QACb,CAAC,eAAe,GAAG;AACjB,YAAA,KAAK,EAAE,EAAY;AACnB,YAAA,GAAG,EAAE,EAAU;AAChB,SAAA;KACF;AACH;;AC5DM,SAAU,eAAe,CAG7B,EAAO,EAAE,WAAc,EAAA;IACvB,MAAM,QAAQ,GAAG,kBAAkB,CAAS,WAAW,EAAE,EAAE,CAAC;AAK5D,IAAA,MAAM,SAAS,GAAiD;AAC9D,QAAA,WAAW,EAAE,kBAAkB,CAAC,WAAW,EAAE,EAAE,CAAC;AAChD,QAAA,iBAAiB,EAAE,CACjB,MAAe,EACf,WAAmB,KACjB;YACF,OAAO,kBAAkB,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC;QACpD,CAAC;AACD,QAAA,qBAAqB,EAAE,CAQrB,OAAiB,EACjB,gBAAwB,KACtB;AACF,YAAA,OAAO,eAAe,CAAC,OAAO,EAAE,gBAAgB,CAI7B;QACrB,CAAC;KACF;AAED,IAAA,OAAO,SAAS;AAClB;;ACjDA,MAAM,YAAY,GAAG,IAAI,cAAc,CAErC,qBAAqB,CAAC;AAElB,SAAU,iBAAiB,CAC/B,MAA+C,EAAA;IAE/C,OAAO;AACL,QAAA,QAAQ,EAAE,MAAM;AAChB,QAAA,OAAO,EAAE,YAAY;KACtB;AACH;SAEgB,gBAAgB,GAAA;AAC9B,IAAA,OAAO,MAAM,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,SAAS;AAC9D;SAEgB,mBAAmB,GAAA;AACjC,IAAA,OAAO,gBAAgB,EAAE,EAAE,aAAa,IAAI,OAAO;AACrD;MAKa,gBAAgB,CAAA;IACV,KAAK,GAAG,eAAe,EAAE;IACzB,MAAM,GAAG,gBAAgB,EAAE;AACnC,IAAA,SAAS,GAAG,MAAM,CAAW,EAAE,qDAAC;IAChC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,kDAAC;IAC1B,aAAa,GAAG,mBAAmB,EAAE;IACrC,YAAY,GAAG,MAAM,CAEpC;AACA,QAAA,CAAC,IAAI,CAAC,aAAa,GAAG,EAAE;AACzB,KAAA,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,cAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AAEe,IAAA,eAAe,GAAG,IAAI,GAAG,EAMvC;AAEc,IAAA,gBAAgB,GAAG,QAAQ,CAAC,OAAO;QAClD,GAAG,IAAI,CAAC,MAAM;AACd,QAAA,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;AACtB,KAAA,CAAC,4DAAC;AAEc,IAAA,QAAQ,GAAG,QAAQ,CAClC,MACE,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;AAClC,QAAA,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC;AACvC,QAAA,EAAE,oDACL;IAEQ,mBAAmB,GAAG,QAAQ,CAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,qBAAA,EAAA,GAAA,EAAA,CAAA,EACrC,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QACtD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,KAAI;AACnD,YAAA,IAAI,CAAC,SAAS;gBAAE;YAEhB,MAAM,mBAAmB,GAAG,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC;YAExD,MAAM,YAAY,GAGJ,EAAE;AAEhB,YAAA,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE;AACjE,gBAAA,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;gBACjC,IAAI,MAAM,EAAE;AACV,oBAAA,MAAM,qBAAqB,GACzB,mBAAmB,CAAC,SAAS,CAAC;AAC9B,wBAAA,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KACnD,GAAG,CAAC,UAAU,CAAC,CAAA,EAAG,YAAY,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA,CAAE,CAAC,CAC9D;oBAEH,IAAI,CAAC,qBAAqB,EAAE;AAC1B,wBAAA,YAAY,CAAC,IAAI,CACf,MAAM;AACH,6BAAA,IAAI,CAAC,CAAC,WAAW,KAAI;4BACpB,IAAI,WAAW,CAAC,OAAO;AAAE,gCAAA,OAAO,IAAI;4BACpC,OAAO;gCACL,SAAS,EAAE,WAAW,CAAC,SAAS;gCAChC,IAAI,EAAE,WAAW,CAAC,IAAI;6BACvB;AACH,wBAAA,CAAC;AACA,6BAAA,KAAK,CAAC,CAAC,GAAG,KAAI;4BACb,IAAI,SAAS,EAAE,EAAE;gCACf,OAAO,CAAC,KAAK,CACX,4BAA4B,EAC5B,SAAS,EACT,SAAS,EACT,GAAG,CACJ;4BACH;AAEA,4BAAA,OAAO,IAAI;wBACb,CAAC,CAAC,CACL;oBACH;gBACF;YACF;AAEA,YAAA,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY;AAC5B,iBAAA,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;AAC3C,iBAAA,IAAI,CAAC,CAAC,GAAG,MAAM;AACd,gBAAA,OAAO,EAAE,GAAG;AACZ,gBAAA,MAAM,EAAE,SAAS;AAClB,aAAA,CAAC,CAAC;AACP,QAAA,CAAC,GACD;AAEO,IAAA,IAAI,GAAG,QAAQ,CAAC,MACvB,UAAU,CACR;QACE,GAAG,IAAI,CAAC,gBAAgB,EAAE;AAC1B,QAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;AAC1B,KAAA,EACD,IAAI,CAAC,KAAK,CACX,gDACF;AAED,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;AACV,YAAA;;AAEE,YAAA,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE;AAChC,gBAAA,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE;gBAEpC;YACF,MAAM,cAAc,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE;AAEvD,YAAA,IAAI,CAAC,cAAc;gBAAE;AACrB,YAAA,KAAK,MAAM,MAAM,IAAI,cAAc,CAAC,OAAO,EAAE;AAC3C,gBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE;AAC9B,oBAAA,CAAC,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI;AACrC,iBAAA,CAAC;YACJ;YACA,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,KACtB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,cAAc,CAAC,MAAM,CAAC,CAC7C;YACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;AACxC,QAAA,CAAC,CAAC;IACJ;IAEA,aAAa,CAAC,GAAW,EAAE,MAAwC,EAAA;AACjE,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE;AAE/D,QAAA,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,EAAE;AAEvB,QAAA,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,aAAa,CAC9B,EAAE,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,EACpC,MAAM,CACP;IACH;IAEA,QAAQ,CACN,SAAiB,EACjB,IAAqD,EAAA;QAErD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,KAAI;AAC/B,YAAA,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAChC,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,KAAI;gBAC7B,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE;gBAE3C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CACrD,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,KAAI;oBACpB,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,GAAG,KAAK;AACzC,oBAAA,OAAO,GAAG;gBACZ,CAAC,EACD,EAA4B,CAC7B;gBAED,GAAG,CAAC,MAAM,CAAC,GAAG;AACZ,oBAAA,GAAG,iBAAiB;AACpB,oBAAA,GAAG,MAAM;iBACV;AAED,gBAAA,OAAO,GAAG;AACZ,YAAA,CAAC,EACD,EAAE,GAAG,GAAG,EAAE,CACX;AACH,QAAA,CAAC,CAAC;IACJ;IAEA,uBAAuB,CACrB,SAAiB,EACjB,OAA2C,EAAA;QAE3C,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC;IAC9C;AAEA,IAAA,gBAAgB,CAAC,MAAc,EAAA;QAC7B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CACnD,CAAC,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAC7B;IACH;uGA7KW,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAhB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,cAFf,MAAM,EAAA,CAAA;;2FAEP,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAH5B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;SAiLe,UAAU,GAAA;AACxB,IAAA,OAAO,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI;AACtC;AAEA;;;;;;;;;;;;;;;;;;AAkBG;SACa,mBAAmB,GAAA;AAGjC,IAAA,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAEtC,IAAA,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,MAAM,EAAE,CAE3C;AAED,IAAA,MAAM,GAAG,GAAG,CAAC,KAAa,KAAI;AAC5B,QAAA,IACE,KAAK,KAAK,SAAS,CAAC,MAAM,CAAC;AAC3B,YAAA,CAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC;YAC9B,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;YAE1C;AACF,QAAA,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;AAC9C,IAAA,CAAC;AACD,IAAA,MAAM,CAAC,GAAG,GAAG,GAAG;AAChB,IAAA,MAAM,CAAC,MAAM,GAAG,CAAC,OAAkC,KAAI;QACrD,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AACvC,QAAA,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;AAClB,IAAA,CAAC;AACD,IAAA,MAAM,CAAC,UAAU,GAAG,MAAM,MAAM;IAEhC,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,mBAAmB,CAAC,SAAS;AAEtD,IAAA,OAAO,MAAM;AACf;;AC3PA,SAAS,kBAAkB,CAA4B,IAAA,GAAoB,EAAE,EAAA;AAC3E,IAAA,IAAI,UAAmC;AAEvC,IAAA,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AACrB,QAAA,UAAU,GAAG,MAAM,IAAI;IACzB;AAAO,SAAA,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AAC5B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;AACnB,QAAA,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;IAC1C;SAAO;AACL,QAAA,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC,KAAI;AACpB,YAAA,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,QAAA,CAAC;IACH;AAEA,IAAA,OAAO,CAAC,CAAK,EAAE,CAAK,KAAa;AAC/B,QAAA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAAE,YAAA,OAAO,IAAI;AACzB,QAAA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;AAAE,YAAA,OAAO,KAAK;AAC1B,QAAA,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;AACzB,IAAA,CAAC;AACH;AAuBA,SAAS,WAAW,CAClB,EAAO,EACP,KAAuB,EAAA;IAEvB,MAAM,OAAO,GAAG,EAA+C;IAE/D,MAAM,QAAQ,GAAG,CACf,GAAS,EACT,GAAG,IAAuD,KACxC;AAClB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAsC;QAC9D,MAAM,SAAS,GAAG,GAAa;AAE/B,QAAA,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,CAAC;QAE5C,MAAM,MAAM,GAAG,SAAS,KAAK,MAAM,SAAS,CAAC;AAC7C,QAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM;AAChC,cAAE;AACF,cAAE,QAAQ,CAAC,MAAM,EAAE;AACf,gBAAA,KAAK,EAAE,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AACvD,aAAA,CAAC;AAEN,QAAA,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;AACpE,IAAA,CAAC;AAED,IAAA,OAAO,CAAC,QAAQ,GAAG,QAAQ;AAE3B,IAAA,OAAO,OAAO;AAChB;AAEM,SAAU,OAAO,CACrB,KAAuB,EAAA;AAEvB,IAAA,OAAO,CACL,GAAS,EACT,GAAG,IAAiD,KAC1C;AACV,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAgC;QACxD,MAAM,SAAS,GAAG,GAAa;QAE/B,OAAO,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;AACpE,IAAA,CAAC;AACH;AAEM,SAAU,iBAAiB,CAG/B,kBAA2C,EAC3C,KASC,EAAA;IAMD,MAAM,OAAO,GAAG,MAAW;AACzB,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAEtC,OAAO,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;AAC3C,IAAA,CAAC;IAED,IAAI,wBAAwB,GAAG,KAAK;AACpC,IAAA,MAAM,QAAQ,GAAG,YAAW;AAC1B,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC;QACtC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;AACtC,QAAA,MAAM,aAAa,GAAG,mBAAmB,EAAE;AAC3C,QAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAuC;AAEpE,QAAA,MAAM,OAAO,GAAG,QAAQ,IAAI,kBAAkB;AAC9C,QAAA,IAAI,CAAC,OAAO,IAAI,SAAS,EAAE,EAAE;YAC3B,OAAO,OAAO,CAAC,IAAI,CAAC,oCAAoC,MAAM,CAAA,CAAE,CAAC;QACnE;AAEA,QAAA,IAAI,OAAO,KAAK,kBAAkB,IAAI,wBAAwB;YAAE;AAEhE,QAAA,IAAI;AACF,YAAA,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE;YAEnC,IACE,OAAO,KAAK,kBAAkB;gBAC9B,WAAW,CAAC,MAAM,KAAK,MAAM;gBAC7B,SAAS,EAAE,EACX;AACA,gBAAA,OAAO,OAAO,CAAC,IAAI,CACjB,CAAA,sBAAA,EAAyB,MAAM,CAAA,SAAA,EAAY,WAAW,CAAC,MAAM,CAAA,CAAE,CAChE;YACH;AAEA,YAAA,KAAK,CAAC,uBAAuB,CAAC,WAAW,CAAC,SAAS,EAAE;AACnD,gBAAA,GAAG,KAAK;gBACR,CAAC,aAAa,GAAG,kBAAkB;AACpC,aAAA,CAAC;AAEF,YAAA,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAS,EAAE;AACpC,gBAAA,CAAC,MAAM,GAAG,WAAW,CAAC,IAAI;AAC3B,aAAA,CAAC;AACF,YAAA,IAAI,OAAO,KAAK,kBAAkB,EAAE;gBAClC,wBAAwB,GAAG,IAAI;YACjC;QACF;AAAE,QAAA,MAAM;YACN,IAAI,SAAS,EAAE,EAAE;AACf,gBAAA,OAAO,CAAC,IAAI,CAAC,0CAA0C,MAAM,CAAA,CAAE,CAAC;YAClE;QACF;AACF,IAAA,CAAC;IAED,OAAO;AACL,QAAA,gBAAgB,EAAE,OAAO;AACzB,QAAA,2BAA2B,EAAE,QAAQ;KACtC;AACH;;MCrKsB,SAAS,CAAA;IAMZ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAE7C,IAAA,SAAS,GAChB,KAAK,CAAC,QAAQ,oDAIX;AAEL,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAK;AACxB,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE;AAC7B,YAAA,QAAQ,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI;AAC9C,QAAA,CAAC,+CAAC;AAEF,QAAA,MAAM,IAAI,GAAG,QAAQ,CACnB,MAAK;AACH,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE;AAC7B,YAAA,QAAQ,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,SAAS;QACnD,CAAC,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,MAAA,EAAA,GAAA,EAAA,CAAA,EAEC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAI;AACd,gBAAA,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS;AAAE,oBAAA,OAAO,IAAI;AACnD,gBAAA,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS;AAAE,oBAAA,OAAO,KAAK;gBAEpD,MAAM,IAAI,GAAG,CAA2B;gBACxC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC9B,MAAM,IAAI,GAAG,CAA2B;gBAExC,IAAI,CAAC,IAAI,CAAC,MAAM;oBAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM;AAElD,gBAAA,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;AACrD,YAAA,CAAC,GAEJ;AAED,QAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,uDAAC;AAEzD,QAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC;AAClC,QAAA,MAAM,EAAE,GAAG,MAAM,CAA0B,UAAU,CAAC;AAEtD,QAAA,iBAAiB,CAAC;YAChB,KAAK,EAAE,MAAK;AACV,gBAAA,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;YACtE,CAAC;AACF,SAAA,CAAC;IACJ;uGApDoB,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAT,SAAS,EAAA,YAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAT,SAAS,EAAA,UAAA,EAAA,CAAA;kBAD9B;;;MCRqB,UAAU,CAAA;AAIb,IAAA,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAChC,IAAA,CAAC,GAAG,OAAO,CAAO,IAAI,CAAC,KAAK,CAAC;AAE9C,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC;QAErC,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YACnB,GAAG,CAAC,YAAY,EAAE;AACpB,QAAA,CAAC,CAAC;IACJ;AAEA,IAAA,SAAS,CACP,GAAM,EACN,GAAG,IAE2B,EAAA;AAE9B,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAC5B,CAAC,CAAC,KAAK,OAAO,CAAC,KAAK,QAAQ,CACY;QAE1C,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;IACnC;AACD;;AClCD;;AAEG;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/translate",
3
- "version": "21.0.1",
3
+ "version": "21.0.2",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "localize",