#!/usr/bin/env python # Need to ensure that the i18n framework is enabled from django.conf import settings settings.configure(USE_I18N = True) from django.utils.translation import templatize import re import os import sys import getopt from itertools import dropwhile from tempfile import mkdtemp from shutil import rmtree pythonize_re = re.compile(r'\n\s*//') msgfmt_re = re.compile(r'((?P\d+) translated messages?)?((, )?(?P\d+) fuzzy translations?)?((, )?(?P\d+) untranslated messages?)?\.') def calculate_stats(): localedir = None if os.path.isdir(os.path.join('conf', 'locale')): #localedir = os.path.abspath(os.path.join('conf', 'locale')) localedir = os.path.join('conf', 'locale') elif os.path.isdir('locale'): #localedir = os.path.abspath('locale') localedir = 'locale' else: print "This script should be run from the django svn tree or your project or app tree." print "If you did indeed run it from the svn checkout or your project or application," print "maybe you are just missing the conf/locale (in the django tree) or locale (for project" print "and application) directory?." sys.exit(1) (opts, args) = getopt.getopt(sys.argv[1:], 'l:d:va') lang = None domain = 'django' verbose = False all = False for o, v in opts: if o == '-l': lang = v elif o == '-d': domain = v elif o == '-v': verbose = True elif o == '-a': all = True if domain not in ('django', 'djangojs'): print "currently l10n-stats.py only supports domains 'django' and 'djangojs'" sys.exit(1) if (lang is None and not all) or domain is None: print "usage: l10n-stats.py -l " print " or: l10n-stats.py -a" sys.exit(1) languages = [] if lang is not None: languages.append(lang) elif all: languages = [el for el in os.listdir(localedir) if not el.startswith('.')] if not languages: sys.exit(0) workdir = mkdtemp() potfile = os.path.join(workdir, '%s.pot' % domain) if os.path.exists(potfile): os.unlink(potfile) for (dirpath, dirnames, filenames) in os.walk("."): for file in filenames: if domain == 'djangojs' and file.endswith('.js'): if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) data = open(os.path.join(dirpath, file), "rb").read() data = pythonize_re.sub('\n#', data) thefile = '%s.py' % file open(os.path.join(dirpath, thefile), "wb").write(data) cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % ( os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile)) (stdin, stdout, stderr) = os.popen3(cmd, 't') msgs = stdout.read() errors = stderr.read() if errors: sys.stderr.write('errors happened while running xgettext on %s\n' % file) sys.stderr.write(errors) rmtree(workdir, True) sys.exit(8) if msgs: open(potfile, 'ab').write(msgs) os.unlink(os.path.join(dirpath, thefile)) elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')): thefile = file litfile = os.path.join(dirpath, file) if file.endswith('.html'): data = open(litfile, "rb").read() thefile = '%s.py' % file litdir = os.path.join(workdir, dirpath) if not os.path.isdir(litdir): os.makedirs(litdir) litfile = os.path.join(litdir, thefile) open(litfile, "wb").write(templatize(data)) if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % ( domain, litfile) (stdin, stdout, stderr) = os.popen3(cmd, 't') msgs = stdout.read() errors = stderr.read() if errors: sys.stderr.write('errors happened while running xgettext on %s\n' % file) sys.stderr.write(errors) rmtree(workdir, True) sys.exit(8) if os.path.exists(potfile): # Strip the header msgs = '\n'.join(dropwhile(len, msgs.split('\n'))) else: msgs = msgs.replace('charset=CHARSET', 'charset=UTF-8') if msgs: open(potfile, 'ab').write(msgs) if os.path.exists(potfile): (stdin, stdout, stderr) = os.popen3('msguniq --to-code=utf-8 "%s"' % potfile, 'b') pot_msgs = stdout.read() errors = stderr.read() if errors: sys.stderr.write('errors happened while running msguniqi\n') sys.stderr.write(errors) rmtree(workdir, True) sys.exit(8) open(potfile, 'w').write(pot_msgs) else: sys.exit(0) for lang in languages: basedir = os.path.join(localedir, lang, 'LC_MESSAGES') if not os.path.isdir(basedir): continue dstdir = os.path.join(workdir, basedir) if not os.path.isdir(dstdir): os.makedirs(dstdir) pofile = os.path.join(basedir, '%s.po' % domain) dstfile = os.path.join(dstdir, '%s.po' % domain) if os.path.exists(pofile): (stdin, stdout, stderr) = os.popen3('msgmerge -q "%s" "%s"' % (pofile, potfile), 'b') msgs = stdout.read() errors = stderr.read() if errors: sys.stderr.write('errors happened while running msgmerge\n') sys.stderr.write(errors) rmtree(workdir, True) sys.exit(8) open(dstfile, 'wb').write(msgs) else: open(dstfile, 'wb').write(pot_msgs) (stdin, stdout, stderr) = os.popen3('LC_ALL=C msgfmt --statistics -o - "%s"' % dstfile, 't') dummy = stdout.read() data = stderr.read() mo = msgfmt_re.match(data) if mo: groups = mo.groupdict('0') transl = int(groups['transl']) fuzzy = int(groups['fuzzy']) untransl = int(groups['untransl']) total = transl + fuzzy + untransl print("%s: translated: %d%%, fuzzy: %d%%, untranslated: %d%%" % (lang, transl*100/total, fuzzy*100/total, untransl*100/total)) #os.unlink(potfile) #os.rmdir(workdir) rmtree(workdir, True) if __name__ == "__main__": calculate_stats()