i18n-utils: CLI to simplify i18n file management
CLI utility to streamline operations on i18n files
4 min read
In my day-to-day work I’m actively using i18n to localize applications. And we are supporting multiple languages. It’s incredibly powerful, but tough to work with sometimes.
Here’s an example workflow when I’m working on a new feature:
- Add a key
feature.example.titlewith valueFeature example titleto the file withentranslations. - Add the same key but with prefix
*EN*to all other language files. - Wait for the localization team to translate all of the prefixed keys.
- Update now correctly translated strings.
Looks straightforward, doesn’t it?
But when translation files grow to a couple of thousand lines it becomes quite a challenge to find all of the places where you needed to add/update or sometimes remove a translation altogether. And while we developers don’t have any control on how the localization team translates this stuff, it occurred to me that I can automate the first and second steps of the workflow!
And in parallel to working on new features I developed a small CLI utility to do
exactly that: i18n-utils 🚀
Let’s look at the features that I’ve implemented, and how to use them.
Repository
This CLI utility is open-source, and the source code is available in the repository. The CLI is written in TypeScript and runs on Node.js. I’ve also published it to the GitHub Packages.
After adding this line to your global .npmrc file:
@chornonoh-vova:registry=https://npm.pkg.github.com/
You should be able to install it!
npm install -g @chornonoh-vova/i18n-utils
It will be available under a name i18n-utils and ready to run!
Help
For working with arguments I’ve used this library: yargs, and when set up correctly, it provides a help out of the box, so you can just run
i18n-utils
or
i18n-utils --help
and it will show all of the available sub-commands.
Subcommand is required when invoking a CLI, so let’s talk about them.
Adding translations
add sub-command is designed to help with adding new translations to the i18n files.
It takes a glob to where the files are located, key and value of the translation
and some optional arguments.
Here’s an example invocation:
i18n-utils add './src/translations/**/translation.json' \
-k 'pageDetail.metadata.command' \
-v 'CLI command'
I have this structure of the i18n files in the project:
src\
translations\
en\
translation.json
it\
translation.json
ja\
translation.json
You can actually test this glob by just running ls:
ls './src/translations/**/translation.json'
And it will show a list of all matching files.
As a result of running this command, the following structure will be added to the
JSON file for English translation (./src/translations/en/translation.json):
{
"pageDetail": {
"metadata": {
"command": "CLI command"
}
}
}
(without overwriting other translations, of course).
And the same structure, but with the value prefixed will be added to all other
languages (in the ./src/translations/ja/translation.json for example):
{
"pageDetail": {
"metadata": {
"command": "*EN* CLI command"
}
}
}
You can additionally customize the “base” language, prefix and indentation:
i18n-utils add './src/translations/**/translation.json' \
-k 'pageDetail.metadata.command' \
-v 'CLI command' \
-b 'en' \
-p '*EN*' \
-i 2
There’s a help available for this sub-command:
i18n-utils add --help
Updating translations
update sub-command is designed to overwrite already existing translations in
i18n files. And while add command will fail if translation already exists, update
command will fail if the translation does not exist.
Invocation looks a lot similar:
i18n-utils update './src/translations/**/translation.json' \
-k 'pageDetail.modal.pageMetadata' \
-v 'Page metadata: {{key}}'
And it supports the same options as an add command.
Actually I created this command only because sometimes I make a typo when running
an add command 😅
But it turned out to be a helpful command as well!
There’s a quite cool use case for the update command:
i18n-utils update './src/translations/ja/translation.json' \
-k 'some.example.feature' \
-v 'いくつかの機能例' \
-b ja
With this command only one file - one for Japanese translations will be updated. (Don’t judge me - I’ve translated “Some example feature” into Japanese with Google Translate).
Removing translations
remove sub-command is designed to simply remove existing translations from all
files. It will fail though, if the key does not exist.
i18n-utils rm './src/translations/**/translation.json' \
-k 'pageDetails.modal.noPageContent'
Btw all commands have shortcuts, for add its a, for update its u and
for remove its r or rm.
Conclusion
That’s it! If you run into similar i18n pain points, I hope this utility helps streamline your workflow. Feedback and contributions are always welcome!
It definitely streamlined my workflow though. And I’m glad that I took a little bit of the time and wrote this utility.