[katello-devel] Watch out when translating in class context
Jason Rist
jrist at redhat.com
Mon May 23 13:24:14 UTC 2011
On 05/23/2011 02:55 AM, Lukas Zapletal wrote:
> 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
>
Good find, Lukas. I didn't know the distinction between _( and N_(
-J
--
Jason E. Rist
Senior Software Engineer
Systems Management and Cloud Enablement
Red Hat, Inc.
+1.919.754.4048
Freenode: jrist
More information about the katello-devel
mailing list