Internationalizing Your Ruby on Rails Application
Definition Time: What is i18n?
The terms "i18n" and "l10n" are often thrown around in the tech and linguistics worlds, but just what exactly do they mean?
Well in short, "i18n" is an abbreviation for the word internationalization. The term is named after the fact that the word internationalization has 18 letters between the "i" and the "n." Similarly, "l10n" stands for localization because there are 10 letters between the "l" and the "n."
Now that we've got these definitions out of the way, it's time to get down to business, or b6s as I like to call it.
Why Internationalize Your Rails Application?
Often developers come to me and ask why they should bother internationalizing their web applications. Well, the answer I often tell them is a blunt "Why not?" The truth is, it's a heck of a lot easier to internationalize a site from the get go then it is to uplift an existing application.
Besides being dead simple, there are numerous other reasons for wanting to internationalize your site. Here are but a few:
- Reach A Global Audience. If you restrict your site to just your native language, you could be missing out on millions of users. Even if you're just starting out, it's important to prepare early on for the global market.
- Extract Out Your Copy. If you are internationalizing a Rails application, chances are you will be using the default i18n gem and placing your translations in some yml files. Aside from making your text i18n ready, this has the added benefit of extracting out all copy into a format that can be edited by non-developers. With your text in yml files, translators/copywriters will not need to be familiar with your view code to update your site's text, freeing up valuable development time.
- Improve Your Tests. Many developers, myself included, feel that localization can make your automated view tests more robust, as this blog post points out. When all of your text is properly localized, you can compare what is in the view directly against what is outputted by the translation helpers instead of against static tests. This means that a simple (valid) update your site's copy won't cause test failures.
How To Begin With i18n
So hopefully by now you are sold on the importance of internationalizing your Ruby on Rails application. The next question, however, is where to begin? Thankfully, Rails (version 2.2 and above) makes i18n super simple by including the i18n gem by default. That means adding new translations is as simple as modifying your "config/locales/en.yml" file. So go ahead, we'll get started by adding a simple key to this file:
en: hello: "Hey, how YOU doin?"
Now, in one of your views, simply reference this translation by invoking the Rails translation helper:
# app/views/home/index.html <%= t('hello') %>
It's as simple as that! In your view now the user will see the translated text depending on their locale. This means that for an English user they will see the pleasant message "Hey, how YOU doin?" Isn't that great?! For more information on internationalizing your app, I recommend reading the Rails guide on i18n.
In addition to simple messages like this, you can localize dates and even interpolate variables into your translations. All of that is covered in the guide that I linked to above.
Writing i18n Friendly HTML
It's not enough to simply rely upon the Rails t method and call it a day. Unless you write i18n friendly markup, all of your globalization and localization efforts may be for nought. Here are a few suggestions for writing some truly worldly HTML.
Use UTF-8 Encoding
This may come as a no-brainer to some folks, but I feel it is worth mentioning. In order to support more than just latin-based languages, you will need to support the UTF-8 character set. This means that you should ensure that your application supports it across the whole stack -- all the way from the database level (if you're using Rails 4.1 configure ActiveRecord to use 'utf8mb4') to your Ruby code to your markup. At the HTML level this is as simple as declaring the following in your document's head (in HTML5 this is the default):
Use The "lang" Attribute Appropriately
To assist screen readers, crawlers, and other mechanical page readers, it's important to properly use the "lang" attribute on your HTML elements. This means that you should set the main language for a document on the initial <html> tag. Whenever the language changes, you should set a "lang" attribute on the relevant tag for that content. Here's a very rough example of how you could do that in a multi-lingual Rails view using ERB:
# I18n.default_locale = 'en' by the way <html lang="<%= I18n.locale %>"> <head> ... </head> <body> <p><%= t('.welcome') # An English welcome message %></p> <p lang="es"> <%= t('.another_message', locale: 'es') %> </p> <p><%= t('.something_else') %></p> </body> </html>
As you can see, the "lang" attribute will allow non-human consumers of your site to know how to interpret different portions of your site.
Use The "dir" Tag To Support Non-Left-To-Right Text Directions
If your site supports non-left-to-right text (which we'll refer to as ltr from now on), be sure to set the "dir" attribute in your initial <html> tag. So if you're rendering a page in Arabic, for example, your html tag should look like this: <html dir="rtl" lang="ar">. This will inform the browser that the language needs to float right by default and it will adjust all other elements accordingly.
Other Things To Consider
We're just scratching the surface with these suggestions, there's a whole slew of things to consider when internationalizing your markup. To keep informed, I recommend reading the w3c's articles on the subject.
Now that you have your site internationalized, you'll want to ensure that it stays that way. By this, I mean that you'll want to have tests in place to prevent regressions and ensure that all translations are accounted for. To start off, I recommend reading this post on testing i18n in Ruby on Rails. It covers some of the techniques that you can use for finding missing translations and ensuring that everything on your application is translated as expected.
Testing Your Application's Design
Automated tests for missing translations are only a start, however. It's one thing to ensure that your site has no missing translations, it's another thing to ensure that all translations fit properly. To test the responsiveness of your site's design, I recommend using the i18n-tasks gem's Google Translate feature. Although the Google translation API is no longer free, it is still relatively cheap, and you can have your entire site translated (mostly correctly) in dozens of languages for around ten bucks. Then, once you have a good deal of translations, I recommend creating a composite set of translations -- a fake locale if you will, that only contains the longest keys from each language. This way you can easily see how your application handles the worst case linguistic scenarios.