Source code for kiwi.i18n.i18n

#
# 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)