Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails and I18n: localized templates vs localized string

As you probably know, starting from Rails 2.2, Rails is shipped with a simple localization and internationalization backend.

By default, you can store the strings you need to translate in the localization files within the config folder.

config/locales/en.yml
config/locales/it.yml

But Rails provides the ability to localize templates and partials as well. For example, the MainController#index action can select a localized template according to the template filename and current locale settings.

apps/views/main/index.it.html.erb
apps/views/main/index.en.html.erb

The first feature is useful when you need to translate single strings or short paragraphs. The latter is a good choice when the same action renders in different ways according to current locale value.

But how do you deal with fair simple templates that share the same business logic but contains a large amount of text? Take for example the following template

<% javascript_content_for :head do %>
$(function() {
  $("#choices :radio").change(function() {
    $(".choice-wizard").hide();
    $("#" + $(this).val()).show();
  });
});
<% end %>

<h1><%= title t(".title") %></h1>

<div class="widget">
  <div class="entry form">

    <h2><%= title t(".header_choices") %></h1>

    <% form_tag "#", :id => "choices" do %>
      <p>
        <%= radio_button_tag :choice, "with" %>
        <%= label_tag "choice_with", "..." %>
      </p>
      <p>
        <%= radio_button_tag :choice, "without" %>
        <%= label_tag "choice_without", "..." %>
      </p>
    <% end %>

    <div id="with" class="choice-wizard" style="display: none;">

      <!-- to be localized -->
      <h3>....</h3>
      <p>a long paragraph</p>
      <p>a long paragraph</p>

      <p class="textcentered">
        <%= link_to "Continue", new_path, :class => "button" %>
      </p>
      <!-- / to be localized -->

    </div>

    <div id="without" class="choice-wizard" style="display: none;">

      <!-- to be localized -->
      <h3>....</h3>
      <p>a long paragraph</p>
      <p>a long paragraph</p>

      <p class="textcentered">
        <%= link_to "Continue", new_path, :class => "button" %>
      </p>
      <!-- / to be localized -->

    </div>

  </div>
</div>

<% sidebar do %>
  <%= render :partial => "sidebar/user" %>
<% end %>

Here I have a form, a JavaScript content and a small amount of text. I need to translate the text but:

  1. the text is too long for creating a simple string in the .yml file and I don't want to end up creating O(n) strings, one for each paragraph
  2. the template contains some "features" and I don't want to create 5 template, one for each language, because it will make the app harder to maintain.

How would you organize the code?

like image 278
Simone Carletti Avatar asked Nov 26 '09 15:11

Simone Carletti


People also ask

What does localized string mean?

There are two categories of localized strings: the strings included in the installation package's UI, common to every MSI file. the strings included in your project, that are particular to the current project: the name of your application, file names, registry values, properties etc.

What is I18n Rails?

The Ruby I18n (shorthand for internationalization) gem which is shipped with Ruby on Rails (starting from Rails 2.2) provides an easy-to-use and extensible framework for translating your application to a single custom language other than English or for providing multi-language support in your application.

What is I18n t?

Internationalization (i18n) is the process of preparing software so that it can support local languages and cultural settings. An internationalized product supports the requirements of local markets around the world, functioning more appropriately based on local norms and better meeting in-country user expectations.


1 Answers

In Rails (at least version 2.3.4), partials respect the same internationalization settings that the views and templates do, so what you could do is put your large bodies of text into partials that are translated, while keeping your features in the original view. For the labels and 'smaller' text, using the t(...) translation method could be used as you suggested. So, to run with your concrete example:

# app/wizards/edit.html.erb
<% javascript_content_for :head do %>
$(function() {
  $("#choices :radio").change(function() {
    $(".choice-wizard").hide();
    $("#" + $(this).val()).show();
  });
});
<% end %>

<h1><%= title t(".title") %></h1>
<div class="widget">
  <div class="entry form">
    <h2><%= title t(".header_choices") %></h1>
    <% form_tag "#", :id => "choices" do %>
      <p>
        <%= radio_button_tag :choice, "with" %>
        <%= label_tag "choice_with", "..." %>
      </p>
      <p>
        <%= radio_button_tag :choice, "without" %>
        <%= label_tag "choice_without", "..." %>
      </p>
    <% end %>
    <div id="with" class="choice-wizard" style="display: none;">
      <!-- to be localized -->
      <%= render :partial => 'dear_readers' %>
...

# app/views/wizards/_dear_readers.en.html.erb
<h3>A Title</h3>
...

# app/views/wizards/_dear_readers.sv.html.erb
<h3>Bork bork bork!</h3>
...

And so forth. My apologies to Sweden.

Another possibility to go with my comment below:

# app/views/wizards/edit.html.erb
<%= render :partial => 'dear_readers' %>
<% javascript_content_for :head do %>
$(function() {
  $("#choices :radio").change(function() {
    $(".choice-wizard").hide();
    $("#" + $(this).val()).show();
  });
});
<% end %>

<h1><%= title t(".title") %></h1>
<div class="widget">
  <div class="entry form">
    <h2><%= title t(".header_choices") %></h1>
    <% form_tag "#", :id => "choices" do %>
      <p>
        <%= radio_button_tag :choice, "with" %>
        <%= label_tag "choice_with", "..." %>
      </p>
      <p>
        <%= radio_button_tag :choice, "without" %>
        <%= label_tag "choice_without", "..." %>
      </p>
    <% end %>
    <div id="with" class="choice-wizard" style="display: none;">
      <!-- to be localized -->
      <%= yield :paragraph_1 %>
      <%= yield :paragraph_2 %>
      ...

# app/wizards/_dear_readers.en.html.erb
<% content_for :paragraph_1 %>
  <h3>Title ...</h3>
  <p>Content ... </p>
<% end %>
<% content_for :paragraph_2 %>
  ...
<% end %>
...

And so on for each language you support. As I mentioned in the comment that inspired this, the approach outlined here feels like we're shoe-horning a solution for one problem, DRYing up shared markup (in the form of site navigation, sidebars, etc.), into a solution for another problem, large bodies of translated text. It seems a bit unconventional to use content_for / yield in this way, but it may be an acceptable solution to your problem.

like image 58
Ian Eccles Avatar answered Oct 05 '22 12:10

Ian Eccles