[ZPT] CVS: Zope3/lib/python/Zope/TAL - TALGenerator.py:1.52.16.3.4.8
Barry Warsaw
barry@wooz.org
Mon, 10 Jun 2002 15:20:40 -0400
Update of /cvs-repository/Zope3/lib/python/Zope/TAL
In directory cvs.zope.org:/tmp/cvs-serv2938/lib/python/Zope/TAL
Modified Files:
Tag: fdrake-tal-i18n-branch
TALGenerator.py
Log Message:
Support for i18n:name, specifically:
emitI18nVariable(): This gets called whenever we see an i18n:name in a
tag without a tal:replace. We actually have to handle those two
situations slightly differently, and this is keyed off of whether the
2nd element of the tuple is None or not.
emitStartElement():
- Get the variable name out of the i18ndict, key: "name".
- reword the "mutually exclusive" exceptions to make more sense.
- if we're i18n:replace'ing and we have an i18n:name substitution to
deal with, then set the todo['i18nvar'] key to a 2-tuple containing
the variable name and the replacement context. This will be used
later by emitEndElement().
- Otherwise, if we've seen an i18n:name with no tal:replacement, then
set todo['i18nvar'] to a 2-tuple, where the first element is still
the variable name, but the second is None. This will be used as a
special marker by emitI18nVariable().
emitEndElement(): If we're about to emit the end tag, we first need to
make a copy of the current sub-program as it stands before the end tag
is emitted. That's because in this situation:
<span i18n:name="name"><b>Jim</b></span>
you want "<b>Jim</b>" to be the implicit value for the key "name" in
the interpolation dictionary, but you do not want "</span>" showing up
there!
=== Zope3/lib/python/Zope/TAL/TALGenerator.py 1.52.16.3.4.7 => 1.52.16.3.4.8 ===
self.expressionCompiler = expressionCompiler
self.CompilerError = expressionCompiler.getCompilerError()
+ # This holds the emitted opcodes representing the input
self.program = []
+ # The program stack for when we need to do some sub-evaluation for an
+ # intermediate result. E.g. in an i18n:name tag for which the
+ # contents describe the ${name} value.
self.stack = []
+ # Another stack of postponed actions. Elements on this stack are a
+ # dictionary; key/values contain useful information that
+ # emitEndElement needs to finish its calculations
self.todoStack = []
self.macros = {}
self.slots = {}
@@ -292,6 +299,30 @@
#assert 0, 'emitSubstitution...' + `cexpr, attrDict, program`
self.emit("insertStructure", cexpr, attrDict, program)
+ def emitI18nVariable(self, varname, arg):
+ # 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
+ # i18n:name value is taken implicitly from the contents of the tag,
+ # e.g. "I live in <span i18n:name="country">the USA</span>". In this
+ # case, arg[1] is the opcode sub-program describing the contents of
+ # the tag.
+ #
+ # When arg[0] is not None, it contains the tal expression used to
+ # calculate the contents of the variable, e.g.
+ # "I live in <span i18n:name="country"
+ # tal:replace="here/countryOfOrigin" />"
+ key = cexpr = ''
+ 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()
+ # XXX Would key be anything but `text'?
+ assert key == 'text'
+ self.emit('i18nVariable', varname, cexpr, program)
+
def emitTranslation(self, msgid):
program = self.popProgram()
self.emit('insertTranslation', msgid, program)
@@ -453,6 +484,7 @@
# code with the msgid='' and calculate the right implicit msgid during
# interpretation phase.
msgid = i18ndict.get("translate")
+ varname = i18ndict.get('name')
if i18ndict.has_key("data") and not i18ndict.has_key("name"):
raise I18NError("i18n:data must be accompanied by i18n:name",
@@ -464,11 +496,13 @@
position)
if replace:
if content:
- raise TALError("content and replace are mutually exclusive",
- position)
+ raise TALError(
+ "tal:content and tal:replace are mutually exclusive",
+ position)
if msgid is not None:
- raise I18NError("i18n:name and replace are mutually exclusive",
- position)
+ raise I18NError(
+ "i18n:translate and tal:replace are mutually exclusive",
+ position)
repeatWhitespace = None
if repeat:
@@ -534,7 +568,18 @@
if content:
todo["content"] = content
if replace:
- todo["replace"] = replace
+ # tal:replace w/ i18n:name has slightly different semantics. What
+ # we're actually replacing then is the contents of the ${name}
+ # placeholder.
+ if varname:
+ todo['i18nvar'] = (varname, replace)
+ else:
+ todo["replace"] = replace
+ self.pushProgram()
+ # i18n:name w/o tal:replace uses the content as the interpolation
+ # dictionary values
+ elif varname:
+ todo['i18nvar'] = (varname, None)
self.pushProgram()
if msgid is not None:
todo['msgid'] = msgid
@@ -583,7 +628,6 @@
if not isend:
self.emitEndTag(name)
return
-
self.position = position = todo.get("position", (None, None))
defineMacro = todo.get("defineMacro")
useMacro = todo.get("useMacro")
@@ -599,6 +643,7 @@
scope = todo.get("scope")
optTag = todo.get("optional tag")
msgid = todo.get('msgid')
+ varname = todo.get('i18nvar')
if implied > 0:
if defineMacro or useMacro or defineSlot or fillSlot:
@@ -617,9 +662,20 @@
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[:],)
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
+ # of the expression go into the i18n substitution dictionary.
if replace:
self.emitSubstitution(replace, repldict)
+ elif varname:
+ self.emitI18nVariable(varname[0], varname[1:])
if repeat:
self.emitRepeat(repeat)
if condition: