Opened 13 years ago
Closed 13 years ago
#19132 closed Cleanup/optimization (fixed)
bug in use of mark_safe and i18n _
| Reported by: | Owned by: | nobody | |
|---|---|---|---|
| Component: | Documentation | Version: | 1.4 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I am using a form which defines this field:
terms = forms.BooleanField(
error_messages={'required': _('You must accept the terms and conditions')},
label="",
help_text=_(mark_safe("I understand and accept the <a href='/terms_and_conditions' target='_blank'>terms of use</a> and <a href='/privacy' target='_blank'>privacy policy</a> of this site."))
)
unfortunately running "./manage.py makemessages --all" does not seem to pickup the help_text named argument.
---
If i change this to:
terms = forms.BooleanField(
error_messages={'required': _('You must accept the terms and conditions')},
label="",
help_text=mark_safe(_("I understand and accept the <a href='/terms_and_conditions' target='_blank'>terms of use</a> and <a href='/privacy' target='_blank'>privacy policy</a> of this site."))
)
the message in the html is left untranslated.
Change History (10)
comment:1 by , 13 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
comment:2 by , 13 years ago
| Component: | Translations → Internationalization |
|---|---|
| Resolution: | invalid |
| Status: | closed → reopened |
| Triage Stage: | Unreviewed → Accepted |
No, even with ugettext_lazy, this does not work. mark_safe is triggering lazy string translation.
>>> from django.utils.translation import ugettext_lazy
>>> from django.utils.safestring import mark_safe
>>> mark_safe(ugettext_lazy('Home'))
u'Home'
>>> mark_safe(ugettext_lazy('Home')).__class__
<class 'django.utils.safestring.SafeText'>
I don't know currently if we can do something to prevent this, but a temporary workaround would be to dynamically set the help_text property in the __init__ of the form.
comment:3 by , 13 years ago
Then the reporter presumably needs mark_safe_lazy, which can be created easily using lazy in the same way that ugettext_lazy is created, I imagine. I think altering the behaviour of mark_safe here is likely to be too risky.
comment:4 by , 13 years ago
| Resolution: | → invalid |
|---|---|
| Status: | reopened → closed |
Thanks Luke for the tip, this seems to work nicely:
from django.utils.functional import lazy
mark_safe_lazy = lazy(mark_safe, six.text_type)
terms = forms.BooleanField(..., help_text=mark_safe_lazy(_("My lazy string)))
comment:5 by , 13 years ago
Hi, yes i am using ugettext_lazy.
Following your tips i did this fix: (thanks for those)
from django.utils.translation import ugettext, ugettext_lazy as _
from django.utils.safestring import mark_safe
from django.utils.functional import lazy
from types import UnicodeType
mark_safe_lazy = lazy(mark_safe, UnicodeType)
...
terms = forms.BooleanField(
error_messages={'required': _('You must accept the terms and conditions')},
label="",
help_text=mark_safe_lazy(_("I understand and accept the <a href='/terms_and_conditions' target='_blank'>terms of use</a> and <a href='/privacy' target='_blank'>privacy policy</a> of this site."))
)
...
This works now. Isn't this worth including in the documentation, or is it too edge case?
comment:6 by , 13 years ago
Hmm, it's difficult to know where to put in the docs, because there are so many places it could apply - anywhere that you want to use HTML in a class or module level translatable string.
Perhaps we should make a note in the mark_safe docs, and possibly add the mark_safe_lazy function, I'm not sure. If it's worth documenting, it's really not much more work to add the function, and would make the documentation probably smaller overall.
comment:7 by , 13 years ago
Maybe here?:
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index aaf728b..6692c1a 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -427,6 +427,24 @@ In this case, the lazy translations in ``result`` will only be converted to
strings when ``result`` itself is used in a string (usually at template
rendering time).
+Other uses of lazy in delayed translations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For any other case where you would like to delay the translation, but have to
+pass the translatable string as argument to another function, you can wrap
+this function inside a lazy call yourself. For example::
+
+ from django.utils import six # Python 3 compatibility
+ from django.utils.functional import lazy
+ from django.utils.safestring import mark_safe
+ from django.utils.translation import ugettext_lazy as _
+
+ mark_safe_lazy = lazy(mark_safe, six.text_type)
+
+And then later::
+
+ lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>"))
+
comment:8 by , 13 years ago
LGTM, and as docs only fix it avoids the problem that we are technically in feature freeze for trunk.
comment:9 by , 13 years ago
| Component: | Internationalization → Documentation |
|---|---|
| Resolution: | invalid |
| Status: | closed → reopened |
| Type: | Bug → Cleanup/optimization |
comment:10 by , 13 years ago
| Resolution: | → fixed |
|---|---|
| Status: | reopened → closed |
You haven't told us what
_is defined as.I'm guessing are probably using ugettext, and need to read the docs about lazy translation:
https://docs.djangoproject.com/en/dev/topics/i18n/translation/#lazy-translation