在 Python 3.x 中使用 PyInstaller 编译 gettext 语言环境

The*_*519 5 python localization gettext pyinstaller python-3.x

我正在冻结一个gettext本地化的(英语和法语,但将来可能更多)Python 脚本,pyinstaller --onefile palc.py它可以完美编译,但是当我尝试运行它时,它尝试使用存储在locales目录中的语言环境(这意味着它找不到如果我不将包与locales目录一起分发)。正如您可以想象的那样,这是一个主要缺点,并且几乎破坏了 PyInstaller \xe2\x80\x94 的意义,为了分发它,我必须提供一个目录和包才能使其工作 \xe2\x80 \x94 不过,正如我将向您展示的那样,即使这样它也不起作用。

\n

这是主要问题:

\n

是否有可能(最好不是太难或需要大量重写)使 PyInstaller 使用语言gettext环境编译 Python 脚本?

\n

编辑:我尝试编辑我的palc.spec,这是新版本:

\n
# -*- mode: python ; coding: utf-8 -*-\n\nblock_cipher = None\n\n\na = Analysis([\'palc.py\'],\n             pathex=[\'~/python-text-calculator\'],\n             binaries=[],\n             datas=[(\'~/python-text-calculator/locales/*\', \'locales\')],\n             hiddenimports=[],\n             hookspath=[],\n             runtime_hooks=[],\n             excludes=[],\n             win_no_prefer_redirects=False,\n             win_private_assemblies=False,\n             cipher=block_cipher,\n             noarchive=False)\npyz = PYZ(a.pure, a.zipped_data,\n             cipher=block_cipher)\nexe = EXE(pyz,\n          a.scripts,\n          [],\n          exclude_binaries=True,\n          name=\'palc\',\n          debug=False,\n          bootloader_ignore_signals=False,\n          strip=False,\n          upx=True,\n          console=True )\ncoll = COLLECT(exe,\n               a.binaries,\n               a.zipfiles,\n               a.datas,\n               strip=False,\n               upx=True,\n               upx_exclude=[],\n               name=\'palc\')\n
Run Code Online (Sandbox Code Playgroud)\n

这是编译包的输出:

\n
>>> ./palc\n--------------------------------------------------------------------------\n                          Language Selection\n--------------------------------------------------------------------------\n1 - English // Anglais\n2 - Francais // French\nType: 1\nTraceback (most recent call last):\n  File "/Users/computer/python-text-calculator/palc.py", line 30, in <module>\n    l_translations = gettext.translation(\'base\', localedir=\'locales\', languages=["en"])\n  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/gettext.py", line 514, in translation\n    raise OSError(ENOENT, \'No translation file found for domain\', domain)\nFileNotFoundError: [Errno 2] No translation file found for domain: \'base\'\n[19393] Failed to execute script palc\n
Run Code Online (Sandbox Code Playgroud)\n

这与未经编辑的输出完全相同palc.spec。另外,它使编译后的包成为一个目录(我在 dist 中的目录./palc中运行palc),所以我仍然需要分发一个目录。我需要的是一个像这里找到的那​​样的单个文件。

\n

有人可以帮忙吗?谢谢!:D

\n

Try*_*yph 2

首先,生成规范文件后,将规范文件提供给 pysintaller 而不是 Python 文件:运行pyinstaller palc.spec而不是pyinstaller palc.py. 否则,pyinstaller 每次都会重置spec 文件。

然后,为了为 onefile 应用程序生成正确的规范文件,请使用pyi-makespec --onefile palc.py. 它生成一个没有COLLECT步骤和不同EXE步骤的规范文件。

然后,您可以在您的spec文件中使用自定义python函数来构建datas您的语言环境(请记住,spec文件只是一个带有自定义文件扩展名的Python文件):

def get_locales_data():
    locales_data = []
    for locale in os.listdir(os.path.join('./locales')):
        locales_data.append((
            os.path.join('./locales', locale, 'LC_MESSAGES/*.mo'),
            os.path.join('locales', locale, 'LC_MESSAGES')
        ))
    return locales_data
Run Code Online (Sandbox Code Playgroud)

然后使用该函数的返回值作为步骤中datas参数的值Analysis

a = Analysis(['palc.py'],
             ...
             datas=get_locales_data(),
             ...)
Run Code Online (Sandbox Code Playgroud)

然后,您将必须调整代码以在正确的位置查找区域设置文件(根据运行时环境:是否打包),但我没有更多时间来开发这部分答案,因此这里有一个讨论此问题的线程。;)


为了方便起见,下面是使用 pyi-makespec 生成并更改为包含语言环境的正确规范文件的示例:

# -*- mode: python ; coding: utf-8 -*-
import os

block_cipher = None


def get_locales_data():
    locales_data = []
    for locale in os.listdir(os.path.join('./locales')):
        locales_data.append((
            os.path.join('./locales', locale, 'LC_MESSAGES/*.mo'),
            os.path.join('locales', locale, 'LC_MESSAGES')
        ))
    return locales_data


a = Analysis(['palc.py'],
             pathex=['.'],
             binaries=[],
             datas=get_locales_data(),
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='palc',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True )

Run Code Online (Sandbox Code Playgroud)