Translate Tool
September 8, 2025
At work, we use ngx-translate
to hande translations for our web-apps. It’s a great tool but it uses JSON files for the translations and managing them is a bit of a pain. I wanted to fix that. I wanted a simple way to interact with the translation files, add new keys, and validate that all the keys are present in all languages. I tried searching online, but quickly gave up as the common “I’ll just build it myself” thought entered my mind.
As usual for me with these things, I built it in Rust.
I started by writing a simple CLI tool using clap that could read and parse the translation files in the specified folder. Then, when I got that working, I upgraded it so that it could write the files. I used the awesome inquire crate to prompt the user for keys and values.
Here’s an overview of the commands I implemented:
add
- add a new key- prompts for values in all languages
update
- update an existing key- prompts for values in all languages
validate
- validate the translation files- test that all keys are present in all languages
--fail-on-empty
flag to make it fail if any keys are missing
Configuration file
For the configuration file I used a simple JSON based file format. The configuration file looks something like this:
{
// commands to execute after writing to the disk; defaults to an empty list
"post_write_commands": ["bun format"],
// defaults to "en"
"default_locale": "en",
// defaults to "translations"
"translations_directory": "test/translations"
}
Usage in docker
While downloading the CLI tool is easy, I wanted to make it even easier to use for my colleages. To accomplish this, I created this command to run the CLI in a docker container with volume mounts to the disk:
docker run --rm -it -v ./tt.config.json:/tt.config.json -v ./translations:/translations ghcr.io/borisnliscool/translate-tool:latest
It is a bit long, yes, but it works great. I even put it in my package.json
file as a script.
{
"scripts": {
"tt": "docker run --rm -it -v ./tt.config.json:/tt.config.json -v ./translations:/translations ghcr.io/borisnliscool/translate-tool:latest"
}
}
The result is a super easy way (pnpm tt
) to run the tool, without having to install it locally.
Usage in workflows
Because I already created a docker image, I also wanted to use it in my workflows. This way, I can automatically lint my translation files before deployment to ensure there are no missing locales in my app.
Here’s an example workflow:
jobs:
lint-translations:
name: Lint translations
image: ghcr.io/borisnliscool/translate-tool:latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate translations
run: |
mkdir /translations
cp -r /static/i18n/* /translations/
translate-tool validate --fail-on-empty
Summary
I spent a weekend building an awesome tool to help me work with translations. source code
Copyright © 2016-2025 boris.foo (formerly borisnl.nl), All rights reserved.