如何使文档字符串符合PEP257,同时与docopt兼容以支持i18n和gettext?

4 投票
3 回答
527 浏览
提问于 2025-04-18 06:45

根据PEP 257的规定,命令行脚本的文档字符串应该是它的使用说明:

一个脚本(独立程序)的文档字符串应该可以作为它的“使用”信息,当脚本被错误或缺少参数调用时(或者使用“-h”选项,即“帮助”时)打印出来。这样的文档字符串应该描述脚本的功能和命令行语法、环境变量和文件。使用说明可以相当详细(可能有好几屏的内容),应该足够让新用户正确使用命令,同时也为高级用户提供所有选项和参数的快速参考。

而且,文档字符串应该是模块级别的第一个字符串,在其他内容之前,以便可以通过__doc__访问。

现在,我也在使用docopt作为使用说明的解析器,所以我只需要写文档字符串,它就会自动构建命令行解析器,这样很好。

_("""...""")

不过,有一点不太好的是,我找不到方法将文档字符串标记为可以国际化(i18n),以便在给docopt时可以转换成其他语言。目前我唯一的解决办法是让使用和帮助信息保持英文,而应用程序的其他字符串都翻译成其他语言!

正如PEP 20所说:

应该有一种——而且最好只有一种——明显的方法来做到这一点。
虽然这种方法一开始可能并不明显,除非你是荷兰人。

那么,有什么好的方法可以优雅地解决无法将文档字符串标记为可翻译的这个限制呢?

注意:这里我们假设我在__init__.py模块中调用了gettext.install(),这样_()在解析__doc__之前就已经存在于内置函数中。

3 个回答

0

另一种方法:

if __name__ == "__main__":
    if hasattr(vars()['__builtins__'], '_') and not 'NullTranslations' in str(_):
        args = docopt.docopt(_("USAGE MESSAGE"))
    else:
        args = docopt.docopt(__doc__)

这种方法不是使用异常,而是通过方法的字符串表示来检查类型,并在内置模块中查找该方法……其实这并没有比其他选项更好。

而且这个方法也算是个相当糟糕且不优雅的解决方案,因为翻译者需要查看源代码来查找文档字符串。或者我得在代码中写两遍文档字符串的内容。

1

目前,我想到的解决方案大致是这样的:

"""\
This is the docstring
"""

import docopt
if __name__ == "__main__":
    try:
        args = docopt.docopt(_("{docstring}").format(docstring=__doc__))
    except KeyError:
        args = docopt.docopt(_("{docstring}")) # string which will be replaced by the i18ned one.

我觉得这个方法不太优雅,因为虽然在Python中使用异常是可以的,但我认为它们应该留给一些特殊情况,而不是应用程序中的常规使用场景。

这也是一个相当不太正统的做法,它会让文档字符串的格式出现在gettext中,而不是__docopt__的文本,这对翻译人员没有帮助,因为他们还得回到源代码去查看...

1

我终于找到了一个很好的方法来解析文档字符串:

-D
--docstrings
    Extract module, class, method, and function docstrings.  These do
    not need to be wrapped in _() markers, and in fact cannot be for
    Python to consider them docstrings. (See also the -X option).

这个方法会提取出所有的文档字符串。所以,唯一需要翻译的部分可以用以下方式进行翻译:

args = docopt.docopt(_(__doc__))

撰写回答