# Find files for getting translatable strings, update the reference pot,
# merge the pot files and compile them.
#
# Written by Guilherme Polo <ggpolo@gmail.com>
import os
import sys
import warnings
import subprocess
# You may change these to point to the paths where your tools live
XGETTEXT = {'xgettext': 'pygettext'}
MSGMERGE = {'msgmerge': 'msgmerge'}
MSGFMT = {'msgfmt': 'msgfmt'}
def call_tool(tool, *args, **kwargs):
gnu_tool, module = tool.items()[0]
try:
# Check for gnu_tool existence. If the program exists it is likely
# that it will emit an error like "no input files given" to stderr,
# so we ignore that.
subprocess.call([gnu_tool], stderr=subprocess.PIPE)
except OSError, err:
if err.errno != 2:
raise
else:
if module not in sys.modules:
warnings.warn("The GNU tool %s is not available, using a "
"Python implementation (%s) as fallback." % (
gnu_tool, module))
# XXX for now I'm assuming the fallback modules are living
# in the same place as this module and that on some builds
# (see generate_windows_package for instance) the path
# may not be on sys.path
if os.path.dirname(__file__) not in sys.path:
sys.path.append(os.path.dirname(__file__))
__import__(module)
tool = sys.modules[module]
tool.main(args)
else:
args = (gnu_tool, ) + args
if kwargs.get('single_arg'):
del kwargs['single_arg']
args = ' '.join(args)
subprocess.check_call(args, **kwargs)
class POTManager(object):
def __init__(self, python_pkgs_root, *exclude_dirs):
"""
python_pkgs_root - The starting directory to look for python
packages to collect translatable messages.
exclude_dirs - Directory names to discard when looking
for packages.
"""
self.python_pkgs_root = python_pkgs_root
self.exclude_dirs = exclude_dirs
def find_packages(self):
root = self.python_pkgs_root
for dirpath, dirnames, filenames in os.walk(root):
for name in list(dirnames):
if name in self.exclude_dirs:
dirnames.remove(name)
if '__init__.py' in filenames:
# This directory is a package, will run xgettext here
yield dirpath
def update_refpot(self, output):
"""Update the reference pot file and return the path of the
new ref pot file."""
args = ['-L', 'Python', '-o', output]
root = self.python_pkgs_root
for dirname in self.find_packages():
relative_path = dirname[len(root) + len(os.path.sep):]
args.append(os.path.join(relative_path, "*.py"))
# XXX is xgettext too weird or what ? we need to use single_arg for
# the gnu one.
call_tool(XGETTEXT, shell=True, single_arg=True, *args)
return output
def update_pots(self, refpot, locale_dir):
"""Traverse locale_dir looking for .po files only inside
subdirectories and merge each of them with the reference pot file."""
for pot in self._find_pots(locale_dir):
# merge pots
print "Merging %r" % pot
call_tool(MSGMERGE, '-U', pot, refpot)
def compile(self, locale_dir, use_fuzzy=True, verbose=False,
do_checks=True, statistics=False, appname='umit',
mo_dir='LC_MESSAGES', distutils_log=None, create_dirs=False):
"""Traverse locale_dir looking for .po files only inside
subdirectories and compile them to .mo files."""
extra_opts = []
if use_fuzzy:
extra_opts.append('-f')
if verbose:
extra_opts.append('-v')
if do_checks:
extra_opts.append('-c')
if statistics:
extra_opts.append('--statistics')
for pot in self._find_pots(locale_dir):
potdir = os.path.dirname(pot)
mo_path = os.path.join(potdir, mo_dir, "%s.mo" % appname)
if not os.path.exists(os.path.dirname(mo_path)) and create_dirs:
os.makedirs(os.path.dirname(mo_path))
# compile pot
if verbose:
print "Compiling %r to %r" % (pot, mo_path)
if distutils_log is not None:
distutils_log("Compiling %r to %r" % (pot, mo_path))
opts = extra_opts + ['-o', mo_path, pot]
call_tool(MSGFMT, *opts)
def _find_pots(self, basedir):
"""Find pot files just in the way that the methods compile and
update_pots expect."""
for name in os.listdir(basedir):
namepath = os.path.join(basedir, name)
if not os.path.isdir(namepath) or name[0] == '.':
continue
for name in os.listdir(namepath):
if name.endswith('.po'):
yield os.path.join(namepath, name)
# Each directory is supposed to contain a single pot file
break
if __name__ == "__main__":
import sys
potgen = POTManager(os.getcwd(),
'higwidgets', 'source-plugins', 'utils', 'tests')
locale_dir = os.path.join(os.getcwd(), 'share', 'locale')
refpot = potgen.update_refpot(output=os.path.join(locale_dir, 'umit.pot'))
potgen.update_pots(refpot, locale_dir=locale_dir)
if '-compile' in sys.argv:
potgen.compile(locale_dir)
|