[Zope3-checkins] SVN: Zope3/trunk/ Fixed issue 301: Bug with i18n:name and i18n:translate on the same element

Dmitry Vasiliev dima at hlabs.spb.ru
Mon May 2 07:05:28 EDT 2005


Log message for revision 30226:
  Fixed issue 301: Bug with i18n:name and i18n:translate on the same element
  

Changed:
  U   Zope3/trunk/doc/CHANGES.txt
  U   Zope3/trunk/src/zope/tal/talgenerator.py
  U   Zope3/trunk/src/zope/tal/tests/input/test22.html
  U   Zope3/trunk/src/zope/tal/tests/input/test28.html
  U   Zope3/trunk/src/zope/tal/tests/input/test31.html
  U   Zope3/trunk/src/zope/tal/tests/input/test36.html
  U   Zope3/trunk/src/zope/tal/tests/output/test29.html
  U   Zope3/trunk/src/zope/tal/tests/test_htmltalparser.py
  U   Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py

-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/doc/CHANGES.txt	2005-05-02 11:05:28 UTC (rev 30226)
@@ -591,6 +591,9 @@
 
     Bug Fixes
 
+      - Fixed issue #301: Bug with i18n:name and i18n:translate
+        on the same element
+
       - The interface directive supports multiple interface types now.
 
       - Fixed issue #314: i18n:translate removes line breaks

Modified: Zope3/trunk/src/zope/tal/talgenerator.py
===================================================================
--- Zope3/trunk/src/zope/tal/talgenerator.py	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/talgenerator.py	2005-05-02 11:05:28 UTC (rev 30226)
@@ -24,9 +24,8 @@
 from zope.tal.taldefs import parseSubstitution
 from zope.tal.translationcontext import TranslationContext, DEFAULT_DOMAIN
 
-I18N_REPLACE = 1
-I18N_CONTENT = 2
-I18N_EXPRESSION = 3
+I18N_CONTENT = 1
+I18N_EXPRESSION = 2
 
 _name_rx = re.compile(NAME_RE)
 
@@ -330,20 +329,11 @@
             raise TALError("illegal i18n:name: %r" % varname, self.position)
         key = cexpr = None
         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
+        if action == I18N_EXPRESSION:
             key, expr = parseSubstitution(expression)
             cexpr = self.compileExpression(expr)
+        else:
+            assert action == I18N_CONTENT
         self.emit('i18nVariable',
                   varname, program, cexpr, int(key == "structure"))
 
@@ -659,7 +649,7 @@
         # i18n:name w/o tal:replace uses the content as the interpolation
         # dictionary values
         elif varname:
-            todo['i18nvar'] = (varname, I18N_REPLACE, None)
+            todo['i18nvar'] = (varname, I18N_CONTENT, None)
             self.pushProgram()
         if msgid is not None:
             self.i18nLevel += 1
@@ -793,16 +783,14 @@
         elif varname:
             # o varname[0] is the variable name
             # o varname[1] is either
-            #   - I18N_REPLACE for implicit tal:replace
             #   - I18N_CONTENT for tal:content
             #   - I18N_EXPRESSION for explicit tal:replace
-            # o varname[2] will be None for the first two actions and the
-            #   replacement tal expression for the third action.  This
+            # o varname[2] will be None for the first action and the
+            #   replacement tal expression for the second action.  This
             #   can include a 'text' or 'structure' indicator.
-            assert (varname[1]
-                    in [I18N_REPLACE, I18N_CONTENT, I18N_EXPRESSION])
+            assert (varname[1] in (I18N_CONTENT, I18N_EXPRESSION))
             self.emitI18nVariable(varname)
-        # Do not test for "msgid is not None", i.e. we only want to test for
+        # Do 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:
             # in case tal:content, i18n:translate and i18n:name in the

Modified: Zope3/trunk/src/zope/tal/tests/input/test22.html
===================================================================
--- Zope3/trunk/src/zope/tal/tests/input/test22.html	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/tests/input/test22.html	2005-05-02 11:05:28 UTC (rev 30226)
@@ -1,4 +1,4 @@
 <span i18n:translate="">
-  <span i18n:name="name"><b>Jim</b></span> was born in
-  <span i18n:name="country">the USA</span>.
+  <span tal:omit-tag="" i18n:name="name"><b>Jim</b></span> was born in
+  <span tal:omit-tag="" i18n:name="country">the USA</span>.
 </span>

Modified: Zope3/trunk/src/zope/tal/tests/input/test28.html
===================================================================
--- Zope3/trunk/src/zope/tal/tests/input/test28.html	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/tests/input/test28.html	2005-05-02 11:05:28 UTC (rev 30226)
@@ -1,5 +1,5 @@
 <p i18n:translate="verify">Your contact email address is recorded as
-    <span i18n:name="email">
+    <span tal:omit-tag="" i18n:name="email">
     <a href="mailto:user at example.com"
        tal:content="request/submitter">user at host.com</a></span>
 </p>

Modified: Zope3/trunk/src/zope/tal/tests/input/test31.html
===================================================================
--- Zope3/trunk/src/zope/tal/tests/input/test31.html	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/tests/input/test31.html	2005-05-02 11:05:28 UTC (rev 30226)
@@ -1,5 +1,5 @@
 <p i18n:translate="verify">Your contact email address is recorded as
-<span i18n:name="email">
+<span tal:omit-tag="" i18n:name="email">
 <a href="user at host.com"
    tal:attributes="href string:mailto:${request/submitter}"
    tal:content="request/submitter">

Modified: Zope3/trunk/src/zope/tal/tests/input/test36.html
===================================================================
--- Zope3/trunk/src/zope/tal/tests/input/test36.html	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/tests/input/test36.html	2005-05-02 11:05:28 UTC (rev 30226)
@@ -2,5 +2,5 @@
 <span i18n:translate="">
   <span tal:replace="string:<foo>" i18n:name="name1" />
   <span tal:replace="structure string:<bar />" i18n:name="name2" />
-  <span i18n:name="name3"><b>some</b> <i>text</i></span>
+  <span tal:omit-tag="" i18n:name="name3"><b>some</b> <i>text</i></span>
 </span>

Modified: Zope3/trunk/src/zope/tal/tests/output/test29.html
===================================================================
--- Zope3/trunk/src/zope/tal/tests/output/test29.html	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/tests/output/test29.html	2005-05-02 11:05:28 UTC (rev 30226)
@@ -1 +1 @@
-<div>AT THE TONE THE TIME WILL BE 59 MINUTES AFTER 6 PM... BEEP!</div>
+<div>AT THE TONE THE TIME WILL BE <span>59 minutes after 6 PM</span>... BEEP!</div>

Modified: Zope3/trunk/src/zope/tal/tests/test_htmltalparser.py
===================================================================
--- Zope3/trunk/src/zope/tal/tests/test_htmltalparser.py	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/tests/test_htmltalparser.py	2005-05-02 11:05:28 UTC (rev 30226)
@@ -693,29 +693,55 @@
         # input/test22.html
         self._run_check('''\
 <span i18n:translate="">
-  <span i18n:name="name"><b>Jim</b></span> was born in
-  <span i18n:name="country">the USA</span>.
+  <span tal:omit-tag="" i18n:name="name"><b>Jim</b></span> was born in
+  <span tal:omit-tag="" i18n:name="country">the USA</span>.
 </span>
-''', [
-  ('setPosition', (1, 0)),
-  ('beginScope', {'i18n:translate': ''}),
-  ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
-  ('insertTranslation',
-   ('',
-    [('rawtextBeginScope', ('\n  ', 2, (2, 2), 0, {'i18n:name': 'name'})),
-     ('i18nVariable',
-      ('name',
-       [('rawtextOffset', ('<b>Jim</b>', 10))], None, 0)),
-     ('rawtextBeginScope',
-      (' was born in\n  ', 2, (3, 2), 1, {'i18n:name': 'country'})),
-     ('i18nVariable',
-      ('country',
-       [('rawtextOffset', ('the USA', 7))], None, 0)),
-     ('endScope', ()),
-     ('rawtextColumn', ('.\n', 0))])),
-  ('endScope', ()),
-  ('rawtextColumn', ('</span>\n', 0))
-  ])
+''', [('setPosition', (1, 0)),
+ ('beginScope', {'i18n:translate': ''}),
+ ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+  ('',
+   [('rawtextBeginScope',
+     ('\n  ', 2, (2, 2), 0, {'i18n:name': 'name', 'tal:omit-tag': ''})),
+    ('i18nVariable',
+     ('name',
+      [('optTag',
+        ('span',
+         '',
+         None,
+         0,
+         [('startTag',
+           ('span',
+            [('tal:omit-tag', '', 'tal'),
+             ('i18n:name', 'name', 'i18n')]))],
+         [('rawtextOffset', ('<b>Jim</b>', 10))]))],
+      None,
+      0)),
+    ('rawtextBeginScope',
+     (' was born in\n  ',
+      2,
+      (3, 2),
+      1,
+      {'i18n:name': 'country', 'tal:omit-tag': ''})),
+    ('i18nVariable',
+     ('country',
+      [('optTag',
+        ('span',
+         '',
+         None,
+         0,
+         [('startTag',
+           ('span',
+            [('tal:omit-tag', '', 'tal'),
+             ('i18n:name', 'country', 'i18n')]))],
+         [('rawtextOffset', ('the USA', 7))]))],
+      None,
+      0)),
+    ('endScope', ()),
+    ('rawtextColumn', ('.\n', 0))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</span>\n', 0))
+ ])
 
     def test_i18n_context_domain(self):
         self._run_check("<span i18n:domain='mydomain'/>", [
@@ -804,8 +830,7 @@
 <span i18n:data="here/currentTime"
       i18n:translate="timefmt"
       i18n:name="time">2:32 pm</span>... beep!</div>
-''',
-[('setPosition', (1, 0)),
+''', [('setPosition', (1, 0)),
  ('beginScope', {'i18n:translate': ''}),
  ('startTag', ('div', [('i18n:translate', '', 'i18n')])),
  ('insertTranslation',
@@ -818,100 +843,79 @@
       {'i18n:data': 'here/currentTime',
        'i18n:name': 'time',
        'i18n:translate': 'timefmt'})),
-    ('insertTranslation',
-     ('timefmt',
+    ('i18nVariable',
+     ('time',
       [('startTag',
         ('span',
          [('i18n:data', 'here/currentTime', 'i18n'),
           ('i18n:translate', 'timefmt', 'i18n'),
           ('i18n:name', 'time', 'i18n')])),
-       ('i18nVariable', ('time', [], None, 0))],
-      '$here/currentTime$')),
+       ('insertTranslation',
+        ('timefmt',
+         [('rawtextOffset', ('2:32 pm', 7))],
+         '$here/currentTime$')),
+       ('rawtextOffset', ('</span>', 7))],
+      None,
+      0)),
     ('endScope', ()),
     ('rawtextOffset', ('... beep!', 9))])),
  ('endScope', ()),
- ('rawtextColumn', ('</div>\n', 0))]
-)
+ ('rawtextColumn', ('</div>\n', 0))
+ ])
 
- 
-    def test_i18n_explicit_msgid_with_name(self):
-        # input/test26.html
-        self._run_check('''\
-<span i18n:translate="jobnum">
-    Job #<span tal:replace="context/@@object_name"
-               i18n:name="jobnum">NN</span></span>
-''', [
-  ('setPosition', (1, 0)),
-  ('beginScope', {'i18n:translate': 'jobnum'}),
-  ('startTag', ('span', [('i18n:translate', 'jobnum', 'i18n')])),
-  ('insertTranslation',
-   ('jobnum',
-    [('rawtextBeginScope',
-      ('\n    Job #',
-       9,
-       (2, 9),
-       0,
-       {'i18n:name': 'jobnum', 'tal:replace': 'context/@@object_name'})),
-     ('i18nVariable',
-      ('jobnum',
-       [('startTag',
-         ('span',
-          [('tal:replace', 'context/@@object_name', 'tal'),
-           ('i18n:name', 'jobnum', 'i18n')])),
-        ('rawtextOffset', ('NN', 2)),
-        ('rawtextOffset', ('</span>', 7))],
-       '$context/@@object_name$',
-       0)),
-     ('endScope', ())])),
-  ('endScope', ()),
-  ('rawtextColumn', ('</span>\n', 0))
-  ])
-
     def test_i18n_name_around_tal_content(self):
         # input/test28.html
         self._run_check('''\
 <p i18n:translate="verify">Your contact email address is recorded as
-    <span i18n:name="email">
+    <span tal:omit-tag="" i18n:name="email">
     <a href="mailto:user at example.com"
        tal:content="request/submitter">user at host.com</a></span>
 </p>
-''', [
-  ('setPosition', (1, 0)),
-  ('beginScope', {'i18n:translate': 'verify'}),
-  ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])),
-  ('insertTranslation',
-   ('verify',
-    [('rawtextBeginScope',
-      ('Your contact email address is recorded as\n    ',
-       4,
-       (2, 4),
-       0,
-       {'i18n:name': 'email'})),
-     ('i18nVariable',
-      ('email',
-       [('rawtextBeginScope',
-         ('\n    ',
-          4,
-          (3, 4),
-          0,
-          {'href': 'mailto:user at example.com',
-           'tal:content': 'request/submitter'})),
-        ('startTag',
-         ('a',
-          [('href', 'href="mailto:user at example.com"'),
-           ('tal:content', 'request/submitter', 'tal')])),
-        ('insertText',
-         ('$request/submitter$',
-          [('rawtextOffset', ('user at host.com', 13))])),
-        ('endScope', ()),
-        ('rawtextOffset', ('</a>', 4))],
-       None,
-       0)),
-     ('endScope', ()),
-     ('rawtextColumn', ('\n', 0))])),
-  ('endScope', ()),
-  ('rawtextColumn', ('</p>\n', 0))
-  ])
+''', [('setPosition', (1, 0)),
+ ('beginScope', {'i18n:translate': 'verify'}),
+ ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])),
+ ('insertTranslation',
+  ('verify',
+   [('rawtextBeginScope',
+     ('Your contact email address is recorded as\n    ',
+      4,
+      (2, 4),
+      0,
+      {'i18n:name': 'email', 'tal:omit-tag': ''})),
+    ('i18nVariable',
+     ('email',
+      [('optTag',
+        ('span',
+         '',
+         None,
+         0,
+         [('startTag',
+           ('span',
+            [('tal:omit-tag', '', 'tal'),
+             ('i18n:name', 'email', 'i18n')]))],
+         [('rawtextBeginScope',
+           ('\n    ',
+            4,
+            (3, 4),
+            0,
+            {'href': 'mailto:user at example.com',
+             'tal:content': 'request/submitter'})),
+          ('startTag',
+           ('a',
+            [('href', 'href="mailto:user at example.com"'),
+             ('tal:content', 'request/submitter', 'tal')])),
+          ('insertText',
+           ('$request/submitter$',
+            [('rawtextOffset', ('user at host.com', 13))])),
+          ('endScope', ()),
+          ('rawtextOffset', ('</a>', 4))]))],
+      None,
+      0)),
+    ('endScope', ()),
+    ('rawtextColumn', ('\n', 0))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</p>\n', 0))
+ ])
 
     def test_i18n_name_with_tal_content(self):
         # input/test27.html

Modified: Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py
===================================================================
--- Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py	2005-05-02 10:53:40 UTC (rev 30225)
+++ Zope3/trunk/src/zope/tal/tests/test_talinterpreter.py	2005-05-02 11:05:28 UTC (rev 30226)
@@ -195,7 +195,7 @@
     def test_complex_replace_with_messageid_and_i18nname(self):
         program, macros = self._compile(
             '<div i18n:translate="" >'
-            '<em i18n:name="foo_name">'
+            '<em tal:omit-tag="" i18n:name="foo_name">'
             '<span tal:replace="foo"/>'
             '</em>'
             '</div>')
@@ -267,7 +267,7 @@
 
             def translate(self, msgid, mapping=None,
                           context=None, target_language=None, default=None):
-                self.data.append(msgid)
+                self.data.append((msgid, mapping))
                 return DummyTranslationDomain.translate(
                     self,
                     msgid, mapping, context, target_language, default)
@@ -286,13 +286,38 @@
         self.interpreter = TALInterpreter(program, {}, self.engine,
                                           stream=result)
         self.interpreter()
-        self.assert_('BaRvAlUe' in xlatdmn.data)
-        self.assert_('This is text for ${bar_name}.' in
-                     xlatdmn.data)
+        msgids = list(xlatdmn.data)
+        msgids.sort()
+        self.assertEqual(2, len(msgids))
+        self.assertEqual('BaRvAlUe', msgids[0][0])
+        self.assertEqual('This is text for ${bar_name}.', msgids[1][0])
+        self.assertEqual({'bar_name': '<span>BARVALUE</span>'}, msgids[1][1])
         self.assertEqual(
             '<div>THIS IS TEXT FOR <span>BARVALUE</span>.</div>\n',
             result.getvalue())
 
+    def test_i18ntranslate_i18nname_and_attributes(self):
+        # Test for Issue 301: Bug with i18n:name and i18n:translate
+        # on the same element
+        xlatdmn = self._getCollectingTranslationDomain()
+        result = StringIO()
+        program, macros = self._compile(
+            '<p i18n:translate="">'
+            'Some static text and a <a tal:attributes="href string:url"'
+            ' i18n:name="link" i18n:translate="">link text</a>.</p>')
+        self.interpreter = TALInterpreter(program, {}, self.engine,
+                                          stream=result)
+        self.interpreter()
+        msgids = list(xlatdmn.data)
+        msgids.sort()
+        self.assertEqual(2, len(msgids))
+        self.assertEqual('Some static text and a ${link}.', msgids[0][0])
+        self.assertEqual({'link': '<a href="url">LINK TEXT</a>'}, msgids[0][1])
+        self.assertEqual('link text', msgids[1][0])
+        self.assertEqual(
+            '<p>SOME STATIC TEXT AND A <a href="url">LINK TEXT</a>.</p>\n',
+            result.getvalue())
+
     def test_for_raw_msgids(self):
         # Test for Issue 314: i18n:translate removes line breaks from
         # <pre>...</pre> contents
@@ -307,9 +332,11 @@
         self.interpreter = TALInterpreter(program, {}, self.engine,
                                           stream=result)
         self.interpreter()
-        self.assert_('This is text for div.' in xlatdmn.data)
-        self.assert_(' This is text\n <b>\tfor</b>\n pre. ' in
-                     xlatdmn.data)
+        msgids = list(xlatdmn.data)
+        msgids.sort()
+        self.assertEqual(2, len(msgids))
+        self.assertEqual(' This is text\n <b>\tfor</b>\n pre. ', msgids[0][0])
+        self.assertEqual('This is text for div.', msgids[1][0])
         self.assertEqual(
             '<div>THIS IS TEXT FOR DIV.</div>'
             '<pre> THIS IS TEXT\n <B>\tFOR</B>\n PRE. </pre>\n',
@@ -328,8 +355,10 @@
         self.interpreter = TALInterpreter(program, {}, self.engine,
                                           stream=result)
         self.interpreter()
-        self.assert_('This is text <b> for</b> barvalue.' in
-                     xlatdmn.data)
+        msgids = list(xlatdmn.data)
+        msgids.sort()
+        self.assertEqual(1, len(msgids))
+        self.assertEqual('This is text <b> for</b> barvalue.', msgids[0][0])
         self.assertEqual(
             '<?xml version="1.0"?>\n'
             '<pre>THIS IS TEXT <B> FOR</B> BARVALUE.</pre>\n',



More information about the Zope3-Checkins mailing list