[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