From 3b9c3764cafd23ddfb1e015612ac64198be170da Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 1 Dec 2016 13:03:56 -0600 Subject: [PATCH 1/6] Added ng2-translate and copy-webpack-plugin --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index b693aac985..6654434006 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "js.clone": "0.0.3", "methods": "~1.1.2", "morgan": "^1.7.0", + "ng2-translate": "~4.0.1", "preboot": "~4.5.2", "rxjs": "5.0.0-beta.12", "webfontloader": "^1.6.26", @@ -77,6 +78,7 @@ "awesome-typescript-loader": "^2.2.4", "codelyzer": "1.0.0-beta.3", "cookie-parser": "^1.4.3", + "copy-webpack-plugin": "~4.0.1", "express-interceptor": "^1.2.0", "iltorb": "^1.0.13", "imports-loader": "^0.6.5", From 7c3e0a3ca40ee9a95c264e0235cd6fc3f395a4bb Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 1 Dec 2016 13:04:31 -0600 Subject: [PATCH 2/6] Added initial i18n en.json file --- resources/i18n/en.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 resources/i18n/en.json diff --git a/resources/i18n/en.json b/resources/i18n/en.json new file mode 100644 index 0000000000..26237a935d --- /dev/null +++ b/resources/i18n/en.json @@ -0,0 +1,13 @@ +{ + "title": "DSpace Universal", + + "nav": { + "home": "Home" + }, + + "example": { + "with": { + "data": "{{greeting}}, {{recipient}}!" + } + } +} From ed5b8a641ff274f17dd3428730d735a927cb4ecf Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 1 Dec 2016 13:05:17 -0600 Subject: [PATCH 3/6] Added CopyWebpackPlugin to webpack config --- webpack.config.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/webpack.config.ts b/webpack.config.ts index 436d22515e..0ce1116f2e 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -2,6 +2,7 @@ var webpack = require('webpack'); var path = require('path'); var clone = require('js.clone'); var webpackMerge = require('webpack-merge'); +let CopyWebpackPlugin = require('copy-webpack-plugin'); export var commonPlugins = [ new webpack.ContextReplacementPlugin( @@ -13,6 +14,11 @@ export var commonPlugins = [ } ), + new CopyWebpackPlugin([{ + from: path.join(__dirname, 'resources', 'i18n'), + to: path.join('assets', 'i18n') + }]), + // Loader options new webpack.LoaderOptionsPlugin({ @@ -24,7 +30,7 @@ export var commonConfig = { devtool: 'source-map', resolve: { extensions: ['.ts', '.js', '.json'], - modules: [ root('node_modules') ] + modules: [root('node_modules')] }, context: __dirname, output: { @@ -34,10 +40,10 @@ export var commonConfig = { module: { rules: [ // TypeScript - { test: /\.ts$/, use: ['awesome-typescript-loader', 'angular2-template-loader'] }, + { test: /\.ts$/, use: ['awesome-typescript-loader', 'angular2-template-loader'] }, { test: /\.html$/, use: 'raw-loader' }, - { test: /\.css$/, use: 'raw-loader' }, - { test: /\.scss$/, use: ['raw-loader', 'sass-loader'] }, + { test: /\.css$/, use: 'raw-loader' }, + { test: /\.scss$/, use: ['raw-loader', 'sass-loader'] }, { test: /\.json$/, use: 'json-loader' } ], }, From 40562a506929b45e5feefc2dc67c458a43c839d1 Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 1 Dec 2016 13:06:31 -0600 Subject: [PATCH 4/6] Added TranslateModule and dependencies to node and browser modules --- src/app/shared/shared.module.ts | 4 ++++ src/browser.module.ts | 16 ++++++++++++++-- src/node.module.ts | 22 +++++++++++++++++----- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 86c72cdbba..0f8b5e5625 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -2,6 +2,9 @@ import { NgModule, ModuleWithProviders } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { TranslateModule } from 'ng2-translate/ng2-translate'; + import { ApiService } from './api.service'; import { ModelService } from './model/model.service'; @@ -9,6 +12,7 @@ const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here CommonModule, RouterModule, + TranslateModule, FormsModule, ReactiveFormsModule ]; diff --git a/src/browser.module.ts b/src/browser.module.ts index 512e68958c..e6475cc118 100755 --- a/src/browser.module.ts +++ b/src/browser.module.ts @@ -1,9 +1,12 @@ import { NgModule } from '@angular/core'; +import { Http } from '@angular/http'; import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { UniversalModule, isBrowser, isNode, AUTO_PREBOOT } from 'angular2-universal/browser'; // for AoT we need to manually split universal packages import { IdlePreload, IdlePreloadModule } from '@angularclass/idle-preload'; +import { TranslateLoader, TranslateModule, TranslateStaticLoader } from 'ng2-translate'; + import { AppModule, AppComponent } from './app/app.module'; import { SharedModule } from './app/shared/shared.module'; import { CacheService } from './app/shared/cache.service'; @@ -14,6 +17,10 @@ import { Meta } from './angular2-meta'; // import * as LRU from 'modern-lru'; +export function createTranslateLoader(http: Http) { + return new TranslateStaticLoader(http, './assets/i18n', '.json'); +} + export function getLRU(lru?: any) { // use LRU for node // return lru || new LRU(10); @@ -33,9 +40,14 @@ export function getResponse() { export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE'; @NgModule({ - bootstrap: [ AppComponent ], + bootstrap: [AppComponent], imports: [ - // MaterialModule.forRoot() should be included first + TranslateModule.forRoot({ + provide: TranslateLoader, + useFactory: (createTranslateLoader), + deps: [Http] + }), + UniversalModule, // BrowserModule, HttpModule, and JsonpModule are included FormsModule, diff --git a/src/node.module.ts b/src/node.module.ts index c7a8ad6296..5395e54750 100755 --- a/src/node.module.ts +++ b/src/node.module.ts @@ -1,8 +1,11 @@ import { NgModule } from '@angular/core'; +import { Http } from '@angular/http'; import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { UniversalModule, isBrowser, isNode } from 'angular2-universal/node'; // for AoT we need to manually split universal packages +import { TranslateLoader, TranslateModule, TranslateStaticLoader } from 'ng2-translate'; + import { AppModule, AppComponent } from './app/app.module'; import { SharedModule } from './app/shared/shared.module'; import { CacheService } from './app/shared/cache.service'; @@ -11,6 +14,10 @@ import { CacheService } from './app/shared/cache.service'; // see https://github.com/angular/angular/pull/12322 import { Meta } from './angular2-meta'; +export function createTranslateLoader(http: Http) { + return new TranslateStaticLoader(http, './assets/i18n', '.json'); +} + export function getLRU() { return new Map(); } @@ -25,9 +32,14 @@ export function getResponse() { export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE'; @NgModule({ - bootstrap: [ AppComponent ], + bootstrap: [AppComponent], imports: [ - // MaterialModule.forRoot() should be included first + TranslateModule.forRoot({ + provide: TranslateLoader, + useFactory: (createTranslateLoader), + deps: [Http] + }), + UniversalModule, // BrowserModule, HttpModule, and JsonpModule are included FormsModule, @@ -63,9 +75,9 @@ export class MainModule { universalCache[CacheService.KEY] = JSON.stringify(this.cache.dehydrate()); } - /** - * Clear the cache after it's rendered - */ + /** + * Clear the cache after it's rendered + */ universalAfterDehydrate = () => { // comment out if LRU provided at platform level to be shared between each user this.cache.clear(); From 1a8aabc996e4b53b1fb9b5ab01195e4a0e61234e Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 1 Dec 2016 13:08:23 -0600 Subject: [PATCH 5/6] Translating app component content --- src/app/app.component.html | 6 ++++-- src/app/app.component.ts | 29 ++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index a7d039d11d..a83351f943 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,9 +1,11 @@ -

DSpace

+

{{ 'title' | translate }}

+

{{ 'example.with.data' | translate:data }}

+

{{ example }}

diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 8951b4881e..215968ced2 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,11 +1,34 @@ -import { Component, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { Component, ChangeDetectionStrategy, OnInit, ViewEncapsulation } from '@angular/core'; + +import { TranslateService } from 'ng2-translate'; @Component({ changeDetection: ChangeDetectionStrategy.Default, encapsulation: ViewEncapsulation.Emulated, selector: 'ds-app', templateUrl: './app.component.html', - styleUrls: [ './app.component.scss' ] + styleUrls: ['./app.component.scss'] }) -export class AppComponent { +export class AppComponent implements OnInit { + + example: string; + + data: any = { + greeting: 'Hello', + recipient: 'World' + } + + constructor(public translate: TranslateService) { + // this language will be used as a fallback when a translation isn't found in the current language + translate.setDefaultLang('en'); + // the lang to use, if the lang isn't available, it will use the current loader to get them + translate.use('en'); + } + + ngOnInit() { + this.translate.get('example.with.data', { greeting: 'Hello', recipient: 'DSpace' }).subscribe((res: string) => { + this.example = res; + }); + } + } From 8268845cf06a12b24b08efa73124298433e31195 Mon Sep 17 00:00:00 2001 From: William Welling Date: Thu, 1 Dec 2016 13:16:39 -0600 Subject: [PATCH 6/6] Use lifecycle hooks to unsubscribe --- src/app/app.component.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 215968ced2..39f73ee36b 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectionStrategy, OnInit, ViewEncapsulation } from '@angular/core'; +import { Component, ChangeDetectionStrategy, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { TranslateService } from 'ng2-translate'; @@ -9,7 +9,7 @@ import { TranslateService } from 'ng2-translate'; templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) -export class AppComponent implements OnInit { +export class AppComponent implements OnDestroy, OnInit { example: string; @@ -18,6 +18,8 @@ export class AppComponent implements OnInit { recipient: 'World' } + private registerSubscription: any; + constructor(public translate: TranslateService) { // this language will be used as a fallback when a translation isn't found in the current language translate.setDefaultLang('en'); @@ -26,9 +28,15 @@ export class AppComponent implements OnInit { } ngOnInit() { - this.translate.get('example.with.data', { greeting: 'Hello', recipient: 'DSpace' }).subscribe((res: string) => { - this.example = res; + this.registerSubscription = this.translate.get('example.with.data', { greeting: 'Hello', recipient: 'DSpace' }).subscribe((translation: string) => { + this.example = translation; }); } + ngOnDestroy() { + if (this.registerSubscription) { + this.registerSubscription.unsubscribe(); + } + } + }