

Internationalizing your Rails Application - zimkies
http://eng.joingrouper.com/blog/2014/04/03/rails-internationalization-translation/

======
tr8n
Have you ever heard of Tr8n? [http://github.com/tr8n](http://github.com/tr8n)

And specifically Tr8n for RoR:
[https://github.com/tr8n/tr8n_rails_clientsdk](https://github.com/tr8n/tr8n_rails_clientsdk)

It is a powerful translation framework, which significantly simplifies the
translation process, while improving your code readability.

First of all you don't need to deal with resources bundles at all - use
English keys right in the code. Tr8n takes care of the rest.

<%= tr("Hello World") %>

Dynamic data tokens are very easy to work with:

<%= tr("Hello {user}", :user => "Michael") %>

It fully supports language context rules:

<%= tr("You have {count||message}", :count => 10) %> <%= tr("{user|He, She}
likes this", :user => some_user) %> <%= tr("{users||likes, like} this a lot",
:user => some_users) %>

It even supports language cases:

<%= tr("{actor} likes {target::possessive} message", ...) %>

Tr8n uses TML (Translation Markup Language) to define translation keys that
now an be shared across all platforms and applications (mobile, web, desktop).

TML can easily handle data and decoration tokens within the same key context:

<%= tr("You have [bold: {count||message}]", :count => 10, :bold => lambda{|t|
"<strong>${t}</strong>"}) %>

<%= tr("This is indeed [bold] a very [italic: powerful] framework]",...) %>

You can predefine all your lambdas elsewhere and use default data and
decorations throughout your app.

The same sentence above, since it uses TML instead of hardcoded HTML, will
actually produce an NSAttributedString in iOS properly decorated in any
language.

Tr8n is used in conjunction with Tr8nHub.com where you have access to UTM
(Universal Translation Memory) - a huge database of translations used across
all applications. You may get fully translated by just connecting to it.

Disclosure: I've been working on Tr8n for the past 4 years, constantly
improving it. We are about to launch a new site soon that will make a lot of
things much cleaner and easier. The framework is used by companies like Yammer
and Geni.

I forgot to mention that you get inline translation tools, translation
widgets, and a lot more...

~~~
Groxx
Hmmm. I like the idea of a shared database, but on the flipside you "only"
need your developers to precisely understand the language they're using. The
vast majority of people have no need for a deep understanding of their native
language, I'd be worried about subtly-wrong translations. Something is better
than nothing, but _weird_ is still bad. For example, you use "you" in "You
have {count||message}" \- there's no gender or other meaning encoded, it'll
probably be a bit off for some languages.

More technically: how does this translate?

> _This is indeed [bold] a very [italic: powerful] framework][ /bold]_

To make a hypothetical worst-case scenario, say one of the target languages
combines "this" and "powerful" into a single word, splits "framework" into
three, and reorders it so conceptually you flip between bold and italic and
plain practically at random. There's (probably) an element of aesthetics
combined with the text's meaning, _can_ the crowd detect that aesthetic? What
if it varies all over your site because it's sourcing from different crowds?

Similarly, say you refer to "this" thing on the website/app, which is up and a
little to the right, but not this other thing to the left. RTL probably
switches that, and does "up and a little to the right" have an encoding in TML
so that the meaning is retained if a language has a specific word for that?

~~~
tr8n
Groxx, you bring up very good points. Let me see if I can address them all.

In the case of "You have {count||message}" as with actually pretty much any
translation key, an implied "viewing_user" token is automatically added by the
Tr8n SDK to provide the gender of the viewing user. So in languages, like
Hebrew, where "You" depends on the gender of the person you are referring to,
there would be actually 2 translations for the key:

"Yesh leha {count||hodaa, hodaot}" for {viewing_user: {gender: male}}

"Yesh lah {count||hodaa, hodaot}" for {viewing_user: {gender: female}}

The SDK would know how to pull the right translation and do the substitution
at the time of the expression evaluation.

Here is what inline translator tool looks like when you deal with such a
situation:

Notice there is a link below the text area to generate context rules for the
phrase:

[http://grab.by/vMTk](http://grab.by/vMTk)

When you select that option, you can generate all rule permutations for the
key:

[http://grab.by/vMTo](http://grab.by/vMTo)

[http://grab.by/vMUc](http://grab.by/vMUc)

Alternatively, you can use TML and provide a single translation:

"Yesh {viewing_user| male: leha, female: lah} {count|| one: hodaa, other:
hodaot}"

Or using the shorthand notation:

"Yesh {viewing_user| leha, lah} {count|| hodaa, hodaot}"

Single pipe means "use the context, but don't display the value". Double pipe
means "use context and display the value".

Looks a bit cryptic, but once you get a hang of it, it becomes a second
nature. Try doing this in I18n.

Even in English you can do things like:

"{user| Born on:}" \- in other languages depends on user gender

"{user| He, She} likes this"

"{users|| loves, love} this"

Context Rules and Language Case Rules are defined per each language. And the
conversion happens on the fly when needed.

For example, in Hebrew, the last example would need many more options:

"{users|| male: ohev, female: ohevet, males: ohavim, females: ohavot, other:
ohavim} ze"

Because in Hebrew it matters whether all users in the list are male, female or
mixed.

In Russian, it needs 2 cases - same as English (but only in present tense):

"{users|| lubit, lubyat} eto"

But if the key happened to be in past tense like:

"{users} liked this"

In English is same for whether there is one person in the list or many.

In Russian, we get 3 cases:

"{users|| lubil, lubila, lubili} eto"

Etc...

For the decoration tokens in a sentence like:

"This is indeed [bold] a very [italic: powerful] framework [/bold]"

It is up to the translator to completely shift things around in any possible
way to convey the meaning of the original key. The only thing the SDK does is
try to ensure that you don't try to inject anything ugly into the sentence. So
lets say the translation to the above in Elbonian would be:

"Munchu punchu [bold: munchuchu] punchu"

Since the Elbonian language doesn't even have a separate word for "powerful",
but instead a single word for "a very powerful framework", so they had to omit
the italic part altogether. And that is perfectly fine. The translator's job
is to provide the best translation that would convey the most meaning of the
original sentence. Well, and they should try to massage the decoration tokens
the best they can, if they can at all.

Since they could use the inline translator tools, they should be able to see
their result right away and try to make it look the best they can in the space
where the key appears on the site.

The beauty about the decoration tokens is that they are replaceable and
reconfigurable even after you have hundreds of translations for the key. As I
was mentioning earlier, in Rails the tokens will be replaced with HTML, but in
iOS you can create an NSAttributedString and reuse all translations, etc...

I didn't fully understand your "up and a little to the right" example. If you
can give me an actual example, that would be great.

TML works in RTL and LTR cases equally well. And since you are the one
controlling the container of the app, you can use CSS to make it look like
whatever you want.

------
shpiel
One of the most annoying things about translation is that the length of the
string may change which can mess up designs and layouts. For example German
strings tend to be longer than their English equivalents. Or dealing with
languages which orientation is right to left (eg. Hebrew).

~~~
colinsidoti
At an airbnb techtalk they stressed how this is a really annoying problem for
them. They actually have a subdomain that substitutes longer than normal
english strings within their design:

[https://xxlong.airbnb.com/](https://xxlong.airbnb.com/)

~~~
Groxx
That's a pretty common approach. In Rails it's also not too hard to monkey
patch I18n in development to e.g. double every string it returns, or throw in
random UTF characters.

The hard part I've encountered is that you have to _think_ about text
differently. Things that are identical in English but have different semantic
meanings must be split. Plurals. Almost-never concatenating or .join(',')ing
or .split()ing. It's pretty easy to write yourself into a corner unless you
stick to doing it right all the time, which takes some time to learn.

------
nathanappere
For the javascript part:
[https://github.com/fnando/i18n-js](https://github.com/fnando/i18n-js)

