Skip to content
This repository was archived by the owner on Oct 1, 2018. It is now read-only.

Commit f0ec397

Browse files
Merge pull request #267 from IraErshova/feat-i18n-initialization
feat(i18n): Setup ngx-translate in rxjs-docs
2 parents 621c41d + 584e008 commit f0ec397

14 files changed

+269
-47
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
"@angular/platform-browser-dynamic": "5.2.2",
4141
"@angular/router": "5.2.2",
4242
"@angular/service-worker": "5.2.2",
43+
"@ngx-translate/core": "9.1.1",
44+
"@ngx-translate/http-loader": "2.0.1",
4345
"@types/hammerjs": "2.0.35",
4446
"core-js": "2.4.1",
4547
"hammerjs": "2.0.8",

src/app/app.component.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
[routerLinkActiveOptions]="menu.options"
1414
[routerLink]="menu.link"
1515
(click)="shouldOpenChildMenu(menu.title)">
16-
{{menu.title}}
16+
{{menu.title | translate}}
1717
</a>
1818
</mat-nav-list>
1919
</mat-sidenav>

src/app/app.component.spec.ts

+26-20
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,42 @@
1-
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { RouterTestingModule } from '@angular/router/testing';
33
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
4-
import { AppComponent } from './app.component';
54
import { MatSidenavModule, MatListModule } from '@angular/material';
5+
import { TranslateModule } from '@ngx-translate/core';
6+
7+
import { AppComponent } from './app.component';
68
import { CoreModule } from './core/core.module';
9+
import { LanguageService } from './core/services/language.service';
710

811
describe('AppComponent', () => {
912
let component: AppComponent;
1013
let fixture: ComponentFixture<AppComponent>;
11-
12-
beforeEach(
13-
async(() => {
14-
TestBed.configureTestingModule({
15-
imports: [
16-
RouterTestingModule,
17-
BrowserAnimationsModule,
18-
CoreModule.forRoot(),
19-
MatSidenavModule,
20-
MatListModule
21-
],
22-
declarations: [AppComponent]
23-
}).compileComponents();
24-
})
25-
);
14+
let languageService: LanguageService;
2615

2716
beforeEach(() => {
17+
TestBed.configureTestingModule({
18+
imports: [
19+
RouterTestingModule,
20+
BrowserAnimationsModule,
21+
CoreModule.forRoot(),
22+
MatSidenavModule,
23+
MatListModule,
24+
TranslateModule.forRoot()
25+
],
26+
declarations: [AppComponent],
27+
providers: [LanguageService]
28+
});
29+
2830
fixture = TestBed.createComponent(AppComponent);
2931
component = fixture.componentInstance;
30-
fixture.detectChanges();
32+
languageService = TestBed.get(LanguageService);
3133
});
3234

33-
it('should create', () => {
34-
expect(component).toBeTruthy();
35+
it('should init supported languages on initialization', () => {
36+
spyOn(languageService, 'init').and.stub();
37+
38+
fixture.detectChanges();
39+
40+
expect(languageService.init).toHaveBeenCalledWith(['en', 'ru']);
3541
});
3642
});

src/app/app.component.ts

+11-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { filter, map, mergeMap } from 'rxjs/operators';
99
import { SeoService, SeoData } from './core/services/seo.service';
1010
import { OperatorMenuService } from './core/services/operator-menu.service';
11+
import { LanguageService } from './core/services/language.service';
1112

1213
interface Menu {
1314
title: string;
@@ -23,22 +24,22 @@ interface Menu {
2324
export class AppComponent implements OnInit {
2425
menus: Menu[] = [
2526
{
26-
title: 'Home',
27+
title: 'MENU.HOME',
2728
link: '/',
2829
options: { exact: true }
2930
},
3031
{
31-
title: 'Operators',
32+
title: 'MENU.OPERATORS',
3233
link: '/operators',
3334
options: { exact: false }
3435
},
3536
{
36-
title: 'Companies',
37+
title: 'MENU.COMPANIES',
3738
link: '/companies',
3839
options: { exact: false }
3940
},
4041
{
41-
title: 'Team',
42+
title: 'MENU.TEAM',
4243
link: '/team',
4344
options: { exact: false }
4445
}
@@ -48,7 +49,8 @@ export class AppComponent implements OnInit {
4849
private _router: Router,
4950
private _activatedRoute: ActivatedRoute,
5051
private _seo: SeoService,
51-
private _operatorMenuService: OperatorMenuService
52+
private _operatorMenuService: OperatorMenuService,
53+
private languageService: LanguageService
5254
) {}
5355

5456
ngOnInit() {
@@ -67,11 +69,13 @@ export class AppComponent implements OnInit {
6769
filter((data: SeoData) => data.title !== undefined)
6870
)
6971
.subscribe((data: SeoData) => this._seo.setHeaders(data));
72+
73+
this.languageService.init(['en', 'ru']);
7074
}
7175

72-
shouldOpenChildMenu(title: string) {
76+
shouldOpenChildMenu(title: string): void {
7377
// for accessibility we need to ensure child menu is open when clicked
74-
if (title === 'Operators') {
78+
if (title === 'MENU.OPERATORS') {
7579
this._operatorMenuService.openOperatorMenu();
7680
}
7781
}

src/app/app.module.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import { NgModule } from '@angular/core';
22
import { BrowserModule } from '@angular/platform-browser';
3+
import { HttpClient, HttpClientModule } from '@angular/common/http';
34
import { ServiceWorkerModule } from '@angular/service-worker';
4-
import { MatSidenavModule, MatListModule } from '@angular/material';
55
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
66
import { FlexLayoutModule } from '@angular/flex-layout';
77

8+
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
9+
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
10+
811
import { environment } from '../environments/environment';
912
import { CoreModule } from '../app/core/core.module';
1013
import { MaterialModule } from './material/material.module';
1114
import { AppRoutingModule } from './app-routing.module';
12-
1315
import { AppComponent } from './app.component';
16+
import { LanguageService } from './core/services/language.service';
17+
18+
export function HttpLoaderFactory(http: HttpClient) {
19+
return new TranslateHttpLoader(http);
20+
}
1421

1522
@NgModule({
1623
declarations: [AppComponent],
@@ -23,8 +30,17 @@ import { AppComponent } from './app.component';
2330
FlexLayoutModule,
2431
MaterialModule,
2532
AppRoutingModule,
26-
CoreModule.forRoot()
33+
HttpClientModule,
34+
CoreModule.forRoot(),
35+
TranslateModule.forRoot({
36+
loader: {
37+
provide: TranslateLoader,
38+
useFactory: HttpLoaderFactory,
39+
deps: [HttpClient]
40+
}
41+
})
2742
],
43+
providers: [LanguageService],
2844
bootstrap: [AppComponent]
2945
})
3046
export class AppModule {}

src/app/core/components/toolbar/toolbar.component.html

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@
66
</button>
77
<span class="title" fxFlex> RxJS Docs </span>
88
<span class="title" fxFlex> WARNING: This is BETA site </span>
9-
<a aria-label="GitHub Repository" class="mat-button" href="https://github.com/ReactiveX" aria-disabled="false">
9+
<button mat-icon-button [matMenuTriggerFor]="appMenu">
10+
<mat-icon>language</mat-icon>
11+
</button>
12+
<mat-menu #appMenu="matMenu" [overlapTrigger]="false" xPosition="before">
13+
<button mat-menu-item *ngFor="let language of languagesList" (click)="onLangSwitch(language)">
14+
{{language.nativeName}}
15+
</button>
16+
</mat-menu>
17+
<a aria-label="GitHub Repository" target="_blank" class="mat-button" href="https://github.com/ReactiveX" aria-disabled="false">
1018
<span class="mat-button-wrapper">
1119
<img src="../../../assets/img/GitHub-Mark-Light-64px.png" alt="ReactiveX GitHub Repository"> GitHub
1220
</span>
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,52 @@
1-
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
33
import { RouterTestingModule } from '@angular/router/testing';
44

55
import { ToolbarComponent } from './toolbar.component';
66
import { MaterialModule } from '../../../material/material.module';
7+
import { LanguageService } from '../../services/language.service';
8+
import { TranslateModule } from '@ngx-translate/core';
9+
import { languagesList } from '../../data/language.data';
710

811
describe('ToolbarComponent', () => {
12+
const languages = languagesList;
913
let component: ToolbarComponent;
1014
let fixture: ComponentFixture<ToolbarComponent>;
11-
12-
beforeEach(
13-
async(() => {
14-
TestBed.configureTestingModule({
15-
imports: [MaterialModule, BrowserAnimationsModule, RouterTestingModule],
16-
declarations: [ToolbarComponent]
17-
}).compileComponents();
18-
})
19-
);
15+
let languageService: LanguageService;
2016

2117
beforeEach(() => {
18+
TestBed.configureTestingModule({
19+
imports: [
20+
MaterialModule,
21+
BrowserAnimationsModule,
22+
RouterTestingModule,
23+
TranslateModule.forRoot()
24+
],
25+
declarations: [ToolbarComponent],
26+
providers: [LanguageService]
27+
});
28+
29+
languageService = TestBed.get(LanguageService);
2230
fixture = TestBed.createComponent(ToolbarComponent);
2331
component = fixture.componentInstance;
32+
});
33+
34+
it('should set languagesList and currentLang on initialization', () => {
35+
spyOn(languageService, 'getLanguagesList').and.returnValue(languages);
36+
spyOn(languageService, 'getCurrentLang').and.returnValue(languages[1]);
37+
2438
fixture.detectChanges();
39+
40+
expect(component.languagesList).toEqual(languages);
41+
expect(component.currentLang).toEqual(languages[1]);
2542
});
2643

27-
it('should create', () => {
28-
expect(component).toBeTruthy();
44+
it('should change current language on onLangSwitch', () => {
45+
spyOn(languageService, 'saveLang').and.stub();
46+
47+
component.onLangSwitch(languages[1]);
48+
49+
expect(component.currentLang).toEqual(languages[1]);
50+
expect(languageService.saveLang).toHaveBeenCalledWith(languages[1]);
2951
});
3052
});
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
2+
import { Lang } from '../../models/language.model';
3+
import { LanguageService } from '../../services/language.service';
24

35
@Component({
46
selector: 'app-toolbar',
@@ -7,11 +9,22 @@ import { Component, OnInit, Output, EventEmitter } from '@angular/core';
79
})
810
export class ToolbarComponent implements OnInit {
911
@Output() navToggle = new EventEmitter<boolean>();
12+
currentLang: Lang;
13+
languagesList: Lang[];
14+
15+
constructor(private languageService: LanguageService) {}
16+
17+
ngOnInit() {
18+
this.languagesList = this.languageService.getLanguagesList();
19+
this.currentLang = this.languageService.getCurrentLang();
20+
}
21+
1022
navOpen() {
1123
this.navToggle.emit(true);
1224
}
1325

14-
constructor() {}
15-
16-
ngOnInit() {}
26+
onLangSwitch(lang: Lang): void {
27+
this.currentLang = lang;
28+
this.languageService.saveLang(lang);
29+
}
1730
}

src/app/core/data/language.data.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Lang } from '../models/language.model';
2+
3+
export const languagesList: Lang[] = [
4+
{
5+
code: 'en',
6+
name: 'English',
7+
nativeName: 'English'
8+
},
9+
{
10+
code: 'ru',
11+
name: 'Russian',
12+
nativeName: 'Русский'
13+
}
14+
];

src/app/core/models/language.model.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export interface Lang {
2+
code: string;
3+
name: string;
4+
nativeName: string;
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { TestBed } from '@angular/core/testing';
2+
import { TranslateModule, TranslateService } from '@ngx-translate/core';
3+
4+
import { languagesList } from '../data/language.data';
5+
import { LanguageService } from './language.service';
6+
7+
describe('LanguageService', () => {
8+
const languages = languagesList;
9+
let languageService: LanguageService;
10+
let translateService: TranslateService;
11+
12+
beforeEach(() => {
13+
TestBed.configureTestingModule({
14+
imports: [TranslateModule.forRoot()],
15+
providers: [LanguageService]
16+
});
17+
18+
languageService = TestBed.get(LanguageService);
19+
translateService = TestBed.get(TranslateService);
20+
21+
window.localStorage.removeItem('current_lang');
22+
});
23+
24+
it('should set fullLangList on initialization', () => {
25+
expect(languageService.fullLangList).toEqual(languages);
26+
});
27+
28+
it('should set the using language and default language on init', () => {
29+
spyOn(translateService, 'getBrowserLang').and.returnValue('en');
30+
spyOn(translateService, 'use').and.stub();
31+
32+
languageService.init(['en', 'ru']);
33+
34+
expect(translateService.use).toHaveBeenCalledWith('en');
35+
});
36+
37+
it('should get language list on getLanguagesList', () => {
38+
spyOn(translateService, 'getLangs').and.returnValue(['en', 'ru']);
39+
40+
languageService.getLanguagesList();
41+
42+
expect(languageService.fullLangList).toEqual(languages);
43+
});
44+
45+
it('should get current language on getCurrentLang', () => {
46+
spyOn(languageService, 'getLanguagesList').and.returnValue(languages);
47+
translateService.currentLang = 'ru';
48+
49+
const result = languageService.getCurrentLang();
50+
51+
expect(result).toEqual({
52+
code: 'ru',
53+
name: 'Russian',
54+
nativeName: 'Русский'
55+
});
56+
});
57+
58+
it('should save language on saveLang', () => {
59+
spyOn(translateService, 'use').and.stub();
60+
61+
languageService.saveLang(languages[1]);
62+
63+
expect(translateService.use).toHaveBeenCalledWith(languages[1].code);
64+
});
65+
});

0 commit comments

Comments
 (0)