我可以在一个库和同时使用它的模块中调用并设置Python的gettext模块吗?

3 投票
2 回答
2137 浏览
提问于 2025-04-11 09:33

我正在编写一个库,这个库需要包含一些文本反馈,而这些反馈需要翻译。

我在一个叫 _config.py 的模块里写了以下几行代码,这个模块在我的应用中到处都用到:

import gettext, os, sys
pathname = os.path.dirname(sys.argv[0])
localdir = os.path.abspath(pathname) + "/locale"
gettext.install("messages", localdir)

我把 *.mo 文件放在 ./locale/lang_LANG/LC_MESSAGES 这个文件夹里,并且我对所有需要翻译的字符串都使用了 _() 这个函数。

现在我刚刚添加了一个功能,让用户(假设是程序员)可以创建自己的消息。我不想让他们去关心底层的实现,所以我希望他们能用一种简单的方式来做,比如:

lib_object.message = "My message"

我使用了属性来保持代码的整洁,但如果我的用户想要翻译他们自己的代码(而这个代码又是基于我的库),并且做了类似这样的事情:

import gettext, os, sys
pathname = os.path.dirname(sys.argv[0])
localdir = os.path.abspath(pathname) + "/locale"
gettext.install("user_app", localdir)

lib_object.message = _("My message")

这样会有问题吗?我该怎么做才能避免麻烦,同时又不打扰到我的用户呢?

2 个回答

3

你只能使用 gettext.install() 一次。一般来说,这个函数在库的开发中没什么用处——因为 gettext.install() 只有在调用它的模块负责整个程序时才会正常工作,因为它只会提供一个可以加载的目录。库的代码应该像 Mailman 那样做:为 gettext() 创建一个自己的封装,传递正确的参数给这个模块,然后在每个想要使用它的模块中将其导入为 '_'。

5

你可以使用基于类的gettext API来管理消息目录,这也是在Python gettext文档中推荐的做法。

不过,这样做的缺点是你或者其他开发者需要使用gettext方法,或者在本地范围内定义一个_()方法,并把它绑定到特定的gettext类上。下面是一个拥有自己字符串目录的类的例子:

import gettext

class MyClass(object):
    def __init__(self, locale_for_instance):
        self.lang = gettext.translation("appname", localedir, \
                                         locale=locale_for_instance)

    def some_method(self, arg):
        return self.lang.gettext("You called some method")

    def other_method(self, arg): # does the same thing
        _ = self.lang.gettext
        return _("You called some method")

你可以把添加_()方法的代码放在一个装饰器里,这样所有需要这个方法的函数前面都可以加上类似@with_local_gettext的标记。

(注意,我没有测试过上面的代码,但它应该能正常工作。)

如果你的目标是让用户使用起来更方便(而且他可能不太懂),我想你可以在代码中使用基于类的方法,让用户使用全局的方法。

撰写回答