#
# Kiwi: a Framework and Enhanced Widgets for Python
#
# Copyright (C) 2005 Async Open Source
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
"""Internationalization utilities. Requires intltool and gettext"""
from distutils.dep_util import newer
from distutils.filelist import FileList, findall
from optparse import OptionParser
import os
from shutil import copyfile
from kiwi.dist import listfiles
# This is a template, used to generate a list of translatable file
# which intltool can understand.
# It reuses the syntax from distutils MANIFEST files, a POTFILES.in
# will be generate from it, see update_po()
POTFILES = 'POTFILES.list'
[docs]def check_directory(root):
po_dir = os.path.join(root, 'po')
if not os.path.exists(po_dir):
raise SystemExit("A 'po` directory must exist")
if not os.path.isdir(po_dir):
raise SystemExit("po must be a directory")
locale_dir = os.path.join(root, 'locale')
if os.path.exists(locale_dir):
if not os.path.isdir(po_dir):
raise SystemExit("locale must be a directory")
[docs]def check_pot_file(root, package):
pot_file = os.path.join(root, 'po', '%s.pot' % package)
if not os.path.exists(pot_file):
raise SystemExit("Need a pot file, run --update first")
return pot_file
[docs]def get_translatable_files(root):
pofiles = os.path.join(root, 'po', POTFILES)
if not os.path.exists(pofiles):
print 'Warning: Could not find %s' % pofiles
return []
filelist = FileList()
fp = open(pofiles)
for line in fp.readlines():
filelist.process_template_line(line)
return sorted(filelist.files)
[docs]def list_languages(root):
return [os.path.basename(po_file[:-3])
for po_file in listfiles(root, 'po', '*.po')]
[docs]def update_po(root, package):
update_pot(root, package)
old = os.getcwd()
os.chdir(os.path.join(root, 'po'))
for lang in list_languages(root):
new = lang + '.new.po'
cmd = ('intltool-update --dist --gettext-package=%s '
'-o %s %s > /dev/null' % (package, new, lang))
os.system(cmd)
if not os.path.exists(new):
raise SystemExit("ERROR: intltool failed, see above")
os.rename(new, lang + '.po')
os.chdir(old)
[docs]def update_pot(root, package):
files = get_translatable_files(root)
potfiles_in = os.path.join(root, 'po', 'POTFILES.in')
if os.path.exists(potfiles_in):
os.unlink(potfiles_in)
rml_files = _extract_rml_files(root)
fd = open(potfiles_in, 'w')
for filename in files + rml_files:
# FIXME: workaround for bug
# https://bugzilla.redhat.com/show_bug.cgi?id=504483
if filename.endswith('.ui'):
filename = '[type: gettext/glade]' + filename
fd.write(filename + '\n')
fd.close()
old = os.getcwd()
os.chdir(os.path.join(root, 'po'))
if os.system('intltool-update 2> /dev/null > /dev/null') != 0:
raise SystemExit('ERROR: intltool-update could not be found')
# POT file first
res = os.system('intltool-update --pot --gettext-package=%s' % package)
if res != 0:
raise SystemExit("ERROR: failed to generate pot file")
os.chdir(old)
for f in rml_files:
os.unlink(f)
os.unlink(potfiles_in)
def _clean_rml(data):
fixed = ''
while data:
start_pos = data.find('<%')
if start_pos == -1:
break
fixed += data[:start_pos]
data = data[start_pos:]
end_pos = data.find('%>')
if end_pos == -1:
end_pos = data.find('/>')
assert end_pos != -1
data = data[end_pos+2:]
return fixed
def _extract_rml_files(root):
files = []
for rml_file in sorted(findall(root)):
if not rml_file.endswith('.rml'):
continue
data = open(rml_file).read()
data = _clean_rml(data)
if not len(data):
continue
extracted = rml_file + '.extracted'
if os.path.exists(extracted):
os.unlink(extracted)
open(extracted, 'w').write(data)
extracted = extracted[len(root)+1:]
cmd = 'intltool-extract -q --type=gettext/xml %s' % extracted
res = os.system(cmd)
if res != 0:
raise SystemExit("ERROR: failed to generate pot file")
os.unlink(extracted)
files.append(extracted + '.h')
return files
[docs]def compile_po_files(root, package):
if os.system('msgfmt 2> /dev/null') != 256:
print 'msgfmt could not be found, disabling translations'
return
mo_file = package + '.mo'
for po_file in listfiles(root, 'po', '*.po'):
lang = os.path.basename(po_file[:-3])
mo = os.path.join(root, 'locale', lang, 'LC_MESSAGES', mo_file)
if not os.path.exists(mo) or newer(po_file, mo):
directory = os.path.dirname(mo)
if not os.path.exists(directory):
os.makedirs(directory)
os.system('msgfmt %s -o %s' % (po_file, mo))
[docs]def main(args):
parser = OptionParser()
parser.add_option('-a', '--add',
action="store", type="string",
dest="lang",
help="Add a new language")
parser.add_option('-l', '--list',
action="store_true",
dest="list",
help="List all supported languages")
parser.add_option('-u', '--update',
action="store_true",
dest="update",
help="Update pot file and all po files")
parser.add_option('-t', '--update-pot',
action="store_true",
dest="update_pot",
help="Update pot file")
parser.add_option('-c', '--compile',
action="store_true",
dest="compile",
help="Compile all .po files into .mo")
parser.add_option('-p', '--package',
action="store", type="string",
dest="package",
help="Package name")
options, args = parser.parse_args(args)
root = os.getcwd()
check_directory(root)
if options.package:
package = options.package
else:
package = os.path.split(root)[1]
if options.lang:
pot_file = check_pot_file(root, package)
copyfile(pot_file, os.path.join(root, 'po', options.lang + '.po'))
return
elif options.list:
for lang in list_languages(root):
print lang
return
if options.update:
update_po(root, package)
if options.update_pot:
update_pot(root, package)
if options.compile:
check_pot_file(root, package)
compile_po_files(root, package)