|
|
|
@ -1,19 +1,19 @@ |
|
|
|
import { registerLocaleData } from '@angular/common'; |
|
|
|
import { Injectable, Injector, NgZone, Optional, SkipSelf } from '@angular/core'; |
|
|
|
import { ActivatedRouteSnapshot, Router } from '@angular/router'; |
|
|
|
import { Injectable, Injector, isDevMode, NgZone, Optional, SkipSelf } from '@angular/core'; |
|
|
|
import { Router } from '@angular/router'; |
|
|
|
import { Store } from '@ngxs/store'; |
|
|
|
import { noop, Observable, of, Subject } from 'rxjs'; |
|
|
|
import { filter, map, mapTo, switchMap } from 'rxjs/operators'; |
|
|
|
import { GetAppConfiguration } from '../actions/config.actions'; |
|
|
|
import { noop, Observable, Subject } from 'rxjs'; |
|
|
|
import { filter, map, mapTo, switchMap, tap } from 'rxjs/operators'; |
|
|
|
import { ApplicationConfiguration } from '../models/application-configuration'; |
|
|
|
import { ABP } from '../models/common'; |
|
|
|
import { Config } from '../models/config'; |
|
|
|
import { ConfigState } from '../states/config.state'; |
|
|
|
import { CORE_OPTIONS } from '../tokens/options.token'; |
|
|
|
import { createLocalizer, createLocalizerWithFallback } from '../utils/localization-utils'; |
|
|
|
import { interpolate } from '../utils/string-utils'; |
|
|
|
import { ApplicationConfigurationService } from './application-configuration.service'; |
|
|
|
import { ConfigStateService } from './config-state.service'; |
|
|
|
import { SessionStateService } from './session-state.service'; |
|
|
|
|
|
|
|
type ShouldReuseRoute = (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) => boolean; |
|
|
|
|
|
|
|
@Injectable({ providedIn: 'root' }) |
|
|
|
export class LocalizationService { |
|
|
|
private latestLang = this.sessionState.getLanguage(); |
|
|
|
@ -38,6 +38,8 @@ export class LocalizationService { |
|
|
|
@Optional() |
|
|
|
@SkipSelf() |
|
|
|
otherInstance: LocalizationService, |
|
|
|
private configState: ConfigStateService, |
|
|
|
private appConfigService: ApplicationConfigurationService, |
|
|
|
) { |
|
|
|
if (otherInstance) throw new Error('LocalizationService should have only one instance.'); |
|
|
|
|
|
|
|
@ -49,12 +51,14 @@ export class LocalizationService { |
|
|
|
.onLanguageChange$() |
|
|
|
.pipe( |
|
|
|
filter( |
|
|
|
lang => |
|
|
|
this.store.selectSnapshot( |
|
|
|
ConfigState.getDeep('localization.currentCulture.cultureName'), |
|
|
|
) !== lang, |
|
|
|
lang => this.configState.getDeep('localization.currentCulture.cultureName') !== lang, |
|
|
|
), |
|
|
|
switchMap(lang => |
|
|
|
this.appConfigService |
|
|
|
.getConfiguration() |
|
|
|
.pipe(tap(res => this.configState.setState(res))) |
|
|
|
.pipe(mapTo(lang)), |
|
|
|
), |
|
|
|
switchMap(lang => this.store.dispatch(new GetAppConfiguration()).pipe(mapTo(lang))), |
|
|
|
) |
|
|
|
.subscribe(lang => { |
|
|
|
this.registerLocale(lang); |
|
|
|
@ -90,11 +94,17 @@ export class LocalizationService { |
|
|
|
key: string | Config.LocalizationWithDefault, |
|
|
|
...interpolateParams: string[] |
|
|
|
): Observable<string> { |
|
|
|
return this.store.select(ConfigState.getLocalization(key, ...interpolateParams)); |
|
|
|
return this.configState |
|
|
|
.getAll$() |
|
|
|
.pipe(map(state => getLocalization(state, key, ...interpolateParams))); |
|
|
|
} |
|
|
|
|
|
|
|
getResource(resourceName: string) { |
|
|
|
return this.store.select(ConfigState.getLocalizationResource(resourceName)); |
|
|
|
return this.configState.getDeep(`localization.values.${resourceName}`); |
|
|
|
} |
|
|
|
|
|
|
|
getResource$(resourceName: string) { |
|
|
|
return this.configState.getDeep$(`localization.values.${resourceName}`); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -103,18 +113,18 @@ export class LocalizationService { |
|
|
|
* @param interpolateParams Values to intepolate. |
|
|
|
*/ |
|
|
|
instant(key: string | Config.LocalizationWithDefault, ...interpolateParams: string[]): string { |
|
|
|
return this.store.selectSnapshot(ConfigState.getLocalization(key, ...interpolateParams)); |
|
|
|
return getLocalization(this.configState.getAll(), key, ...interpolateParams); |
|
|
|
} |
|
|
|
|
|
|
|
localize(resourceName: string, key: string, defaultValue: string): Observable<string> { |
|
|
|
return this.store.select(ConfigState.getOne('localization')).pipe( |
|
|
|
return this.configState.getOne$('localization').pipe( |
|
|
|
map(createLocalizer), |
|
|
|
map(localize => localize(resourceName, key, defaultValue)), |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
localizeSync(resourceName: string, key: string, defaultValue: string): string { |
|
|
|
const localization = this.store.selectSnapshot(ConfigState.getOne('localization')); |
|
|
|
const localization = this.configState.getOne('localization'); |
|
|
|
return createLocalizer(localization)(resourceName, key, defaultValue); |
|
|
|
} |
|
|
|
|
|
|
|
@ -123,14 +133,71 @@ export class LocalizationService { |
|
|
|
keys: string[], |
|
|
|
defaultValue: string, |
|
|
|
): Observable<string> { |
|
|
|
return this.store.select(ConfigState.getOne('localization')).pipe( |
|
|
|
return this.configState.getOne$('localization').pipe( |
|
|
|
map(createLocalizerWithFallback), |
|
|
|
map(localizeWithFallback => localizeWithFallback(resourceNames, keys, defaultValue)), |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
localizeWithFallbackSync(resourceNames: string[], keys: string[], defaultValue: string): string { |
|
|
|
const localization = this.store.selectSnapshot(ConfigState.getOne('localization')); |
|
|
|
const localization = this.configState.getOne('localization'); |
|
|
|
return createLocalizerWithFallback(localization)(resourceNames, keys, defaultValue); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function getLocalization( |
|
|
|
state: ApplicationConfiguration.Response, |
|
|
|
key: string | Config.LocalizationWithDefault, |
|
|
|
...interpolateParams: string[] |
|
|
|
) { |
|
|
|
if (!key) key = ''; |
|
|
|
let defaultValue: string; |
|
|
|
|
|
|
|
if (typeof key !== 'string') { |
|
|
|
defaultValue = key.defaultValue; |
|
|
|
key = key.key; |
|
|
|
} |
|
|
|
|
|
|
|
const keys = key.split('::') as string[]; |
|
|
|
const warn = (message: string) => { |
|
|
|
if (isDevMode) console.warn(message); |
|
|
|
}; |
|
|
|
|
|
|
|
if (keys.length < 2) { |
|
|
|
warn('The localization source separator (::) not found.'); |
|
|
|
return defaultValue || (key as string); |
|
|
|
} |
|
|
|
if (!state.localization) return defaultValue || keys[1]; |
|
|
|
|
|
|
|
const sourceName = keys[0] || state.localization.defaultResourceName; |
|
|
|
const sourceKey = keys[1]; |
|
|
|
|
|
|
|
if (sourceName === '_') { |
|
|
|
return defaultValue || sourceKey; |
|
|
|
} |
|
|
|
|
|
|
|
if (!sourceName) { |
|
|
|
warn('Localization source name is not specified and the defaultResourceName was not defined!'); |
|
|
|
|
|
|
|
return defaultValue || sourceKey; |
|
|
|
} |
|
|
|
|
|
|
|
const source = state.localization.values[sourceName]; |
|
|
|
if (!source) { |
|
|
|
warn('Could not find localization source: ' + sourceName); |
|
|
|
return defaultValue || sourceKey; |
|
|
|
} |
|
|
|
|
|
|
|
let localization = source[sourceKey]; |
|
|
|
if (typeof localization === 'undefined') { |
|
|
|
return defaultValue || sourceKey; |
|
|
|
} |
|
|
|
|
|
|
|
// [TODO]: next line should be removed in v3.2, breaking change!!!
|
|
|
|
interpolateParams = interpolateParams.filter(params => params != null); |
|
|
|
if (localization) localization = interpolate(localization, interpolateParams); |
|
|
|
|
|
|
|
if (typeof localization !== 'string') localization = ''; |
|
|
|
|
|
|
|
return localization || defaultValue || (key as string); |
|
|
|
} |
|
|
|
|