Localizing your Rails application
Recently I discovered that most of the visitors to one of my apps (What I want for Xmas) were from Italy. It suddenly seemed like a good time to localize my Rails application, but I had no idea where to start! I asked my twitter stream for recommendations for a good Rails plugin.
Peter Cooper pointed me in the right direction:
Yep! Rails 2.2 includes nice localization stuff right out of the box!
So, after some hard work I localized my app to cater for Italian visitors. (You can check out the Italian version here).
Here’s how I did it:
Get your Rails app ready for localization
In Rails 2.2 you get a folder that keeps all your locale details: /config/locales. This is where you’ll keep all the different locale snippets in files named after the locales (en.yml, it.yml etc)
You can set the default locale by setting a flag in environment.rb:
config.i18n.default_locale = :en
Translate your application into English
Next (oddly enough) you’ll need to translate your application into English (or whatever language your app is already). This means finding all the places where you have fragments of English and replacing it with something that looks like this:
t("main.title")
The t* stands for translate, and *main.title refers to a key in the locale yaml files. The yaml file can have nested keys, so, “main.title” finds the title key belonging to the main key in the yaml file. e.g.
main: title: "Some title"You can use string interpolation as well. So if you have text that looks like this:
"What #{name} wants for Xmas"
You can simply put the name of the variable within double braces in the yaml line like so:
title: "What {{name}} wants for Xmas"And then call on it with the t method by passing in the variable. Like this:
t("title", :name => user.first_name)
Translate your application into other languages
After you’ve gone through the arduous process of translating your app to English (yawn!) you can then create translations into other languages!
What I did was just grab the yaml file, and send it to an Italian friend to translate.
Here’s a portion of an example English yaml file:en: main_title: "What I want for Xmas" countdown: merry_xmas: "Merry Christmas!" days_until_xmas: "Only {{number_of_days}} until Xmas" days: "days" day: "day"And here’s the translated version:
it: main_title: "Ciò che voglio per Natale!" countdown: merry_xmas: "Buon Natale!" days_until_xmas: "Solo {{number_of_days}} fino a Natale" days: "giorni" day: "giorno"
Provide a way to switch between different locales
So, now you’ll need to add the ability to switch locales. What I did was put a before_filter
in application.rb that sets the locale depending on:
- whether the user is logged in and has a locale
- whether the locale is stored in the session
- failing that, use the default_locale – although this step could be unnecessary, but makes me feel comfortable.
# in Application.rb
before_filter :set_locale
def set_locale
I18n.locale = (current_user.locale if current_user) || session[:locale] || I18n.default_locale
end
I also included a locales controller for switching locality.
# locales_controller.rb
class LocalesController < ApplicationController
def show
if current_user # if I'm logged in
current_user.locale = params[:locale] # change my locality
current_user.save
end
session[:locale] = params[:locale]
redirect_to :back
end
end
# routes.rb
map.locales 'locales/:locale', :controller => 'locales', :action => 'show'
This enabled me to have links for simply switching languages that look like this:
link_to "English", locales_path('en')
Tips
Localizing your app can be a frustrating experience. Here’s some tips to ease the pain:
Repeat yourself
Resist the urge to DRY up your yaml snippets and have them used in several different locations. Different languages could translate your snippets differently depending on context.
Provide context for your translators
Your translators need to know a little bit about the context that the text represents. Write comments in your yaml file to make it easier for them.
Avoid the pluralize
method
Right now, you can’t trust the pluralize
helper method if you’re using localization. (i.e. it tried to say that the plural of giorno (day) is giornos (it’s actually giorni)
Instead, provide keys in your translation yaml files asking for the plural and singular words, and write a method for dealing with the plural.
Adopt some sort of convention in your yaml files for links that are embedded in other text.
For example, if you wanted to write Sign up if you want to join whatiwantforxmas.com I would separate this out in the yaml file like this:sign_up: "{{link}} if you want to join whatiwantforxmas.com" sign_up_link: "Sign up" # this is the text used in the 'link' variable above
Just because the “Sign up” appears at the front of the sentence in English, doesn’t make it so in another language.
Remember ActiveRecord validation messages and dates
Rails includes numerous English phrases. You can translate this quite easily by including the sample code found here in your yaml files.
What’s this Yaml thing?
Ideally you’ll want to get your translators to translate the yaml file. Beware though that yaml is a strange file format to non-technical people. Let your translators know here do get a file editor that they can use (SciTE for example. Grab it at http://prdownloads.sourceforge.net/scintilla/Sc177.exe)
But is it REALLY right
After getting the translation, walk through the website with the translator to make sure it’s REALLY right. Sometimes things translate differently when the context changes. I also noticed that some special characters sometimes got mixed up, so this is a good opportunity to spot those.
Translate ALL of the snippets
As I write this, if any of your translation files are missing a snippet, then you’ll get nasty ‘span’ classes outputted onto the screen. Make sure that each and everyone of your snippets are updated in every locale yaml file.