Localizing dates and time with Rails’ I18n using procs
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.