From a80ef7c03c9deee39ef9599e6ed0b26f07299f01 Mon Sep 17 00:00:00 2001 From: Thomas Flori Date: Mon, 20 Mar 2017 08:46:16 +0100 Subject: [PATCH 1/2] use a single configuration --- bundles/angular2-translator.js | 2 +- src/TranslateConfig.ts | 29 ++++++++++++---- src/TranslateLoader.ts | 12 ++----- src/TranslateLoaderJson.ts | 46 +++++++++++++------------- src/TranslateService.ts | 39 +++++++++++----------- src/TranslatorModule.ts | 6 ++-- tests/TranslateLoaderJson.spec.ts | 41 ----------------------- tests/TranslateLogHandler.spec.ts | 14 ++++++++ tests/TranslatePipe.spec.ts | 10 +++--- tests/TranslateService.spec.ts | 55 ++++++++++++++++--------------- tests/helper/TranslatorMocks.ts | 18 ++++++++++ 11 files changed, 135 insertions(+), 137 deletions(-) create mode 100644 tests/TranslateLogHandler.spec.ts create mode 100644 tests/helper/TranslatorMocks.ts diff --git a/bundles/angular2-translator.js b/bundles/angular2-translator.js index ee5cfe8..e27ee75 100644 --- a/bundles/angular2-translator.js +++ b/bundles/angular2-translator.js @@ -1,2 +1,2 @@ -!function(a){function b(a){Object.defineProperty(this,a,{enumerable:!0,get:function(){return this[o][a]}})}function c(a){var b;if(a&&a.__esModule){b={};for(var c in a)Object.hasOwnProperty.call(a,c)&&(b[c]=a[c]);b.__useDefault&&delete b.__useDefault,b.__esModule=!0}else{if("[object Module]"===Object.prototype.toString.call(a)||"undefined"!=typeof System&&System.isModule&&System.isModule(a))return a;b={default:a,__useDefault:!0}}return new d(b)}function d(a){Object.defineProperty(this,o,{value:a}),Object.keys(a).forEach(b,this)}function e(a){return"@node/"===a.substr(0,6)?m(a,c(p(a.substr(6))),{}):n[a]}function f(a){var b=e(a);if(!b)throw new Error('Module "'+a+'" expected, but not contained in build.');if(b.module)return b.module;var c=b.linkRecord;return g(b,c),l(b,c,[]),b.module}function g(a,b){if(!b.depLoads){b.declare&&h(a,b),b.depLoads=[];for(var c=0;c1)for(var l=1;l=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g}),e=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},f=b&&b.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(b,"__esModule",{value:!0});var g=a("c"),h=a("d"),i=function(){function a(a){var b=this;this.translation="",this._params={},this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return Object.defineProperty(a.prototype,"key",{set:function(a){this._key=a,this._startTranslation()},enumerable:!0,configurable:!0}),Object.defineProperty(a.prototype,"params",{set:function(a){if("object"!=typeof a)return void this._translate.logHandler.error("Params have to be an object");this._params=a,this._startTranslation()},enumerable:!0,configurable:!0}),a.prototype._startTranslation=function(){var a=this;this._key&&this._translate.translate(this._key,this._params).then(function(b){return a.translation=String(b)})},a}();d([h.Input("translate"),e("design:type",String),e("design:paramtypes",[String])],i.prototype,"key",null),d([h.Input("translateParams"),e("design:type",Object),e("design:paramtypes",[Object])],i.prototype,"params",null),i=d([h.Component({selector:"[translate]",template:"{{translation}}"}),f(0,h.Inject(g.TranslateService)),e("design:paramtypes",[g.TranslateService])],i),b.TranslateComponent=i}),$__System.registerDynamic("e",["f","d","10"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__extends||function(){var a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,b){a.__proto__=b}||function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])};return function(b,c){function d(){this.constructor=b}a(b,c),b.prototype=null===c?Object.create(c):(d.prototype=c.prototype,new d)}}()),e=b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},f=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},g=b&&b.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(b,"__esModule",{value:!0});var h=a("f"),i=a("d"),j=a("10"),k=function(){function a(a,b){this.path="assets/i18n/",this.extension=".json",a&&(this.path=a.replace(/\/+$/,"")+"/"),b&&(this.extension=b)}return a}();b.TranslateLoaderJsonConfig=k;var l=function(a){function b(b,c){var d=a.call(this)||this;return d._http=b,d._config=c,d}return d(b,a),b.prototype.load=function(a){var b=this;return new Promise(function(c,d){var e=b._config.path+a+b._config.extension;b._http.get(e).subscribe(function(a){if(200===a.status){var e={};b.flattenTranslations(e,a.json()),c(e)}else d("StatusCode: "+a.status)},function(a){d(a.message)})})},b.prototype.flattenTranslations=function(a,b,c){void 0===c&&(c="");for(var d in b)Array.isArray(b[d])?a[c+d]=b[d].filter(function(a){return"string"==typeof a}).join(""):"object"==typeof b[d]?this.flattenTranslations(a,b[d],c+d+"."):"string"==typeof b[d]&&(a[c+d]=b[d])},b}(h.TranslateLoader);l=e([i.Injectable(),g(0,i.Inject(j.Http)),g(1,i.Inject(k)),f("design:paramtypes",[j.Http,k])],l),b.TranslateLoaderJson=l}),$__System.registerDynamic("11",["c","d"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},__param=exports&&exports.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateService_1=$__require("c"),core_1=$__require("d"),TranslatePipe=TranslatePipe_1=function(){function TranslatePipe(a){var b=this;this._translation="",this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return TranslatePipe._parseParams=function(arg){try{var o=eval("("+arg+")");if("object"==typeof o)return o}catch(a){}return{}},TranslatePipe.prototype.transform=function(a,b){void 0===b&&(b=[]);var c={};return b[0]&&("string"==typeof b[0]?(c=TranslatePipe_1._parseParams(b[0]),Object.keys(c).length||this._translate.logHandler.error("'"+b[0]+"' could not be parsed to object")):"object"==typeof b[0]&&(c=b[0])),this._translated&&this._promise&&(this._translated.key!==a||JSON.stringify(this._translated.params)!==JSON.stringify(c))&&(this._promise=null),this._promise||(this._translated={key:a,params:c},this._startTranslation()),this._translation},TranslatePipe.prototype._startTranslation=function(){var a=this;this._translated&&this._translated.key&&(this._promise=this._translate.translate(this._translated.key,this._translated.params),this._promise.then(function(b){return a._translation=String(b)}))},TranslatePipe}();TranslatePipe=TranslatePipe_1=__decorate([core_1.Pipe({name:"translate",pure:!1}),__param(0,core_1.Inject(TranslateService_1.TranslateService)),__metadata("design:paramtypes",[TranslateService_1.TranslateService])],TranslatePipe),exports.TranslatePipe=TranslatePipe;var TranslatePipe_1}),$__System.registerDynamic("12",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(b){var c=b.defaultLang,d=void 0===c?"en":c,e=b.providedLangs,f=void 0===e?["en"]:e,g=b.detectLanguageOnStart,h=void 0===g||g;this.defaultLang=f.indexOf(d)>-1?d:f[0],this.providedLangs=f,this.detectLanguageOnStart=h,this.navigatorLanguages=function(){var b=a.navigator;return b.languages instanceof Array?Array.prototype.slice.call(b.languages):[b.languages||b.language||b.browserLanguage||b.userLanguage].filter(function(a){return"string"==typeof a})}()}return a.prototype.langProvided=function(a,b){void 0===b&&(b=!1);var c,d=!1,e=function(a){var b=/^([A-Za-z]{2})(?:[\.\-_\/]?([A-Za-z]{2}))?$/;return a.match(b)?a.replace(b,function(a,b,c){return void 0===c&&(c=""),b=b.toLowerCase(),c=c.toUpperCase(),c?b+"-"+c:b}):""},f=this.providedLangs.map(e);return a=e(a),0===a.length?d:(c=f.indexOf(a),c>-1?d=this.providedLangs[c]:b||(a=a.substr(0,2),c=f.indexOf(a),c>-1?d=this.providedLangs[c]:(c=f.map(function(a){return a.substr(0,2)}).indexOf(a),c>-1&&(d=this.providedLangs[c]))),d)},a}();d.navigator=window&&window.navigator?window.navigator:{},b.TranslateConfig=d}),$__System.registerDynamic("f",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a}();b.TranslateLoader=d}),$__System.registerDynamic("13",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a.prototype.error=function(a){console&&console.error&&console.error(a)},a.prototype.info=function(a){},a.prototype.debug=function(a){},a}();b.TranslateLogHandler=d}),$__System.registerDynamic("c",["12","f","13","d","14","15"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},__param=exports&&exports.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateConfig_1=$__require("12"),TranslateLoader_1=$__require("f"),TranslateLogHandler_1=$__require("13"),core_1=$__require("d"),Observable_1=$__require("14");$__require("15");var TranslateService=function(){function TranslateService(a,b,c){var d=this;if(this._loadedLangs={},this._translations={},this._config=a,this._loader=b,this.logHandler=c,this._lang=a.defaultLang,a.detectLanguageOnStart){var e=this.detectLang(a.navigatorLanguages);e&&(this._lang=String(e),c.info("Language "+e+" got detected"))}this.languageChanged=new Observable_1.Observable(function(a){return d._languageChangedObserver=a}).share()}return Object.defineProperty(TranslateService.prototype,"lang",{get:function(){return this._lang},set:function(a){var b=this._config.langProvided(a,!0);if("string"==typeof b)return this._lang=b,this.logHandler.info("Language changed to "+b),void(this._languageChangedObserver&&this._languageChangedObserver.next(this._lang));throw new Error("Language not provided")},enumerable:!0,configurable:!0}),TranslateService.prototype.detectLang=function(a){var b,c=!1;for(b=0;b0)return this.logHandler.error("Parse error only first parameter can be passed as params in '"+a+"'"),"";j="wait_getter"}break;case"read_param_key":if(b[e].match(/[A-Za-z0-9_]/))g+=b[e];else if("="===b[e])j="wait_getter";else if(","===b[e])l(!1),j="wait_param";else{if(!b[e].match(/\s/))return this._referencedError(a,"character","comma, equal sign or end",e);j="param_key_readed"}break;case"param_key_readed":if(b[e].match(/\s/));else if("="===b[e])j="wait_getter";else{if(","!==b[e])return this._referencedError(a,"character","comma, equal sign or end",e);l(!1),j="wait_param"}break;case"wait_getter":if(b[e].match(/\s/));else{if(!b[e].match(/[A-Za-z0-9_]/))return this._referencedError(a,"character","getter",e);j="read_getter",h=b[e]}break;case"read_getter":if(b[e].match(/[A-Za-z0-9_.]/))h+=b[e];else if(b[e].match(/\s/))j="getter_readed";else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}break;case"getter_readed":if(b[e].match(/\s/));else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}}switch(j){case"param_key_readed":case"read_param_key":l(!1);break;case"getter_readed":case"read_getter":l();break;case"wait_key":return this._referencedError(a,"end","key");case"wait_param":return this._referencedError(a,"end","parameter");case"wait_getter":return this._referencedError(a,"end","getter")}return String(this.instant(f,k,d))},TranslateService}();TranslateService=__decorate([core_1.Injectable(),__param(0,core_1.Inject(TranslateConfig_1.TranslateConfig)),__param(1,core_1.Inject(TranslateLoader_1.TranslateLoader)),__param(2,core_1.Inject(TranslateLogHandler_1.TranslateLogHandler)),__metadata("design:paramtypes",[TranslateConfig_1.TranslateConfig,TranslateLoader_1.TranslateLoader,TranslateLogHandler_1.TranslateLogHandler])],TranslateService),exports.TranslateService=TranslateService}),$__System.registerDynamic("16",["b","12","f","e","11","13","c","d","10"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g});Object.defineProperty(b,"__esModule",{value:!0});var e=a("b"),f=a("12"),g=a("f"),h=a("e"),i=a("11"),j=a("13"),k=a("c"),l=a("d"),m=a("10"),n=function(){function a(){}return a}();n=d([l.NgModule({declarations:[i.TranslatePipe,e.TranslateComponent],exports:[i.TranslatePipe,e.TranslateComponent],imports:[m.HttpModule],providers:[{provide:f.TranslateConfig,useValue:new f.TranslateConfig({})},{provide:h.TranslateLoaderJsonConfig,useValue:new h.TranslateLoaderJsonConfig},{provide:g.TranslateLoader,useClass:h.TranslateLoaderJson},{provide:j.TranslateLogHandler,useClass:j.TranslateLogHandler},k.TranslateService]})],n),b.TranslatorModule=n,b.TRANSLATE_PROVIDERS=[{provide:f.TranslateConfig,useValue:new f.TranslateConfig({})},{provide:h.TranslateLoaderJsonConfig,useValue:new h.TranslateLoaderJsonConfig},{provide:g.TranslateLoader,useClass:h.TranslateLoaderJson},{provide:j.TranslateLogHandler,useValue:j.TranslateLogHandler},k.TranslateService]}),$__System.registerDynamic("a",["c","11","b","12","f","e","13","16"],!0,function(a,b,c){"use strict";function d(a){for(var c in a)b.hasOwnProperty(c)||(b[c]=a[c])}this||self;Object.defineProperty(b,"__esModule",{value:!0}),d(a("c")),d(a("11")),d(a("b")),d(a("12")),d(a("f")),d(a("e")),d(a("13")),d(a("16"))})})(function(a){if("function"==typeof define&&define.amd)define(["@angular/core","@angular/http","rxjs/Observable","rxjs/add/operator/share"],a);else{if("object"!=typeof module||!module.exports||"function"!=typeof require)throw new Error("Module must be loaded as AMD or CommonJS");module.exports=a(require("@angular/core"),require("@angular/http"),require("rxjs/Observable"),require("rxjs/add/operator/share"))}}); +!function(a){function b(a){Object.defineProperty(this,a,{enumerable:!0,get:function(){return this[o][a]}})}function c(a){var b;if(a&&a.__esModule){b={};for(var c in a)Object.hasOwnProperty.call(a,c)&&(b[c]=a[c]);b.__useDefault&&delete b.__useDefault,b.__esModule=!0}else{if("[object Module]"===Object.prototype.toString.call(a)||"undefined"!=typeof System&&System.isModule&&System.isModule(a))return a;b={default:a,__useDefault:!0}}return new d(b)}function d(a){Object.defineProperty(this,o,{value:a}),Object.keys(a).forEach(b,this)}function e(a){return"@node/"===a.substr(0,6)?m(a,c(p(a.substr(6))),{}):n[a]}function f(a){var b=e(a);if(!b)throw new Error('Module "'+a+'" expected, but not contained in build.');if(b.module)return b.module;var c=b.linkRecord;return g(b,c),l(b,c,[]),b.module}function g(a,b){if(!b.depLoads){b.declare&&h(a,b),b.depLoads=[];for(var c=0;c1)for(var l=1;l=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g}),e=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},f=b&&b.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(b,"__esModule",{value:!0});var g=a("c"),h=a("d"),i=function(){function a(a){var b=this;this.translation="",this._params={},this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return Object.defineProperty(a.prototype,"key",{set:function(a){this._key=a,this._startTranslation()},enumerable:!0,configurable:!0}),Object.defineProperty(a.prototype,"params",{set:function(a){if("object"!=typeof a)return void this._translate.logHandler.error("Params have to be an object");this._params=a,this._startTranslation()},enumerable:!0,configurable:!0}),a.prototype._startTranslation=function(){var a=this;this._key&&this._translate.translate(this._key,this._params).then(function(b){return a.translation=String(b)})},a}();d([h.Input("translate"),e("design:type",String),e("design:paramtypes",[String])],i.prototype,"key",null),d([h.Input("translateParams"),e("design:type",Object),e("design:paramtypes",[Object])],i.prototype,"params",null),i=d([h.Component({selector:"[translate]",template:"{{translation}}"}),f(0,h.Inject(g.TranslateService)),e("design:paramtypes",[g.TranslateService])],i),b.TranslateComponent=i}),$__System.registerDynamic("e",["f","d","10"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__extends||function(){var a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,b){a.__proto__=b}||function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])};return function(b,c){function d(){this.constructor=b}a(b,c),b.prototype=null===c?Object.create(c):(d.prototype=c.prototype,new d)}}()),e=b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},f=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},g=b&&b.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(b,"__esModule",{value:!0});var h=a("f"),i=a("d"),j=a("10"),k=function(){function a(a,b){this.path="assets/i18n/",this.extension=".json",a&&(this.path=a.replace(/\/+$/,"")+"/"),b&&(this.extension=b)}return a}();b.TranslateLoaderJsonConfig=k;var l=function(a){function b(b,c){var d=a.call(this)||this;return d._http=b,d._config=c,d}return d(b,a),b.prototype.load=function(a){var b=this;return new Promise(function(c,d){var e=b._config.path+a+b._config.extension;b._http.get(e).subscribe(function(a){if(200===a.status){var e={};b.flattenTranslations(e,a.json()),c(e)}else d("StatusCode: "+a.status)},function(a){d(a.message)})})},b.prototype.flattenTranslations=function(a,b,c){void 0===c&&(c="");for(var d in b)Array.isArray(b[d])?a[c+d]=b[d].filter(function(a){return"string"==typeof a}).join(""):"object"==typeof b[d]?this.flattenTranslations(a,b[d],c+d+"."):"string"==typeof b[d]&&(a[c+d]=b[d])},b}(h.TranslateLoader);l=e([i.Injectable(),g(0,i.Inject(j.Http)),g(1,i.Inject(k)),f("design:paramtypes",[j.Http,k])],l),b.TranslateLoaderJson=l}),$__System.registerDynamic("11",["c","d"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},__param=exports&&exports.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateService_1=$__require("c"),core_1=$__require("d"),TranslatePipe=TranslatePipe_1=function(){function TranslatePipe(a){var b=this;this._translation="",this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return TranslatePipe._parseParams=function(arg){try{var o=eval("("+arg+")");if("object"==typeof o)return o}catch(a){}return{}},TranslatePipe.prototype.transform=function(a,b){void 0===b&&(b=[]);var c={};return b[0]&&("string"==typeof b[0]?(c=TranslatePipe_1._parseParams(b[0]),Object.keys(c).length||this._translate.logHandler.error("'"+b[0]+"' could not be parsed to object")):"object"==typeof b[0]&&(c=b[0])),this._translated&&this._promise&&(this._translated.key!==a||JSON.stringify(this._translated.params)!==JSON.stringify(c))&&(this._promise=null),this._promise||(this._translated={key:a,params:c},this._startTranslation()),this._translation},TranslatePipe.prototype._startTranslation=function(){var a=this;this._translated&&this._translated.key&&(this._promise=this._translate.translate(this._translated.key,this._translated.params),this._promise.then(function(b){return a._translation=String(b)}))},TranslatePipe}();TranslatePipe=TranslatePipe_1=__decorate([core_1.Pipe({name:"translate",pure:!1}),__param(0,core_1.Inject(TranslateService_1.TranslateService)),__metadata("design:paramtypes",[TranslateService_1.TranslateService])],TranslatePipe),exports.TranslatePipe=TranslatePipe;var TranslatePipe_1}),$__System.registerDynamic("12",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(b){var c=b.defaultLang,d=void 0===c?"en":c,e=b.providedLangs,f=void 0===e?["en"]:e,g=b.detectLanguageOnStart,h=void 0===g||g;this.defaultLang=f.indexOf(d)>-1?d:f[0],this.providedLangs=f,this.detectLanguageOnStart=h,this.navigatorLanguages=function(){var b=a.navigator;return b.languages instanceof Array?Array.prototype.slice.call(b.languages):[b.languages||b.language||b.browserLanguage||b.userLanguage].filter(function(a){return"string"==typeof a})}()}return a.prototype.langProvided=function(a,b){void 0===b&&(b=!1);var c,d=!1,e=function(a){var b=/^([A-Za-z]{2})(?:[\.\-_\/]?([A-Za-z]{2}))?$/;return a.match(b)?a.replace(b,function(a,b,c){return void 0===c&&(c=""),b=b.toLowerCase(),c=c.toUpperCase(),c?b+"-"+c:b}):""},f=this.providedLangs.map(e);return a=e(a),0===a.length?d:(c=f.indexOf(a),c>-1?d=this.providedLangs[c]:b||(a=a.substr(0,2),c=f.indexOf(a),c>-1?d=this.providedLangs[c]:(c=f.map(function(a){return a.substr(0,2)}).indexOf(a),c>-1&&(d=this.providedLangs[c]))),d)},a}();d.navigator=window&&window.navigator?window.navigator:{},b.TranslateConfig=d}),$__System.registerDynamic("f",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a}();b.TranslateLoader=d}),$__System.registerDynamic("13",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a.prototype.error=function(a){console&&console.error&&console.error(a)},a.prototype.info=function(a){},a.prototype.debug=function(a){},a}();b.TranslateLogHandler=d}),$__System.registerDynamic("c",["12","f","13","d","14","15"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},__param=exports&&exports.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateConfig_1=$__require("12"),TranslateLoader_1=$__require("f"),TranslateLogHandler_1=$__require("13"),core_1=$__require("d"),Observable_1=$__require("14");$__require("15");var TranslateService=function(){function TranslateService(a,b,c){var d=this;if(this._loadedLangs={},this._translations={},this._config=a,this._loader=b,this.logHandler=c,this._lang=a.defaultLang,a.detectLanguageOnStart){var e=this.detectLang(a.navigatorLanguages);e&&(this._lang=String(e),c.info("Language "+e+" got detected"))}this.languageChanged=new Observable_1.Observable(function(a){return d._languageChangedObserver=a}).share()}return Object.defineProperty(TranslateService.prototype,"lang",{get:function(){return this._lang},set:function(a){var b=this._config.langProvided(a,!0);if("string"==typeof b)return this._lang=b,this.logHandler.info("Language changed to "+b),void(this._languageChangedObserver&&this._languageChangedObserver.next(this._lang));throw new Error("Language not provided")},enumerable:!0,configurable:!0}),TranslateService.prototype.detectLang=function(a){var b,c=!1;for(b=0;b0)return this.logHandler.error("Parse error only first parameter can be passed as params in '"+a+"'"),"";j="wait_getter"}break;case"read_param_key":if(b[e].match(/[A-Za-z0-9_]/))g+=b[e];else if("="===b[e])j="wait_getter";else if(","===b[e])l(!1),j="wait_param";else{if(!b[e].match(/\s/))return this._referencedError(a,"character","comma, equal sign or end",e);j="param_key_readed"}break;case"param_key_readed":if(b[e].match(/\s/));else if("="===b[e])j="wait_getter";else{if(","!==b[e])return this._referencedError(a,"character","comma, equal sign or end",e);l(!1),j="wait_param"}break;case"wait_getter":if(b[e].match(/\s/));else{if(!b[e].match(/[A-Za-z0-9_]/))return this._referencedError(a,"character","getter",e);j="read_getter",h=b[e]}break;case"read_getter":if(b[e].match(/[A-Za-z0-9_.]/))h+=b[e];else if(b[e].match(/\s/))j="getter_readed";else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}break;case"getter_readed":if(b[e].match(/\s/));else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}}switch(j){case"param_key_readed":case"read_param_key":l(!1);break;case"getter_readed":case"read_getter":l();break;case"wait_key":return this._referencedError(a,"end","key");case"wait_param":return this._referencedError(a,"end","parameter");case"wait_getter":return this._referencedError(a,"end","getter")}return String(this.instant(f,k,d))},TranslateService}();TranslateService=__decorate([core_1.Injectable(),__param(0,core_1.Inject(TranslateConfig_1.TranslateConfig)),__param(1,core_1.Inject(TranslateLoader_1.TranslateLoader)),__param(2,core_1.Inject(TranslateLogHandler_1.TranslateLogHandler)),__metadata("design:paramtypes",[TranslateConfig_1.TranslateConfig,TranslateLoader_1.TranslateLoader,TranslateLogHandler_1.TranslateLogHandler])],TranslateService),exports.TranslateService=TranslateService}),$__System.registerDynamic("16",["b","12","f","e","13","11","c","d","10"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g});Object.defineProperty(b,"__esModule",{value:!0});var e=a("b"),f=a("12"),g=a("f"),h=a("e"),i=a("13"),j=a("11"),k=a("c"),l=a("d"),m=a("10"),n=function(){function a(){}return a}();n=d([l.NgModule({declarations:[j.TranslatePipe,e.TranslateComponent],exports:[j.TranslatePipe,e.TranslateComponent],imports:[m.HttpModule],providers:[{provide:f.TranslateConfig,useValue:new f.TranslateConfig({})},{provide:h.TranslateLoaderJsonConfig,useValue:new h.TranslateLoaderJsonConfig},{provide:g.TranslateLoader,useClass:h.TranslateLoaderJson},{provide:i.TranslateLogHandler,useClass:i.TranslateLogHandler},k.TranslateService]})],n),b.TranslatorModule=n,b.TRANSLATE_PROVIDERS=[{provide:f.TranslateConfig,useValue:new f.TranslateConfig({})},{provide:h.TranslateLoaderJsonConfig,useValue:new h.TranslateLoaderJsonConfig},{provide:g.TranslateLoader,useClass:h.TranslateLoaderJson},{provide:i.TranslateLogHandler,useValue:i.TranslateLogHandler},k.TranslateService]}),$__System.registerDynamic("a",["c","11","b","12","f","e","13","16"],!0,function(a,b,c){"use strict";function d(a){for(var c in a)b.hasOwnProperty(c)||(b[c]=a[c])}this||self;Object.defineProperty(b,"__esModule",{value:!0}),d(a("c")),d(a("11")),d(a("b")),d(a("12")),d(a("f")),d(a("e")),d(a("13")),d(a("16"))})})(function(a){if("function"==typeof define&&define.amd)define(["@angular/core","@angular/http","rxjs/Observable","rxjs/add/operator/share"],a);else{if("object"!=typeof module||!module.exports||"function"!=typeof require)throw new Error("Module must be loaded as AMD or CommonJS");module.exports=a(require("@angular/core"),require("@angular/http"),require("rxjs/Observable"),require("rxjs/add/operator/share"))}}); //# sourceMappingURL=angular2-translator.js.map \ No newline at end of file diff --git a/src/TranslateConfig.ts b/src/TranslateConfig.ts index 0a22a2f..8db2cfc 100644 --- a/src/TranslateConfig.ts +++ b/src/TranslateConfig.ts @@ -1,23 +1,38 @@ +import {TranslateLoader} from "./TranslateLoader"; +import {TranslateLoaderJson} from "./TranslateLoaderJson"; + +import {Type} from "@angular/core"; + export class TranslateConfig { public static navigator: any = window && window.navigator ? window.navigator : {}; public defaultLang: string; public providedLangs: string[]; public detectLanguageOnStart: boolean; + public loader: Type; + public loaderConfig: Object; + public navigatorLanguages: string[]; constructor({ defaultLang = "en", providedLangs = ["en"], detectLanguageOnStart = true, - }: { + loader = TranslateLoaderJson, + loaderConfig = {}, + }: { defaultLang?: string, - providedLangs?: string[] - detectLanguageOnStart?: boolean + providedLangs?: string[], + detectLanguageOnStart?: boolean, + loader?: Type, + loaderConfig?: Object }) { - this.defaultLang = providedLangs.indexOf(defaultLang) > -1 ? defaultLang : providedLangs[0]; + this.defaultLang = providedLangs.indexOf(defaultLang) > -1 ? defaultLang : providedLangs[0]; this.providedLangs = providedLangs; this.detectLanguageOnStart = detectLanguageOnStart; + this.loader = loader; + this.loaderConfig = loaderConfig; + this.navigatorLanguages = ((): string[] => { let navigator: any = TranslateConfig.navigator; @@ -60,8 +75,8 @@ export class TranslateConfig { return languageString.replace( regExp, function (substring: string, language: string, country: string = "") { - language = language.toLowerCase(); - country = country.toUpperCase(); + language = language.toLowerCase(); + country = country.toUpperCase(); return country ? language + "-" + country : language; } ); @@ -79,7 +94,7 @@ export class TranslateConfig { provided = this.providedLangs[p]; } else if (!strict) { lang = lang.substr(0, 2); - p = providedLangsNormalized.indexOf(lang); + p = providedLangsNormalized.indexOf(lang); if (p > -1) { provided = this.providedLangs[p]; } else { diff --git a/src/TranslateLoader.ts b/src/TranslateLoader.ts index 9d54802..6043ff7 100644 --- a/src/TranslateLoader.ts +++ b/src/TranslateLoader.ts @@ -1,11 +1,5 @@ -/** - * A TranslateLoader has to load every file even if they are divided to partials. If a TranslateLoader resolves - * the language is marked as loaded. It will not get loaded again. - */ -export interface ITranslateLoader { - load(lang: string): Promise; -} - -export abstract class TranslateLoader implements ITranslateLoader { +export abstract class TranslateLoader { public abstract load(lang: string): Promise; + + public configure(config: Object): void {} } diff --git a/src/TranslateLoaderJson.ts b/src/TranslateLoaderJson.ts index 230fede..0d111e2 100644 --- a/src/TranslateLoaderJson.ts +++ b/src/TranslateLoaderJson.ts @@ -1,38 +1,36 @@ import {TranslateLoader} from "./TranslateLoader"; -import {Inject, Injectable} from "@angular/core"; -import {Http} from "@angular/http"; -export class TranslateLoaderJsonConfig { - public path: string = "assets/i18n/"; - public extension: string = ".json"; - - // @todo maybe we will change it to a destructed parameter like we did for TranslateConfig - constructor(path?: string, extension?: string) { - if (path) { - this.path = path.replace(/\/+$/, "") + "/"; - } - - if (extension) { - this.extension = extension; - } - } -} +import {Injectable} from "@angular/core"; +import {Http} from "@angular/http"; @Injectable() export class TranslateLoaderJson extends TranslateLoader { - private _http: Http; - private _config: TranslateLoaderJsonConfig; + private options: { + extension: string, + path: string + } = { + extension: ".json", + path: "assets/i18n", + }; - constructor(@Inject(Http) http: Http, @Inject(TranslateLoaderJsonConfig) config: TranslateLoaderJsonConfig) { + constructor(private http: Http) { super(); - this._http = http; - this._config = config; + } + + public configure(config: any): void { + if (typeof config.extension === "string") { + this.options.extension = config.extension; + } + + if (typeof config.path === "string") { + this.options.path = config.path; + } } public load(lang: string): Promise { return new Promise((resolve, reject) => { - let file = this._config.path + lang + this._config.extension; - this._http.get(file) + let file = this.options.path + "/" + lang + this.options.extension; + this.http.get(file) .subscribe( (response) => { if (response.status === 200) { diff --git a/src/TranslateService.ts b/src/TranslateService.ts index 6c00d6c..8f59bca 100644 --- a/src/TranslateService.ts +++ b/src/TranslateService.ts @@ -2,32 +2,31 @@ import {TranslateConfig} from "./TranslateConfig"; import {TranslateLoader} from "./TranslateLoader"; import {TranslateLogHandler} from "./TranslateLogHandler"; -import {Inject, Injectable} from "@angular/core"; -import {Observable} from "rxjs/Observable"; -import {Observer} from "rxjs/Observer"; +import {Injectable, Injector} from "@angular/core"; +import {Observable} from "rxjs/Observable"; +import {Observer} from "rxjs/Observer"; import "rxjs/add/operator/share"; @Injectable() export class TranslateService { public languageChanged: Observable; - public logHandler: TranslateLogHandler; - - private _config: TranslateConfig; - private _loader: TranslateLoader; + private loader: TranslateLoader; private _lang: string; private _loadedLangs: Object = {}; private _translations: Object = {}; private _languageChangedObserver: Observer; - constructor(@Inject(TranslateConfig) config: TranslateConfig, - @Inject(TranslateLoader) loader: TranslateLoader, - @Inject(TranslateLogHandler) logHandler: TranslateLogHandler) { - this._config = config; - this._loader = loader; + constructor(public logHandler: TranslateLogHandler, + private config: TranslateConfig, + private injector: Injector) { + this.config = config; this.logHandler = logHandler; + this.loader = injector.get(config.loader); + this.loader.configure(config.loaderConfig); + this._lang = config.defaultLang; if (config.detectLanguageOnStart) { @@ -48,7 +47,7 @@ export class TranslateService { } set lang(lang: string) { - let providedLang = this._config.langProvided(lang, true); + let providedLang = this.config.langProvided(lang, true); if (typeof providedLang === "string") { this._lang = providedLang; @@ -76,15 +75,17 @@ export class TranslateService { let detected: string|boolean = false; let i: number; + this.logHandler.debug("Detecting language from " + JSON.stringify(navLangs) + " in strict mode."); for (i = 0; i < navLangs.length; i++) { - detected = this._config.langProvided(navLangs[i], true); + detected = this.config.langProvided(navLangs[i], true); if (detected) { break; } } if (!detected) { + this.logHandler.debug("Detecting language from " + JSON.stringify(navLangs) + " in non-strict mode."); for (i = 0; i < navLangs.length; i++) { - detected = this._config.langProvided(navLangs[i]); + detected = this.config.langProvided(navLangs[i]); if (detected) { break; } @@ -101,7 +102,7 @@ export class TranslateService { * @returns {Promise|Promise} */ public waitForTranslation(lang: string = this._lang): Promise { - let l = this._config.langProvided(lang, true); + let l = this.config.langProvided(lang, true); if (!l) { return Promise.reject("Language not provided"); } else { @@ -123,7 +124,7 @@ export class TranslateService { public translate(keys: string|string[], params: any = {}, lang: string = this._lang): Promise { return new Promise((resolve) => { if (lang !== this._lang) { - let l = this._config.langProvided(lang, true); + let l = this.config.langProvided(lang, true); if (!l) { resolve(keys); return; @@ -156,7 +157,7 @@ export class TranslateService { } if (lang !== this._lang) { - let l = this._config.langProvided(lang, true); + let l = this.config.langProvided(lang, true); if (l) { lang = String(l); } @@ -205,7 +206,7 @@ export class TranslateService { private _loadLang(lang: string): Promise { if (!this._loadedLangs[lang]) { this._loadedLangs[lang] = new Promise((resolve, reject) => { - this._loader.load(lang).then((translations) => { + this.loader.load(lang).then((translations) => { this._translations[lang] = translations; this.logHandler.info("Language " + lang + " got loaded"); resolve(); diff --git a/src/TranslatorModule.ts b/src/TranslatorModule.ts index c01bfa5..7d5d672 100644 --- a/src/TranslatorModule.ts +++ b/src/TranslatorModule.ts @@ -1,7 +1,7 @@ import {TranslateComponent} from "./TranslateComponent"; import {TranslateConfig} from "./TranslateConfig"; import {TranslateLoader} from "./TranslateLoader"; -import {TranslateLoaderJson, TranslateLoaderJsonConfig} from "./TranslateLoaderJson"; +import {TranslateLoaderJson} from "./TranslateLoaderJson"; import {TranslateLogHandler} from "./TranslateLogHandler"; import {TranslatePipe} from "./TranslatePipe"; import {TranslateService} from "./TranslateService"; @@ -21,8 +21,7 @@ import {HttpModule} from "@angular/http"; imports: [HttpModule], providers: [ { provide: TranslateConfig, useValue: new TranslateConfig({}) }, - { provide: TranslateLoaderJsonConfig, useValue: new TranslateLoaderJsonConfig() }, - { provide: TranslateLoader, useClass: TranslateLoaderJson }, + { provide: TranslateLoaderJson, useClass: TranslateLoaderJson }, { provide: TranslateLogHandler, useClass: TranslateLogHandler }, TranslateService, ], @@ -31,7 +30,6 @@ export class TranslatorModule {} export const TRANSLATE_PROVIDERS: any[] = [ { provide: TranslateConfig, useValue: new TranslateConfig({}) }, - { provide: TranslateLoaderJsonConfig, useValue: new TranslateLoaderJsonConfig() }, { provide: TranslateLoader, useClass: TranslateLoaderJson }, { provide: TranslateLogHandler, useValue: TranslateLogHandler }, TranslateService, diff --git a/tests/TranslateLoaderJson.spec.ts b/tests/TranslateLoaderJson.spec.ts index ffc3cc4..e5f6dce 100644 --- a/tests/TranslateLoaderJson.spec.ts +++ b/tests/TranslateLoaderJson.spec.ts @@ -1,6 +1,5 @@ import { TranslateLoaderJson, - TranslateLoaderJsonConfig, } from "../index"; import {JasmineHelper} from "./helper/JasmineHelper"; @@ -15,50 +14,11 @@ import { } from "@angular/http"; import {MockBackend, MockConnection} from "@angular/http/testing"; -describe("TranslateLoaderJsonConfig", function () { - it("is defined", function () { - let config = new TranslateLoaderJsonConfig(); - - expect(TranslateLoaderJsonConfig).toBeDefined(); - expect(config).toBeDefined(); - expect(config instanceof TranslateLoaderJsonConfig).toBeTruthy(); - }); - - it("defines default path and extension", function () { - let config = new TranslateLoaderJsonConfig(); - - expect(config.path).toBe("assets/i18n/"); - expect(config.extension).toBe(".json"); - }); - - it("overrides defaults by constructor", function () { - let config = new TranslateLoaderJsonConfig("localization", "-lang.json"); - - expect(config.path).toBe("localization/"); - expect(config.extension).toBe("-lang.json"); - }); -}); - describe("TranslateLoaderJson", function () { it("is defined", function () { expect(TranslateLoaderJson).toBeDefined(); }); - describe("constructor", function () { - it("requires a TranslateLoaderJsonConfig", function () { - TestBed.configureTestingModule({ - imports: [HttpModule], - providers: [TranslateLoaderJson], - }); - - let action = function () { - TestBed.get(TranslateLoaderJson); - }; - - expect(action).toThrow(new Error("No provider for TranslateLoaderJsonConfig!")); - }); - }); - describe("load", function () { let loader: TranslateLoaderJson; let backend: MockBackend; @@ -69,7 +29,6 @@ describe("TranslateLoaderJson", function () { imports: [HttpModule], providers: [ {provide: XHRBackend, useClass: MockBackend}, - {provide: TranslateLoaderJsonConfig, useValue: new TranslateLoaderJsonConfig()}, TranslateLoaderJson, ], }); diff --git a/tests/TranslateLogHandler.spec.ts b/tests/TranslateLogHandler.spec.ts new file mode 100644 index 0000000..16b978e --- /dev/null +++ b/tests/TranslateLogHandler.spec.ts @@ -0,0 +1,14 @@ +import { + TranslateLogHandler, +} from "../index"; + +describe("TranslateLogHandler", () => { + it("writes errors to console.error", () => { + spyOn(console, "error"); + let logHandler: TranslateLogHandler = new TranslateLogHandler(); + + logHandler.error("This was bad"); + + expect(console.error).toHaveBeenCalledWith("This was bad"); + }); +}); diff --git a/tests/TranslatePipe.spec.ts b/tests/TranslatePipe.spec.ts index 4c9b9d0..6c50c5e 100644 --- a/tests/TranslatePipe.spec.ts +++ b/tests/TranslatePipe.spec.ts @@ -12,13 +12,13 @@ import {TranslateLoaderMock} from "./helper/TranslateLoaderMock"; import {ReflectiveInjector} from "@angular/core"; import {fakeAsync, flushMicrotasks} from "@angular/core/testing"; -describe("TranslatePipe", function() { - it("is defined", function () { +describe("TranslatePipe", () => { + it("is defined", () => { expect(TranslatePipe).toBeDefined(); }); - describe("constructor", function() { - it("requires a TranslateService", function () { + describe("constructor", () => { + it("requires a TranslateService", () => { let injector = ReflectiveInjector.resolveAndCreate([ TranslatePipe ]); let action = function () { @@ -31,7 +31,7 @@ describe("TranslatePipe", function() { }); }); - describe("transform", function() { + describe("transform", () => { let translate: TranslateService; let translatePipe: TranslatePipe; let logHandler: TranslateLogHandler; diff --git a/tests/TranslateService.spec.ts b/tests/TranslateService.spec.ts index 7357564..2501cd1 100644 --- a/tests/TranslateService.spec.ts +++ b/tests/TranslateService.spec.ts @@ -1,14 +1,19 @@ import { TranslateConfig, TranslateLoader, + TranslateLoaderJson, TranslateLogHandler, TranslateService, TranslatorModule, } from "../index"; +import { + TranslateLoaderMock, + TranslateLogHandlerMock, +} from "./helper/TranslatorMocks"; + import {JasmineHelper} from "./helper/JasmineHelper"; import {JasminePromise, PromiseMatcher} from "./helper/promise-matcher"; -import {TranslateLoaderMock} from "./helper/TranslateLoaderMock"; import {ReflectiveInjector} from "@angular/core"; import {TestBed, fakeAsync} from "@angular/core/testing"; import {Observable} from "rxjs/Observable"; @@ -22,45 +27,41 @@ describe("TranslateService", function () { it("requires a TranslateConfig", function () { let injector = ReflectiveInjector.resolveAndCreate([ TranslateService, + { provide: TranslateLogHandler, useClass: TranslateLogHandlerMock }, ]); let action = function () { - injector.get(TranslateService); - }; - - // let providerError = new NoProviderError(injector, ReflectiveKey.get(TranslateConfig)); - // providerError.addKey(injector, ReflectiveKey.get(TranslateService)); - expect(action).toThrow(); - }); - - it("requires a TranslateLoader", function () { - let injector = ReflectiveInjector.resolveAndCreate([ - TranslateService, - { provide: TranslateConfig, useValue: new TranslateConfig({}) }, - ]); - - let action = function () { - injector.get(TranslateService); + try { + injector.get(TranslateService); + } catch (e) { + expect(e.message).toBe( + "No provider for TranslateConfig! (TranslateService -> TranslateConfig)" + ); + throw e; + } }; - - // let providerError = new NoProviderError(injector, ReflectiveKey.get(TranslateLoader)); - // providerError.addKey(injector, ReflectiveKey.get(TranslateService)); expect(action).toThrow(); }); it("requires an TranslateLogHandler", function() { let injector = ReflectiveInjector.resolveAndCreate([ TranslateService, - { provide: TranslateConfig, useValue: new TranslateConfig({}) }, - { provide: TranslateLoader, useValue: new TranslateLoaderMock() }, + TranslateLoaderMock, + { provide: TranslateConfig, useValue: new TranslateConfig({ + loader: TranslateLoaderMock, + }) }, ]); let action = function () { - injector.get(TranslateService); + try { + injector.get(TranslateService); + } catch (e) { + expect(e.message).toBe( + "No provider for TranslateLogHandler! (TranslateService -> TranslateLogHandler)" + ); + throw e; + } }; - - // let providerError = new NoProviderError(injector, ReflectiveKey.get(TranslateLogHandler)); - // providerError.addKey(injector, ReflectiveKey.get(TranslateService)); expect(action).toThrow(); }); @@ -142,7 +143,7 @@ describe("TranslateService", function () { }); translate = TestBed.get(TranslateService); - loader = TestBed.get(TranslateLoader); + loader = TestBed.get(TranslateLoaderJson); translate.logHandler.error = (msg) => { console.error(msg); }; PromiseMatcher.install(); }); diff --git a/tests/helper/TranslatorMocks.ts b/tests/helper/TranslatorMocks.ts new file mode 100644 index 0000000..4107598 --- /dev/null +++ b/tests/helper/TranslatorMocks.ts @@ -0,0 +1,18 @@ +import {TranslateLoader} from "../../index"; +import {TranslateLogHandler} from "../../index"; + +export class TranslateLoaderMock extends TranslateLoader { + private _provided: Object = {}; + + public provide(lang: string, translations: Object) { + this._provided[lang] = translations; + } + + public load(lang: string): Promise { + return Promise.resolve(this._provided[lang] || {}); + } +} + +export class TranslateLogHandlerMock extends TranslateLogHandler { + public error(message: string): void {} +} From 01f930055d5cbe19c846e3f2f77f02533fb78023 Mon Sep 17 00:00:00 2001 From: Thomas Flori Date: Mon, 20 Mar 2017 22:27:56 +0100 Subject: [PATCH 2/2] fixed the tests and increased test coverage --- bundles/angular2-translator.js | 2 +- src/TranslateService.ts | 11 +- src/TranslatorModule.ts | 12 +- tests/TranslateComponent.spec.ts | 61 ++++---- tests/TranslateConfig.spec.ts | 42 ++--- tests/TranslateLoader.spec.ts | 4 +- tests/TranslateLoaderJson.spec.ts | 15 ++ tests/TranslateLogHandler.spec.ts | 13 ++ tests/TranslatePipe.spec.ts | 73 +++++---- tests/TranslateService.spec.ts | 247 ++++++++++++++++++++---------- 10 files changed, 299 insertions(+), 181 deletions(-) diff --git a/bundles/angular2-translator.js b/bundles/angular2-translator.js index e27ee75..077d805 100644 --- a/bundles/angular2-translator.js +++ b/bundles/angular2-translator.js @@ -1,2 +1,2 @@ -!function(a){function b(a){Object.defineProperty(this,a,{enumerable:!0,get:function(){return this[o][a]}})}function c(a){var b;if(a&&a.__esModule){b={};for(var c in a)Object.hasOwnProperty.call(a,c)&&(b[c]=a[c]);b.__useDefault&&delete b.__useDefault,b.__esModule=!0}else{if("[object Module]"===Object.prototype.toString.call(a)||"undefined"!=typeof System&&System.isModule&&System.isModule(a))return a;b={default:a,__useDefault:!0}}return new d(b)}function d(a){Object.defineProperty(this,o,{value:a}),Object.keys(a).forEach(b,this)}function e(a){return"@node/"===a.substr(0,6)?m(a,c(p(a.substr(6))),{}):n[a]}function f(a){var b=e(a);if(!b)throw new Error('Module "'+a+'" expected, but not contained in build.');if(b.module)return b.module;var c=b.linkRecord;return g(b,c),l(b,c,[]),b.module}function g(a,b){if(!b.depLoads){b.declare&&h(a,b),b.depLoads=[];for(var c=0;c1)for(var l=1;l=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g}),e=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},f=b&&b.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(b,"__esModule",{value:!0});var g=a("c"),h=a("d"),i=function(){function a(a){var b=this;this.translation="",this._params={},this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return Object.defineProperty(a.prototype,"key",{set:function(a){this._key=a,this._startTranslation()},enumerable:!0,configurable:!0}),Object.defineProperty(a.prototype,"params",{set:function(a){if("object"!=typeof a)return void this._translate.logHandler.error("Params have to be an object");this._params=a,this._startTranslation()},enumerable:!0,configurable:!0}),a.prototype._startTranslation=function(){var a=this;this._key&&this._translate.translate(this._key,this._params).then(function(b){return a.translation=String(b)})},a}();d([h.Input("translate"),e("design:type",String),e("design:paramtypes",[String])],i.prototype,"key",null),d([h.Input("translateParams"),e("design:type",Object),e("design:paramtypes",[Object])],i.prototype,"params",null),i=d([h.Component({selector:"[translate]",template:"{{translation}}"}),f(0,h.Inject(g.TranslateService)),e("design:paramtypes",[g.TranslateService])],i),b.TranslateComponent=i}),$__System.registerDynamic("e",["f","d","10"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__extends||function(){var a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,b){a.__proto__=b}||function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])};return function(b,c){function d(){this.constructor=b}a(b,c),b.prototype=null===c?Object.create(c):(d.prototype=c.prototype,new d)}}()),e=b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},f=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},g=b&&b.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(b,"__esModule",{value:!0});var h=a("f"),i=a("d"),j=a("10"),k=function(){function a(a,b){this.path="assets/i18n/",this.extension=".json",a&&(this.path=a.replace(/\/+$/,"")+"/"),b&&(this.extension=b)}return a}();b.TranslateLoaderJsonConfig=k;var l=function(a){function b(b,c){var d=a.call(this)||this;return d._http=b,d._config=c,d}return d(b,a),b.prototype.load=function(a){var b=this;return new Promise(function(c,d){var e=b._config.path+a+b._config.extension;b._http.get(e).subscribe(function(a){if(200===a.status){var e={};b.flattenTranslations(e,a.json()),c(e)}else d("StatusCode: "+a.status)},function(a){d(a.message)})})},b.prototype.flattenTranslations=function(a,b,c){void 0===c&&(c="");for(var d in b)Array.isArray(b[d])?a[c+d]=b[d].filter(function(a){return"string"==typeof a}).join(""):"object"==typeof b[d]?this.flattenTranslations(a,b[d],c+d+"."):"string"==typeof b[d]&&(a[c+d]=b[d])},b}(h.TranslateLoader);l=e([i.Injectable(),g(0,i.Inject(j.Http)),g(1,i.Inject(k)),f("design:paramtypes",[j.Http,k])],l),b.TranslateLoaderJson=l}),$__System.registerDynamic("11",["c","d"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},__param=exports&&exports.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateService_1=$__require("c"),core_1=$__require("d"),TranslatePipe=TranslatePipe_1=function(){function TranslatePipe(a){var b=this;this._translation="",this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return TranslatePipe._parseParams=function(arg){try{var o=eval("("+arg+")");if("object"==typeof o)return o}catch(a){}return{}},TranslatePipe.prototype.transform=function(a,b){void 0===b&&(b=[]);var c={};return b[0]&&("string"==typeof b[0]?(c=TranslatePipe_1._parseParams(b[0]),Object.keys(c).length||this._translate.logHandler.error("'"+b[0]+"' could not be parsed to object")):"object"==typeof b[0]&&(c=b[0])),this._translated&&this._promise&&(this._translated.key!==a||JSON.stringify(this._translated.params)!==JSON.stringify(c))&&(this._promise=null),this._promise||(this._translated={key:a,params:c},this._startTranslation()),this._translation},TranslatePipe.prototype._startTranslation=function(){var a=this;this._translated&&this._translated.key&&(this._promise=this._translate.translate(this._translated.key,this._translated.params),this._promise.then(function(b){return a._translation=String(b)}))},TranslatePipe}();TranslatePipe=TranslatePipe_1=__decorate([core_1.Pipe({name:"translate",pure:!1}),__param(0,core_1.Inject(TranslateService_1.TranslateService)),__metadata("design:paramtypes",[TranslateService_1.TranslateService])],TranslatePipe),exports.TranslatePipe=TranslatePipe;var TranslatePipe_1}),$__System.registerDynamic("12",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(b){var c=b.defaultLang,d=void 0===c?"en":c,e=b.providedLangs,f=void 0===e?["en"]:e,g=b.detectLanguageOnStart,h=void 0===g||g;this.defaultLang=f.indexOf(d)>-1?d:f[0],this.providedLangs=f,this.detectLanguageOnStart=h,this.navigatorLanguages=function(){var b=a.navigator;return b.languages instanceof Array?Array.prototype.slice.call(b.languages):[b.languages||b.language||b.browserLanguage||b.userLanguage].filter(function(a){return"string"==typeof a})}()}return a.prototype.langProvided=function(a,b){void 0===b&&(b=!1);var c,d=!1,e=function(a){var b=/^([A-Za-z]{2})(?:[\.\-_\/]?([A-Za-z]{2}))?$/;return a.match(b)?a.replace(b,function(a,b,c){return void 0===c&&(c=""),b=b.toLowerCase(),c=c.toUpperCase(),c?b+"-"+c:b}):""},f=this.providedLangs.map(e);return a=e(a),0===a.length?d:(c=f.indexOf(a),c>-1?d=this.providedLangs[c]:b||(a=a.substr(0,2),c=f.indexOf(a),c>-1?d=this.providedLangs[c]:(c=f.map(function(a){return a.substr(0,2)}).indexOf(a),c>-1&&(d=this.providedLangs[c]))),d)},a}();d.navigator=window&&window.navigator?window.navigator:{},b.TranslateConfig=d}),$__System.registerDynamic("f",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a}();b.TranslateLoader=d}),$__System.registerDynamic("13",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a.prototype.error=function(a){console&&console.error&&console.error(a)},a.prototype.info=function(a){},a.prototype.debug=function(a){},a}();b.TranslateLogHandler=d}),$__System.registerDynamic("c",["12","f","13","d","14","15"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},__param=exports&&exports.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateConfig_1=$__require("12"),TranslateLoader_1=$__require("f"),TranslateLogHandler_1=$__require("13"),core_1=$__require("d"),Observable_1=$__require("14");$__require("15");var TranslateService=function(){function TranslateService(a,b,c){var d=this;if(this._loadedLangs={},this._translations={},this._config=a,this._loader=b,this.logHandler=c,this._lang=a.defaultLang,a.detectLanguageOnStart){var e=this.detectLang(a.navigatorLanguages);e&&(this._lang=String(e),c.info("Language "+e+" got detected"))}this.languageChanged=new Observable_1.Observable(function(a){return d._languageChangedObserver=a}).share()}return Object.defineProperty(TranslateService.prototype,"lang",{get:function(){return this._lang},set:function(a){var b=this._config.langProvided(a,!0);if("string"==typeof b)return this._lang=b,this.logHandler.info("Language changed to "+b),void(this._languageChangedObserver&&this._languageChangedObserver.next(this._lang));throw new Error("Language not provided")},enumerable:!0,configurable:!0}),TranslateService.prototype.detectLang=function(a){var b,c=!1;for(b=0;b0)return this.logHandler.error("Parse error only first parameter can be passed as params in '"+a+"'"),"";j="wait_getter"}break;case"read_param_key":if(b[e].match(/[A-Za-z0-9_]/))g+=b[e];else if("="===b[e])j="wait_getter";else if(","===b[e])l(!1),j="wait_param";else{if(!b[e].match(/\s/))return this._referencedError(a,"character","comma, equal sign or end",e);j="param_key_readed"}break;case"param_key_readed":if(b[e].match(/\s/));else if("="===b[e])j="wait_getter";else{if(","!==b[e])return this._referencedError(a,"character","comma, equal sign or end",e);l(!1),j="wait_param"}break;case"wait_getter":if(b[e].match(/\s/));else{if(!b[e].match(/[A-Za-z0-9_]/))return this._referencedError(a,"character","getter",e);j="read_getter",h=b[e]}break;case"read_getter":if(b[e].match(/[A-Za-z0-9_.]/))h+=b[e];else if(b[e].match(/\s/))j="getter_readed";else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}break;case"getter_readed":if(b[e].match(/\s/));else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}}switch(j){case"param_key_readed":case"read_param_key":l(!1);break;case"getter_readed":case"read_getter":l();break;case"wait_key":return this._referencedError(a,"end","key");case"wait_param":return this._referencedError(a,"end","parameter");case"wait_getter":return this._referencedError(a,"end","getter")}return String(this.instant(f,k,d))},TranslateService}();TranslateService=__decorate([core_1.Injectable(),__param(0,core_1.Inject(TranslateConfig_1.TranslateConfig)),__param(1,core_1.Inject(TranslateLoader_1.TranslateLoader)),__param(2,core_1.Inject(TranslateLogHandler_1.TranslateLogHandler)),__metadata("design:paramtypes",[TranslateConfig_1.TranslateConfig,TranslateLoader_1.TranslateLoader,TranslateLogHandler_1.TranslateLogHandler])],TranslateService),exports.TranslateService=TranslateService}),$__System.registerDynamic("16",["b","12","f","e","13","11","c","d","10"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g});Object.defineProperty(b,"__esModule",{value:!0});var e=a("b"),f=a("12"),g=a("f"),h=a("e"),i=a("13"),j=a("11"),k=a("c"),l=a("d"),m=a("10"),n=function(){function a(){}return a}();n=d([l.NgModule({declarations:[j.TranslatePipe,e.TranslateComponent],exports:[j.TranslatePipe,e.TranslateComponent],imports:[m.HttpModule],providers:[{provide:f.TranslateConfig,useValue:new f.TranslateConfig({})},{provide:h.TranslateLoaderJsonConfig,useValue:new h.TranslateLoaderJsonConfig},{provide:g.TranslateLoader,useClass:h.TranslateLoaderJson},{provide:i.TranslateLogHandler,useClass:i.TranslateLogHandler},k.TranslateService]})],n),b.TranslatorModule=n,b.TRANSLATE_PROVIDERS=[{provide:f.TranslateConfig,useValue:new f.TranslateConfig({})},{provide:h.TranslateLoaderJsonConfig,useValue:new h.TranslateLoaderJsonConfig},{provide:g.TranslateLoader,useClass:h.TranslateLoaderJson},{provide:i.TranslateLogHandler,useValue:i.TranslateLogHandler},k.TranslateService]}),$__System.registerDynamic("a",["c","11","b","12","f","e","13","16"],!0,function(a,b,c){"use strict";function d(a){for(var c in a)b.hasOwnProperty(c)||(b[c]=a[c])}this||self;Object.defineProperty(b,"__esModule",{value:!0}),d(a("c")),d(a("11")),d(a("b")),d(a("12")),d(a("f")),d(a("e")),d(a("13")),d(a("16"))})})(function(a){if("function"==typeof define&&define.amd)define(["@angular/core","@angular/http","rxjs/Observable","rxjs/add/operator/share"],a);else{if("object"!=typeof module||!module.exports||"function"!=typeof require)throw new Error("Module must be loaded as AMD or CommonJS");module.exports=a(require("@angular/core"),require("@angular/http"),require("rxjs/Observable"),require("rxjs/add/operator/share"))}}); +!function(a){function b(a){Object.defineProperty(this,a,{enumerable:!0,get:function(){return this[o][a]}})}function c(a){var b;if(a&&a.__esModule){b={};for(var c in a)Object.hasOwnProperty.call(a,c)&&(b[c]=a[c]);b.__useDefault&&delete b.__useDefault,b.__esModule=!0}else{if("[object Module]"===Object.prototype.toString.call(a)||"undefined"!=typeof System&&System.isModule&&System.isModule(a))return a;b={default:a,__useDefault:!0}}return new d(b)}function d(a){Object.defineProperty(this,o,{value:a}),Object.keys(a).forEach(b,this)}function e(a){return"@node/"===a.substr(0,6)?m(a,c(p(a.substr(6))),{}):n[a]}function f(a){var b=e(a);if(!b)throw new Error('Module "'+a+'" expected, but not contained in build.');if(b.module)return b.module;var c=b.linkRecord;return g(b,c),l(b,c,[]),b.module}function g(a,b){if(!b.depLoads){b.declare&&h(a,b),b.depLoads=[];for(var c=0;c1)for(var l=1;l=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g}),e=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},f=b&&b.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(b,"__esModule",{value:!0});var g=a("c"),h=a("d"),i=function(){function a(a){var b=this;this.translation="",this._params={},this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return Object.defineProperty(a.prototype,"key",{set:function(a){this._key=a,this._startTranslation()},enumerable:!0,configurable:!0}),Object.defineProperty(a.prototype,"params",{set:function(a){if("object"!=typeof a)return void this._translate.logHandler.error("Params have to be an object");this._params=a,this._startTranslation()},enumerable:!0,configurable:!0}),a.prototype._startTranslation=function(){var a=this;this._key&&this._translate.translate(this._key,this._params).then(function(b){return a.translation=String(b)})},a}();d([h.Input("translate"),e("design:type",String),e("design:paramtypes",[String])],i.prototype,"key",null),d([h.Input("translateParams"),e("design:type",Object),e("design:paramtypes",[Object])],i.prototype,"params",null),i=d([h.Component({selector:"[translate]",template:"{{translation}}"}),f(0,h.Inject(g.TranslateService)),e("design:paramtypes",[g.TranslateService])],i),b.TranslateComponent=i}),$__System.registerDynamic("e",["c","d"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)},__param=exports&&exports.__param||function(a,b){return function(c,d){b(c,d,a)}};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateService_1=$__require("c"),core_1=$__require("d"),TranslatePipe=TranslatePipe_1=function(){function TranslatePipe(a){var b=this;this._translation="",this._translate=a,a.languageChanged.subscribe(function(){b._startTranslation()})}return TranslatePipe._parseParams=function(arg){try{var o=eval("("+arg+")");if("object"==typeof o)return o}catch(a){}return{}},TranslatePipe.prototype.transform=function(a,b){void 0===b&&(b=[]);var c={};return b[0]&&("string"==typeof b[0]?(c=TranslatePipe_1._parseParams(b[0]),Object.keys(c).length||this._translate.logHandler.error("'"+b[0]+"' could not be parsed to object")):"object"==typeof b[0]&&(c=b[0])),this._translated&&this._promise&&(this._translated.key!==a||JSON.stringify(this._translated.params)!==JSON.stringify(c))&&(this._promise=null),this._promise||(this._translated={key:a,params:c},this._startTranslation()),this._translation},TranslatePipe.prototype._startTranslation=function(){var a=this;this._translated&&this._translated.key&&(this._promise=this._translate.translate(this._translated.key,this._translated.params),this._promise.then(function(b){return a._translation=String(b)}))},TranslatePipe}();TranslatePipe=TranslatePipe_1=__decorate([core_1.Pipe({name:"translate",pure:!1}),__param(0,core_1.Inject(TranslateService_1.TranslateService)),__metadata("design:paramtypes",[TranslateService_1.TranslateService])],TranslatePipe),exports.TranslatePipe=TranslatePipe;var TranslatePipe_1}),$__System.registerDynamic("f",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a.prototype.configure=function(a){},a}();b.TranslateLoader=d}),$__System.registerDynamic("10",["f","d","11"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__extends||function(){var a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(a,b){a.__proto__=b}||function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c])};return function(b,c){function d(){this.constructor=b}a(b,c),b.prototype=null===c?Object.create(c):(d.prototype=c.prototype,new d)}}()),e=b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},f=b&&b.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)};Object.defineProperty(b,"__esModule",{value:!0});var g=a("f"),h=a("d"),i=a("11"),j=function(a){function b(b){var c=a.call(this)||this;return c.http=b,c.options={extension:".json",path:"assets/i18n"},c}return d(b,a),b.prototype.configure=function(a){"string"==typeof a.extension&&(this.options.extension=a.extension),"string"==typeof a.path&&(this.options.path=a.path)},b.prototype.load=function(a){var b=this;return new Promise(function(c,d){var e=b.options.path+"/"+a+b.options.extension;b.http.get(e).subscribe(function(a){if(200===a.status){var e={};b.flattenTranslations(e,a.json()),c(e)}else d("StatusCode: "+a.status)},function(a){d(a.message)})})},b.prototype.flattenTranslations=function(a,b,c){void 0===c&&(c="");for(var d in b)Array.isArray(b[d])?a[c+d]=b[d].filter(function(a){return"string"==typeof a}).join(""):"object"==typeof b[d]?this.flattenTranslations(a,b[d],c+d+"."):"string"==typeof b[d]&&(a[c+d]=b[d])},b}(g.TranslateLoader);j=e([h.Injectable(),f("design:paramtypes",[i.Http])],j),b.TranslateLoaderJson=j}),$__System.registerDynamic("12",["10"],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=a("10"),e=function(){function a(b){var c=b.defaultLang,e=void 0===c?"en":c,f=b.providedLangs,g=void 0===f?["en"]:f,h=b.detectLanguageOnStart,i=void 0===h||h,j=b.loader,k=void 0===j?d.TranslateLoaderJson:j,l=b.loaderConfig,m=void 0===l?{}:l;this.defaultLang=g.indexOf(e)>-1?e:g[0],this.providedLangs=g,this.detectLanguageOnStart=i,this.loader=k,this.loaderConfig=m,this.navigatorLanguages=function(){var b=a.navigator;return b.languages instanceof Array?Array.prototype.slice.call(b.languages):[b.languages||b.language||b.browserLanguage||b.userLanguage].filter(function(a){return"string"==typeof a})}()}return a.prototype.langProvided=function(a,b){void 0===b&&(b=!1);var c,d=!1,e=function(a){var b=/^([A-Za-z]{2})(?:[\.\-_\/]?([A-Za-z]{2}))?$/;return a.match(b)?a.replace(b,function(a,b,c){return void 0===c&&(c=""),b=b.toLowerCase(),c=c.toUpperCase(),c?b+"-"+c:b}):""},f=this.providedLangs.map(e);return a=e(a),0===a.length?d:(c=f.indexOf(a),c>-1?d=this.providedLangs[c]:b||(a=a.substr(0,2),c=f.indexOf(a),c>-1?d=this.providedLangs[c]:(c=f.map(function(a){return a.substr(0,2)}).indexOf(a),c>-1&&(d=this.providedLangs[c]))),d)},a}();e.navigator=window&&window.navigator?window.navigator:{},b.TranslateConfig=e}),$__System.registerDynamic("13",[],!0,function(a,b,c){"use strict";this||self;Object.defineProperty(b,"__esModule",{value:!0});var d=function(){function a(){}return a.prototype.error=function(a){console&&console.error&&console.error(a)},a.prototype.info=function(a){},a.prototype.debug=function(a){},a}();b.TranslateLogHandler=d}),$__System.registerDynamic("c",["12","13","d","14","15"],!0,function($__require,exports,module){"use strict";var global=this||self,GLOBAL=global,__decorate=exports&&exports.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g},__metadata=exports&&exports.__metadata||function(a,b){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(a,b)};Object.defineProperty(exports,"__esModule",{value:!0});var TranslateConfig_1=$__require("12"),TranslateLogHandler_1=$__require("13"),core_1=$__require("d"),Observable_1=$__require("14");$__require("15");var TranslateService=function(){function TranslateService(a,b,c){var d=this;if(this.logHandler=a,this.config=b,this.injector=c,this._loadedLangs={},this._translations={},this.config=b,this.logHandler=a,this.loader=c.get(b.loader),this.loader.configure(b.loaderConfig),this._lang=b.defaultLang,b.detectLanguageOnStart){var e=this.detectLang(b.navigatorLanguages);e&&(this._lang=String(e),a.info("Language "+e+" got detected"))}this.languageChanged=new Observable_1.Observable(function(a){return d._languageChangedObserver=a}).share()}return Object.defineProperty(TranslateService.prototype,"lang",{get:function(){return this._lang},set:function(a){var b=this.config.langProvided(a,!0);if("string"==typeof b)return this._lang=b,this.logHandler.info("Language changed to "+b),void(this._languageChangedObserver&&this._languageChangedObserver.next(this._lang));throw new Error("Language not provided")},enumerable:!0,configurable:!0}),TranslateService.prototype.detectLang=function(a){var b,c=!1;for(this.logHandler.debug("Detecting language from "+JSON.stringify(a)+" in strict mode."),b=0;b0)return this.logHandler.error("Parse error only first parameter can be passed as params in '"+a+"'"),"";j="wait_getter"}break;case"read_param_key":if(b[e].match(/[A-Za-z0-9_]/))g+=b[e];else if("="===b[e])j="wait_getter";else if(","===b[e])l(!1),j="wait_param";else{if(!b[e].match(/\s/))return this._referencedError(a,"character","comma, equal sign or end",e);j="param_key_readed"}break;case"param_key_readed":if(b[e].match(/\s/));else if("="===b[e])j="wait_getter";else{if(","!==b[e])return this._referencedError(a,"character","comma, equal sign or end",e);l(!1),j="wait_param"}break;case"wait_getter":if(b[e].match(/\s/));else{if(!b[e].match(/[A-Za-z0-9_]/))return this._referencedError(a,"character","getter",e);j="read_getter",h=b[e]}break;case"read_getter":if(b[e].match(/[A-Za-z0-9_.]/))h+=b[e];else if(b[e].match(/\s/))j="getter_readed";else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}break;case"getter_readed":if(b[e].match(/\s/));else{if(","!==b[e])return this._referencedError(a,"character","comma or end",e);l(),j="wait_param"}}switch(j){case"param_key_readed":case"read_param_key":l(!1);break;case"getter_readed":case"read_getter":l();break;case"wait_key":return this._referencedError(a,"end","key");case"wait_param":return this._referencedError(a,"end","parameter");case"wait_getter":return this._referencedError(a,"end","getter")}return String(this.instant(f,k,d))},TranslateService}();TranslateService=__decorate([core_1.Injectable(),__metadata("design:paramtypes",[TranslateLogHandler_1.TranslateLogHandler,TranslateConfig_1.TranslateConfig,core_1.Injector])],TranslateService),exports.TranslateService=TranslateService}),$__System.registerDynamic("16",["b","12","10","13","e","c","d","11"],!0,function(a,b,c){"use strict";var d=(this||self,b&&b.__decorate||function(a,b,c,d){var e,f=arguments.length,g=f<3?b:null===d?d=Object.getOwnPropertyDescriptor(b,c):d;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)g=Reflect.decorate(a,b,c,d);else for(var h=a.length-1;h>=0;h--)(e=a[h])&&(g=(f<3?e(g):f>3?e(b,c,g):e(b,c))||g);return f>3&&g&&Object.defineProperty(b,c,g),g});Object.defineProperty(b,"__esModule",{value:!0});var e=a("b"),f=a("12"),g=a("10"),h=a("13"),i=a("e"),j=a("c"),k=a("d"),l=a("11"),m=function(){function a(){}return a}();m=d([k.NgModule({declarations:[i.TranslatePipe,e.TranslateComponent],exports:[i.TranslatePipe,e.TranslateComponent],imports:[l.HttpModule],providers:[{provide:f.TranslateConfig,useValue:new f.TranslateConfig({})},g.TranslateLoaderJson,h.TranslateLogHandler,j.TranslateService]})],m),b.TranslatorModule=m}),$__System.registerDynamic("a",["c","e","b","12","f","10","13","16"],!0,function(a,b,c){"use strict";function d(a){for(var c in a)b.hasOwnProperty(c)||(b[c]=a[c])}this||self;Object.defineProperty(b,"__esModule",{value:!0}),d(a("c")),d(a("e")),d(a("b")),d(a("12")),d(a("f")),d(a("10")),d(a("13")),d(a("16"))})})(function(a){if("function"==typeof define&&define.amd)define(["@angular/core","@angular/http","rxjs/Observable","rxjs/add/operator/share"],a);else{if("object"!=typeof module||!module.exports||"function"!=typeof require)throw new Error("Module must be loaded as AMD or CommonJS");module.exports=a(require("@angular/core"),require("@angular/http"),require("rxjs/Observable"),require("rxjs/add/operator/share"))}}); //# sourceMappingURL=angular2-translator.js.map \ No newline at end of file diff --git a/src/TranslateService.ts b/src/TranslateService.ts index 8f59bca..95c60b7 100644 --- a/src/TranslateService.ts +++ b/src/TranslateService.ts @@ -104,7 +104,7 @@ export class TranslateService { public waitForTranslation(lang: string = this._lang): Promise { let l = this.config.langProvided(lang, true); if (!l) { - return Promise.reject("Language not provided"); + return Promise.reject("Language " + lang + " not provided"); } else { lang = String(l); } @@ -160,6 +160,9 @@ export class TranslateService { let l = this.config.langProvided(lang, true); if (l) { lang = String(l); + } else { + this.logHandler.error("Language " + lang + " not provided"); + return keys; } } @@ -259,16 +262,14 @@ export class TranslateService { * @returns {string} * @private */ - private _referencedError(sub: string, unexpected: string, expected?: string, pos?: number): string { + private _referencedError(sub: string, unexpected: string, expected: string, pos?: number): string { let msg = "Parse error unexpected " + unexpected; if (pos !== undefined) { msg += " at pos " + (pos + 3); } - if (expected) { - msg += " expected " + expected; - } + msg += " expected " + expected; this.logHandler.error(msg + " in '" + sub + "'"); return ""; diff --git a/src/TranslatorModule.ts b/src/TranslatorModule.ts index 7d5d672..dfd9205 100644 --- a/src/TranslatorModule.ts +++ b/src/TranslatorModule.ts @@ -1,6 +1,5 @@ import {TranslateComponent} from "./TranslateComponent"; import {TranslateConfig} from "./TranslateConfig"; -import {TranslateLoader} from "./TranslateLoader"; import {TranslateLoaderJson} from "./TranslateLoaderJson"; import {TranslateLogHandler} from "./TranslateLogHandler"; import {TranslatePipe} from "./TranslatePipe"; @@ -21,16 +20,9 @@ import {HttpModule} from "@angular/http"; imports: [HttpModule], providers: [ { provide: TranslateConfig, useValue: new TranslateConfig({}) }, - { provide: TranslateLoaderJson, useClass: TranslateLoaderJson }, - { provide: TranslateLogHandler, useClass: TranslateLogHandler }, + TranslateLoaderJson, + TranslateLogHandler, TranslateService, ], }) export class TranslatorModule {} - -export const TRANSLATE_PROVIDERS: any[] = [ - { provide: TranslateConfig, useValue: new TranslateConfig({}) }, - { provide: TranslateLoader, useClass: TranslateLoaderJson }, - { provide: TranslateLogHandler, useValue: TranslateLogHandler }, - TranslateService, -]; diff --git a/tests/TranslateComponent.spec.ts b/tests/TranslateComponent.spec.ts index e9fd3cd..e405d46 100644 --- a/tests/TranslateComponent.spec.ts +++ b/tests/TranslateComponent.spec.ts @@ -1,20 +1,20 @@ import { - TRANSLATE_PROVIDERS, TranslateComponent, TranslateConfig, - TranslateLoader, TranslateLogHandler, TranslateService, + TranslatorModule, } from "../index"; -import {JasmineHelper} from "./helper/JasmineHelper"; -import {TranslateLoaderMock} from "./helper/TranslateLoaderMock"; -import {ReflectiveInjector} from "@angular/core"; -import {fakeAsync, flushMicrotasks} from "@angular/core/testing"; +import {JasmineHelper} from "./helper/JasmineHelper"; +import {TranslateLoaderMock} from "./helper/TranslateLoaderMock"; +import {TranslateLogHandlerMock} from "./helper/TranslatorMocks"; +import {ReflectiveInjector} from "@angular/core"; +import {TestBed, fakeAsync, flushMicrotasks} from "@angular/core/testing"; -describe("TranslateComponent", function() { +describe("TranslateComponent", () => { - describe("constructor", function() { + describe("constructor", () => { it("requires a TranslateService", function () { let injector = ReflectiveInjector.resolveAndCreate([ TranslateComponent ]); @@ -28,36 +28,39 @@ describe("TranslateComponent", function() { }); }); - describe("instance", function() { + describe("instance", () => { let translate: TranslateService; let translateComponent: TranslateComponent; let logHandler: TranslateLogHandler; - beforeEach(function() { - let injector = ReflectiveInjector.resolveAndCreate([ - TRANSLATE_PROVIDERS, - { provide: TranslateLoader, useValue: new TranslateLoaderMock() }, - { provide: TranslateConfig, useValue: new TranslateConfig( { - providedLangs: [ "en", "de" ], - } ) }, - { provide: TranslateLogHandler, useValue: new TranslateLogHandler() }, - ]); - - translate = injector.get(TranslateService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TranslatorModule], + providers: [ + TranslateLoaderMock, + { provide: TranslateLogHandler, useClass: TranslateLogHandlerMock }, + { provide: TranslateConfig, useValue: new TranslateConfig( { + loader: TranslateLoaderMock, + providedLangs: [ "en", "de" ], + } ) }, + ], + }); + + translate = TestBed.get(TranslateService); translateComponent = new TranslateComponent(translate); - logHandler = injector.get(TranslateLogHandler); + logHandler = TestBed.get(TranslateLogHandler); spyOn(translate, "translate").and.returnValue(Promise.resolve("This is a text")); spyOn(logHandler, "error"); }); - it("starts translation when key got set", function() { + it("starts translation when key got set", () => { translateComponent.key = "TEXT"; expect(translate.translate).toHaveBeenCalledWith("TEXT", {}); }); - it("starts translation when key is set and params got changed", function() { + it("starts translation when key is set and params got changed", () => { translateComponent.key = "TEXT"; JasmineHelper.calls(translate.translate).reset(); @@ -66,7 +69,7 @@ describe("TranslateComponent", function() { expect(translate.translate).toHaveBeenCalledWith("TEXT", { some: "value" }); }); - it("restarts translation when key got changed", function() { + it("restarts translation when key got changed", () => { translateComponent.key = "ANYTHING"; translateComponent.params = { some: "value" }; JasmineHelper.calls(translate.translate).reset(); @@ -76,13 +79,13 @@ describe("TranslateComponent", function() { expect(translate.translate).toHaveBeenCalledWith("TEXT", { some: "value" }); }); - it("does not translate when key got not set", function() { + it("does not translate when key got not set", () => { translateComponent.params = { some: "value" }; expect(translate.translate).not.toHaveBeenCalled(); }); - it("does not accept non-object params", function() { + it("does not accept non-object params", () => { translateComponent.key = "TEXT"; JasmineHelper.calls(translate.translate).reset(); @@ -91,7 +94,7 @@ describe("TranslateComponent", function() { expect(translate.translate).not.toHaveBeenCalled(); }); - it("stores translation when promise got resolved", fakeAsync(function() { + it("stores translation when promise got resolved", fakeAsync(() => { translateComponent.key = "TEXT"; flushMicrotasks(); @@ -99,7 +102,7 @@ describe("TranslateComponent", function() { expect(translateComponent.translation).toBe("This is a text"); })); - it("restarts translation when language got changed", function() { + it("restarts translation when language got changed", () => { translateComponent.key = "TEXT"; JasmineHelper.calls(translate.translate).reset(); @@ -108,7 +111,7 @@ describe("TranslateComponent", function() { expect(translate.translate).toHaveBeenCalledWith("TEXT", {}); }); - it("shows error if params are not object", function() { + it("shows error if params are not object", () => { translateComponent.params = "foo"; expect(logHandler.error).toHaveBeenCalledWith("Params have to be an object"); diff --git a/tests/TranslateConfig.spec.ts b/tests/TranslateConfig.spec.ts index 41a39f2..72b038a 100644 --- a/tests/TranslateConfig.spec.ts +++ b/tests/TranslateConfig.spec.ts @@ -1,7 +1,7 @@ import {TranslateConfig} from "../index"; -describe("TranslateConfig", function() { - it("is defined", function() { +describe("TranslateConfig", () => { + it("is defined", () => { let translateConfig = new TranslateConfig({}); expect(TranslateConfig).toBeDefined(); @@ -9,7 +9,7 @@ describe("TranslateConfig", function() { expect(translateConfig instanceof TranslateConfig).toBeTruthy(); }); - it("gets default language from parameter defaultLang", function() { + it("gets default language from parameter defaultLang", () => { let translateConfig = new TranslateConfig({ defaultLang: "cn", providedLangs: [ "en", "cn" ], @@ -18,19 +18,19 @@ describe("TranslateConfig", function() { expect(translateConfig.defaultLang).toBe("cn"); }); - it("defines a list of provided languages", function() { + it("defines a list of provided languages", () => { let translateConfig = new TranslateConfig({}); expect(translateConfig.providedLangs).toEqual(["en"]); }); - it("gets provided languages from parameter providedLangs", function() { + it("gets provided languages from parameter providedLangs", () => { let translateConfig = new TranslateConfig({ providedLangs: [ "cn" ] }); expect(translateConfig.providedLangs).toEqual([ "cn" ]); }); - it("uses first provided language", function() { + it("uses first provided language", () => { let translateConfig = new TranslateConfig({ defaultLang: "en", // default - unnecessary providedLangs: [ "cn" ], @@ -39,14 +39,14 @@ describe("TranslateConfig", function() { expect(translateConfig.defaultLang).toBe("cn"); }); - describe("navigatorLanguages", function() { - it("is always an array", function() { + describe("navigatorLanguages", () => { + it("is always an array", () => { let translateConfig = new TranslateConfig({}); expect(translateConfig.navigatorLanguages instanceof Array).toBe(true); }); - it("uses navigator.languages when given", function() { + it("uses navigator.languages when given", () => { TranslateConfig.navigator = { languages: [ "bm", "de", "fr", "en" ] }; let translateConfig = new TranslateConfig({}); @@ -54,7 +54,7 @@ describe("TranslateConfig", function() { expect(translateConfig.navigatorLanguages).toEqual([ "bm", "de", "fr", "en" ]); }); - it("transforms navigator.languages to Array if it is String", function() { + it("transforms navigator.languages to Array if it is String", () => { TranslateConfig.navigator = { languages: "bm" }; let translateConfig = new TranslateConfig({}); @@ -62,7 +62,7 @@ describe("TranslateConfig", function() { expect(translateConfig.navigatorLanguages).toEqual([ "bm" ]); }); - it("falls back to navigator.language", function() { + it("falls back to navigator.language", () => { TranslateConfig.navigator = {language: "fr"}; let translateConfig = new TranslateConfig({}); @@ -71,14 +71,14 @@ describe("TranslateConfig", function() { }); }); - describe("langProvided", function() { + describe("langProvided", () => { let translateConfig: TranslateConfig; - beforeEach(function() { + beforeEach(() => { translateConfig = new TranslateConfig({}); }); - it("returns the language if provided", function() { + it("returns the language if provided", () => { translateConfig.providedLangs = ["bm", "en"]; let providedLang = translateConfig.langProvided("bm"); @@ -86,7 +86,7 @@ describe("TranslateConfig", function() { expect(providedLang).toBe("bm"); }); - it("returns false when it is not provided", function() { + it("returns false when it is not provided", () => { translateConfig.providedLangs = ["en"]; let providedLang = translateConfig.langProvided("bm"); @@ -94,7 +94,7 @@ describe("TranslateConfig", function() { expect(providedLang).toBeFalsy(); }); - it("returns provided language when we search with country", function() { + it("returns provided language when we search with country", () => { translateConfig.providedLangs = ["en"]; let providedLang = translateConfig.langProvided("en-US"); @@ -102,7 +102,7 @@ describe("TranslateConfig", function() { expect(providedLang).toBe("en"); }); - it("returns the first provided country specific language", function() { + it("returns the first provided country specific language", () => { translateConfig.providedLangs = ["de-DE", "de-AT"]; let providedLang = translateConfig.langProvided("de-CH"); @@ -110,7 +110,7 @@ describe("TranslateConfig", function() { expect(providedLang).toBe("de-DE"); }); - it("normalizes provided languages for checks", function() { + it("normalizes provided languages for checks", () => { translateConfig.providedLangs = [ "DE", "DE_AT" ]; let providedLang = translateConfig.langProvided("de-AT"); @@ -118,7 +118,7 @@ describe("TranslateConfig", function() { expect(providedLang).toBe("DE_AT"); }); - it("normalizes searched language", function() { + it("normalizes searched language", () => { translateConfig.providedLangs = [ "de-DE", "de-AT" ]; let providedLang = translateConfig.langProvided("DE/de"); @@ -126,7 +126,7 @@ describe("TranslateConfig", function() { expect(providedLang).toBe("de-DE"); }); - it("only finds direct matches", function() { + it("only finds direct matches", () => { translateConfig.providedLangs = ["de-DE"]; let providedLang = translateConfig.langProvided("de", true); @@ -134,7 +134,7 @@ describe("TranslateConfig", function() { expect(providedLang).toBeFalsy(); }); - it("only takes valid matches", function() { + it("only takes valid matches", () => { translateConfig.providedLangs = [ "br", "en" ]; let providedLang = translateConfig.langProvided("british"); diff --git a/tests/TranslateLoader.spec.ts b/tests/TranslateLoader.spec.ts index 990d63c..9452698 100644 --- a/tests/TranslateLoader.spec.ts +++ b/tests/TranslateLoader.spec.ts @@ -1,7 +1,7 @@ import {TranslateLoader} from "../index"; -describe("TranslateLoader", function() { - it("is defined", function() { +describe("TranslateLoader", () => { + it("is defined", () => { expect(TranslateLoader).toBeDefined(); }); diff --git a/tests/TranslateLoaderJson.spec.ts b/tests/TranslateLoaderJson.spec.ts index e5f6dce..1267b47 100644 --- a/tests/TranslateLoaderJson.spec.ts +++ b/tests/TranslateLoaderJson.spec.ts @@ -64,6 +64,21 @@ describe("TranslateLoaderJson", function () { expect(request.method).toBe(RequestMethod.Get); }); + it("can be configured", () => { + spyOn(backend, "createConnection").and.callThrough(); + + loader.configure({ + extension: "-lang.json", + path: "app/translations", + }); + loader.load("en"); + + expect(backend.createConnection).toHaveBeenCalled(); + let request = JasmineHelper.calls(backend.createConnection).mostRecent().args[0]; + expect(request.url).toBe("app/translations/en-lang.json"); + expect(request.method).toBe(RequestMethod.Get); + }); + it("resolves when connection responds", function () { let promise = loader.load("en"); diff --git a/tests/TranslateLogHandler.spec.ts b/tests/TranslateLogHandler.spec.ts index 16b978e..c469ee7 100644 --- a/tests/TranslateLogHandler.spec.ts +++ b/tests/TranslateLogHandler.spec.ts @@ -11,4 +11,17 @@ describe("TranslateLogHandler", () => { expect(console.error).toHaveBeenCalledWith("This was bad"); }); + + it("does not throw when console.error is undefined", () => { + let logHandler: TranslateLogHandler = new TranslateLogHandler(); + let error = console.error; + + delete console.error; + let action = function action() { + logHandler.error("This was bad"); + }; + + expect(action).not.toThrow(); + console.error = error; + }); }); diff --git a/tests/TranslatePipe.spec.ts b/tests/TranslatePipe.spec.ts index 6c50c5e..acb31e2 100644 --- a/tests/TranslatePipe.spec.ts +++ b/tests/TranslatePipe.spec.ts @@ -1,16 +1,16 @@ import { - TRANSLATE_PROVIDERS, TranslateConfig, - TranslateLoader, TranslateLogHandler, TranslatePipe, TranslateService, + TranslatorModule, } from "../index"; -import {JasmineHelper} from "./helper/JasmineHelper"; -import {TranslateLoaderMock} from "./helper/TranslateLoaderMock"; -import {ReflectiveInjector} from "@angular/core"; -import {fakeAsync, flushMicrotasks} from "@angular/core/testing"; +import {JasmineHelper} from "./helper/JasmineHelper"; +import {TranslateLoaderMock} from "./helper/TranslateLoaderMock"; +import {TranslateLogHandlerMock} from "./helper/TranslatorMocks"; +import {ReflectiveInjector} from "@angular/core"; +import {TestBed, fakeAsync, flushMicrotasks} from "@angular/core/testing"; describe("TranslatePipe", () => { it("is defined", () => { @@ -36,62 +36,65 @@ describe("TranslatePipe", () => { let translatePipe: TranslatePipe; let logHandler: TranslateLogHandler; - beforeEach(function() { - let injector = ReflectiveInjector.resolveAndCreate([ - TRANSLATE_PROVIDERS, - { provide: TranslateLoader, useValue: new TranslateLoaderMock() }, - { provide: TranslateConfig, useValue: new TranslateConfig( { - providedLangs: [ "en", "de" ], - } ) }, - { provide: TranslateLogHandler, useValue: new TranslateLogHandler() }, - ]); - - translate = injector.get(TranslateService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TranslatorModule], + providers: [ + TranslateLoaderMock, + { provide: TranslateLogHandler, useClass: TranslateLogHandlerMock }, + { provide: TranslateConfig, useValue: new TranslateConfig( { + loader: TranslateLoaderMock, + providedLangs: [ "en", "de" ], + } ) }, + ], + }); + + translate = TestBed.get(TranslateService); translatePipe = new TranslatePipe(translate); - logHandler = injector.get(TranslateLogHandler); + logHandler = TestBed.get(TranslateLogHandler); spyOn(translate, "translate").and.returnValue(Promise.resolve("This is a text")); spyOn(logHandler, "error"); }); - it("returns an empty string", function() { + it("returns an empty string", () => { let translation = translatePipe.transform("TEXT"); expect(translation).toBe(""); }); - it("calls translate to get translation", function() { + it("calls translate to get translation", () => { translatePipe.transform("TEXT"); expect(translate.translate).toHaveBeenCalledWith("TEXT", {}); }); - it("calls translate only once", function() { + it("calls translate only once", () => { translatePipe.transform("TEXT"); translatePipe.transform("TEXT"); expect(JasmineHelper.calls(translate.translate).count()).toBe(1); }); - it("gets params from args[0]", function() { + it("gets params from args[0]", () => { translatePipe.transform("TEXT", [{ some: "value" }]); expect(translate.translate).toHaveBeenCalledWith("TEXT", { some: "value" }); }); - it("evaluates args[0] to get object", function() { + it("evaluates args[0] to get object", () => { translatePipe.transform("TEXT", ["{some:'value'}"]); expect(translate.translate).toHaveBeenCalledWith("TEXT", { some: "value" }); }); - it("calls with empty object if args[0] got not evaluated to object", function() { + it("calls with empty object if args[0] got not evaluated to object", () => { translatePipe.transform("TEXT", ["'value'"]); expect(translate.translate).toHaveBeenCalledWith("TEXT", {}); }); - it("returns translation when promise got resolved", fakeAsync(function() { + it("returns translation when promise got resolved", fakeAsync(() => { translatePipe.transform("TEXT"); flushMicrotasks(); @@ -100,7 +103,7 @@ describe("TranslatePipe", () => { expect(translation).toBe("This is a text"); })); - it("calls translate again when key changes", function() { + it("calls translate again when key changes", () => { translatePipe.transform("ANYTHING"); translatePipe.transform("TEXT"); @@ -109,7 +112,7 @@ describe("TranslatePipe", () => { expect(JasmineHelper.calls(translate.translate).count()).toBe(2); }); - it("calls translate again when params changes", function() { + it("calls translate again when params changes", () => { translatePipe.transform("TEXT", [{ some: "value" }]); translatePipe.transform("TEXT", [{ some: "otherValue" }]); @@ -118,7 +121,7 @@ describe("TranslatePipe", () => { expect(JasmineHelper.calls(translate.translate).count()).toBe(2); }); - it("calls translate again when language got changed", function() { + it("calls translate again when language got changed", () => { translatePipe.transform("TEXT"); translate.lang = "de"; @@ -126,10 +129,22 @@ describe("TranslatePipe", () => { expect(JasmineHelper.calls(translate.translate).count()).toBe(2); }); - it("shows error if params could not be parsed", function() { + it("shows error if params could not be parsed", () => { translatePipe.transform("TEXT", ["{baefa}"]); expect(logHandler.error).toHaveBeenCalledWith("'{baefa}' could not be parsed to object"); }); + + it("ignores params that are not object or string", () => { + translatePipe.transform("TEXT", [42]); + + expect(translate.translate).toHaveBeenCalledWith("TEXT", {}); + }); + + it("does not translate when no values given", () => { + translate.lang = "de"; + + expect(translate.translate).not.toHaveBeenCalled(); + }); }); }); diff --git a/tests/TranslateService.spec.ts b/tests/TranslateService.spec.ts index 2501cd1..fefddae 100644 --- a/tests/TranslateService.spec.ts +++ b/tests/TranslateService.spec.ts @@ -43,7 +43,7 @@ describe("TranslateService", function () { expect(action).toThrow(); }); - it("requires an TranslateLogHandler", function() { + it("requires an TranslateLogHandler", () => { let injector = ReflectiveInjector.resolveAndCreate([ TranslateService, TranslateLoaderMock, @@ -86,7 +86,7 @@ describe("TranslateService", function () { expect(translate.lang).toBe("en"); }); - it("detects language automatically on start", function() { + it("detects language automatically on start", () => { let translateConfig = new TranslateConfig({ providedLangs: [ "en", "de" ], }); @@ -104,7 +104,26 @@ describe("TranslateService", function () { expect(translate.lang).toBe("de"); }); - it("informs about detected language", function() { + it("does not detect language on start by configuration", () => { + let translateConfig = new TranslateConfig({ + detectLanguageOnStart: false, + providedLangs: [ "en", "de" ], + }); + translateConfig.navigatorLanguages = ["de-DE", "de", "en-US", "en"]; + + TestBed.configureTestingModule({ + imports: [TranslatorModule], + providers: [ + { provide: TranslateConfig, useValue: translateConfig }, + ], + }); + + let translate: TranslateService = TestBed.get(TranslateService); + + expect(translate.lang).toBe("en"); + }); + + it("informs about detected language", () => { let translateConfig = new TranslateConfig({ providedLangs: [ "en", "de" ], }); @@ -132,8 +151,9 @@ describe("TranslateService", function () { let loader: TranslateLoader; beforeEach(function () { - translateConfig.providedLangs = ["en"]; + translateConfig.providedLangs = ["en", "de"]; translateConfig.defaultLang = "en"; + translateConfig.detectLanguageOnStart = false; TestBed.configureTestingModule({ imports: [TranslatorModule], @@ -148,7 +168,7 @@ describe("TranslateService", function () { PromiseMatcher.install(); }); - afterEach(function() { + afterEach(() => { PromiseMatcher.uninstall(); }); @@ -190,6 +210,15 @@ describe("TranslateService", function () { expect(detectedLang).toBe("de-AT"); }); + + it("stops when language got found", function() { + translateConfig.providedLangs = [ "de-DE", "en-US" ]; + spyOn(translateConfig, "langProvided").and.callThrough(); + + translate.detectLang(["de", "en"]); + + expect(translateConfig.langProvided).not.toHaveBeenCalledWith("en"); + }); }); describe("change language", function () { @@ -212,18 +241,18 @@ describe("TranslateService", function () { it("throws error if language is not provided", function () { translateConfig.providedLangs = ["de/de"]; - let action = function() { + let action = () => { translate.lang = "de"; }; expect(action).toThrow(new Error("Language not provided")); }); - it("has an observable", function() { + it("has an observable", () => { expect(translate.languageChanged instanceof Observable).toBe(true); }); - it("gives the next value to the observable", function() { + it("gives the next value to the observable", () => { translateConfig.providedLangs = ["en", "de"]; let newLang: string; translate.languageChanged.subscribe(function(nextLang) { @@ -236,7 +265,7 @@ describe("TranslateService", function () { expect(newLang).toBe("de"); }); - it("informs about language change", function() { + it("informs about language change", () => { spyOn(translate.logHandler, "info"); translateConfig.providedLangs = [ "de/de" ]; @@ -250,7 +279,7 @@ describe("TranslateService", function () { let loaderPromiseResolve: Function; let loaderPromiseReject: Function; - beforeEach(function() { + beforeEach(() => { spyOn(loader, "load").and.returnValue(new Promise((resolve, reject) => { loaderPromiseResolve = resolve; loaderPromiseReject = reject; @@ -269,7 +298,7 @@ describe("TranslateService", function () { expect(loader.load).toHaveBeenCalledWith("en"); }); - it("resolves when loader resolves", fakeAsync(function() { + it("resolves when loader resolves", fakeAsync(() => { let promise = translate.waitForTranslation(); loaderPromiseResolve({ TEXT: "This is a text" }); @@ -278,7 +307,7 @@ describe("TranslateService", function () { expect(promise).toBeResolved(); })); - it("rejects when loader rejects", fakeAsync(function() { + it("rejects when loader rejects", fakeAsync(() => { translate.logHandler.error = () => {}; let promise = translate.waitForTranslation(); @@ -288,14 +317,14 @@ describe("TranslateService", function () { expect(promise).toBeRejected(); })); - it("loads a language only once", function() { + it("loads a language only once", () => { translate.waitForTranslation(); translate.waitForTranslation(); expect(JasmineHelper.calls(loader.load).count()).toBe(1); }); - it("returns the already resolved promise", fakeAsync(function() { + it("returns the already resolved promise", fakeAsync(() => { let firstPromise = translate.waitForTranslation(); loaderPromiseResolve({ TEXT: "This is a text" }); JasminePromise.flush(); @@ -306,7 +335,7 @@ describe("TranslateService", function () { expect(secondPromise).toBe(firstPromise); })); - it("loads given language", function() { + it("loads given language", () => { translateConfig.providedLangs = ["en", "de"]; translate.waitForTranslation("de"); @@ -314,7 +343,7 @@ describe("TranslateService", function () { expect(loader.load).toHaveBeenCalledWith("de"); }); - it("checks if the language is provided", function() { + it("checks if the language is provided", () => { spyOn(translateConfig, "langProvided"); translate.waitForTranslation("de"); @@ -322,13 +351,13 @@ describe("TranslateService", function () { expect(translateConfig.langProvided).toHaveBeenCalledWith("de", true); }); - it("rejects if the language is not provided", function() { - let promise = translate.waitForTranslation("de"); + it("rejects if the language is not provided", () => { + let promise = translate.waitForTranslation("ru"); - expect(promise).toBeRejectedWith("Language not provided"); + expect(promise).toBeRejectedWith("Language ru not provided"); }); - it("informs about loaded language", fakeAsync(function() { + it("informs about loaded language", fakeAsync(() => { spyOn(translate.logHandler, "info"); translate.waitForTranslation(); @@ -338,7 +367,7 @@ describe("TranslateService", function () { expect(translate.logHandler.info).toHaveBeenCalledWith("Language en got loaded"); })); - it("shows error when language could not be loaded", fakeAsync(function() { + it("shows error when language could not be loaded", fakeAsync(() => { spyOn(translate.logHandler, "error").and.callFake(() => {}); translate.waitForTranslation(); @@ -350,24 +379,24 @@ describe("TranslateService", function () { })); }); - describe("translate", function() { + describe("translate", () => { let loaderPromiseResolve: Function; let loaderPromiseReject: Function; - beforeEach(function() { + beforeEach(() => { spyOn(loader, "load").and.returnValue(new Promise((resolve, reject) => { loaderPromiseResolve = resolve; loaderPromiseReject = reject; })); }); - it("loads the current language", function() { + it("loads the current language", () => { translate.translate("TEXT"); expect(loader.load).toHaveBeenCalledWith("en"); }); - it("loads the given language", function() { + it("loads the given language", () => { translateConfig.providedLangs = ["en", "de"]; translate.translate("TEXT", {}, "de"); @@ -375,7 +404,7 @@ describe("TranslateService", function () { expect(loader.load).toHaveBeenCalledWith("de"); }); - it("checks if the language is provided", function() { + it("checks if the language is provided", () => { spyOn(translateConfig, "langProvided"); translate.translate("TEXT", {}, "de"); @@ -384,7 +413,7 @@ describe("TranslateService", function () { }); // current language got checked before - it("does not check current language", function() { + it("does not check current language", () => { spyOn(translateConfig, "langProvided"); translate.translate("TEXT"); @@ -392,20 +421,20 @@ describe("TranslateService", function () { expect(translateConfig.langProvided).not.toHaveBeenCalled(); }); - it("loads a language only once", function() { + it("loads a language only once", () => { translate.translate("TEXT"); translate.translate("OTHER_TEXT"); expect(JasmineHelper.calls(loader.load).count()).toBe(1); }); - it("resolves keys if language is not provided", function() { - let promise = translate.translate("TEXT", {}, "de"); + it("resolves keys if language is not provided", () => { + let promise = translate.translate("TEXT", {}, "ru"); expect(promise).toBeResolvedWith("TEXT"); }); - it("resolves keys if laguage could not be loaded", fakeAsync(function() { + it("resolves keys if laguage could not be loaded", fakeAsync(() => { translate.logHandler.error = () => {}; let promise = translate.translate(["TEXT", "OTHER_TEXT"]); @@ -415,7 +444,7 @@ describe("TranslateService", function () { expect(promise).toBeResolvedWith(["TEXT", "OTHER_TEXT"]); })); - it("uses instant to translate after loader resolves", fakeAsync(function() { + it("uses instant to translate after loader resolves", fakeAsync(() => { spyOn(translate, "instant"); translate.translate("TEXT"); @@ -425,7 +454,7 @@ describe("TranslateService", function () { expect(translate.instant).toHaveBeenCalledWith("TEXT", {}, translate.lang); })); - it("resolves with the return value from instant", fakeAsync(function() { + it("resolves with the return value from instant", fakeAsync(() => { spyOn(translate, "instant").and.returnValue("This is a text"); let promise = translate.translate("TEXT"); @@ -435,32 +464,50 @@ describe("TranslateService", function () { })); }); - describe("instant", function() { + describe("instant", () => { // noinspection JSUnusedLocalSymbols let loaderPromiseResolve: Function = (t: Object) => {}; - beforeEach(fakeAsync(function() { - spyOn(loader, "load").and.returnValue(new Promise((resolve) => { - loaderPromiseResolve = resolve; - })); + beforeEach(fakeAsync(() => { + spyOn(loader, "load").and.callFake(() => { + return new Promise((resolve) => { + loaderPromiseResolve = resolve; + }); + }); })); - it("returns keys if language is not loaded", function() { - let translation = translate.instant("TEXT", {}, "de"); + it("returns keys if language is not provided", () => { + spyOn(translate.logHandler, "error"); + + let translation = translate.instant("TEXT", {}, "ru"); expect(translation).toBe("TEXT"); + expect(translate.logHandler.error).toHaveBeenCalledWith("Language ru not provided"); }); - it("returns keys if translation not found", function() { + it("returns keys if translation not found", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({}); + JasminePromise.flush(); let translations = translate.instant(["SOME_TEXT", "OTHER_TEXT"]); expect(translations).toEqual(["SOME_TEXT", "OTHER_TEXT"]); - }); + })); - it("returns interpolated text", fakeAsync(function() { + it("translates in different language", fakeAsync(() => { + translate.waitForTranslation("de"); + loaderPromiseResolve({ + HELLO_WORLD: "Hallo Welt!", + }); + JasminePromise.flush(); + + let translations = translate.instant("HELLO_WORLD", {}, "de"); + + expect(translations).toEqual("Hallo Welt!"); + })); + + it("returns interpolated text", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ INTERPOLATION: "The sum from 1+2 is {{1+2}}", @@ -488,7 +535,7 @@ describe("TranslateService", function () { ]); })); - it("catches parse errors in translations", fakeAsync(function() { + it("catches parse errors in translations", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ BROKEN: 'This "{{notExisting.func()}}" is empty string', @@ -501,7 +548,7 @@ describe("TranslateService", function () { expect(translation).toBe('This "" is empty string'); })); - it("does not throw if variable is not existent", fakeAsync(function() { + it("does not throw if variable is not existent", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ PROP: "{{another.one}}", @@ -515,8 +562,8 @@ describe("TranslateService", function () { expect(translate.logHandler.error).not.toHaveBeenCalled(); })); - describe("referenced translations", function() { - it("removes valid translation references", fakeAsync(function() { + describe("referenced translations", () => { + it("removes valid translation references", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ WELCOME: "Welcome [[]]!", @@ -529,7 +576,7 @@ describe("TranslateService", function () { expect(translation).toBe("Welcome !"); })); - it("logs an error if reference has no key", fakeAsync(function() { + it("logs an error if reference has no key", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ HELLO: "Hello [[:]]!", @@ -555,7 +602,7 @@ describe("TranslateService", function () { ); })); - it("reads the key after opening brackets", fakeAsync(function() { + it("reads the key after opening brackets", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ WELCOME: "Welcome [[A]]!", @@ -571,7 +618,7 @@ describe("TranslateService", function () { ); })); - it("ignores spaces before key", fakeAsync(function() { + it("ignores spaces before key", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ WELCOME: "Welcome [[ \t\n]]!", @@ -587,7 +634,7 @@ describe("TranslateService", function () { ); })); - it("allows dots in key", fakeAsync(function() { + it("allows dots in key", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ HELLO: "Hello [[ app.WORLD ]]!", @@ -601,7 +648,7 @@ describe("TranslateService", function () { expect(translation).toBe("Hello World!"); })); - it("key is finish after space character", fakeAsync(function() { + it("key is finish after space character", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ WELCOME: "Welcome [[ A B ]]!", @@ -617,7 +664,23 @@ describe("TranslateService", function () { ); })); - it("key can have more than one character", fakeAsync(function() { + it("ignores other spaces before colon", fakeAsync(() => { + translate.waitForTranslation(); + loaderPromiseResolve({ + WELCOME: "Welcome [[ A B ]]!", + }); + JasminePromise.flush(); + spyOn(translate.logHandler, "error").and.callFake(() => {}); + + let translation = translate.instant("WELCOME"); + + expect(translation).toBe("Welcome !"); + expect(translate.logHandler.error).toHaveBeenCalledWith( + "Parse error unexpected character at pos 7 expected colon or end in '[[ A B ]]'" + ); + })); + + it("key can have more than one character", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ WELCOME: "Welcome [[ ABC ]]!", @@ -630,7 +693,7 @@ describe("TranslateService", function () { expect(translation).toBe("Welcome ABC!"); })); - it("expects a parameter after colon", fakeAsync(function() { + it("expects a parameter after colon", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T :. ]]", @@ -646,7 +709,7 @@ describe("TranslateService", function () { ); })); - it("ignores spaces after colon", fakeAsync(function() { + it("ignores spaces after colon", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : ]]", @@ -662,7 +725,7 @@ describe("TranslateService", function () { ); })); - it("key can not have comma, equal sign, or colon", fakeAsync(function() { + it("key can not have comma, equal sign, or colon", fakeAsync(() => { // for key is allowed [A-Za-z0-9_.-] not [,=:] translate.waitForTranslation(); loaderPromiseResolve({ @@ -696,7 +759,7 @@ describe("TranslateService", function () { ); })); - it("waits for parameters after colon", fakeAsync(function() { + it("waits for parameters after colon", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : ]]!", @@ -711,7 +774,7 @@ describe("TranslateService", function () { ); })); - it("reads the parameter key passes this parameter to referenced translation", fakeAsync(function() { + it("reads the parameter key passes this parameter to referenced translation", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : a]]", @@ -724,7 +787,7 @@ describe("TranslateService", function () { expect(translation).toBe("Hello world!"); })); - it("transports only variables defined to subtranslations", fakeAsync(function() { + it("transports only variables defined to subtranslations", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ CALL: "You don\'t know {{privateVar}} but [[HACK:givenVar]]", @@ -741,7 +804,7 @@ describe("TranslateService", function () { expect(translation).toBe("You don\'t know private but given"); })); - it("throws an error for illegal parameter characters", fakeAsync(function() { + it("throws an error for illegal parameter characters", fakeAsync(() => { // for parameter is allowed [A-Za-z0-9_] not [.,=:-] let translations = { A: "[[ T : a.]]", @@ -783,7 +846,7 @@ describe("TranslateService", function () { } })); - it("stops param reading after space", fakeAsync(function() { + it("stops param reading after space", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo bar ]]!", @@ -799,7 +862,7 @@ describe("TranslateService", function () { ); })); - it("expects comma after reading param key", fakeAsync(function() { + it("expects comma after reading param key", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : a , ]]", @@ -815,7 +878,7 @@ describe("TranslateService", function () { ); })); - it("waits for a getter after equal sign", fakeAsync(function() { + it("waits for a getter after equal sign", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo =]]!", @@ -831,7 +894,7 @@ describe("TranslateService", function () { ); })); - it("transports variables under different names", fakeAsync(function() { + it("transports variables under different names", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ GREETING: "Hello [[SALUTATION:name=u]]!", @@ -852,7 +915,7 @@ describe("TranslateService", function () { expect(translation).toBe("Hello Dr. Jane Doe!"); })); - it("throws error if getter begins with illegal character", fakeAsync(function() { + it("throws error if getter begins with illegal character", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo ==]]", @@ -868,7 +931,7 @@ describe("TranslateService", function () { ); })); - it("ignores space in front of getter", fakeAsync(function() { + it("ignores space in front of getter", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo = ]]", @@ -884,7 +947,7 @@ describe("TranslateService", function () { ); })); - it("continues reading getter", fakeAsync(function() { + it("continues reading getter", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo = ab]]", @@ -897,7 +960,7 @@ describe("TranslateService", function () { expect(translation).toBe("Hello world!"); })); - it("throws error if getter contains illegal character", fakeAsync(function() { + it("throws error if getter contains illegal character", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo = a=]]", @@ -913,7 +976,7 @@ describe("TranslateService", function () { ); })); - it("stops reading getter after space", fakeAsync(function() { + it("stops reading getter after space", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo = a a]]", @@ -929,7 +992,7 @@ describe("TranslateService", function () { ); })); - it("waits for next parameter after comma", fakeAsync(function() { + it("waits for next parameter after comma", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo = a ,]]", @@ -955,7 +1018,7 @@ describe("TranslateService", function () { ); })); - it("ignores spaces after reading getter", fakeAsync(function() { + it("ignores spaces after reading getter", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : foo = ab ]]", @@ -968,7 +1031,7 @@ describe("TranslateService", function () { expect(translation).toBe("Hello world!"); })); - it("transports multiple parameters", fakeAsync(function() { + it("transports multiple parameters", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : h,a ]]", @@ -991,7 +1054,7 @@ describe("TranslateService", function () { expect(translations[3]).toBe("Hello D!"); })); - it("gets deep objects", fakeAsync(function() { + it("gets deep objects", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ NEW_COMMENT: "New comment from [[ SALUTATION : name = comment.author ]].", @@ -1014,7 +1077,7 @@ describe("TranslateService", function () { expect(translation).toBe("New comment from Mr. John Doe."); })); - it("provides the object under getter for params", fakeAsync(function() { + it("provides the object under getter for params", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ NEW_COMMENT: "New comment from [[ SALUTATION : = comment.author ]].", @@ -1038,7 +1101,7 @@ describe("TranslateService", function () { expect(translation).toBe("New comment from Mrs. Jane Doe."); })); - it("accepts only objects for params", fakeAsync(function() { + it("accepts only objects for params", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : = a ]]", @@ -1056,7 +1119,7 @@ describe("TranslateService", function () { expect(translation).toBe("Hello !"); })); - it("accepts only first parameter without key", fakeAsync(function() { + it("accepts only first parameter without key", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ A: "[[ T : b , = a ]]", @@ -1077,7 +1140,7 @@ describe("TranslateService", function () { expect(translation).toBe(""); })); - it("second parameter got added to the object", fakeAsync(function() { + it("second parameter got added to the object", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ REFERENCE: "{{hello}} {{person}}!", @@ -1094,7 +1157,7 @@ describe("TranslateService", function () { })); }); - it("informs about missing translation", function() { + it("informs about missing translation", () => { spyOn(translate.logHandler, "info"); translate.instant("UNDEFINED"); @@ -1103,7 +1166,7 @@ describe("TranslateService", function () { .toHaveBeenCalledWith("Translation for \'UNDEFINED\' in language en not found"); }); - it("shows error when parsing throws error", fakeAsync(function() { + it("shows error when parsing throws error", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ BROKEN: 'This "{{throw}}" is empty string', @@ -1118,7 +1181,7 @@ describe("TranslateService", function () { })); - it("can not get __context as parameter", fakeAsync(function() { + it("can not get __context as parameter", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ INTERPOLATION: "The sum from 1+2 is {{1+2}}", @@ -1131,7 +1194,7 @@ describe("TranslateService", function () { expect(translate.logHandler.error).toHaveBeenCalledWith("Parameter \'__context\' is not allowed."); })); - it("can not get numeric keys in parameter", fakeAsync(function() { + it("can not get numeric keys in parameter", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ INTERPOLATION: "The sum from 1+2 is {{1+2}}", @@ -1146,7 +1209,23 @@ describe("TranslateService", function () { expect(translate.logHandler.error).toHaveBeenCalledWith("Parameter \'42\' is not allowed."); })); - it("continues with other parameters after __context", fakeAsync(function() { + it("ignores prototyped properties in parameters", fakeAsync(() => { + translate.waitForTranslation(); + + loaderPromiseResolve({ + INTERPOLATION: "{{something}}", + }); + JasminePromise.flush(); + + let MyObject = function MyOption(): void {}; + MyObject.prototype.something = 42; + + let result = translate.instant("INTERPOLATION", new MyObject()); + + expect(result).toBe(""); + })); + + it("continues with other parameters after __context", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ VARIABLES_TEST: "This {{count > 5 ? 'is interesting' : 'is boring'}}", @@ -1159,7 +1238,7 @@ describe("TranslateService", function () { expect(translation).toBe("This is interesting"); })); - it("continues with other parameters after numeric", fakeAsync(function() { + it("continues with other parameters after numeric", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ VARIABLES_TEST: "This {{count > 5 ? 'is interesting' : 'is boring'}}", @@ -1172,7 +1251,7 @@ describe("TranslateService", function () { expect(translation).toBe("This is interesting"); })); - it("ignores array as parameters", fakeAsync(function() { + it("ignores array as parameters", fakeAsync(() => { translate.waitForTranslation(); loaderPromiseResolve({ INTERPOLATION: "The sum from 1+2 is {{1+2}}",