Skip to content

Commit

Permalink
feat: load translations with webpack
Browse files Browse the repository at this point in the history
  • Loading branch information
dhhyi committed Apr 17, 2021
1 parent 0d1be10 commit 8c725de
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 66 deletions.
29 changes: 15 additions & 14 deletions docs/concepts/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,21 +219,22 @@ To dynamically set the default locale, use the URL parameter `lang` when rewriti
## Extend Locales
To add other languages except English, German or French, you have to create a new json-mapping-file with all translations, e.g., _./src/assets/i18n/nl_NL.json_).
Add the locale in the file _./src/environment/environments.ts_.
Additionally, for Angular's built-in components, e.g., currency-pipe, you have to register locale data similar to `localeDe` and `localeFr` with `registerLocaleData(localeNl)` in _./src/app/core/configuration.module.ts._
To add other languages except English, German or French:
```typescript
...
import localeNl from '@angular/common/locales/nl';
...
export class ConfigurationModule {
constructor(@Inject(LOCALE_ID) lang: string, translateService: TranslateService) {
registerLocaleData(localeNl);
...
}
}
```
1. Create a new json-mapping-file with all translations, e.g., `src/assets/i18n/nl_NL.json`.
2. Add the locale to the environments under `src/environments`, e.g.
```typescript
{ lang: 'nl_NL', currency: 'EUR', value: 'nl', displayName: 'Dutch', displayLong: 'Dutch (Netherlands)' }
```
3. Import a [global variant of the locale data](https://angular.io/guide/i18n#import-global-variants-of-the-locale-data) in the [`InternationalizationModule`](../../src/app/core/internationalization.module.ts), e.g.
```typescript
case 'nl_NL':
import('@angular/common/locales/global/nl');
break;
```
# Further References
Expand Down
41 changes: 1 addition & 40 deletions src/app/app.server.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ import { ErrorHandler, NgModule } from '@angular/core';
import { TransferState } from '@angular/platform-browser';
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server';
import { META_REDUCERS } from '@ngrx/store';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';
import { Observable, Observer } from 'rxjs';

import { configurationMeta } from 'ish-core/configurations/configuration.meta';
import { COOKIE_CONSENT_VERSION, DISPLAY_VERSION } from 'ish-core/configurations/state-keys';
Expand All @@ -18,31 +14,6 @@ import { environment } from '../environments/environment';
import { AppComponent } from './app.component';
import { AppModule } from './app.module';

class TranslateUniversalLoader implements TranslateLoader {
getTranslation(lang: string): Observable<string> {
return new Observable((observer: Observer<string>) => {
let rootPath = process.cwd();
if (rootPath && rootPath.indexOf('browser') > 0) {
rootPath = process.cwd().split('browser')[0];
}
const file = join(rootPath, 'dist', 'browser', 'assets', 'i18n', `${lang}.json`);
if (!existsSync(file)) {
const errString = `Localization file '${file}' not found!`;
console.error(errString);
observer.error(errString);
} else {
const content = JSON.parse(readFileSync(file, 'utf8'));
observer.next(content);
observer.complete();
}
});
}
}

export function translateLoaderFactory() {
return new TranslateUniversalLoader();
}

export class UniversalErrorHandler implements ErrorHandler {
handleError(error: Error): void {
if (error instanceof HttpErrorResponse) {
Expand All @@ -54,17 +25,7 @@ export class UniversalErrorHandler implements ErrorHandler {
}

@NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: translateLoaderFactory,
},
}),
],
imports: [AppModule, ServerModule, ServerTransferStateModule],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: UniversalMockInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: UniversalLogInterceptor, multi: true },
Expand Down
30 changes: 18 additions & 12 deletions src/app/core/internationalization.module.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
import { registerLocaleData } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import localeDe from '@angular/common/locales/de';
import localeFr from '@angular/common/locales/fr';
import { Inject, LOCALE_ID, NgModule } from '@angular/core';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { Observable, from } from 'rxjs';
import { tap } from 'rxjs/operators';

export function translateFactory(http: HttpClient) {
return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
class WebpackTranslateLoader implements TranslateLoader {
getTranslation(lang: string): Observable<unknown> {
return from(import(`../../assets/i18n/${lang}.json`)).pipe(
tap(() => {
switch (lang) {
case 'de_DE':
import('@angular/common/locales/global/de');
break;
case 'fr_FR':
import('@angular/common/locales/global/fr');
break;
}
})
);
}
}

@NgModule({
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: translateFactory,
deps: [HttpClient],
useClass: WebpackTranslateLoader,
},
}),
],
})
export class InternationalizationModule {
constructor(@Inject(LOCALE_ID) lang: string, translateService: TranslateService) {
registerLocaleData(localeDe);
registerLocaleData(localeFr);

translateService.setDefaultLang(lang.replace(/\-/, '_'));
}
}
4 changes: 4 additions & 0 deletions src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
/* SystemJS module definition */
declare var module: NodeModule;

declare module '@angular/common/locales/global/de';

declare module '@angular/common/locales/global/fr';

interface NodeModule {
id: string;
}
Expand Down
18 changes: 18 additions & 0 deletions templates/webpack/webpack.custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,24 @@ export default (
return 'tracking';
}

// move translation files into own bundles
const i18nMatch = /[\\/]assets[\\/]i18n[\\/](.*?)\.json/.exec(identifier);
const locale = i18nMatch && i18nMatch[1];

if (locale) {
return locale.replace('_', '-');
}

// move Angular locale data into bundle with translations
const localeDataMatch = /[\\/]@angular[\\/]common[\\/]locales[\\/]global[\\/](.*?)\.js/.exec(identifier);
let localeData = localeDataMatch && localeDataMatch[1];
if (localeData) {
if (!localeData.includes('-')) {
localeData += '-' + localeData.toUpperCase();
}
return localeData;
}

const match = /[\\/](extensions|projects)[\\/](.*?)[\\/](src[\\/]app[\\/])?(.*)/.exec(identifier);
const feature = match && match[2];

Expand Down

1 comment on commit 8c725de

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Azure Demo Servers are available:

Please sign in to comment.