有没有办法避免输入 QCoreApplication.translate("Context",?
Is there a way to avoid typing QCoreApplication.translate("Context",?
要在 PySide2 应用程序中翻译字符串,我需要调用 QCoreApplication.translate() 并指定一个上下文,这是翻译一个短字符串的大量字符。
即:QCoreApplication.translate("MyClassName", "Hello")
我试着做这样的事情:
from PySide2.QtCore import QCoreApplication
from functools import partial
class Translate:
def __init__(self, context):
self.context = context
self.translate = partial(QCoreApplication.translate, self.context)
def __call__(self, text):
return self.translate(text)
这样 QCoreApplication.translate()
是在正确的上下文中调用的,在我的源代码中我可以使用更短的名称,但字符串没有被提取并存储在 *.ts 文件中。
有没有办法至少减少翻译用 python 编写的 Qt 软件所需的样板字符数量?也许通过配置 pyside2-lupdate?
如果您使用 类,继承自 QObject 可为您提供一个 self.tr("your text")
方法,该方法将具有适当的上下文。
将 QCoreApplication.translate()
替换为 QObject().tr("your string")
确实有效,但假设您每次翻译字符串时都创建了一个新的 QObject ...
似乎做一些全局的 tr = QObject().tr
也确实有效(我怀疑这会很快变得棘手)。
我想到的是这个非常简单的函数:
defaultContext = "MyClassName"
def translate(str, context=defaultContext):
return QCoreApplication.translate(context, str)
您在定义函数时指定默认上下文,也可以随时通过将 defaultContext
设置为不同的值来全局更改它。您可以选择在每次调用时传入不同的上下文,但使用默认值的调用非常简单干净:
translated = translate("Hello")
还是我遗漏了什么?
更新
issue 已在 Qt 5.15.4+ 和 Qt 6+
中修复
首先感谢 benjamin-forest 和 CryptoFool,他们的回答很有用。
我发现这里实际上存在三个不同的问题:
- 只有 PyQt5 的
pylupdate5
支持自定义函数,
而 pyside2-lupdate
没有配置选项,不像 lupdate
pylupdate5
和pyside2-lupdate
在使用全局函数时都无法猜测上下文,因此它们读取的每个字符串都会转到@default
上下文
self.tr()
的默认实现在运行时获取其上下文,如官方 PyQt 文档所述
Differences Between PyQt5 and Qt
Qt implements internationalisation support through the QTranslator
class, and the translate()
and tr()
methods. Usually tr()
is used to
obtain the correct translation of a message. The translation process
uses a message context to allow the same message to be translated
differently. In Qt tr()
is actually generated by moc
and uses the
hardcoded class name as the context. On the other hand, translate
allows the context to be specified explicitly.
Unfortunately, because of the way Qt implements tr()
it is not
possible for PyQt5 to exactly reproduce its behaviour. The PyQt5
implementation of tr()
uses the class name of the instance as the
context. The key difference, and the source of potential problems, is
that the context is determined dynamically in PyQt5, but is hardcoded
in Qt. In other words, the context of a translation may change
depending on an instance’s class hierarchy.
我的解决方案是声明一个私有 __tr()
方法来包装 QCoreApplication.translate()
def __tr(self, txt, disambiguation=None, n=-1):
return QCoreApplication.translate("TestWidget", txt, disambiguation, n)
并配置 pylupdate5 在从 setup.py:
调用时查找它
if has_build_ui:
class build_res(build_ui):
"""Build UI, resources and translations."""
def run(self):
# build translations
check_call(["pylupdate5", "-tr-function", "__tr", "app.pro"])
lrelease = os.environ.get("LRELEASE_BIN")
if not lrelease:
lrelease = "lrelease"
check_call([lrelease, "app.pro"])
# build UI & resources
build_ui.run(self)
# create __init__ file for compiled ui
open("app/ui/__init__.py", "a").close()
cmdclass["build_res"] = build_res
这样 pylupdate5
在生成 .ts
文件时获得正确的上下文,并且 self.__tr()
在运行时始终具有正确的上下文。
要在 PySide2 应用程序中翻译字符串,我需要调用 QCoreApplication.translate() 并指定一个上下文,这是翻译一个短字符串的大量字符。
即:QCoreApplication.translate("MyClassName", "Hello")
我试着做这样的事情:
from PySide2.QtCore import QCoreApplication
from functools import partial
class Translate:
def __init__(self, context):
self.context = context
self.translate = partial(QCoreApplication.translate, self.context)
def __call__(self, text):
return self.translate(text)
这样 QCoreApplication.translate()
是在正确的上下文中调用的,在我的源代码中我可以使用更短的名称,但字符串没有被提取并存储在 *.ts 文件中。
有没有办法至少减少翻译用 python 编写的 Qt 软件所需的样板字符数量?也许通过配置 pyside2-lupdate?
如果您使用 类,继承自 QObject 可为您提供一个 self.tr("your text")
方法,该方法将具有适当的上下文。
将 QCoreApplication.translate()
替换为 QObject().tr("your string")
确实有效,但假设您每次翻译字符串时都创建了一个新的 QObject ...
似乎做一些全局的 tr = QObject().tr
也确实有效(我怀疑这会很快变得棘手)。
我想到的是这个非常简单的函数:
defaultContext = "MyClassName"
def translate(str, context=defaultContext):
return QCoreApplication.translate(context, str)
您在定义函数时指定默认上下文,也可以随时通过将 defaultContext
设置为不同的值来全局更改它。您可以选择在每次调用时传入不同的上下文,但使用默认值的调用非常简单干净:
translated = translate("Hello")
还是我遗漏了什么?
更新
issue 已在 Qt 5.15.4+ 和 Qt 6+
首先感谢 benjamin-forest 和 CryptoFool,他们的回答很有用。
我发现这里实际上存在三个不同的问题:
- 只有 PyQt5 的
pylupdate5
支持自定义函数,
而pyside2-lupdate
没有配置选项,不像lupdate
pylupdate5
和pyside2-lupdate
在使用全局函数时都无法猜测上下文,因此它们读取的每个字符串都会转到@default
上下文self.tr()
的默认实现在运行时获取其上下文,如官方 PyQt 文档所述
Differences Between PyQt5 and Qt
Qt implements internationalisation support through the
QTranslator
class, and thetranslate()
andtr()
methods. Usuallytr()
is used to obtain the correct translation of a message. The translation process uses a message context to allow the same message to be translated differently. In Qttr()
is actually generated bymoc
and uses the hardcoded class name as the context. On the other hand, translate allows the context to be specified explicitly.Unfortunately, because of the way Qt implements
tr()
it is not possible for PyQt5 to exactly reproduce its behaviour. The PyQt5 implementation oftr()
uses the class name of the instance as the context. The key difference, and the source of potential problems, is that the context is determined dynamically in PyQt5, but is hardcoded in Qt. In other words, the context of a translation may change depending on an instance’s class hierarchy.
我的解决方案是声明一个私有 __tr()
方法来包装 QCoreApplication.translate()
def __tr(self, txt, disambiguation=None, n=-1):
return QCoreApplication.translate("TestWidget", txt, disambiguation, n)
并配置 pylupdate5 在从 setup.py:
调用时查找它if has_build_ui:
class build_res(build_ui):
"""Build UI, resources and translations."""
def run(self):
# build translations
check_call(["pylupdate5", "-tr-function", "__tr", "app.pro"])
lrelease = os.environ.get("LRELEASE_BIN")
if not lrelease:
lrelease = "lrelease"
check_call([lrelease, "app.pro"])
# build UI & resources
build_ui.run(self)
# create __init__ file for compiled ui
open("app/ui/__init__.py", "a").close()
cmdclass["build_res"] = build_res
这样 pylupdate5
在生成 .ts
文件时获得正确的上下文,并且 self.__tr()
在运行时始终具有正确的上下文。