Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
# Using Ancient Technologies To Localize Modern Apps
People often stop me on the streets to ask one question. Maksim, what makes you so happy
about localization workflow you have at Mojang?
Today I will tell you how localization is usually being done, or at least how I've seen it being done.
What kind of solution did we come up in mojang, and why am I more happy about it than previous ones.
As you could aldeady notice this talk is going to be very opinionated and experience based so if at any point
you'll disagree - feel free to discuss it with me after the talk, i'll be more than happy.
So, how translations are usually being done.
I'll be talking about react applications but, as I remember working with Ruby on Rails - localization
there was done in more or less same way.
Let's look at [React Intl](https://github.com/yahoo/react-intl) for example.
**APP EXAMPLE (REACT INTL)**
```jsx
<h1>
<FormattedMessage
id="app.title"
defaultMessage="React Intl Translations Example"
/>
</h1>
```
Instead of using regular text here and just writing:
```html
<h1>React Intl Translations Example</h1>
```
We now specify the namespaced id for the string and default message.
On the backend side we have the JSON or YAML file with mappings of those keys to actual
translations. So we have a file for each language we want to support.
```json
```
And this format is more or less same across most of the libraries used to localize React applications.
There is some set of components and functions to localize your strings and a json structure to store translations.
Some libraries provide additional support for currencies, date formatting and pluralization, but overall the functionality and the way you use those libraries is more or less similar.
I must say - this approach works, a lot of applications are translated this way.
So, Maksim, what don't you like then, and what is the alternative?
## Making Up Keys As Keys
And first one is having to come up with those keys in a first place. Every time you'll be adding text - you'll have to come up with some meaningful name for it. You also need to make sure to not make typos in that name, because it's just a string value, so nothing is holding you back from using a non-existant one in your views.
## Searching For Text That Needs To Be Translated
Next, you will have to update the texts. And in order to do that you'll have to first find it's key in your components code and then find the corresponding translation in YAML / JSON files.
## Keeping Keys Up To Date With Base Translation
Now sometimes the context of the text you are translating might change, and you'll have to update the key accordingly. Or the base translation text will be updated significantly enough and of course it's not a big deal, but still it's additional work and would be cool to not have to do this.
Recent example, I was working on the armory screen, when all of a sudden i was renamed to <INSERT_YOUR OPTION> and keys had to be renamed accordingly.
## Reusing Translations
Not that it's impossible to reuse translations, but you'll have to create some shared namespace, and put some conscious effort to put some translations there if you'll want to reuse them in multiple contexts.
## Pluralization
## Overall Lack Of Automation
And last thing is that most of those tools solve only the problem of accessing the translations and substituting the text in place. All the workflow of creating and updating your locale files is up to you as a developer. But we'll get back to it later.
## Alternative - Gettext
Now, what did we find as an alternative? And it's not something new, this tool is actually older than me. Of course would be more impressive to say this if I would at least have grey hair.
But, long story short, we decided to use gettext, a program, or actually a system of programs that was originally written by Sun Microsystems almost thirty years ago.
Now let's have a look at a demo app localized using Gettext. I've used Jed here, that is javascript implementation of gettext and that allows me to have the translated components.
Actually let me go through all my complains about other solutions and just show how are they handled by gettext.
## Making Up Keys As Keys
Look at how translations are being used in my components. It's just regular text wrapped into `<T>` component. As we use the actual text as key - we don't have to come up with specific names for those strings. Which as I said can be cumbersome.
## Searching For Text That Needs To Be Translated
Now to change the base translation you just update the text in place, and everything else will be handled by gettext. We'll get to it, for now let's just update the text.
## Keeping Keys Up To Date With Base Translation
What was next, keeping keys up to date with the translations. No keys no need to keep them up to date.
## Reusing Translations
Also as a bonus it's now super easy to reuse your translations and save some sweet moneyz. Now by default if you have similar text on multiple screens it will be just one key in your translation file automatically. You won't have to think about it and have shared translations.
## Pluralization
## Automation
Now we came to the sweetest part, let me show how our workflow now looks like.
Let's say we have an app, we updated the texts there, added few more lines here and there.
Now we run our first script - `get translations from code`. It parses the components finds all the occurences of the `<T>` component
and puts them into translation template file.
Translation template files have same format as translation files themselves, but they are intended for developers, they are not used as source to translate the app.
From this file we can generate the base translation file, in our case `en-us`.
The script took the keys and used them as actual translated strings. It is needed in our specific workflow so we have the base text for our translators.
But if we wouldn't do this and leave the strings empty it wouldn't cause any problems, because in the app texts would just fallback to keys.
Now as we have base translation file generated we'll upload it to our translation service. We use phraseapp and it supports gettext format out of the box.
After we got our translations done, we can pull them.
And after we run the `convert to json` script they are ready to be consumed in our application.
Let's swith language in our app and verify that it works.
Now you see what makes me so joyful about this setup. Everything is automated and requires minimal effort to work with locales in your app.
Can it be done even better - yes. Most of the improvements should be done on javascript part.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment