10.1. Introduction

If you are in the lucky situation of only creating web pages in English, then you can skip this chapter completely. For you, everything is set up correctly by default. But even if you want to create a web page that only uses one language (other than English), you will need to dive into this chapter. It is not enough to just translate the views. Because already if you use scaffolding, you will need to take care of the English and therefore not yet translated validation errors.
The class I18n is responsible for anything to do with translation in the Rails application. It offers two important methods for this purpose:
  • I18n.translate or I18n.t
    Takes care of inserting previously defined text blocks. These can contain variables.
  • I18n.localize or I18n.l
    Takes care of adapting time and date specifications to the local format.
With I18n.locale you define the language you want to use in the current call. In the configuration file config/application.rb, the entry config.i18n.default_locale sets the default value for I18n.locale. If you do not make any changes there, this value is set by default to :en for English.
For special cases such as displaying numbers, currencies and times, there are special helpers available. For example, if you want to create a German web page, you can ensure that the number 1000.23 can be correctly displayed with a decimal comma as "1.000,23" on the German page and with a decimal point on an English web page as "1,000.23". As example, we use the German and English (US) variation of this amount with currency in the console:
$ rails new webshop
  [...]
$ cd webshop 
$ echo "gem 'rails-i18n'" >> Gemfile
$ bundle
  [...]
$ rails console
Loading development environment (Rails 3.2.9)
>> helper.number_to_currency('1000.23', :locale => :de)
=> "1.000,23 €"
>> helper.number_to_currency('1000.23', :locale => :en)
=> "$1,000.23"
>> helper.number_to_currency('1000.23', :locale => :fr)
=> "1 000,23 €"
>> exit
$

Note

To have a quick go at trying out the helper.number_to_currency in your own application, you first need to insert the line gem 'rails-i18n' into the file Gemfile and then execute bundle. This installs all required language files for you.

I18n.t

With I18n.t you can retrieve previously defined translations. The translations are saved by default in YAML format in the directory config/locales/. Technically, you do not have to use YAML as format.
In config/locales/ you can find an example file config/locales/en.yml with the following content:
en:
  hello: "Hello world"
In the Rails console we can try out how I18n.t works:
$ rails console
Loading development environment (Rails 3.2.9)
>> I18n.t :hello
=> "Hello world"
>> I18n.locale
=> :en
>> exit
$
Let's first create a config/locales/de.yml with the following content:
de:
  hello: "Hallo Welt"
Now back to the console:
$ rails console
Loading development environment (Rails 3.2.9)
>> I18n.locale
=> :en
>> I18n.t :hello
=> "Hello world"
>> I18n.locale = :de
=> :de
>> I18n.t :hello
=> "Hallo Welt"
>>
I18n.t looks by default for the entry in the language defined in I18n.locale. It does not matter if you are working with I18n.t or I18n.translate. Nor does it matter if you are searching for a symbol or a string:
>> I18n.locale = :en
=> :en
>> I18n.t :hello
=> "Hello world"
>> I18n.t 'hello'
=> "Hello world"
>> I18n.translate 'hello'
=> "Hello world"
>>
You can also specify the desired language for an individual I18n.t call with :locale => :de.
=> "Hallo Welt"
>> I18n.t :hello
=> "Hello world"
>>
If a translation does not exist, you get an error message that says "translation missing:". This also applies if a translation is only missing in one language (then all other languages will work, but for the missing translation you will get the error message). In that case, you can define a default with :default => 'any default value':
>> I18n.t 'asdfasdfasdf'
=> "translation missing: en.asdfasdfasdf"
>> I18n.t 'asdfasdfasdf', :default => 'asdfasdfasdf'
=> "asdfasdfasdf"
>> exit
$ 
In the YAML structure you can also specify several levels. Please amend the config/locale/en.yml as follows:
en:
  hello: "Hello world"
  example:
    test: "A test"
  aaa:
    bbb:
      test: "An other test"
You can display the different levels within the string with dots or with a :scope for the symbols. You can also mix both options.
$ rails console
Loading development environment (Rails 3.2.9)
>> I18n.t 'example.test'
=> "A test"
>> I18n.t 'aaa.bbb.test'
=> "An other test"
>> I18n.t :test, :scope => [:aaa, :bbb]
=> "An other test"
>> I18n.t :test, :scope => 'aaa.bbb'
=> "An other test"
>> exit
$
It is up to you which structure you choose to save your translations in the YAML files. But the structure described in Section 10.2, “A Rails Application in Only One Language: German” does make some things easier and that's why we are going to use it for this application as well.

Using I18n.t in the View

In the view, you can use I18n.t as follows:
<%= t :hello-world %>

<%= I18n.t :hello-world %>

<%= I18n.translate :hello-world %>

<%= I18n.t 'hello-world' %>

<%= I18n.t 'aaa.bbb.test' %>

<%= link_to I18n.t('views.destroy'), book, confirm: I18n.t('views.are_you_sure'), method: :delete %>

Localized Views

In Rails, there is a useful option of saving several variations of a view as "localized views", each of which represents a different language. This technique is independent of the potential use of I18n.t in these views. The file name results from the view name, the language code (for example, de for German) and html.erb for ERB pages. Each of these are separated by a dot. So the German variation of the index.html.erb page would get the file name index.de.html.erb.
Your views directory could then look like this:
|-app
|---views
|-----products
|-------_form.html.erb
|-------_form.de.html.erb
|-------edit.html.erb
|-------edit.de.html.erb
|-------index.html.erb
|-------index.de.html.erb
|-------new.html.erb
|-------new.de.html.erb
|-------show.html.erb
|-------show.de.html.erb
|-------
|-----page
|-------index.html.erb
|-------index.de.html.erb
The language saved in config.i18n.default_locale is used automatically if no language was encoded in the file name. In a new and not yet configured Rails project, this will be English.

Updates about this book will be published on my Twitter feed.