[Zope-Checkins] CVS: Zope3/lib/python/Zope/TAL - TALGenerator.py:1.59 TALInterpreter.py:1.80 driver.py:1.31
Barry Warsaw
barry@wooz.org
Mon, 1 Jul 2002 11:59:12 -0400
Update of /cvs-repository/Zope3/lib/python/Zope/TAL
In directory cvs.zope.org:/tmp/cvs-serv5877/lib/python/Zope/TAL
Modified Files:
TALGenerator.py TALInterpreter.py driver.py
Log Message:
Merging tal-i18n-refactor-branch back into the Zope3 trunk.
=== Zope3/lib/python/Zope/TAL/TALGenerator.py 1.58 => 1.59 ===
from TranslationContext import TranslationContext, DEFAULT_DOMAIN
+I18N_REPLACE = 1
+I18N_CONTENT = 2
+I18N_EXPRESSION = 3
+
class TALGenerator:
inMacroUse = 0
@@ -91,6 +95,12 @@
# instructions to be joined together.
output.append(self.optimizeArgsList(item))
continue
+ if opcode == 'noop':
+ # This is a spacer for end tags in the face of i18n:name
+ # attributes. We can't let the optimizer collect immediately
+ # following end tags into the same rawtextOffset.
+ opcode = None
+ pass
text = "".join(collect)
if text:
i = text.rfind("\n")
@@ -299,7 +309,7 @@
assert key == "structure"
self.emit("insertStructure", cexpr, attrDict, program)
- def emitI18nVariable(self, varname, arg):
+ def emitI18nVariable(self, varname, action, expression):
# Used for i18n:name attributes. arg is extra information describing
# how the contents of the variable should get filled in, and it will
# either be a 1-tuple or a 2-tuple. If arg[0] is None, then the
@@ -313,15 +323,24 @@
# "I live in <span i18n:name="country"
# tal:replace="here/countryOfOrigin" />"
key = cexpr = None
- if arg[0] is not None:
- key, expr = parseSubstitution(arg[0])
- cexpr = self.compileExpression(expr)
- else:
- cexpr = self.optimize(arg[1][1:])
program = self.popProgram()
+ if action == I18N_REPLACE:
+ # This is a tag with an i18n:name and a tal:replace (implicit or
+ # explicit). Get rid of the first and last elements of the
+ # program, which are the start and end tag opcodes of the tag.
+ program = program[1:-1]
+ elif action == I18N_CONTENT:
+ # This is a tag with an i18n:name and a tal:content
+ # (explicit-only). Keep the first and last elements of the
+ # program, so we keep the start and end tag output.
+ pass
+ else:
+ assert action == I18N_EXPRESSION
+ key, expr = parseSubstitution(expression)
+ cexpr = self.compileExpression(expr)
# XXX Would key be anything but 'text' or None?
assert key in ('text', None)
- self.emit('i18nVariable', varname, cexpr, program)
+ self.emit('i18nVariable', varname, program, cexpr)
def emitTranslation(self, msgid, i18ndata):
program = self.popProgram()
@@ -685,19 +704,30 @@
raise exc("%s attributes on <%s> require explicit </%s>" %
(what, name, name), position)
+ # If there's no tal:content or tal:replace in the tag with the
+ # i18n:name, tal:replace is the default.
+ i18nNameAction = I18N_REPLACE
if content:
+ if varname:
+ i18nNameAction = I18N_CONTENT
self.emitSubstitution(content, {})
- if msgid is not None:
+ # If we're looking at an implicit msgid, emit the insertTranslation
+ # opcode now, so that the end tag doesn't become part of the implicit
+ # msgid. If we're looking at an explicit msgid, it's better to emit
+ # the opcode after the i18nVariable opcode so we can better handle
+ # tags with both of them in them (and in the latter case, the contents
+ # would be thrown away for msgid purposes).
+ if msgid is not None and not varname:
self.emitTranslation(msgid, i18ndata)
if optTag:
self.emitOptTag(name, optTag, isend)
elif not isend:
- # Before we emit the end tag, we need to see if the value of the
- # current program is to be used as the value of the i18n:name
- # interpolation variable. If so, we need to make a copy of the
- # program /without the end tag/ and squirrel it away for later.
- if not replace and varname and varname[1] is None:
- varname += (self.program[:],)
+ # If we're processing the end tag for a tag that contained
+ # i18n:name, we need to make sure that optimize() won't collect
+ # immediately following end tags into the same rawtextOffset, so
+ # put a spacer here that the optimizer will recognize.
+ if varname:
+ self.emit('noop')
self.emitEndTag(name)
# If i18n:name appeared in the same tag as tal:replace then we're
# going to do the substitution a little bit differently. The results
@@ -705,7 +735,20 @@
if replace:
self.emitSubstitution(replace, repldict)
elif varname:
- self.emitI18nVariable(varname[0], varname[1:])
+ if varname[1] is not None:
+ i18nNameAction = I18N_EXPRESSION
+ # o varname[0] is the variable name
+ # o i18nNameAction is either
+ # - I18N_REPLACE for implicit tal:replace
+ # - I18N_CONTENT for tal:content
+ # - I18N_EXPRESSION for explicit tal:replace
+ # o varname[1] will be None for the first two actions and the
+ # replacement tal expression for the third action.
+ self.emitI18nVariable(varname[0], i18nNameAction, varname[1])
+ # Do not test for "msgid is not None", i.e. we only want to test for
+ # explicit msgids here. See comment above.
+ if msgid is not None and varname:
+ self.emitTranslation(msgid, i18ndata)
if repeat:
self.emitRepeat(repeat)
if condition:
=== Zope3/lib/python/Zope/TAL/TALInterpreter.py 1.79 => 1.80 ===
]
+def normalize(text):
+ # Now we need to normalize the whitespace in implicit message ids and
+ # implicit $name substitution values by stripping leading and trailing
+ # whitespace, and folding all internal whitespace to a single space.
+ return ' '.join(text.split())
+
+
class AltTALGenerator(TALGenerator):
def __init__(self, repldict, expressionCompiler=None, xml=0):
@@ -192,8 +199,8 @@
try:
if self.debug:
for (opcode, args) in program:
- s = "%sdo_%s%s\n" % (" "*self.level, opcode,
- repr(args))
+ s = "%sdo_%s(%s)\n" % (" "*self.level, opcode,
+ repr(args))
if len(s) > 80:
s = s[:76] + "...\n"
sys.stderr.write(s)
@@ -470,21 +477,21 @@
bytecode_handlers["insertText"] = do_insertText
def do_i18nVariable(self, stuff):
- varname = stuff[0]
- if isinstance(stuff[1], ListType):
+ varname, program, expression = stuff
+ if expression is None:
# The value is implicitly the contents of this tag, so we have to
- # evaluate the mini-program
+ # evaluate the mini-program to get the value of the variable.
state = self.saveState()
try:
tmpstream = StringIO()
- self.interpret(stuff[1], tmpstream)
- value = tmpstream.getvalue()
+ self.interpret(program, tmpstream)
+ value = normalize(tmpstream.getvalue())
finally:
self.restoreState(state)
else:
# Evaluate the value to be associated with the variable in the
# i18n interpolation dictionary.
- value = self.engine.evaluate(stuff[1])
+ value = self.engine.evaluate(expression)
# Either the i18n:name tag is nested inside an i18n:translate in which
# case the last item on the stack has the i18n dictionary and string
# representation, or the i18n:name and i18n:translate attributes are
@@ -517,11 +524,7 @@
# message id. All other useful information will be in the i18ndict on
# the top of the i18nStack.
if msgid == '':
- msgid = tmpstream.getvalue()
- # Now we need to normalize the whitespace in the implicit message
- # id by stripping leading and trailing whitespace, and folding all
- # internal whitespace to a single space.
- msgid = ' '.join(msgid.split())
+ msgid = normalize(tmpstream.getvalue())
self.i18nStack.pop()
# See if there is was an i18n:data for msgid
if len(stuff) > 2:
=== Zope3/lib/python/Zope/TAL/driver.py 1.30 => 1.31 ===
Leave TAL/METAL attributes in output
-i
- Leave I18N substitution strings un-interpolated
+ Leave I18N substitution strings un-interpolated.
"""
import os
@@ -58,6 +58,13 @@
return '%(minutes)s minutes after %(hours)s %(ampm)s' % mapping
elif msgid == 'jobnum':
return '%(jobnum)s is the JOB NUMBER' % mapping
+ elif msgid == 'verify':
+ s = 'Your contact email address is recorded as %(email)s'
+ return s % mapping
+ elif msgid == 'mailto:${request/submitter}':
+ return 'mailto:bperson@dom.ain'
+ elif msgid == 'origin':
+ return '%(name)s was born in %(country)s' % mapping
return DummyTranslationService.translate(self, domain, msgid,
mapping, context,
target_language)
@@ -75,6 +82,8 @@
}
elif expr == 'context/@@object_name':
return '7'
+ elif expr == 'request/submitter':
+ return 'aperson@dom.ain'
return DummyEngine.evaluatePathOrVar(self, expr)
@@ -84,6 +93,12 @@
ENGINES = {'test23.html': TestEngine,
'test24.html': TestEngine,
'test26.html': TestEngine,
+ 'test27.html': TestEngine,
+ 'test28.html': TestEngine,
+ 'test29.html': TestEngine,
+ 'test30.html': TestEngine,
+ 'test31.html': TestEngine,
+ 'test32.html': TestEngine,
}
def usage(code, msg=''):