Permalink
Browse files

Move from Zamboni -> Tower

  • Loading branch information...
0 parents commit 4b13a0095b456baf9549c00f4c262eb13bb17311 @clouserw clouserw committed Mar 8, 2010
@@ -0,0 +1,28 @@
+=====
+Tower
+=====
+
+Tower provides some additional functionality to Jinja and it's i18n extension,
+and the Babel library. Specifics:
+
+- Pulls strings from a variety of sources: Python, JavaScript, and .lhtml files.
+- Collapses whitespace in all strings to prevent unwieldy msgids.
+- Supports Gettext context (msgctxt) in all gettext, and ngettext calls.
+- Supports merging PHP and Python .pot files. This is temporary. If you want
+ to support that for an extended time look at phppo2pypo in the `Translate Toolkit
+ <http://translate.sourceforge.net/>`_.
+
+
+Requirements
+------------
+
+Look at requirements.txt.
+
+
+Installation
+------------
+
+`github <http://github.com/clouserw/tower>`_::
+
+ pip install -e git://github.com/clouserw/tower.git#egg=tower
+
No changes.
@@ -0,0 +1,27 @@
+import os
+
+TEST_RUNNER = 'django_nose.runner.NoseTestSuiteRunner'
+
+ROOT = os.path.dirname(os.path.abspath(__file__))
+path = lambda *a: os.path.join(ROOT, *a)
+
+DATABASES = {
+ 'default': {
+ 'NAME': 'test.db',
+ 'ENGINE': 'django.db.backends.sqlite3',
+ }
+}
+
+INSTALLED_APPS = (
+ 'django_nose',
+)
+
+def JINJA_CONFIG():
+ import jinja2
+ from django.conf import settings
+ config = {'extensions': ['l10n.template.i18n',
+ 'jinja2.ext.with_', 'jinja2.ext.loopcontrols'],
+ 'finalize': lambda x: x if x is not None else ''}
+ return config
+
+DOMAIN_METHODS = { }
@@ -0,0 +1,26 @@
+"""
+Creating standalone Django apps is a PITA because you're not in a project, so
+you don't have a settings.py file. I can never remember to define
+DJANGO_SETTINGS_MODULE, so I run these commands which get the right env
+automatically.
+"""
+import functools
+import os
+
+from fabric.api import local, cd, env
+from fabric.contrib.project import rsync_project
+
+NAME = os.path.basename(os.path.dirname(__file__))
+ROOT = os.path.abspath(os.path.dirname(__file__))
+
+os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % NAME
+os.environ['PYTHONPATH'] = os.pathsep.join([ROOT,
+ os.path.join(ROOT, 'examples')])
+
+env.hosts = ['localhost']
+
+local = functools.partial(local, capture=False)
+
+
+def test():
+ local('django-admin.py test')
@@ -0,0 +1,130 @@
+import gettext
+import re
+
+from django.conf import settings
+from django.utils.functional import lazy
+from django.utils.importlib import import_module
+from django.utils.thread_support import currentThread
+from django.utils.translation import (trans_real as django_trans,
+ ugettext as django_ugettext,
+ ungettext as django_nugettext)
+
+
+def ugettext(message, context=None):
+ """Always return a stripped string, localized if possible"""
+ stripped = strip_whitespace(message)
+
+ message = add_context(context, stripped) if context else stripped
+
+ ret = django_ugettext(message)
+
+ # If the context isn't found, we need to return the string without it
+ return stripped if ret == message else ret
+
+
+def ungettext(singular, plural, number, context=None):
+ """Always return a stripped string, localized if possible"""
+ singular_stripped = strip_whitespace(singular)
+ plural_stripped = strip_whitespace(plural)
+
+ if context:
+ singular = add_context(context, singular_stripped)
+ plural = add_context(context, plural_stripped)
+ else:
+ singular = singular_stripped
+ plural = plural_stripped
+
+ ret = django_nugettext(singular, plural, number)
+
+ # If the context isn't found, the string is returned as it came
+ if ret == singular:
+ return singular_stripped
+ elif ret == plural:
+ return plural_stripped
+ return ret
+
+ugettext_lazy = lazy(ugettext, unicode)
+ungettext_lazy = lazy(ungettext, unicode)
+
+
+def add_context(context, message):
+ # \x04 is a magic gettext number.
+ return u"%s\x04%s" % (context, message)
+
+
+def split_context(message):
+ # \x04 is a magic gettext number.
+ ret = message.split(u"\x04")
+ if len(ret) == 1:
+ ret.insert(0, "")
+ return ret
+
+
+def strip_whitespace(message):
+ return re.compile(r'\s+', re.UNICODE).sub(' ', message).strip()
+
+
+def activate(locale):
+ """
+ Override django's utils.translation.activate(). Django forces files
+ to be named django.mo (http://code.djangoproject.com/ticket/6376). Since
+ that's dumb and we want to be able to load different files depending on
+ what part of the site the user is in, we'll make our own function here.
+ """
+
+ class Translation(object):
+ """
+ We pass this object to jinja so it can find our gettext implementation.
+ If we pass the GNUTranslation object directly, it won't have our
+ context and whitespace stripping action.
+ """
+ ugettext = staticmethod(ugettext)
+ ungettext = staticmethod(ungettext)
+
+ import jingo
+ jingo.env.install_gettext_translations(Translation)
+
+ django_trans._active[currentThread()] = _activate(locale)
+
+
+def _activate(locale):
+ # XXX TODO: When it comes time to load .mo files on the fly and merge
+ # them, this is the place to do it. We'll also need to implement our own
+ # caching since the _translations stuff is built on a per locale basis,
+ # not per locale + some key
+
+ # Django caches the translation objects here
+ t = django_trans._translations.get(locale, None)
+ if t is not None:
+ return t
+
+ # Django's activate() simply calls translation() and adds it to a global.
+ # We'll do the same here, first calling django's translation() so it can
+ # do everything it needs to do, and then calling gettext directly to
+ # load the rest.
+ t = django_trans.translation(locale)
+ try:
+ """When trying to load css, js, and images through the Django server
+ gettext() throws an exception saying it can't find the .mo files. I
+ suspect this has something to do with Django trying not to load
+ extra stuff for requests that won't need it. I do know that I don't
+ want to try to debug it. This is what Django does in their function
+ also.
+ """
+ #If you've got extra .mo files to load, this is the place.
+ path = import_module(settings.SETTINGS_MODULE).path
+ bonus = gettext.translation('messages', path('locale'), [locale],
+ django_trans.DjangoTranslation)
+ t.merge(bonus)
+ except IOError:
+ pass
+
+ return t
+
+
+def deactivate_all():
+ """ Override django's utils.translation.deactivate_all(). Django continues
+ to cache a catalog even if you call their deactivate_all().
+ """
+ django_trans.deactivate_all()
+ django_trans._translations = {}
No changes.
No changes.
@@ -0,0 +1,84 @@
+import os
+import sys
+from subprocess import Popen
+from tempfile import TemporaryFile
+
+from django.core.management.base import BaseCommand
+
+from manage import settings
+
+from translate.tools import pypo2phppo
+
+
+class Command(BaseCommand):
+ """
+ This will merge zamboni strings into the current remora messages.po file
+ in the PHP format. This is not for the faint of heart.
+ """
+
+ def handle(self, *args, **options):
+
+ locale_dir = os.path.join(settings.ROOT, 'locale')
+
+ z_keys = os.path.join(locale_dir, 'z-keys.pot')
+ r_keys = os.path.join(locale_dir, 'r-keys.pot')
+
+ if not os.path.isfile(z_keys) or not os.path.isfile(r_keys):
+ sys.exit("Can't find .pot files")
+
+ # Step 1: Convert the zamboni .pot file to php format
+ z_keys_file = open(z_keys)
+ z_keys_python = TemporaryFile('w+t')
+
+ if not pypo2phppo.convertpy2php(z_keys_file, z_keys_python):
+ sys.exit(" Something is broken in (%s)" % z_keys_python)
+
+ z_keys_file.close()
+
+ merged = TemporaryFile('w+t')
+
+ # Step 2: Merge the remora and zamboni .pot files together
+ z_keys_python.seek(0)
+ p1 = Popen(["msgcat", r_keys, "-"], stdin=z_keys_python,
+ stdout=merged)
+
+ # Wait for process to terminate
+ p1.communicate()
+
+ for locale in os.listdir(locale_dir):
+ if (not os.path.isdir(os.path.join(locale_dir, locale)) or
+ locale.startswith('.')):
+ continue
+
+ r_messages = os.path.join(locale_dir, locale, 'LC_MESSAGES',
+ 'messages.po')
+
+ if not os.path.isfile(r_messages):
+ print " Can't find (%s). Skipping..." % (r_messages)
+ continue
+
+ print "Mushing python strings into messages.po for %s" % (locale)
+
+ # Step 3: Merge our new combined .pot with the .po file
+ if locale == "en_US":
+ merged.seek(0)
+ enmerged = TemporaryFile('w+t')
+ p3 = Popen(["msgen", "-"], stdin=merged, stdout=enmerged)
+ p3.communicate()
+ mergeme = enmerged
+ else:
+ mergeme = merged
+
+ mergeme.seek(0)
+ p2 = Popen(["msgmerge",
+ "--update",
+ "--no-fuzzy-matching",
+ "--sort-output",
+ "--width=200",
+ r_messages,
+ "-"],
+ stdin=mergeme)
+
+ p2.communicate()
+
+ print "finished"
Oops, something went wrong.

0 comments on commit 4b13a00

Please sign in to comment.