Rails: I18n — how to translate text containing links using gem “it”

The basics

Translating normal texts with I18n in Rails is quite simple:

welcome_message: This is some text written in en.yml
= t('welcome_message') # in some_view.html.haml

You can also include HTML and interpolation escapes:

welcome_message: Hello and welcome user <b>%{username}</b>!
= t('welcome_message', username: @current_user.username).html_safe

Note that only keys with a “_html” suffix or keys which are named “html” (e.g. “welcome_message_html” or “welcome_message.html”) are marked as HTML safe — otherwise you would have to use raw or html_safe as shown above.

The problem

What if we want to include one or multiple links in our translation texts?

Do not just include a <a href> HTML tag in the translation file and define all parameters there, this will leave you with a bunch of problems while your app is growing, e.g. im routes change.

What you want to do is use the power of link_to from Rails UrlHelper — so we use interpolation escapes and define the labels of our links:

welcome_message: Hello and welcome, 
please %{register_link} or %{login_link}
register_message: register an account
login_message: login with your credentials
t('welcome_message',
register_link: link_to(t('register_message'), register_path),
login_link: link_to(t('login_message'), login_path)).html_safe

This works — but as you see it is necessary to provide the keys and translations for the description of the links to keep the advantages of using I18n. With this , using multiple texts in your language files and especially texts with multiple links included can look quite messy. So can we improve this?

The (more beautiful) solution

The issue was discussed on Stack Overflow: translating text with links inside where I also found the very useful gem “it” by iGel. Using “it” we can shorten the above example to:

welcome_message: Hello and welcome,
please %{register_link:register an account}
or %{login_link:login with your credentials}
it('welcome_message',
register_link: register_path,
login_link: login_path
)
…it doesn’t require raw anymore. Of course, all HTML in the translation gets properly escaped, so you don’t have to worry about XSS. (from the README)

Be aware that if you do not use an interpolation named “link” or a name starting / ending with “link_” / “_link” you have to call It.link — which than gives you the possibility of specifying options same as with link_to:

welcome_message: Hello and welcome,
please %{register_link:register an account}
or %{login_link:login with your credentials}
it('welcome_message',
register_link: It.link(register_path, target: '_blank', class: 'highlight'),
login_link: login_path)

For further information about the gem and other functions like nested interpolations take a look at the github repo of “it”.