[katello-devel] Watch out when translating in class context

Lukas Zapletal lzap at redhat.com
Mon May 23 08:55:30 UTC 2011


Hello,

I have found we are using gettext translating incorrectly in quite a lot 
places.

The very basic util function is the underscore one. It is easy to 
understand - it translates the string immediately. Like a function call.

_("Hello World")

The little issue is in the class context. It gets evaluated before our 
I18n code gets initialized. Thus the gettext layer has no clue how to 
translate (which language to use for the current user?) and the string 
never gets translated. Typical example is in our model classes:

class Post < ActiveRecord::Base
   validates_presence_of :text, :message => _('Hey it's missing!')
end

Since we use gettext_i18n_rails gem it automatically try to translate 
one more time while rendering this string into the session. The key is 
to use dynamic util function in this case:

N_('Hey it's missing!')

Dynamic util function just "marks" the strings for extraction (rake 
gettext:find in our case) so it is available in our po/mo files. It 
doesn't do the actual translation. The rails gettext plugin does it for 
us in this case.

If you git-grep our code you will see we are using it. Great. But we use 
it in places where we should not do that. And that's the issue. Since it 
doesn't do the actual translation our strings are never translated. It's 
just all English for these cases.

Looks like a copy&paste thing. The simple rule is:

1) Always use _() or its variants (plurals etc.)
2) For class context model messages use N_() [*]
3) For other class context use N_() as well (but you must translate the 
string later on otherwise it wont be translated)

I am not currently aware of other class context in our app. If you find 
one the workaround is to use the dynamic variant first and then 
translate the string later on:

before initialization:

...
   fruit = N_("Apple")   # same as fruit = "Apple"
...

after initialization:

...
   _(fruit)              # does a normal translation
...


[*] Please keep in mind not all model error messages are in the class 
context! In this example you must use _() since the following block is 
executed after I18n has already been initialized:

...
   validate :only_one_rhn_provider
...
   def only_one_rhn_provider
     # this is not in class context anymore
     if new_record? and provider_type == REDHAT and xyz
       errors.add(:base, _("Only one Red Hat provider permitted"))
     end
   end
...

I will fix all the places and put this remark to our I18N wiki page.
More reading:

https://github.com/grosser/fast_gettext/wiki/activerecord
https://github.com/grosser/gettext_i18n_rails
https://github.com/mutoh/gettext

-- 
Later,

  Lukas Zapletal | E32E400A
  RHN Satellite Engineering
  Red Hat Czech s.r.o. Brno




More information about the katello-devel mailing list