Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switch translations in python and gettext

I have the following code which should display two lines of English text and one line of Romanian text between the two English ones, but it only displays English text (the translation switching doesn't work):

main.py:

#! /usr/bin/env python2.7

import gettext
gettext.install('messages', '../i18n', unicode=True)

import card

if __name__ == '__main__':
    x = card.Rank()
    print x.j, x.a, x.q, x.k

    ro = gettext.translation('messages', localedir='../i18n', languages=['ro'])
    ro.install()

    print x.j, x.a, x.q, x.k

    en = gettext.translation('messages', localedir='../i18n', languages=['en'])
    en.install()

    print x.j, x.a, x.q, x.k

card.py

class Suit(object):
    clubs = _('Clubs'),
    diamonds = _('Diamonds'),
    hearts = _('Hearts'),
    spades = _('Spades')


class Rank(object):
    j = _('Jack')
    q = _('Queen')
    k = _('King')
    a = _('Ace')


class Card(object):
    # ...

My directory structure is as follows:

.
├── i18n
│   ├── en
│   │   └── LC_MESSAGES
│   │       └── messages.mo
│   ├── en.po
│   ├── en_US.po
│   ├── ro
│   │   └── LC_MESSAGES
│   │       └── messages.mo
│   ├── ro.po
│   └── ro.pot
├── Makefile
├── README.md
└── src
    ├── card.py
    ├── card.pyc
    ├── deck.py
    └── main.py

I used xgettext and msgfmt to generate the .po and .mo files.

The problem is that if I only load a single language, the text gets translated (I have to do this as the sole thing before any output is displayed).

#! /usr/bin/env python2.7
import gettext

if __name__ == '__main__':
    ro = gettext.translation('messages', localedir='../i18n', languages=['ro'])
    ro.install()

    import card
    x = card.Rank()
    print x.j, x.a, x.q, x.k

But if I want to change languages on the fly the output made by the first code snippet presented above won't be translated.

What I'm doing wrong? What did I understand wrong from the docs?

like image 476
Paul Avatar asked Oct 22 '25 04:10

Paul


2 Answers

All gettext.install() does is define the _() function as something that translates text. In your first example, you do x = card.Rank() before your ro.install() call - and so the only time that j = _('Jack') is called, _() translates it into the default English. Subsequently, _() gets redefined to Romanian - but it never gets called again, and so never gets retranslated.

I expect this will work:

#! /usr/bin/env python2.7

import gettext
gettext.install('messages', '../i18n', unicode=True)

import card

if __name__ == '__main__':
    x = card.Rank()
    print x.j, x.a, x.q, x.k

    ro = gettext.translation('messages', localedir='../i18n', languages=['ro'])
    ro.install()

    x = card.Rank()
    print x.j, x.a, x.q, x.k

    en = gettext.translation('messages', localedir='../i18n', languages=['en'])
    en.install()

    x = card.Rank()
    print x.j, x.a, x.q, x.k
like image 96
rkday Avatar answered Oct 24 '25 17:10

rkday


Translations are typically for end-users, not developers. So leave your strings as literals in the code and only translate when you display them:

class Rank(object):
    j = 'Jack'
    q = 'Queen'
    k = 'King'
    a = 'Ace'

...

    x = card.Rank()
    print _(x.j), _(x.a), _(x.q), _(x.k)

Note that the string extraction tools won't be able to find these strings anymore unless you call them with _() somewhere in your code.

If you don't want to add the strings to the translation files manually, you could add something like this to the module:

if False:
    _('Jack')
    _('Queen')
    _('King')
    _('Ace')

Or this:

assert(_('Jack'))
assert(_('Queen'))
assert(_('King'))
assert(_('Ace'))
like image 37
helix7 Avatar answered Oct 24 '25 16:10

helix7