Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

The Last Rails I18n Guide You’ll Ever Need: Part II

DZone's Guide to

The Last Rails I18n Guide You’ll Ever Need: Part II

Here is the second half of Ilya Bodrov's guide for Rails I18n.

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

Here is the second half of Ilya Bodrov's guide for Rails I18n. Did you miss Part I? Read it here!

Translations for ActiveRecord

So now suppose we wish to manage blog posts using our application. Create a scaffold and apply the corresponding migration:

    $ rails g scaffold Post title:string body:text
    $ rails db:migrate

When using Rails 3 or 4, the latter command should be

    $ rake db:migrate

Now add the link to create a new post:

views/pages/index.html.erb

    <h1><%= t('.welcome') %></h1>

    <%= link_to t('.new_post'), new_post_path %>

Translations:

config/locales/en.yml

    en:
      pages:
        index:
          welcome: "Welcome!"
          new_post: 'New post'

config/locales/ru.yml

    ru:
      pages:
        index:
          welcome: 'Добро пожаловать!'
          new_post: 'Добавить запись'

Boot the server and click this new link. You'll see a form to create a new post, however, the problem is that it's not being translated: the labels are in English and the button says "Создать Post". The interesting thing here is that the word "Создать" (meaning "Create") was taken from the rails-i18n gem that, as you remember, stores translations for some common words. Still, Rails has no idea how to translate model's attributes and its title.

To achieve that, we have to introduce a special scope:

config/locales/ru.yml

    ru:
      activerecord:
        models:
          post: 'Запись'
        attributes:
          post:
            title: 'Заголовок'
            body: 'Текст'

config/locales/en.yml

    en:
      activerecord:
        models:
          post: 'Post'
        attributes:
          post:
            title: 'Title'
            body: 'Body'

So the models' names are scoped under the activerecord.models namespace, whereas attributes' names reside under activerecord.attributes.SINGULAR_MODEL_NAME.

The label helper method is clever enough to translate the attribute's title automatically, therefore, this line of code inside the _form.html.erb partial does not require any changes:

    <%= f.label :title %>

Now provide some basic validation rules for the model:

models/post.rb

  validates :title, presence: true
  validates :body, presence: true, length: {minimum: 2}

Next, try to submit an empty form and note that even the error messages are localized properly thanks to rails-i18n gem! The only part of the page left untranslated in the "New Post" title and the "Back" link - I'll leave them for you to take care of.

Date and Time

Now let's discuss how to localize date and time in Rails. Before moving on, create a post either using a form or by employing seeds.rb file. Also, add a new link to the root page

pages/index.html.erb

    <%= link_to t('.posts'), posts_path %>

Then translate it

config/locales/en.yml

    en:
      pages:
        index:
          posts: 'Posts'

config/locales/ru.yml

    ru:
      pages:
        index:
          posts: 'Список записей'

and tweak the posts index view by introducing a new column called "Created at":

views/posts/index.html.erb

    <table>
      <thead>
        <tr>
          <th>Title</th>
          <th>Body</th>
          <th>Created at</th>
          <th colspan="3"></th>
        </tr>
      </thead>

      <tbody>
        <% @posts.each do |post| %>
          <tr>
            <td><%= post.title %></td>
            <td><%= post.body %></td>
            <td><%= post.created_at %></td>
            <td><%= link_to 'Show', post %></td>
            <td><%= link_to 'Edit', edit_post_path(post) %></td>
            <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
          </tr>
        <% end %>
      </tbody>
    </table>

We are not going to translate all the columns and titles on this page - let's focus only on the post's creation date. Currently, it looks like "2016-08-24 14:37:26 UTC" which is not very user-friendly. To localize a date or time utilize the localize method (aliased as l).

    l(post.created_at)

The result will be "Ср, 24 авг. 2016, 14:37:26 +0000" - that's the default (long) time format, but rails-i18n gem provides some additional ones that can be used out of the box - you can see their masks here (for the dates) and here (for the times). If you have used Ruby's strftime method before, you'll notice that those format directives (%Y, %m and others) are absolutely the same.

In order to employ one of the predefined formatting rules, say

    l(post.created_at, format: :long)

If you are not satisfied with the formats available by default, you may introduce a new one for every language:

ru:
  time:
    formats:
      own: '%H:%M:%S, %d %B'

Now this format can be used inside the view:

    l(post.created_at, format: :own)

Of course, if for some reason you don't want to define a new format, the mask may be passed directly to the :format option:

    l(post.created_at, format: '%H:%M:%S, %d %B')

Just like the t method, l also accepts the :locale option:

    l(post.created_at, locale: :en)

The last thing to notice here is that rails-i18n also has translations for the distance_of_time_in_words, distance_of_time_in_words_to_now and time_ago_in_words methods, so you may employ them as well:

    time_ago_in_words(post.created_at)

Pluralization Rules and Variables

Different languages have, of course, absolutely different pluralization rules. English words are pluralized by adding an "s" flection (except for special some cases), but in Russian, for example, pluralization rules are much complex, therefore it is your job to add them.

Suppose we want to display how many posts were written for the blog. Create a new scope and add pluralization rules for the English locale:

locales/en.yml

    en:
      posts:
        index:
          count:
            one: "%{count} post"
            other: "%{count} posts"

The %{count} is the variable part - we will pass a value for it when using the t method.

As for the Russian locale, things are a bit more complex:

locales/en.yml

    ru:
      posts:
       index:
         count:
           zero: "%{count} записей"
           one: "%{count} запись"
           few: "%{count} записи"
           many: "%{count} записей"
           other: "%{count} записи"

Rails automatically determines which key to use based on the provided number.

Now tweak the view:

views/posts/index.html.erb

    <%= t('.count', count: @posts.length) %>

Note that there is also an inflections.rb initializer file that can be used to store inflection rules for various cases.

Lastly, you may provide any other variables to your translations utilizing the same approach described above:

    en:
        apple_price: "Apple costs %{amount} dollars"

Then just say:

    t('apple_price', amount: 5)

PhraseApp Makes Your Life Easier!

Keeping track of translation keys as your app grows can be quite tedious, especially if you support many languages. After adding some translation you have to make sure that it does present for all languages. PhraseApp is here to help you!

  • Create a new account if you don't have one, fill in your details, and create a new project (I've named it "I18n demo")
  • Navigate to the Dashboard - here you may observe summary information about the project
  • Open Locales tab and click Upload File button
  • Choose one of two locale files (en.yml or ru.yml). The first uploaded locale will be marked as the default one, but that can be changed later
  • Select Ruby/Rails YAML from the Format dropdown
  • Select UTF-8 for the Encoding
  • You may also add some Tags for convenience
  • Upload another translations file

Now inside the Locales tab you'll see two languages, both having a green line: it means that these locales are 100% translated. Here you may also download them, edit their settings and delete.

Next suppose we want to add support for German language and track which keys need to be translated.

  • Click Add locale button
  • Enter a name for the locale ("de", for example)
  • Select "German - de" from the Locale dropdown
  • Click Save

Now the new locale is present one the page. Note there is a small message saying "9 untranslated" meaning that you will have keys without the corresponding translation. Click on that message and you'll see all the keys we've added while building the demo app. Now simply click on these keys, add translation for them and click Save (this button may be changed to Click & Next). Note that there is even a History tab available saying who, when and how changed translation for this key.

When you are done return to the Locales tab and click Download button next to the German locale. You'll get a YAML file that only needs to be copied into the locales directory - the translation is done!

Localization is not only about translation and you may be not that familiar with a language you plan to support. But that's not a problem - you can ask professionals to help you! Select Order Translations from the dropdown next to the locale, choose provider, provide details about your request and click Calculate price. Submit request and your translation will be ready soon! Here you can read more about professional translations and average prices.

Conclusion

So, in this article we've discussed internationalization and localization in Rails. We've set up basic translations, introduced localized views, translated ActiveRecord attributes and models, localized date and time, and also provided some pluralization rules. Hopefully, now you are feeling more confident about using I18n with Rails!

For additional information, you may refer to this official Rails guide and read up some info on rails-i18n GitHub page. Storing translations inside the YAML files is not the only approach in Rails, so you may be interested in a solution called Globalize — with the help of it, you may store translations in the database.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
rails tutorial ,i18n ,ruby ,translation ,web dev

Published at DZone with permission of Ilya Bodrov. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}