Edgewall Software

Opened 16 years ago

Closed 16 years ago

Last modified 12 years ago

#278 closed defect (fixed)

advanced-18n: an i18n:msg gets partially translated

Reported by: cboos Owned by: palgarvio
Priority: major Milestone: 0.6
Component: Internationalization Version: devel
Keywords: i18n:msg Cc: cboos@…

Description

This is with genshi's branches/experimental/advanced-i18n@966.

The following html snippet in a Trac template, added in [T7727]:

<div i18n:msg="">
        <label>View changes from <input type="text" size="10" name="from" value="${format_date(fromdate)}" /></label> <br />
        and <label><input type="text" size="3" name="daysback" value="$daysback" /> days back</label><br />
        <label>done by <input type="text" size="16" name="author" value="$author" /></label>
       </div>

gets extracted like that:

#: trac/timeline/templates/timeline.html:20
msgid ""
"[1:View changes from [2:]] [3:]\n"
"        and [4:[5:] days back][6:]\n"
"        [7:done by [8:]]"
msgstr ""
"[1:Afficher les modifications entre le : [2:]] [3:]\n"
"        et les : [4:[5:] jours précédents][6:]\n"
"        [7:Auteur : [8:]]"

The extraction seems to be correct.

But the translated text skips the "days back" (default language) or "jours précédents" (fr_FR) part.

The generated HTML is (in the default language):

<div><label>View changes from </label><input type="text" size="10" name="from" value="11/22/2008" /> <br /> 
        and <label><input type="text" size="3" name="daysback" value="30" /></label><br /> 
        <label>done by </label><input type="text" size="16" name="author" value="" /></div> 
       <fieldset> 
        <label> 
          <input type="checkbox" name="changeset" checked="checked" /> Repository checkins
        </label><label> 
          <input type="checkbox" name="milestone" checked="checked" /> Milestones
        </label><label> 
          <input type="checkbox" name="wiki" checked="checked" /> Wiki changes
        </label> 
       </fieldset> 
       <div class="buttons"> 
         <input type="submit" name="update" value="Update" /> 
       </div> 

(no "days back" on second line)

Attachments (2)

label_with_nested_input_failing_test_case.patch (1.9 KB) - added by palgarvio 16 years ago.
Testcase representing the failure.
label_with_nested_input_failing_test_case_and_possible_fix.patch (3.2 KB) - added by palgarvio 16 years ago.

Download all attachments as: .zip

Change History (25)

comment:1 Changed 16 years ago by cboos

  • Cc cboos@… added
  • Summary changed from advanced-18n: n i18n:msg gets partially translated to advanced-18n: an i18n:msg gets partially translated

comment:2 Changed 16 years ago by palgarvio

  • Owner changed from palgarvio to cmlenz
  • Version changed from 0.5.1 to devel

This seems to be non-related to the adavanced-i18n branch since the same happens with current trunk and is probably also related to the unfinished work on #129. Chris, how about this ticket, have an idea?

comment:3 Changed 16 years ago by palgarvio

  • Owner changed from cmlenz to palgarvio

Needed to reassign to cmlenz because I can't add him to CC directly.

comment:4 Changed 16 years ago by palgarvio

This can, although, be fixed on this branch since ticket #129 is also related to advanced i18n stuff, though that exact piece of code was cmlenz's work, he knows more about that part.

Either way, when I find the time, probably Friday, I'll have a deep look at it.

comment:5 Changed 16 years ago by palgarvio

A test just changing the place holders does not correct the issue:

  • genshi/filters/tests/i18n.py

     
    192192        tmpl.add_directives(Translator.NAMESPACE, translator)     
    193193        messages = list(translator.extract(tmpl.stream))         
    194194        self.assertEqual(1, len(messages))                       
    195         self.assertEqual('Please see [1:Help] for details.', messages[0][2])
     195        self.assertEqual('Please see {{1:Help}} for details.', messages[0][2])
    196196                                                                             
    197197    def test_translate_i18n_msg(self):                                       
    198198        tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
     
    201201            Please see <a href="help.html">Help</a> for details.             
    202202          </p>                                                               
    203203        </html>""")                                                           
    204         gettext = lambda s: u"Für Details siehe bitte [1:Hilfe]."             
     204        gettext = lambda s: u"Für Details siehe bitte {{1:Hilfe}}."           
    205205        translator = Translator(gettext)                                     
    206206        setup_i18n(tmpl, translator)                                         
    207207        self.assertEqual("""<html>                                           
     
    219219        tmpl.add_directives(Translator.NAMESPACE, translator)                 
    220220        messages = list(translator.extract(tmpl.stream))                     
    221221        self.assertEqual(1, len(messages))                                   
    222         self.assertEqual('Please see [1:[2:Help] page] for details.',         
     222        self.assertEqual('Please see {{1:{{2:Help}} page}} for details.',     
    223223                         messages[0][2])                                     
    224224                                                                             
    225225    def test_translate_i18n_msg_nested(self):                                 
     
    229229            Please see <a href="help.html"><em>Help</em> page</a> for details.
    230230          </p>                                                               
    231231        </html>""")                                                           
    232         gettext = lambda s: u"Für Details siehe bitte [1:[2:Hilfeseite]]."   
     232        gettext = lambda s: u"Für Details siehe bitte {{1:{{2:Hilfeseite}}}}."
    233233        translator = Translator(gettext)                                     
    234234        setup_i18n(tmpl, translator)                                         
    235235        self.assertEqual("""<html>                                           
     
    247247        tmpl.add_directives(Translator.NAMESPACE, translator)                 
    248248        messages = list(translator.extract(tmpl.stream))                     
    249249        self.assertEqual(1, len(messages))                                   
    250         self.assertEqual('Show me [1:] entries per page.', messages[0][2])   
     250        self.assertEqual('Show me {{1:}} entries per page.', messages[0][2]) 
    251251                                                                             
    252252    def test_translate_i18n_msg_empty(self):                                 
    253253        tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"
     
    256256            Show me <input type="text" name="num" /> entries per page.       
    257257          </p>                                                               
    258258        </html>""")                                                           
    259         gettext = lambda s: u"[1:] Einträge pro Seite anzeigen."             
     259        gettext = lambda s: u"{{1:}} Einträge pro Seite anzeigen."           
    260260        translator = Translator(gettext)                                     
    261261        setup_i18n(tmpl, translator)                                         
    262262        self.assertEqual("""<html>                                           
     
    274274        tmpl.add_directives(Translator.NAMESPACE, translator)                 
    275275        messages = list(translator.extract(tmpl.stream))                     
    276276        self.assertEqual(1, len(messages))                                   
    277         self.assertEqual('Please see [1:Help] for [2:details].', messages[0][2])
     277        self.assertEqual('Please see {{1:Help}} for {{2:details}}.', messages[0][2])
    278278                                                                                   
    279279    def test_translate_i18n_msg_multiple(self):                                     
    280280        tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"       
     
    283283            Please see <a href="help.html">Help</a> for <em>details</em>.           
    284284          </p>                                                                     
    285285        </html>""")                                                                 
    286         gettext = lambda s: u"Für [2:Details] siehe bitte [1:Hilfe]."               
     286        gettext = lambda s: u"Für {{2:Details}} siehe bitte {{1:Hilfe}}."           
    287287        translator = Translator(gettext)                                           
    288288        setup_i18n(tmpl, translator)                                               
    289289        self.assertEqual("""<html>                                                 
     
    301301        tmpl.add_directives(Translator.NAMESPACE, translator)                       
    302302        messages = list(translator.extract(tmpl.stream))                           
    303303        self.assertEqual(1, len(messages))                                         
    304         self.assertEqual('Show me [1:] entries per page, starting at page [2:].',   
     304        self.assertEqual('Show me {{1:}} entries per page, starting at page {{2:}}.',
    305305                         messages[0][2])                                             
    306306                                                                                     
    307307    def test_translate_i18n_msg_multiple_empty(self):                               
     
    311311            Show me <input type="text" name="num" /> entries per page, starting at page <input type="text" name="num" />.
    312312          </p>                                                                                                           
    313313        </html>""")                                                                                                     
    314         gettext = lambda s: u"[1:] Einträge pro Seite, beginnend auf Seite [2:]."                                       
     314        gettext = lambda s: u"{{1:}} Einträge pro Seite, beginnend auf Seite {{2:}}."                                   
    315315        translator = Translator(gettext)                                                                                 
    316316        setup_i18n(tmpl, translator)                                                                                     
    317317        self.assertEqual("""<html>                                                                                       
     
    366366            Hello, <a href="#${anchor}">dude</a>!                                                                       
    367367          </p>                                                                                                           
    368368        </html>""")                                                                                                     
    369         gettext = lambda s: u"Sei gegrüßt, [1:Alter]!"                                                                   
     369        gettext = lambda s: u"Sei gegrüßt, {{1:Alter}}!"                                                                 
    370370        translator = Translator(gettext)                                                                                 
    371371        setup_i18n(tmpl, translator)                                                                                     
    372372        self.assertEqual("""<html>                                                                                       
     
    415415        tmpl.add_directives(Translator.NAMESPACE, translator)                                                           
    416416        messages = list(translator.extract(tmpl.stream))                                                                 
    417417        self.assertEqual(1, len(messages))                                                                               
    418         self.assertEqual('Show me [1:] entries per page.', messages[0][2])                                               
     418        self.assertEqual('Show me {{1:}} entries per page.', messages[0][2])                                             
    419419                                                                                                                         
    420420    def test_translate_i18n_msg_with_directive(self):                                                                   
    421421        tmpl = MarkupTemplate("""<html xmlns:py="http://genshi.edgewall.org/"                                           
     
    424424            Show me <input type="text" name="num" py:attrs="{'value': 'x'}" /> entries per page.                         
    425425          </p>                                                                                                           
    426426        </html>""")                                                                                                     
    427         gettext = lambda s: u"[1:] Einträge pro Seite anzeigen."                                                         
     427        gettext = lambda s: u"{{1:}} Einträge pro Seite anzeigen."                                                       
    428428        translator = Translator(gettext)                                                                                 
    429429        setup_i18n(tmpl, translator)                                                                                     
    430430        self.assertEqual("""<html>                                                                                       
     
    11821182        tmpl.add_directives(Translator.NAMESPACE, translator)                                                           
    11831183        messages = list(translator.extract(tmpl.stream))                                                                 
    11841184        self.assertEqual(1, len(messages))                                                                               
    1185         self.assertEqual((3, None, u'Please see [1:Help] for details.', []),                                             
     1185        self.assertEqual((3, None, u'Please see {{1:Help}} for details.', []),                                           
    11861186                         messages[0])                                                                                   
    11871187                                                                                                                         
    11881188    def test_extract_i18n_msg_with_py_strip_and_comment(self):                                                           
     
    11961196        tmpl.add_directives(Translator.NAMESPACE, translator)                                                           
    11971197        messages = list(translator.extract(tmpl.stream))                                                                 
    11981198        self.assertEqual(1, len(messages))                                                                               
    1199         self.assertEqual((3, None, u'Please see [1:Help] for details.',                                                 
     1199        self.assertEqual((3, None, u'Please see {{1:Help}} for details.',                                               
    12001200                          ['Foo']), messages[0])                                                                         
    12011201                                                                                                                         
    12021202    def test_extract_i18n_choose_as_attribute_and_py_strip(self):                                                       
  • genshi/filters/i18n.py

    ===================================================================                                                       
     
    9292    >>>                                                                                                                 
    9393    >>> setup_i18n(tmpl, translator)                                                                                     
    9494    >>>                                                                                                                 
    95     >>> list(translator.extract(tmpl.stream))                                                                           
    96     [(2, None, u'[1:Foo]\n    [2:Bar]', []), (6, None, u'Foo [1:bar]!', [])]                                             
     95    >>> list(translator.extract(tmpl.stream)) #doctest: +NORMALIZE_WHITESPACE                                           
     96    [(2, None, u'{{1:Foo}}\n    {{2:Bar}}', []),                                                                         
     97    (6, None, u'Foo {{1:bar}}!', [])]                                                                                   
    9798    >>> print tmpl.generate().render()                                                                                   
    9899    <html>                                                                                                               
    99100      <div><p>Foo</p>                                                                                                   
     
    110111    ... </html>''')                                                                                                     
    111112    >>> setup_i18n(tmpl, translator)                                                                                     
    112113    >>> list(translator.extract(tmpl.stream)) #doctest: +NORMALIZE_WHITESPACE                                           
    113     [(2, None, u'[1:First Name: %(fname)s]\n    [2:Last Name: %(lname)s]', []),                                         
    114     (6, None, u'Foo [1:bar]!', [])]                                                                                      
     114    [(2, None, u'{{1:First Name: %(fname)s}}\n    {{2:Last Name: %(lname)s}}',                                          
     115    []), (6, None, u'Foo {{1:bar}}!', [])]                                                                               
    115116    >>>                                                                                                                 
    116117    >>> tmpl = MarkupTemplate('''<html xmlns:i18n="http://genshi.edgewall.org/i18n">                                     
    117118    ...   <div i18n:msg="fname, lname">                                                                                 
     
    985986            self.values[param] = (kind, data, pos)                                                                       
    986987        else:                                                                                                           
    987988            if kind is START:                                                                                           
    988                 self.string.append(u'[%d:' % self.order)                                                                
     989                self.string.append(u'{{%d:' % self.order)                                                               
    989990                self.events.setdefault(self.order, []).append((kind, data, pos))                                         
    990991                self.stack.append(self.order)                                                                           
    991992                self.depth += 1                                                                                         
     
    994995                self.depth -= 1
    995996                if self.depth:
    996997                    self.events[self.stack[-1]].append((kind, data, pos))
    997                     self.string.append(u']')
     998                    self.string.append(u'}}')
    998999                    self.stack.pop()
    9991000
    10001001    def format(self):
     
    10281029                        break
    10291030
    10301031
    1031 def parse_msg(string, regex=re.compile(r'(?:\[(\d+)\:)|\]')):
     1032def parse_msg(string, regex=re.compile(r'(?:\{\{(\d+)\:)|\}\}')):
    10321033    """Parse a translated message using Genshi mixed content message
    10331034    formatting.
    10341035
    1035     >>> parse_msg("See [1:Help].")
     1036    >>> parse_msg("See {{1:Help}}.")
    10361037    [(0, 'See '), (1, 'Help'), (0, '.')]
    10371038
    1038     >>> parse_msg("See [1:our [2:Help] page] for details.")
     1039    >>> parse_msg("See {{1:our {{2:Help}} page}} for details.")
    10391040    [(0, 'See '), (1, 'our '), (2, 'Help'), (1, ' page'), (0, ' for details.')]
    10401041
    1041     >>> parse_msg("[2:Details] finden Sie in [1:Hilfe].")
     1042    >>> parse_msg("{{2:Details}} finden Sie in {{1:Hilfe}}.")
    10421043    [(2, 'Details'), (0, ' finden Sie in '), (1, 'Hilfe'), (0, '.')]
    10431044
    1044     >>> parse_msg("[1:] Bilder pro Seite anzeigen.")
     1045    >>> parse_msg("{{1:}} Bilder pro Seite anzeigen.")
    10451046    [(1, ''), (0, ' Bilder pro Seite anzeigen.')]
    10461047
    10471048    :param string: the translated message string

This must then be related with the Message Buffer.

Changed 16 years ago by palgarvio

Testcase representing the failure.

comment:6 Changed 16 years ago by palgarvio

The above testcase mimics the failure you talk about.

What apparently happens is that since an input field does not hold any text like <a href="/foo">Foo</a> does, it's being neglected, let's see if I'm right.

comment:7 Changed 16 years ago by palgarvio

Could you please try the above fix to see if you find any more problems?

comment:8 Changed 16 years ago by cboos

Thanks for the patch, I'll test it soon.

comment:9 Changed 16 years ago by palgarvio

Updated the fix patch with a simpler version.

comment:10 follow-up: Changed 16 years ago by cboos

I confirm that the fix works (both patches), and it seems that there's no bad side-effects.

comment:11 in reply to: ↑ 10 Changed 16 years ago by palgarvio

  • Status changed from new to assigned

Replying to cboos:

I confirm that the fix works (both patches), and it seems that there's no bad side-effects.

Ok, I'll check these changes in, Thanks!

comment:12 Changed 16 years ago by palgarvio

  • Resolution set to fixed
  • Status changed from assigned to closed

Fixed in [967].

comment:13 follow-up: Changed 16 years ago by cboos

  • Resolution fixed deleted
  • Status changed from closed to reopened

I've seen it again today with [T8107], when running advanced-i18n at r1028.

The following translation:

#: trac/templates/error.html:131
msgid ""
"Before you do that, though, please first try\n"
"                [1:[2:searching]\n"
"                for similar issues], as it is quite likely that this "
"problem\n"
"                has been reported before. For questions about "
"installation\n"
"                and configuration of Trac, please try the\n"
"                [3:mailing list]\n"
"                instead of filing a ticket."
msgstr ""
"Avant de faire cela, [1:veuillez au préalable essayer de\n"
"                [2:trouver]\n"
"                d'éventuels rapports similaires], car il est probable que"
" ce problème\n"
"                ait déjà été reporté. Pour des questions concernant "
"l'installation\n"
"                et la configuration de Trac, veuillez utiliser la\n"
"                [3:liste de diffusion]\n"
"                plutôt que de créer un ticket."

appears like this in the generated HTML:

Avant de faire cela, veuillez au préalable essayer de trouver, car il est probable que ce problème ...

i.e. d'éventuels rapports similaires is missing.

The untranslated string is displayed correctly, with r1028.

What is eventually interesting is that with r966, the untranslated string becomes:

Before you do that, though, please first try searching, as it is quite likely 

i.e. for similar issues is missing here as well.

comment:14 in reply to: ↑ 13 Changed 16 years ago by cboos

Replying to cboos:

I've seen it again today with [T8107],

Sorry, I meant [T8108].

comment:15 follow-up: Changed 16 years ago by cboos

The comment:13 issue is still present with [1057].

comment:16 in reply to: ↑ 15 Changed 16 years ago by palgarvio

Replying to cboos:

The comment:13 issue is still present with [1057].

Hmm, I'm unable to confirm the issue, for me it renders well. The catalog part, for pt_PT:

#: trac/timeline/templates/timeline.html:20
msgid ""
"[1:View changes from [2:]] [3:]\n"
"        and [4:[5:] days back][6:]\n"
"        [7:done by [8:]]"
msgstr ""
"[1:Ver mudanças desde [2:]] [3:]\n"
"        e à [4:[5:] dias atrás][6:]\n"
"        [7:feitas por [8:]]"

The rendered html:

<label>Ver mudanças desde </label><input size="10" name="from" value="13/05/09" type="text"> <br>
        e à <label><input size="3" name="daysback" value="30" type="text"> dias atrás</label><br>
        <label>feitas por </label><input size="16" name="authors" value="" type="text">

For the fr_FR locale:

<label>Afficher les modifications entre le </label><input size="10" name="from" value="13/05/09" type="text"> <br>
        et les <label><input size="3" name="daysback" value="30" type="text"> jours précédents</label><br>
        <label>Auteur&nbsp;: </label><input size="16" name="authors" value="" type="text">

Which also appears correct.

Did you re-{extracted/updated/compiled} the French catalog?

comment:17 Changed 16 years ago by palgarvio

I'm on [T8197].

comment:18 Changed 16 years ago by palgarvio

cboos can this be closed?

comment:19 follow-up: Changed 16 years ago by cboos

Well, in comment:16 you just tried the specific example shown in the original description, and this is indeed working fine now.

But I reopened the ticket because I detected a very similar problem elsewhere, please read comment:13, and I definitely still have that problem with latest Trac [T8199], [G1057], Babel 0.9.4 and Python 2.6.

I noticed that the structure of the embedding is slightly different in the translation than in the original, for the French translation:

English:

text \n [1:[2: text ] \n text ] text \n ...

French:

text [1: text [2: text ] \n text ] text \n ...

Is this allowed? (I hope so). Could that be the problem?

comment:20 Changed 16 years ago by cboos

(and it also still happens with [1058])

comment:21 in reply to: ↑ 19 Changed 16 years ago by palgarvio

Replying to cboos:

Well, in comment:16 you just tried the specific example shown in the original description, and this is indeed working fine now.

But I reopened the ticket because I detected a very similar problem elsewhere, please read comment:13, and I definitely still have that problem with latest Trac [T8199], [G1057], Babel 0.9.4 and Python 2.6.

I noticed that the structure of the embedding is slightly different in the translation than in the original, .....

Is this allowed? (I hope so). Could that be the problem?

Yes, the problem is the restructure of the phrase. I'll see if I can get MessageBuffer to handle that though.

comment:22 Changed 16 years ago by palgarvio

  • Resolution set to fixed
  • Status changed from reopened to closed

Fixed in [1059].

comment:23 Changed 16 years ago by cboos

Verified, thanks!

Note: See TracTickets for help on using tickets.