About this project

Why Puente?

Puente is a derivative of Tower, but with a slightly different scope and a different purpose. Our goals are as follows:

  1. Ease translation issues.
  2. Correctly support Jinja2 templates.
  3. Be as close to vanilla Django as possible.

Ideally, we want to move closer to vanilla Django over time. The best-case scenario is that no one is using Puente in a couple of years. To get there, we need to adjust Puente so that it’s closer to vanilla Django and also fix things upstream to meet the needs we have that aren’t currently being met.

So, why start a new project instead of continue Tower? Tower is pretty tied to Jingo and it does a few things I don’t want to do anymore. I think this is enough of a difference that if I took over Tower and then marched it into my ideal future, users of Tower would get annoyed and I’d hit a lot of friction. With a library like this where it’s pretty small in scope, it seemed way easier to break with the past, take the interesting parts and start anew.

Why not just use Babel?

Puente does three nice things:

  1. makes it easy to migrate from Tower to something you can use with Django 1.8
  2. collapses whitespace in Jinja2 trans blocks
  3. adds pgettext and npgettext to template environment that work like Jinja2’s newstyle gettext
  4. pulls bits from Django settings to configure extraction (e.g. Jinja2 extensions)

If you don’t care about any of those things, go use Babel’s pybabel command and Jinja2’s i18n extension–don’t use Puente.

What’s different between Tower and Puente?

  1. Tower defaults to messages and javascript, but Puente defaults to django and djangojs.

    Django’s makemessages command supports django and djangojs domains which create django.po(t) and djangojs.po(t) files so that’s what we support with Puente, too.

    As far as I can tell, this won’t be a problem for most situations. However, there is one situation where this makes things difficult. If you had parts of the site that need to be fully translated and other parts that need to be translated, but if it’s not translated, it’s not a big deal, then this makes that difficult.

    That’s on the list of things to mull over how to deal with.

  2. Tower collapses whitespace for all extracted strings, but Puente only collapses whitespace for Jinja2 trans blocks.

    Django has a blocktrans tag which since Django 1.7 has had a trimmed flag indicating that whitespace should be collapsed. Jinja2 has no such thing, but I wrote up an issue for it:


    If that got implemented, then we could drop the tweaks we do to the trans block and use vanilla Jinja2 trans block.

    I think it’s important to collapse whitespace in trans blocks because they’re the most susceptible to msgid changes merely because of adjustments to indentation of the HTML template. That stinks because translators have to go through and fix all the translations.

  3. Tower had a bunch of code to support msgctxt in extraction and gettext calls, but Puente relies on Django’s pgettext functions and Babel’s msgctxt support and that works super… except in Jinja2 templates. Puente adds pgettext and npgettext to the template environment and they work just like Jinja2’s newstyle gettext.

  4. Tower had its own gettext and ngettext that marked output as safe, but Puente drops that because it’s unneeded if you’re using Jinja2’s newstyle gettext and autoescape enabled.

  5. Tower used translate-toolkit to build the .pot file, but Puente uses Babel for putting together the .pot file. Thus we don’t need translate-toolkit anymore.

  6. Tower required Jingo, but Puente supports Jingo, django-jinja and other Jinja2 template environments.

  7. Tower only supports Django 1.7 and lower versions and Puente only supports Django 1.7+.

  8. Tower supports Python 2.6 and 2.7, but Puente supports 2.7. Hopefully Python 3 in the near future.

  9. Tower has most of the code in __init__.py, but Puente tries to be easier to use so you can import it without problems.

  10. Tower uses nose for tests, but Puente uses py.test.

    This is purely because I stopped using nose on my projects. Generally, I find py.test easier to set up and use these days. I don’t want to change this unless there’s a compelling reason. Generally, if you were maintaining the project, I’d encourage you to use whichever test framework works best for you.

Current status of phasing Puente out

The best future for Puente is that it gets phased out because it’s not needed anymore.

We need to do the following before we can end Puente:

  1. DONE!: Jinja2 needs to collapse whitespace in the trans tag


  2. IN PROGRESS: Jinja2 needs to support pgettext/npgettext in templates.


  3. DONE!: django-babel needs to support “trimmed” in django templates.


  4. Puente’s extract command should work more like Babel’s pybabel extract command.

    The way forward is to phase Puente out for pybabel. In order to make that work well, we should mimic pybabel’s extract command more closely.

    This should probably be broken up into more steps as we discover differences.

  5. Ditch Puente’s merge for pybabel’s update?

  6. Need a nice way to use Django settings for pybabel configuration. For example, I’d rather not have to define the list of Jinja2 extensions to use in two places.

  7. Is there anything else?