Skip to content

Commit

Permalink
feat(MissingTranslationHandler): the MissingTranslationHandler is now…
Browse files Browse the repository at this point in the history
… able to return a value or an o
  • Loading branch information
ocombe committed Mar 6, 2016
1 parent 260d8d7 commit 23267b1
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 45 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ provide(TranslateLoader, {useClass: CustomLoader})
#### How to handle missing translations
You can setup a provider for `MissingTranslationHandler` in the bootstrap of your application (recommended), or in the `providers` property of a component.
It will be called when the requested translation is not available.
The only required method is `handle` where you can do whatever you want. Just don't forget that it will be called synchronously from the `get` & `instant` methods.
The only required method is `handle` where you can do whatever you want. If this method returns a value or an observable (that should return a string), then this will be used.
Just don't forget that it will be called synchronously from the `instant` method.

##### Example:
Create a Missing Translation Handler
Expand All @@ -139,7 +140,7 @@ import {MissingTranslationHandler} from 'ng2-translate/ng2-translate';

export class MyMissingTranslationHandler implements MissingTranslationHandler {
handle(key: string) {
console.log(key);
return 'some value';
}
}
```
Expand Down
90 changes: 67 additions & 23 deletions bundles/ng2-translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ System.registerDynamic("src/translate.pipe", ["angular2/core", "./translate.serv
this.value = '';
this.translate = translate;
}
TranslatePipe.prototype.isRegExp = function(value) {
return toString.call(value) === '[object RegExp]';
};
TranslatePipe.prototype.equals = function(o1, o2) {
if (o1 === o2)
return true;
Expand All @@ -54,28 +51,21 @@ System.registerDynamic("src/translate.pipe", ["angular2/core", "./translate.serv
}
return true;
}
} else if (lang_1.isDate(o1)) {
if (!lang_1.isDate(o2))
return false;
return this.equals(o1.getTime(), o2.getTime());
} else if (this.isRegExp(o1)) {
if (!this.isRegExp(o2))
return false;
return o1.toString() == o2.toString();
} else {
if (lang_1.isArray(o2) || lang_1.isDate(o2) || this.isRegExp(o2))
if (lang_1.isArray(o2)) {
return false;
}
keySet = Object.create(null);
for (key in o1) {
if (key.charAt(0) === '$' || lang_1.isFunction(o1[key]))
continue;
if (!this.equals(o1[key], o2[key]))
if (!this.equals(o1[key], o2[key])) {
return false;
}
keySet[key] = true;
}
for (key in o2) {
if (!(key in keySet) && key.charAt(0) !== '$' && typeof o2[key] !== 'undefined' && !lang_1.isFunction(o2[key]))
if (!(key in keySet) && typeof o2[key] !== 'undefined') {
return false;
}
}
return true;
}
Expand Down Expand Up @@ -137,7 +127,7 @@ System.registerDynamic("src/translate.pipe", ["angular2/core", "./translate.serv
return module.exports;
});

System.registerDynamic("src/translate.service", ["angular2/core", "angular2/http", "rxjs/Observable", "rxjs/add/observable/fromArray", "rxjs/add/operator/share", "rxjs/add/operator/map", "./translate.parser"], true, function($__require, exports, module) {
System.registerDynamic("src/translate.service", ["angular2/core", "angular2/http", "rxjs/Observable", "rxjs/add/observable/fromArray", "rxjs/add/operator/share", "rxjs/add/operator/map", "rxjs/add/operator/merge", "rxjs/add/operator/toArray", "./translate.parser"], true, function($__require, exports, module) {
"use strict";
;
var global = this,
Expand Down Expand Up @@ -170,6 +160,8 @@ System.registerDynamic("src/translate.service", ["angular2/core", "angular2/http
$__require('rxjs/add/observable/fromArray');
$__require('rxjs/add/operator/share');
$__require('rxjs/add/operator/map');
$__require('rxjs/add/operator/merge');
$__require('rxjs/add/operator/toArray');
var translate_parser_1 = $__require('./translate.parser');
var MissingTranslationHandler = (function() {
function MissingTranslationHandler() {}
Expand Down Expand Up @@ -256,11 +248,35 @@ System.registerDynamic("src/translate.service", ["angular2/core", "angular2/http
TranslateService.prototype.getParsedResult = function(translations, key, interpolateParams) {
var res;
if (key instanceof Array) {
var result = {};
var result = {},
observables = false;
for (var _i = 0,
key_1 = key; _i < key_1.length; _i++) {
var k = key_1[_i];
result[k] = this.getParsedResult(translations, k, interpolateParams);
if (typeof result[k].subscribe === 'function') {
observables = true;
}
}
if (observables) {
var mergedObs;
for (var _a = 0,
key_2 = key; _a < key_2.length; _a++) {
var k = key_2[_a];
var obs = typeof result[k].subscribe === 'function' ? result[k] : Observable_1.Observable.of(result[k]);
if (typeof mergedObs === 'undefined') {
mergedObs = obs;
} else {
mergedObs = mergedObs.merge(obs);
}
}
return mergedObs.toArray().map(function(arr) {
var obj = {};
arr.forEach(function(value, index) {
obj[key[index]] = value;
});
return obj;
});
}
return result;
}
Expand All @@ -271,7 +287,7 @@ System.registerDynamic("src/translate.service", ["angular2/core", "angular2/http
res = this.parser.interpolate(this.parser.getValue(this.translations[this.defaultLang], key), interpolateParams);
}
if (!res && this.missingTranslationHandler) {
this.missingTranslationHandler.handle(key);
res = this.missingTranslationHandler.handle(key);
}
return res || key;
};
Expand All @@ -281,18 +297,46 @@ System.registerDynamic("src/translate.service", ["angular2/core", "angular2/http
throw new Error('Parameter "key" required');
}
if (this.pending) {
return this.pending.map(function(res) {
return _this.getParsedResult(res, key, interpolateParams);
return Observable_1.Observable.create(function(observer) {
var onComplete = function(res) {
observer.next(res);
observer.complete();
};
_this.pending.subscribe(function(res) {
var res = _this.getParsedResult(res, key, interpolateParams);
if (typeof res.subscribe === 'function') {
res.subscribe(onComplete);
} else {
onComplete(res);
}
});
});
} else {
return Observable_1.Observable.of(this.getParsedResult(this.translations[this.currentLang], key, interpolateParams));
var res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
if (typeof res.subscribe === 'function') {
return res;
} else {
return Observable_1.Observable.of(res);
}
}
};
TranslateService.prototype.instant = function(key, interpolateParams) {
if (!key) {
throw new Error('Parameter "key" required');
}
return this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
var res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
if (typeof res.subscribe !== 'undefined') {
if (key instanceof Array) {
var obj = {};
key.forEach(function(value, index) {
obj[key[index]] = key[index];
});
return obj;
}
return key;
} else {
return res;
}
};
TranslateService.prototype.set = function(key, value, lang) {
if (lang === void 0) {
Expand Down
84 changes: 72 additions & 12 deletions src/translate.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {Injectable, EventEmitter, Optional} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable'
import {Observer} from "rxjs/Observer";
import 'rxjs/add/observable/fromArray';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/merge';
import 'rxjs/add/operator/toArray';

import {Parser} from './translate.parser';

Expand All @@ -13,7 +16,15 @@ export interface LangChangeEvent {
}

export abstract class MissingTranslationHandler {
abstract handle(key: string): void;
/**
* A function that handles missing translations.
* @param key the missing key
* @returns {any} a value or an observable
* If it returns a value, then this value is used.
* If it return an observable, the value returned by this observable will be used (except if the method was "instant").
* If it doesn't return then the key will be used as a value
*/
abstract handle(key: string): any;
}

export abstract class TranslateLoader {
Expand Down Expand Up @@ -60,7 +71,7 @@ export class TranslateService {
*
* @param http The Angular 2 http provider
* @param currentLoader An instance of the loader currently used
* @param missingTranslationHandler A handler for missing translations
* @param missingTranslationHandler A handler for missing translations.
*/
constructor(private http: Http, public currentLoader: TranslateLoader, @Optional() private missingTranslationHandler: MissingTranslationHandler) {}

Expand Down Expand Up @@ -149,13 +160,35 @@ export class TranslateService {
* @param interpolateParams
* @returns {any}
*/
private getParsedResult(translations: any, key: any, interpolateParams?: Object): string {
var res: string;
private getParsedResult(translations: any, key: any, interpolateParams?: Object): any {
var res: string|Observable<string>;

if(key instanceof Array) {
let result: any = {};
for (var k of key) {
let result: any = {},
observables: boolean = false;
for (let k of key) {
result[k] = this.getParsedResult(translations, k, interpolateParams);
if(typeof result[k].subscribe === 'function') {
observables = true;
}
}
if(observables) {
var mergedObs: any;
for (let k of key) {
let obs = typeof result[k].subscribe === 'function' ? result[k] : Observable.of(result[k]);
if(typeof mergedObs === 'undefined') {
mergedObs = obs;
} else {
mergedObs = mergedObs.merge(obs);
}
}
return mergedObs.toArray().map((arr: Array<string>) => {
var obj: any = {};
arr.forEach((value: string, index: number) => {
obj[key[index]] = value;
});
return obj;
});
}
return result;
}
Expand All @@ -169,7 +202,7 @@ export class TranslateService {
}

if(!res && this.missingTranslationHandler) {
this.missingTranslationHandler.handle(key);
res = this.missingTranslationHandler.handle(key);
}

return res || key;
Expand All @@ -185,14 +218,29 @@ export class TranslateService {
if(!key) {
throw new Error('Parameter "key" required');
}

// check if we are loading a new translation to use
if(this.pending) {
return this.pending.map((res: any) => {
return this.getParsedResult(res, key, interpolateParams);
return Observable.create((observer: Observer<string>) => {
var onComplete = (res: string) => {
observer.next(res);
observer.complete();
};
this.pending.subscribe((res: any) => {
var res = this.getParsedResult(res, key, interpolateParams);
if(typeof res.subscribe === 'function') {
res.subscribe(onComplete);
} else {
onComplete(res);
}
});
});
} else {
return Observable.of(this.getParsedResult(this.translations[this.currentLang], key, interpolateParams));
var res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
if(typeof res.subscribe === 'function') {
return res;
} else {
return Observable.of(res);
}
}
}

Expand All @@ -208,7 +256,19 @@ export class TranslateService {
throw new Error('Parameter "key" required');
}

return this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
var res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
if(typeof res.subscribe !== 'undefined') {
if(key instanceof Array) {
var obj: any = {};
key.forEach((value: string, index: number) => {
obj[key[index]] = key[index];
});
return obj;
}
return key;
} else {
return res;
}
}

/**
Expand Down
Loading

0 comments on commit 23267b1

Please sign in to comment.