如何将 gettext 与 python >3.6 f-strings 一起使用
How to use gettext with python >3.6 f-strings
以前您会按如下方式使用 gettext
:
_('Hey {},').format(username)
但是新 Python 的 f-string 呢?
f'Hey {username}'
'Hey {},'
原样包含在您的翻译词典中。
如果您使用 f'Hey {username},'
,则会创建另一个不会被翻译的字符串。
在这种情况下,format
方法仍然是唯一可用的方法。
我的解决方案是创建一个函数 f()
,它在 gettext
被调用后执行 f-string 插值。
from copy import copy
from inspect import currentframe
def f(s):
frame = currentframe().f_back
kwargs = copy(frame.f_globals)
kwargs.update(frame.f_locals)
return eval(s.format(**kwargs))
现在你只需将 _(...)
包裹在 f()
中,不要在字符串前加上 f:
f(_('Hey, {username}'))
注意事项
我通常反对使用 eval,因为它可能使函数有潜在的不安全性,但我个人认为在这里应该证明它是合理的,只要您知道正在格式化的内容。也就是说,使用风险自负。
记得
这不是一个完美的解决方案,这只是我的解决方案。根据 PEP 498 的规定,每种格式化方法“都有其优点,但也有缺点”,包括这一点。
例如,如果您需要更改字符串中的表达式,那么它将不再匹配,因此不会被翻译,除非您也更新您的 .po
文件。此外,如果您不是翻译它们的人,并且您使用的表达方式很难解读结果是什么,那么可能会导致翻译中的沟通不畅或其他问题。
以前您会按如下方式使用 gettext
:
_('Hey {},').format(username)
但是新 Python 的 f-string 呢?
f'Hey {username}'
'Hey {},'
原样包含在您的翻译词典中。
如果您使用 f'Hey {username},'
,则会创建另一个不会被翻译的字符串。
在这种情况下,format
方法仍然是唯一可用的方法。
我的解决方案是创建一个函数 f()
,它在 gettext
被调用后执行 f-string 插值。
from copy import copy
from inspect import currentframe
def f(s):
frame = currentframe().f_back
kwargs = copy(frame.f_globals)
kwargs.update(frame.f_locals)
return eval(s.format(**kwargs))
现在你只需将 _(...)
包裹在 f()
中,不要在字符串前加上 f:
f(_('Hey, {username}'))
注意事项
我通常反对使用 eval,因为它可能使函数有潜在的不安全性,但我个人认为在这里应该证明它是合理的,只要您知道正在格式化的内容。也就是说,使用风险自负。
记得
这不是一个完美的解决方案,这只是我的解决方案。根据 PEP 498 的规定,每种格式化方法“都有其优点,但也有缺点”,包括这一点。
例如,如果您需要更改字符串中的表达式,那么它将不再匹配,因此不会被翻译,除非您也更新您的 .po
文件。此外,如果您不是翻译它们的人,并且您使用的表达方式很难解读结果是什么,那么可能会导致翻译中的沟通不畅或其他问题。