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...