However, this template is buggy when `title` is a string, which I'd argue
is a common use case.
`title` will be escaped when formatting the content of the
`blocktranslate` block, but the "was escaped" information is discarded,
and `the_title` will be a `str` instance with escaped content.
When later using the `the_title` variable, it will be conditionally
escaped. Since it is a `str`, it will be escaped, so control characters
are escaped again, breaking their display on the final page.
Minimal example to reproduce (can be put in any view):
{{{
from django.template import Template, Context
template_content = """
{% blocktranslate asvar the_title %}The title is {{ title }}.{%
endblocktranslate %}
<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">
"""
rendered = Template(template_content).render(Context({"title": "<>&
Title"}))
assert "&lt;" not in rendered, "> was escaped two times"
}}}
I'd argue that `blocktranslate` should:
* Either assign a `SafeString` instance to prevent future escaping
* or not escape the variables used within the translation, and store them
marked as unsafe (= as `str` instance)
--
Ticket URL: <https://code.djangoproject.com/ticket/33631>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* status: new => closed
* resolution: => wontfix
Comment:
Hi Richard, thanks for the report.
So this would be the way forward:
> ... assign a SafeString instance to prevent future escaping
But it's not at all clear how feasible it would be to correctly mark the
returned string as safe. Individual variables are run via
`render_value_in_context()` which escapes them assuming `autoescape` is
enabled, but then the final output is constructed after that, so it's not
clear we can reliably mark it safe.
**Rather** if, in your example, you know `the_title` is safe, declare it
as so: `{{ the_title|safe }}`. The following test case passes:
{{{
diff --git a/tests/template_tests/syntax_tests/i18n/test_blocktranslate.py
b/tests/template_tests/syntax_tests/i18n/test_blocktranslate.py
index 4a162362c6..967a7c1829 100644
--- a/tests/template_tests/syntax_tests/i18n/test_blocktranslate.py
+++ b/tests/template_tests/syntax_tests/i18n/test_blocktranslate.py
@@ -388,6 +388,23 @@ class I18nBlockTransTagTests(SimpleTestCase):
output = self.engine.render_to_string("i18n39")
self.assertEqual(output, ">Seite nicht gefunden<")
+ @setup(
+ {
+ "issue33631": (
+ """
+ {% load i18n %}
+ {% blocktranslate asvar the_title %}The title is
{{title}}.{% endblocktranslate %}
+ < title > {{the_title|safe}} < / title >
+ < meta name="description" content="{{ the_title|safe }}"
>
+ """
+ )
+ }
+ )
+ def test_issue33631(self):
+ with translation.override("en"):
+ output = self.engine.render_to_string("issue33631", {"title":
"<>& Title"})
+ self.assertNotIn("&lt;", output)
+
@setup(
{
}}}
... and it avoids trying to resolve the difficulty above.
As such, I'm going to say `wontfix` here initially, and ask that you
follow-up on the [https://forum.djangoproject.com/c/internals/i18n/14
Internationalization Topics section of the Django Forum] to get a wider
audience if you'd like to discuss it further.
Thanks.
--
Ticket URL: <https://code.djangoproject.com/ticket/33631#comment:1>
* status: closed => new
* resolution: wontfix =>
* stage: Unreviewed => Accepted
Comment:
Reopening to assess a patch [https://forum.djangoproject.com/t
/blocktranslate-asvar-escapes-without-marking-safe-re-ticket-33631/13146
based on forum discussion].
--
Ticket URL: <https://code.djangoproject.com/ticket/33631#comment:2>
* owner: nobody => Cheng Yuan
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/33631#comment:3>
* has_patch: 0 => 1
Comment:
PR
https://github.com/django/django/pull/15742
--
Ticket URL: <https://code.djangoproject.com/ticket/33631#comment:4>
* needs_docs: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/33631#comment:5>
* needs_docs: 1 => 0
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/33631#comment:6>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"d4c5d2b52c897ccc07f04482d3f42f976a79223c" d4c5d2b5]:
{{{
#!CommitTicketReference repository=""
revision="d4c5d2b52c897ccc07f04482d3f42f976a79223c"
Fixed #33631 -- Marked {% blocktranslate asvar %} result as HTML safe.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/33631#comment:7>