我需要将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用于为预定义的常量提供符号名称,而不是像我们在这里使用的那样用于动态计算值。