Friday, July 18, 2008

Rails + Gettext Crash Course, Part 1

This article is a short guide to how use gettext with ruby-on-rails. If you do not know gettext is the standard internationalisation (i18n) library of the GNU project http://en.wikipedia.org/wiki/Gettext. And this is the first part of the two articles. The second one might be found here.

Since there are some of i18n plugins for rails why should you chose gettext?

For some reasons.

First as I said it is the standard for GNU. Standard means wide support several tools to work with it, optimisation, documentation, etc. Most of Linux programmes use gettext.

Second, one of the key features of gettext is ability to use real, correct strings. You don't write strange keys in your code, you just put usual English phrases instead, like that

<p><%= _('Some text here') %></p>
<p><%= _('Length: <i>(%{min} min)</i>') % { :min => @min_chars } %></p>

As you see this allows you easily use any placeholders or html formatting tags in here if you need so. Another point for gettext is that you don't have to keep in mind the translation issues during the development time. You just put your text as nothing happened and always have a default translation with normal usual looking strings.

After you have done with the development you can parse out all the strings which need to be translated with special util. You will have standard formed .po file which you can then translate with some special programs, where you can use spellchecking versioning and all the civilize life advantages.

Third, this stuff can do lots of things, localize numbers, dates, currencies, work with pluralization on native languages and so one. Take a look at the official site for getting more information http://www.gnu.org/software/gettext/gettext.html

So how do we use the stuff with rails?

Quite simple.

First of all you need to install gettext by itself and rubysupport aka gem. Installation of gettext depends on your platform. With linux it's pretty simple. Say something like

# emerge gettext
or
# apt-get install gettext

Once you have installed gettext support, you need to install the gettext gem.

# gem install gettext

After it is done, you need to include it into config/environment.rb file of your rails project.

require 'gettext/rails'

After this you can start develop your project and use the _('text') constructions where you need to put some text.

If you are using Rails 2.1, there's a bug which have not fixed yet. But you can easily fix it by saving the following code into a file config/initializers/gettext.rb

# the gettext missed method fix
module ActionView
class Base
delegate :file_exists?, :to => :finder unless respond_to?(:file_exists?)
end
end

Once you have done with the development and want to create some translation you need to do some preparations.

First you need to add two simple tasks to your Rakefile.

require 'gettext/utils'
desc "Update pot/po files to match new version."
task :updatepo do
GetText.update_pofiles(
"my_site",
Dir.glob("{app,lib}/**/*.{rb,rhtml,erb,rjs}"),
"my_site version"
)
end

desc "Create mo-files for L10n"
task :makemo do
GetText.create_mofiles(true, "po", "locale")
end

The first one will scan though your source code and parse out all the strings which need to be translated and put them all into a .po file. The second one will compile all your translations into a standard .mo files which gettext can use.

So, you say 'rake updatepo' in your console and this will create for you the file named 'po/my_site.pot', this is template of your internationalisation. You copy the file in translation directories like that.

po/
de_DE/my_site.po
fr_FR/my_site.po
ru_RU/my_site.po
my_site.pot

Then you translate the .po files with one of the translation programmes, say this one http://www.poedit.net. Under Linux and KDE you can use standard KBabel programme, or under Gnome you can use the gtrasnlator project. Certainly you can edit those files just as plain text if you like so. Many texteditors support them.

Once you have done with the translation, run the 'rake makemo' task in your console and it will create the 'locale' directory in your rails project folder with a standard structure like that

locale/
de_DE/LC_MESSAGES/my_site.mo
fr_FR/LC_MESSAGES/my_site.mo
ru_RU/LC_MESSAGES/my_site.mo

This is almost it. You only need to initiate it in your application controller now.

class ApplicationController < ActionController::Base
GetText.locale = 'en_EN' # <- default locale
init_gettext 'my_site'

before_filter :define_language

def define_language
# here you can switch the locale on fly
# say like that

case params[:lang]
when 'de': set_locale 'de_DE'
when 'fr': set_locale 'fr_FR'
when 'ru': set_locale 'ru_RU'
else set_locale 'en_EN'
end
end
end

As you see we have used non existing locale 'en_EN', if there is no some locale your default strings from the source code will be used. So you always have a fallback language.

This is pretty much it for the start.

But remember with gettext you not only put some translated text-labels in your application, you easily can create translations of whole template files, you can translate models, values, format numbers, dates and do lot of another useful things.

3 comments:

Marnen said...
This comment has been removed by the author.
Marnen said...

This no longer works as of Rails 2.2. Please see here for instructions on how to use Gettext with Rails 2.2's I18n library.

Michael said...

a plugin with a simpler approach, fast_gettext support, thread-safety and example application can be found @
http://github.com/grosser/gettext_i18n_rails/tree/master