Playing with Rails I18N
I've been annoyed by the lack of i18n in Rails since its very inception. Building web applications for the Belgian market makes proper i18n support a requirement for any framework.
I skimmed through a bunch of plug-ins but some makes way too much assumption about the way content is organized in the application.
Fortunately things recently got easier thanks to a clever and dead simple localization module written by Thomas Fuchs of the Scriptaculous fame. It's the less intrusive solution I found so far but one thing was missing: the localization of texts stored in the model. So I rolled up my sleeves and started hacking an extension to ActiveRecord.Base.
The idea is to provide a locale-aware accessor for the fields that needs a translation. Localized text would be stored in the same table as the model (no metadata nightmare) following a simple naming convention. Let's say we have a products table with a name attribute to be localized: products.name would hold the text for the :default language, products.name_fr would then hold the french translation, products.name_nl for the dutch, and so on...
Let's start by providing a Railsish interface to this new facility:
class Product < ActiveRecord::Base # Will create a locale-aware _name accessor localize :name end
Now you can output the localized name for any product, based on Localization.lang:
# some_view.rhtml <%= @product._name %>
And here's the black magic:
class ActiveRecord::Base def self.localize(*attribute_names) attribute_names.each { |attribute_name| class_eval %{ def _#{attribute_name} unless Localization.lang == :default localized_method = "#{attribute_name}_\#{Localization.lang.to_s}" return send(localized_method.to_sym) if respond_to?(localized_method) end #{attribute_name} end } } end end
And voila! ;)
This worked fine for me. The column redundancy in the database may look ugly and kind of anti-DRY but Rails migrations make it a piece of cake to deal with new languages.
I should now have a look at the shiny new plug-in API...

