The Wordchuck Blog.

Shelly Roche is a Ruby on Rails engineer and founder of Wordchuck. She usually blogs about Ruby, Rails 3, woodchucks, i18n, l10n, startup life or whatever has her fired up on any given day. Yes, she is available for i18n consulting & training. Find her or by .

How to: Localize in Rails 3

by Shelly

What is Localization?


If you want to offer your site in more than one language, you need to go through a process called internationalization (i18n) and localization (l10n).

As I wrote about in my previous post, the internationalization process involves abstracting your site’s content strings, dates and currencies from your application and replacing each abstracted piece of content with a placeholder.

The localization process involves translating your content and providing other locale-specific information, like date and currency formats.

Localization in Rails 3:


In Rails 3, all dependencies for localization (l10n) are automatically included as part of the built-in i18n library, so let’s take a look at the three steps required to localize your site using i18n’s default Simple backend (more on that in another post):

Step 1: Add translations


When we internationalized our site, we created a locale file to store our site's content strings in our default language -- for this example, English. We created our base locale file in config/locales and called it en.rb. If we want to offer our site in French, we need to add a new locale file to config/locales (called fr.rb) to store our French translations. The French locale file will look very similar to our base English locale file, except:
»  the language code will be :fr instead of :en, and
»  the descriptive content keys (:page_title, for example) will point to the French translation:
{
  :fr =>
  {
    :welcome => {
      :page_title => "Bienvenue sur mon site!"
    }
  }
}

We'll create a new locale file for each language, so if we are translating into French, Spanish and Japanese, we'll end up with four files in our config/locales directory: en.rb, fr.rb, es.rb and ja.rb.

As you can imagine, managing content and translations becomes pretty cumbersome as our site's content grows and changes. Every change requires us to generate new translations, then copy and paste the new translations into each locale file.

Step 2: Define locale-specific formats


Localization involves more than just translating a content string from one language into another. We also need to tell our app how to display locale-specific content like dates and currencies.
{
  :'fr' =>
  {
    :date => {
      :abbr_day_names => ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"],
      :abbr_month_names => ["day", "month", "year"],
      :day_names => ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
      :month_names => ["~", "janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
      :formats => {
        :default => "%d/%m/%Y",
        :long => "%e %B %Y",
        :long_ordinal => "%e %B %Y",
        :only_day => "%e",
        :short => "%e %b"
      }
    }
  }
}
We can find community-contributed locale-specific formats for a multitude of locales on github. These files are a great starting point, but it's definitely a good idea to review each one for consistency and errors before using it in a production environment.

Step 3: Use localized formats


To use a localized date format, we simply specify the :format in our view code, like so:
"content">

Last updated <%= post.updated_at, :format => :short -%>

> </div>
YAY - we now have a properly internationalized and localized Rails 3 app, and are ready to look at ways to add some sophistication. Next up: Activerecord validation error messages.

Additional Resources:


If you'd like to play around with a fully-featured Rails 3 i18n and l10n implementation, check out our demo app here. The source code is available on github, so you can see exactly how everything works.

The official Rails i18n API documentation is excellent, and packed with all sorts of additional details and options for doing more complex implementations of internationalization and localization.