UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

796 lines (781 loc) 37 kB
import * as i0 from '@angular/core'; import { InjectionToken, Injectable, Optional, Inject, NgModule, SkipSelf, Directive } from '@angular/core'; import { Destroyable, CoreModule } from '@bespunky/angular-zen/core'; import * as i1 from '@bespunky/angular-zen/router-x'; import { UrlReflectionService, RouteAware } from '@bespunky/angular-zen/router-x'; import { from, of } from 'rxjs'; import { access } from '@bespunky/angular-zen/utils'; import * as i2 from '@angular/router'; /** * An injection token representing the the global language integration configuration provided by an app to its libraries. * Provided by `LanguageIntegrationModule.forRoot()`. */ const LanguageIntegration = new InjectionToken('LanguageIntegration.Config'); /* eslint-disable @typescript-eslint/no-non-null-assertion */ /** * Uses the language integration configuration provided by an app to provide language services for a library. * @see `LanguageIntegrationModule.forRoot()`. * * @export * @class LanguageIntegrationService * @extends {Destroyable} */ class LanguageIntegrationService extends Destroyable { /** * Creates an instance of LanguageIntegrationService. * * @param {LanguageIntegrationConfig} [config] The language integration configuration provided using `LanguageIntegrationModule.forRoot()`. */ constructor(config) { super(); this.config = config; this.initReadyObservable(); if (config) this.initMultiLanguageSupport(); } initReadyObservable() { const ready = this.config?.ready; // Using of() instead of EMPTY as EMPTY only calls `complete` but not `next`. // This allows users to subscribe more intuitively. this.$ready = ready ? from(ready) : of(); } initMultiLanguageSupport() { this.subscribe(this.config.changed, lang => this.currentLang = lang); // User's responsability to provide a completing observables. this.loadDefaultLanguage().subscribe(defaultLang => this.defaultLang = defaultLang); this.loadSupportedLanguages().subscribe(languages => this.supportedLangs = languages); } loadDefaultLanguage() { const defaultLang = this.config.default; return typeof defaultLang === 'string' ? of(defaultLang) : from(defaultLang()); } loadSupportedLanguages() { const supported = this.config.supported; return Array.isArray(supported) ? of(supported) : from(supported()); } /** * A subscribable event emitting every time the integrated app changes a language. * The new language name is emitted with each change. * * This will be `undefined` if the language integration module hasn't been imported by the app. * * @readonly * @type {Observable<string> | undefined} */ get changed() { return this.config?.changed; } /** * The default language used by the integrated app. * * This will be `undefined` in the following cases: * 1. The language integration module hasn't been imported by the app. * 2. The default language hasn't resolved yet. * * @readonly * @type {string | undefined} */ get default() { return this.defaultLang; } /** * The languages supported by the integrated app. * * This will be `undefined` in the following cases: * 1. The language integration module hasn't been imported by the app. * 2. Supported languages haven't resolved yet. * * @readonly * @type {string[] | undefined} */ get supported() { return this.supportedLangs; } /** * The current language used by the integrated app. * * This will be `undefined` in the following cases: * 1. The language integration module hasn't been imported by the app. * 2. The `changed` event hasn't emitted yet. * * @readonly * @type {string | undefined} */ get current() { return this.currentLang; } /** * Indicated whether the language integration module has been imported into the app. * If this is `false`, this service will serve no purpose. * * @readonly * @type {boolean} */ get enabled() { return !!(this.config); } /** * A resolvable async object which emits once when the intgrated language services are ready for operation. * * This will complete immediately if the the language integration module hasn't been imported, or a `ready` observable hasn't * been provided when importing the module. * * @readonly * @type {Observable<void>} */ get ready() { return this.$ready; } /** * Retrieves the list of alternative languages to the specified language supported by the integrated app. * * @param {string} lang The language for which to get the alternative languages. * @returns {string[]} An array of alternative languages supported by the integrated app. * @throws If the language integration module hasn't been imported into the app. */ alternateLanguagesFor(lang) { this.ensureEnabled(); return this.supported.filter(supportedLocale => supportedLocale !== lang); } /** * Translates a value (typically a translation id) into the current language used by the integrated app. * * @param {string} value The value to translate (typically a translation id). * @param {Record<string, unknown>} [params] (Optional) Any params needed for translating the value. * @returns {string} The translation of the specified value and params in the current language used by the integrated app. * @throws If the language integration module hasn't been imported into the app. */ translate(value, params) { this.ensureEnabled(); return this.config.translate(value, params); } /** * Dives deep into an object or an array and replaces the indicated properties in-place with their translation. * * The `paths` argument is an array of paths representing deep properties which should be translated. * For example: * * ```typescript * // If we have a user object, we can translate its city and role properties * { * id: 15, * addresses: [ * { city: 'Tel Aviv', ... }, * { city: 'Rishon LeTzion' } * ], * system: { * role: 'Admin' * } * } * * // Our paths would be: * `addresses[0].city` * `addresses[1].city` * `system.role` * ``` * * @param {Record<string, unknown>} data The object which holds the translatable properties. Can be a deeply nested object. * @param {string[]} paths The paths of the translatable properties to translate and replace. * @throws If the language integration module hasn't been imported into the app. */ translateProperties(data, paths) { this.ensureEnabled(); paths.forEach(path => { const valueAccessor = access(data, path); const value = valueAccessor.get(); if (typeof value !== 'string') return; valueAccessor.set(this.translate(value)); }); } /** * Ensures that the language integration module has been imported and a configuration object has been provided. * * @throws {Error} The language integration module hasn't been imported by the app. */ ensureEnabled() { if (this.enabled) return true; throw new Error(` Language integration hasn't been enabled. Did you import the language integration module in your app module using 'LanguageIntegrationModule.forRoot()'? `); } } LanguageIntegrationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LanguageIntegrationService, deps: [{ token: LanguageIntegration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); LanguageIntegrationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LanguageIntegrationService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LanguageIntegrationService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [LanguageIntegration] }] }]; } }); /** * The base class for url localization implementors. This can be used as an injectable token to get a hold of the currently * configured url localizer class. * * @export * @abstract * @class UrlLocalizer */ class UrlLocalizer { /** * Creates an instance of UrlLocalizer. * * @param {UrlReflectionService} urlReflection The url reflection service. */ constructor(urlReflection) { this.urlReflection = urlReflection; } } UrlLocalizer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlLocalizer, deps: [{ token: i1.UrlReflectionService }], target: i0.ɵɵFactoryTarget.Injectable }); UrlLocalizer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlLocalizer }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlLocalizer, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.UrlReflectionService }]; } }); /** * An injection token for the provided url localization configuration. * `LanguageIntegrationModule.forRoot()` facilitates the injection of this token. No need to inject directly. */ const UrlLocalization = new InjectionToken('LanguageIntegration.UrlLocalizationConfig'); /** * Provides tools for localization and delocalization of the currently navigated url by adding or removing * a route segment dedicated for language. * * @export * @class RoutePositionUrlLocalizer * @extends {UrlLocalizer} */ class RoutePositionUrlLocalizer extends UrlLocalizer { constructor({ strategy }, urlReflection, language) { super(urlReflection); this.language = language; this.position = strategy; } /** * Localizes the currently navigated url by adding or updating the language segment of the route. * If `position` is positive, language lookup will be performed from the beginning of route. * If `position` is negative, language lookup will be performed from the end of route. * If `position` points to an index out of bounds, the last/first element will be treated as the language. * * #### Example * Position 1 - /en/some/route - first segment from the left. * Position 2 - /some/en/route - second segment from the left. * Position 5 - /some/route/en - out of bounds. last segment from the left. * * Position -1 - /some/route/en - first segment from the right. * Position -2 - /some/en/route - second segment from the right. * Position -5 - /en/some/route - out of bounds. last segment from the right. * * @param {string} lang * @returns {string} The currently navigated url localized to the specified language. */ localize(lang) { return this.transformUrl((segments, langIndex, isLanguage) => this.insertOrReplaceLanguage(lang, segments, langIndex, isLanguage)); } /** * Delocalizes the currently navigated url by removing the language segment from the route. * If `position` is positive, language lookup will be performed from the beginning of route. * If `position` is negative, language lookup will be performed from the end of route. * If `position` points to an index out of bounds, the last/first element will be treated as the language. * If no language exists at the language position, returns the url unchanged. * * #### Example * Position 1 - /en/some/route - first segment from the left. * Position 2 - /some/en/route - second segment from the left. * Position 5 - /some/route/en - out of bounds. last segment from the left. * * Position -1 - /some/route/en - first segment from the right. * Position -2 - /some/en/route - second segment from the right. * Position -5 - /en/some/route - out of bounds. last segment from the right. * * @returns {string} The delocalized currently navigated url. */ delocalize() { return this.transformUrl((segments, langIndex, isLanguage) => this.removeLanguage(segments, langIndex, isLanguage), // When removing the language segment, the index should always be in range. Unlike when inserting, an overflowing index // will not be converted to the last index automatically by `.splice()`. (segments, langIndex) => langIndex >= segments.length ? segments.length - 1 : langIndex); } transformUrl(transform, sanitizeIndex) { // Position of zero will not touch the url as zero's functionality is not defined if (this.position === 0) return this.urlReflection.fullUrl; const segments = this.urlReflection.routeSegments; // Convert the position to replace/add to an index (might result in large negatives or positives, exceeding array bounds) let langIndex = this.indexOfPosition(); this.accessSegmentsSafely(segments, () => { if (sanitizeIndex) langIndex = sanitizeIndex(segments, langIndex); // Determine if a language segment exists at the specified index const isLanguage = this.isLanguage(segments[langIndex]); return transform(segments, langIndex, isLanguage); }); return this.composeUrl(segments); } /** * Updates the specified route segments array with the specified language. * * @protected * @param {string} lang The new language to set to the route. * @param {string[]} segments The current route segments. * @param {number} langIndex The index of the expected language segment. * @param {boolean} isLanguage `true` if the current value at `langIndex` is a supported language; otherwise `false`. */ insertOrReplaceLanguage(lang, segments, langIndex, isLanguage) { // Define how many items to remove. If the segment is already a language and should be replaced, zero items should be removed. const deleteCount = isLanguage ? 1 : 0; // Replace existing language segment or add a new one. If the specified index exceeds the length of the array, splice will add a new item at the end/beginning of the array. segments.splice(langIndex, deleteCount, lang); } /** * Removes the language segment from a route segments array. * If the language index points to a non-language segment, returns without changing the segments. * * @protected * @param {string[]} segments The current route segments. * @param {number} langIndex The index of the expected langauge segment. * @param {boolean} isLanguage `true` if the current value at `langIndex` is a supported language; otherwise `false`. */ removeLanguage(segments, langIndex, isLanguage) { if (!isLanguage) return; segments.splice(langIndex, 1); } /** * Accessing segments by index requires the `this.position` to be translated into an index. * As the position can either be positive or negative, there are two different formulas for index calculation. * In turn, this means two different scenarios with different edge cases. * * To unify the cases and reduce complexity, when position is negative, this method reverses the segments array, runs the segments manipulation, then reverses it again to restore the original order. * This way the indexing is always done from one side of the array. * * @protected * @param {string[]} segments The segments about to be manipulated. * @param {() => void} accessSegments The function that needs safe access by index to the */ accessSegmentsSafely(segments, accessSegments) { if (this.isNegativeLookup) segments.reverse(); accessSegments(); if (this.isNegativeLookup) segments.reverse(); } /** * Indicates whether the configured language position is positive, resulting in a lookup from the left (positive lookup). * `true` if positive lookup should be performed; otherwise `false`. * * @readonly * @protected * @type {boolean} */ get isPositiveLookup() { return this.position > 0; } /** * Indicates whether the configured language position is negative, resulting in a lookup from the right (negative lookup). * `true` if negative lookup should be performed; otherwise `false`. * * @readonly * @protected * @type {boolean} */ get isNegativeLookup() { return this.position < 0; } /** * Calculates the absolute index for the configured language position. * * @protected * @returns {number} */ indexOfPosition() { return Math.abs(this.position) - 1; } /** * Checks whether the specified value is a language supported by the language integration services. * * @protected * @param {string} value The value to check. * @returns {boolean} `true` if the value is a supported language; otherwise `false`. */ isLanguage(value) { return this.language.supported?.includes(value) || false; } /** * Concats the host url as given by the url reflection service with the segments and the current query string to create * a fully qualified url. * * @protected * @param {string[]} segments The route segments to place in the url. * @returns {string} The fully qualified url composed of the host url as given by the url reflection service, the specified route segments, and the current query params. */ composeUrl(segments) { const { hostUrl, queryString } = this.urlReflection; return `${hostUrl}/${segments.join('/')}${queryString}`; } } RoutePositionUrlLocalizer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RoutePositionUrlLocalizer, deps: [{ token: UrlLocalization }, { token: i1.UrlReflectionService }, { token: LanguageIntegrationService }], target: i0.ɵɵFactoryTarget.Injectable }); RoutePositionUrlLocalizer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RoutePositionUrlLocalizer, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: RoutePositionUrlLocalizer, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [UrlLocalization] }] }, { type: i1.UrlReflectionService }, { type: LanguageIntegrationService }]; } }); /** * Provides tools for localization and delocalization of the currently navigated url by adding or removing * a named query param dedicated for language. * * @export * @class QueryParamsUrlLocalizer * @extends {UrlLocalizer} */ class QueryParamsUrlLocalizer extends UrlLocalizer { constructor({ strategy }, urlReflection) { super(urlReflection); this.paramName = strategy; } /** * Localizes the currently navigated url by adding or updating the query param specifying the language. * * @param {string} lang The new language of the url. * @returns {string} The currently navigated url localized into the specified language. */ localize(lang) { const currentUrlTree = this.parseUrlTree(); const localizedParams = this.replaceLanguageParam(this.urlReflection.queryParams, lang); const localizedRoute = this.replaceQueryParamsInUrlTree(currentUrlTree, localizedParams); const localizedRouteUrl = this.urlReflection.router.serializeUrl(localizedRoute); return this.composeUrl(localizedRouteUrl); } /** * Delocalizes the currently navigated url by removing the query param specifying the language. * * @returns {string} The currently navigated url without the query param for language. */ delocalize() { return this.localize(''); } /** * Returns the `UrlTree` representing the currently navigated url. * * @protected * @returns {UrlTree} The `UrlTree` representing the currently navigated url. */ parseUrlTree() { const { router } = this.urlReflection; // Parsing the url seems dumb as the router should have it parsed already, but the route object doesn't hold // the tree and the router SOMETIMES holds it in getCurrentNavigation(). return router.parseUrl(router.url); } /** * Updates the language param in a query params object. * * @protected * @param {*} params The object representing the query params. * @param {string} lang The new language to set to the language query param. If `null` or `undefined`, the language query param will be deleted from the object. * @returns {*} The updated query params object. */ replaceLanguageParam(params, lang) { if (lang) params[this.paramName] = lang; else delete params[this.paramName]; return params; } /** * Replaces the query params in a url tree object. * * @protected * @param {UrlTree} url The url tree in which query params should be replaced. * @param {Object} newParams The new query params object to set to the url tree. * @returns {UrlTree} The updated url tree object. */ replaceQueryParamsInUrlTree(url, newParams) { return Object.assign(url, { queryParams: newParams }); } /** * Concats the host url and the specified route url to compose a fully qualified url. * Uses the host url provided by the url reflection service. * * @protected * @param {string} routeUrl The route url to concat to the host url. Should be prefixed with '/'. * @returns {string} The fully qualified url composed of the host url defined by the url reflection service and the specified route url. */ composeUrl(routeUrl) { const { hostUrl } = this.urlReflection; return `${hostUrl}${routeUrl}`; } } QueryParamsUrlLocalizer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: QueryParamsUrlLocalizer, deps: [{ token: UrlLocalization }, { token: i1.UrlReflectionService }], target: i0.ɵɵFactoryTarget.Injectable }); QueryParamsUrlLocalizer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: QueryParamsUrlLocalizer, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: QueryParamsUrlLocalizer, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [UrlLocalization] }] }, { type: i1.UrlReflectionService }]; } }); /** * A noop implemetation for the `UrlLocalizer` class. * Always returns unchanged urls. * * @export * @class NoopUrlLocalizer * @extends {UrlLocalizer} */ class NoopUrlLocalizer extends UrlLocalizer { /** * Returns the currently navigated url as is. * * @param {string} lang Ignore. * @returns {string} The currently navigated url as is. */ localize(lang) { return this.urlReflection.fullUrl; } /** * Returns the currently navigated url as is. * * @returns {string} The currently navigated url as is. */ delocalize() { return this.urlReflection.fullUrl; } } NoopUrlLocalizer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: NoopUrlLocalizer, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); NoopUrlLocalizer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: NoopUrlLocalizer, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: NoopUrlLocalizer, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * The default configuration for url localization when loading the language integration module. * Uses the `NoopUrlLocalizer` as strategy and does not force https. Localization and delocalization will always return an unchanged url url. */ const DefaultUrlLocalizationConfig = { strategy: { useClass: NoopUrlLocalizer }, forceHttps: false }; /** * Creates the appropriate DI compatible provider for the `UrlLocalizer` class, depending on the strategy specified in the url localization configuration. * If the configured strategy is a number, `RoutePositionUrlLocalizer` will be used. * If the configured strategy is a string, `QueryParamsUrlLocalizer` will be used. * If the configured strategy is a valid `UrlLocalizer` provider, the provider will be used as is. * Otherwise, `NoopUrlLocalizer` will be used. * * @export * @param {UrlLocalizationConfig} config The url localization configuration holding the strategy. * @returns {(ClassProvider | FactoryProvider)} A DI compatible provider for the `UrlLocalizer` class with the implementation appropriate for the specified strategy. */ function provideUrlLocalizer(config) { const strategy = config?.strategy; const strategies = { // Use route position strategy for numbers number: () => ({ useFactory: (urlReflect, language) => new RoutePositionUrlLocalizer(config, urlReflect, language), deps: [UrlReflectionService, LanguageIntegrationService] }), // Use query params strategy for strings string: () => ({ useFactory: (urlReflect) => new QueryParamsUrlLocalizer(config, urlReflect), deps: [UrlReflectionService] }), // Use the user's factory or class provider object: () => strategy, // Use the noop localizer when nothing provided (in case url localization config is not present) undefined: () => ({ useClass: NoopUrlLocalizer }) }; // Create a basic provider to which the strategy will be assigned const provider = { provide: UrlLocalizer }; // Override the useClass or useFactory with the detected strategy return Object.assign(provider, strategies[typeof strategy]()); } /** * Creates the providers for the `UrlLocalization` token and the `UrlLocalizer` class. * * @export * @param {UrlLocalizationConfig} [config] (Optional) The configuration for url localization tools. Default is `DefaultUrlLocalizationConfig`. * @returns {Provider[]} The providers for the `UrlLocalization` token and the `UrlLocalizer` class. */ function provideUrlLocalization(config) { config = Object.assign({}, DefaultUrlLocalizationConfig, config); return [ { provide: UrlLocalization, useValue: config }, provideUrlLocalizer(config) ]; } /** * Generates language integration tokens and services to be provided in a module. * Used by `LanguageIntegrationModule.forRoot()`. * * @export * @param {LanguageIntegrationProvider} { useFactory, deps, urlLocalization } The language integration provider configuration. * @returns {Provider[]} An array of providers for language integration. */ function provideLanguageIntegration({ useFactory, deps, urlLocalization }) { return [ { provide: LanguageIntegration, useFactory, deps }, ...provideUrlLocalization(urlLocalization) ]; } /** * Provides services for libraries requiring integration with their user's language services. * * @export * @class LanguageIntegrationModule */ class LanguageIntegrationModule { constructor(parentModule) { if (parentModule) throw new Error('`LanguageIntegrationModule` has already been loaded. Import it only once, in your app module, using `forRoot()`.'); } /** * Generates the language integration modules with the appropriate providers for the app to share its language services with * libraries and supporting languages. * * @static * @param {LanguageIntegrationProvider} configProvider The integration configuration. Tells the module how to operate with your language services. */ static forRoot(configProvider) { return { ngModule: LanguageIntegrationModule, providers: provideLanguageIntegration(configProvider) }; } } LanguageIntegrationModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LanguageIntegrationModule, deps: [{ token: LanguageIntegrationModule, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.NgModule }); LanguageIntegrationModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: LanguageIntegrationModule, imports: [CoreModule] }); LanguageIntegrationModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LanguageIntegrationModule, imports: [CoreModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LanguageIntegrationModule, decorators: [{ type: NgModule, args: [{ imports: [CoreModule] }] }], ctorParameters: function () { return [{ type: LanguageIntegrationModule, decorators: [{ type: Optional }, { type: SkipSelf }] }]; } }); /** * Integrates with the `LanguageIntegrationService` and facilitates language related work in route-aware services. * * @export * @abstract * @class LocalizedRouteAware * @extends {RouteAware} */ // eslint-disable-next-line @angular-eslint/directive-class-suffix class LocalizedRouteAware extends RouteAware { /** * Creates an instance of LocalizedRouteAware. * * @param {LanguageIntegrationService} language The instance of the language integration service. * @param {Router} router The instance of Angular's router service. * @param {ActivatedRoute} route The instance of Angular's activated route service. * @param {RouterOutletComponentBus} [componentBus] (Optional) The component bus for router-x functionality. * Provide this when you want your route-aware service to have access to the instance(s) of the activated component(s). */ constructor(language, router, route, componentBus) { super(router, route, componentBus); this.language = language; if (this.language.enabled) this.initLanguageSupport(); } initLanguageSupport() { this.subscribe(this.language.ready, this.onLanguageServicesReady.bind(this)); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.subscribe(this.language.changed, this.onLanguageChanged.bind(this)); } /** * Called when the app's language services have initialized and are ready for use. * When language integration is disabled, or no ready observable have been provided by the app * this will execute immediatelly on construction time. * * Override to implement. * * @virtual * @protected */ onLanguageServicesReady() { void 0; } /** * Called when the current language used by the integrated app has changed. Override to implement. * * @virtual * @protected * @param {*} lang The language code of the new language. */ onLanguageChanged(lang) { void 0; } } LocalizedRouteAware.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LocalizedRouteAware, deps: [{ token: LanguageIntegrationService }, { token: i2.Router }, { token: i2.ActivatedRoute }, { token: i1.RouterOutletComponentBus }], target: i0.ɵɵFactoryTarget.Directive }); LocalizedRouteAware.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.12", type: LocalizedRouteAware, usesInheritance: true, ngImport: i0 }); LocalizedRouteAware.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LocalizedRouteAware }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LocalizedRouteAware, decorators: [{ type: Directive }, { type: Injectable }], ctorParameters: function () { return [{ type: LanguageIntegrationService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i1.RouterOutletComponentBus }]; } }); /** * Provides tools for localization and delocalization of the currently navigated url taking into * account the url localization configuration provided when importing the language integration module. * * @export * @class UrlLocalizationService */ class UrlLocalizationService { /** * Creates an instance of UrlLocalizationService. * * @param {UrlLocalizationConfig} config The url localization configuration provided for the `UrlLocalization` token. * @param {UrlReflectionService} urlReflection The url reflection service. * @param {UrlLocalizer} localizer The url localizer which will actually do the localization work. * The instance and implementation depend on the strategy configured for url localization when importing the language integration module. */ constructor(config, urlReflection, localizer) { this.config = config; this.urlReflection = urlReflection; this.localizer = localizer; } /** * Localizes the currently navigated url using the configured localization strategy and forces https if needed. * * @param {string} lang The langugae to localize the currently navigated url to. * @returns {string} The localized currently navigated url. */ localize(lang) { return this.replaceHttpIfRequired(this.localizer.localize(lang)); } /** * Delocalizes the currently navigated url using the configured localization strategy and forces https if needed. * * @returns {string} The delocalized currently navigated url. */ delocalize() { return this.replaceHttpIfRequired(this.localizer.delocalize()); } /** * Generates a localized version of the currently navigate url for each of the specified languages using the configured localization strategy. * * @param {string[]} langs The languages for which to generate the localized urls. * @returns {{ [lang: string]: string }[]} An array of { [lang]: url } containing an object for each language and its corresponding localized url. */ generateLocalizedUrls(langs) { return langs.map(lang => ({ [lang]: this.localizer.localize(lang) })); } replaceHttpIfRequired(url) { return this.config?.forceHttps ? this.urlReflection.forceHttps(url) : url; } } UrlLocalizationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlLocalizationService, deps: [{ token: UrlLocalization }, { token: i1.UrlReflectionService }, { token: UrlLocalizer }], target: i0.ɵɵFactoryTarget.Injectable }); UrlLocalizationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlLocalizationService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: UrlLocalizationService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [UrlLocalization] }] }, { type: i1.UrlReflectionService }, { type: UrlLocalizer }]; } }); /** * Generated bundle index. Do not edit. */ export { DefaultUrlLocalizationConfig, LanguageIntegration, LanguageIntegrationModule, LanguageIntegrationService, LocalizedRouteAware, NoopUrlLocalizer, QueryParamsUrlLocalizer, RoutePositionUrlLocalizer, UrlLocalization, UrlLocalizationService, UrlLocalizer, provideLanguageIntegration, provideUrlLocalization, provideUrlLocalizer }; //# sourceMappingURL=bespunky-angular-zen-language.mjs.map