diff i18next

Calculating the Difference Between JSON Files

Learn how to find missing translations in JSON files with dictionaries.

Daniel Gustaw

Daniel Gustaw

• 3 min read

Calculating the Difference Between JSON Files

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.