diff --git a/openerp/addons/base/tests/test_translate.py b/openerp/addons/base/tests/test_translate.py
index 35518bbfb11..40cf960873c 100644
--- a/openerp/addons/base/tests/test_translate.py
+++ b/openerp/addons/base/tests/test_translate.py
@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import unittest
-from openerp.tools.translate import quote, unquote, xml_translate
+from openerp.tools.translate import quote, unquote, xml_translate, html_translate
class TranslationToolsTestCase(unittest.TestCase):
@@ -142,3 +142,11 @@ class TranslationToolsTestCase(unittest.TestCase):
self.assertEquals(result, source)
self.assertItemsEqual(terms,
['', 'More '])
+
+ def test_translate_html(self):
+ """ Test xml_translate() and html_translate() with elements. """
+ source = """"""
+ result = xml_translate(lambda term: term, source)
+ self.assertEquals(result, """""")
+ result = html_translate(lambda term: term, source)
+ self.assertEquals(result, source)
diff --git a/openerp/fields.py b/openerp/fields.py
index 5f815de6909..ec3a1b8d3c3 100644
--- a/openerp/fields.py
+++ b/openerp/fields.py
@@ -15,7 +15,7 @@ import xmlrpclib
from openerp.tools import float_round, frozendict, html_sanitize, ustr, OrderedSet
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
-from openerp.tools.translate import xml_translate
+from openerp.tools.translate import html_translate
DATE_LENGTH = len(date.today().strftime(DATE_FORMAT))
DATETIME_LENGTH = len(datetime.now().strftime(DATETIME_FORMAT))
@@ -1245,9 +1245,9 @@ class Html(_String):
def _setup_attrs(self, model, name):
super(Html, self)._setup_attrs(model, name)
- # Translated sanitized html fields must use xml_translate or a callable.
+ # Translated sanitized html fields must use html_translate or a callable.
if self.translate and not callable(self.translate) and self.sanitize:
- self.translate = xml_translate
+ self.translate = html_translate
_column_sanitize = property(attrgetter('sanitize'))
_related_sanitize = property(attrgetter('sanitize'))
diff --git a/openerp/tools/translate.py b/openerp/tools/translate.py
index 713603b5904..3287547c790 100644
--- a/openerp/tools/translate.py
+++ b/openerp/tools/translate.py
@@ -151,16 +151,8 @@ TRANSLATED_ATTRS = {
'string', 'help', 'sum', 'avg', 'confirm', 'placeholder', 'alt', 'title',
}
-def serialize(tag, attrib, content):
- """ Return a serialized element with the given `tag`, attributes
- `attrib`, and already-serialized `content`.
- """
- elem = etree.tostring(etree.Element(tag, attrib))
- assert elem.endswith("/>")
- return "%s>%s%s>" % (elem[:-2], content, tag) if content else elem
-
class XMLTranslator(object):
- """ A sequence of serialized xml items, with some of them to translate
+ """ A sequence of serialized XML/HTML items, with some of them to translate
(todo) and others already translated (done). The purpose of this object
is to simplify the handling of phrasing elements (like ) that must be
translated together with their surrounding text.
@@ -177,8 +169,9 @@ class XMLTranslator(object):
"""
- def __init__(self, callback):
+ def __init__(self, callback, method):
self.callback = callback # callback function to translate terms
+ self.method = method # serialization method ('xml' or 'html')
self._done = [] # translated strings
self._todo = [] # todo strings that come after _done
self.needs_trans = False # whether todo needs translation
@@ -227,12 +220,12 @@ class XMLTranslator(object):
):
# do not translate the contents of the node
tail, node.tail = node.tail, None
- self.done(etree.tostring(node))
+ self.done(etree.tostring(node, method=self.method))
self.todo(escape(tail or ""))
return
# process children nodes locally in child_trans
- child_trans = XMLTranslator(self.callback)
+ child_trans = XMLTranslator(self.callback, self.method)
child_trans.todo(escape(node.text or ""))
for child in node:
child_trans.process(child)
@@ -241,38 +234,61 @@ class XMLTranslator(object):
node.tag in TRANSLATED_ELEMENTS and
not any(attr.startswith("t-") for attr in node.attrib)):
# serialize the node element as todo
- self.todo(serialize(node.tag, node.attrib, child_trans.get_todo()),
+ self.todo(self.serialize(node.tag, node.attrib, child_trans.get_todo()),
child_trans.needs_trans)
else:
# complete translations and serialize result as done
for attr in TRANSLATED_ATTRS:
if node.get(attr):
node.set(attr, self.process_text(node.get(attr)))
- self.done(serialize(node.tag, node.attrib, child_trans.get_done()))
+ self.done(self.serialize(node.tag, node.attrib, child_trans.get_done()))
# add node tail as todo
self.todo(escape(node.tail or ""))
+ def serialize(self, tag, attrib, content):
+ """ Return a serialized element with the given `tag`, attributes
+ `attrib`, and already-serialized `content`.
+ """
+ if content:
+ elem = etree.tostring(etree.Element(tag, attrib), method='xml')
+ assert elem.endswith("/>")
+ return "%s>%s%s>" % (elem[:-2], content, tag)
+ else:
+ return etree.tostring(etree.Element(tag, attrib), method=self.method)
+
def xml_translate(callback, value):
""" Translate an XML value (string), using `callback` for translating text
- appearing in `value`. If `value` is not XML valid, it is parsed with an HTML
- parser instead, and some element wrapping is done to make the parsing work.
+ appearing in `value`.
"""
if not value:
return value
- trans = XMLTranslator(callback)
+ trans = XMLTranslator(callback, 'xml')
try:
root = etree.fromstring(encode(value))
trans.process(root)
return trans.get_done()
except etree.ParseError:
- wrapped = "
%s
" % encode(value)
- root = etree.fromstring(wrapped, etree.HTMLParser(encoding='utf-8'))
- # html > body > div
- trans.process(root[0][0])
- return trans.get_done()[5:-6]
+ # fallback in case it is a translated term...
+ root = etree.fromstring("%s
" % encode(value))
+ trans.process(root)
+ return trans.get_done()[5:-6] # remove tags and
+
+def html_translate(callback, value):
+ """ Translate an HTML value (string), using `callback` for translating text
+ appearing in `value`.
+ """
+ if not value:
+ return value
+
+ trans = XMLTranslator(callback, 'html')
+ wrapped = "%s
" % encode(value)
+ root = etree.fromstring(wrapped, etree.HTMLParser(encoding='utf-8'))
+ # html > body > div
+ trans.process(root[0][0])
+ return trans.get_done()[5:-6] # remove tags and
#