Localizing dates and time with Rails’ I18n using procs

February 12, 2009 by Michael

Ruby on Rails I18n infrastructure did a great job to internationalization in Rails applications. Most things work right out of the box.

Daily Fratze is fully internationalized and i wanted to use ordinal day numbers in the English version. Pity, there is no template for strftime that works that way.

As i already hat monkey patched a “t” method to all date and time related classes, i came up with the following solution:

Parallel to “en.yml” i now have “en.rb” in my locales folder which gets loaded in environment.rb via

config.i18n.load_path += Dir[File.join(RAILS_ROOT, 'app', 'locales', '*.{yml,rb}')]

The en.rb files defines some procs as translation values like so:

{
  :'en' => {
    :date => {
      :formats => {
        :dmy_with_long_month              => lambda { |date| "%B #{date.day.ordinalize}, %Y" },
      }
    },
    :time => {
      :formats => {
        :dmy_with_long_month                       => lambda { |date| "%B #{date.day.ordinalize}, %Y" },        
        :dmy_with_full_day_and_long_month_and_time => lambda { |date| "%A, %B #{date.day.ordinalize}, %Y at %H:%M" }
      }
    }
  }
}

Used with the standard I18n tools you’ll end up with the string representation of the proc object. Useless 😉

So time for monkeypatching like so:

module DateTimeSupport
  def t(format = nil)
    type = self.respond_to?(:sec) ? 'time' : 'date'
    formats = I18n.translate(:"#{type}.formats")
    format = formats[format.to_sym] if formats && formats[format.to_sym]
 
    I18n.localize(self, :format => format.respond_to?(:call) ? format.call(self) : format)
  end
end
 
class Time
  include DateTimeSupport
end
 
class Date
  include DateTimeSupport
end       
 
class DateTime
  include DateTimeSupport
end
 
class ActiveSupport::TimeWithZone
  include DateTimeSupport
end

Code resides in a file in config/initializers and gets loaded automatically. It adds a t method to all date and time related classes. The method tries to look up the translation of format just like I18n/Simple does.

If it is proc, it gets called and then passed to I18n, otherwise it the original parameter is used.

That way the t method can use “dmy_with_long_month”, :dmy_with_long_month and any other arbitrary format like “%B %Y” that is not defined in any language file.

No comments yet

Post a Comment

Your email is never published nor shared. Required fields are marked *