Calculating the Difference Between JSON Files
Learn how to find missing translations in JSON files with dictionaries.
Daniel Gustaw
• 3 min read
In this article, we will demonstrate how to create a function that identifies the differences between two JSON files.
From an educational standpoint, this serves as an excellent example of using recursive functions. From a practical perspective, it’s a valuable tool for managing translations.
To begin, we’ll create a command that reads the files and prints all keys present in the first file but missing in the second file to the standard output.
We will start by checking if the files indicated as arguments exist:
const fs = require('fs')
const pathBase = `${process.cwd()}/${process.argv[2]}`;
const pathComp = `${process.cwd()}/${process.argv[3]}`;
if (!fs.existsSync(pathBase)) {
console.error(`File ${pathBase} not existst`);
process.exit()
}
if (!fs.existsSync(pathComp)) {
console.error(`File ${pathComp} not existst`);
process.exit()
}
Next, we’ll read the contents of these files and convert JSON to objects:
const base = JSON.parse(fs.readFileSync(pathBase).toString());
const comp = JSON.parse(fs.readFileSync(pathComp).toString());
Now, we’ll define a function for finding differences:
function getDiff(a, b) {
const res = {};
for (let key in a) {
if (a.hasOwnProperty(key)) {
if (!b.hasOwnProperty(key)) {
res[key] = a[key]
} else {
if (typeof a[key] === 'object') {
res[key] = getDiff(a[key], b[key])
}
}
if (res[key] && !Object.keys(res[key]).length) {
delete res[key];
}
}
}
return res;
}
This function takes a pair of objects and iterates through the keys of the first (base) object. If the second object (comparison) does not have the key, it is added to the result. If the key is present, it checks if the type is an object and, if so, recursively calls the getDiff function.
Finally, we delete keys with empty objects before displaying the results:
process.stdout.write(JSON.stringify(getDiff(base, comp)))
This program does not support arrays. For translation files, they aren’t necessary. If you want to read about more advanced methods for comparing JSON files, a good starting point is a thread on Stack Overflow:
Using jq or alternative command line tools to compare JSON files
Now, let’s see how the program works in practice with translation files. The first file, en_old.json, was prepared manually and covers all translations in the application, while the second file, en.json, was generated by i18next. The issue is that i18next did not detect all translations.
At first, I sorted both files manually using the service: codeshack.io/json-sorter
https://codeshack.io/json-sorter/
Next, I used diffchecker
to find the differences between them:
https://www.diffchecker.com/yffDMWff
Then I created a file with the missing translations:
node ../DevTools/json-diff.js src/locales/en_old.json src/locales/en.json > src/locales/en-codes.json
The file, displayed and formatted by jq, looks like this:
We can see that it includes all the missing keys.
When importing translation files, we can use the deepmerge package. The i18n configuration file might look like this:
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import deepmerge from 'deepmerge'
import en from 'vuetify/lib/locale/en'
import pl from 'vuetify/lib/locale/pl'
Vue.use(VueI18n);
const messages = {
en: deepmerge(
require('@/locales/en-codes.json'),
require('@/locales/en.json'),
{$vuetify: en}
),
pl: deepmerge(
require('@/locales/pl-codes.json'),
require('@/locales/pl.json'),
{$vuetify: pl}
),
};
export default new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
messages,
})
export const languages = [
{text: 'lang.pl', value: 'pl'},
{text: 'lang.en', value: 'en'},
];
If you have any experiences related to automating translation work or recommendations for tools and scripts, feel free to share them in the comments. I’m interested in learning about the tools and approaches you use.
Other articles
You can find interesting also.
CodinGame: Best fit to data - Rust - Regression Analysis
Linear and logarithmic regressions were derived here. Models were fitted in rust language. This article shows that sometimes it's worth improving the theoretical model before starting implementation.
Daniel Gustaw
• 6 min read
Analysis of Apache logs with GoAccess
In this post, I show a tool that allows you to extract interesting information from files automatically generated during server operation.
Daniel Gustaw
• 21 min read
CodinGame: ASCI Art - Rust, NodeJs - Strings, Arrays, Loops
Solving this puzzle teaches how to manage strings and array arithmetics. You'll know how to split a string into separate parts and concatenate them into a new one. You can use indexes of arrays
Daniel Gustaw
• 9 min read