Is there a portable way to provide localization of a package distributed on PyPI?
EDIT 7/12/2018:
After some work, I could build a specific package based on what is below in this answer. It can be used from other projects to automatically compile po files at build time through the magic of setuptools enty_points. It is now available on GitHUB (https://github.com/s-ball/mo_installer) and distributed on PyPI (https://pypi.org/project/mo_installer)
The researches that I did before asking the question gave me enough hints to reach a possible solution.
I can now say, thay is is possible to include a platform specific mo file in a wheel - unfortunately in my current solution the wheel gives no indication that it is platform specific. But the same solution allows to build a source distribution that build the mo file on the target platform.
Now for the details:
the tools needed to compile a mo file on the target:
Most solutions picked from Google or SO rely either on Babel or on the GNU gettext
msgfmt
program. But cPython tools include a pure Python modulemsgfmt.py
that is enough here. Unfortunately, this tool is often not installed by default in many Linux/Unix-like. My solution just includes a copy of that module (a mere 7k file) for 3.7.1 version. It looks like a very stable code (few changes in recent years) and it should work for any Python >= 3.3the setuptools integration
The magic of setuptools is that the same build subcommand is internally used to build a binary wheel, to install with pip from a source package or to directly install with
python setup.py install
from a copy (git clone) of the full source package. So I provide abuild
subclass insetup.py
that generates the .mo files with their full path before calling the superclass method. I also use aMANIFEST.in
file to list the files that should be copied in a source distribution and apackage_data
setup argument to list what should go in a binary package or installation folderrun time usage
Provided the mo hierarchy to be installed under a knows package,
os.dirname(__file__)
called from a module of that package gives its parent folder
Code (assuming the msgfmt.py
file is copied under a tools_i18n
folder and that po files are under a src
folder):
in 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},
)
In MANIFEST.in
:
...
include src/*
include tools_i18n/*
To use the translations at run time:
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)
A full project using this method is available at https://github.com/s-ball/i18nparse
Last but not least, after a more in depth reading of the GNU gettext doc, I can say that gettext can process mo files whatever their endianness:
MO files of any endianness can be used on any platform. When a MO file has an endianness other than the platform’s one, the 32-bit numbers from the MO file are swapped at runtime. The performance impact is negligible.
How do I find the location of Python module sources?
For a pure python module you can find the source by looking at themodule.__file__
.
The datetime module, however, is written in C, and therefore datetime.__file__
points to a .so file (there is no datetime.__file__
on Windows), and therefore, you can't see the source.
If you download a python source tarball and extract it, the modules' code can be found in the Modules subdirectory.
For example, if you want to find the datetime code for python 2.6, you can look at
Python-2.6/Modules/datetimemodule.c
You can also find the latest version of this file on github on the web at
https://github.com/python/cpython/blob/main/Modules/_datetimemodule.c
Where does pip install its packages?
pip when used with virtualenv will generally install packages in the path <virtualenv_name>/lib/<python_ver>/site-packages
.
For example, I created a test virtualenv named venv_test with Python 2.7, and the django
folder is in venv_test/lib/python2.7/site-packages/django
.
What is the correct way to set Python's locale on Windows?
It seems you're using Windows. The locale strings are different there. Take a more precise look at the doc:
locale.setlocale(locale.LC_ALL, 'de_DE') # use German locale; name might vary with platform
On Windows, I think it would be something like:
locale.setlocale(locale.LC_ALL, 'deu_deu')
MSDN has a list of language strings and of country/region strings
What is the best way to internationalize a Python app with multiple i18n domains?
how about you bind _ to a function roughly like this (for each module):
def _(message):
return my_gettext(__name__, message)
This allows you to use gettext while at the same time perform any lookup on a per-module-per-call-base that allows you to switch locale as well.
Related Topics
Running a Bash Script from Python
Magicexception:File 5.41 Supports Only Version 16 Magic File, Magic.Mgc Is Version 14
Visibility of Global Variables in Imported Modules
What Are the Risks of Running 'Sudo Pip'
Setting Y-Axis Limit in Matplotlib
Read Specific Columns from a CSV File with CSV Module
Why Is Button Parameter "Command" Executed When Declared
How to Use String.Replace() in Python 3.X
How to Catch and Print the Full Exception Traceback Without Halting/Exiting the Program
How to Use Python Requests to Fake a Browser Visit A.K.A and Generate User Agent
Python Multiprocessing + Subprocess Issues
Module Not Found After Building Python Project by Using Pysinstaller
Instance Variables VS. Class Variables in Python
Apply Function to Each Element of a List
Plotting Time in Python with Matplotlib
What's the Difference Between Globals(), Locals(), and Vars()
Pip Install MySQL-Python Fails with Environmenterror: MySQL_Config Not Found