Skip to content

Commit

Permalink
Merge pull request abpframework#1685 from abpframework/feature/implem…
Browse files Browse the repository at this point in the history
…ent-angular-locale

feature(core): implement angular locale system
  • Loading branch information
thediaval authored Aug 26, 2019
2 parents a453b9f + f741e77 commit 731347e
Show file tree
Hide file tree
Showing 13 changed files with 169 additions and 23 deletions.
33 changes: 33 additions & 0 deletions npm/ng-packs/packages/core/src/lib/constants/different-locales.ts
Original file line number Diff line number Diff line change
@@ -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',
};
1 change: 1 addition & 0 deletions npm/ng-packs/packages/core/src/lib/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './different-locales';
20 changes: 14 additions & 6 deletions npm/ng-packs/packages/core/src/lib/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down Expand Up @@ -73,6 +74,7 @@ export class CoreModule {
return {
ngModule: CoreModule,
providers: [
LocaleProvider,
{
provide: NGXS_PLUGINS,
useClass: ConfigPlugin,
Expand All @@ -93,6 +95,12 @@ export class CoreModule {
deps: [Injector],
useFactory: getInitialData,
},
{
provide: APP_INITIALIZER,
multi: true,
deps: [Injector],
useFactory: localeInitializer,
},
],
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
Expand Down
1 change: 1 addition & 0 deletions npm/ng-packs/packages/core/src/lib/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './locale.provider';
24 changes: 24 additions & 0 deletions npm/ng-packs/packages/core/src/lib/providers/locale.provider.ts
Original file line number Diff line number Diff line change
@@ -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],
};
Original file line number Diff line number Diff line change
@@ -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<string> {
return this.store.select(ConfigState.getCopy(keys, ...interpolateParams));
Expand Down
14 changes: 9 additions & 5 deletions npm/ng-packs/packages/core/src/lib/states/config.state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}),
);
}

Expand Down
9 changes: 7 additions & 2 deletions npm/ng-packs/packages/core/src/lib/states/session.state.ts
Original file line number Diff line number Diff line change
@@ -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<Session.State>({
name: 'SessionState',
Expand All @@ -17,13 +20,15 @@ export class SessionState {
return tenant;
}

constructor() {}
constructor(private localizationService: LocalizationService) {}

@Action(SetLanguage)
setLanguage({ patchState }: StateContext<Session.State>, { payload }: SetLanguage) {
setLanguage({ patchState, dispatch }: StateContext<Session.State>, { payload }: SetLanguage) {
patchState({
language: payload,
});

return combineLatest([dispatch(new GetAppConfiguration()), from(this.localizationService.registerLocale(payload))]);
}

@Action(SetTenant)
Expand Down
26 changes: 26 additions & 0 deletions npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts
Original file line number Diff line number Diff line change
@@ -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() {
Expand All @@ -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);
});
}
2 changes: 1 addition & 1 deletion npm/ng-packs/packages/core/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
/* <animations */
.fade-in-top {
Expand Down

0 comments on commit 731347e

Please sign in to comment.