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.

8 comments

Gravatar
Jan wrote 5 days later:

Great! This made my life alot easier…I hope this gets fixed in a future release of gettext though!

I still have a few problems with GetText and edge rails. I created the two rake-taks “updatepo and makemo”, but somehow makemo doesn’t work. It should create the locale directory with all its language folders along with the compiled .pot files etc. right? When I run makemo nothing happens…no errors, nothing. Any ideas?
-


Gravatar
Andreas wrote 8 days later:

I’m sure it will. Afaik, Masao already added it to his repository.

I’m not sure why makemo doesn’t work for you. It should create a “locale” directory in your application directory and put .mo files there. In case of a german translation for MyApp, it should e.g. create locale/de/LC_MESSAGES/myapp.mo. If it does simply nothing, it sounds like there’s a problem with gettext at all. Maybe you’re missing some library or something. Did you try to run the ruby-gettext tests? If there’s something wrong, the test results should give you a hint.

Gravatar
Priit Tamboom wrote 3 months later:

@Jan: I got similar issue where makemo does not do anything. My mistake was very simple, I had manually copied po/myapp.pot to po/en/myapp.pot and forgot to rename myapp.pot to myapp.po. In this pot situation makemo runs without any error or output. Hope it helps somebody who also googles this article with rails edge gettext.
-
PING:
[…] Learn how to install gettext in this excellent guide. Use this tip to get it working with Rails 2.0. […]

An article was published 6 months later
[...] Learn how to install gettext in this excellent guide. Use this tip to get it working with Rails 2.0. [...]
Gravatar
tonkla wrote 7 months later:

Thanks for “New-style .html.erb templates” … you saved my life : )

Gravatar
Raul Riera wrote 12 months later:

Hi,

I implented gettext on a Rails application and I am having the following doutb, I have a Users table and a UserStatus table (not the real names hehe) how do I go and translate the values un the user_statutes table? I have

pending | active | inactive

is there a solutin within the gettext? thanks

Gravatar
Andreas wrote 12 months later:

there’s a gettext method called N_. This method does nothing at runtime, but makes rgettext (which is run in the updatepo task to create po files) recognize the string inside so that it can be translated later using the _ method.

In your case, put N_(‘pending’) and N_(‘active’) and N_(‘inactive’) somewhere into your model, update the translations and _(status) will work for these three values.

There’s more information about such cases in the gettext and the ruby-gettext documentation i guess.

Gravatar
feby wrote over 1 year later:

Good Solution :-)

Thanks.

Feby

Comments are closed