Internationalization
Internationalization (I18n) is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes.
When creating an application with for single target locale and language, implementing the application with internationalization in mind can serve as a valuable foundation for decoupling the copywriting process from the application development process.
Let’s create a Marketing page
Our application’s landing page will include copy about a hypothetical product launch.
This commit introduces all constituent parts, including a root
route
declaration, a MarketingsController
,
and a view template for that rendering the HTML response
from that controller’s index
action.
For the most part, that portion of this changeset’s code is standard and uninteresting.
Rails ❤️ [I18n](#i18n)
Out of the box, [Rails provides framework-level support][rails-18n] for declaring and translation internationalized text.
The Rails Internationalization Guides include a section
that outlines the changes involved in rendering
translated text into a response’s HTML through a controller’s flash
helper.
Declaring and rendering our Translations
This commit’s changes take that example’s code a step further by
rendering translated text directly into the marketings#index
template
via calls to the translate
helper, and into our
document’s <title>
element in the layouts/applications
layout via a combination of calls to the content_for
helper (both with and without a block
argument):
--- /dev/null
+++ b/app/views/marketings/index.html.erb
@@ -0,0 +1,5 @@
+<% content_for :document_title do %>
+ <%= translate(".hero.title") %>
+<% end %>
+
+<h1><%= translate(".hero.title") %></h1>
Since the calls to translate
are made from within a controller
action’s view template, both the controller name
(marketings
) and action name (index
) portions of the key can be
omitted.
Finally, to set the text Content Authoring
as the value for the
en.marketing.hero.title
translation key, declare it in the
config/locales/en.yml
configuration file:
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -30,4 +30,7 @@
# available at https://guides.rubyonrails.org/i18n.html.
en:
- hello: "Hello world"
+ marketings:
+ index:
+ hero:
+ title: "Content Authoring"
Testing out our translations
In order to make sure that reading and writing our translations is
working, this commit also includes a test for the
MarketingsController#index
action, along with two
changes to Rails’ internationalization configuration:
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -62,7 +62,7 @@ Rails.application.configure do
config.assets.quiet = true
# Raises error for missing translations.
- # config.i18n.raise_on_missing_translations = true
+ config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names
# config.action_view.annotate_rendered_view_with_filenames = true
diff --git a/config/environments/test.rb b/config/environments/test.rb
index b5edb26..0f7d25d 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -53,7 +53,7 @@ Rails.application.configure do
config.active_support.disallowed_deprecation_warnings = []
# Raises error for missing translations.
- # config.i18n.raise_on_missing_translations = true
+ config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names
# config.action_view.annotate_rendered_view_with_filenames = true
Without these configuration changes, tests that cover controllers that render incorrectly declared translations fail with confusing messages:
Failure:
test/controllers/marketings_controller_test.rb|9| MarketingsControllerTest#test_#index_renders_marketing_copy
<<span class="translation_missing" title="translation missing: en.marketings.index.title">Title</span>> expected but was <Title>..
Expected 0 to be >= 1.
The <span class="translation_missing" title="translation missing:
en.marketings.index.title">Title</span>
part of the exception is
surprising: we didn’t write that code to render that <span>
element,
so what did?
By default, when Rails is running in a development or test environment
mode, it is configured to render <span>
elements like this when it
fails to translate an internationalization key:
Rails adds a
t
(translate
) helper method to your views so that you do not need to spell outI18n.t
all the time. Additionally this helper will catch missing translations and wrap the resulting error message into a<span class="translation_missing">
.
In an effort to make our test failures communicate more helpful information, we configure Rails to raise an exception instead.
After making this configuration change and re-running our tests, the failure message is much more helpful:
Error:
MarketingsControllerTest#test_#index_renders_marketing_copy:
ActionView::Template::Error: translation missing: en.marketings.index.title
Our application so far
At this point, we have a functional application that renders text from an internationalization-ready, configurable set of translations!
Visually, the application lacks… an aesthetic identity.
Desktop
Mobile
Let’s change that!