translations-cli

A small script created as an attempt to make work with `react-intl` generated translation files a bit convenient

Usage no npm install needed!

<script type="module">
  import translationsCli from 'https://cdn.skypack.dev/translations-cli';
</script>

README

translations

Description


A small script created as an attempt to make work with `react-intl` generated translation files a bit convenient

Installation


This package should be installed globally cause it provides an executable `translations` command that you can run from the shell (CLI), and it could be reused across projects:

npm install -g translations-cli

Usage


Let's say your project already supports Spanish language and uses format.js as an internationalization tool.

So there are two JSON files in src/languages folder - one for English (en.json) and one for Spanish (es.json) locale:

src/languages
├── en.json
└── es.json

es.json content looks like:

{
  "Home.home": "Inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña",
  ... and 100 more lines
}

And in your code you have declared new messages to be translated:

intl.formatMessage({ id: 'Home.home', defaultMessage: 'Home' })

After you have extracted messages in some src/languages/extracted-messages.json file you got mix of previously and newly translated messages in it:

src/languages
├── en.json
├── es.json
└── extracted-messages.json

The extracted-messages.json now contains:

{
  "Home.home": {
    "defaultMessage": "Home",
    "description": "Home page title"
  },
  ... and 100 more lines
}

Now only newly declared messages (untranslated yet) have to be sent to your translation vendor.
To get them you could write next command in you terminal:

translations get-from src/languages/extracted-messages.json --exclude src/languages/es.json

This command writes all the messages from extracted-messages.json which ids not in es.json file yet. If no output file explicitly provided with -o or --output flag - it will create untranslated-messages.json file in the same folder as the first command's argument (src/languages):

src/languages
├── en.json
├── es.json
├── extracted-messages.json
└── untranslated-messages.json

now the untranslated-messages.json contains:

{
  "Home.home": {
    "defaultMessage": "Home",
    "description": "Home page title"
  },
  ... and 20 more lines
}

Now you can send them to your translation vendor and they will give you back the translated raw-fresh-es.json JSON file of the same format:

{
  "Home.home": {
    "defaultMessage": "Inicio",
    "description": "Home page title"
  },
  ... and 20 more lines
}

You have to compile this into a react-intl consumable JSON file.
So you compiled it into fresh-es.json:

src/languages
├── en.json
├── es.json
├── extracted-messages.json
├── fresh-es.json
└── untranslated-messages.json

The fresh-es.json contains:

{
  "Home.home": "Inicio",
  "Login.login": "Iniciar Sesión",
  "Login.email": "Dirección de E-mail",
  "Login.password": "Contraseña",
  ... and 17 more lines
}

After this you have to merge newly translated messages from the fresh-es.json into previously translated messages in the es.json.
In this point you may have two scenarios:

  1. add to es.json new messages only (new by id value) and preserve from overriding messages with already existing ids but with a new value (e.g. if translations for message with corresponding id was changed in fresh-es.json recently).
  2. to update all messages despite of the fact that their ids already exist in the es.json and gonna be overridden with messages from the fresh-es.json.

So currently es.json is:

{
  "Home.home": "Inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña",
  ... and 100 more lines
}

and fresh-es.json:

{
  "Home.home": "Página de inicio",
  "Login.login": "Iniciar Sesión",
  "Login.email": "Dirección de E-mail",
  "Login.password": "Contraseña",
  ... and 17 more lines
}

We can see that in the fresh-es.json the message with id "Home.home" was modified and "Login.email" was added.
Let's check next commands results.

  1. Command:
translations update src/languages/es.json --with src/languages/fresh-es.json --action update-existing
  1. es.json:
{
  "Home.home": "Página de inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña"
  ... and 100 more lines
}
  1. Command:
translations update src/languages/es.json --with src/languages/fresh-es.json --action append-missing
  1. es.json:
{
    "Home.home": "Inicio",
    "Login.login": "Iniciar Sesión",
    "Login.password": "Contraseña",
    "Login.email": "Dirección de E-mail"
    ... and 100 more lines
}
  1. Command:

If -a (--action) flag wasn't provided explicitly:

translations update src/languages/es.json --with src/languages/fresh-es.json

is the same as:

translations update src/languages/es.json --with src/languages/fresh-es.json --action update-all
  1. es.json:
{
  "Home.home": "Página de inicio",
  "Login.login": "Iniciar Sesión",
  "Login.password": "Contraseña",
  "Login.email": "Dirección de E-mail"
  ... and 100 more lines
}

And finally manually clean up the src/languages:

src/languages
├── en.json
└── es.json