【问题标题】:Is there a portable way to provide localization of a package distributed on PyPI?是否有一种可移植的方式来提供在 PyPI 上分发的包的本地化?
【发布时间】:2018-11-13 16:38:58
【问题描述】:

上下文:

这是对我的another question 的一种跟进。

我想提供一个包的本地化版本。根据 Python 文档,我用 pygettext 提取了一个 .pot 文件,在 .po 文件中准备了翻译,在 .mo 文件中编译它。

到那里为止一切都很好,我的包裹会显示翻译后的消息。

但我的最终目标是让它在 PyPI 上可用。所以我做了一些研究,发现:

问题:

有没有办法构建包含编译 mo 文件的平台特定轮子?

如果不是,我将不得不在目标上要求 babel 并尝试在安装时通过 mo 编译找到我的方式。

【问题讨论】:

    标签: python localization setuptools


    【解决方案1】:

    2018 年 7 月 12 日编辑:

    经过一些工作,我可以根据以下答案构建一个特定的包。它可以从其他项目中使用,通过 setuptools enty_points 的魔力在构建时自动编译 po 文件。它现已在 Github (https://github.com/s-ball/mo_installer) 上可用,并在 PyPI (https://pypi.org/project/mo_installer) 上分发


    我在提出这个问题之前所做的研究给了我足够的提示来找到一个可能的解决方案。

    我现在可以说,可以在轮子中包含特定于平台的 mo 文件 - 不幸的是,在我当前的解决方案中,轮子没有表明它是特定于平台的。但同样的解决方案允许构建在目标平台上构建 mo 文件的源分发。

    现在了解详情:

    1. 在目标上编译 mo 文件所需的工具:

      从 Google 或 SO 挑选的大多数解决方案都依赖 Babel 或 GNU gettext msgfmt 程序。但是 cPython 工具包含一个纯 Python 模块msgfmt.py,在这里就足够了。不幸的是,在许多类似 Linux/Unix 的情况下,通常不会默认安装此工具。我的解决方案仅包含 3.7.1 版本的该模块的副本(仅 7k 文件)。它看起来像一个非常稳定的代码(近年来几乎没有变化),它应该适用于任何 Python >= 3.3

    2. setuptools 集成

      setuptools 的神奇之处在于,相同的 build 子命令在内部用于构建二进制轮子,使用源包中的 pip 安装或直接使用完整源包的副本(git clone)中的python setup.py install 安装.所以我在setup.py 中提供了一个build 子类,它在调用超类方法之前生成带有完整路径的.mo 文件。我还使用MANIFEST.in 文件列出应在源代码分发中复制的文件,并使用package_data 设置参数列出二进制包或安装文件夹中应包含的内容

    3. 运行时使用情况

      提供要安装在 know 包下的 mo 层次结构,从该包的模块调用的 os.dirname(__file__) 提供其父文件夹


    代码(假设msgfmt.py文件复制到tools_i18n文件夹下,po文件在src文件夹下):

    setup.py

    ...
    sys.path.append(os.path.join(os.path.dirname(__file__), "tools_i18n"))
    import msgfmt
    from distutils.command.build import build as _build
    
    class Builder(_build):
        def run(self):
            # po files in src folder are named domain_lang.po
            po = re.compile(r"(.*)_(.*).po")
            for file in os.listdir("src"):
                m = po.match(file)
                if m:
                    # create the LANG/LC_MESSAGES subdir of "locale"
                    path = os.path.join(self.build_lib, NAME, "locale",
                                     m.group(2), "LC_MESSAGES")
                    os.makedirs(path, exist_ok=True)
                    # use msgfmt.py to compile the po file
                    msgfmt.make(os.path.join("src", file),
                                os.path.join(path, m.group(1) + ".mo"))
            _build.run(self)
            
    setup(
        name=NAME,
        ...
        package_data = { "": [..., "locale/*/*/*.mo"]}, # ensure .mo file are copied
        cmdclass = {"build": Builder},
        )
    

    MANIFEST.in:

    ...
    include src/*
    include tools_i18n/*
    

    在运行时使用翻译:

    locpath = os.path.dirname(__file__)
    lang = locale.getdefaultlocale()[0]   # to get platform default language, or whatever...
    tr = gettext.translation("argparse", os.path.join(locpath, "locale"),
                             [lang], fallback=True)
    

    使用此方法的完整项目可在https://github.com/s-ball/i18nparse 获得


    最后但并非最不重要的一点是,在更深入地阅读了GNU gettext doc 之后,我可以说 gettext 可以处理 mo 文件,无论它们的字节顺序如何:

    任何字节序的 MO 文件都可以在任何平台上使用。当 MO 文件的字节序不是平台的字节序时,MO 文件中的 32 位数字会在运行时交换。性能影响可以忽略不计。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-09
      • 1970-01-01
      • 2023-04-01
      • 2011-03-24
      相关资源
      最近更新 更多