As a software developer you know all about the costs of getting a product coded, maintained and marketed, but what you may not know is the importance of localization – let’s call this knowledge internet linguistics. Apps and mobile Web usage are the future of the Internet, and English is not the only language with a solid market share. High cell phone penetration in the US, UK, Australia and Canada pushed the market for the first several years, but a recent study shows that the US only makes up 28 percent of the free app download market and only 34 percent of paid app sales for the iPhone market. Who’s next on the list? Not the UK, Canada or Australia. In the free app market, China comes in at number two, and Japan is second for paid apps. With non-English speaking countries increasing their mobile presence each year, software developers can’t afford to ignore the potential opportunities. Either start translating software for international markets, or risk losing a big share of the market.
What Languages are the Best Bet for Internationalization?
For paid app purchases and mobile users, the current “top ten countries” are US, Japan, UK, Australia, Germany, Canada, France, Italy, Switzerland and China. This means that developers only need translation services for five different languages to take advantage of the bulk of the market. More than three-quarters of the total app download market occur in one of these six languages. Because both Japanese and Chinese make the list, translation alone is not enough. Translation takes care of the text, but it doesn’t fix function issues that occur when customer use a language that runs vertically and right-to-left. Putting globalization plans into place from day one can save a lot of money.
Don’t Stop at the Top 10
Sure, the top ten make up the bulk of the software market, but the remaining 26 percent is not trivial. Developing countries improve their Internet user numbers every day. In developed countries, market penetration is fairly static. With at least one computer in almost every home, the United States market has nowhere to go. China added more Internet users in the past three years than live in the United States. Nigeria is projected to take the top spot for mobile internet users by 2015. Sure, the listed national language of Nigeria is English, but it is not the primarily spoken language. To appeal to the Nigerian market think about adding Hausa, Igbo and Yoruba to your localization plans. These are the three most spoken languages in Nigeria and represent a population of approximately 55.4 million people. That doesn’t touch the larger populations of the more global languages, but it certainly represents significant unit sales for those properly positioned to take advantage of this rapidly expanding market.
Start Now and Beat Out the Competition
As with any product, software development is all about timing. Being the first to market gives you a big opportunity to gain a solid customer base. Think globally with production, and earn profits on a larger scale. Adding globalization plans to development products is a small investment with massive earning potential. Make sure you tap all existing and potential markets to maximize your return.
Now, let’s start with some other features of I18n in Ruby on Rails.
Localization of Times/Dates
As I18n API provides date/time localization feature, we can easily add localized version of timestamp in Ruby on Rails application. To use this feature, first of all we need to add our localized translation for time format. Let’s change our de.yml file to add a German version.
Now, we can use I18n.l or Rails #l helper to localize the Time object in our desired time format.
You can add many more formats for date/time to make it work using the format that you want. You can also get a ready made version of different types of local files from rails-i18n github repository. Once you place those file(s) in config/locales/ folder, they are ready to use for localization.
Using views for translation
In Rails 2.3 a new feature named “localized views (templates)” was introduced. For example, your application has an ItemsController class with an index view. Your default index template page for ItemsController is rendered by app/views/items/index.html.erb. If you want a localized version of index page, you will just have to write your text in index.de.html.erb file and then will have to save in the same folder. By setting the locale to :de, you can force Ruby on Rails application to render the German version of that template. When the locale is set to the default locale, the generic index.html.erb view will be used.
Generally, this feature is used for large amount of static content pages, where putting this large text content in YAML or in Ruby dictionaries feels cumbersome.
Translating ActiveRecord errors
You can translate Active Record validation error messages easily. Active Record uses different namespaces which can be used to translate easily models, attributes, and/or validations.
For example, an Item model with a validates_presence_of validation for the name attribute like this:
In this case :blank is the key for the error message. So, Active Record will check this key in the namespaces:
After following keys in the above mentioned order the result will be:
If, your models are using inheritance then the messages are looked up in the inheritance chain.
For example, you might have an Book model inheriting from Item:
Then Active Record will look for messages in this order:
You can also add translations for Active Record error_messages_for helper like this.
Organization of resource files
If you are using default i18n library settings, you may find that all files are stored in plain-text format on the disc. Placing all translations text of your Ruby on Rails application in one file per locale could be tedious to organize. You can easily store these files in a hierarchy structure which is easy to understand for you. For example, your config/locales directory could be organized like this:
By following the above way to organize resource files, you can easily differentiate model and their attribute names from text inside views, and all of this from the “defaults”. In Ruby on Rails, locale files in nested dictionaries structure are not being loaded automatically. So, to make it work we have to do this settings in config/application.rb
Setting the Locale from the Domain Name
In the previous article you read about how to set the locale in Ruby on Rails using application.rb settings. There are also other ways to do so. You can set the locale from the domain name where your Ruby on Rails application runs. Like www.example.com will load the content in English locale, www.example.de will load the content in German locale. This way you can use top-level domain names to set the locale for Ruby on Rails application.
The benefits of using this method are:
The locale setting is an obvious part of the URL.
Visitors obviously know in which language the content of the website will be displayed.
It is very easy to implement in Ruby on Rails.
Search engines love the content in different languages served at different domains.
You can use it in your ApplicationController:
We can also set the locale from the subdomain in a very similar way:
You can also use switching menu option in your application like this:
assuming you would set APP_CONFIG[:deutsch_website_url] to some value like http://www.example.de.
As previously mentioned this method has benefits, but what if you do not want to or able to provide different localizations (“language versions”) on different domains. The solution to this will be to add locale code in the URL params (or request path).
Setting the Locale from the URL Params
We can also set the locale by including it in URL params like www.example.com/items?locale=de or www.example.com/de/items.
You can use it in your ApplicationController:
You can get same benefits with this method as with setting the locale from the domain name, but the only little problem is it takes bit more code to implement. Here is the code to implement it by including it in our ApplicationController:
This way we can easily set/override “defaults” for url_for and helper methods dependent on it. So, every url_for dependent helper method will now add the locale in the query string like, http://example.com/?locale=de.
Now, if you want URLs to look like this http://example.com/de/items (which loads the German locale), we need to set up routes with path_prefix option this way:
So, when you call items_path for :de locales, an URL like http://example.com/de/items will be generated with the German locale. But, if you do not want to force the use of a locale in your routes you can set an optional path scope like:
This way when you access http://example.com/items without a locale, you will not get a routing error, which is very useful for setting default locale when one is not mentioned.
Setting the Locale from the Client Supplied Information
Sometimes, you have to set the locale from the information that client had supplied (not from the URL.) i.e. user’s preferred language or by choosing the locale in your application interface and saving it to their profile.
Using Accept-Language HTTP header
Client may set Accept-Language HTTP header in their browser or other client (like curl) and request the url. By supplying the information of the locale. We can implement this scenario with this code in ApplicationController.
Using User Profile
In your Ruby on Rails application it is also possible that users want to set the locale for their interface by setting it from database. In user’s profile, user will have to choose the locale from a dropdown list and it will get saved in the database along with other profile data. In this case, you need to override the locale value something like this.
Whenever we hear about Internationalization of web application, the first word that comes to our mind is “Translation“. There are three ways to translate software:
Do it Yourself
Pay Someone for doing Translation
Ask your Users
No matter what, making the software ‘Internationalization ready’ is the developer’s job. No static strings, dates in the code and so forth; every text must be put in resource files and the code decides which text to use. Luckily Ruby on Rails provides a simple ruby gem called “I18n” (internationalization) that does exactly that.
Definition of Internationalization & Localization :
First of all let’s check the definition of Internationalization & Localization. According to Wikipedia,
i18n – “Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes.” This means, the “Internationalization” functionality translates all string and other locale specific information ( like date and currency formats) from your application in desire language to end user.
l10n – “Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text.” This means, the “Localization” functionality gives translations in local-specific language and other localized formats for local specific information.
How i18n mechanism works in Rails :
All the languages are different from each other in many ways (For example pluralization rules). It is very difficult for any tools/software to provide a general solution for language translation. To solve this problem I18n API provides two features in Ruby on Rails.
Give support for English and other similar languages out of the box
Provide a user-friendly and adjustable functions for supporting other languages
This means in Ruby on Rails every static string has been internationalized and you can “over-ride” these defaults with “localization” of the application.
There are two parts of Ruby I18n gem which are:
The public I18n API – provides a Ruby module with public methods to characterize the work of the library
A default backend – which executes these public methods
The Public I18n API comes with two most important methods which are:
translate # This public method do translations of the text
localize # This public method localize Date and Time objects to local formats as per settings
These method have aliases #t and #l respectively, so you can use them like this:
Setup/Configuration about the i18n mechanism
You can easily setup ruby I18n gem with few simple steps and use in your application for I18n support. Ruby on Rails application set up reasonable defaults in all .rb and .yml files in config folder. If you want to change the settings, you can easily change them according to your need.
To check the defaults for I18n module you have to check config/locales directory, which is default path for translation.
You will get one file named en.yml which default locale and contains these translation strings:
English is default locale in I18n library. So, if your application is not set in different locale, :en will translate all the static text changes.
So, when you check this on console the output shows like following :
Some other available locales which are supported by rails 3 are:
The easiest method to set your own locales to override the default locale is to change config/application.rb file in Rails 3. (You can apply same settings to config/environment.rb in Rails 2). Add this line to get German language as default locale:
The first line of code tells the location of translation file to the I18n library. The second line of code will set the default locale to :de other than :en.
Using the I18n module
Put these lines in config/locale/de.yml.
Let’s check now whether this settings translate “hello” into “German” locale or not.
Using the I18n with interpolation
Most of the time you want to use various variables with your translations. That’s why I18n API also provide interpolation feature.
Using the I18n with pluralization
In English there are only one singular and one plural form for a given string, e.g. “1 friend” and “2 friends”. The best thing is I18n API also provides a flexible pluralization feature in Rails applications.
We must note that an interpolation variable named :count plays key role in translation and pluralization.
The algorithm for pluralization is:
I.e. here 1 denotes singular and 0 denotes plural. So as specified using conditional operator, if count == 1, it will consider it as singular form otherwise its plural.
That’s it for Part I. In Part II we will check other features of I18n like
Localization of Times/Dates
Using views for translation
Translating ActiveModel errors
Organization of resource files
Setting the locale (from domain, parameter or client) and of course storing it in the database when the user is logged in