简体   繁体   中英

How to compile *.po gettext translations in setup.py python script

Consider a python package that has multilanguage support (using gettext ). How to compile *.po files to *.mo files on the fly when executing setup.py ? I really don't want to distribute precompiled *.mo files.

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from distutils.core import setup

setup(
    name='tractorbeam',
    version='0.1.0',
    url='http://starfleet.org/tractorbeam/',
    description='Pull beer out of the fridge while sitting on the couch.',

    author='James T. Kirk',
    author_email= 'jkirk@starfleet.org',

    packages=['tractorbeam'],
    package_data={
        'tractorbeam': [
            'locale/*.po',
            'locale/*.mo',  # How to compile on the fly?
        ]
    },

    install_requires=[
        'requests'
    ]
)

Thanks in advance!

I know this question begins to be a bit old, but in case anyone's still looking for an answer: it's possible to add a function to setup.py that will compile po files and return the data_files list . I didn't choose to include them in package_data because data_files 's description looked more appropriate:

configuration files, message catalogs , data files, anything which doesn't fit in the previous categories.

Of course you can only append this list to the one you're already using, but assuming you only have these mo files to add in data_files, you can write:

setup(
    .
    .
    .
    data_files=create_mo_files(),
    .
    .
    .
)

For your information, here's the function create_mo_files() I use. I don't pretend it's the best implementation possible. I put it here because it looks useful and is easy to adapt. Note that it's a bit more extra-complicated than what you need because it doesn't assume there's only one po file to compile per directory, it deals with several instead; note also that it assumes that all po files are located in something like locale/language/LC_MESSAGES/*.po , you'll have to change it to fit your needs:

def create_mo_files():
    data_files = []
    localedir = 'relative/path/to/locale'
    po_dirs = [localedir + '/' + l + '/LC_MESSAGES/'
               for l in next(os.walk(localedir))[1]]
    for d in po_dirs:
        mo_files = []
        po_files = [f
                    for f in next(os.walk(d))[2]
                    if os.path.splitext(f)[1] == '.po']
        for po_file in po_files:
            filename, extension = os.path.splitext(po_file)
            mo_file = filename + '.mo'
            msgfmt_cmd = 'msgfmt {} -o {}'.format(d + po_file, d + mo_file)
            subprocess.call(msgfmt_cmd, shell=True)
            mo_files.append(d + mo_file)
        data_files.append((d, mo_files))
    return data_files

(you'll have to import os and subprocess to use it)

I could share my version of *.mo files compilation process:

import glob
import pathlib
import subprocess
(...)

PO_FILES = 'translations/locale/*/LC_MESSAGES/app_name.po'

def create_mo_files():
    mo_files = []
    prefix = 'app_name'

    for po_path in glob.glob(str(pathlib.Path(prefix) / PO_FILES)):
        mo = pathlib.Path(po_path.replace('.po', '.mo'))

        subprocess.run(['msgfmt', '-o', str(mo), po_path], check=True)
        mo_files.append(str(mo.relative_to(prefix)))

    return mo_files
(...)

setup(
    (...)
    package_data = {
        'app_name': [
            (...)
        ] + create_mo_files(),
    },
)

@edit Comment:

For example pl translation file:

app_name/translations/locale/pl/LC_MESSAGES/app_name.po

function create_mo_files() creates compiled app_name.mo file

app_name/translations/locale/pl/LC_MESSAGES/app_name.mo

and then on package build this app_name.mo file is copying to

package/translations/locale/pl/LC_MESSAGES/app_name.po

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM