【问题标题】:How can I localize argparse generated messages in a portable way?如何以可移植的方式本地化 argparse 生成的消息?
【发布时间】:2018-11-05 16:25:39
【问题描述】:

上下文:

我正在开发一个小模块,用于根据 exif 时间戳自动重命名目录中的照片(目标:轻松混合来自不同相机或智能手机的图片)。它可以作为 Python 包顺利运行,也可以通过使用 argparse 的小型包装器直接从命令行运行。

我刚刚有了一个(相当愚蠢的)想法,将其本地化为非英语语言。好吧,gettext 是我所有自己代码的朋友,但是当我来到 agparse 生成的消息时,我发现自己处于草率状态......

目前的研究:

我已经在 SO 上找到了一些资源:

最终都将argparse 中的相关字符串 添加到po/mo 文件中,并让argparse 模块自动使用翻译后的字符串,因为它在内部使用_(...) 包装器。到目前为止,一切顺利。

我的问题:

我觉得这更像是一种解决方法,而不是一个干净整洁的解决方案,因为:

  • 我在 Python 官方文档中找不到一个词来建议它
  • 它看起来像一个正在进行的工作:由未记录的实现,因此某些字符串可能会在未来的 Python 版本中发生变化(或者我错过了什么?)

当前代码:

parser = argparse.ArgumentParser(
    prog = prog,
    description="Rename pictures according to their exif timestamp")
parser.add_argument("-v", "--version", action="version",
                    version="%(prog)s " + __version__)
parser.add_argument("--folder", "-f", default = ".",
                    help = "folder containing files to rename")
parser.add_argument("-s", "--src_mask", default="DSCF*.jpg",
                    help = "pattern to select the files to rename")
parser.add_argument("-d", "--dst_mask", default="%Y%m%d_%H%M%S",
                    help = "format for the new file name")
parser.add_argument("-e", "--ext", default=".jpg", dest="ext_mask",
                    help = "extension for the new file name")
parser.add_argument("-r", "--ref_file", default="names.log",
                    help = "a file to remember the old names")
parser.add_argument("-D", "--debug", action="store_true",
                    help = "print a line per rename")
parser.add_argument("-X", "--dry_run", action="store_true", dest="dummy",
                    help = "process normally except no rename occurs")

# subcommands configuration (rename, back, merge)
subparser = parser.add_subparsers(dest='subcommand', help="sub-commands")
ren = subparser.add_parser("rename", help=
                           "rename files by using their exif timestamp")
ren.add_argument("files", nargs="*",
                  help = "files to process (default: src_mask)")
back = subparser.add_parser("back",
                            help="rename files back to their original name")
back.add_argument("files", nargs="*",
                   help = "files to process (default: content of ref_file)")
merge = subparser.add_parser("merge",
                             help="merge files from a different folder")
merge.add_argument("src_folder", metavar="folder",
                    help = "folder from where merge picture files")
merge.add_argument("files", nargs="*",
                  help = "files to process (default: src_mask)")

我知道如何用_() 包装我自己的字符串,并且我可能对 usagehelp 消息有可接受的翻译,但是有很多错误用户给出错误语法时的消息,我想防止在法语程序中间出现英文错误消息...

问题:

是否可以保证argparse 模块中字符串的实现不会改变,或者是否有更健壮/可移植的方式为其消息提供翻译?

【问题讨论】:

  • 我已经尝试关注所有argparse 错误/问题,但很少有人讨论它对gettext 的使用。 (我没有关注与gettext 相关的其他问题)。 argparse 变化不大,很大程度上是因为开发人员不希望出现向后兼容性问题。因此,如果将来有变化,它们很可能是不会破坏现有代码的增强功能。
  • @hpaulj:感谢您的评论。令人遗憾的是,消息列表并未明确包含在公共界面中,但恐怕我不得不接受它......
  • unittest 文件test_argparse.py 最初只是测试错误与否,在少数情况下测试异常类。某些测试仅在文件的后半部分查看消息(通常使用某种正则表达式)。大多数针对最终用户(而不是像您这样的代码编写者)的错误都会通过ArgparseErrorparser.error。这些错误将包括usage 和相关的操作“名称”(dest)。但我从未尝试过盘点可能的错误消息。
  • @hpaulj:我主要关心的是针对最终用户的错误。我已经阅读了argparse.py 及其最近(几年)的更改(在您发表评论之后),我将很快对其测试文件进行相同的处理。坏消息是,即使是完整的错误消息也有建议的转换(这里很难详尽),但应该可以转换最简单的字符串并通过覆盖 ArgParser.error 设置 catch all。我将进一步试验,如果我没有得到好的答案,我可以提交我自己的问题的答案。无论如何,感谢您的反馈。

标签: python internationalization argparse


【解决方案1】:

经过更多研究和@hpaulj 的伟大cmets,我可以确认:

  • 来自argparse 的可本地化消息从 3.3 向上兼容到当前版本(旧消息从未更改,但为新功能添加了新消息)
  • 在 3.3 之前以上不成立
  • 2.7 略有不同

这意味着这里只有 2 条路径是可能的:

  • 接受风险并为将接受任何 Python 版本 >= 3.3 的当前版本提供翻译 - 风险是未来版本会破坏翻译或添加新的(未翻译的)消息。无需多说,因为这将明确使用模块的实现细节
  • 完全不要使用argparse 模块并基于getopt 构建自定义解析器。对于不需要argparse 的全部功能的简单用例,这可能是一个可接受的选择

没有一个真的很好,但我想不出更好的......

我将尝试在 github 或 gitlab 上设置一个项目,为当前的 argparse 提供 pot 文件和法语翻译,并使其在 PyPI 上可用。如果它存在,我会在这里添加它的引用,并很高兴在那里包含其他语言。


为 argparse 模块提供法语翻译的项目的 beta 版本目前在 GitHUB 上提供

我称它为 beta 是因为目前它还没有经过广泛的测试,但它既可以直接使用,也可以作为可以做的示例。二进制轮子包含一个小的 endian mo 文件,但源代码分发允许 mo 文件在目标系统上自动生成,无需额外依赖,方法是包含来自 CPython 工具 i18n 的 msgfmt.py 文件的副本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多