From f741e77f20c1cf0980da88a7f141717a865ec165 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Mon, 26 Aug 2019 14:48:14 +0300 Subject: [PATCH] feature(core): implement angular locale system add new feature to ellipsis.directive --- .../src/lib/constants/different-locales.ts | 33 ++++++++++++++ .../packages/core/src/lib/constants/index.ts | 1 + .../packages/core/src/lib/core.module.ts | 20 ++++++--- .../src/lib/directives/ellipsis.directive.ts | 9 +++- .../packages/core/src/lib/providers/index.ts | 1 + .../core/src/lib/providers/locale.provider.ts | 24 ++++++++++ .../src/lib/services/localization.service.ts | 44 ++++++++++++++++--- .../core/src/lib/states/config.state.ts | 14 +++--- .../core/src/lib/states/session.state.ts | 9 +++- .../core/src/lib/utils/initial-utils.ts | 26 +++++++++++ npm/ng-packs/packages/core/src/public-api.ts | 2 +- .../application-layout.component.ts | 1 - .../theme-shared/src/lib/contants/styles.ts | 8 +++- 13 files changed, 169 insertions(+), 23 deletions(-) create mode 100644 npm/ng-packs/packages/core/src/lib/constants/different-locales.ts create mode 100644 npm/ng-packs/packages/core/src/lib/providers/index.ts create mode 100644 npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts diff --git a/npm/ng-packs/packages/core/src/lib/constants/different-locales.ts b/npm/ng-packs/packages/core/src/lib/constants/different-locales.ts new file mode 100644 index 0000000000..401a766fda --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/constants/different-locales.ts @@ -0,0 +1,33 @@ +// Different locales from .NET +// Key is .NET locale, value is Angular locale + +export default { + 'ar-sa': 'ar-SA', + 'ca-ES-valencia': 'ca-ES-VALENCIA', + 'de-de': 'de', + 'es-ES': 'es', + 'en-US': 'en', + 'fil-Latn': 'en', + 'ku-Arab': 'en', + 'ky-Cyrl': 'en', + 'mi-Latn': 'en', + 'prs-Arab': 'en', + 'qut-Latn': 'en', + nso: 'en', + quz: 'en', + 'fr-FR': 'fr', + 'gd-Latn': 'gd', + 'ha-Latn': 'ha', + 'ig-Latn': 'ig', + 'it-it': 'it', + 'mn-Cyrl': 'mn', + 'pt-BR': 'pt', + 'sd-Arab': 'pa-Arab', + 'sr-Cyrl-RS': 'sr-Cyrl', + 'sr-Latn-RS': 'sr-Latn', + 'tg-Cyrl': 'tg', + 'tk-Latn': 'tk', + 'tt-Cyrl': 'tt', + 'ug-Arab': 'ug', + 'yo-Latn': 'yo', +}; diff --git a/npm/ng-packs/packages/core/src/lib/constants/index.ts b/npm/ng-packs/packages/core/src/lib/constants/index.ts index e69de29bb2..54aaba730c 100644 --- a/npm/ng-packs/packages/core/src/lib/constants/index.ts +++ b/npm/ng-packs/packages/core/src/lib/constants/index.ts @@ -0,0 +1 @@ +export * from './different-locales'; diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index d967ae74c9..e9d6c87836 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -8,21 +8,22 @@ import { NgxsStoragePluginModule } from '@ngxs/storage-plugin'; import { NgxsModule, NGXS_PLUGINS } from '@ngxs/store'; import { DynamicLayoutComponent } from './components/dynamic-layout.component'; import { RouterOutletComponent } from './components/router-outlet.component'; +import { AutofocusDirective } from './directives/autofocus.directive'; +import { InputEventDebounceDirective } from './directives/debounce.directive'; +import { EllipsisDirective } from './directives/ellipsis.directive'; +import { FormSubmitDirective } from './directives/form-submit.directive'; import { PermissionDirective } from './directives/permission.directive'; +import { ClickEventStopPropagationDirective } from './directives/stop-propagation.directive'; import { VisibilityDirective } from './directives/visibility.directive'; import { ApiInterceptor } from './interceptors/api.interceptor'; import { ABP } from './models/common'; import { LocalizationPipe } from './pipes/localization.pipe'; import { ConfigPlugin, NGXS_CONFIG_PLUGIN_OPTIONS } from './plugins/config.plugin'; +import { LocaleProvider } from './providers/locale.provider'; import { ConfigState } from './states/config.state'; import { ProfileState } from './states/profile.state'; import { SessionState } from './states/session.state'; -import { getInitialData } from './utils/initial-utils'; -import { EllipsisDirective } from './directives/ellipsis.directive'; -import { AutofocusDirective } from './directives/autofocus.directive'; -import { InputEventDebounceDirective } from './directives/debounce.directive'; -import { ClickEventStopPropagationDirective } from './directives/stop-propagation.directive'; -import { FormSubmitDirective } from './directives/form-submit.directive'; +import { getInitialData, localeInitializer } from './utils/initial-utils'; @NgModule({ imports: [ @@ -73,6 +74,7 @@ export class CoreModule { return { ngModule: CoreModule, providers: [ + LocaleProvider, { provide: NGXS_PLUGINS, useClass: ConfigPlugin, @@ -93,6 +95,12 @@ export class CoreModule { deps: [Injector], useFactory: getInitialData, }, + { + provide: APP_INITIALIZER, + multi: true, + deps: [Injector], + useFactory: localeInitializer, + }, ], }; } diff --git a/npm/ng-packs/packages/core/src/lib/directives/ellipsis.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/ellipsis.directive.ts index c43b6fc923..fbfba8edda 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/ellipsis.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/ellipsis.directive.ts @@ -14,14 +14,19 @@ export class EllipsisDirective implements AfterContentInit { @Input('abpEllipsisEnabled') enabled = true; + @HostBinding('class.abp-ellipsis-inline') + get inlineClass() { + return this.enabled && this.width; + } + @HostBinding('class.abp-ellipsis') get class() { - return this.enabled; + return this.enabled && !this.width; } @HostBinding('style.max-width') get maxWidth() { - return this.enabled ? this.width || '170px' : undefined; + return this.enabled && this.width ? this.width || '170px' : undefined; } constructor(private cdRef: ChangeDetectorRef, private elRef: ElementRef) {} diff --git a/npm/ng-packs/packages/core/src/lib/providers/index.ts b/npm/ng-packs/packages/core/src/lib/providers/index.ts new file mode 100644 index 0000000000..fcbdb58be2 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/providers/index.ts @@ -0,0 +1 @@ +export * from './locale.provider'; diff --git a/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts b/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts new file mode 100644 index 0000000000..a0dce3c8bf --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts @@ -0,0 +1,24 @@ +import { LOCALE_ID, Provider } from '@angular/core'; +import localesMapping from '../constants/different-locales'; +import { LocalizationService } from '../services/localization.service'; + +export class LocaleId extends String { + constructor(private localizationService: LocalizationService) { + super(); + } + + toString(): string { + const { currentLang } = this.localizationService; + return localesMapping[currentLang] || currentLang; + } + + valueOf(): string { + return this.toString(); + } +} + +export const LocaleProvider: Provider = { + provide: LOCALE_ID, + useClass: LocaleId, + deps: [LocalizationService], +}; diff --git a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts index a86ef53203..4dba26bc1f 100644 --- a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts +++ b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts @@ -1,11 +1,45 @@ -import { Injectable } from '@angular/core'; -import { Store } from '@ngxs/store'; -import { ConfigState } from '../states'; -import { Observable } from 'rxjs'; +import { Injectable, Optional, SkipSelf } from '@angular/core'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; +import { Actions, Store } from '@ngxs/store'; +import { noop, Observable } from 'rxjs'; +import { ConfigState } from '../states/config.state'; +import { SessionState } from '../states/session.state'; +import { registerLocale } from '../utils/initial-utils'; + +type ShouldReuseRoute = (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) => boolean; @Injectable({ providedIn: 'root' }) export class LocalizationService { - constructor(private store: Store) {} + get currentLang(): string { + return this.store.selectSnapshot(SessionState.getLanguage); + } + + constructor( + private store: Store, + private router: Router, + private actions: Actions, + @Optional() + @SkipSelf() + otherInstance: LocalizationService, + ) { + if (otherInstance) throw new Error('LocaleService should have only one instance.'); + } + + private setRouteReuse(reuse: ShouldReuseRoute) { + this.router.routeReuseStrategy.shouldReuseRoute = reuse; + } + + registerLocale(locale: string) { + const { shouldReuseRoute } = this.router.routeReuseStrategy; + + this.setRouteReuse(() => false); + this.router.navigated = false; + + return registerLocale(locale).then(async () => { + await this.router.navigateByUrl(this.router.url).catch(noop); + this.setRouteReuse(shouldReuseRoute); + }); + } get(keys: string, ...interpolateParams: string[]): Observable { return this.store.select(ConfigState.getCopy(keys, ...interpolateParams)); diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index ccad1a6439..9ad6c08527 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -169,11 +169,15 @@ export class ConfigState { ...configuration, }), ), - switchMap(configuration => - this.store.selectSnapshot(SessionState.getLanguage) - ? of(null) - : dispatch(new SetLanguage(snq(() => configuration.setting.values['Abp.Localization.DefaultLanguage']))), - ), + switchMap(configuration => { + let defaultLang: string = configuration.setting.values['Abp.Localization.DefaultLanguage']; + + if (defaultLang.includes(';')) { + defaultLang = defaultLang.split(';')[0]; + } + + return this.store.selectSnapshot(SessionState.getLanguage) ? of(null) : dispatch(new SetLanguage(defaultLang)); + }), ); } diff --git a/npm/ng-packs/packages/core/src/lib/states/session.state.ts b/npm/ng-packs/packages/core/src/lib/states/session.state.ts index 58d0eddcfa..0754b0d62b 100644 --- a/npm/ng-packs/packages/core/src/lib/states/session.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/session.state.ts @@ -1,6 +1,9 @@ import { Action, Selector, State, StateContext } from '@ngxs/store'; import { SetLanguage, SetTenant } from '../actions/session.actions'; import { ABP, Session } from '../models'; +import { GetAppConfiguration } from '../actions/config.actions'; +import { LocalizationService } from '../services/localization.service'; +import { from, combineLatest } from 'rxjs'; @State({ name: 'SessionState', @@ -17,13 +20,15 @@ export class SessionState { return tenant; } - constructor() {} + constructor(private localizationService: LocalizationService) {} @Action(SetLanguage) - setLanguage({ patchState }: StateContext, { payload }: SetLanguage) { + setLanguage({ patchState, dispatch }: StateContext, { payload }: SetLanguage) { patchState({ language: payload, }); + + return combineLatest([dispatch(new GetAppConfiguration()), from(this.localizationService.registerLocale(payload))]); } @Action(SetTenant) diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index 6efba1e19b..7cf870667b 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -1,6 +1,9 @@ +import { registerLocaleData } from '@angular/common'; import { Injector } from '@angular/core'; import { Store } from '@ngxs/store'; import { GetAppConfiguration } from '../actions/config.actions'; +import differentLocales from '../constants/different-locales'; +import { SessionState } from '../states/session.state'; export function getInitialData(injector: Injector) { const fn = function() { @@ -11,3 +14,26 @@ export function getInitialData(injector: Injector) { return fn; } + +export function localeInitializer(injector: Injector) { + const fn = function() { + const store: Store = injector.get(Store); + + const lang = store.selectSnapshot(SessionState.getLanguage) || 'en'; + + return new Promise((resolve, reject) => { + registerLocale(lang).then(() => resolve(), reject); + }); + }; + + return fn; +} + +export function registerLocale(locale: string) { + return import( + /* webpackInclude: /(af|am|ar-SA|as|az-Latn|be|bg|bn-BD|bn-IN|bs|ca|ca-ES-VALENCIA|cs|cy|da|de|de|el|en-GB|en|es|en|es-US|es-MX|et|eu|fa|fi|en|fr|fr|fr-CA|ga|gd|gl|gu|ha|he|hi|hr|hu|hy|id|ig|is|it|it|ja|ka|kk|km|kn|ko|kok|en|en|lb|lt|lv|en|mk|ml|mn|mr|ms|mt|nb|ne|nl|nl-BE|nn|en|or|pa|pa-Arab|pl|en|pt|pt-PT|en|en|ro|ru|rw|pa-Arab|si|sk|sl|sq|sr-Cyrl-BA|sr-Cyrl|sr-Latn|sv|sw|ta|te|tg|th|ti|tk|tn|tr|tt|ug|uk|ur|uz-Latn|vi|wo|xh|yo|zh-Hans|zh-Hant|zu)\.js$/ */ + `@angular/common/locales/${differentLocales[locale] || locale}.js` + ).then(module => { + registerLocaleData(module.default); + }); +} diff --git a/npm/ng-packs/packages/core/src/public-api.ts b/npm/ng-packs/packages/core/src/public-api.ts index b10edcbbc9..0209f124de 100644 --- a/npm/ng-packs/packages/core/src/public-api.ts +++ b/npm/ng-packs/packages/core/src/public-api.ts @@ -5,7 +5,7 @@ // export * from './lib/handlers'; export * from './lib/actions'; export * from './lib/components'; -// export * from './lib/constants'; +export * from './lib/constants'; export * from './lib/directives'; export * from './lib/enums'; export * from './lib/guards'; diff --git a/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts b/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts index 7bdbdf58ed..c942aa7c92 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts @@ -147,7 +147,6 @@ export class ApplicationLayoutComponent implements AfterViewInit, OnDestroy { onChangeLang(cultureName: string) { this.store.dispatch(new SetLanguage(cultureName)); - this.store.dispatch(new GetAppConfiguration()); } logout() { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts b/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts index 78e68cc7f8..0cf6b5c2dd 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/contants/styles.ts @@ -32,13 +32,19 @@ export default ` background-color: rgba(0, 0, 0, .6); } -.abp-ellipsis { +.abp-ellipsis-inline { display: inline-block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.abp-ellipsis { + overflow: hidden !important; + text-overflow: ellipsis; + white-space: nowrap; +} + /*