Managing translations

Managing translations has always been a tedious task, but sharing them cross platforms is an even bigger nightmare.

At Hypefactors we have a PHP backend via Laravel and our frontend apps are SPA’s made with Vue.js. Because of this, we had to find a way to share translations and keywords across 3 apps and 1 backend.

After going over a large list of very competitive services, we ended up using Lokalise.com. Their feature set and pricing structure suited our needs the most, as we could create a project that shares translations across our platforms and give translators fine grained access.

How does it work for each platform?

Lets start first by explaining the file structure for each platform.

Laravel

Laravel encourages developers to split their translations into small files, each named after the section they hold translations for. I.E. you could have a file like lang/en/email/register/new_users.php that holds all the translation strings for the emails a new user receives. More on Laravel Localisation.

That allows for easily maintainable translations, as long as you are organized with your file naming schemes.

One potential problem with this approach is, you could have translation keys that have the same name, but are in different folders. Most translation managers only recognize translation keys, and having multiple ones would result in the last registered string overwrite prior registered one.

Fortunately Lokalise has a feature called Differentiate keys by file, which does exactly that – “Turn on to differentiate similar keys in different files when you import them”.

PROs

  • Easy to navigate
  • Reduces conflicts
  • Makes it easier to manage translatable database info

CONs

  • Lots of files, could make it harder to sync up with Lokalise

Vue

Our Vue apps utilize a library called Vue-i18n which is the most popular i18n library in the Vue ecosystem.

By default however, that library offers two ways to store translations. In a en.json file or as a <lang> tag inside your .vue components.

We chose the file approach over the lang tag as it would be much easier to upload json files than creating functionality for extracting keys from each .vue file.

You have to also choose between a flat structure or a deeply nested JSON object to hold your translations. We went with the nested-tree as it felt easier to scope translations to components if we needed to do so.

PROs

  • We can easily upload translation source files to Lokalise.
  • We can easily sync translations down from Lokalise for each language.
  • It is easy to find translations, they are in just one file.
  • It is easy to share translations across components, as they all have access to them.
  • All keys for a language are loaded upfront, ensuring text is correctly displayed when navigating around.

CONs

  • Files can become quite long and difficult to navigate.
  • Merge conflicts can occur, if things get moved around between commits.
  • As apps grow, translations count also increase, making each translation file heavier, this slower to download on first visit.

As you can see there is no perfect solution, you have to sacrifice here and there.

Some of the issues we had to solve:

  • How to store cross all translations?
  • How to share strings across apps?
  • How to sync down translations easily?
  • How to sync up translations easily?
  • How do you pick what format to export?
  • How to reduce duplication across translations?
  • How to lazyload the language the current language strings?
  • How to manage deletion/updating/moving of source language strings?
  • How to manage changes across branches?

How to store cross all translations

To achieve this we use a tags.

We start off with a single Lokalise project for the back-end and the 3 apps. Upon upload we enable a feature called Tagging which allows us to tag the currently uploaded strings with a set of tags.

Example

For the Hypefactors app we use app for Hype.news we use hypenews, for the API we use hypefactors-api etc.

This way it is very easy to later download translations per platform.

How to share strings across apps.

We used the tags to tag when we have a translation that should be shared across apps, and we assign it the app-shared tag. Upon syncing down, it will get downloaded along with platform specific translations. This means that each app asks for both its own tag and the shared one.

How to sync down translations easily

We achieved this using the Lokalise CLI. We just have a few commands that we run to download all the translations for a platform.

Below is the command we use for the API:

lokalise --token {$TOKEN} export {$ID} --type php  --unzip_to resources/lang --use_original 1 --no_language_folders 1 --export_sort first_added --include_tags hypefactors-api --export_empty skip

How to sync up translations easily

Currently we sync them manually. We drag and drop each translation source file from the apps into Lokalise, and the translation source folder from the API, assigning the correct tags prior to processing (it is around 4-5 files at most).

This has proven for now to be the best way as we can monitor how many new translations get added or updated, even if it is a bit manual labor.

We could use the CLI to auto upload and tag, but that is a task for another day.

Manage deletion/updating/moving of source language strings

You must have just one source of truth. All of your translators are going to use Lokalise, that is its purpose any way. You however cannot be expected to add translations there first as you develop.

That is why, we add new strings to our source files, like en.json , and then we upload them to Lokalise without enabling the update feature. We see which strings got newly added and we then sync down, to get all the new translations. We do this for each platform.

Potential issues

  1. Collision between local and remote source strings:

Source translation changes should be done on Lokalise. Lokalise allows you to auto update changed strings from source files on upload, which will overwrite any already existing mismatching strings.

Changing the source files directly could result in a collusion with potentially updated strings on Lokalise, if you don’t have not updated your local files.

Scenario: Management updates the wording of some text, but you have not downloaded the latest version yet. You update your file and overwrite upon upload to Lokalise, then management looses their changes.

This is why we encourage developers to sync down before doing changes to their local files and never auto-overwrite strings on Lokalise.

How do you pick what format to export

This is done through the UI or via CLI parameters. Lokalise does not save the files you import, rather it parses the translations and offers you a few flexible options to export.

We just choose to export for PHP Laravel array and then pick “Use previously assigned filenames with the following directory prefix”. This will export all the files in the structure we had uploaded them as.

The CLI parameters are:

--type php --use_original 1 --no_language_folders 1

How to reduce duplication across platforms

We use a feature called “Duplication Finder” and we scan for identical source strings. What it allows us to do, is assign a master source string, that the rest will just copy the translation from. It is a very cool feature that could save you allot of money for translators. More on the feature.

How to lazyload the language the current language strings

Instead of loading all translations at boot time, we load the English ones. Once the app boots, we can detect the language that is applied and we can async load a translation file. It usually takes a few milliseconds and the user does not even see it.

We have English loaded by default, so we don’t end up with path.to.key.of.translation strings all over the place, if connection is slow.

You can read more on how to do this with Vue in “Add i18n and manage translations of a Vue.js powered website”.

How to manage changes across branches

This was last not supported by their platform, but it is being worked on, so we decided to only upload the new or updated translations for a branch, after QA, just before a deployment. This could delay a deployment until translations are done.

Final thoughts

Localization has never been an easy task. As you can see there are multiple things that could go wrong, multiple things to be aware of when adding or updating translations. Platforms like Lokalise make interaction between developers and translators a bit easier.