python gettext:在()中指定区域设置

2024-10-04 07:29:07 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一种在请求gettext中的字符串的翻译时动态设置语言的方法。我来解释原因:

我有一个多线程机器人,它在多个服务器上通过文本响应用户,因此需要用不同的语言进行响应。 gettext的documentation声明,要在运行时更改区域设置,应执行以下操作:

import gettext # first, import gettext

lang1 = gettext.translation('myapplication', languages=['en']) # Load every translations
lang2 = gettext.translation('myapplication', languages=['fr'])
lang3 = gettext.translation('myapplication', languages=['de'])

# start by using language1
lang1.install()

# ... time goes by, user selects language 2
lang2.install()

# ... more time goes by, user selects language 3
lang3.install()

但是,这不适用于我的情况,因为bot是多线程的:

假设以下两个代码段同时运行:

^{pr2}$

以及

import time
import gettext 
lang = gettext.translation('myapplication', languages=['en'])
time.sleep(3) # Not requested on the same time
lang.install()
message(_("Loading a dummy task")) # This should be in english, and it will
time.sleep(10)
message(_("Finished loading")) # This should be in english too, and it will

您可以看到消息有时在错误的区域设置中被翻译。 但是,如果我能做一些类似_("string", lang="FR")的事情,问题就会消失!在

我是否遗漏了什么,或者我使用了错误的模块来完成任务。。。 我用的是Python3


Tags: installimport语言区域langbytimetranslation
3条回答

下面的示例直接使用translation,如o11c'sanswer所示,以允许使用线程:

import gettext
import threading
import time

def translation_function(quit_flag, language):
    lang = gettext.translation('simple', localedir='locale', languages=[language])
    while not quit_flag.is_set():
        print(lang.gettext("Running translator"), ": %s" % language)
        time.sleep(1.0)

if __name__ == '__main__':
    thread_list = list()
    quit_flag = threading.Event()
    try:
        for lang in ['en', 'fr', 'de']:
            t = threading.Thread(target=translation_function, args=(quit_flag, lang,))
            t.daemon = True
            t.start()
            thread_list.append(t)
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        quit_flag.set()
        for t in thread_list:
            t.join()

输出:

^{pr2}$

如果我知道更多关于gettext的信息,我会发布这个答案的。我把我之前的答案留给那些真正想继续使用_()的人。在

我花了一些时间创建了一个脚本,它使用系统上可用的所有区域设置,并尝试在其中打印一条众所周知的消息。请注意,“所有区域设置”只包括编码更改,不管怎样,这些更改都被Python否定,而且很多翻译都是不完整的,所以请使用回退。在

显然,您还必须对xgettext(或等效值)的使用进行适当的更改,以使您的实际代码能够识别转换函数。在

#!/usr/bin/env python3

import gettext
import os

def all_languages():
    rv = []
    for lang in os.listdir(gettext._default_localedir):
        base = lang.split('_')[0].split('.')[0].split('@')[0]
        if 2 <= len(base) <= 3 and all(c.islower() for c in base):
            if base != 'all':
                rv.append(lang)
    rv.sort()
    rv.append('C.UTF-8')
    rv.append('C')
    return rv

class Domain:
    def __init__(self, domain):
        self._domain = domain
        self._translations = {}

    def _get_translation(self, lang):
        try:
            return self._translations[lang]
        except KeyError:
            # The fact that `fallback=True` is not the default is a serious design flaw.
            rv = self._translations[lang] = gettext.translation(self._domain, languages=[lang], fallback=True)
            return rv

    def get(self, lang, msg):
        return self._get_translation(lang).gettext(msg)

def print_messages(domain, msg):
    domain = Domain(domain)
    for lang in all_languages():
        print(lang, ':', domain.get(lang, msg))

def main():
    print_messages('libc', 'No such file or directory')

if __name__ == '__main__':
    main()

下面的简单示例演示如何为每个转换器使用单独的进程:

import gettext
import multiprocessing
import time

def translation_function(language):
    try:
        lang = gettext.translation('simple', localedir='locale', languages=[language])
        lang.install()
        while True:
            print(_("Running translator"), ": %s" % language)
            time.sleep(1.0)
    except KeyboardInterrupt:
        pass

if __name__ == '__main__':
    thread_list = list()
    try:
        for lang in ['en', 'fr', 'de']:
            t = multiprocessing.Process(target=translation_function, args=(lang,))
            t.daemon = True
            t.start()
            thread_list.append(t)
        while True:
            time.sleep(1.0)
    except KeyboardInterrupt:
        for t in thread_list:
            t.join()

输出如下:

^{pr2}$

当我用线程尝试这个时,我只得到了一个英文翻译。您可以在每个进程中创建单独的线程来处理连接。您可能不想为每个连接创建一个新进程。在

相关问题 更多 >