Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python : using gettext everywhere with __init__.py

Tags:

python

gettext

I would like to use gettext through my application.

So, I tried to put the basics into __ init__.py like this :

import gettext
_ = gettext.gettext

gettext.bindtextdomain ( 'brainz', '../datas/translations/' )
gettext.textdomain ( 'brainz' )

And I try simple call in Brainz.py :

#!/usr/bin/python

from brainz import *

##
# Main class of the game
class Brainz :

    def __init__ ( self ) :

        print _( "BrainZ" )
        print _( "There will be blood..." )
        print _( "By %s" ) % "MARTIN Damien"

But I have the following error at execution time :

Traceback (most recent call last):
  File "main.py", line 8, in <module>
    Brainz ()
  File "/home/damien/Dropbox/Projets/BrainZ/brainz/Brainz.py", line 12, in __init__
    print _( "BrainZ" )
NameError: global name '_' is not defined

As I'm new to python I don't understand what is wrong.

Could you give me good advices ?

Thanks,

Damien

like image 586
MARTIN Damien Avatar asked Sep 30 '10 20:09

MARTIN Damien


1 Answers

sdolan explained why your code didn't work, and provided a great solution. But it has an inconvenience: you have to import gettext in every module you want to enable translations.

Elf Sternberg provided a very convenient approach: manually make gettext visible project-wide. But it looks a bit cryptic and, as he said, it is pure evil :). He also suggests, for an unknown reason, the totally unrelated Django ugettext. No need of Django, stick with the standard lib gettext like you did before.

May I suggest a 3rd, officially endorsed approach? In the same __init__.py you tried before, use this:

import gettext
gettext.install('brainz', '../datas/translations/')

And that's it! Project-wide _() availability, in a non-cryptic, elegant and convenient way, using the standard gettext module. But, to be fair, if you look at gettext's source code, you'll see that uses the same trick Elf suggested. So, in essence, this is also Pure Evil(tm). But this is perfectly fine if 'brainz' module is only used by your application and not meant to imported by other applications.

If you want to share 'brainz' with other applications, you should use sdolan's approach: import it in each module. But, again, instead of using bindtextdomain and textdomain like you did, I suggest this:

import gettext
t = gettext.translation('brainz', '../datas/translations/')
_ = t.ugettext

The difference is using gettext's Class-based API instead of the GNU gettext API. Take a look in the official reference for why. The install approach is also part of the Class-based API.

Side note: you will notice the docs suggest using pygettext as a replacement for GNU's xgettext. Don't! Pygettext is extremely outdated and lacks several features. xgettext is much more powerful and flexible, and fully supports Python.

like image 107
MestreLion Avatar answered Oct 27 '22 00:10

MestreLion