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:
How would you organize the code?
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With