如何将gettext翻译应用于case语句中的字符串字面量?



我需要将gettext翻译添加到代码中的所有字符串文字中,但它不适用于case语句中的文字。

这个失败的尝试给出SyntaxError: Expected ':':

from gettext import gettext as _
direction = input(_('Enter a direction: '))   # <-- This works
match direction:
case _('north'):                          # <-- This fails
adj = 1, 0
case _('south'):
adj = -1, 0
case _('east'):
adj = 0, 1
case _('west'):
adj = 0, -1
case _:
raise ValueError(_('Unknown direction'))

这个错误是什么意思?如何标记方向以便翻译?

这个错误是什么意思?

match/case语句的语法将_视为通配符模式。后面唯一可以接受的标记是冒号。由于您的代码使用了开括号,因此会引发SyntaxError

如何修复

从文字模式(如case "north": ...)切换到使用点运算符的值模式(如case Directions.north: ...)。

转换可以在上游执行,在case语句之外:

from gettext import gettext as _
class Directions:
north = _('north')
south = _('south')
east = _('east')
west = _('west')
direction = input(_('Enter a direction: '))
match direction:
case Directions.north:
adj = 1, 0
case Directions.south:
adj = -1, 0
case Directions.east:
adj = 0, 1
case Directions.west:
adj = 0, -1
case _:
raise ValueError(_('Unknown direction'))

不仅字符串字面量被翻译了,case语句也更可读了。

更高级、更动态的解决方案

上述解决方案仅在语言选择不变的情况下有效。如果语言可以改变(可能是在为来自不同国家的用户提供服务的在线应用程序中),则需要动态查找。

首先,我们需要一个描述符来动态地将模式属性查找转发给函数调用:

class FuncCall:
"Descriptor to convert fc.name to func(name)."
def __init__(self, func):
self.func = func
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, objtype=None):
return self.func(self.name)

我们这样使用:

class Directions:
north = FuncCall(_)  # calls _('north') for every lookup
south = FuncCall(_)
east = FuncCall(_)
west = FuncCall(_)
def convert(direction):
match direction:
case Directions.north:
return 1, 0
case Directions.south:
return -1, 0
case Directions.east:
return 0, 1
case Directions.west:
return 0, -1
case _:
raise ValueError(_('Unknown direction'))
print('Adjustment:', adj)

下面是一个示例会话:

>>> set_language('es')   # Spanish
>>> convert('sur')
(-1, 0)
>>> set_language('fr')   # French
>>> convert('nord')
(1, 0)

值模式的命名空间

任何带点查找的命名空间都可以在值模式中使用:SimpleNamespace、Enum、模块、类、实例等。

这里选择一个类是因为它简单,并且可以与更高级的解决方案所需的描述符一起工作。

没有考虑Enum,因为它要复杂得多,而且它的元类逻辑会干扰描述符。此外,Enum用于为预定义的常量提供符号名称,而不是像我们在这里使用的那样用于动态计算值。

相关内容

  • 没有找到相关文章

最新更新