We’ve been doing Ruby on Rails projects here at Agency Fusion for a year now. I’m somewhat of a stickler for doing things The Right Way™. Luckily, the Rails framework has a pretty nice method for translating strings throughout the site. In this post I’m going to outline some of the different ways that you can implement localized strings and the advantages and disadvantages of each.
First, in Rails there are two methods used for localization: translate
(aliased t
) and localize
(aliased l
). Pretty straightforward,
right? See the ActionView::Helpers::TranslationHelper docs for
more info. Here are some quick examples of them being used in the wild:
I like to put the t
next to the =
because it looks nice and concise,
but the following is the exact same thing:
The yaml file with translated strings would look like this:
Okay, now let’s discuss the above strategy.
I18n gettext style
The above type of translation is a lot like the gettext style of
translating strings. You provide the full English translation, and that
translation is used as a sort of key. The problem with doing it this way
in Rails, though, is that Rails doesn’t have a full implementation of
gettext, so it doesn’t allow you to attach a domain and/or context to a
string. What this means is that all instances of 'This is the header!'
will be translated exactly the same across all uses, even if it makes
sense to translate one instance a different way for some languages. To
sum up:
- Advantages:
- Easy and straightforward.
- If there are no translations for that key in the appropriate language, it will just use the key, which is great for English.
- Disadvantages:
- There is no way to contextualize the translation.
Symbolized Keys
Another method that has similar strengths and weaknesses is to you use symbols as translation keys:
This is nice, mostly because symbols are such a beautiful feature of Ruby syntax. They have the same advantages and disadvantages of using a full-text key, except that when there isn’t a translation available in the yaml file, it will return a capitalized version of the string:
This Is The Header
This is okay in a lot of instances, but again, it doesn’t provide the contextualization that you often need with translations.
A contextualization pattern for Rails i18n
To include context, you can namespace your keys. This is a little bit of a combination between the first two approaches with a little twist:
The reason I gave the full relative path to the view was so that we
could see what controller and action the view belonged to. The above
example would be the view for the ExampleController
’s index
action.
This is important because the .
before this_is_the_header
in the
translation key automagically provides controller/action context to the
key. The yaml file then looks like this:
I love this way of doing things, but it is also not without
disadvantages. The main disadvantage is that you have to now have a
translation of the same basic key (this_is_the_header
) for every view
that uses it. This can suck for some strings that you use throughout the
site.
One method to overcome this, though, is to use the :default
option as
an option argument to the t
method:
Now the key has a default translation, but can be overridden per context if needed. So if there is another view that you decide to override for Korean, you can do so without affecting all other instances of the translated key:
The Korean translation above defaults in all instances except the
other
action to the common.this_is_the_header
translation, but the
English is the same across the board.
This method, unfortunately still has one ugly disadvantage, and that is that translating strings can sometimes make for really long lines in your views when you provide interpolated elements to your translations:
Maybe there’s a better way to deal with this, but I am as yet unaware of what it might be. Leave any ideas in the comments, thanks!