Advanced enterprise localisation process with Lingui, Locize, GitHub Actions, Docker, React
Tags: react, localisation, architecture, docker
Published: 2022-12-22 07:13:04

I have experience in integrating localisation into three applications of different sizes. In this article, I will share my experience only with the enterprise localisation process. If you are interested in localisation for other project sizes, please share your thoughts in the comments 💭

## General idea 🚀

The main idea was to have a process allowing developers to do fewer actions and have everything automated in the CI, from uploading to downloading the translations.
We want a source of truth for keys **in the code** and a source of truth for translations - **a 3rd party translation platform** (in our case - locize).

## Choosing front-end library 📚
### Quick Summary:
We choose [lingui](https://lingui.js.org/).

### Comparison table for front-end libs
First, we should check out the libs for the front end, which will work with our localisation.

| Name             | Size (minified + gzipped)| Dependecies | Typescript |Open/Closed issues | Last publish  |
| ---------------- | ------------------------ | ----------- | -----------|------------------ |---------------|
| react-i18next    | 6.7kB                    | 2           | 8%         |8/1044             |  a month ago  |
| lingui           | 7.8kB                    | 3           | 89%        |20/693             |  4 months ago |
| react-intl       | 17.8kB                   | 10          | 77%        |12/1686            |  4 days ago   |
| react-translated | 7.8kB                    | 2           | 0%         |3/6                |  3 years ago  |

Also, a big plus was a minimal amount of issues for `lingui/react`. Previously I tried `react-i18next`, which was good, but we didn't go with it because the feedback from the other organisation members was good. Our application already has system modules that were integrated with `lingui`.

**Here is a detailed article about how to choose the proper library.**

{% embed https://dev.to/dealwith/how-to-choose-the-right-npm-package-in-a-4-steps-42bo %}

## Choosing 3rd party localisation service 🗺️
### Quick Summary: 
We choose [locize](https://locize.com/).

### Localisation platforms comparison
| service         | integration       | pricing for 10k/m                                                                                                                         | experience for translator                  | developer features                     | summary                                                                     |
|-----------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------|----------------------------------------|-----------------------------------------------------------------------------|
| locize.com      | good doc, easy    | fluid pricing depends on the usage                                                                                                        | bad UX, hard to collaborate                | versioning, plurals, reach API & CLI   | Unlimited Contributors, Unlimited projects                                  |
| poeditor.com    | GitHub app        | $38.24                                                                                                                                    | comments, good UI, machine translations    | plurals, versioning, multiple projects | Unlimited Contributors, Unlimited Projects                                  |
| lokalise.com    | GitHub app        | $230 (only 10 seats included)                                                                                                             | discussions, good UI                       | plurals, work with multiple branches   | Really high price with no machine translations, limited seats               |
| translation.com | sync cli/platform | $0.01/ key active projects $100 $0.005/key archive project $50                                                                            | discussions, machine translations, good UI | plurals                                | Promoted by lingui, easy to use, cheap                                      |
| smartling       | -                 | -                                                                                                                                         | -                                          | -                                      | Push you to buy annual, high price for a small number of features           |
| Сrowdin         | GitHub, Gitlab    | 0.01$/key with no available integrations, basic subscription is so limited, you also need additional payments for translation managers | -                                          | -                                      | good UI, not so hard to use                                                 |
| phrase          | -                 | 70usd per month for 3 users (100api/request per user monthly)                                                                              | -                                          | -                                      | too expensive, most of the features are the same or less as everywhere else |

*Minus sign in the table has the meaning of not having a feature or doesn't have enough info about features in the specific service.*

At first glance, I realised there would be little difference in localisation platforms. For our team, the crucial point was to have a good amount of features for a reasonable price and a robust API which would allow us to deeply integrate our CI with a translation platform.

#### Platform locize was chosen for:
1. Fluid pricing systems that depend on the actual usage of the platform
2. Good versioning system, which allows you to use a semver versioning system
3. Reach API and CLI for a better low-level integration
4. Unlimited Contributors and Unlimited projects
5. Easy way to integrate with client library - lingui.
6. Fast support from the creator

## Upload new keys process 📑
Here is a sequence diagram which explains the whole process of uploading. Your detailed implementation can be different according to your project tools.
If you don't know what is sequence diagram you can check out this [documentation in mermaid](https://mermaid-js.github.io/mermaid/#/sequenceDiagram)


![Upload new keys process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zudl4xw63doju1kpgnn9.png)


### Implementation details
*This section will describe some implementation details inside our project. If you're using another tech stack, feel free to skip it and go on.*

#### Step 1
We only trigger the upload process in the `origin/main` branch when merging the PR.
#### Step 2
Our project is a monorepo containing several front-ends which need localisation. 

[Rush](https://rushjs.io/) provides an excellent way to understand what project is changed by running `rush change`.

After that, we pick these projects inside the CI step and analyse the [package.json of this project for the `localisation: true` flag](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#config). We put a flag inside our front-end project for a faster localisation check. This config section is rarely used, but so cool to know about.

`package.json` 
```javascript
{
  ...,
  devDependencies: {...},
  config: {
    localisation: true
  }
}
```

#### Step 3
To extract the translations keys from the code, we used [lingui extract](https://lingui.js.org/ref/cli.html#lingui-cli-extract)

`lingui extract --clean`

This tool works as we need it - developers do nothing, and everything is automated. He/she is just putting translation keys into the code, and this command will automatically search for the keys and put them into all translation files if the key doesn't exist there yet.

#### Version calculation
We're calculating a future version and returning a major or minor version.

#### Steps 4-9
We upgrade a minor version when developers add new keys to the translations.

These steps are done by manipulating the [Locize API](https://docs.locize.com/integration/api)

#### Steps 10-14
When a developer removes translation keys, we're upgrading a major version.

These steps are done by manipulating the [Locize API](https://docs.locize.com/integration/api)

## Download new keys process 📲

![Download new keys process](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8tmq3xctsclvq1f5zfle.png)



### Implementation details
*This section will describe some implementation details inside our project. If you're using another tech stack, feel free to skip it and go further.*

Most steps are part of the `download-localisation.sh` script.

#### Step 1
The developer pushes code to the remote repository.

#### Step 2
Inside Github CI, we're building a docker image of the application.

#### Step 3
We run the image with environment variables.

Useful env variables were:
1. **Translation version**. For the different dev environments, we used different translation versions.
2. **Project id** from locize. As I wrote, we had several projects inside one repository, so we need several in locize. Also, we need our script to be reusable across the organisation.
3. **Namespace.**

#### Step 4
This part of the download-localisation script is responsible for pulling languages for the project.

```shell
LANGUAGES="$(
  curl -s "https://api.locize.app/languages/$LOCIZE_PROJECT_ID" \
  | jq -r 'keys | join(" ")'
)"
```

#### Step 5
Code piece which helps us to download translations

```shell
for language in $LANGUAGES
do
	printf "Downloading translation for $language..."

	if [ -d "$TRANSLATIONS_DIR/$language" ]
	then
		rm -fr "$TRANSLATIONS_DIR/$language"
	fi

	mkdir -p "$TRANSLATIONS_DIR/$language"

	curl -s -o "$TRANSLATIONS_DIR/$language/$LOCIZE_NAMESPACE.json" "$LOCIZE_API_BASE/$LOCIZE_PROJECT_ID/$LOCIZE_VERSION/$language/$LOCIZE_NAMESPACE"

	echo "Done"
done
```

#### Step 6
Loading the translations is happening with the help of `@lingui/remote-loader`. This remote loader wasn't listed in the lingui documentation but exists in npm and the codebase. Finding this module took some time, so right now, you can use that time wisely!

## Finish 🏁
I hope you enjoyed reading this article. Please leave your thoughts about such localisation design architecture.

Cover design by: [Julia Mazur](https://www.behance.net/jumazur)