Browse Source

Merge remote-tracking branch 'origin/master' into dev

pull/4882/head
mehmet-erim 6 years ago
parent
commit
ddc4d45f27
  1. 4
      docs/en/Text-Templating.md
  2. 28
      docs/en/UI/Angular/Localization.md
  3. BIN
      docs/en/UI/Angular/images/locale-error.png
  4. 9
      npm/ng-packs/packages/core/src/lib/core.module.ts
  5. 1
      npm/ng-packs/packages/core/src/lib/models/common.ts
  6. 4
      npm/ng-packs/packages/core/src/lib/services/localization.service.ts
  7. 11
      npm/ng-packs/packages/core/src/lib/tokens/options.token.ts
  8. 14
      npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts
  9. 24
      npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts

4
docs/en/Text-Templating.md

@ -4,7 +4,7 @@
ABP Framework provides a simple, yet efficient text template system. Text templating is used to dynamically render contents based on a template and a model (a data object): ABP Framework provides a simple, yet efficient text template system. Text templating is used to dynamically render contents based on a template and a model (a data object):
***TEMPLATE + MODEL ==render==> RENDERED CONTENT*** Template + Model =renderer=> Rendered Content
It is very similar to an ASP.NET Core Razor View (or Page): It is very similar to an ASP.NET Core Razor View (or Page):
@ -454,4 +454,4 @@ Return `null` if your source can not find the content, so `ITemplateContentProvi
* [The source code of the sample application](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo) developed and referred through this document. * [The source code of the sample application](https://github.com/abpframework/abp-samples/tree/master/TextTemplateDemo) developed and referred through this document.
* [Localization system](Localization.md). * [Localization system](Localization.md).
* [Virtual File System](Virtual-File-System.md). * [Virtual File System](Virtual-File-System.md).

28
docs/en/UI/Angular/Localization.md

@ -193,6 +193,32 @@ import { Component } from '@angular/core';
export class AppComponent {} export class AppComponent {}
``` ```
## Mapping of Culture Name to Angular Locale File Name
Some of the culture names defined in .NET do not match Angular locales. In such cases, the Angular app throws an error like below at runtime:
![locale-error](./images/locale-error.png)
If you see an error like this, you should pass the `cultureNameToLocaleFileNameMapping` property like below to CoreModule's forRoot static method.
```js
// app.module.ts
@NgModule({
imports: [
// other imports
CoreModule.forRoot({
// other options
cultureNameToLocaleFileNameMapping: {
"DotnetCultureName": "AngularLocaleFileName",
"pt-BR": "pt" // example
}
})
//...
```
See [all locale files in Angular](https://github.com/angular/angular/tree/master/packages/common/locales).
## See Also ## See Also
@ -200,4 +226,4 @@ export class AppComponent {}
## What's Next? ## What's Next?
* [Permission Management](./Permission-Management.md) * [Permission Management](./Permission-Management.md)

BIN
docs/en/UI/Angular/images/locale-error.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

9
npm/ng-packs/packages/core/src/lib/core.module.ts

@ -34,7 +34,7 @@ import { ConfigState } from './states/config.state';
import { ProfileState } from './states/profile.state'; import { ProfileState } from './states/profile.state';
import { ReplaceableComponentsState } from './states/replaceable-components.state'; import { ReplaceableComponentsState } from './states/replaceable-components.state';
import { SessionState } from './states/session.state'; import { SessionState } from './states/session.state';
import { CORE_OPTIONS } from './tokens/options.token'; import { CORE_OPTIONS, coreOptionsFactory } from './tokens/options.token';
import { noop } from './utils/common-utils'; import { noop } from './utils/common-utils';
import './utils/date-extensions'; import './utils/date-extensions';
import { getInitialData, localeInitializer, configureOAuth } from './utils/initial-utils'; import { getInitialData, localeInitializer, configureOAuth } from './utils/initial-utils';
@ -171,9 +171,14 @@ export class CoreModule {
useValue: { environment: options.environment }, useValue: { environment: options.environment },
}, },
{ {
provide: CORE_OPTIONS, provide: 'CORE_OPTIONS',
useValue: options, useValue: options,
}, },
{
provide: CORE_OPTIONS,
useFactory: coreOptionsFactory,
deps: ['CORE_OPTIONS'],
},
{ {
provide: HTTP_INTERCEPTORS, provide: HTTP_INTERCEPTORS,
useClass: ApiInterceptor, useClass: ApiInterceptor,

1
npm/ng-packs/packages/core/src/lib/models/common.ts

@ -9,6 +9,7 @@ export namespace ABP {
environment: Partial<Config.Environment>; environment: Partial<Config.Environment>;
skipGetAppConfiguration?: boolean; skipGetAppConfiguration?: boolean;
sendNullsAsQueryParam?: boolean; sendNullsAsQueryParam?: boolean;
cultureNameToLocaleFileNameMapping?: Dictionary<string>;
} }
export interface Test { export interface Test {

4
npm/ng-packs/packages/core/src/lib/services/localization.service.ts

@ -8,6 +8,7 @@ import { Config } from '../models/config';
import { ConfigState } from '../states/config.state'; import { ConfigState } from '../states/config.state';
import { registerLocale } from '../utils/initial-utils'; import { registerLocale } from '../utils/initial-utils';
import { createLocalizer, createLocalizerWithFallback } from '../utils/localization-utils'; import { createLocalizer, createLocalizerWithFallback } from '../utils/localization-utils';
import { CORE_OPTIONS } from '../tokens/options.token';
type ShouldReuseRoute = (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) => boolean; type ShouldReuseRoute = (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) => boolean;
@ -44,11 +45,12 @@ export class LocalizationService {
registerLocale(locale: string) { registerLocale(locale: string) {
const router = this.injector.get(Router); const router = this.injector.get(Router);
const { cultureNameToLocaleFileNameMapping: localeNameMap } = this.injector.get(CORE_OPTIONS);
const { shouldReuseRoute } = router.routeReuseStrategy; const { shouldReuseRoute } = router.routeReuseStrategy;
router.routeReuseStrategy.shouldReuseRoute = () => false; router.routeReuseStrategy.shouldReuseRoute = () => false;
router.navigated = false; router.navigated = false;
return registerLocale(locale).then(() => { return registerLocale(locale, localeNameMap).then(() => {
this.ngZone.run(async () => { this.ngZone.run(async () => {
await router.navigateByUrl(router.url).catch(noop); await router.navigateByUrl(router.url).catch(noop);
router.routeReuseStrategy.shouldReuseRoute = shouldReuseRoute; router.routeReuseStrategy.shouldReuseRoute = shouldReuseRoute;

11
npm/ng-packs/packages/core/src/lib/tokens/options.token.ts

@ -1,4 +1,15 @@
import { InjectionToken } from '@angular/core'; import { InjectionToken } from '@angular/core';
import { ABP } from '../models/common'; import { ABP } from '../models/common';
import differentLocales from '../constants/different-locales';
export const CORE_OPTIONS = new InjectionToken<ABP.Root>('CORE_OPTIONS'); export const CORE_OPTIONS = new InjectionToken<ABP.Root>('CORE_OPTIONS');
export function coreOptionsFactory({
cultureNameToLocaleFileNameMapping: localeNameMap = {},
...options
}: ABP.Root) {
return {
...options,
cultureNameToLocaleFileNameMapping: { ...differentLocales, ...localeNameMap },
} as ABP.Root;
}

14
npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts

@ -4,7 +4,6 @@ import { Store } from '@ngxs/store';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { GetAppConfiguration } from '../actions/config.actions'; import { GetAppConfiguration } from '../actions/config.actions';
import differentLocales from '../constants/different-locales';
import { ABP } from '../models/common'; import { ABP } from '../models/common';
import { ConfigState } from '../states/config.state'; import { ConfigState } from '../states/config.state';
import { CORE_OPTIONS } from '../tokens/options.token'; import { CORE_OPTIONS } from '../tokens/options.token';
@ -45,22 +44,25 @@ function checkAccessToken(store: Store, injector: Injector) {
export function localeInitializer(injector: Injector) { export function localeInitializer(injector: Injector) {
const fn = () => { const fn = () => {
const store: Store = injector.get(Store); const store: Store = injector.get(Store);
const options = injector.get(CORE_OPTIONS);
const lang = store.selectSnapshot(state => state.SessionState.language) || 'en'; const lang = store.selectSnapshot(state => state.SessionState.language) || 'en';
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
registerLocale(lang).then(() => resolve('resolved'), reject); registerLocale(lang, options.cultureNameToLocaleFileNameMapping).then(
() => resolve('resolved'),
reject,
);
}); });
}; };
return fn; return fn;
} }
export function registerLocale(locale: string) { export function registerLocale(locale: string, localeNameMap: ABP.Dictionary<string>) {
return import( return import(
/* webpackInclude: /(af|ar|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$/ */ /* webpackChunkName: "_locale-[request]"*/
/* webpackChunkName: "[request]"*/ `@angular/common/locales/${localeNameMap[locale] || locale}.js`
`@angular/common/locales/${differentLocales[locale] || locale}.js`
).then(module => { ).then(module => {
registerLocaleData(module.default); registerLocaleData(module.default);
}); });

24
npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts

@ -42,6 +42,20 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
NgbCollapseModule, NgbCollapseModule,
NgbDropdownModule, NgbDropdownModule,
NgxValidateCoreModule, NgxValidateCoreModule,
],
entryComponents: [...LAYOUTS, ValidationErrorComponent, CurrentUserComponent, LanguagesComponent],
})
export class ThemeBasicModule {
static forRoot(): ModuleWithProviders<ThemeBasicModule> {
return {
ngModule: RootThemeBasicModule,
providers: [BASIC_THEME_NAV_ITEM_PROVIDERS, BASIC_THEME_STYLES_PROVIDERS],
};
}
}
@NgModule({
imports: [
NgxValidateCoreModule.forRoot({ NgxValidateCoreModule.forRoot({
targetSelector: '.form-group', targetSelector: '.form-group',
blueprints: { blueprints: {
@ -63,13 +77,5 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
errorTemplate: ValidationErrorComponent, errorTemplate: ValidationErrorComponent,
}), }),
], ],
entryComponents: [...LAYOUTS, ValidationErrorComponent, CurrentUserComponent, LanguagesComponent],
}) })
export class ThemeBasicModule { export class RootThemeBasicModule {}
static forRoot(): ModuleWithProviders<ThemeBasicModule> {
return {
ngModule: ThemeBasicModule,
providers: [BASIC_THEME_NAV_ITEM_PROVIDERS, BASIC_THEME_STYLES_PROVIDERS],
};
}
}

Loading…
Cancel
Save