Way*_*oor 7 python multithreading gettext internationalization python-3.x
我正在寻找一种在请求 gettext 中的字符串翻译时动态设置语言的方法。我会解释为什么:
我有一个多线程机器人,它在多个服务器上通过文本响应用户,因此需要用不同的语言回复。文档,要在运行时更改区域设置,您应该执行以下操作:
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()
Run Code Online (Sandbox Code Playgroud)
但是,这不适用于我的情况,因为机器人是多线程的:
想象一下以下 2 个片段同时运行:
import time
import gettext
lang1 = gettext.translation('myapplication', languages=['fr'])
lang1.install()
message(_("Loading a dummy task")) # This should be in french, and it will
time.sleep(10)
message(_("Finished loading")) # This should be in french too, but it wont :'(
Run Code Online (Sandbox Code Playgroud)
和
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
Run Code Online (Sandbox Code Playgroud)
您可以看到消息有时会在错误的区域设置中翻译。但是,如果我能做类似的事情_("string", lang="FR")
,问题就会消失!
我错过了什么,或者我使用了错误的模块来完成任务......我正在使用 python3
虽然上述解决方案似乎有效,但它们不能很好地与_()
别名gettext()的传统函数配合使用。但我想保留该功能,因为它\xe2\x80\x99s 用于从源中提取翻译字符串(请参阅文档或例如此博客)。
因为我的模块在多进程和多线程环境中运行,所以使用 application\xe2\x80\x99s 内置命名空间或module\xe2\x80\x99s 全局命名空间不会 \xe2\x80\x99s 工作,因为_()
会共享资源,并且如果多个线程安装不同的翻译,则会受到竞争条件的影响。
因此,首先我编写了一个简短的辅助函数,它返回一个翻译闭包:
\nimport gettext\n\ndef get_translator(lang: str = "en"):\n trans = gettext.translation("foo", localedir="/path/to/locale", languages=(lang,))\n return trans.gettext\n
Run Code Online (Sandbox Code Playgroud)\n然后,在使用翻译字符串的函数中,我将该翻译闭包分配给_
,从而使其成为_()
函数本地范围内所需的函数,而不会污染全局共享命名空间:
def some_function(...):\n _ = get_translator() # Pass whatever language is needed.\n\n log.info(_("A translated log message!"))\n
Run Code Online (Sandbox Code Playgroud)\n(额外的奖励点是将get_translator()
函数包装到记忆缓存中,以避免多次创建相同的闭包。)
小智 1
以下简单示例展示了如何为每个转换器使用单独的进程:
\n\nimport gettext\nimport multiprocessing\nimport time\n\ndef translation_function(language):\n try:\n lang = gettext.translation(\'simple\', localedir=\'locale\', languages=[language])\n lang.install()\n while True:\n print(_("Running translator"), ": %s" % language)\n time.sleep(1.0)\n except KeyboardInterrupt:\n pass\n\nif __name__ == \'__main__\':\n thread_list = list()\n try:\n for lang in [\'en\', \'fr\', \'de\']:\n t = multiprocessing.Process(target=translation_function, args=(lang,))\n t.daemon = True\n t.start()\n thread_list.append(t)\n while True:\n time.sleep(1.0)\n except KeyboardInterrupt:\n for t in thread_list:\n t.join()\n
Run Code Online (Sandbox Code Playgroud)\n\n输出如下所示:
\n\n\n运行翻译器 : en\nTraducteur 课程 d\xe2\x80\x99ex\xc3\xa9cution : fr\nLaufenden \xc3\x9cbersetzer : de\n运行翻译器 : en\nTraducteur 课程 d\xe2\x80\x99ex\xc3\xa9cution : fr\n劳芬登 \xc3\x9cbersetzer : de\n\n\n
当我使用线程尝试此操作时,我只得到了英文翻译。您可以在每个进程中创建单独的线程来处理连接。您可能不想为每个连接创建一个新进程。
\n 归档时间: |
|
查看次数: |
3657 次 |
最近记录: |