Using ruby-gettext with Edge Rails

Posted by Andreas on Sunday, July 29, 2007 at 07:07 (CEST)

The more I read about the various new features coming up in Rails 2.0, the more I couldn’t resist… and finally, a few days ago, I switched over to Edge Rails with my current project.

Switching to Edge Rails was easily done, however after fireing up /script/server and doing the first request, I was presented with a 500 Internal Server Error.

DISPATCHER FAILSAFE RESPONSE (has cgi) Sun Jul 29 12:43:56 +0200 2007
Status: 500 Internal Server Error
You have a nil object when you didn’t expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
/usr/lib64/ruby/1.8/cgi.rb:1165:in `[]’
/usr/lib64/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale_cgi.rb:26:in `system’
/usr/lib64/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale.rb:88:in `system’
/usr/lib64/ruby/gems/1.8/gems/gettext-1.10.0/lib/gettext/locale.rb:96:in `default’

After some time of debugging, it turned out to be ruby-gettext, which I use for I18N, that causes a NoMethodError on each request during init-gettext.

What happened here is, that ruby-gettext tries to figure out the current visitor’s language by looking for an URL parameter or a cookie named lang or the HTTP Accept header. Looking for the URL parameter seems to be the problem in this case. Locale::SystemCGI.system calls cgi["lang"] to look for the URL parameter, but CGI#[] raises a NoMethodError, because the @params hash does not contain a key named lang. Here are the first few lines of CGI#[] (starting at line 1163 in cgi.rb):

1 def [](key)                     # cgi.rb:1163
2   params = @params[key]         # nil gets assigned to params
3   value = params[0]             # raises NoMethodError, because params is nil
4   if @multipart
5     if value
6       return value

The solution

The problem could be fixed by patching cgi.rb of the ruby standard library or locale_cgi.rb of ruby-gettext (like somebody with a similar problem suggested in this mail). However this isn’t usually applicable on production servers. Instead, you can work around this problem by modifying CGI#[] from within your rails application temporarily, until the bug is fixed.

With Edge Rails, you don’t place your own statements in config/environment.rb anymore. Instead, you can write an initializer file and place it into config/initializers. For ruby-gettext, I created config/initializers/gettext.rb, which contains:

require 'gettext/rails'

To work around the above problem, add the following code to your gettext initializer, right after the require statement:

 1 class CGI
 2   module QueryExtension
 3     alias index_without_fix :[]
 4     def [] (key)
 5       return nil unless @params[key]
 6       index_without_fix(key)
 7     end
 8   end
 9 end

This modifies CGI#[] to return nil if the requested param does not exist.

Update (2007-10-20): The above problem was fixed in Ruby 1.8.6-p26.

Finally, my application runs with Edge Rails and I can now start to explore all the new stuff (and probably do a lot of refactoring to use those features).

New-style .html.erb templates

Update (2007-07-31): Ruby-gettext is currently unable to recognize new-style .html.erb template files (since it doesn’t know that .erb files should be parsed by GetText::ErbParser). I reported this to Masao, the author of ruby-gettext (so it’ll be probably fixed in future versions). Since then, you can work around it by modifying your lib/tasks/gettext.rake like this:

 1 require 'gettext/utils'
 2  # Tell ruby-gettext's ErbParser to parse .erb files as well
 3  # See also http://zargony.com/2007/07/29/using-ruby-gettext-with-edge-rails
 4 GetText::ErbParser.init(:extnames => ['.rhtml', '.erb'])
 5 desc 'Update pot/po files'
 6 task :updatepo do
 7   GetText.update_pofiles('messages', Dir.glob("{app,lib}/**/*.{rb,rhtml,erb,rjs}"), 'MyApp')
 8 end
 9 desc 'Create mo-files'
10 task :makemo do
11   GetText.create_mofiles(true, 'po', 'locale')
12 end

Update (2007-08-01): Masao pointed out, that it’s better to use the GetText::ErbParser.init method rather than overriding ErbParser. Thanks Masao.

Update (2008-02-25): .erb files are now parsed by default, so the above fix isn’t necessary anymore. Scanning .erb files was added on July 31, 2007 and is included in ruby-gettext 1.90.0 which was released on Feb 02, 2008.

• Tags: ,
CommentsPermalink
blog comments powered by Disqus