From fab7a071e396fd53448673d1fabb3515470f1c87 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Mon, 14 Dec 2015 10:14:45 -0500 Subject: [PATCH] Add new helper methods. --- common/djangoapps/util/markup.py | 51 ++++++++++++++++ common/djangoapps/util/tests/test_markup.py | 68 +++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 common/djangoapps/util/markup.py create mode 100644 common/djangoapps/util/tests/test_markup.py diff --git a/common/djangoapps/util/markup.py b/common/djangoapps/util/markup.py new file mode 100644 index 0000000000..304533de32 --- /dev/null +++ b/common/djangoapps/util/markup.py @@ -0,0 +1,51 @@ +""" +Utilities for use in Mako markup. +""" + +from django.utils.translation import ugettext as django_ugettext +from django.utils.translation import ungettext as django_ungettext +import markupsafe + + +# So that we can use escape() imported from here. +escape = markupsafe.escape # pylint: disable=invalid-name + + +def ugettext(text): + """Translate a string, and escape it as plain text. + + Use like this in Mako:: + + <% from util.markup import ugettext as _ %> +

${_("Hello, world!")}

+ + Or with formatting:: + + <% from util.markup import HTML, ugettext as _ %> + ${_("Write & send {start}email{end}").format( + start=HTML(""), + end=HTML(""), + )} + + """ + return markupsafe.escape(django_ugettext(text)) + + +def ungettext(text1, text2, num): + """Translate a number-sensitive string, and escape it as plain text.""" + return markupsafe.escape(django_ungettext(text1, text2, num)) + + +def HTML(html): # pylint: disable=invalid-name + """Mark a string as already HTML, so that it won't be escaped before output. + + Use this when formatting HTML into other strings:: + + <% from util.markup import HTML, ugettext as _ %> + ${_("Write & send {start}email{end}").format( + start=HTML(""), + end=HTML(""), + )} + + """ + return markupsafe.Markup(html) diff --git a/common/djangoapps/util/tests/test_markup.py b/common/djangoapps/util/tests/test_markup.py new file mode 100644 index 0000000000..d700df57f8 --- /dev/null +++ b/common/djangoapps/util/tests/test_markup.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +""" +Tests for util.markup +""" + +import unittest + +import ddt + +from edxmako.template import Template +from util.markup import escape, HTML, ugettext as _, ungettext + + +@ddt.ddt +class FormatHtmlTest(unittest.TestCase): + """Test that we can format plain strings and HTML into them properly.""" + + @ddt.data( + (u"hello", u"hello"), + (u"", u"<hello>"), + (u"It's cool", u"It's cool"), + (u'"cool," she said.', u'"cool," she said.'), + (u"Stop & Shop", u"Stop & Shop"), + (u"нтмℓ-єѕ¢αρє∂", u"<a>нтмℓ-єѕ¢αρє∂</a>"), + ) + def test_simple(self, (before, after)): + self.assertEqual(unicode(_(before)), after) # pylint: disable=translation-of-non-string + self.assertEqual(unicode(escape(before)), after) + + def test_formatting(self): + # The whole point of this function is to make sure this works: + out = _(u"Point & click {start}here{end}!").format( + start=HTML(""), + end=HTML(""), + ) + self.assertEqual( + unicode(out), + u"Point & click here!", + ) + + def test_nested_formatting(self): + # Sometimes, you have plain text, with html inserted, and the html has + # plain text inserted. It gets twisty... + out = _(u"Send {start}email{end}").format( + start=HTML("").format(email="A&B"), + end=HTML(""), + ) + self.assertEqual( + unicode(out), + u"Send email", + ) + + def test_mako(self): + # The default_filters used here have to match the ones in edxmako. + template = Template( + """ + <%! from util.markup import HTML, ugettext as _ %> + ${_(u"A & {BC}").format(BC=HTML("B & C"))} + """, + default_filters=['decode.utf8', 'h'], + ) + out = template.render({}) + self.assertEqual(out.strip(), u"A & B & C") + + def test_ungettext(self): + for i in [1, 2]: + out = ungettext("1 & {}", "2 & {}", i).format(HTML("<>")) + self.assertEqual(out, "{} & <>".format(i))