I am using angular-translate for a big application. Having several people committing code + translations, many times the translation objects are not in sync.
I am building a Grunt plugin to look at both files' structure and compare it (just the keys and overall structure, not values).
The main goals are:
It turns out it was a bit more complicated than I anticipated. So i figured I could do something like:
A tiny example would be the following object:
{
key1: 'cool',
key2: 'cooler',
keyWhatever: {
anotherObject: {
key1: 'better',
keyX: 'awesome'
},
aObject: 'actually, it\'s a string'
},
aKey: 'more awesomeness'
}
would map to:
{
aKey: 'String',
key1: 'String',
key2: 'String',
keyWhatever: {
aObject: 'String',
anotherObject: {
key1: 'String',
keyX: 'String'
}
}
}
After this, I would stringify all the objects and proceed with a strict comparison.
My question is, is there a better way to perform this? Both in terms of simplicity and performance, since there are many translation files and they are fairly big.
I tried to look for libraries that would already do this, but I couldn't find any.
Thank you
EDIT: Thank you Jared for pointing out objects can't be sorted. I am ashamed for saying something like that :D Another solution could be iterating each of the properties on the main translation file, and in case they are strings, compare the key with the other files. In case they are objects, "enter" them, and do the same. Maybe it is even simpler than my first guess. What should be done?
Lets say you have two JSON objects, jsonA and jsonB.
function compareValues(a, b) {
//if a and b aren't the same type, they can't be equal
if (typeof a !== typeof b) {
return false;
}
// Need the truthy guard because
// typeof null === 'object'
if (a && typeof a === 'object') {
var keysA = Object.keys(a).sort(),
keysB = Object.keys(b).sort();
//if a and b are objects with different no of keys, unequal
if (keysA.length !== keysB.length) {
return false;
}
//if keys aren't all the same, unequal
if (!keysA.every(function(k, i) { return k === keysB[i];})) {
return false;
}
//recurse on the values for each key
return keysA.every(function(key) {
//if we made it here, they have identical keys
return compareValues(a[key], b[key]);
});
//for primitives just use a straight up check
} else {
return a === b;
}
}
//true if their structure, values, and keys are identical
var passed = compareValues(jsonA, jsonB);
Note that this can overflow the stack for deeply nested JSON objects. Note also that this will work for JSON but not necessarily regular JS objects as special handling is needed for Date Objects, Regexes, etc.
Actually you do need to sort the keys, as they are not required to be spit out in any particular order. Write a function,
function getComparableForObject(obj) {
var keys = Object.keys(obj);
keys.sort(a, b => a > b ? 1 : -1);
var comparable = keys.map(
key => key + ":" + getValueRepresentation(obj[key])
).join(",");
return "{" + comparable + "}";
}
Where getValueRepresentation
is a function that either returns "String" or calls getComparableForObject
. If you are worried about circular references, add a Symbol
to the outer scope, repr
, assign obj[repr] = comparable
in the function above, and in getValueRepresentation
check every object for a defined obj[repr]
and return it instead of processing it recursively.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With