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 contai开发者_如何学运维ns 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:
- 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
- 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?
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.
精彩评论