[ZPT] CVS: Zope/lib/python/TAL - TALInterpreter.py:1.69.6.6

Florent Guillaume fg@nuxeo.com
Tue, 24 Sep 2002 11:39:29 -0400


Update of /cvs-repository/Zope/lib/python/TAL
In directory cvs.zope.org:/tmp/cvs-serv20613/lib/python/TAL

Modified Files:
      Tag: Zope-2_6-branch
	TALInterpreter.py 
Log Message:
Modified the translation service to return None if no translation exist.

So now using i18n tags without a translation service should give the
same behavior as before. The tests reflect that.

Tagged efge-before-i18n-notransserv-fix before this checkin.


=== Zope/lib/python/TAL/TALInterpreter.py 1.69.6.5 => 1.69.6.6 ===
--- Zope/lib/python/TAL/TALInterpreter.py:1.69.6.5	Fri Sep 20 15:52:25 2002
+++ Zope/lib/python/TAL/TALInterpreter.py	Tue Sep 24 11:39:29 2002
@@ -47,6 +47,23 @@
     return ' '.join(text.split())
 
 
+NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
+_interp_regex = re.compile(r'(?<!\$)(\$(?:%(n)s|{%(n)s}))' %({'n': NAME_RE}))
+_get_var_regex = re.compile(r'%(n)s' %({'n': NAME_RE}))
+
+def interpolate(text, mapping):
+    """Interpolate ${keyword} substitutions."""
+    if not mapping:
+        return text
+    # Find all the spots we want to substitute.
+    to_replace = _interp_regex.findall(text)
+    # Now substitute with the variables in mapping.
+    for string in to_replace:
+        var = _get_var_regex.findall(string)[0]
+        text = text.replace(string, mapping.get(var))
+    return text
+
+
 class AltTALGenerator(TALGenerator):
 
     def __init__(self, repldict, expressionCompiler=None, xml=0):
@@ -338,7 +355,9 @@
                     ok = 0
                 value = evalue
         if msgid:
-            value = self.i18n_attribute(value)
+            xlated = self.i18n_attribute(value)
+            if xlated is not None:
+                value = xlated
         if value is None:
             value = name
         value = '%s="%s"' % (name, escape(value, 1))
@@ -348,6 +367,7 @@
     def i18n_attribute(self, s):
         # s is the value of an attribute before translation
         # it may have been computed
+        # This may return None if no translation is available.
         return self.translate(s, {})
 
     def no_tag(self, start, program):
@@ -518,25 +538,35 @@
         # subnodes, which should /not/ go to the output stream.
         tmpstream = self.StringIO()
         self.interpretWithStream(stuff[1], tmpstream)
+        content = None
         # We only care about the evaluated contents if we need an implicit
         # message id.  All other useful information will be in the i18ndict on
         # the top of the i18nStack.
         if msgid == '':
-            msgid = normalize(tmpstream.getvalue())
+            content = tmpstream.getvalue()
+            msgid = normalize(content)
         self.i18nStack.pop()
         # See if there is was an i18n:data for msgid
         if len(stuff) > 2:
             obj = self.engine.evaluate(stuff[2])
         xlated_msgid = self.translate(msgid, i18ndict, obj)
-        # XXX I can't decide whether we want to cgi escape the translated
-        # string or not.  OT1H not doing this could introduce a cross-site
-        # scripting vector by allowing translators to sneak JavaScript into
-        # translations.  OTOH, for implicit interpolation values, we don't
-        # want to escape stuff like ${name} <= "<b>Timmy</b>".
-        #s = escape(xlated_msgid)
-        s = xlated_msgid
+        # If there is no translation available, use evaluated content.
+        if xlated_msgid is None:
+            if content is None:
+                content = tmpstream.getvalue()
+            # We must do potential substitutions "by hand".
+            s = interpolate(content, i18ndict)
+        else:
+            # XXX I can't decide whether we want to cgi escape the translated
+            # string or not.  OT1H not doing this could introduce a cross-site
+            # scripting vector by allowing translators to sneak JavaScript into
+            # translations.  OTOH, for implicit interpolation values, we don't
+            # want to escape stuff like ${name} <= "<b>Timmy</b>".
+            #s = escape(xlated_msgid)
+            s = xlated_msgid
         # If there are i18n variables to interpolate into this string, better
         # do it now.
+        # XXX efge: actually, this is already done by the translation service.
         self._stream_write(s)
     bytecode_handlers['insertTranslation'] = do_insertTranslation