Commit f082feed3feb02387c2eea02f0c839653ad4270c

Authored by Victor Costa
1 parent c0ec34f9

Refactor language component

src/app/components/language-selector/language-selector.component.spec.ts
... ... @@ -11,69 +11,28 @@ describe("Components", () => {
11 11  
12 12 beforeEach(angular.mock.module("templates"));
13 13  
  14 + let languageService: any;
  15 +
14 16 let buildComponent = (): Promise<ComponentFixture> => {
  17 + languageService = jasmine.createSpyObj("languageService", ["availableLanguages", "currentLanguage"])
15 18 return helpers.quickCreateComponent({
16 19 template: "<language-selector></language-selector>",
17 20 directives: [LanguageSelector],
18 21 providers: [
19   - provide('$translate', {
20   - useValue: helpers.mocks.$translate
21   - }),
22   - provide('tmhDynamicLocale', {
23   - useValue: helpers.mocks.tmhDynamicLocale
24   - }),
25   - provide('amMoment', {
26   - useValue: helpers.mocks.amMoment
27   - }),
28   - provide('angularLoad', {
29   - useValue: helpers.mocks.angularLoad
  22 + provide('LanguageService', {
  23 + useValue: languageService
30 24 })
31 25 ].concat(helpers.provideFilters("translateFilter"))
32 26 });
33 27 }
34 28  
35   - it("set available languages when change language", (done) => {
36   - let component: LanguageSelector = new LanguageSelector(
37   - <any>helpers.mocks.$translate,
38   - <any>helpers.mocks.tmhDynamicLocale,
39   - <any>helpers.mocks.amMoment,
40   - <any>helpers.mocks.angularLoad
41   - );
42   - component.availableLanguages = null;
43   - expect(component.availableLanguages).toBeNull();
44   - component.changeLanguage('en');
45   - expect(component.availableLanguages).toBeDefined();
46   - done();
47   - });
48   -
49 29 it("display language options", (done) => {
50 30 buildComponent().then(fixture => {
  31 + fixture.debugElement.getLocal("$rootScope").$apply();
51 32 expect(fixture.debugElement.queryAll('li.language').length).toEqual(2);
52 33 done();
53 34 });
54 35 });
55 36  
56   - it("change the language", (done) => {
57   - buildComponent().then(fixture => {
58   - let component: LanguageSelector = fixture.debugElement.componentViewChildren[0].componentInstance;
59   - let $q = fixture.debugElement.getLocal("$q");
60   - let loadScripPromise = $q.defer();
61   - loadScripPromise.resolve();
62   - component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue(loadScripPromise.promise);
63   - component["tmhDynamicLocale"].set = jasmine.createSpy("set");
64   - component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue("en");
65   - component["$translate"].use = jasmine.createSpy("use");
66   -
67   - component.changeLanguage('pt');
68   - fixture.debugElement.getLocal("$rootScope").$digest();
69   -
70   - expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");
71   - expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/messageformat/locale/pt.js");
72   - expect(component["tmhDynamicLocale"].set).toHaveBeenCalledWith("pt");
73   - expect(component["$translate"].use).toHaveBeenCalledWith("pt");
74   - done();
75   - });
76   - });
77   -
78 37 });
79 38 });
... ...
src/app/components/language-selector/language-selector.component.ts
1 1 import {Component, Inject} from "ng-forward";
  2 +import {LanguageService} from "./language.service";
2 3  
3 4 @Component({
4 5 selector: "language-selector",
5 6 templateUrl: "app/components/language-selector/language-selector.html"
6 7 })
7   -@Inject("$translate", "tmhDynamicLocale", "amMoment", "angularLoad")
  8 +@Inject(LanguageService)
8 9 export class LanguageSelector {
9 10  
10   - availableLanguages: any;
11   -
12   - constructor(private $translate: angular.translate.ITranslateService,
13   - private tmhDynamicLocale: any,
14   - private amMoment: any,
15   - private angularLoad: any) {
16   -
17   - this.configAvailableLanguages();
18   - this.changeLanguage(tmhDynamicLocale.get() || $translate.use());
19   - }
  11 + constructor(private languageService: LanguageService) { }
20 12  
21 13 currentLanguage() {
22   - return this.$translate.use();
  14 + return this.languageService.currentLanguage();
23 15 }
24 16  
25 17 changeLanguage(language: string) {
26   - this.changeMomentLocale(language);
27   - this.tmhDynamicLocale.set(language);
28   - this.angularLoad.loadScript(`/bower_components/messageformat/locale/${language}.js`).then(() => {
29   - return this.$translate.use(language);
30   - }).then(() => {
31   - this.configAvailableLanguages();
32   - });
33   - }
34   -
35   - private configAvailableLanguages() {
36   - this.availableLanguages = {
37   - "en": this.$translate.instant("language.en"),
38   - "pt": this.$translate.instant("language.pt")
39   - };
  18 + this.languageService.changeLanguage(language);
40 19 }
41 20  
42   - private changeMomentLocale(language: string) {
43   - let localePromise = Promise.resolve();
44   - if (language != "en") {
45   - localePromise = this.angularLoad.loadScript(`/bower_components/moment/locale/${language}.js`);
46   - }
47   - localePromise.then(() => {
48   - this.amMoment.changeLocale(language);
49   - });
  21 + availableLanguages() {
  22 + return this.languageService.availableLanguages;
50 23 }
51 24 }
... ...
src/app/components/language-selector/language-selector.html
... ... @@ -3,7 +3,7 @@
3 3 <span>{{"language.selector" | translate}}</span> <b class="caret"></b>
4 4 </a>
5 5 <ul class="dropdown-menu" dropdown-menu>
6   - <li ng-repeat="(language, description) in ctrl.availableLanguages"
  6 + <li ng-repeat="(language, description) in ctrl.availableLanguages()"
7 7 class="language language-{{language}}" ng-class="{'active': language==ctrl.currentLanguage()}">
8 8 <a href="#" ng-click="ctrl.changeLanguage(language)">
9 9 {{description}}
... ...
src/app/components/language-selector/language.service.spec.ts 0 → 100644
... ... @@ -0,0 +1,61 @@
  1 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {provide} from 'ng-forward';
  3 +
  4 +import {LanguageService} from './language.service';
  5 +
  6 +import * as helpers from "../../../spec/helpers";
  7 +
  8 +describe("Services", () => {
  9 +
  10 + describe("Language Service", () => {
  11 +
  12 + let $rootScope: ng.IScope;
  13 + let $q: ng.IQService;
  14 +
  15 + beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {
  16 + $rootScope = _$rootScope_;
  17 + $q = _$q_;
  18 + }));
  19 +
  20 + it("set available languages when change language", (done) => {
  21 + let component: LanguageService = new LanguageService(
  22 + <any>helpers.mocks.$translate,
  23 + <any>helpers.mocks.tmhDynamicLocale,
  24 + <any>helpers.mocks.amMoment,
  25 + <any>helpers.mocks.angularLoad,
  26 + helpers.mocks.scopeWithEvents
  27 + );
  28 + component.availableLanguages = null;
  29 + expect(component.availableLanguages).toBeNull();
  30 + component.changeLanguage('en');
  31 + expect(component.availableLanguages).toBeDefined();
  32 + done();
  33 + });
  34 +
  35 + it("change the language", (done) => {
  36 + let component: LanguageService = new LanguageService(
  37 + <any>helpers.mocks.$translate,
  38 + <any>helpers.mocks.tmhDynamicLocale,
  39 + <any>helpers.mocks.amMoment,
  40 + <any>helpers.mocks.angularLoad,
  41 + helpers.mocks.scopeWithEvents
  42 + );
  43 + let loadScripPromise = $q.defer();
  44 + loadScripPromise.resolve();
  45 + component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue(loadScripPromise.promise);
  46 + component["tmhDynamicLocale"].set = jasmine.createSpy("set");
  47 + component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue("en");
  48 + component["$translate"].use = jasmine.createSpy("use");
  49 +
  50 + component.changeLanguage('pt');
  51 + $rootScope.$digest();
  52 +
  53 + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");
  54 + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/messageformat/locale/pt.js");
  55 + expect(component["tmhDynamicLocale"].set).toHaveBeenCalledWith("pt");
  56 + expect(component["$translate"].use).toHaveBeenCalledWith("pt");
  57 + done();
  58 + });
  59 +
  60 + });
  61 +});
... ...
src/app/components/language-selector/language.service.ts 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +
  3 +@Injectable()
  4 +@Inject("$translate", "tmhDynamicLocale", "amMoment", "angularLoad", "$rootScope")
  5 +export class LanguageService {
  6 +
  7 + availableLanguages: any;
  8 +
  9 + constructor(private $translate: angular.translate.ITranslateService,
  10 + private tmhDynamicLocale: angular.dynamicLocale.tmhDynamicLocaleService,
  11 + private amMoment: any,
  12 + private angularLoad: any,
  13 + private $rootScope: any) {
  14 +
  15 + this.configAvailableLanguages();
  16 + this.$rootScope.$on("$localeChangeSuccess", () => {
  17 + this.changeLanguage(tmhDynamicLocale.get() || $translate.use());
  18 + });
  19 + }
  20 +
  21 + currentLanguage() {
  22 + return this.$translate.use();
  23 + }
  24 +
  25 + changeLanguage(language: string) {
  26 + if (!language) {
  27 + console.log("WARN: language undefined");
  28 + return;
  29 + }
  30 + this.changeMomentLocale(language);
  31 + this.tmhDynamicLocale.set(language);
  32 + this.angularLoad.loadScript(`/bower_components/messageformat/locale/${language}.js`).then(() => {
  33 + return this.$translate.use(language);
  34 + }).then(() => {
  35 + this.configAvailableLanguages();
  36 + });
  37 + }
  38 +
  39 + translate(text: string) {
  40 + return this.$translate.instant(text);
  41 + }
  42 +
  43 + private configAvailableLanguages() {
  44 + this.availableLanguages = {
  45 + "en": this.$translate.instant("language.en"),
  46 + "pt": this.$translate.instant("language.pt")
  47 + };
  48 + }
  49 +
  50 + private changeMomentLocale(language: string) {
  51 + let localePromise = Promise.resolve();
  52 + if (language != "en") {
  53 + localePromise = this.angularLoad.loadScript(`/bower_components/moment/locale/${language}.js`);
  54 + }
  55 + localePromise.then(() => {
  56 + this.amMoment.changeLocale(language);
  57 + });
  58 + }
  59 +}
... ...
src/app/components/notification/notification.component.spec.ts
... ... @@ -13,12 +13,12 @@ describe(&quot;Components&quot;, () =&gt; {
13 13  
14 14 beforeEach(angular.mock.module("templates"));
15 15  
16   - it("use the default message when call notification component without a specific message", done => {
  16 + it("use the default message when call notification component without a message", done => {
17 17 let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
18 18 sweetAlert.swal = jasmine.createSpy("swal");
19 19  
20   - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate);
21   - component.httpError(500, {});
  20 + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.languageService);
  21 + component.error();
22 22 expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
23 23 text: Notification.DEFAULT_ERROR_MESSAGE,
24 24 type: "error"
... ... @@ -26,27 +26,26 @@ describe(&quot;Components&quot;, () =&gt; {
26 26 done();
27 27 });
28 28  
29   - it("use the default message when call notification component without error data", done => {
  29 + it("display a success message when call notification success", done => {
30 30 let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
31 31 sweetAlert.swal = jasmine.createSpy("swal");
32 32  
33   - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate);
34   - component.httpError(500, null);
  33 + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.languageService);
  34 + component.success("title", "message", 1000);
35 35 expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
36   - text: Notification.DEFAULT_ERROR_MESSAGE,
37   - type: "error"
  36 + type: "success"
38 37 }));
39 38 done();
40 39 });
41 40  
42   - it("display a success message when call notification success", done => {
  41 + it("display a message relative to the http error code", done => {
43 42 let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
44 43 sweetAlert.swal = jasmine.createSpy("swal");
45 44  
46   - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate);
47   - component.success("title", "message", 1000);
  45 + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.languageService);
  46 + component.httpError(500, {});
48 47 expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
49   - type: "success"
  48 + text: "notification.http_error.500.message"
50 49 }));
51 50 done();
52 51 });
... ... @@ -55,7 +54,7 @@ describe(&quot;Components&quot;, () =&gt; {
55 54 let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
56 55 sweetAlert.swal = jasmine.createSpy("swal");
57 56  
58   - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate);
  57 + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.languageService);
59 58 component.success("title", "message");
60 59 expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
61 60 type: "success",
... ...
src/app/components/notification/notification.component.ts
1 1 import {Injectable, Inject} from "ng-forward";
  2 +import {LanguageService} from "../language-selector/language.service";
2 3  
3 4 @Injectable()
4   -@Inject("$log", "SweetAlert", "$translate")
  5 +@Inject("$log", "SweetAlert", LanguageService)
5 6 export class Notification {
6 7  
7 8 constructor(
8 9 private $log: ng.ILogService,
9 10 private SweetAlert: any,
10   - private $translate: angular.translate.ITranslateService
  11 + private languageService: LanguageService
11 12 ) { }
12 13  
13 14 public static DEFAULT_ERROR_TITLE = "notification.error.default.title";
... ... @@ -15,16 +16,15 @@ export class Notification {
15 16 public static DEFAULT_SUCCESS_TIMER = 1000;
16 17  
17 18 error(message: string = Notification.DEFAULT_ERROR_MESSAGE, title: string = Notification.DEFAULT_ERROR_TITLE) {
18   - this.$log.debug("Notification error:", title, message);
  19 + this.$log.debug("Notification error:", title, message, this.languageService.currentLanguage());
19 20 this.SweetAlert.swal({
20   - title: this.$translate.instant(title),
21   - text: this.$translate.instant(message),
  21 + title: this.languageService.translate(title),
  22 + text: this.languageService.translate(message),
22 23 type: "error"
23 24 });
24 25 }
25 26  
26 27 httpError(status: number, data: any): boolean {
27   - let message = (data || {}).message || Notification.DEFAULT_ERROR_MESSAGE;
28 28 this.error(`notification.http_error.${status}.message`);
29 29 return true; // return true to indicate that the error was already handled
30 30 }
... ...
src/spec/mocks.ts
... ... @@ -6,13 +6,11 @@ class ScopeWithEvents {
6 6 }
7 7  
8 8 public $on(eventName: string, func: Function) {
9   - console.log(this.listeners);
10 9 if ((<any>this.listeners)[eventName]) {
11 10 (<any>this.listeners)[eventName].push(func);
12 11 } else {
13 12 (<any>this.listeners)[eventName] = [func];
14 13 }
15   - console.log(this.listeners);
16 14 }
17 15  
18 16 public $emit(message: string, arg?: any) {
... ... @@ -97,5 +95,10 @@ export var mocks = {
97 95 },
98 96 $log: {
99 97 debug: () => { }
  98 + },
  99 + languageService: {
  100 + currentLanguage: () => { },
  101 + changeLanguage: (lang: string) => { },
  102 + translate: (text: string) => { return text }
100 103 }
101 104 };
... ...
typings.json
... ... @@ -4,6 +4,7 @@
4 4 "devDependencies": {},
5 5 "ambientDependencies": {
6 6 "angular": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#1c4a34873c9e70cce86edd0e61c559e43dfa5f75",
  7 + "angular-dynamic-locale": "github:DefinitelyTyped/DefinitelyTyped/angular-dynamic-locale/angular-dynamic-locale.d.ts#42ab06c354ccbadeafa60df1efc76b81a22809b1",
7 8 "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts",
8 9 "angular-translate": "github:DefinitelyTyped/DefinitelyTyped/angular-translate/angular-translate.d.ts#19850bf86c876e0c2544842114878ece4664941a",
9 10 "angular-ui-router": "github:DefinitelyTyped/DefinitelyTyped/angular-ui-router/angular-ui-router.d.ts#655f8c1bf3c71b0e1ba415b36309604f79326ac8",
... ...