This post originated from an RSS feed registered with Ruby Buzz
by Patrick Lenz.
Original Post: Revisiting Time#strftime localization
Feed Title: poocs.net
Feed URL: http://feeds.feedburner.com/poocsnet
Feed Description: Personal weblog about free and open source software, personal development projects and random geek buzz.
The folks behind Ruby-GetText have been busy bees in the last few months to tighten the integration their package provides with Rails.
It took some time for me to notice, because my old hacks to support localization for Time#stftime worked just fine up to Ruby-GetText 1.4.0. Suddenly, with an innocent update to version 1.6.0 everything broke, nothing was being localized anymore.
I revisited the Gettext Howto for Rails and noticed two things: The Gettext implementation looked completely different and actually much simpler than before. The disclaimer in the top designates it as optimized for Ruby-GetText 1.1.0 and newer.
So I revisited my general localization scheme and updated according to the Rails howto (which you should, too, if you want the newer Ruby-GetText versions to work nicely with your application). I won't repeat the necessary steps here, the aforementioned howto does a fine job there.
However, even after restructuring my code to use the new abilities of Ruby-GetText 1.1.0 and beyond, localization of Time#strftime still didn't play.
Changes needed for Time#strftime localization
In my application, I need to bind a language to a certain site a user is visiting. As such, I'm still using a before_filter to initialize the Gettext environment as opposed to simply using the class-level methods mentioned in the Rails Howto.
before_filter :localize
protected
def localize
GetText.locale = Portal.current_portal
init_gettext
end
This ensures that a proper locale is selected per-request, as multiple sites with differing locales are served from the same set of dispatchers.
What also changed in newer versions of Ruby-GetText is the fact that the _() function it's no longer available globally, it's restricted to controllers and views and their corresponding namespaces. While this is good in general, it broke the neck of my Time#strftime localization as it relied on the _() to be available either globally or at least to the Date class.
However, what's even worse (in this case) is the fact that the instantiation and initialization of the whole Gettext environment is also sitting in constraints, which means that even if you re-enable global use of the _() function you'll end up with non-localized strings as the environment just hasn't been initialized.
I've worked around this by adding some eval magic to the Date class (stored in lib/overrides.rb, just as in the previous article), replacing the original Date::translate_strings class method like so:
class Date
def self.translate_strings(controller)
@action_controller = controller
eval %(
def self._(string)
@action_controller.instance_eval { gettext(string) }
end
)
end
The rest of the class (redefining the contents of the Date::MONTHNAMES, Date::DAYNAMES, Date::ABBR_MONTHNAMES, and Date::ABBR_DAYNAMES arrays) stays in place. Refer to the old article for details.
As you noticed, Date::translate_strings works with a controller instance, which we need to pass in from the localize before filter in ApplicationController:
def localize
GetText.locale = Portal.current_portal
init_gettext
Date::translate_strings(self)
end
This solution is, by no means, pretty. It works for me (and survived about 30 million page impressions with multiple calls to the modified functionality per page) and hopefully one or two of you (that'd be about half my readership actually) finds it useful.
What else is in there?
In case you're curious what else has made it into the most recent Ruby-GetText releases, here's a list of my favorites:
Automated harvesting of database tables for column names, which end up in the .po file for easy localization in conjunction with error_messages_for for example
Better support for pluralized strings
Localization of DateHelper.distance_of_time_in_words
Localization of ActiveRecord error messages
Localization of ActionMailer templates (using file extensions)