Georg Brandl avatar Georg Brandl committed 6827970 Merge

Merged in knzm/sphinx-fix-backlink-fork (pull request #97: fix #1058 Footnote backlinks do not work)

Comments (0)

Files changed (5)

sphinx/environment.py

         for citnode in self.document.traverse(nodes.citation_reference):
             cittext = citnode.astext()
             refnode = addnodes.pending_xref(cittext, reftype='citation',
-                                            reftarget=cittext, refwarn=True)
+                                            reftarget=cittext, refwarn=True,
+                                            ids=citnode["ids"])
             refnode.line = citnode.line or citnode.parent.line
             refnode += nodes.Text('[' + cittext + ']')
             citnode.parent.replace(citnode, refnode)
                 continue # skip for now
 
             # auto-numbered foot note reference should use original 'ids'.
-            is_autonumber_footnote_ref = lambda node: \
-                    isinstance(node, nodes.footnote_reference) \
-                    and node.get('auto') == 1
+            def is_autonumber_footnote_ref(node):
+                return isinstance(node, nodes.footnote_reference) and \
+                    node.get('auto') == 1
             old_foot_refs = node.traverse(is_autonumber_footnote_ref)
             new_foot_refs = patch.traverse(is_autonumber_footnote_ref)
             if len(old_foot_refs) != len(new_foot_refs):
             # * reference target ".. _Python: ..." is not translatable.
             # * section refname is not translatable.
             # * inline reference "`Python <...>`_" has no 'refname'.
-            is_refnamed_ref = lambda node: \
-                    isinstance(node, nodes.reference) \
-                    and 'refname' in node
+            def is_refnamed_ref(node):
+                return isinstance(node, nodes.reference) and  \
+                    'refname' in node
             old_refs = node.traverse(is_refnamed_ref)
             new_refs = patch.traverse(is_refnamed_ref)
             applied_refname_map = {}
 
                 self.document.note_refname(new)
 
+            # refnamed footnote and citation should use original 'ids'.
+            def is_refnamed_footnote_ref(node):
+                footnote_ref_classes = (nodes.footnote_reference,
+                                        nodes.citation_reference)
+                return isinstance(node, footnote_ref_classes) and \
+                    'refname' in node
+            old_refs = node.traverse(is_refnamed_footnote_ref)
+            new_refs = patch.traverse(is_refnamed_footnote_ref)
+            refname_ids_map = {}
+            if len(old_refs) != len(new_refs):
+                env.warn_node('inconsistent references in '
+                              'translated message', node)
+            for old in old_refs:
+                refname_ids_map[old["refname"]] = old["ids"]
+            for new in new_refs:
+                refname = new["refname"]
+                if refname in refname_ids_map:
+                    new["ids"] = refname_ids_map[refname]
+
             # update leaves
             for child in patch.children:
                 child.parent = node

tests/root/contents.txt

    extensions
    versioning/index
    only
+   footnote
    i18n/index
 
    Python <http://python.org/>

tests/root/footnote.txt

+:tocdepth: 2
+
+Testing footnote and citation
+================================
+.. #1058 footnote-backlinks-do-not-work
+
+numbered footnote
+--------------------
+
+[1]_
+
+auto-numbered footnote
+------------------------------
+
+[#]_
+
+named footnote
+--------------------
+
+[#foo]_
+
+citation
+--------------------
+
+[bar]_
+
+footenotes
+--------------------
+
+.. rubric:: Footnotes
+
+.. [1] numbered
+
+.. [#] auto numbered
+
+.. [#foo] named
+
+.. rubric:: Citations
+
+.. [bar] cite

tests/test_footnote.py

+# -*- coding: utf-8 -*-
+"""
+    test_footnote
+    ~~~~~~~~~~~~~
+
+    Test for footnote and citation.
+
+    :copyright: Copyright 2010 by the Sphinx team, see AUTHORS.
+    :license: BSD, see LICENSE for details.
+"""
+
+import re
+
+from util import *
+
+
+def teardown_module():
+    (test_root / '_build').rmtree(True)
+
+
+@with_app(buildername='html')
+def test_html(app):
+    app.builder.build(['footnote'])
+    result = (app.outdir / 'footnote.html').text(encoding='utf-8')
+    expects = [
+        '<a class="footnote-reference" href="#id5" id="id1">[1]</a>',
+        '<a class="footnote-reference" href="#id6" id="id2">[2]</a>',
+        '<a class="footnote-reference" href="#foo" id="id3">[3]</a>',
+        '<a class="reference internal" href="#bar" id="id4">[bar]</a>',
+        '<a class="fn-backref" href="#id1">[1]</a>',
+        '<a class="fn-backref" href="#id2">[2]</a>',
+        '<a class="fn-backref" href="#id3">[3]</a>',
+        '<a class="fn-backref" href="#id4">[bar]</a>',
+        ]
+    for expect in expects:
+        matches = re.findall(re.escape(expect), result)
+        assert len(matches) == 1

tests/test_intl.py

     assert result == expect
 
 
+@with_app(buildername='html', cleanenv=True,
+          confoverrides={'language': 'xx', 'locale_dirs': ['.'],
+                         'gettext_compact': False})
+def test_i18n_footnote_backlink(app):
+    """i18n test for #1058"""
+    app.builder.build(['i18n/footnote'])
+    result = (app.outdir / 'i18n' / 'footnote.html').text(encoding='utf-8')
+    expects = [
+        '<a class="footnote-reference" href="#id5" id="id1">[100]</a>',
+        '<a class="footnote-reference" href="#id4" id="id2">[1]</a>',
+        '<a class="reference internal" href="#ref" id="id3">[ref]</a>',
+        '<a class="fn-backref" href="#id2">[1]</a>',
+        '<a class="fn-backref" href="#id3">[ref]</a>',
+        '<a class="fn-backref" href="#id1">[100]</a>',
+        ]
+    for expect in expects:
+        matches = re.findall(re.escape(expect), result)
+        assert len(matches) == 1
+
+
 @with_app(buildername='text', warning=warnfile, cleanenv=True,
           confoverrides={'language': 'xx', 'locale_dirs': ['.'],
                          'gettext_compact': False})
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.