Commits

Takayuki Shimizukawa  committed 9bfb539

fix: keep reference if link refname was translated. refs #1193

case1::

Keep link to ExternalSite_.

It will translated with ``\`SomeOtherString\`_``.

.. _ExternalSite: http://example.com

case2::

Keep link to `title string`_ before appearing.

title string
=============

case3::

Keep link to glossary 'term string'.

.. glossary::

term string
description...

  • Participants
  • Parent commits 0d93d51

Comments (0)

Files changed (3)

File sphinx/domains/std.py

         return title, target
 
 
-def make_termnodes_from_paragraph_node(env, node):
+def make_termnodes_from_paragraph_node(env, node, new_id=None):
     gloss_entries = env.temp_data.setdefault('gloss_entries', set())
     objects = env.domaindata['std']['objects']
 
     termtext = node.astext()
-    new_id = 'term-' + nodes.make_id(termtext)
+    if new_id is None:
+        new_id = 'term-' + nodes.make_id(termtext)
     if new_id in gloss_entries:
         new_id = 'term-' + str(len(gloss_entries))
     gloss_entries.add(new_id)

File sphinx/transforms.py

 
         parser = RSTParser()
 
+        #phase1: replace reference ids with translated names
         for node, msg in extract_messages(self.document):
             msgstr = catalog.gettext(msg)
             # XXX add marker to untranslated parts
             if not isinstance(patch, nodes.paragraph):
                 continue # skip for now
 
+            processed = False  # skip flag
+
             # update title(section) target name-id mapping
             if isinstance(node, nodes.title):
                 section_node = node.parent
                     _type = self.document.nametypes.pop(old_name, None)
                     self.document.set_name_id_map(
                             section_node, _id, section_node, explicit=_type)
+                    processed = True
+
+            # glossary terms update refid
+            if isinstance(node, nodes.term):
+                gloss_entries = env.temp_data.setdefault('gloss_entries', set())
+                ids = []
+                termnodes = []
+                for _id in node['names']:
+                    if _id in gloss_entries:
+                        gloss_entries.remove(_id)
+                    _id, _, new_termnodes = \
+                        make_termnodes_from_paragraph_node(env, patch, _id)
+                    ids.append(_id)
+                    termnodes.extend(new_termnodes)
+
+                if termnodes and ids:
+                    patch = make_term_from_paragraph_node(termnodes, ids)
+                    node['ids'] = patch['ids']
+                    node['names'] = patch['names']
+                    processed = True
+
+            # update leaves with processed nodes
+            if processed:
+                for child in patch.children:
+                    child.parent = node
+                node.children = patch.children
+                node['translated'] = True
+
+
+        #phase2: translation
+        for node, msg in extract_messages(self.document):
+            if node.get('translated', False):
+                continue
+
+            msgstr = catalog.gettext(msg)
+            # XXX add marker to untranslated parts
+            if not msgstr or msgstr == msg: # as-of-yet untranslated
+                continue
+
+            # Avoid "Literal block expected; none found." warnings.
+            # If msgstr ends with '::' then it cause warning message at
+            # parser.parse() processing.
+            # literal-block-warning is only appear in avobe case.
+            if msgstr.strip().endswith('::'):
+                msgstr += '\n\n   dummy literal'
+                # dummy literal node will discard by 'patch = patch[0]'
+
+            patch = new_document(source, settings)
+            CustomLocaleReporter(node.source, node.line).set_reporter(patch)
+            parser.parse(msgstr, patch)
+            patch = patch[0]
+            # XXX doctest and other block markup
+            if not isinstance(patch, nodes.paragraph):
+                continue # skip for now
 
             # auto-numbered foot note reference should use original 'ids'.
             def is_autonumber_footnote_ref(node):
             if len(old_refs) != len(new_refs):
                 env.warn_node('inconsistent references in '
                               'translated message', node)
+            old_ref_names = [r['refname'] for r in old_refs]
+            new_ref_names = [r['refname'] for r in new_refs]
+            orphans = list(set(old_ref_names) - set(new_ref_names))
             for new in new_refs:
+                if not self.document.has_name(new['refname']):
+                    # Maybe refname is translated but target is not translated.
+                    # Note: multiple translated refnames break link ordering.
+                    if orphans:
+                        new['refname'] = orphans.pop(0)
+                    else:
+                        # orphan refnames is already empty!
+                        # reference number is same in new_refs and old_refs.
+                        pass
+
                 self.document.note_refname(new)
 
             # refnamed footnote and citation should use original 'ids'.
                 if refname in refname_ids_map:
                     new["ids"] = refname_ids_map[refname]
 
-            # glossary terms update refid
-            if isinstance(node, nodes.term):
-                new_id, _, termnodes = \
-                    make_termnodes_from_paragraph_node(env, patch)
-                term = make_term_from_paragraph_node(
-                        termnodes, [new_id])
-                patch = term
-                node['ids'] = patch['ids']
-                node['names'] = patch['names']
-
             # Original pending_xref['reftarget'] contain not-translated
             # target name, new pending_xref must use original one.
             # This code restricts to change ref-targets in the translation.
             for child in patch.children:
                 child.parent = node
             node.children = patch.children
+            node['translated'] = True
 
         # Extract and translate messages for index entries.
         for node, entries in traverse_translatable_index(self.document):

File tests/test_intl.py

              'SOME NEW TERM', '.'],
             ['i18n-role-xref',
              'contents',
-             'glossary_terms#term-some-new-term'])
+             'glossary_terms#term-some-term'])
 
     para2 = sec2.findall('paragraph')
     assert_elem_text_refs(
             para2[0],
             ['LINK TO', 'SOME OTHER NEW TERM', 'AND', 'SOME NEW TERM', '.'],
-            ['glossary_terms#term-some-other-new-term',
-             'glossary_terms#term-some-new-term'])
+            ['glossary_terms#term-some-other-term',
+             'glossary_terms#term-some-term'])
     assert_elem_text_refs(
             para2[1],
             ['LINK TO', 'SAME TYPE LINKS', 'AND', "I18N ROCK'N ROLE XREF", '.'],