Stripping out Babel in Flask Jinja Template - flask

I’m working with this tutorial which has the following lines:
{% set user_link %}
<span class="user_popup">
<a href="{{ url_for('main.user', username=post.author.username) }}">
{{ post.author.username }}
</a>
</span>
{% endset %}
{{ _('%(username)s said %(when)s',
username=user_link, when=moment(post.timestamp).fromNow()) }}
It looks this was specifically because he uses Babel translate, which he talks about on his blog.
My question is, how can I make this work when I strip all the Babel code out, because I don’t need any translation, specifically the bit after end set.
This is the sort of thing I tried but could never get the replacement correct:
{{username, username=user_link }} said {{when,when=moment(post.timestamp).fromNow())}}

{{ user_link }} said {{ moment(post.timestamp).fromNow() }}
The arguments after the string define the replacement map for the different keywords, so:
%(username)s will be replaced by user_link, because username=user_link
$(when)s will be replaced by moment(post.timestamp).fromNow(), because when=moment(post.timestamp).fromNow()
The s ending the $(placeholder)s is there to indicate that the placeholder should be considered as a string.

Related

Replace function inside value not working

Maybe I'm doing it wrong (tried several ways to achieve my goal) or overlooking something here.
What I'd like to achieve is this:
When I use the Live-search function, I get categories containing the search keyword (like: Paint -> Paint buckets, Paint brushes, Paint colors etc.) which works like a charm. The one thing I need is to style the searched keyword in the presented categories like:
Paint bucket,
Paint brushes,
Color paint
This is the code I have at the moment:
{% if (products.length + categories.length + pages.length) == 0 %}
<div id="Pi56dYpB" class="undefined"> No results for:
<b>{{ query }}</b>...
</div>
{% endif %}
{% if categories.length > 0 %}
<div class="categories">
{% for category in categories %}
{% if loop.index < 7 %}
<a class="p-0" href="{{ category.url }}" style="all:inherit;">
<h3 id="bvwiyjEN" class="undefined">{{ category.name|replace({{ query }}: "<strong>"{{ query }}"<strong>"})|raw }}</h3>
</a>
{% endif %}
{% endfor %}
{% endif %}
Unfortunately this isn't working. I did check if the {{ query }} value is accessible with this simple line of code:
<h3 id="bvwiyjEN" class="undefined">{{ category.name }} - {{ query }}</h3>
No problems found here.
Did I use the wrong syntax in my code maybe? Any help would be appreciated!
replace({{ query }}) is the wrong syntax - replace(query) should work, as you don't want to echo the variable query here
As Nico Haase pointed out already, {{ ... }} is used to output variables, this translate to something like <?php echo $foo; ?> and can't/shouldn't be used inside statements
Furthermore, the filter replace expects an array of keys to replace with the values.
You would need to change your code to the following:
{% for category in categories %}
{{ category|replace({ (query): '<strong>'~query~'</strong>',})|raw }}
{% endfor %}
demo
Some notes:
The filter replace uses the PHP function strtr in the background. This mean the output will be case-sensitive. If you don't want this, I'd advice you to follow through here
Wrapping the key with parantheses is mandatory. This will force twig to evaluate/interpolate the value of the key - demo

.Site.Data values are not accessible inside a range block

So I just noticed that when I try to access something from .Site itself inside a range block it returns as null/blank.
Here's an example:
<div class="row weekday">
{{ .Site.Data.company.social_media.whatsapp }}
{{ range $entry := sort .Site.Data.events "order" "asc" }}
<div class="col-sm-6 col-md-4 col-lg-4">
{{ .Site.Data.company.social_media.whatsapp }}
{{ partial "events_detail.html" (dict "entry" $entry) }}
</div>
{{ end }}
</div>
The first .Site.Data.company.social_media.whatsapp (before the range) renders a phone number.
The second .Site.Data.company.social_media.whatsapp (after the range) do not renders anything.
This same behavior happens in the partial events_detail.html. If I try to access the .Site from inside of the partial scope it renders a null. I also tried to pass it along on the (dict ...) but no lucky.
What Am I missing here?
I was missing how Hugo manage the scopes for the dot. You read a more in-depth explanation about this (and other important concepts) here:
https://regisphilibert.com/blog/2018/02/hugo-the-scope-the-context-and-the-dot/
In Resume is (extracted from the link above):
The root context, the one available to you in your
baseof.html and layouts will always be the Page context. Basically
everything you need to build this page is in that dot. .Title,
.Permalink, .Resources, you name it.
Even your site’s informations is stored in the page context with .Site
ready for the taking.
But in Go Template the minute you step into a function you lose that
context as your precious dot or context is replaced by the function’s
own… dot.
(...)
Same goes here, once you’ve opened an iteration with range the context
is the whatever item the cursor is pointing to at the moment. You will
lose your page context in favor of the the range context.
{{ range .Data.Pages }}
{{/* Here the dot is that one page 'at cursor'. */}}
{{ .Permalink }}
{{ end }}
Luckily Hugo stores the root context of a template file in a $ so no
matter how deeply nested you are within with or range, you can always
retrieve the top context. In basic template file, it will generally be
your page.
{{ with .Title }}
{{/* Dot is .Title */}}
<h1>{{ . }}</h1>
{{/* $ is the top level page */}}
<h3>From {{ $.Title }}</h3>
{{ end }}

How to mark string for translation in jinja2 using trans blocks

I am using django and jinja2 and have something like this in one of my html pages
<p><strong>Q. {{ _("What products will you accept?") }}</strong></p>
<p class="style3"><strong>A: </strong>{% trans myurl=request.url('start') %}A list of qualifying devices is available once you start your trade-in estimate. <a href= {{myurl}}>Click here</a> to learn what your old device is worth.</p>{% endtrans %}
When I run django-admin.py makemessages, "What products will you accept?" is the only string that gets processed. I thought that wrapping a string with the {% trans %} block also marks that string or is this a wrong statement?
What is the best technique to mark that second string (it's tricky because of the request.url variable)
I've tried {{ _("A list of qualifying devices is available once you start your trade-in estimate. <a href= {{ request.url('start') }}>Click here</a> to learn what your old device is worth.")|safe }} but then the link doesn't work properly.
To translate a block like that you need to use the {% blocktrans %} template tag,
{% blocktrans with myurl=request.url('start') %}
A list of qualifying devices is available once you start your trade-in estimate. <a href= {{myurl}}>Click here</a> to learn what your old device is worth.</p>
{% endblocktrans %}
However, I'm not sure you can call a function like that anywhere in a template like you are attempting.
Consider instead passing myurl in as a template variable, and then using smaller chunks of text. This increases reuse of the translations - especially for small common blocks like "Click here".
{% blocktrans %}
"A list of qualifying devices is available once you start your trade-in estimate."
{% endblocktrans %}
<a href= {{myurl}}>{% trans "Click here" %}</a>
{% trans "to learn what your old device is worth." %}
Also, when using HTML and template tags, try and keep them correctly nested. For example, in your code you would have:
<p>... {% blocktrans %}... </p>{% endblocktrans %}
Instead try to nest them like so:
<p>... {% blocktrans %}... {% endblocktrans %}</p>
This is especially useful for IDEs that can auto indent and fold content and helps readability.

Django templates - Formatting strings

I've these variables:
#Int
user.id
#Float (e.g. X.YYYY)
profile.rating
I need these formatted like so (the ` is delimiter):
`profile.rating`
I've tried numerous ways to format them, but none worked. For example, concatenating them: ""|add:profile.rating|add:"" gave me nothing (literally, nothing).
I suspect that this is because add: is numbers-first, but converting the numbers into string with either slugify or stringformat:"" gave me, again, nothing.
How do I do this?
Do note: I need to do this with filters since the result will be passed as a parameter to an include.
Update:
Basically, I'm building a sort of modular include. It include looks like this:
<section>
...
{% if custom_section %}
<section id="{{ custom_section_id }}">
{{ custom_section }}
</section>
{% endif %}
...
</section>
which means that I can't just directly include the values in a parameter, I need the markup that will go inside the nested section.
I managed to solve this issue with this piece of markup:
{% with "<a href="\"/user/" as link_start %}
{% with profile.rating|stringformat:".1f" as rating %}
{% with user.id|slugify as id %}
{% with link_start|add:id|add:"/\">" as link %}
{% with link|add:rating|add:"/5</a>" as data %}
{% include "XX" with custom_data:data|safe %}
{% endwith %} a couple of times
Key here is the |stringformat:".1f" and the user.id|slugify since without them, djangos worthless templating language defaults on the belief all values are numerical, and thus crap comes out.
Of note is the |safe as well, as without it the language escapes the value.
Do note: I need to do this with filters since the result will be
passed as a parameter to an include.
You can pass them directly to include, as it will take context correctly.
{% include user.id %}

Can I specify a multiline context variable/parameter when {% include %}ing a template?

I know that it is possible to set context variables when including a Django template from another template using
{% include "default_table.html" with table_header=table_header1 table_data=table_data1 %}
or
{% with "My data" as table_data %}
{% include 'default_table.html' %}
{% endwith %}
My issue with this is that both approaches don't let me define multiline variables (unless they are based on a previous multiline variable of course).
My specific usecase is this
<!-- widget.html -->
<div class="box">
<div class="title">{{ title }}</div>
<div class="title">{{ body }}</div>
</div>
and I'd like to be able to set a longer text for the body context variable. This will make is possible for me to reuse common widget HTML in various places. Can this be done?
I've been searching a bit on http://djangosnippets.org for an über {% with ... %} template tag, but haven't found any so far.
This Django snippet kinda solves my issue: http://djangosnippets.org/snippets/1860/ But I'd love to be able to set context variables instead of defining {% localblock step_ready_js %}{% endlocalblock %} in my widget HTML.