在Python和gettext中切换翻译

4 投票
3 回答
8740 浏览
提问于 2025-04-17 16:18

我有一段代码,应该能显示两行英文文本,中间夹着一行罗马尼亚文的文本,但它只显示了英文文本(语言切换功能没有正常工作):

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):
    # ...

我的文件夹结构如下:

.
├── 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

我使用了 xgettextmsgfmt 来生成 .po.mo 文件。

问题是,如果我只加载一种语言,文本就能被翻译(我必须在显示任何输出之前先做这个)。

#! /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

但是如果我想在运行时切换语言,上面第一段代码生成的输出就不会被翻译。

我哪里做错了?我对文档的理解有什么问题吗?

3 个回答

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

完全可以用!

没错,字符串常量必须在你的代码中的某个地方。

这些字符串常量不一定要在显示文本的同一个模块里。把字符串常量放在同一个模块里看起来不太美观(也不符合面向对象编程的原则)。

在使用 py v2.7 / gtk v2.24.10 / gettext 0.18.1 的情况下成功测试过。

python
import gtk 
gtk.gtk_version
(2, 24, 10)

gettext --version
gettext (GNU gettext-runtime) 0.18.1

免责声明 在让 gettext 在你的 Python 应用程序中正常工作之前,不要尝试这个。包括能够动态切换语言(地区)。这些都不是小事。这会消除99%的困惑。然后要么就能正常工作,要么就不能。我是说它会正常工作的!

1

翻译通常是为了最终用户,而不是开发者。所以在代码中保留你的字符串原样,只有在显示它们的时候才进行翻译:

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

...

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

请注意,字符串提取工具将无法再找到这些字符串,除非你在代码的某个地方用 _() 调用它们。

如果你不想手动将字符串添加到翻译文件中,可以在模块中添加类似这样的内容:

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

或者这样:

assert(_('Jack'))
assert(_('Queen'))
assert(_('King'))
assert(_('Ace'))
2

gettext.install() 这个函数的作用就是把 _() 这个函数定义为一个用来翻译文本的工具。在你第一个例子中,你在调用 ro.install() 之前就执行了 x = card.Rank(),所以当 j = _('Jack') 被调用的时候,_() 只会把它翻译成默认的英语。之后,_() 被重新定义为罗马尼亚语,但因为它没有再被调用过,所以也就没有再进行翻译。

我想这个方法会有效:

#! /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

撰写回答