12

Rails i18n — Handling formatting within translated content

 3 years ago
source link: https://sourcediving.com/rails-i18n-handling-formatting-within-translated-content-e45f4d6cf63d
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Rails i18n — Handling formatting within translated content

Image for post
Image for post

At Cookpad we build a global product to not only make cooking fun every day but also everywhere. With the help of the Rails Internationalization (i18n) API we have brought Cookpad to over 30 languages around the world. However, translating a product in 30 languages is not easy, and we’re constantly learning and improving.

In the following article we will introduce one approach we’ve adopted for handling formatting of translated phrases.

Our Workflow

  • Working on a new feature, our development team uploads all new phrases in English to OneSky.
  • Our colleagues around the world use the OneSky UI to translate new phrases.
  • Once a day an automated background job imports any new translations back into our repository.

Passing Variables to Translations

As stated in the Rails i18n guide, a key consideration for successfully internationalizing an application is to avoid making incorrect assumptions about grammar rules when abstracting localized code. Let’s say we want to display when a user joined Cookpad. A naive implementation could look like this:

# app/views/users/show.html.erb
<%= “#{t(‘joined’)} #{@user.created_at.year}” %># config/locales/en.yml
en:
joined: “Joined”

This translation makes the assumption that `Joined` is always in front of the date. However, a correct translation for German would be ‘2020 beigetreten’. A better abstraction therefore would be:

# app/views/users/show.html.erb
<%= t("joined", year: @user.created_at.year) %># config/locales/en.yml
en:
joined: "Joined %{year}"# config/locales/de.yml
de:
joined: "%{year} beigetreten"

So far so good! But what happens if we now need to make the year bold?Luckily you can use HTML in translations by adding a ‘_html’ suffix to the key. We can now simply add a ‘<b>’ tag in our translation:

# app/views/users/show.html.erb
<%= t("joined_html", year: @user.created_at.year) %># config/locales/en.yml
en:
joined_html: "Joined <b>%{year}</b>"# config/locales/de.yml
de:
joined_html: "<b>%{year}</b> beigetreten"

Problem solved, right? Not quite, because we’re now mixing content and formatting which leads to other problems:

  • Our translators, who are not developers, may be confused by markup languages and make mistakes when editing the translation.
  • If we want to change the formatting, we now have to update all the translations.
  • If the markup is even slightly more involved than a simple ‘<b>’ (ie links, HTML classes etc), it quickly becomes a maintenance nightmare, that’s also very prone to mistakes.

Solution

The solution we’ve adopted is to pass in any formatting to the translation:

# app/views/users/show.html.erb
<%= t “joined_html”,
year: tag.b(@user.created_at.year)
%># config/locales/en.yml
en:
joined_html: "Joined %{year}"# config/locales/de.yml
de:
joined_html: "%{year} beigetreten"

This can scale to accommodate even complicated markup, by combining strings:

# app/views/users/show.html.erb
<%= t “have_account_html”,
link: link_to(t(“login”), logout_path, class: “link-primary”)
%># config/locales/en.yml
en:
have_account_html: “Already have an account? %{link}”
login: “Login here.”

Summary

While it may take a bit of extra work and the ERB markup grow slightly more than we’d ideally wish for, ultimately we think it’s worth it for the problems it saves us from in the long run.

Your translators (and future you) will thank you!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK