@acorex/core 19.13.0-next.0 → 19.13.0-next.1
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/fesm2022/acorex-core-components.mjs +3 -3
- package/fesm2022/acorex-core-config.mjs +3 -3
- package/fesm2022/acorex-core-date-time.mjs +25 -25
- package/fesm2022/acorex-core-events.mjs +3 -3
- package/fesm2022/acorex-core-file.mjs +10 -10
- package/fesm2022/acorex-core-format.mjs +36 -35
- package/fesm2022/acorex-core-format.mjs.map +1 -1
- package/fesm2022/acorex-core-image.mjs +3 -3
- package/fesm2022/acorex-core-locale.mjs +10 -10
- package/fesm2022/acorex-core-network.mjs +3 -3
- package/fesm2022/acorex-core-pipes.mjs +3 -3
- package/fesm2022/acorex-core-platform.mjs +3 -3
- package/fesm2022/acorex-core-storage.mjs +9 -9
- package/fesm2022/acorex-core-translation.mjs +245 -213
- package/fesm2022/acorex-core-translation.mjs.map +1 -1
- package/fesm2022/acorex-core-utils.mjs +143 -18
- package/fesm2022/acorex-core-utils.mjs.map +1 -1
- package/fesm2022/acorex-core-validation.mjs +40 -40
- package/format/lib/format.service.d.ts +8 -7
- package/package.json +1 -1
- package/translation/index.d.ts +1 -1
- package/translation/lib/translation-loader.service.d.ts +20 -0
- package/translation/lib/translation.config.d.ts +19 -6
- package/translation/lib/translation.loader.d.ts +2 -2
- package/translation/lib/translation.parser.d.ts +7 -0
- package/translation/lib/translation.resolver.d.ts +9 -0
- package/translation/lib/translation.service.d.ts +12 -32
- package/translation/lib/translation.types.d.ts +8 -2
- package/translation/lib/translator.pipe.d.ts +0 -2
- package/utils/index.d.ts +6 -5
- package/utils/lib/execution.utils.d.ts +33 -0
- package/utils/lib/string.utils.d.ts +4 -0
- package/utils/lib/string-util.d.ts +0 -6
- /package/utils/lib/{color-util.d.ts → color.utils.d.ts} +0 -0
- /package/utils/lib/{drawing-util.d.ts → drawing.utils.d.ts} +0 -0
- /package/utils/lib/{html-util.d.ts → html-utils.d.ts} +0 -0
- /package/utils/lib/{auto-unsubscribe.d.ts → lifecycle-helpers.utils.d.ts} +0 -0
@@ -184,10 +184,10 @@ class AXCookieStorageService {
|
|
184
184
|
}
|
185
185
|
}
|
186
186
|
}
|
187
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
188
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.
|
187
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXCookieStorageService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
188
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXCookieStorageService }); }
|
189
189
|
}
|
190
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
190
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXCookieStorageService, decorators: [{
|
191
191
|
type: Injectable
|
192
192
|
}], ctorParameters: () => [{ type: Document, decorators: [{
|
193
193
|
type: Inject,
|
@@ -242,10 +242,10 @@ class AXLocalStorageService {
|
|
242
242
|
return null;
|
243
243
|
}
|
244
244
|
}
|
245
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
246
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.
|
245
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXLocalStorageService, deps: [{ token: AX_LOCALSTORAGE_SECRET_KEY }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
246
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXLocalStorageService }); }
|
247
247
|
}
|
248
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
248
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXLocalStorageService, decorators: [{
|
249
249
|
type: Injectable
|
250
250
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
251
251
|
type: Inject,
|
@@ -277,10 +277,10 @@ class AXSessionStorageService {
|
|
277
277
|
return sessionStorage.removeItem(key);
|
278
278
|
}
|
279
279
|
}
|
280
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
281
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.
|
280
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXSessionStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
281
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXSessionStorageService }); }
|
282
282
|
}
|
283
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
283
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXSessionStorageService, decorators: [{
|
284
284
|
type: Injectable
|
285
285
|
}] });
|
286
286
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import * as i0 from '@angular/core';
|
2
2
|
import { InjectionToken, inject, Injectable, Directive, Pipe, provideAppInitializer, NgModule } from '@angular/core';
|
3
|
-
import {
|
4
|
-
import {
|
5
|
-
import {
|
6
|
-
import {
|
3
|
+
import { of, shareReplay, firstValueFrom, BehaviorSubject, switchMap, from } from 'rxjs';
|
4
|
+
import { get } from 'lodash-es';
|
5
|
+
import { AXLocaleService } from '@acorex/core/locale';
|
6
|
+
import { waitFor } from '@acorex/core/utils';
|
7
7
|
|
8
8
|
const AX_TRANSLATION_CONFIG = new InjectionToken('AX_TRANSLATION_CONFIG', {
|
9
9
|
providedIn: 'root',
|
@@ -12,9 +12,17 @@ const AX_TRANSLATION_CONFIG = new InjectionToken('AX_TRANSLATION_CONFIG', {
|
|
12
12
|
},
|
13
13
|
});
|
14
14
|
const AXTranslationDefaultConfig = {
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
defaults: {
|
16
|
+
lang: 'en-US',
|
17
|
+
scope: 'common',
|
18
|
+
},
|
19
|
+
preload: {
|
20
|
+
langs: ['en-US'],
|
21
|
+
scopes: ['common'],
|
22
|
+
},
|
23
|
+
resolver: {
|
24
|
+
scopeKey: 'scope',
|
25
|
+
},
|
18
26
|
};
|
19
27
|
function translationConfig(config = {}) {
|
20
28
|
const result = {
|
@@ -25,7 +33,7 @@ function translationConfig(config = {}) {
|
|
25
33
|
}
|
26
34
|
|
27
35
|
class AXTranslationLoaderDefault {
|
28
|
-
|
36
|
+
load(options) {
|
29
37
|
return of({});
|
30
38
|
}
|
31
39
|
}
|
@@ -36,232 +44,256 @@ const AX_TRANSLATION_LOADER = new InjectionToken('AX_TRANSLATION_LOADER', {
|
|
36
44
|
},
|
37
45
|
});
|
38
46
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
return this.config.defaultLang;
|
46
|
-
}
|
47
|
-
getActiveLang() {
|
48
|
-
return this.activeLang.getValue();
|
47
|
+
class AXTranslationLoaderService {
|
48
|
+
constructor() {
|
49
|
+
this.loader = inject(AX_TRANSLATION_LOADER);
|
50
|
+
this.config = inject(AX_TRANSLATION_CONFIG);
|
51
|
+
this.cache = new Map();
|
52
|
+
this.inflight = new Map();
|
49
53
|
}
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
load(lang, scope) {
|
55
|
+
const key = `${lang}:${scope}`;
|
56
|
+
console.log('load', key);
|
57
|
+
if (this.cache.has(key)) {
|
58
|
+
return of(this.cache.get(key));
|
59
|
+
}
|
60
|
+
if (!this.inflight.has(key)) {
|
61
|
+
const obs = this.loader.load({ lang, scope }).pipe(shareReplay(1));
|
62
|
+
this.inflight.set(key, obs);
|
63
|
+
obs.subscribe({
|
64
|
+
next: (data) => {
|
65
|
+
this.cache.set(key, data);
|
66
|
+
this.inflight.delete(key);
|
67
|
+
},
|
68
|
+
error: () => {
|
69
|
+
this.inflight.delete(key);
|
70
|
+
},
|
56
71
|
});
|
57
72
|
}
|
73
|
+
return this.inflight.get(key);
|
58
74
|
}
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
this.
|
66
|
-
this.
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
singletonInstance = this;
|
74
|
-
//
|
75
|
-
this.localeService.profileChanged$.subscribe((locale) => {
|
76
|
-
if (locale?.localeInfo?.code) {
|
77
|
-
this.setActiveLang(locale.localeInfo.code);
|
78
|
-
}
|
75
|
+
peek(lang, scope, key) {
|
76
|
+
const cacheKey = `${lang}:${scope}`;
|
77
|
+
const data = this.cache.get(cacheKey);
|
78
|
+
return get(data, key, null);
|
79
|
+
}
|
80
|
+
async preload(options) {
|
81
|
+
const langs = [...new Set(options?.langs ?? this.config.preload?.langs ?? [this.config.defaults.lang])];
|
82
|
+
const scopes = [...new Set(options?.scopes ?? this.config.preload?.scopes ?? [this.config.defaults.scope])];
|
83
|
+
const promises = [];
|
84
|
+
langs.forEach(lang => {
|
85
|
+
scopes.forEach(scope => {
|
86
|
+
const p = firstValueFrom(this.load(lang, scope));
|
87
|
+
promises.push(p);
|
88
|
+
});
|
79
89
|
});
|
90
|
+
await Promise.all(promises);
|
80
91
|
}
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
if (this.translationCache[lang]?.[scope]) {
|
85
|
-
return of(this.translationCache[lang][scope]);
|
86
|
-
}
|
87
|
-
// Use the new method to handle ongoing requests and loading
|
88
|
-
return this.fetchTranslationFiles(lang, scope);
|
89
|
-
}));
|
90
|
-
return forkJoin(requests);
|
92
|
+
clear() {
|
93
|
+
this.cache.clear();
|
94
|
+
this.inflight.clear();
|
91
95
|
}
|
92
|
-
|
93
|
-
|
94
|
-
// Return existing observable if the request is already in progress
|
95
|
-
if (this.ongoingRequests.has(requestKey)) {
|
96
|
-
return this.ongoingRequests.get(requestKey);
|
97
|
-
}
|
98
|
-
// Load translations if not in cache or ongoing requests
|
99
|
-
const translationObservable = this.loader.getTranslation({ lang, scope }).pipe(tap((translations) => this.setTranslationCache(lang, scope, translations)), catchError((error) => {
|
100
|
-
this.handleError(`Error loading translations for lang: ${lang}, scope: ${scope}`, error);
|
101
|
-
return of(null);
|
102
|
-
}), finalize(() => {
|
103
|
-
this.eventService.emitEvent({
|
104
|
-
type: AXLocaleEvents.AXLanguageLoaded,
|
105
|
-
payload: lang,
|
106
|
-
});
|
107
|
-
this.ongoingRequests.delete(requestKey);
|
108
|
-
}), shareReplay(1));
|
109
|
-
this.ongoingRequests.set(requestKey, translationObservable);
|
110
|
-
return translationObservable;
|
96
|
+
getFallbackLangs(lang) {
|
97
|
+
return this.config.fallbacks?.langs?.[lang] ?? [];
|
111
98
|
}
|
112
|
-
|
113
|
-
|
114
|
-
* Set translation data into cache
|
115
|
-
*/
|
116
|
-
setTranslationCache(lang, scope, translations) {
|
117
|
-
set(this.translationCache, `${lang}.${scope}`, translations);
|
99
|
+
getFallbackScopes(scope) {
|
100
|
+
return this.config.fallbacks?.scopes?.[scope] ?? [];
|
118
101
|
}
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
102
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
103
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationLoaderService, providedIn: 'root' }); }
|
104
|
+
}
|
105
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationLoaderService, decorators: [{
|
106
|
+
type: Injectable,
|
107
|
+
args: [{ providedIn: 'root' }]
|
108
|
+
}] });
|
109
|
+
|
110
|
+
class TranslationParserService {
|
111
|
+
constructor() {
|
112
|
+
this.legacyRegex = /t\(["']([^"']+)["']\s*(?:,\s*(\{.*?\}))?\)/g;
|
113
|
+
this.inlineRegex = /@([a-zA-Z\-]+:)?([a-zA-Z0-9_-]+):([a-zA-Z0-9_.:-]+)(?=[\\s.,;!?)]|$)/g;
|
124
114
|
}
|
125
|
-
|
126
|
-
return
|
115
|
+
isExpression(value) {
|
116
|
+
return typeof value === 'string' && (value.includes('t(') || value.includes('@'));
|
127
117
|
}
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
if (params && typeof translation === 'string') {
|
139
|
-
Object.keys(params).forEach((paramKey) => {
|
140
|
-
translation = translation.replace(new RegExp(`{{\\s*${paramKey}\\s*}}`, 'g'), params[paramKey]);
|
141
|
-
});
|
118
|
+
parse(expression, currentLang, currentScope) {
|
119
|
+
const tokens = [];
|
120
|
+
// Extract inline references like @lang:scope:key or @scope:key
|
121
|
+
let inlineMatch;
|
122
|
+
while ((inlineMatch = this.inlineRegex.exec(expression)) !== null) {
|
123
|
+
const langPart = inlineMatch[1]?.replace(':', '') ?? null;
|
124
|
+
const scope = inlineMatch[2] ?? currentScope;
|
125
|
+
const key = inlineMatch[3];
|
126
|
+
const fullMatch = inlineMatch[0];
|
127
|
+
tokens.push({ lang: langPart || currentLang, scope, key, fullMatch });
|
142
128
|
}
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
129
|
+
// Extract legacy expressions
|
130
|
+
let legacyMatch;
|
131
|
+
while ((legacyMatch = this.legacyRegex.exec(expression)) !== null) {
|
132
|
+
const key = legacyMatch[1];
|
133
|
+
const rawOptions = legacyMatch[2];
|
134
|
+
let scope = currentScope;
|
135
|
+
let lang = currentLang;
|
136
|
+
if (rawOptions) {
|
137
|
+
try {
|
138
|
+
const jsonString = rawOptions
|
139
|
+
.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?\s*:/g, '"$2":')
|
140
|
+
.replace(/'/g, '"');
|
141
|
+
const options = JSON.parse(jsonString);
|
142
|
+
scope = options.scope || scope;
|
143
|
+
lang = options.lang || lang;
|
144
|
+
}
|
145
|
+
catch (err) {
|
146
|
+
console.error('Invalid translation expression options:', err);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
tokens.push({ key, scope, lang, fullMatch: legacyMatch[0] });
|
148
150
|
}
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
return tokens;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
class TranslationResolverService {
|
156
|
+
constructor() {
|
157
|
+
this.loaderService = inject(AXTranslationLoaderService);
|
158
|
+
this.cache = new Map();
|
159
|
+
this.inflight = new Map();
|
160
|
+
this.parser = new TranslationParserService();
|
161
|
+
}
|
162
|
+
async resolve(lang, scope, key, params) {
|
163
|
+
const cacheKey = `${lang}:${scope}`;
|
164
|
+
// Load and cache if not present
|
165
|
+
if (!this.cache.has(cacheKey)) {
|
166
|
+
if (!this.inflight.has(cacheKey)) {
|
167
|
+
const fetchPromise = firstValueFrom(this.loaderService.load(lang, scope));
|
168
|
+
this.inflight.set(cacheKey, fetchPromise);
|
169
|
+
const data = await fetchPromise;
|
170
|
+
this.cache.set(cacheKey, data);
|
171
|
+
this.inflight.delete(cacheKey);
|
158
172
|
}
|
159
|
-
|
160
|
-
|
161
|
-
.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?\s*:/g, '"$2":') // Ensure keys are quoted
|
162
|
-
.replace(/'/g, '"'); // Replace single quotes with double quotes
|
163
|
-
const options = JSON.parse(jsonString);
|
164
|
-
matches.push({
|
165
|
-
key,
|
166
|
-
scope: options.scope || null,
|
167
|
-
lang: options.lang || null,
|
168
|
-
fullMatch: match[0],
|
169
|
-
});
|
173
|
+
else {
|
174
|
+
await this.inflight.get(cacheKey); // wait for the inflight fetch
|
170
175
|
}
|
171
|
-
|
172
|
-
|
173
|
-
|
176
|
+
}
|
177
|
+
const translations = this.cache.get(cacheKey);
|
178
|
+
let result = get(translations, key, key);
|
179
|
+
// Recursively resolve references
|
180
|
+
if (typeof result === 'string' && this.parser.isExpression(result)) {
|
181
|
+
const tokens = this.parser.parse(result, lang, scope);
|
182
|
+
if (tokens.length > 0) {
|
183
|
+
const first = tokens[0];
|
184
|
+
result = await this.resolve(first.lang || lang, first.scope || scope, first.key, params);
|
174
185
|
}
|
175
186
|
}
|
176
|
-
this.
|
177
|
-
|
187
|
+
return this.format(result, params);
|
188
|
+
}
|
189
|
+
format(text, params) {
|
190
|
+
if (!params || typeof text !== 'string')
|
191
|
+
return text;
|
192
|
+
return Object.keys(params).reduce((out, key) => {
|
193
|
+
const re = new RegExp(`{{\s*${key}\s*}}`, 'g');
|
194
|
+
return out.replace(re, params[key]);
|
195
|
+
}, text);
|
178
196
|
}
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
197
|
+
}
|
198
|
+
|
199
|
+
let singletonInstance;
|
200
|
+
function translateSync(key, options) {
|
201
|
+
return singletonInstance.translateSync(key, options);
|
202
|
+
}
|
203
|
+
class AXTranslationService {
|
204
|
+
constructor() {
|
205
|
+
this.localeService = inject(AXLocaleService);
|
206
|
+
this.config = inject(AX_TRANSLATION_CONFIG);
|
207
|
+
this.loader = inject(AXTranslationLoaderService);
|
208
|
+
this.parser = new TranslationParserService();
|
209
|
+
this.resolver = new TranslationResolverService();
|
210
|
+
this.activeLang = new BehaviorSubject('en-US');
|
211
|
+
this.langChanges$ = this.activeLang.asObservable();
|
212
|
+
singletonInstance = this;
|
213
|
+
this.localeService.profileChanged$.subscribe((locale) => {
|
214
|
+
if (locale?.localeInfo?.code) {
|
215
|
+
this.setActiveLang(locale.localeInfo.code);
|
216
|
+
}
|
184
217
|
});
|
185
218
|
}
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
if (!this.isExpression(text)) {
|
190
|
-
return this.loadLanguagesAndScopes([contextLang], [contextScope]).pipe(map(() => this.translateKey(text, contextLang, contextScope, params)), catchError((error) => {
|
191
|
-
this.handleError(`Error during translation:`, error);
|
192
|
-
return of(text); // Fallback to the original text
|
193
|
-
}));
|
219
|
+
setActiveLang(lang) {
|
220
|
+
if (lang && lang !== this.activeLang.getValue()) {
|
221
|
+
this.activeLang.next(lang);
|
194
222
|
}
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
const langs = Array.from(new Set(Array.from(langScopeSet).map((pair) => pair.split('_')[0])));
|
199
|
-
const scopes = Array.from(new Set(Array.from(langScopeSet).map((pair) => pair.split('_')[1])));
|
200
|
-
// Load all required languages and scopes
|
201
|
-
return this.loadLanguagesAndScopes(langs, scopes).pipe(map(() => {
|
202
|
-
// Resolve translations after loading
|
203
|
-
const translations = matches.reduce((acc, { key, scope, lang, fullMatch }) => {
|
204
|
-
const resolvedScope = scope || contextScope;
|
205
|
-
const resolvedLang = lang || contextLang;
|
206
|
-
acc[fullMatch] = this.translateKey(key, resolvedLang, resolvedScope, params);
|
207
|
-
return acc;
|
208
|
-
}, {});
|
209
|
-
// Replace all matches in the text with their resolved translations
|
210
|
-
return matches.reduce((result, { fullMatch }) => result.replace(new RegExp(fullMatch.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), translations[fullMatch]), text);
|
211
|
-
}), catchError((error) => {
|
212
|
-
this.handleError(`Error during translation:`, error);
|
213
|
-
return of(text); // Fallback to the original text
|
214
|
-
}));
|
223
|
+
}
|
224
|
+
getActiveLang() {
|
225
|
+
return this.activeLang.getValue();
|
215
226
|
}
|
216
227
|
translate$(text, options) {
|
217
|
-
if (
|
218
|
-
return
|
219
|
-
}
|
220
|
-
|
221
|
-
|
228
|
+
if (!text)
|
229
|
+
return of('');
|
230
|
+
const staticOptions = { ...options };
|
231
|
+
const staticScope = staticOptions.scope ?? this.config.defaults.scope;
|
232
|
+
return this.langChanges$.pipe(switchMap(lang => {
|
233
|
+
return from(this.translateAsync(text, {
|
234
|
+
...staticOptions,
|
235
|
+
lang: staticOptions.lang ?? lang,
|
236
|
+
scope: staticScope
|
237
|
+
}));
|
222
238
|
}));
|
223
239
|
}
|
224
240
|
async translateAsync(text, options) {
|
225
|
-
|
241
|
+
const lang = options?.lang ?? this.getActiveLang() ?? this.config.defaults.lang;
|
242
|
+
const scope = options?.scope ?? this.config.defaults.scope;
|
243
|
+
const params = options?.params;
|
244
|
+
if (!this.parser.isExpression(text)) {
|
245
|
+
const resolved = await this.resolver.resolve(lang, scope, text, params);
|
246
|
+
return this.resolver.format(resolved, params);
|
247
|
+
}
|
248
|
+
const tokens = this.parser.parse(text, lang, scope);
|
249
|
+
const results = await Promise.all(tokens.map(token => this.resolver.resolve(token.lang ?? lang, token.scope ?? scope, token.key, params)
|
250
|
+
.then(translated => [token.fullMatch, this.resolver.format(translated, params)])));
|
251
|
+
return results.reduce((output, [match, translated]) => output.replace(match, translated), text);
|
226
252
|
}
|
227
|
-
//#endregion
|
228
|
-
//#region Sync Translation Methods
|
229
253
|
translateSync(text, options) {
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
254
|
+
const lang = options?.lang ?? this.getActiveLang() ?? this.config.defaults.lang;
|
255
|
+
const scope = options?.scope ?? this.config.defaults.scope;
|
256
|
+
const params = options?.params;
|
257
|
+
const waitForLoad = options?.waitForLoad ?? false;
|
258
|
+
const timeoutMs = options?.timeoutMs ?? 100;
|
259
|
+
if (!this.parser.isExpression(text)) {
|
260
|
+
let translated = this.loader.peek(lang, scope, text);
|
261
|
+
if (!translated && waitForLoad) {
|
262
|
+
translated = waitFor(() => this.loader.peek(lang, scope, text), () => this.loader.load(lang, scope).subscribe(), timeoutMs);
|
263
|
+
}
|
264
|
+
return this.resolver.format(translated ?? text, params);
|
235
265
|
}
|
236
|
-
|
237
|
-
|
238
|
-
const
|
239
|
-
|
240
|
-
const
|
241
|
-
const
|
242
|
-
|
243
|
-
if (!
|
244
|
-
|
266
|
+
const tokens = this.parser.parse(text, lang, scope);
|
267
|
+
let result = text;
|
268
|
+
for (const token of tokens) {
|
269
|
+
const targetLang = token.lang ?? lang;
|
270
|
+
const targetScope = token.scope ?? scope;
|
271
|
+
const key = token.key;
|
272
|
+
let translation = this.loader.peek(targetLang, targetScope, key);
|
273
|
+
if (!translation) {
|
274
|
+
translation = waitFor(() => this.loader.peek(targetLang, targetScope, key), () => this.loader.load(targetLang, targetScope).subscribe(), waitForLoad ? timeoutMs : 0) ?? key;
|
245
275
|
}
|
246
|
-
|
247
|
-
}
|
248
|
-
|
249
|
-
return matches.reduce((result, { fullMatch }) => result.replace(fullMatch, translations[fullMatch]), text);
|
276
|
+
result = result.replace(token.fullMatch, this.resolver.format(translation, params));
|
277
|
+
}
|
278
|
+
return result;
|
250
279
|
}
|
251
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
252
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.
|
280
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
281
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationService, providedIn: 'root' }); }
|
253
282
|
}
|
254
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
283
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationService, decorators: [{
|
255
284
|
type: Injectable,
|
256
|
-
args: [{
|
285
|
+
args: [{
|
286
|
+
providedIn: 'root'
|
287
|
+
}]
|
257
288
|
}], ctorParameters: () => [] });
|
258
289
|
|
259
290
|
const loadTranslationScope = (route, state) => {
|
260
|
-
const
|
291
|
+
const translationLoaderService = inject(AXTranslationLoaderService);
|
292
|
+
const translationService = inject(AXTranslationService);
|
261
293
|
const config = inject(AX_TRANSLATION_CONFIG);
|
262
|
-
const scopeValue = route.data[config.
|
294
|
+
const scopeValue = route.data[config.resolver?.scopeKey];
|
263
295
|
const scopes = Array.isArray(scopeValue) ? scopeValue : [scopeValue];
|
264
|
-
return
|
296
|
+
return translationLoaderService.preload({ langs: [translationService.getActiveLang()], scopes });
|
265
297
|
};
|
266
298
|
|
267
299
|
class AXTranslatorDirective {
|
@@ -278,17 +310,17 @@ class AXTranslatorDirective {
|
|
278
310
|
},
|
279
311
|
});
|
280
312
|
}
|
281
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
282
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.
|
313
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslatorDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: AXTranslationService }], target: i0.ɵɵFactoryTarget.Directive }); }
|
314
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.8", type: AXTranslatorDirective, isStandalone: true, selector: "[translate]", ngImport: i0 }); }
|
283
315
|
}
|
284
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
316
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslatorDirective, decorators: [{
|
285
317
|
type: Directive,
|
286
318
|
args: [{ selector: '[translate]' }]
|
287
319
|
}], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: AXTranslationService }] });
|
288
320
|
|
289
321
|
class AXTranslatorPipe {
|
290
|
-
constructor(
|
291
|
-
this.service =
|
322
|
+
constructor() {
|
323
|
+
this.service = inject(AXTranslationService);
|
292
324
|
}
|
293
325
|
transform(key, options) {
|
294
326
|
if (!key) {
|
@@ -296,40 +328,40 @@ class AXTranslatorPipe {
|
|
296
328
|
}
|
297
329
|
return this.service.translate$(key, options);
|
298
330
|
}
|
299
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
300
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.
|
331
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslatorPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
332
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.8", ngImport: i0, type: AXTranslatorPipe, isStandalone: true, name: "translate" }); }
|
301
333
|
}
|
302
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
334
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslatorPipe, decorators: [{
|
303
335
|
type: Pipe,
|
304
336
|
args: [{
|
305
337
|
name: 'translate',
|
306
338
|
pure: true,
|
307
339
|
}]
|
308
|
-
}]
|
340
|
+
}] });
|
309
341
|
|
310
|
-
function initializeApp(translatorService
|
342
|
+
function initializeApp(translatorService) {
|
311
343
|
return () => {
|
312
|
-
return translatorService.
|
344
|
+
return translatorService.preload();
|
313
345
|
};
|
314
346
|
}
|
315
347
|
class AXTranslationModule {
|
316
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.
|
317
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.
|
318
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.
|
348
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
349
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationModule, imports: [AXTranslatorPipe, AXTranslatorDirective], exports: [AXTranslatorPipe, AXTranslatorDirective] }); }
|
350
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationModule, providers: [
|
319
351
|
provideAppInitializer(() => {
|
320
|
-
const initializerFn = initializeApp(inject(
|
352
|
+
const initializerFn = initializeApp(inject(AXTranslationLoaderService));
|
321
353
|
return initializerFn();
|
322
354
|
}),
|
323
355
|
] }); }
|
324
356
|
}
|
325
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.
|
357
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.8", ngImport: i0, type: AXTranslationModule, decorators: [{
|
326
358
|
type: NgModule,
|
327
359
|
args: [{
|
328
360
|
imports: [AXTranslatorPipe, AXTranslatorDirective],
|
329
361
|
exports: [AXTranslatorPipe, AXTranslatorDirective],
|
330
362
|
providers: [
|
331
363
|
provideAppInitializer(() => {
|
332
|
-
const initializerFn = initializeApp(inject(
|
364
|
+
const initializerFn = initializeApp(inject(AXTranslationLoaderService));
|
333
365
|
return initializerFn();
|
334
366
|
}),
|
335
367
|
],
|