Multiple pluralisable variables in internationalized django template - python

I am internationalizing (i18n) our django project, i.e. adding {% blocktrans %} to our templates. I know about using count and {% plural %} to have different strings for varaibles. However I have a string that has two variables that each need to be pluralized, i.e. 4 possible options.
For example, my string is "You have {{ num_unread }} unread message{{ num_unread|pluralize }} out of {{ total }} total message{{ total|pluralize }}"
How would I convert that to blocktrans tags?

After doing some more research and reading, specifically about gettext, I don't think this is possible. gettext documentation only allows one variable to control the pluralization. There are probably problems with having 2 variable pluralization, since in arabic, you'd have to have 36 different strings to translate.
In the end I just worked around my original problem, and split it into two strings.

Related

{% translate s %} passed in {% include ... with s=s %} not in .po file

I have a basic feed I am trying to render in my Django project. I have created a feed.html file as a base template for slight variations of the same type of feed. Among those variations, is the header of the feed. Importantly, I want that header to be translated into multiple languages.
I have implemented this "variation" idea using {% include "feed.html" with variation=variation %}. However, I am having problems translating those variations.
I am trying the following in feed.html:
{% translate header %}
Then in one of the templates where I want a variation of feed.html I have:
{% include "feed.html" with header="Header" %}
The problem is, the string "Header" does not make it into any of my .po files and therefore remains untranslatable.
What am I doing wrong? Should I use different syntax?
The problem is, the string "Header" does not make it into any of my .po files and therefore remains untranslatable.
If that means that the makemessages command doesn't extract the string, then yes, it won't, because there is no string. Only a variable. That variable could take any value at all, makemessages cannot possibly trace that back to all possible locations where you might be setting the value for header. makemessages can only extract what you literally put into {% translate %} tags or _() function calls directly.
The caveat with using variables or computed values, as in the previous two examples, is that Django’s translation-string-detecting utility, django-admin makemessages, won’t be able to find these strings.
https://docs.djangoproject.com/en/3.1/topics/i18n/translation/#standard-translation
You'll want to translate the header value before passing it:
{% include "feed.html" with header=_("Header") %}

Django template "pluralize" filter causes raw text output

I'm going through the Django tutorial right now (https://docs.djangoproject.com/en/3.0/intro/tutorial04/) and encountering this little problem with pluralize.
With this code:
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{
The pluralize filter isn’t doing anything, The template returns something like this:
Just hacking again -- 2 vote{{ votes|pluralize }} // just the template code itself.
as if it was just ignoring the {{ }} indicators.
If I take pluralize out, then the choice.votes variable will display (in this case) a 2, as expected, just like it does with {{ choice.votes }}. The addition of | pluralize seems to break the interpolation, just in that area.
I don't see any sort of import or the like that I need to add; I even copy and pasted to ensure no spelling errors, nor do I see anything in the console.log.
Any insight into what might be (not) happening here?
#Ben provided the start of the solution by suggesting removing spaces, like this:
vote{{ choice.votes|pluralize }} // not quite
That was close. I took out all spaces (which had been added in my auto-formatter because of where my lines split) and this worked:
vote{{choice.votes|pluralize}} // bingo
To me what actually solved this problem was writing all on the same line:
vote{{ choice.votes|pluralize }}
And this worked regardless of the above-mentioned spaces in between.
The code in Django's tutorial (https://docs.djangoproject.com/en/3.2/intro/tutorial04/) shows a line break right after the opening {{, so it can be misleading:
(Screenshot taken in Chrome at 100% zoom. But this line break also shows up until 125%)

Jinja2 - Given 2 templates (as strings) how to render one that extends the other?

I'm making a simple script that works on Jinja2 templates. Right now it's just reading files in from disk manually, i.e. no Jinja Loaders. I have 2 strings (A and B), representing 2 templates. I want to make one template (B) inherit from the other (A), i.e. I have {% block body %}{% endblock %} in A, and I want to make the body block be the contents of B. How can I get the rendered output of this?
Normally I'd use {% extends 'filename' %} in B and it'd use the right one, however I don't have the filename (per se) for A.
Your best bet probably to use a different template loader. Take a look at DictLoader and FunctionLoader, or try your hand a writing your own template loader.

How can I distinguish lists from strings in django templates

I'm developing a project on Google AppEngine, using Django templates, so I have to use tags like {{ aitem.Author }} to print content within my HTML template.
Author, however, can either be a string or a list object, and I have no way to tell it in advance. When the Author is a list and I try to print it on my template, I get the ugly result of
Author: [u'J. K. Rowling', u'Mary GrandPr\xe9']
Is there any way to handle this kind of scenario (basically printing a field differently depending on its type) effectively? Do I have to rely on custom tags or any other means?
I think the cleanest solution would be to add a method to the model get_authors() which always returns a list either of one or more authors. Then you can use:
Author: {{ aitem.get_authors|join:", " }}
If you for some reason have only access to the templates and can't change the model, then you can use a hack like this:
{% if "[" == aitem.Author|pprint|slice:":1" %}
Author: {{ aitem.Author|join:", " }}
{% else %}
Author: {{ aitem.Author }}
{% endif %}
P.S. it's not a good convention to use capital letters for attribute names.
I think that Aidas's get_authors() solution is the best, but an alternative might be to create a template tag that does the test. You'll want to read up on custom template tags, but they aren't that hard to create if you look at the existing ones.
I followed Matthew's advice and eventually implemented a filter to handle lists.
I'm posting it here just in case someone else needs it.
#register.filter(name='fixlist')
def fixlist(author):
if type(author) == list:
return ', '.join(author)
else:
return author
I call it from the template pages like this {{ aitem.Author|fixlist }}
Thank you for the help!

Display additional data while iterating over a Django formset

I have a list of soccer matches for which I'd like to display forms. The list comes from a remote source.
matches = ["A vs. B", "C vs. D", "E vs, F"]
matchFormset = formset_factory(MatchForm,extra=len(matches))
formset = MatchFormset()
On the template side, I would like to display the formset with the according title (i.e. "A vs. B").
{% for form in formset.forms %}
<fieldset>
<legend>{{TITLE}}</legend>
{{form.team1}} : {{form.team2}}
</fieldset>
{% endfor %}
Now how do I get TITLE to contain the right title for the current form? Or asked in a different way: how do I iterate over matches with the same index as the iteration over formset.forms?
Thanks for your input!
I believe that in the Django template language there is no built-in filter for indexing, but there is one for slicing (slice) -- and therefore I think that, in a pinch, you could use a 1-item slice (with forloop.counter0:forloop.counter) and .first on it to extract the value you want.
Of course it would be easier to do it with some cooperation from the Python side -- you could just have a context variable forms_and_matches set to zip(formset.forms, matches) in the Python code, and, in the template, {% for form, match in forms_and_matches %} to get at both items simply and readably (assuming Django 1.0 or better throughout this answer, of course).
This is an addition to Alex's answer.
I did some reading after my comment on Alex's answer and found that it is important to get the management form (basically a meta-form with information about how many forms are in the formset) into your template for your submitted data to be treated as a formset rather than just a pile of forms. Documentation here.
The only two ways I know to get that into your template are:
Send the formset in addition to whatever data structure you made,
and then render the management form with {{ my_formset.management_form }}
Render the management form in your view and send that as an item to your template
Of course if you use Alex's first method, the formset is already available so you can add the management form directly.

Categories

Resources