Skip to content
Saumya Kanoria edited this page Nov 30, 2016 · 27 revisions

Internationalization (or i18n) is the process of making code easily support different languages and locales. This then needs to be followed by localization (or l10n), which is the process of actually supporting different languages and locales.

Conceptually, this is simple: To internationalize, replace all language and locale specific strings with normalized 'keys', and to localize, provide language and locale specific translations or formats (such as dates and currency formats) for these keys. However, in practice, things get much more complicated:

  • Each language has peculiarities that need to be dealt with - grammar structure, pluralization rules etc.
  • The number of normalized 'keys' can grow very very large. How are they to be organized hierarchically and meaningfully?
  • Most code relies on 3rd party libraries that may need their own l10n. This needs to be provided and organized.
  • In software such as ours which aims to be flexible enough to support the building of SPAs and traditional web apps (recall that we allow the admin console to be swapped out for existing solutions such as ActiveAdmin etc. that are traditional web apps with server generated views), we need to design for i18n and l10n on the server as well as the client side

This starter kit is comprehensively internationalized on the server and client side, keeping in mind the challenges listed above. We have also provided complete localization in Hindi, as a reference that can be used to create other localizations as desired.

Server Side i18n

For the most part, this is fairly straightforward, and is implemented using Rails' excellent built-in i18n library. Locale files can be found in the /config/locales directory. The file organization therein is self explanatory.

There are just a few additions that we have made on top of vanilla Rails i18n, and these are detailed below:

Available and Default Locales

We make it possible to have different sets of available locales for the main and the admin apps (the admin app will likely have a subset of locales of the main app). These can be set in /app/models/i18n_utils.rb.

However, at a more basic level Rails needs to be told of ALL available locales (i.e. the union of the two sets above). This should be done in /config/application.rb - search for 'locale' to see where exactly this needs to be done.

NOTE: The client Angular code picks up the available locales from the server, so you don't need to provide this information separately in the client code!

The default locale can be set as you normally would in Rails.

Integration with Client-Side Angular i18n

This controller provides the following endpoints for the client and server code to communicate:

  • /i18n/switch_locale.json: Called by the locale-switcher directive (see the section below for details) to switch locales. This controller action then redirects to the appropriate page in the newly selected locale.

  • /i18n/translations.json: Upon redirection to the appropriate page by the action above, as part of the page initialization the client side I18nProvider service (again see below for details) picks up the locale from some initialization data sent over by the server, and calls this endpoint to retrieve the translations for the set locale

Client Side i18n

This has been implemented using the comprehensive angular-translate library, with several of our own additions and conveniences on top. The setup is non-trivial and needs a proper explanation, which is given below.

Architecture and Code Organization

I18nProvider Service

angular-translate provides various ways of "hooking up" i18n. One of them is to cause localization strings (which it calls 'translations') to be retrieved from the server when a language is set/changed, so that they can then be used in the internationalized Angular code/views. This is the approach we follow, but provide a little sugar on top to do so, via our I18nProvider service which delegates to angular-translate.

This service can be used to set a locale, and to do various other useful things that angular-translate does not do (or makes it non-trivial to do), such as:

  • Intelligently localize URLs when required
  • Perform bulk translations
  • Provide the list of available locales, which can then used used by our locale-switcher directive to switch languages
  • Pop-up an internationalized window.confirm dialog
  • Introduce a concept of "relative" and "absolute" translation ids (angular-translate refers to keys as 'translation ids') somewhat like Rails i18n. This can help developers write flexible and DRY internationalized code. See the fb-field directive as an example of how. Specifically, read the docs therein about how to override the label/hint translation ids.

This service can be used to accomplish a lot, without having to dive into 'raw' angular-translate. Read its documentation for a thorough understanding. Of course, if you want or need to, you can use angular-translate directly wherever you wish.

I18n Angular Module

In fact, the I18Provider service is part of our I18n module, which as a whole, contains all the i18n and l10n functionality we provide on top of angular-translate. Other than I18nProvider, this module also contains the following:

  • l-href directive: Localizes URLs by replacing a "placeholder" substring with the current or desired locale. Can be very handy in certain URL generation scenarios. Read the documentation for detail on when it can be useful and how.

  • locale-switcher directive: Provides the UI for changing locales. Intelligently replaces/adds the target locale in/to the current URL. It can also handle more complex scenarios, such as changing the locale via a request to some server endpoint set up for this purpose, which is in fact the workflow that we choose to follow in this starter kit.

Clone this wiki locally