Website Internationalization Ideas 2008

From OpenStreetMap Wiki
Jump to navigation Jump to search

In 2008 Arindam Ghosh kicked off Website Internationalization efforts in earnest with his Google Summer of Code project. This page details the ideas he worked on, some of which were recently adopted and deployed. Other ideas described here may be outdated due to later various of Ruby on Rails, which provided different internationalization features. His GSoC project also included work on Map internationalization

For reference, the initial plan that kick-started the work is User:Makghosh/GSoC_2008#Roadmap

Ruby on Rails

The website stands on Ruby on Rails platform fondly known as the “rails-port”. So, in rails, though there is no built-in support for i18n. But there are several ways to do this as listed out here. Each of them have their own advantages and disadvantages also. Out of all those, ruby-gettext and globalize were first chosen for test runs on test setups. Now, ruby-gettext is quite well known to generate .po files and likes. But globalize along with click-to-globalize gives a definite edge with their on the fly method of localization.

RoR plugins

The two rails plugins used for this purpose are:

  • Globalize plugin [1]
  • Click to Globalize plugin [2]

The latest version of both the plugins can be found here. But the required versions are already present in vendor/plugins of i18n branch.

Features covered

Configure the plugins

Before discussing all the different features that are completed, first how to configure the globalize plugin, so that it starts working in the osm rails-app. They are quite simple actually,

  $ ruby script/plugin install
  $ rake globalize:setup (might take a while, about a minute or so)

For setting up the click to globalize plugin,

  $ ruby script/plugin install
  $ rake click:setup

The plugin/install part may be skipped as they are already present in i18n branch. Just performing rake tasks will suffice.

Globalization of views

This is one of the primary things that has been done. It simply means wrapping the translatable text in the views within a helper method. The principle method that caters to this, is provided by the Globalize plugin that is, String#t. The different ways this method has been used are,

  • Wrapping just a translatable text within a view:
 For example: <%= "text to globalize".t -%>
  • Wrapping a translatable text along with a single variable:
 For example: <%= "Hello, %s".t(nil, -%>
  • Wrapping a translatable text along with multiple variables:
 For example: <%= "%s has %s friends".t(nil,, ....) -%>


User language preference

As obvious, there is a global language preference for a user. It is basically implemented by a drop-down menu in the settings page of the user, from where he can easily select & save the desired locale. When the selection is saved, it’s saved in the database where a locale column has been added to user table by migration. The drop-down menu is implemented in the view by a helper method called “select” as given. Screenshot

 select ("user", "locale", { "English" => "en", 
                             "Bengali(IN)" => "bn-IN",
                             "Hindi(IN)" => "hn-IN", 
                             "Spanish" => "es-ES" })


Translation updates via RSS

This is one of the interesting aspect of the web-site i18n. Here in, there is a translate_controller.rb present specifically to take care for different actions related to translation. Now the views related to translation are viewable only to translators (done with the help of before_filter). This takes advantage of the fact that in users table there is tr_status column (sort of status flag) which for translator hold value “1” and holds “0” for normal users.

As for translation updates, there are separate links to see “pending/completed” translation strings for the locale selected by the translator in his/her settings page. They are taken care of by 'pending' and 'complete' action in the translate controller. The groups of strings are collected from globalize_translations table for a particular locale and paginated in the action and correspondingly rendered by a partial in the views. Screenshot


Translation Interface

As the name suggests, this is where translations can be added, viewed and/or modified as necessary. Normally, when the pending/completed translations are viewed, every string has a link that brings up its' translation interface. The interface shows the string to be translated, the corresponding translation in the current locale, and also has a submit form for adding/updating the translation. Screenshot


L10n Statistics

This is another important feature of i18n. As the name suggests, it basically shows the total number of pending strings, total number of completed strings and percentage of translation. This gives a comparative study of amount of translation done/left in different language branch. Now, couple of nifty feature that it boasts are that, first the result can be sorted in accordance to number of completed strings or percentage completed (default) in descending order and secondly, the number of pending/completed strings has a link to those list of pending/completed strings for that locale.

Now in this context, another feature is that the user's home page now has an l10n link. For translators, it opens up the entire space for translation works. Otherwise, for normal users, it just opens up this 'l10n statistics' page to motivate more of them into translation. Screenshot


Language filtering of diary entries

This is a very nifty feature that allows all user diary entries to be tagged by the language in which its' being written while posting the entry. It has a drop-down menu for selecting the desired language for the post. Screenshot

And then, of-course there is filtering the diary entries by language. So, there are two options, 'show all' or 'filter by my language'. 'Show all' is self-explanatory. But 'filter by my language' actually filters the diary entries according to the current/default locale selected by the user in the settings page. Also, RSS feeds had to be updated accordingly. Screenshot


Get the source code

Currently the entire thing is present in i18n branch of osm rails_port_branches.

Trac: i18n-trac

Detailed Write-up: PDF


  • How to change locale?

Any user will have a dropdown menu in his/her "settings" page, wherein s/he can select desired language and after saving the preference the entire website changes to that locale of-course wherever translations are available.

  • How to translate?

Translators can check the pending/completed translation updates for the desired language, either in webpage or in the rss feeds and select to translate any of the strings. Now, just clicking on the string pointer "String #1234" opens up the translation interface to add/update translations. Since the pointer id "1234" is unique, so it becomes really easy to discuss/refer to it.

  • How to add new language branch?

Now, there is global hash variable called LOCALES in environment.rb which hold all the language branches as given,

 LOCALES = { "English" => "en", 
             "Bengali(IN)" => "bn-IN", 
             "Hindi(IN)" => "hi-IN", 
             "Spanish" => "es-ES",
             "German" => "de-DE",
             "Arabic" => "ar"}

So, just adding a new language branch and code will do the trick and populate that globally.

  • How to add translators?

For now, it has to be done manually by setting tr_status=1 in the 'users' table. By default its' set to 0 for any normal user. There are plans to setup l10n-admin thingy to make this more easier.

  • Where are translations stored in database?

Well, actually the translations are stored in globalize_translations table. Particularly the migrations provided by the globalize plugin creates three tables namely

* globalize_translations: for storing translations
* globalize_languages: contains language name, language code, id etc
* globalize_countries: contains country name,id etc

Things to do

  • Map internationalization: This is one of important chunk left to be done. The preparatory works were to be done in this time-line. But there was absolutely no time left for it. So, this is to be completed now. See Map internationalization.

Some initial discussions are over here

  • Solving Click to Globalize problems: The stopper with the CtG plugin is that the ajax in-place-editor won't start up when translatable text is being clicked. This problems seems to be related to the fact that all translatable elements should be placed strictly in html tags like "p", "span", "div" etc. So, updation of views as required.
  • Timestamps in RSS feeds: The rss feeds for translation updates use a static timestamp for now. Because there is no way globalize keeps a track of the timestamps when a translation is updated/added etc. Now, a little provision is created for that in statistics table where timestamps are updated only when the no. of pending/completed strings change. So that, somewhat realistic data that can be included. Otherwise globalize plugin has to be made to keep timestamps for this purpose.
  • L10n admin: As of now, translators have to be added manually by setting tr_status=1 in the 'users' table. By default, its' set to 0 for any normal user. Now, there can be one/more l10n admins who will add/remove translators, add/remove more admins/coordinators. Technically its' easy, but how this can be best done needs discussion.
  • Right-to-left languages: There are two rtl languages that is Arabic & Hebrew. Though, things work well with existing templates, but normally these languages require r-t-l templates. Need to see if there is other way around.
  • More to follow surely...