From d7f362301d17a84c8eeb3428b208eca691c49aaa Mon Sep 17 00:00:00 2001 From: Marcin Koziej Date: Wed, 28 Mar 2012 11:49:25 +0200 Subject: [PATCH] localepack command --- .../management/commands/translation2po.py | 84 ++++++---- apps/wolnelektury_core/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../management/commands/localepack.py | 147 ++++++++++++++++++ requirements-dev.txt | 1 + 5 files changed, 206 insertions(+), 26 deletions(-) create mode 100644 apps/wolnelektury_core/management/__init__.py create mode 100644 apps/wolnelektury_core/management/commands/__init__.py create mode 100644 apps/wolnelektury_core/management/commands/localepack.py diff --git a/apps/modeltranslation/management/commands/translation2po.py b/apps/modeltranslation/management/commands/translation2po.py index 9ab8489c6..9cb34deca 100644 --- a/apps/modeltranslation/management/commands/translation2po.py +++ b/apps/modeltranslation/management/commands/translation2po.py @@ -1,4 +1,3 @@ -import polib import os import sys @@ -8,6 +7,7 @@ from django.conf import settings from django.core.management.base import BaseCommand from django.core.management.color import color_style +import polib import modeltranslation.models from modeltranslation.translator import translator, NotRegistered @@ -22,7 +22,7 @@ def metadata(language=''): 'POT-Creation-Date': '%s' % t, 'PO-Revision-Date': '%s' % t, 'Last-Translator': 'you ', - 'Language-Team': '%s ' % language, + 'Language-Team': '%s' % dict(settings.LANGUAGES).get(language, language), 'MIME-Version': '1.0', 'Content-Type': 'text/plain; charset=utf-8', 'Content-Transfer-Encoding': '8bit', @@ -44,39 +44,71 @@ def make_po(language=''): class Command(BaseCommand): option_list = BaseCommand.option_list + ( make_option('-d', '--directory', help='Specify which directory should hold generated PO files', dest='directory'), + make_option('-l', '--load', help='load locales back to source', action='store_true', dest='load', default=False), ) help = 'Export models from app to po files' args = 'app' - def handle(self, appname, **options): - app = __import__(appname) - pofiles = {} + def get_models(self, app): + r = [] for mdname in dir(app.models): if mdname[0] == '_': continue md = getattr(app.models, mdname) try: opts = translator.get_options_for_model(md) + r.append((md, opts)) except NotRegistered: continue + return r + + def handle(self, appname, **options): + app = __import__(appname) + if options['load']: + objects = {} + modmod = {} + for md, opts in self.get_models(app): + if not md.__name__ in objects: + objects[md.__name__] = {} + modmod['model'] = md + + for lng in zip(*settings.LANGUAGES)[0]: + pofile = os.path.join(options['directory'], lng, appname + '.po') + po = polib.pofile(pofile) + for entry in po: + loc, pk = entry.occurrences[0] + _appname, modelname, fieldname = loc.split('/') + try: + obj = objects[modelname][pk] + except KeyError: + obj = modmod['model'].objects.get(pk=pk) + objects[modelname][pk] = obj + setattr(obj, fieldname, entry.msgstr) + + for mod, objcs in objects.items(): + for o in objcs.values(): + o.save() + + else: + pofiles = {} + for md, opts in self.get_models(app): + for obj in md.objects.all().order_by('pk'): + for fld in opts.fields: + for locfld in opts.localized_fieldnames[fld]: + cur_lang = lang(locfld) + try: + po = pofiles[cur_lang] + except: + po = make_po(cur_lang) + pofiles[cur_lang] = po + + entry = polib.POEntry( + msgid=getattr(obj, '%s_%s' % (fld, settings.LANGUAGE_CODE)), + msgstr=getattr(obj, locfld), + occurrences=[('%s/%s/%s' % (appname, md.__name__, locfld), obj.id)]) + po.append(entry) - for obj in md.objects.all().order_by('pk'): - for fld in opts.fields: - for locfld in opts.localized_fieldnames[fld]: - cur_lang = lang(locfld) - try: - po = pofiles[cur_lang] - except: - po = make_po(cur_lang) - pofiles[cur_lang] = po - - entry = polib.POEntry( - msgid=getattr(obj, '%s_%s' % (fld, settings.LANGUAGE_CODE)), - msgstr=getattr(obj, locfld), - occurrences=[('%s/%s/%s' % (appname, mdname, locfld), obj.id)]) - po.append(entry) - - directory = options['directory'] - for lng, po in pofiles.items(): - try: os.makedirs(os.path.join(directory, lng)) - except OSError: pass - po.save(os.path.join(directory, lng, '%s.po' % appname)) + directory = options['directory'] + for lng, po in pofiles.items(): + try: os.makedirs(os.path.join(directory, lng)) + except OSError: pass + po.save(os.path.join(directory, lng, '%s.po' % appname)) diff --git a/apps/wolnelektury_core/management/__init__.py b/apps/wolnelektury_core/management/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/wolnelektury_core/management/commands/__init__.py b/apps/wolnelektury_core/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/wolnelektury_core/management/commands/localepack.py b/apps/wolnelektury_core/management/commands/localepack.py new file mode 100644 index 000000000..813515e8e --- /dev/null +++ b/apps/wolnelektury_core/management/commands/localepack.py @@ -0,0 +1,147 @@ + +from optparse import make_option +from django.conf import settings +from django.core.management.base import BaseCommand +from django.core.management.color import color_style +from django.core.management import call_command + +import os +import shutil +import tempfile + +import allauth + +ROOT = os.path.dirname(settings.PROJECT_DIR) + + +def is_our_app(mod): + return mod.__path__[0].startswith(ROOT) + + +class Locale(object): + def save(self, output_directory, languages): + pass + + def generate(self, languages): + pass + + +class AppLocale(Locale): + def __init__(self, appmod): + self.app = appmod + if not os.path.exists(os.path.join(self.path, 'locale')): + raise LookupError('No locale for app %s' % appmod) + + @property + def path(self): + return self.app.__path__[0] + + @property + def name(self): + return self.app.__name__ + + def save(self, output_directory, languages): + for lc in languages: + lc = lc[0] + if os.path.exists(os.path.join(self.path, 'locale', lc)): + shutil.copy2(os.path.join(self.path, 'locale', lc, 'LC_MESSAGES', 'django.po'), + os.path.join(output_directory, lc, self.name + '.po')) + + def load(self, input_directory, languages): + for lc in zip(*languages)[0]: + shutil.copy2(os.path.join(input_directory, lc, self.name + '.po'), + os.path.join(self.path, 'locale', lc, 'LC_MESSAGES', 'django.po')) + + def generate(self, languages): + os.chdir(self.path) + print "in %s" % os.getcwd() + try: + call_command('makemessages', all=True) + except: + pass + + +class ModelTranslation(Locale): + def __init__(self, appname): + self.appname = appname + + def save(self, output_directory, languages): + call_command('translation2po', self.appname, directory=output_directory) + + def load(self, input_directory, languages): + call_command('translation2po', self.appname, directory=input_directory, load=True) + + +class CustomLocale(Locale): + def __init__(self, app_dir, + config=os.path.join(ROOT, "babel.cfg"), + out_file=os.path.join(ROOT, 'wolnelektury/locale-contrib/django.pot'), + name=None): + self.app_dir = app_dir + self.config = config + self.out_file = out_file + self.name = name + + def generate(self, languages): + os.system('pybabel extract -F "%s" -o "%s" "%s"' % (self.config, self.out_file, self.app_dir)) + os.system('pybabel update -D django -i %s -d %s' % (self.out_file, os.path.dirname(self.out_file))) + + def po_file(self, language): + d = os.path.dirname(self.out_file) + n = os.path.basename(self.out_file).split('.')[0] + return os.path.join(d, language, 'LC_MESSAGES', n + '.po') + + def save(self, output_directory, languages): + for lc in zip(*languages)[0]: + if os.path.exists(self.po_file(lc)): + shutil.copy2(self.po_file(lc), + os.path.join(output_directory, lc, self.name + '.po')) + + def load(self, input_directory, languages): + for lc in zip(*languages)[0]: + shutil.copy2(os.path.join(input_directory, lc, self.name + '.po'), + self.po_file(lc)) + + +SOURCES = [] + +for appn in settings.INSTALLED_APPS: + app = __import__(appn) + if is_our_app(app): + try: + SOURCES.append(AppLocale(app)) + except LookupError, e: + print "no locales in %s" % app + +SOURCES.append(ModelTranslation('infopages')) +SOURCES.append(CustomLocale(os.path.dirname(allauth.__file__), name='contrib')) + + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option('-l', '--load', help='load locales back to source', action='store_true', dest='load', default=False), + make_option('-o', '--outfile', help='Resulting zip file', dest='outfile', default='./wl-locale.zip'), + ) + help = 'Make a locale pack' + args = '' + + def handle(self, *a, **options): + tmp_dir = tempfile.mkdtemp('-wl-locale') + out_dir = os.path.join(tmp_dir, 'wl-locale') + os.mkdir(out_dir) + + try: + for lang in settings.LANGUAGES: + os.mkdir(os.path.join(out_dir, lang[0])) + + for src in SOURCES: + src.generate(settings.LANGUAGES) + src.save(out_dir, settings.LANGUAGES) + # src.save(settings.LANGUAGES) + + packname = options.get('outfile') + packname_b = os.path.basename(packname).split('.')[0] + fmt = '.'.join(os.path.basename(packname).split('.')[1:]) + shutil.make_archive(packname_b, fmt, root_dir=os.path.dirname(out_dir), base_dir=os.path.basename(out_dir)) + finally: + shutil.rmtree(tmp_dir, ignore_errors=True) diff --git a/requirements-dev.txt b/requirements-dev.txt index 60cfab704..59084374e 100755 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,3 @@ django-debug-toolbar polib +BabelDjango -- 2.20.1