Skip to content

Commit a6cd095

Browse files
Ismaestroiramos
authored and
iramos
committed
feat(i18n): added internationalization ng2 translate plugin
1 parent 021a43c commit a6cd095

20 files changed

+167
-50
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"core-js": "^2.4.1",
2727
"font-awesome": "^4.7.0",
2828
"json-server": "^0.9.4",
29+
"ng2-translate": "^5.0.0",
2930
"rxjs": "^5.0.1",
3031
"ts-helpers": "^1.1.1",
3132
"zone.js": "^0.7.2"

src/app/app.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<div class="container">
2-
<toh-nav [title]="'Tour of heroes'"></toh-nav>
2+
<toh-nav [title]="'tourOfHeroes' | translate"></toh-nav>
33
<router-outlet></router-outlet>
44
</div>
55
<footer class="footer">
66
<div class="container">
7-
<span class="text-muted">Tour of heroes @2016.</span>
7+
<span class="text-muted">{{ 'tourOfHeroes' | translate }} @2016.</span>
88
</div>
99
</footer>

src/app/app.component.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import {Component, Inject} from '@angular/core';
2-
3-
import {APP_CONFIG} from './config/app.config';
4-
import {IAppConfig} from './config/iapp.config';
1+
import {Component} from '@angular/core';
2+
import {TranslateService} from 'ng2-translate';
53

64
@Component({
75
selector: 'toh-app',
86
templateUrl: './app.component.html'
97
})
108

119
export class AppComponent {
12-
title: string;
10+
private translateService: TranslateService;
1311

14-
constructor(@Inject(APP_CONFIG) private appConfig: IAppConfig) {
15-
this.title = this.appConfig.title;
12+
constructor(translateService: TranslateService) {
13+
this.translateService = translateService;
14+
this.translateService.setDefaultLang('en');
15+
this.translateService.use('en');
1616
}
1717
}

src/app/app.module.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
import {NgModule} from '@angular/core';
2-
import {BrowserModule} from '@angular/platform-browser';
3-
import {FormsModule} from '@angular/forms';
4-
import {HttpModule} from '@angular/http';
1+
import {NgModule} from '@angular/core';
2+
import {BrowserModule} from '@angular/platform-browser';
3+
import {FormsModule} from '@angular/forms';
4+
import {Http, HttpModule} from '@angular/http';
5+
import {TranslateModule, TranslateLoader} from 'ng2-translate';
6+
import {TranslateLoaderFactory} from './app.translate.factory';
57

68
import {APP_CONFIG, AppConfig} from './config/app.config';
79

@@ -18,6 +20,11 @@ import {HeroTopComponent} from './heroes/hero-top/hero-top.component';
1820
BrowserModule,
1921
FormsModule,
2022
HttpModule,
23+
TranslateModule.forRoot({
24+
provide: TranslateLoader,
25+
useFactory: TranslateLoaderFactory,
26+
deps: [Http]
27+
}),
2128
AppRoutingModule,
2229
CoreModule,
2330
HeroesModule,

src/app/app.translate.factory.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import {TranslateStaticLoader} from 'ng2-translate';
2+
3+
export function TranslateLoaderFactory(http: any) {
4+
return new TranslateStaticLoader(http, '/assets/i18n', '.json');
5+
}

src/app/config/app.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export let APP_CONFIG = new OpaqueToken('app.config');
66

77
let heroesRoute = 'heroes';
88
export const AppConfig: IAppConfig = {
9-
title: 'Tour of Heroes',
109
routes: {
1110
heroes: heroesRoute,
1211
heroById: heroesRoute + '/:id'

src/app/config/iapp.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export interface IAppConfig {
22
routes: any;
33
endpoints: any;
4-
title: string;
54
}

src/app/core/core.module.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import {NgModule, Optional, SkipSelf} from '@angular/core';
2-
import {CommonModule} from '@angular/common';
3-
import {FormsModule} from '@angular/forms';
1+
import {NgModule, Optional, SkipSelf} from '@angular/core';
2+
import {CommonModule} from '@angular/common';
3+
import {FormsModule} from '@angular/forms';
4+
import {Http} from '@angular/http';
5+
import {TranslateModule, TranslateLoader} from 'ng2-translate';
6+
import {TranslateLoaderFactory} from '../app.translate.factory';
47

58
import {throwIfAlreadyLoaded} from './module-import-guard';
69
import {LoggerService} from './logger.service';
@@ -10,12 +13,18 @@ import {HeroRoutingModule} from '../heroes/heroes-routing.module';
1013

1114
import {NavComponent} from './nav/nav.component';
1215

16+
1317
@NgModule({
1418
imports: [
1519
CommonModule,
1620
FormsModule,
1721
HeroRoutingModule,
18-
HeroesModule
22+
HeroesModule,
23+
TranslateModule.forRoot({
24+
provide: TranslateLoader,
25+
useFactory: TranslateLoaderFactory,
26+
deps: [Http]
27+
}),
1928
],
2029
exports: [
2130
NavComponent

src/app/core/nav/nav.component.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
</li>
1010
</ul>
1111
</div>
12+
<div class="dropdown">
13+
<a class="btn btn-secondary dropdown-toggle" id="dropdownMenuLink" data-toggle="dropdown"
14+
aria-haspopup="true" aria-expanded="false">
15+
<i class="fa fa-globe" aria-hidden="true"></i> {{ 'language' | translate }}
16+
</a>
17+
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
18+
<a class="dropdown-item" (click)="changeLanguage('en')">{{ 'english' | translate }}</a>
19+
<a class="dropdown-item" (click)="changeLanguage('es')">{{ 'spanish' | translate }}</a>
20+
</div>
21+
</div>
1222
<toh-hero-search></toh-hero-search>
1323
</nav>
1424
</header>

src/app/core/nav/nav.component.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {Component, Inject, Input} from '@angular/core';
2+
import {TranslateService} from 'ng2-translate';
23

34
import {APP_CONFIG} from '../../config/app.config';
45
import {IAppConfig} from '../../config/iapp.config';
@@ -14,10 +15,25 @@ export class NavComponent {
1415

1516
menuItems: any[];
1617

17-
constructor(@Inject(APP_CONFIG) private appConfig: IAppConfig) {
18-
this.menuItems = [
19-
{link: '/', name: 'Home'},
20-
{link: '/' + appConfig.routes.heroes, name: 'Heroes list'}
21-
];
18+
private translateService: TranslateService;
19+
20+
private loadMenus(): void {
21+
this.translateService.get(['home', 'heroesList'], {}).subscribe((texts: string) => {
22+
this.menuItems = [
23+
{link: '/', name: texts['home']},
24+
{link: '/' + this.appConfig.routes.heroes, name: texts['heroesList']}
25+
];
26+
});
27+
}
28+
29+
constructor(@Inject(APP_CONFIG) private appConfig: IAppConfig,
30+
translateService: TranslateService) {
31+
this.translateService = translateService;
32+
this.loadMenus();
33+
}
34+
35+
changeLanguage(language: string): void {
36+
this.translateService.use(language);
37+
this.loadMenus();
2238
}
2339
}
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
1-
<h3>New hero</h3>
1+
<h3>{{ 'hero-create-new.newHero' | translate }}</h3>
22
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">
33
<div class="form-group">
4-
<label class="form-label" for="name">Name</label>
4+
<label class="form-label" for="name">{{ 'name' | translate }}</label>
55
<input type="text" class="form-control" id="name"
66
required
77
[(ngModel)]="hero.name" name="name"
88
#heroName="ngModel">
99
<div [hidden]="heroName.valid || heroName.pristine"
1010
class="alert alert-danger">
11-
Name is required
11+
{{ 'nameRequired' | translate }}
1212
</div>
1313
</div>
1414
<div class="form-group">
15-
<label class="form-label" for="alterEgo">Alter Ego</label>
15+
<label class="form-label" for="alterEgo">Álter Ego</label>
1616
<input type="text" class="form-control" id="alterEgo"
1717
[(ngModel)]="hero.alterEgo" name="alterEgo">
1818
</div>
1919
<div class="form-group">
20-
<label class="form-label" for="power">Hero Power</label>
20+
<label class="form-label" for="power">{{ 'heroPower' | translate }}</label>
2121
<select class="form-control" id="power"
2222
required
2323
[(ngModel)]="hero.power" name="power">
2424
<option *ngFor="let power of powers" [value]="power">{{power}}</option>
2525
</select>
2626
</div>
27-
<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Create new hero!</button>
27+
<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">{{ 'createNewHero' | translate }}!
28+
</button>
2829
</form>
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<div class="container">
22
<div *ngIf="hero">
3-
<h2>{{hero.name}} details!</h2>
3+
<h2>{{hero.name}} {{ 'details' | translate }}!</h2>
44
<div class="input-group">
55
<span class="input-group-addon" id="hero-id">Id</span>
66
<input type="text" class="form-control" placeholder="Id" aria-describedby="hero-id"
77
[value]="hero.id" disabled>
88
</div>
99
<br>
1010
<div class="input-group">
11-
<span class="input-group-addon" id="hero-name">Name</span>
11+
<span class="input-group-addon" id="hero-name">{{ 'name' | translate }}</span>
1212
<input type="text" class="form-control" placeholder="Name" aria-describedby="hero-name"
1313
[(ngModel)]="hero.name">
1414
</div>
@@ -19,7 +19,7 @@ <h2>{{hero.name}} details!</h2>
1919
[(ngModel)]="hero.alterEgo">
2020
</div>
2121
<br>
22-
<button class="btn btn-secondary" (click)="goBack()">Back</button>
23-
<button class="btn btn-primary" (click)="saveHero()">Save hero</button>
22+
<button class="btn btn-secondary" (click)="goBack()">{{ 'back' | translate }}</button>
23+
<button class="btn btn-primary" (click)="saveHero()">{{ 'saveHero' | translate }}</button>
2424
</div>
2525
</div>

src/app/heroes/hero-list/hero-list.component.html

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
<div class="container">
22
<h2>
3-
Heroes list
3+
{{ 'heroesList' | translate }}
44
<button class="btn btn-success"
55
(click)="createNewHero = !createNewHero">
66
<i class="fa fa-plus" aria-hidden="true"></i>
77
</button>
88
</h2>
99
<div>
1010
<div class="hero-list">
11-
<h3>Pick a highlight color</h3>
11+
<h3>{{ 'pickColor' | translate }}</h3>
1212
<div class="color-picker">
1313
<label class="custom-control custom-radio">
1414
<input id="color1" name="radio" type="radio" class="custom-control-input" (click)="color='orange'">
1515
<span class="custom-control-indicator"></span>
16-
<span class="custom-control-description">Orange</span>
16+
<span class="custom-control-description">{{ 'orange' | translate }}</span>
1717
</label>
1818
<label class="custom-control custom-radio">
1919
<input id="color2" name="radio" type="radio" class="custom-control-input" (click)="color='yellow'">
2020
<span class="custom-control-indicator"></span>
21-
<span class="custom-control-description">Yellow</span>
21+
<span class="custom-control-description">{{ 'yellow' | translate }}</span>
2222
</label>
2323
<label class="custom-control custom-radio">
2424
<input id="color3" name="radio" type="radio" class="custom-control-input" (click)="color='cyan'">
2525
<span class="custom-control-indicator"></span>
26-
<span class="custom-control-description">Cyan</span>
26+
<span class="custom-control-description">{{ 'cyan' | translate }}</span>
2727
</label>
2828
</div>
2929

@@ -51,18 +51,20 @@ <h3>Pick a highlight color</h3>
5151
<div class="modal-dialog" role="document">
5252
<div class="modal-content">
5353
<div class="modal-header">
54-
<h5 class="modal-title" id="exampleModalLabel">Alert</h5>
54+
<h5 class="modal-title" id="exampleModalLabel">{{ 'alert' | translate }}</h5>
5555
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
5656
<span aria-hidden="true">&times;</span>
5757
</button>
5858
</div>
5959
<div class="modal-body">
60-
Do you want to remove the hero?
60+
{{ 'sureRemoveHero' | translate}}
6161
</div>
6262
<div class="modal-footer">
63-
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
63+
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ 'cancel' |
64+
translate}}
65+
</button>
6466
<button type="button" class="btn btn-primary" (click)="remove()">
65-
Remove hero
67+
{{ 'remove' | translate}}
6668
</button>
6769
</div>
6870
</div>

src/app/heroes/hero-list/hero-list.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {IAppConfig} from '../../config/iapp.config';
66

77
import {Hero} from '../shared/hero.model';
88
import {HeroService} from '../shared/hero.service';
9-
declare const $:any;
9+
declare const $: any;
1010

1111
@Component({
1212
selector: 'toh-hero-list',

src/app/heroes/hero-search/hero-search.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<input id="search-box" type="text" class="form-control" placeholder="Find a hero!"
1+
<input id="search-box" type="text" class="form-control" placeholder="{{ 'findHero' | translate }}!"
22
[(ngModel)]="searchBox"
33
(keyup)="search()"
44
(focus)="showDropDown=true;"

src/app/heroes/hero-top/hero-top.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="container">
2-
<h3>Top Heroes</h3>
2+
<h3>{{ 'hero-top.title' | translate }}</h3>
33
<div class="row">
44
<div class="col" *ngFor="let hero of heroes" [routerLink]="['/heroes/', hero.id]">
55
<div class="card-block">

src/app/heroes/hero-top/hero-top.component.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
.card-block {
77
background-color: #808080;
88
color: white;
9-
border-radius: 10px;
9+
border-radius: 5px;
1010
cursor: pointer;
1111

1212
.card-title {

src/app/heroes/heroes.module.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import {NgModule} from '@angular/core';
2-
import {CommonModule} from '@angular/common';
3-
import {FormsModule} from '@angular/forms';
1+
import {NgModule} from '@angular/core';
2+
import {CommonModule} from '@angular/common';
3+
import {FormsModule} from '@angular/forms';
4+
import {Http} from '@angular/http';
5+
import {TranslateModule, TranslateLoader} from 'ng2-translate';
6+
import {TranslateLoaderFactory} from '../app.translate.factory';
47

58
import {HeroRoutingModule} from './heroes-routing.module';
69
import {SharedModule} from '../shared/shared.module';
@@ -16,6 +19,11 @@ import {HeroService} from './shared/hero.service';
1619
imports: [
1720
CommonModule,
1821
FormsModule,
22+
TranslateModule.forRoot({
23+
provide: TranslateLoader,
24+
useFactory: TranslateLoaderFactory,
25+
deps: [Http]
26+
}),
1927
SharedModule,
2028
HeroRoutingModule
2129
],

src/assets/i18n/en.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"home": "Home",
3+
"heroesList": "Heroes list",
4+
"tourOfHeroes": "Tour of heroes",
5+
"language": "Language",
6+
"english": "English",
7+
"spanish": "Spanish",
8+
"orange": "Orange",
9+
"yellow": "Yellow",
10+
"cyan": "Cyan",
11+
"name": "Name",
12+
"nameRequired": "Name is required",
13+
"hero-top": {
14+
"title": "Top Heroes"
15+
},
16+
"hero-create-new": {
17+
"newHero": "New hero"
18+
},
19+
"heroPower": "Hero power",
20+
"details": "details",
21+
"saveHero": "Save hero",
22+
"createNewHero": "Create new hero",
23+
"pickColor": "Pick a highlight color",
24+
"alert": "Alert",
25+
"sureRemoveHero": "Do you want to remove the hero?",
26+
"cancel": "Cancel",
27+
"remove": "Remove",
28+
"findHero": "Find a hero",
29+
"back": "Back"
30+
}

0 commit comments

Comments
 (0)