[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