Laura Diane Hamilton

Technical Product Manager at Groupon

Resumé

Internationalization for Ruby on Rails Apps

Today Eric Meyer gave a great talk at the 8th light meetup about internationalizing a ruby on rails application.

In his talk, Eric stepped through this github repo.

Eric advocates starting your greenfield rails app out with internationalization from the get-go. It's relatively easy to add internationalization support at the very beginning, whereas retrofitting an existing application with internationalization support can be quite painful.


Definitions:

i18n—short for "internationalization." (There are 18 letters between the "i" and the "n" in "internationalization.") Internationalization means architecting and developing an application in order to bring support for a second locale—possibly at a future time.
l10n—short for "localization." (There are 10 letters between the "l" and the "n" in "localization.") Localization is actually adding a second language & region combo. (For example, expanding to British English in addition to American English.)

Eric suggests building new apps with i18n support from the start for two reasons. First, from an architecture perspective, it forces a separation of concerns and leads to a better-organized application. Second, it serves customers better. In the United States, 20% of the population has a first language other than English!

Here is a list of the types of content that typically ought to be internationalized:

  • Static text
  • Admin-entered text
  • Displayed currencies
  • Number formatting—some countries use a comma as the decimal separator, for example
  • Dates
  • Layout—for example, Chinese is written from top to bottom. (CSS3 enables the use of vertical text.)


In contrast, the following things typically won't changed from one locale to the next:

  • Comments and reviews—it's more typical to simply hide reviews that are not in the reader's native language
  • Some displayed currencies—if you're creating an accounting report, typically you will want to keep currencies according to how the transaction took place


The default tool for internationalizing a rails application is is with the ruby i18n gem.

Basically, the i18n gem creates a directory called config/locales. Rails then stores the application's various languages in a yaml file, such as en.yml for English or fr.yml for French.

Eric suggest using multiple levels of nesting in order to make it really clear where each key is used. He provided this example en.yml file: en:   hello: "Hello world"   app:     views:       welcome:         index:           header: "Some Header"           number_of_things:             zero: "There are %{count} things"             one: "There is %{count} thing"             other: "There are %{count} things" As you can see, each view will have its own keys which can be nested themselves according to their logical groupings.

The corresponding view would then look something like this: <p>   <%= I18n.translate("hello", :locale => "en") %> </p>
<p>   <%= I18n.translate("number_of_things", :count => 0) %> </p>
<p>   <%= I18n.translate("number_of_things", :count => 1) %> </p>
<p>   <%= I18n.translate("number_of_things", :count => 10) %> </p>


Eric suggest the following i18n best practices:

  1. Do not abstract—call translate or localize directly from the views. Localizations are heavily context-dependent.
  2. Do not enforce structure—instead, use interpolation. Accept that different languages will have different sentence structures, paragraph structures, even layouts (in the case of vertical languages).
  3. Reuse translations with shared partials
  4. Always store dates as UTC—then convert to the appropriate time zone when you display them.
  5. Use the ISO standard localizations—look them up! Do not invent your own unless you would like to create future frustration for yourself.


Eric suggests using the following three development tools to make your life easier when internationalizing a rails app:

  1. Auto-generated locales—automatically convert from the default locale to a different one for testing and debugging ease.
  2. Ways to compare locales and identify deprecated keys, duplicate keys, and missing keys.
  3. Environment-based error handling—Eric suggests raising an error on missing a translation in development and test environments. (Note: You probably will not want to do this in production!)


What are the best practices for determining a user's locale?

Eric suggests using a RESTful architecture. For example, many websites embed the locale in the URL:

You may also want to store the user's locale preference in the database in order to send him appropriately localized emails and/or text messages. For desktop apps, you're pretty much limited to asking the user for his preference and saving his preference.


What about internationalizing an API?

Stripe, Eric told us, is a good example of API internationalization best practices. Stripe provides default English error messages to make things easy for developers and users, but it also returns error codes. The developer can then use the error codes as keys to internationalize the Stripe error messages as appropriate.

Facebook has a novel approach to localization. Rather than pay teams of translators to translate each phrase into every language, Facebook essentially crowd-sources the translation. Facebook gets its users to write the translations in their native languages. Then, users vote on which translation is the best. (This helps to prevent vandalism such as teenagers injecting profanity.)

Depending on the size of your user base, Facebook's crowd-sourcing strategy may or may not work for your application.

You may also be interested in checking out Eric's sample internationalized app on Github.

Lauradhamilton.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to amazon.com.