Search code examples
djangodjango-templatesgettext

Django how to mark_safe a link but not the arguments in a gettext translation


Let say we have a message like this :

            messages.add_message(request, messages.SUCCESS,
                _('Document <a href="%(url)s">%(doc_type_name)s %(name)s (%(fname)s)</a> created.') % {
                    'doc_type_name': conditional_escape(document.doc_type.name),
                    'name': conditional_escape(document.title),
                    'fname': conditional_escape(document.name),
                    'url': document.get_absolute_url()
                })

Here it will work only if we display the message with {{ message|safe }} but we don't want that since if there is some code in %(name) it will be executed too.

If I use:

            messages.add_message(request, messages.SUCCESS,
                mark_safe(_('Document <a href="%(url)s">%(doc_type_name)s %(name)s (%(fname)s)</a> created.') % {
                    'doc_type_name': conditional_escape(document.doc_type.name),
                    'name': conditional_escape(document.title),
                    'fname': conditional_escape(document.name),
                    'url': document.get_absolute_url()
                }))

The mark_safe doesn't work.

I read a solution over there : https://stackoverflow.com/a/12600388/186202

But it is the reverse that I need here:

_('Document %s created.') % mark_safe('')

And as soon as it goes through the ugettext function it is not safe anymore.

How should I do?


Solution

  • You are trying to mix view and logic by placing HTML inside Python code. Well, sometimes you just have to do this but it is not the case.

    mark_safe() returns SafeString object which is treated by Django templates specially. If SafeString evaluated by ugettext or % you will get string again, it is an expected behaviour. You can not mark safe only formatting string, either complete output with doc name/title etc or everything is not safe. Ie, it will not work this way.

    You can put HTML into template and use render_to_string(), and probably it is the best option.

    Are document title, name and doc_type.name set by user? If not, you can skip mark_safe and document using HTML in document properties as feature.