Index: lib/python/zope/tal/talinterpreter.py =================================================================== --- lib/python/zope/tal/talinterpreter.py (revision 1294) +++ lib/python/zope/tal/talinterpreter.py (working copy) @@ -607,11 +607,15 @@ self.interpret(stuff[1]) bytecode_handlers["insertText"] = do_insertText bytecode_handlers["insertI18nText"] = do_insertText + bytecode_handlers["insertMltext"] = do_insertText + bytecode_handlers["insertI18nMltext"] = do_insertText - def _writeText(self, text): + def _writeText(self, text, quote_amp=True): # '&' must be done first! - s = text.replace( - "&", "&").replace("<", "<").replace(">", ">") + s = ( + (quote_amp and text.replace( "&", "&") or text) + .replace("<", "<").replace(">", ">") + ) self._stream_write(s) i = s.rfind('\n') if i < 0: @@ -619,7 +623,7 @@ else: self.col = len(s) - (i + 1) - def do_insertText_tal(self, stuff): + def do_insertXText_tal(self, stuff, quote_amp): text = self.engine.evaluateText(stuff[0]) if text is None: return @@ -629,9 +633,15 @@ if isinstance(text, I18nMessageTypes): # Translate this now. text = self.translate(text) - self._writeText(text) + self._writeText(text, quote_amp) - def do_insertI18nText_tal(self, stuff): + def do_insertText_tal(self, stuff): + return self.do_insertXText_tal(stuff, True) + + def do_insertMltext_tal(self, stuff): + return self.do_insertXText_tal(stuff, False) + + def do_insertI18nXText_tal(self, stuff, quote_amp): # TODO: Code duplication is BAD, we need to fix it later text = self.engine.evaluateText(stuff[0]) if text is not None: @@ -640,8 +650,14 @@ else: if isinstance(text, TypesToTranslate): text = self.translate(text) - self._writeText(text) + self._writeText(text, quote_amp) + def do_insertI18nText_tal(self, stuff): + return self.do_insertI18nXText_tal(stuff, True) + + def do_insertI18nMltext_tal(self, stuff): + return self.do_insertI18nXText_tal(stuff, False) + def do_i18nVariable(self, stuff): varname, program, expression, structure = stuff if expression is None: @@ -994,7 +1010,9 @@ bytecode_handlers_tal["insertStructure"] = do_insertStructure_tal bytecode_handlers_tal["insertI18nStructure"] = do_insertI18nStructure_tal bytecode_handlers_tal["insertText"] = do_insertText_tal + bytecode_handlers_tal["insertMltext"] = do_insertMltext_tal bytecode_handlers_tal["insertI18nText"] = do_insertI18nText_tal + bytecode_handlers_tal["insertI18nMltext"] = do_insertI18nMltext_tal bytecode_handlers_tal["loop"] = do_loop_tal bytecode_handlers_tal["onError"] = do_onError_tal bytecode_handlers_tal[""] = attrAction_tal Index: lib/python/zope/tal/tests/test_talinterpreter.py =================================================================== --- lib/python/zope/tal/tests/test_talinterpreter.py (revision 1294) +++ lib/python/zope/tal/tests/test_talinterpreter.py (working copy) @@ -202,17 +202,30 @@ def test_text_translate(self): program, macros = self._compile( - '') - self._check(program, 'BaR\n') + '') + self._check(program, '&BaR\n') program, macros = self._compile( - '') - self._check(program, 'BAR\n') + '') + self._check(program, '&BAR\n') program, macros = self._compile( - '') - self._check(program, 'BAR\n') + '') + self._check(program, '&BAR\n') + def test_mltext_translate(self): + program, macros = self._compile( + '') + self._check(program, '<&>BaR\n') + + program, macros = self._compile( + '') + self._check(program, '<&>BAR\n') + + program, macros = self._compile( + '') + self._check(program, '<&>BAR\n') + def test_structure_text_variable_translate(self): program, macros = self._compile( '') Index: lib/python/zope/tal/taldefs.py =================================================================== --- lib/python/zope/tal/taldefs.py (revision 1294) +++ lib/python/zope/tal/taldefs.py (working copy) @@ -112,7 +112,7 @@ _attr_re = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S) -_subst_re = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S) +_subst_re = re.compile(r"\s*(?:(text|structure|mltext)\s+)?(.*)\Z", re.S) def parseAttributeReplacements(arg, xml): dict = {} Index: lib/python/zope/tal/talgenerator.py =================================================================== --- lib/python/zope/tal/talgenerator.py (revision 1294) +++ lib/python/zope/tal/talgenerator.py (working copy) @@ -277,6 +277,8 @@ cexpr = self.compileExpression(expr) if key == "text": self.emit("insertText", cexpr, []) + elif key == "mltext": + self.emit("insertMltext", cexpr, []) else: assert key == "structure" self.emit("insertStructure", cexpr, {}, []) @@ -308,6 +310,8 @@ program = self.popProgram() if key == "text": self.emit("insertText", cexpr, program) + elif key == "mltext": + self.emit("insertMltext", cexpr, program) else: assert key == "structure" self.emit("insertStructure", cexpr, attrDict, program) @@ -319,6 +323,8 @@ program = self.popProgram() if key == "text": self.emit("insertI18nText", cexpr, program) + elif key == "mltext": + self.emit("insertI18nMltext", cexpr, program) else: assert key == "structure" self.emit("insertI18nStructure", cexpr, attrDict, program)