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
- 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.