Week 1: Disappearing Text

We had a case where we wanted to replace some static text in a template with some text that changed depending on who was logged in. Textbook webdev 101 stuff. We added a property on the relevant model to return the correct phrase, we made sure that the model was accessible from something in the context, replaced the text in the template with a reference to this in some {{ curly brackets }} … and we came up with nothing. Or it showed up in some cases but not in other cases where we applied the |title filter.

There's no indication of why that reference is coming up blank, as django silently replaces unrecognized references with empty strings (a design decision I vehiminently disagree with, although there's some relief available).

After spinning our wheels for a bit, we realized that the places it wasn't working were inside {% blocktrans %} blocks. And while blocktrans allows simple placeholders, to translate a template expression — say, accessing object attributes or using template filters — you need to bind the expression to a local variable for use within the translation block.

Using the blocktrans with form as described in the documentation ended up working just fine, but our localization expert told us to use this approach with care. Replacing a single word in a sentence may have other effects on the sentence structure, e.g. gendered nouns may require different articles, and while blocktrans has a stanza for dealing with pluralization, it doesn't have any parameters for gender.

Now we know how to use variables within blocktrans, but how might we have come to realize our error earlier? Does the aforementioned trick with raising an exception from TEMPLATE_​STRING_​IF_INVALID work inside blocktrans? Not exactly.

Up through Django 1.5, blocktrans was entirely unaware of TEMPLATE_​STRING_​IF_INVALID, so regardless of what you set your IF_INVALID string to, you wouldn't see it show up in your rendered template. This is somewhat fixed for Django 1.6 (thank you nessita, matíasb, and ramiro), but it's not treated as a format string. So it'll now show up inside blocktrans blocks, but if you put a %s in there hoping to see what the invalid input was, you'll be disappointed and find a literal %s in the output. And since it's never used as a format string, that hack of raising TemplateSyntaxError when it's formatted never gets triggered.

Let's call that ticket #21417.

That's just one of the things I learned about Django this week. More stories coming soon!