@derschmidtler/ngx-translate-router 10.0.0
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.
|
@@ -0,0 +1,1401 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, Inject, Injectable, Pipe, inject, PLATFORM_ID, Compiler, runInInjectionContext, NgModuleFactory, Optional, SkipSelf, APP_INITIALIZER, NgModule } from '@angular/core';
|
|
3
|
+
import * as i3 from '@angular/router';
|
|
4
|
+
import { NavigationStart, NavigationCancel, Router, ActivatedRoute, ROUTES, PRIMARY_OUTLET, ɵEmptyOutletComponent as _EmptyOutletComponent, RouteReuseStrategy, RouterModule } from '@angular/router';
|
|
5
|
+
import { firstValueFrom, Observable, Subject, ReplaySubject, isObservable } from 'rxjs';
|
|
6
|
+
import { filter, pairwise } from 'rxjs/operators';
|
|
7
|
+
import * as i1 from '@ngx-translate/core';
|
|
8
|
+
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
|
9
|
+
import * as i2 from '@angular/common';
|
|
10
|
+
import { Location, isPlatformBrowser, CommonModule } from '@angular/common';
|
|
11
|
+
import { HttpParams } from '@angular/common/http';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Guard to make sure we have single initialization of forRoot
|
|
15
|
+
*/
|
|
16
|
+
const LOCALIZE_ROUTER_FORROOT_GUARD = new InjectionToken('LOCALIZE_ROUTER_FORROOT_GUARD');
|
|
17
|
+
/**
|
|
18
|
+
* Static provider for keeping track of routes
|
|
19
|
+
*/
|
|
20
|
+
const RAW_ROUTES = new InjectionToken('RAW_ROUTES');
|
|
21
|
+
/**
|
|
22
|
+
* Type for Caching of default language
|
|
23
|
+
*/
|
|
24
|
+
// export type CacheMechanism = 'LocalStorage' | 'Cookie';
|
|
25
|
+
/**
|
|
26
|
+
* Namespace for fail proof access of CacheMechanism
|
|
27
|
+
*/
|
|
28
|
+
var CacheMechanism;
|
|
29
|
+
(function (CacheMechanism) {
|
|
30
|
+
CacheMechanism["LocalStorage"] = "LocalStorage";
|
|
31
|
+
CacheMechanism["SessionStorage"] = "SessionStorage";
|
|
32
|
+
CacheMechanism["Cookie"] = "Cookie";
|
|
33
|
+
})(CacheMechanism || (CacheMechanism = {}));
|
|
34
|
+
/**
|
|
35
|
+
* Boolean to indicate whether to use cached language value
|
|
36
|
+
*/
|
|
37
|
+
const USE_CACHED_LANG = new InjectionToken('USE_CACHED_LANG');
|
|
38
|
+
/**
|
|
39
|
+
* Cache mechanism type
|
|
40
|
+
*/
|
|
41
|
+
const CACHE_MECHANISM = new InjectionToken('CACHE_MECHANISM');
|
|
42
|
+
/**
|
|
43
|
+
* Cache name
|
|
44
|
+
*/
|
|
45
|
+
const CACHE_NAME = new InjectionToken('CACHE_NAME');
|
|
46
|
+
/**
|
|
47
|
+
* Cookie cache format
|
|
48
|
+
*/
|
|
49
|
+
const COOKIE_FORMAT = new InjectionToken('COOKIE_FORMAT');
|
|
50
|
+
/**
|
|
51
|
+
* Cookie cache format
|
|
52
|
+
*/
|
|
53
|
+
const INITIAL_NAVIGATION = new InjectionToken('INITIAL_NAVIGATION');
|
|
54
|
+
/**
|
|
55
|
+
* Function for calculating default language
|
|
56
|
+
*/
|
|
57
|
+
const DEFAULT_LANG_FUNCTION = new InjectionToken('DEFAULT_LANG_FUNCTION');
|
|
58
|
+
/**
|
|
59
|
+
* Boolean to indicate whether prefix should be set for single language scenarios
|
|
60
|
+
*/
|
|
61
|
+
const ALWAYS_SET_PREFIX = new InjectionToken('ALWAYS_SET_PREFIX');
|
|
62
|
+
const LOCALIZE_CACHE_NAME = 'LOCALIZE_DEFAULT_LANGUAGE';
|
|
63
|
+
const DEFAULT_COOKIE_FORMAT = '{{value}};{{expires}}';
|
|
64
|
+
const DEFAULT_INITIAL_NAVIGATION = false;
|
|
65
|
+
class LocalizeRouterSettings {
|
|
66
|
+
/**
|
|
67
|
+
* Settings for localize router
|
|
68
|
+
*/
|
|
69
|
+
constructor(useCachedLang = true, alwaysSetPrefix = true, cacheMechanism = CacheMechanism.LocalStorage, cacheName = LOCALIZE_CACHE_NAME, defaultLangFunction = void 0, cookieFormat = DEFAULT_COOKIE_FORMAT, initialNavigation = DEFAULT_INITIAL_NAVIGATION) {
|
|
70
|
+
this.useCachedLang = useCachedLang;
|
|
71
|
+
this.alwaysSetPrefix = alwaysSetPrefix;
|
|
72
|
+
this.cacheName = cacheName;
|
|
73
|
+
this.cookieFormat = cookieFormat;
|
|
74
|
+
this.initialNavigation = initialNavigation;
|
|
75
|
+
this.cacheMechanism = cacheMechanism;
|
|
76
|
+
this.defaultLangFunction = defaultLangFunction;
|
|
77
|
+
}
|
|
78
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterSettings, deps: [{ token: USE_CACHED_LANG }, { token: ALWAYS_SET_PREFIX }, { token: CACHE_MECHANISM }, { token: CACHE_NAME }, { token: DEFAULT_LANG_FUNCTION }, { token: COOKIE_FORMAT }, { token: INITIAL_NAVIGATION }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
79
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterSettings }); }
|
|
80
|
+
}
|
|
81
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterSettings, decorators: [{
|
|
82
|
+
type: Injectable
|
|
83
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
84
|
+
type: Inject,
|
|
85
|
+
args: [USE_CACHED_LANG]
|
|
86
|
+
}] }, { type: undefined, decorators: [{
|
|
87
|
+
type: Inject,
|
|
88
|
+
args: [ALWAYS_SET_PREFIX]
|
|
89
|
+
}] }, { type: undefined, decorators: [{
|
|
90
|
+
type: Inject,
|
|
91
|
+
args: [CACHE_MECHANISM]
|
|
92
|
+
}] }, { type: undefined, decorators: [{
|
|
93
|
+
type: Inject,
|
|
94
|
+
args: [CACHE_NAME]
|
|
95
|
+
}] }, { type: undefined, decorators: [{
|
|
96
|
+
type: Inject,
|
|
97
|
+
args: [DEFAULT_LANG_FUNCTION]
|
|
98
|
+
}] }, { type: undefined, decorators: [{
|
|
99
|
+
type: Inject,
|
|
100
|
+
args: [COOKIE_FORMAT]
|
|
101
|
+
}] }, { type: undefined, decorators: [{
|
|
102
|
+
type: Inject,
|
|
103
|
+
args: [INITIAL_NAVIGATION]
|
|
104
|
+
}] }] });
|
|
105
|
+
|
|
106
|
+
const COOKIE_EXPIRY = 30; // 1 month
|
|
107
|
+
/**
|
|
108
|
+
* Abstract class for parsing localization
|
|
109
|
+
*/
|
|
110
|
+
class LocalizeParser {
|
|
111
|
+
/**
|
|
112
|
+
* Loader constructor
|
|
113
|
+
*/
|
|
114
|
+
constructor(translate, location, settings) {
|
|
115
|
+
this.translate = translate;
|
|
116
|
+
this.location = location;
|
|
117
|
+
this.settings = settings;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Prepare routes to be fully usable by ngx-translate-router
|
|
121
|
+
* @param routes
|
|
122
|
+
*/
|
|
123
|
+
/* private initRoutes(routes: Routes, prefix = '') {
|
|
124
|
+
routes.forEach(route => {
|
|
125
|
+
if (route.path !== '**') {
|
|
126
|
+
const routeData: any = route.data = route.data || {};
|
|
127
|
+
routeData.localizeRouter = {};
|
|
128
|
+
routeData.localizeRouter.fullPath = `${prefix}/${route.path}`;
|
|
129
|
+
if (route.children && route.children.length > 0) {
|
|
130
|
+
this.initRoutes(route.children, routeData.localizeRouter.fullPath);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
} */
|
|
135
|
+
/**
|
|
136
|
+
* Initialize language and routes
|
|
137
|
+
*/
|
|
138
|
+
init(routes) {
|
|
139
|
+
let selectedLanguage;
|
|
140
|
+
// this.initRoutes(routes);
|
|
141
|
+
this.routes = routes;
|
|
142
|
+
if (!this.locales || !this.locales.length) {
|
|
143
|
+
return Promise.resolve();
|
|
144
|
+
}
|
|
145
|
+
/** detect current language */
|
|
146
|
+
const locationLang = this.getLocationLang();
|
|
147
|
+
const browserLang = this._getBrowserLang();
|
|
148
|
+
if (this.settings.defaultLangFunction) {
|
|
149
|
+
this.defaultLang = this.settings.defaultLangFunction(this.locales, this._cachedLang, browserLang);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
this.defaultLang = this._cachedLang || browserLang || this.locales[0];
|
|
153
|
+
}
|
|
154
|
+
selectedLanguage = locationLang || this.defaultLang;
|
|
155
|
+
this.translate.setDefaultLang(this.defaultLang);
|
|
156
|
+
let children = [];
|
|
157
|
+
/** if set prefix is enforced */
|
|
158
|
+
if (this.settings.alwaysSetPrefix) {
|
|
159
|
+
const baseRoute = { path: '', redirectTo: this.defaultLang, pathMatch: 'full' };
|
|
160
|
+
/** extract potential wildcard route */
|
|
161
|
+
const wildcardIndex = routes.findIndex((route) => route.path === '**');
|
|
162
|
+
if (wildcardIndex !== -1) {
|
|
163
|
+
this._wildcardRoute = routes.splice(wildcardIndex, 1)[0];
|
|
164
|
+
}
|
|
165
|
+
children = this.routes.splice(0, this.routes.length, baseRoute);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
children = [...this.routes]; // shallow copy of routes
|
|
169
|
+
}
|
|
170
|
+
/** exclude certain routes */
|
|
171
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
172
|
+
if (children[i].data && children[i].data['skipRouteLocalization']) {
|
|
173
|
+
if (this.settings.alwaysSetPrefix) {
|
|
174
|
+
// add directly to routes
|
|
175
|
+
this.routes.push(children[i]);
|
|
176
|
+
}
|
|
177
|
+
// remove from routes to translate only if doesn't have to translate `redirectTo` property
|
|
178
|
+
if (children[i].redirectTo === undefined || !(children[i].data['skipRouteLocalization']['localizeRedirectTo']) || typeof children[i].redirectTo === 'function') {
|
|
179
|
+
children.splice(i, 1);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** append children routes */
|
|
184
|
+
if (children && children.length) {
|
|
185
|
+
if (this.locales.length > 1 || this.settings.alwaysSetPrefix) {
|
|
186
|
+
this._languageRoute = { children: children };
|
|
187
|
+
this.routes.unshift(this._languageRoute);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** ...and potential wildcard route */
|
|
191
|
+
if (this._wildcardRoute && this.settings.alwaysSetPrefix) {
|
|
192
|
+
this.routes.push(this._wildcardRoute);
|
|
193
|
+
}
|
|
194
|
+
/** translate routes */
|
|
195
|
+
return firstValueFrom(this.translateRoutes(selectedLanguage));
|
|
196
|
+
}
|
|
197
|
+
initChildRoutes(routes) {
|
|
198
|
+
this._translateRouteTree(routes);
|
|
199
|
+
return routes;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Translate routes to selected language
|
|
203
|
+
*/
|
|
204
|
+
translateRoutes(language) {
|
|
205
|
+
return new Observable((observer) => {
|
|
206
|
+
this._cachedLang = language;
|
|
207
|
+
if (this._languageRoute) {
|
|
208
|
+
this._languageRoute.path = language;
|
|
209
|
+
}
|
|
210
|
+
this.translate.use(language).subscribe((translations) => {
|
|
211
|
+
this._translationObject = translations;
|
|
212
|
+
this.currentLang = language;
|
|
213
|
+
if (this._languageRoute) {
|
|
214
|
+
this._translateRouteTree(this._languageRoute.children, true);
|
|
215
|
+
// if there is wildcard route
|
|
216
|
+
if (this._wildcardRoute && this._wildcardRoute.redirectTo) {
|
|
217
|
+
this._translateProperty(this._wildcardRoute, 'redirectTo', true);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this._translateRouteTree(this.routes, true);
|
|
222
|
+
}
|
|
223
|
+
observer.next(void 0);
|
|
224
|
+
observer.complete();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Translate the route node and recursively call for all it's children
|
|
230
|
+
*/
|
|
231
|
+
_translateRouteTree(routes, isRootTree) {
|
|
232
|
+
routes.forEach((route) => {
|
|
233
|
+
const skipRouteLocalization = (route.data && route.data['skipRouteLocalization']);
|
|
234
|
+
const localizeRedirection = !skipRouteLocalization || skipRouteLocalization['localizeRedirectTo'];
|
|
235
|
+
if (route.redirectTo && localizeRedirection && !(typeof route.redirectTo === 'function')) {
|
|
236
|
+
const prefixLang = route.redirectTo.indexOf('/') === 0 || isRootTree;
|
|
237
|
+
this._translateProperty(route, 'redirectTo', prefixLang);
|
|
238
|
+
}
|
|
239
|
+
if (skipRouteLocalization) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (route.path !== null && route.path !== undefined /* && route.path !== '**'*/) {
|
|
243
|
+
this._translateProperty(route, 'path');
|
|
244
|
+
}
|
|
245
|
+
if (route.children) {
|
|
246
|
+
this._translateRouteTree(route.children);
|
|
247
|
+
}
|
|
248
|
+
if (route.loadChildren && route._loadedRoutes?.length) {
|
|
249
|
+
this._translateRouteTree(route._loadedRoutes);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Translate property
|
|
255
|
+
* If first time translation then add original to route data object
|
|
256
|
+
*/
|
|
257
|
+
_translateProperty(route, property, prefixLang) {
|
|
258
|
+
// set property to data if not there yet
|
|
259
|
+
const routeData = route.data = route.data || {};
|
|
260
|
+
if (!routeData.localizeRouter) {
|
|
261
|
+
routeData.localizeRouter = {};
|
|
262
|
+
}
|
|
263
|
+
if (!routeData.localizeRouter[property]) {
|
|
264
|
+
routeData.localizeRouter = { ...routeData.localizeRouter, [property]: route[property] };
|
|
265
|
+
}
|
|
266
|
+
const result = this.translateRoute(routeData.localizeRouter[property]);
|
|
267
|
+
route[property] = prefixLang ? this.addPrefixToUrl(result) : result;
|
|
268
|
+
}
|
|
269
|
+
get urlPrefix() {
|
|
270
|
+
if (this.settings.alwaysSetPrefix || this.currentLang !== this.defaultLang) {
|
|
271
|
+
return this.currentLang ? this.currentLang : this.defaultLang;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
return '';
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Add current lang as prefix to given url.
|
|
279
|
+
*/
|
|
280
|
+
addPrefixToUrl(url) {
|
|
281
|
+
const splitUrl = url.split('?');
|
|
282
|
+
const isRootPath = splitUrl[0].length === 1 && splitUrl[0] === '/';
|
|
283
|
+
splitUrl[0] = splitUrl[0].replace(/\/$/, '');
|
|
284
|
+
const joinedUrl = splitUrl.join('?');
|
|
285
|
+
if (this.urlPrefix === '') {
|
|
286
|
+
return joinedUrl;
|
|
287
|
+
}
|
|
288
|
+
if (!joinedUrl.startsWith('/') && !isRootPath) {
|
|
289
|
+
return `${this.urlPrefix}/${joinedUrl}`;
|
|
290
|
+
}
|
|
291
|
+
return `/${this.urlPrefix}${joinedUrl}`;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Translate route and return observable
|
|
295
|
+
*/
|
|
296
|
+
translateRoute(path) {
|
|
297
|
+
const queryParts = path.split('?');
|
|
298
|
+
if (queryParts.length > 2) {
|
|
299
|
+
throw Error('There should be only one query parameter block in the URL');
|
|
300
|
+
}
|
|
301
|
+
const pathSegments = queryParts[0].split('/');
|
|
302
|
+
/** collect observables */
|
|
303
|
+
return pathSegments
|
|
304
|
+
.map((part) => part.length ? this.translateText(part) : part)
|
|
305
|
+
.join('/') +
|
|
306
|
+
(queryParts.length > 1 ? `?${queryParts[1]}` : '');
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get language from url
|
|
310
|
+
*/
|
|
311
|
+
getLocationLang(url) {
|
|
312
|
+
const queryParamSplit = (url || this.location.path()).split(/[\?;]/);
|
|
313
|
+
let pathSlices = [];
|
|
314
|
+
if (queryParamSplit.length > 0) {
|
|
315
|
+
pathSlices = queryParamSplit[0].split('/');
|
|
316
|
+
}
|
|
317
|
+
if (pathSlices.length > 1 && this.locales.indexOf(pathSlices[1]) !== -1) {
|
|
318
|
+
return pathSlices[1];
|
|
319
|
+
}
|
|
320
|
+
if (pathSlices.length && this.locales.indexOf(pathSlices[0]) !== -1) {
|
|
321
|
+
return pathSlices[0];
|
|
322
|
+
}
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get user's language set in the browser
|
|
327
|
+
*/
|
|
328
|
+
_getBrowserLang() {
|
|
329
|
+
return this._returnIfInLocales(this.translate.getBrowserLang());
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get language from local storage or cookie
|
|
333
|
+
*/
|
|
334
|
+
get _cachedLang() {
|
|
335
|
+
if (!this.settings.useCachedLang) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (this.settings.cacheMechanism === CacheMechanism.LocalStorage) {
|
|
339
|
+
return this._cacheWithLocalStorage();
|
|
340
|
+
}
|
|
341
|
+
if (this.settings.cacheMechanism === CacheMechanism.SessionStorage) {
|
|
342
|
+
return this._cacheWithSessionStorage();
|
|
343
|
+
}
|
|
344
|
+
if (this.settings.cacheMechanism === CacheMechanism.Cookie) {
|
|
345
|
+
return this._cacheWithCookies();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Save language to local storage or cookie
|
|
350
|
+
*/
|
|
351
|
+
set _cachedLang(value) {
|
|
352
|
+
if (!this.settings.useCachedLang) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (this.settings.cacheMechanism === CacheMechanism.LocalStorage) {
|
|
356
|
+
this._cacheWithLocalStorage(value);
|
|
357
|
+
}
|
|
358
|
+
if (this.settings.cacheMechanism === CacheMechanism.SessionStorage) {
|
|
359
|
+
this._cacheWithSessionStorage(value);
|
|
360
|
+
}
|
|
361
|
+
if (this.settings.cacheMechanism === CacheMechanism.Cookie) {
|
|
362
|
+
this._cacheWithCookies(value);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Cache value to local storage
|
|
367
|
+
*/
|
|
368
|
+
_cacheWithLocalStorage(value) {
|
|
369
|
+
try {
|
|
370
|
+
if (typeof window === 'undefined' || typeof window.localStorage === 'undefined') {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (value) {
|
|
374
|
+
window.localStorage.setItem(this.settings.cacheName, value);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
return this._returnIfInLocales(window.localStorage.getItem(this.settings.cacheName));
|
|
378
|
+
}
|
|
379
|
+
catch (e) {
|
|
380
|
+
// weird Safari issue in private mode, where LocalStorage is defined but throws error on access
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Cache value to session storage
|
|
386
|
+
*/
|
|
387
|
+
_cacheWithSessionStorage(value) {
|
|
388
|
+
try {
|
|
389
|
+
if (typeof window === 'undefined' || typeof window.sessionStorage === 'undefined') {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (value) {
|
|
393
|
+
window.sessionStorage.setItem(this.settings.cacheName, value);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
return this._returnIfInLocales(window.sessionStorage.getItem(this.settings.cacheName));
|
|
397
|
+
}
|
|
398
|
+
catch (e) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Cache value via cookies
|
|
404
|
+
*/
|
|
405
|
+
_cacheWithCookies(value) {
|
|
406
|
+
try {
|
|
407
|
+
if (typeof document === 'undefined' || typeof document.cookie === 'undefined') {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const name = encodeURIComponent(this.settings.cacheName);
|
|
411
|
+
if (value) {
|
|
412
|
+
let cookieTemplate = `${this.settings.cookieFormat}`;
|
|
413
|
+
cookieTemplate = cookieTemplate
|
|
414
|
+
.replace('{{value}}', `${name}=${encodeURIComponent(value)}`)
|
|
415
|
+
.replace(/{{expires:?(\d+)?}}/g, (fullMatch, groupMatch) => {
|
|
416
|
+
const days = groupMatch === undefined ? COOKIE_EXPIRY : parseInt(groupMatch, 10);
|
|
417
|
+
const date = new Date();
|
|
418
|
+
date.setTime(date.getTime() + days * 86400000);
|
|
419
|
+
return `expires=${date.toUTCString()}`;
|
|
420
|
+
});
|
|
421
|
+
document.cookie = cookieTemplate;
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const regexp = new RegExp('(?:^' + name + '|;\\s*' + name + ')=(.*?)(?:;|$)', 'g');
|
|
425
|
+
const result = regexp.exec(document.cookie);
|
|
426
|
+
return decodeURIComponent(result[1]);
|
|
427
|
+
}
|
|
428
|
+
catch (e) {
|
|
429
|
+
return; // should not happen but better safe than sorry (can happen by using domino)
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Check if value exists in locales list
|
|
434
|
+
*/
|
|
435
|
+
_returnIfInLocales(value) {
|
|
436
|
+
if (value && this.locales.indexOf(value) !== -1) {
|
|
437
|
+
return value;
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Get translated value
|
|
443
|
+
*/
|
|
444
|
+
translateText(key) {
|
|
445
|
+
if (this.escapePrefix && key.startsWith(this.escapePrefix)) {
|
|
446
|
+
return key.replace(this.escapePrefix, '');
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
if (!this._translationObject) {
|
|
450
|
+
return key;
|
|
451
|
+
}
|
|
452
|
+
const fullKey = this.prefix + key;
|
|
453
|
+
const res = this.translate.getParsedResult(this._translationObject, fullKey);
|
|
454
|
+
return res !== fullKey ? res : key;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Strategy to choose between new or old queryParams
|
|
459
|
+
* @param newExtras extras that containes new QueryParams
|
|
460
|
+
* @param currentQueryParams current query params
|
|
461
|
+
*/
|
|
462
|
+
chooseQueryParams(newExtras, currentQueryParams) {
|
|
463
|
+
let queryParamsObj;
|
|
464
|
+
if (newExtras && newExtras.queryParams) {
|
|
465
|
+
queryParamsObj = newExtras.queryParams;
|
|
466
|
+
}
|
|
467
|
+
else if (currentQueryParams) {
|
|
468
|
+
queryParamsObj = currentQueryParams;
|
|
469
|
+
}
|
|
470
|
+
return queryParamsObj;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Format query params from object to string.
|
|
474
|
+
* Exemple of result: `param=value¶m2=value2`
|
|
475
|
+
* @param params query params object
|
|
476
|
+
*/
|
|
477
|
+
formatQueryParams(params) {
|
|
478
|
+
return new HttpParams({ fromObject: params }).toString();
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Get translation key prefix from config
|
|
482
|
+
*/
|
|
483
|
+
getPrefix() {
|
|
484
|
+
return this.prefix;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Get escape translation prefix from config
|
|
488
|
+
*/
|
|
489
|
+
getEscapePrefix() {
|
|
490
|
+
return this.escapePrefix;
|
|
491
|
+
}
|
|
492
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeParser, deps: [{ token: TranslateService }, { token: Location }, { token: LocalizeRouterSettings }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
493
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeParser }); }
|
|
494
|
+
}
|
|
495
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeParser, decorators: [{
|
|
496
|
+
type: Injectable
|
|
497
|
+
}], ctorParameters: () => [{ type: i1.TranslateService, decorators: [{
|
|
498
|
+
type: Inject,
|
|
499
|
+
args: [TranslateService]
|
|
500
|
+
}] }, { type: i2.Location, decorators: [{
|
|
501
|
+
type: Inject,
|
|
502
|
+
args: [Location]
|
|
503
|
+
}] }, { type: LocalizeRouterSettings, decorators: [{
|
|
504
|
+
type: Inject,
|
|
505
|
+
args: [LocalizeRouterSettings]
|
|
506
|
+
}] }] });
|
|
507
|
+
/**
|
|
508
|
+
* Manually set configuration
|
|
509
|
+
*/
|
|
510
|
+
class ManualParserLoader extends LocalizeParser {
|
|
511
|
+
/**
|
|
512
|
+
* CTOR
|
|
513
|
+
*/
|
|
514
|
+
constructor(translate, location, settings, locales = ['en'], prefix = 'ROUTES.', escapePrefix = '') {
|
|
515
|
+
super(translate, location, settings);
|
|
516
|
+
this.locales = locales;
|
|
517
|
+
this.prefix = prefix || '';
|
|
518
|
+
this.escapePrefix = escapePrefix || '';
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Initialize or append routes
|
|
522
|
+
*/
|
|
523
|
+
load(routes) {
|
|
524
|
+
return new Promise((resolve) => {
|
|
525
|
+
this.init(routes).then(resolve);
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
class DummyLocalizeParser extends LocalizeParser {
|
|
530
|
+
load(routes) {
|
|
531
|
+
return new Promise((resolve) => {
|
|
532
|
+
this.init(routes).then(resolve);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DummyLocalizeParser, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
536
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DummyLocalizeParser }); }
|
|
537
|
+
}
|
|
538
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DummyLocalizeParser, decorators: [{
|
|
539
|
+
type: Injectable
|
|
540
|
+
}] });
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Compare if two objects are same
|
|
544
|
+
*/
|
|
545
|
+
function equals(o1, o2) {
|
|
546
|
+
if (o1 === o2) {
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
if (o1 === null || o2 === null) {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
if (o1 !== o1 && o2 !== o2) {
|
|
553
|
+
return true; // NaN === NaN
|
|
554
|
+
}
|
|
555
|
+
const t1 = typeof o1, t2 = typeof o2;
|
|
556
|
+
let length, key, keySet;
|
|
557
|
+
if (t1 === t2 && t1 === 'object') {
|
|
558
|
+
if (Array.isArray(o1)) {
|
|
559
|
+
if (!Array.isArray(o2)) {
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
if ((length = o1.length) === o2.length) {
|
|
563
|
+
for (key = 0; key < length; key++) {
|
|
564
|
+
if (!equals(o1[key], o2[key])) {
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return true;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
if (Array.isArray(o2)) {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
keySet = Object.create(null);
|
|
576
|
+
for (key in o1) {
|
|
577
|
+
if (o1.hasOwnProperty(key)) {
|
|
578
|
+
if (!equals(o1[key], o2[key])) {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
keySet[key] = true;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
for (key in o2) {
|
|
585
|
+
if (o2.hasOwnProperty(key)) {
|
|
586
|
+
if (!(key in keySet) && typeof o2[key] !== 'undefined') {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Determine if the argument is shaped like a Promise
|
|
598
|
+
*/
|
|
599
|
+
function isPromise(obj) {
|
|
600
|
+
// allow any Promise/A+ compliant thenable.
|
|
601
|
+
// It's up to the caller to ensure that obj.then conforms to the spec
|
|
602
|
+
return !!obj && typeof obj.then === 'function';
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Deep copy of object and array
|
|
606
|
+
*/
|
|
607
|
+
function deepCopy(object) {
|
|
608
|
+
const output = Array.isArray(object) ? [] : {};
|
|
609
|
+
for (const data in object) {
|
|
610
|
+
if (data) {
|
|
611
|
+
const value = object[data];
|
|
612
|
+
output[data] = (typeof value === 'object') ? deepCopy(value) : value;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return output;
|
|
616
|
+
}
|
|
617
|
+
function flatten(list) {
|
|
618
|
+
return list.reduce((flat, item) => {
|
|
619
|
+
const flatItem = Array.isArray(item) ? flatten(item) : item;
|
|
620
|
+
return flat.concat(flatItem);
|
|
621
|
+
}, []);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Localization service
|
|
626
|
+
* modifyRoutes
|
|
627
|
+
*/
|
|
628
|
+
class LocalizeRouterService {
|
|
629
|
+
/**
|
|
630
|
+
* CTOR
|
|
631
|
+
*/
|
|
632
|
+
constructor(parser, settings, router, route /*,
|
|
633
|
+
@Inject(Location) private location: Location*/) {
|
|
634
|
+
this.parser = parser;
|
|
635
|
+
this.settings = settings;
|
|
636
|
+
this.router = router;
|
|
637
|
+
this.route = route;
|
|
638
|
+
this.routerEvents = new Subject();
|
|
639
|
+
const initializedSubject = new ReplaySubject(1);
|
|
640
|
+
this.hooks = {
|
|
641
|
+
_initializedSubject: initializedSubject,
|
|
642
|
+
initialized: initializedSubject.asObservable()
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Start up the service
|
|
647
|
+
*/
|
|
648
|
+
init() {
|
|
649
|
+
this.applyConfigToRouter(this.parser.routes);
|
|
650
|
+
// subscribe to router events
|
|
651
|
+
this.router.events
|
|
652
|
+
.pipe(filter(event => event instanceof NavigationStart), pairwise())
|
|
653
|
+
.subscribe(this._routeChanged());
|
|
654
|
+
if (this.settings.initialNavigation) {
|
|
655
|
+
this.router.initialNavigation();
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Change language and navigate to translated route
|
|
660
|
+
*/
|
|
661
|
+
changeLanguage(lang, extras, useNavigateMethod) {
|
|
662
|
+
if (lang !== this.parser.currentLang) {
|
|
663
|
+
const rootSnapshot = this.router.routerState.snapshot.root;
|
|
664
|
+
this.parser.translateRoutes(lang).subscribe(() => {
|
|
665
|
+
let url = this.traverseRouteSnapshot(rootSnapshot);
|
|
666
|
+
url = this.translateRoute(url);
|
|
667
|
+
if (!this.settings.alwaysSetPrefix) {
|
|
668
|
+
let urlSegments = url.split('/');
|
|
669
|
+
const languageSegmentIndex = urlSegments.indexOf(this.parser.currentLang);
|
|
670
|
+
// If the default language has no prefix make sure to remove and add it when necessary
|
|
671
|
+
if (this.parser.currentLang === this.parser.defaultLang) {
|
|
672
|
+
// Remove the language prefix from url when current language is the default language
|
|
673
|
+
if (languageSegmentIndex === 0 || (languageSegmentIndex === 1 && urlSegments[0] === '')) {
|
|
674
|
+
// Remove the current aka default language prefix from the url
|
|
675
|
+
urlSegments = urlSegments.slice(0, languageSegmentIndex).concat(urlSegments.slice(languageSegmentIndex + 1));
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
// When coming from a default language it's possible that the url doesn't contain the language, make sure it does.
|
|
680
|
+
if (languageSegmentIndex === -1) {
|
|
681
|
+
// If the url starts with a slash make sure to keep it.
|
|
682
|
+
const injectionIndex = urlSegments[0] === '' ? 1 : 0;
|
|
683
|
+
urlSegments = urlSegments.slice(0, injectionIndex).concat(this.parser.currentLang, urlSegments.slice(injectionIndex));
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
url = urlSegments.join('/');
|
|
687
|
+
}
|
|
688
|
+
// Prevent multiple "/" character
|
|
689
|
+
url = url.replace(/\/+/g, '/');
|
|
690
|
+
const lastSlashIndex = url.lastIndexOf('/');
|
|
691
|
+
if (lastSlashIndex > 0 && lastSlashIndex === url.length - 1) {
|
|
692
|
+
url = url.slice(0, -1);
|
|
693
|
+
}
|
|
694
|
+
const queryParamsObj = this.parser.chooseQueryParams(extras, this.route.snapshot.queryParams);
|
|
695
|
+
this.applyConfigToRouter(this.parser.routes);
|
|
696
|
+
this.lastExtras = extras;
|
|
697
|
+
if (useNavigateMethod) {
|
|
698
|
+
const extrasToApply = extras ? { ...extras } : {};
|
|
699
|
+
if (queryParamsObj) {
|
|
700
|
+
extrasToApply.queryParams = queryParamsObj;
|
|
701
|
+
}
|
|
702
|
+
this.router.navigate([url], extrasToApply);
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
let queryParams = this.parser.formatQueryParams(queryParamsObj);
|
|
706
|
+
queryParams = queryParams ? `?${queryParams}` : '';
|
|
707
|
+
this.router.navigateByUrl(`${url}${queryParams}`, extras);
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Traverses through the tree to assemble new translated url
|
|
714
|
+
*/
|
|
715
|
+
traverseRouteSnapshot(snapshot) {
|
|
716
|
+
if (snapshot.firstChild && snapshot.routeConfig) {
|
|
717
|
+
return `${this.parseSegmentValue(snapshot)}/${this.traverseRouteSnapshot(snapshot.firstChild)}`;
|
|
718
|
+
}
|
|
719
|
+
else if (snapshot.firstChild) {
|
|
720
|
+
return this.traverseRouteSnapshot(snapshot.firstChild);
|
|
721
|
+
}
|
|
722
|
+
else {
|
|
723
|
+
return this.parseSegmentValue(snapshot);
|
|
724
|
+
}
|
|
725
|
+
/* if (snapshot.firstChild && snapshot.firstChild.routeConfig && snapshot.firstChild.routeConfig.path) {
|
|
726
|
+
if (snapshot.firstChild.routeConfig.path !== '**') {
|
|
727
|
+
return this.parseSegmentValue(snapshot) + '/' + this.traverseRouteSnapshot(snapshot.firstChild);
|
|
728
|
+
} else {
|
|
729
|
+
return this.parseSegmentValue(snapshot.firstChild);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return this.parseSegmentValue(snapshot); */
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Build URL from segments and snapshot (for params)
|
|
736
|
+
*/
|
|
737
|
+
buildUrlFromSegments(snapshot, segments) {
|
|
738
|
+
return segments.map((s, i) => s.indexOf(':') === 0 ? snapshot.url[i].path : s).join('/');
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Extracts new segment value based on routeConfig and url
|
|
742
|
+
*/
|
|
743
|
+
parseSegmentValue(snapshot) {
|
|
744
|
+
if (snapshot.routeConfig && snapshot.routeConfig.matcher) {
|
|
745
|
+
const subPathMatchedSegments = this.parseSegmentValueMatcher(snapshot);
|
|
746
|
+
return this.buildUrlFromSegments(snapshot, subPathMatchedSegments);
|
|
747
|
+
}
|
|
748
|
+
else if (snapshot.data.localizeRouter) {
|
|
749
|
+
const path = snapshot.data.localizeRouter.path;
|
|
750
|
+
const subPathSegments = path.split('/');
|
|
751
|
+
return this.buildUrlFromSegments(snapshot, subPathSegments);
|
|
752
|
+
}
|
|
753
|
+
else if (snapshot.parent && snapshot.parent.parent) { // Not lang route and no localizeRouter data = excluded path
|
|
754
|
+
const path = snapshot.routeConfig.path;
|
|
755
|
+
const subPathSegments = path.split('/');
|
|
756
|
+
return this.buildUrlFromSegments(snapshot, subPathSegments);
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
return '';
|
|
760
|
+
}
|
|
761
|
+
/* if (snapshot.routeConfig) {
|
|
762
|
+
if (snapshot.routeConfig.path === '**') {
|
|
763
|
+
return snapshot.url.filter((segment: UrlSegment) => segment.path).map((segment: UrlSegment) => segment.path).join('/');
|
|
764
|
+
} else {
|
|
765
|
+
const subPathSegments = snapshot.routeConfig.path.split('/');
|
|
766
|
+
return subPathSegments.map((s: string, i: number) => s.indexOf(':') === 0 ? snapshot.url[i].path : s).join('/');
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return ''; */
|
|
770
|
+
}
|
|
771
|
+
parseSegmentValueMatcher(snapshot) {
|
|
772
|
+
const localizeMatcherParams = snapshot.data && snapshot.data.localizeMatcher && snapshot.data.localizeMatcher.params || {};
|
|
773
|
+
const subPathSegments = snapshot.url
|
|
774
|
+
.map((segment) => {
|
|
775
|
+
const currentPath = segment.path;
|
|
776
|
+
const matchedParamName = segment.localizedParamName;
|
|
777
|
+
const val = (matchedParamName && localizeMatcherParams[matchedParamName]) ?
|
|
778
|
+
localizeMatcherParams[matchedParamName](currentPath) : null;
|
|
779
|
+
return val || `${this.parser.getEscapePrefix()}${currentPath}`;
|
|
780
|
+
});
|
|
781
|
+
return subPathSegments;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Translate route to current language
|
|
785
|
+
* If new language is explicitly provided then replace language part in url with new language
|
|
786
|
+
*/
|
|
787
|
+
translateRoute(path) {
|
|
788
|
+
if (typeof path === 'string') {
|
|
789
|
+
const url = this.parser.translateRoute(path);
|
|
790
|
+
return !path.indexOf('/') ? this.parser.addPrefixToUrl(url) : url;
|
|
791
|
+
}
|
|
792
|
+
// it's an array
|
|
793
|
+
const result = [];
|
|
794
|
+
path.forEach((segment, index) => {
|
|
795
|
+
if (typeof segment === 'string') {
|
|
796
|
+
const res = this.parser.translateRoute(segment);
|
|
797
|
+
if (!index && !segment.indexOf('/')) {
|
|
798
|
+
result.push(this.parser.addPrefixToUrl(res));
|
|
799
|
+
}
|
|
800
|
+
else {
|
|
801
|
+
result.push(res);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
result.push(segment);
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
return result;
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Event handler to react on route change
|
|
812
|
+
*/
|
|
813
|
+
_routeChanged() {
|
|
814
|
+
return ([previousEvent, currentEvent]) => {
|
|
815
|
+
const previousLang = this.parser.getLocationLang(previousEvent.url) || this.parser.defaultLang;
|
|
816
|
+
const currentLang = this.parser.getLocationLang(currentEvent.url) || this.parser.defaultLang;
|
|
817
|
+
const lastExtras = this.lastExtras;
|
|
818
|
+
if (currentLang !== previousLang && this.latestUrl !== currentEvent.url) {
|
|
819
|
+
this.latestUrl = currentEvent.url;
|
|
820
|
+
this.cancelCurrentNavigation();
|
|
821
|
+
this.parser.translateRoutes(currentLang)
|
|
822
|
+
.subscribe(() => {
|
|
823
|
+
// Reset routes again once they are all translated
|
|
824
|
+
this.applyConfigToRouter(this.parser.routes);
|
|
825
|
+
// Clear global extras
|
|
826
|
+
this.lastExtras = undefined;
|
|
827
|
+
// Init new navigation with same url to take new config in consideration
|
|
828
|
+
this.router.navigateByUrl(currentEvent.url, lastExtras);
|
|
829
|
+
// Fire route change event
|
|
830
|
+
this.routerEvents.next(currentLang);
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
this.latestUrl = currentEvent.url;
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Drop the current Navigation
|
|
838
|
+
*/
|
|
839
|
+
cancelCurrentNavigation() {
|
|
840
|
+
const currentNavigation = this.router.currentNavigation();
|
|
841
|
+
const url = this.router.serializeUrl(currentNavigation.extractedUrl);
|
|
842
|
+
this.router.events.next(new NavigationCancel(currentNavigation.id, url, ''));
|
|
843
|
+
this.router.navigationTransitions.transitions.next({
|
|
844
|
+
...this.router.navigationTransitions.transitions.getValue(),
|
|
845
|
+
id: 0,
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Apply config to Angular RouterModule
|
|
850
|
+
* @param config routes to apply
|
|
851
|
+
*/
|
|
852
|
+
applyConfigToRouter(config) {
|
|
853
|
+
this.router.resetConfig(deepCopy(config));
|
|
854
|
+
}
|
|
855
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterService, deps: [{ token: LocalizeParser }, { token: LocalizeRouterSettings }, { token: Router }, { token: ActivatedRoute }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
856
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterService }); }
|
|
857
|
+
}
|
|
858
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterService, decorators: [{
|
|
859
|
+
type: Injectable
|
|
860
|
+
}], ctorParameters: () => [{ type: LocalizeParser, decorators: [{
|
|
861
|
+
type: Inject,
|
|
862
|
+
args: [LocalizeParser]
|
|
863
|
+
}] }, { type: LocalizeRouterSettings, decorators: [{
|
|
864
|
+
type: Inject,
|
|
865
|
+
args: [LocalizeRouterSettings]
|
|
866
|
+
}] }, { type: i3.Router, decorators: [{
|
|
867
|
+
type: Inject,
|
|
868
|
+
args: [Router]
|
|
869
|
+
}] }, { type: i3.ActivatedRoute, decorators: [{
|
|
870
|
+
type: Inject,
|
|
871
|
+
args: [ActivatedRoute]
|
|
872
|
+
}] }] });
|
|
873
|
+
|
|
874
|
+
const VIEW_DESTROYED_STATE = 128;
|
|
875
|
+
class LocalizeRouterPipe {
|
|
876
|
+
/**
|
|
877
|
+
* CTOR
|
|
878
|
+
*/
|
|
879
|
+
constructor(localize, _ref) {
|
|
880
|
+
this.localize = localize;
|
|
881
|
+
this._ref = _ref;
|
|
882
|
+
this.value = '';
|
|
883
|
+
this.subscription = this.localize.routerEvents.subscribe(() => {
|
|
884
|
+
this.transform(this.lastKey);
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
ngOnDestroy() {
|
|
888
|
+
if (this.subscription) {
|
|
889
|
+
this.subscription.unsubscribe();
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Transform current url to localized one
|
|
894
|
+
*/
|
|
895
|
+
transform(query) {
|
|
896
|
+
if (!query || query.length === 0 || !this.localize.parser.currentLang) {
|
|
897
|
+
return query;
|
|
898
|
+
}
|
|
899
|
+
if (equals(query, this.lastKey) && equals(this.lastLanguage, this.localize.parser.currentLang)) {
|
|
900
|
+
return this.value;
|
|
901
|
+
}
|
|
902
|
+
this.lastKey = query;
|
|
903
|
+
this.lastLanguage = this.localize.parser.currentLang;
|
|
904
|
+
/** translate key and update values */
|
|
905
|
+
this.value = this.localize.translateRoute(query);
|
|
906
|
+
this.lastKey = query;
|
|
907
|
+
// if view is already destroyed, ignore firing change detection
|
|
908
|
+
const view = this._ref._view;
|
|
909
|
+
if (view && (view.state & VIEW_DESTROYED_STATE)) {
|
|
910
|
+
return this.value;
|
|
911
|
+
}
|
|
912
|
+
setTimeout(() => {
|
|
913
|
+
this._ref.detectChanges();
|
|
914
|
+
}, 0);
|
|
915
|
+
return this.value;
|
|
916
|
+
}
|
|
917
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterPipe, deps: [{ token: LocalizeRouterService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
918
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterPipe, isStandalone: true, name: "localize", pure: false }); }
|
|
919
|
+
}
|
|
920
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterPipe, decorators: [{
|
|
921
|
+
type: Pipe,
|
|
922
|
+
args: [{
|
|
923
|
+
name: 'localize',
|
|
924
|
+
pure: false, // required to update the value when the promise is resolved
|
|
925
|
+
standalone: true
|
|
926
|
+
}]
|
|
927
|
+
}], ctorParameters: () => [{ type: LocalizeRouterService }, { type: i0.ChangeDetectorRef }] });
|
|
928
|
+
|
|
929
|
+
class GilsdavReuseStrategy {
|
|
930
|
+
// private handlers: {[key: string]: DetachedRouteHandle} = {};
|
|
931
|
+
constructor() {
|
|
932
|
+
}
|
|
933
|
+
shouldDetach(route) {
|
|
934
|
+
// console.log('shouldDetach', route);
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
store(route, handle) {
|
|
938
|
+
// console.log('store', route, handle);
|
|
939
|
+
// console.log('store url', this.getKey(route));
|
|
940
|
+
// this.handlers[this.getKey(route)] = handle;
|
|
941
|
+
}
|
|
942
|
+
shouldAttach(route) {
|
|
943
|
+
// console.log('shouldAttach', route, this.getKey(route));
|
|
944
|
+
// return !!this.handlers[this.getKey(route)];
|
|
945
|
+
return false;
|
|
946
|
+
}
|
|
947
|
+
retrieve(route) {
|
|
948
|
+
// console.log('retrieve', route);
|
|
949
|
+
// console.log('retrieve url', this.getKey(route));
|
|
950
|
+
// const result = this.handlers[this.getKey(route)];
|
|
951
|
+
// delete this.handlers[this.getKey(route)];
|
|
952
|
+
// return result;
|
|
953
|
+
return null;
|
|
954
|
+
}
|
|
955
|
+
shouldReuseRoute(future, curr) {
|
|
956
|
+
// console.log('shouldReuseRoute', future, curr, this.getKey(future) === this.getKey(curr));
|
|
957
|
+
// console.log('shouldReuseRoute', future && curr ? this.getKey(future) === this.getKey(curr) : false);
|
|
958
|
+
return future && curr ? this.getKey(future) === this.getKey(curr) : false;
|
|
959
|
+
}
|
|
960
|
+
getKey(route) {
|
|
961
|
+
// console.log(route.parent.component.toString());
|
|
962
|
+
if (route.firstChild && route.firstChild.routeConfig && route.firstChild.routeConfig.path &&
|
|
963
|
+
route.firstChild.routeConfig.path.indexOf('**') !== -1) { // WildCard
|
|
964
|
+
return 'WILDCARD';
|
|
965
|
+
}
|
|
966
|
+
else if (!route.data.localizeRouter && (!route.parent || !route.parent.parent) && !route.data.skipRouteLocalization) { // Lang route
|
|
967
|
+
return 'LANG';
|
|
968
|
+
}
|
|
969
|
+
else if (route.routeConfig.matcher) {
|
|
970
|
+
let keyM = `${this.getKey(route.parent)}/${route.routeConfig.matcher.name}`;
|
|
971
|
+
if (route.data.discriminantPathKey) {
|
|
972
|
+
keyM = `${keyM}-${route.data.discriminantPathKey}`;
|
|
973
|
+
}
|
|
974
|
+
return keyM;
|
|
975
|
+
}
|
|
976
|
+
else if (route.data.localizeRouter) {
|
|
977
|
+
let key = `${this.getKey(route.parent)}/${route.data.localizeRouter.path}`;
|
|
978
|
+
if (route.data.discriminantPathKey) {
|
|
979
|
+
key = `${key}-${route.data.discriminantPathKey}`;
|
|
980
|
+
}
|
|
981
|
+
return key;
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
let key = route.routeConfig.path;
|
|
985
|
+
if (route.parent) {
|
|
986
|
+
key = `${this.getKey(route.parent)}/${route.routeConfig.path}`;
|
|
987
|
+
}
|
|
988
|
+
if (route.data.discriminantPathKey) {
|
|
989
|
+
key = `${key}-${route.data.discriminantPathKey}`;
|
|
990
|
+
}
|
|
991
|
+
return key;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* LocalizedRouter
|
|
998
|
+
* ----------------
|
|
999
|
+
* TL;DR: extends the angular router, especially the parts responsible for loading
|
|
1000
|
+
* routes + child routes.
|
|
1001
|
+
*
|
|
1002
|
+
* This class extends Angular's Router to transparently localize routes that
|
|
1003
|
+
* are loaded lazily.
|
|
1004
|
+
*
|
|
1005
|
+
* Why does this exist?
|
|
1006
|
+
* ====================
|
|
1007
|
+
*
|
|
1008
|
+
* ngx-translate-router modifies route definitions by translating the `path`
|
|
1009
|
+
* properties before Angular starts matching URLs.
|
|
1010
|
+
*
|
|
1011
|
+
* Prior to Angular 21 the library could recursively walk the route tree,
|
|
1012
|
+
* including lazily loaded children, by accessing Router internals such as
|
|
1013
|
+
* `_loadedRoutes` and repeatedly calling `router.resetConfig()`.
|
|
1014
|
+
*
|
|
1015
|
+
* Angular 21 completely changed the lazy loading pipeline. Child routes are now
|
|
1016
|
+
* resolved asynchronously through RouterConfigLoader and no longer exist at the
|
|
1017
|
+
* time `resetConfig()` executes.
|
|
1018
|
+
*
|
|
1019
|
+
* As a consequence, lazily loaded routes remained untranslated which eventually
|
|
1020
|
+
* caused router failures during matching (for example
|
|
1021
|
+
* `containsEmptyPathMatches()` receiving an undefined route array).
|
|
1022
|
+
*
|
|
1023
|
+
* Instead of rewriting Angular's routing pipeline, this class intercepts the
|
|
1024
|
+
* lazy loading process itself.
|
|
1025
|
+
*
|
|
1026
|
+
* High level flow
|
|
1027
|
+
* ===============
|
|
1028
|
+
*
|
|
1029
|
+
* Angular navigation
|
|
1030
|
+
* │
|
|
1031
|
+
* ▼
|
|
1032
|
+
* RouterConfigLoader.loadChildren()
|
|
1033
|
+
* │
|
|
1034
|
+
* ▼
|
|
1035
|
+
* LocalizedRouter.customLoadChildren()
|
|
1036
|
+
* │
|
|
1037
|
+
* ├── load original lazy module/routes
|
|
1038
|
+
* ├── translate child routes
|
|
1039
|
+
* ├── return translated Routes
|
|
1040
|
+
* ▼
|
|
1041
|
+
* Angular continues normally
|
|
1042
|
+
*
|
|
1043
|
+
* Angular itself never sees untranslated child routes.
|
|
1044
|
+
*
|
|
1045
|
+
* Design
|
|
1046
|
+
* ======
|
|
1047
|
+
*
|
|
1048
|
+
* The implementation overrides Angular's internal
|
|
1049
|
+
* RouterConfigLoader.loadChildren() method.
|
|
1050
|
+
*
|
|
1051
|
+
* This is intentionally done in one place instead of modifying the router state
|
|
1052
|
+
* afterwards via resetConfig(), because Angular now expects lazy routes to be
|
|
1053
|
+
* resolved through this loader.
|
|
1054
|
+
*
|
|
1055
|
+
* customLoadChildren() reproduces Angular's original implementation almost
|
|
1056
|
+
* verbatim while inserting the localization step immediately before the loaded
|
|
1057
|
+
* Routes are returned.
|
|
1058
|
+
*
|
|
1059
|
+
* Module-based lazy loading requires an additional trick:
|
|
1060
|
+
*
|
|
1061
|
+
* injector.get(ROUTES)
|
|
1062
|
+
*
|
|
1063
|
+
* is intercepted so the ROUTES injection token returns already-localized route
|
|
1064
|
+
* definitions. This avoids having to patch Angular's module loading process.
|
|
1065
|
+
*
|
|
1066
|
+
* Caching
|
|
1067
|
+
* =======
|
|
1068
|
+
*
|
|
1069
|
+
* Angular expects concurrent requests for the same lazy route to share a single
|
|
1070
|
+
* Promise. childrenLoaders reproduces that behaviour using a WeakMap keyed by
|
|
1071
|
+
* Route.
|
|
1072
|
+
*
|
|
1073
|
+
* Compatibility
|
|
1074
|
+
* =============
|
|
1075
|
+
*
|
|
1076
|
+
* This implementation intentionally accesses Angular private APIs:
|
|
1077
|
+
*
|
|
1078
|
+
* - navigationTransitions.configLoader
|
|
1079
|
+
* - RouterConfigLoader.loadChildren()
|
|
1080
|
+
* - _loadedRoutes
|
|
1081
|
+
* - _loadedInjector
|
|
1082
|
+
* - _loadedNgModuleFactory
|
|
1083
|
+
*
|
|
1084
|
+
* These APIs are not stable and may change between Angular releases.
|
|
1085
|
+
*
|
|
1086
|
+
* This file should therefore be considered an Angular-version compatibility
|
|
1087
|
+
* layer. If a future Angular update breaks lazy route localization, this is the
|
|
1088
|
+
* first file that should be investigated.
|
|
1089
|
+
*
|
|
1090
|
+
* Verified against:
|
|
1091
|
+
*
|
|
1092
|
+
* Angular 21.x
|
|
1093
|
+
*
|
|
1094
|
+
* A cleaner implementation using only public Router APIs is planned for a
|
|
1095
|
+
* future major version once Angular exposes sufficient extension points.
|
|
1096
|
+
*/
|
|
1097
|
+
class LocalizedRouter extends Router {
|
|
1098
|
+
constructor() {
|
|
1099
|
+
super();
|
|
1100
|
+
this.platformId = inject(PLATFORM_ID);
|
|
1101
|
+
this.compiler = inject(Compiler);
|
|
1102
|
+
this.localize = inject(LocalizeParser);
|
|
1103
|
+
this.childrenLoaders = new WeakMap();
|
|
1104
|
+
// get the configLoader in order to get access to loadChildren().
|
|
1105
|
+
const isBrowser = isPlatformBrowser(this.platformId);
|
|
1106
|
+
// __proto__ is needed for preloaded modules be doesn't work with SSR
|
|
1107
|
+
// @ts-ignore
|
|
1108
|
+
const configLoader = isBrowser
|
|
1109
|
+
? this.navigationTransitions.configLoader.__proto__
|
|
1110
|
+
: this.navigationTransitions.configLoader;
|
|
1111
|
+
// Overrides default Angular RouterConfigLoader.loadChildren method so we can extend it
|
|
1112
|
+
configLoader.loadChildren = (parentInjector, route) => {
|
|
1113
|
+
if (this.childrenLoaders.get(route)) {
|
|
1114
|
+
return this.childrenLoaders.get(route);
|
|
1115
|
+
}
|
|
1116
|
+
else if (route._loadedRoutes) {
|
|
1117
|
+
return Promise.resolve({
|
|
1118
|
+
routes: route._loadedRoutes,
|
|
1119
|
+
injector: route._loadedInjector,
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
if (this.onLoadStartListener) {
|
|
1123
|
+
this.onLoadStartListener(route);
|
|
1124
|
+
}
|
|
1125
|
+
const loader = (async () => {
|
|
1126
|
+
try {
|
|
1127
|
+
const result = await this.customLoadChildren(route, this.compiler, parentInjector, this.onLoadEndListener);
|
|
1128
|
+
route._loadedRoutes = result.routes;
|
|
1129
|
+
route._loadedInjector = result.injector;
|
|
1130
|
+
route._loadedNgModuleFactory = result.factory;
|
|
1131
|
+
return result;
|
|
1132
|
+
}
|
|
1133
|
+
finally {
|
|
1134
|
+
this.childrenLoaders.delete(route);
|
|
1135
|
+
}
|
|
1136
|
+
})();
|
|
1137
|
+
this.childrenLoaders.set(route, loader);
|
|
1138
|
+
return loader;
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
async customLoadChildren(route, compiler, parentInjector, onLoadEndListener) {
|
|
1142
|
+
const loaded = await wrapIntoPromise(runInInjectionContext(parentInjector, () => route.loadChildren()));
|
|
1143
|
+
const t = maybeUnwrapDefaultExport(loaded);
|
|
1144
|
+
let factoryOrRoutes;
|
|
1145
|
+
if (t instanceof NgModuleFactory || Array.isArray(t)) {
|
|
1146
|
+
factoryOrRoutes = t;
|
|
1147
|
+
}
|
|
1148
|
+
else {
|
|
1149
|
+
factoryOrRoutes = await compiler.compileModuleAsync(t);
|
|
1150
|
+
}
|
|
1151
|
+
if (onLoadEndListener) {
|
|
1152
|
+
onLoadEndListener(route);
|
|
1153
|
+
}
|
|
1154
|
+
let injector;
|
|
1155
|
+
let rawRoutes;
|
|
1156
|
+
let factory = undefined;
|
|
1157
|
+
if (Array.isArray(factoryOrRoutes)) {
|
|
1158
|
+
rawRoutes = this.localize.initChildRoutes([].concat(...factoryOrRoutes));
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
1161
|
+
injector = factoryOrRoutes.create(parentInjector).injector;
|
|
1162
|
+
factory = factoryOrRoutes;
|
|
1163
|
+
// instead of having to overwrite the whole routes function stack,
|
|
1164
|
+
// we simply override the ROUTES injection token
|
|
1165
|
+
const getMethod = injector.get.bind(injector);
|
|
1166
|
+
injector["get"] = (token, notFoundValue, flags) => {
|
|
1167
|
+
const getResult = getMethod(token, notFoundValue, flags);
|
|
1168
|
+
if (token === ROUTES) {
|
|
1169
|
+
return this.localize.initChildRoutes([].concat(...getResult));
|
|
1170
|
+
}
|
|
1171
|
+
else {
|
|
1172
|
+
return getResult;
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
rawRoutes = injector
|
|
1176
|
+
.get(ROUTES, [], { optional: true, self: true })
|
|
1177
|
+
.flat();
|
|
1178
|
+
}
|
|
1179
|
+
const routes = rawRoutes.map(standardizeConfig);
|
|
1180
|
+
return { routes, injector, factory };
|
|
1181
|
+
}
|
|
1182
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizedRouter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1183
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizedRouter, providedIn: "root" }); }
|
|
1184
|
+
}
|
|
1185
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizedRouter, decorators: [{
|
|
1186
|
+
type: Injectable,
|
|
1187
|
+
args: [{ providedIn: "root" }]
|
|
1188
|
+
}], ctorParameters: () => [] });
|
|
1189
|
+
function standardizeConfig(r) {
|
|
1190
|
+
const children = r.children && r.children.map(standardizeConfig);
|
|
1191
|
+
const c = children ? { ...r, children } : { ...r };
|
|
1192
|
+
if (!c.component &&
|
|
1193
|
+
!c.loadComponent &&
|
|
1194
|
+
(children || c.loadChildren) &&
|
|
1195
|
+
c.outlet &&
|
|
1196
|
+
c.outlet !== PRIMARY_OUTLET) {
|
|
1197
|
+
c.component = _EmptyOutletComponent;
|
|
1198
|
+
}
|
|
1199
|
+
return c;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* see
|
|
1203
|
+
* @param value
|
|
1204
|
+
* @returns
|
|
1205
|
+
*/
|
|
1206
|
+
function isWrappedDefaultExport(value) {
|
|
1207
|
+
// We use `in` here with a string key `'default'`, because we expect `DefaultExport` objects to be
|
|
1208
|
+
// dynamically imported ES modules with a spec-mandated `default` key. Thus we don't expect that
|
|
1209
|
+
// `default` will be a renamed property.
|
|
1210
|
+
return value && typeof value === "object" && "default" in value;
|
|
1211
|
+
}
|
|
1212
|
+
function maybeUnwrapDefaultExport(input) {
|
|
1213
|
+
// As per `isWrappedDefaultExport`, the `default` key here is generated by the browser and not
|
|
1214
|
+
// subject to property renaming, so we reference it with bracket access.
|
|
1215
|
+
return isWrappedDefaultExport(input) ? input["default"] : input;
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* see https://github.com/angular/angular/blob/main/packages/router/src/utils/collection.ts#L88
|
|
1219
|
+
* @param value
|
|
1220
|
+
* @returns
|
|
1221
|
+
*/
|
|
1222
|
+
function wrapIntoPromise(value) {
|
|
1223
|
+
if (isObservable(value)) {
|
|
1224
|
+
return firstValueFrom(value);
|
|
1225
|
+
}
|
|
1226
|
+
return Promise.resolve(value);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
class ParserInitializer {
|
|
1230
|
+
/**
|
|
1231
|
+
* CTOR
|
|
1232
|
+
*/
|
|
1233
|
+
constructor(injector) {
|
|
1234
|
+
this.injector = injector;
|
|
1235
|
+
}
|
|
1236
|
+
appInitializer() {
|
|
1237
|
+
const res = this.parser.load(this.routes);
|
|
1238
|
+
return res.then(() => {
|
|
1239
|
+
const localize = this.injector.get(LocalizeRouterService);
|
|
1240
|
+
const router = this.injector.get(Router);
|
|
1241
|
+
const settings = this.injector.get(LocalizeRouterSettings);
|
|
1242
|
+
localize.init();
|
|
1243
|
+
if (settings.initialNavigation) {
|
|
1244
|
+
return new Promise(resolve => {
|
|
1245
|
+
// @ts-ignore
|
|
1246
|
+
const oldAfterPreactivation = router.navigationTransitions.afterPreactivation;
|
|
1247
|
+
let firstInit = true;
|
|
1248
|
+
// @ts-ignore
|
|
1249
|
+
router.navigationTransitions.afterPreactivation = () => {
|
|
1250
|
+
if (firstInit) {
|
|
1251
|
+
resolve();
|
|
1252
|
+
firstInit = false;
|
|
1253
|
+
localize.hooks._initializedSubject.next(true);
|
|
1254
|
+
localize.hooks._initializedSubject.complete();
|
|
1255
|
+
}
|
|
1256
|
+
return oldAfterPreactivation();
|
|
1257
|
+
};
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
else {
|
|
1261
|
+
localize.hooks._initializedSubject.next(true);
|
|
1262
|
+
localize.hooks._initializedSubject.complete();
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
generateInitializer(parser, routes) {
|
|
1267
|
+
this.parser = parser;
|
|
1268
|
+
this.routes = routes.reduce((a, b) => a.concat(b));
|
|
1269
|
+
return this.appInitializer;
|
|
1270
|
+
}
|
|
1271
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ParserInitializer, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1272
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ParserInitializer }); }
|
|
1273
|
+
}
|
|
1274
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ParserInitializer, decorators: [{
|
|
1275
|
+
type: Injectable
|
|
1276
|
+
}], ctorParameters: () => [{ type: i0.Injector }] });
|
|
1277
|
+
function getAppInitializer(p, parser, routes) {
|
|
1278
|
+
// DeepCopy needed to prevent RAW_ROUTES mutation
|
|
1279
|
+
const routesCopy = deepCopy(routes);
|
|
1280
|
+
return p.generateInitializer(parser, routesCopy).bind(p);
|
|
1281
|
+
}
|
|
1282
|
+
function createLocalizeRouterProviders(routes, config) {
|
|
1283
|
+
return [
|
|
1284
|
+
{
|
|
1285
|
+
provide: Router,
|
|
1286
|
+
useClass: LocalizedRouter
|
|
1287
|
+
},
|
|
1288
|
+
{
|
|
1289
|
+
provide: LOCALIZE_ROUTER_FORROOT_GUARD,
|
|
1290
|
+
useFactory: provideForRootGuard,
|
|
1291
|
+
deps: [[LocalizeRouterModule, new Optional(), new SkipSelf()]]
|
|
1292
|
+
},
|
|
1293
|
+
{ provide: USE_CACHED_LANG, useValue: config.useCachedLang },
|
|
1294
|
+
{ provide: ALWAYS_SET_PREFIX, useValue: config.alwaysSetPrefix },
|
|
1295
|
+
{ provide: CACHE_NAME, useValue: config.cacheName },
|
|
1296
|
+
{ provide: CACHE_MECHANISM, useValue: config.cacheMechanism },
|
|
1297
|
+
{ provide: DEFAULT_LANG_FUNCTION, useValue: config.defaultLangFunction },
|
|
1298
|
+
{ provide: COOKIE_FORMAT, useValue: config.cookieFormat },
|
|
1299
|
+
{ provide: INITIAL_NAVIGATION, useValue: config.initialNavigation },
|
|
1300
|
+
LocalizeRouterSettings,
|
|
1301
|
+
config.parser || { provide: LocalizeParser, useClass: DummyLocalizeParser },
|
|
1302
|
+
{
|
|
1303
|
+
provide: RAW_ROUTES,
|
|
1304
|
+
multi: true,
|
|
1305
|
+
useValue: routes
|
|
1306
|
+
},
|
|
1307
|
+
LocalizeRouterService,
|
|
1308
|
+
ParserInitializer,
|
|
1309
|
+
{
|
|
1310
|
+
provide: APP_INITIALIZER,
|
|
1311
|
+
multi: true,
|
|
1312
|
+
useFactory: getAppInitializer,
|
|
1313
|
+
deps: [ParserInitializer, LocalizeParser, RAW_ROUTES]
|
|
1314
|
+
},
|
|
1315
|
+
{
|
|
1316
|
+
provide: RouteReuseStrategy,
|
|
1317
|
+
useClass: GilsdavReuseStrategy
|
|
1318
|
+
}
|
|
1319
|
+
];
|
|
1320
|
+
}
|
|
1321
|
+
class LocalizeRouterModule {
|
|
1322
|
+
static forRoot(routes, config = {}) {
|
|
1323
|
+
return {
|
|
1324
|
+
ngModule: LocalizeRouterModule,
|
|
1325
|
+
providers: createLocalizeRouterProviders(routes, config)
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
static forChild(routes) {
|
|
1329
|
+
return {
|
|
1330
|
+
ngModule: LocalizeRouterModule,
|
|
1331
|
+
providers: [
|
|
1332
|
+
{
|
|
1333
|
+
provide: RAW_ROUTES,
|
|
1334
|
+
multi: true,
|
|
1335
|
+
useValue: routes
|
|
1336
|
+
}
|
|
1337
|
+
]
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1341
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterModule, imports: [CommonModule, RouterModule, TranslateModule, LocalizeRouterPipe], exports: [LocalizeRouterPipe] }); }
|
|
1342
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterModule, imports: [CommonModule, RouterModule, TranslateModule] }); }
|
|
1343
|
+
}
|
|
1344
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: LocalizeRouterModule, decorators: [{
|
|
1345
|
+
type: NgModule,
|
|
1346
|
+
args: [{
|
|
1347
|
+
imports: [CommonModule, RouterModule, TranslateModule, LocalizeRouterPipe],
|
|
1348
|
+
exports: [LocalizeRouterPipe]
|
|
1349
|
+
}]
|
|
1350
|
+
}] });
|
|
1351
|
+
function provideForRootGuard(localizeRouterModule) {
|
|
1352
|
+
if (localizeRouterModule) {
|
|
1353
|
+
throw new Error(`LocalizeRouterModule.forRoot() called twice. Lazy loaded modules should use LocalizeRouterModule.forChild() instead.`);
|
|
1354
|
+
}
|
|
1355
|
+
return 'guarded';
|
|
1356
|
+
}
|
|
1357
|
+
function withLocalizeRouter(routes, config = {}) {
|
|
1358
|
+
return {
|
|
1359
|
+
ɵkind: 'LocalizeRouter',
|
|
1360
|
+
ɵproviders: createLocalizeRouterProviders(routes, config)
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
class LocalizeNgModuleFactory extends NgModuleFactory {
|
|
1365
|
+
constructor(moduleType) {
|
|
1366
|
+
super();
|
|
1367
|
+
this.moduleType = moduleType;
|
|
1368
|
+
this.create = (parentInjector) => {
|
|
1369
|
+
const compiler = parentInjector.get(Compiler);
|
|
1370
|
+
const localize = parentInjector.get(LocalizeParser);
|
|
1371
|
+
const compiled = compiler.compileModuleAndAllComponentsSync(this.moduleType);
|
|
1372
|
+
const moduleRef = compiled.ngModuleFactory.create(parentInjector);
|
|
1373
|
+
const getMethod = moduleRef.injector.get.bind(moduleRef.injector);
|
|
1374
|
+
moduleRef.injector['get'] = (token, notFoundValue) => {
|
|
1375
|
+
const getResult = getMethod(token, notFoundValue);
|
|
1376
|
+
if (token === ROUTES) {
|
|
1377
|
+
// translate lazy routes
|
|
1378
|
+
return localize.initChildRoutes([].concat(...getResult));
|
|
1379
|
+
}
|
|
1380
|
+
else {
|
|
1381
|
+
return getResult;
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
return moduleRef;
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
function translateModule(moduleType) {
|
|
1389
|
+
return new LocalizeNgModuleFactory(moduleType);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/*
|
|
1393
|
+
* Public API Surface of ngx-translate-router
|
|
1394
|
+
*/
|
|
1395
|
+
|
|
1396
|
+
/**
|
|
1397
|
+
* Generated bundle index. Do not edit.
|
|
1398
|
+
*/
|
|
1399
|
+
|
|
1400
|
+
export { ALWAYS_SET_PREFIX, CACHE_MECHANISM, CACHE_NAME, COOKIE_FORMAT, CacheMechanism, DEFAULT_LANG_FUNCTION, DummyLocalizeParser, GilsdavReuseStrategy, INITIAL_NAVIGATION, LOCALIZE_ROUTER_FORROOT_GUARD, LocalizeNgModuleFactory, LocalizeParser, LocalizeRouterModule, LocalizeRouterPipe, LocalizeRouterService, LocalizeRouterSettings, LocalizedRouter, ManualParserLoader, ParserInitializer, RAW_ROUTES, USE_CACHED_LANG, getAppInitializer, provideForRootGuard, standardizeConfig, translateModule, withLocalizeRouter, wrapIntoPromise };
|
|
1401
|
+
//# sourceMappingURL=derschmidtler-ngx-translate-router.mjs.map
|