Skip to content

Commit

Permalink
fix(TranslateParser): parser.flattenObject is called too often
Browse files Browse the repository at this point in the history
Fixes #47
  • Loading branch information
ribizli authored and ocombe committed Mar 6, 2016
1 parent e5729f0 commit f01ee79
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 74 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,5 @@ With the given translation: `"HELLO": "hello {{value}}"`.
- `interpolate(expr: string, params?: any): string`: Interpolates a string to replace parameters.

`This is a {{ key }}` ==> `This is a value` with `params = { key: "value" }`
- `flattenObject(target: Object): Object`: Flattens an object
`{ key1: { keyA: 'valueI' }}` ==> `{ 'key1.keyA': 'valueI' }`

- `getValue(target: any, key: stirng): any`: Gets a value from an object by composed key
`parser.getValue({ key1: { keyA: 'valueI' }}, 'key1.keyA') ==> 'valueI'`
28 changes: 12 additions & 16 deletions bundles/ng2-translate.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
System.registerDynamic("src/translate.pipe", ["angular2/core", "./translate.service", "angular2/src/facade/lang"], true, function($__require, exports, module) {
"use strict";
;
var global = this,
__define = global.define;
global.define = undefined;
var define;
var global = this;
var GLOBAL = this;
var __decorate = (this && this.__decorate) || function(decorators, target, key, desc) {
var c = arguments.length,
r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
Expand Down Expand Up @@ -133,16 +133,15 @@ System.registerDynamic("src/translate.pipe", ["angular2/core", "./translate.serv
return TranslatePipe;
}());
exports.TranslatePipe = TranslatePipe;
global.define = __define;
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) {
"use strict";
;
var global = this,
__define = global.define;
global.define = undefined;
var define;
var global = this;
var GLOBAL = this;
var __decorate = (this && this.__decorate) || function(decorators, target, key, desc) {
var c = arguments.length,
r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc,
Expand Down Expand Up @@ -336,16 +335,15 @@ System.registerDynamic("src/translate.service", ["angular2/core", "angular2/http
return TranslateService;
}());
exports.TranslateService = TranslateService;
global.define = __define;
return module.exports;
});

System.registerDynamic("src/translate.parser", [], true, function($__require, exports, module) {
"use strict";
;
var global = this,
__define = global.define;
global.define = undefined;
var define;
var global = this;
var GLOBAL = this;
var Parser = (function() {
function Parser() {
this.templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
Expand Down Expand Up @@ -384,16 +382,15 @@ System.registerDynamic("src/translate.parser", [], true, function($__require, ex
return Parser;
}());
exports.Parser = Parser;
global.define = __define;
return module.exports;
});

System.registerDynamic("ng2-translate", ["./src/translate.pipe", "./src/translate.service", "./src/translate.parser"], true, function($__require, exports, module) {
"use strict";
;
var global = this,
__define = global.define;
global.define = undefined;
var define;
var global = this;
var GLOBAL = this;
function __export(m) {
for (var p in m)
if (!exports.hasOwnProperty(p))
Expand All @@ -409,6 +406,5 @@ System.registerDynamic("ng2-translate", ["./src/translate.pipe", "./src/translat
pipes: [translate_pipe_1.TranslatePipe],
providers: [translate_service_1.TranslateService]
};
global.define = __define;
return module.exports;
});
50 changes: 17 additions & 33 deletions src/translate.parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,33 @@ export class Parser {
* @returns {string}
*/
public interpolate(expr: string, params?: any): string {
if(!params) {
if (typeof expr !== 'string' || !params) {
return expr;
} else {
params = this.flattenObject(params);
}

return expr.replace(this.templateMatcher, function (substring: string, b: string): string {
var r = params[b];
return expr.replace(this.templateMatcher, (substring: string, b: string) => {
var r = this.getValue(params, b);
return typeof r !== 'undefined' ? r : substring;
});
}

/**
* Flattens an object
* { key1: { keyA: 'valueI' }} ==> { 'key1.keyA': 'valueI' }
* Gets a value from an object by composed key
* parser.getValue({ key1: { keyA: 'valueI' }}, 'key1.keyA') ==> 'valueI'
* @param target
* @returns {Object}
* @param key
* @returns any
*/
public flattenObject(target: Object): Object {
var delimiter = '.';
var maxDepth: number;
var currentDepth = 1;
var output: any = {};

function step(object: any, prev?: string) {
Object.keys(object).forEach(function (key) {
var value = object[key];
var newKey = prev ? prev + delimiter + key : key;

maxDepth = currentDepth + 1;

if(!Array.isArray(value) && typeof value === 'object' && Object.keys(value).length && currentDepth < maxDepth) {
++currentDepth;
return step(value, newKey);
}

output[newKey] = value;
});
public getValue(target: any, key: string) {
let keys = key.split('.');
try {
for (let k of keys) {
target = target[k];
}
return target;
} catch (e) {
return;
}

step(target);

return output;
}

}
24 changes: 5 additions & 19 deletions src/translate.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,11 @@ export class TranslateService {
}

if(translations) {
res = this.parser.interpolate(translations[key], interpolateParams);
res = this.parser.interpolate(this.parser.getValue(translations, key), interpolateParams);
}

if(typeof res === 'undefined' && this.defaultLang && this.defaultLang !== this.currentLang) {
let translations: any = this.parser.flattenObject(this.translations[this.defaultLang]);
res = this.parser.interpolate(translations[key], interpolateParams);
res = this.parser.interpolate(this.parser.getValue(this.translations[this.defaultLang], key), interpolateParams);
}

if(!res && this.missingTranslationHandler) {
Expand All @@ -228,16 +227,10 @@ export class TranslateService {
// check if we are loading a new translation to use
if(this.pending) {
return this.pending.map((res: any) => {
return this.getParsedResult(this.parser.flattenObject(res), key, interpolateParams);
return this.getParsedResult(res, key, interpolateParams);
});
} else {
let translations: any;

if(this.translations[this.currentLang]) {
translations = this.parser.flattenObject(this.translations[this.currentLang]);
}

return Observable.of(this.getParsedResult(translations, key, interpolateParams));
return Observable.of(this.getParsedResult(this.translations[this.currentLang], key, interpolateParams));
}
}

Expand All @@ -253,14 +246,7 @@ export class TranslateService {
throw new Error('Parameter "key" required');
}

// check if we are loading a new translation to use
let translations: any;

if(this.translations[this.currentLang]) {
translations = this.parser.flattenObject(this.translations[this.currentLang]);
}

return this.getParsedResult(translations, key, interpolateParams);
return this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
}

/**
Expand Down
9 changes: 6 additions & 3 deletions tests/translate.parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ export function main() {
expect(parser.interpolate("This is a {{ key1.key2.key3 }}", {key1: {key2: {key3: "value3"}}})).toEqual("This is a value3");
});

it('should be able to flatten objects', () => {
expect(parser.flattenObject({key1: {key2: "value2"}})).toEqual({"key1.key2": "value2"});
expect(parser.flattenObject({key1: {key2: {key3: "value3"}}})).toEqual({"key1.key2.key3": "value3"});
it('should get the addressed value', () => {
expect(parser.getValue({key1: {key2: "value2"}}, 'key1.key2')).toEqual("value2");
expect(parser.getValue({key1: {key2: "value"}}, 'keyWrong.key2')).not.toBeDefined();
expect(parser.getValue({key1: {key2: {key3: "value3"}}}, 'key1.key2.key3')).toEqual("value3");
expect(parser.getValue({key1: {key2: {key3: "value3"}}}, 'key1.keyWrong.key3')).not.toBeDefined();
expect(parser.getValue({key1: {key2: {key3: "value3"}}}, 'key1.key2.keyWrong')).not.toBeDefined();
});
});
}

0 comments on commit f01ee79

Please sign in to comment.