mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'stable'
This commit is contained in:
commit
ef890a45d3
16
CHANGES
16
CHANGES
@ -18,11 +18,13 @@ Features added
|
|||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* #1976: Avoid "2.0" version of Babel because it doesn't work with Windows environment.
|
||||||
|
* Add a "default.css" stylesheet (which imports "classic.css") for compatibility.
|
||||||
|
* #1788: graphviz extension raises exception when caption option is present.
|
||||||
* #1789: ``:pyobject:`` option of ``literalinclude`` directive includes following
|
* #1789: ``:pyobject:`` option of ``literalinclude`` directive includes following
|
||||||
lines after class definitions.
|
lines after class definitions.
|
||||||
* #1790: ``literalinclude`` strips empty lines at the head and tail.
|
* #1790: ``literalinclude`` strips empty lines at the head and tail.
|
||||||
* #1913: C++, fix assert bug for enumerators in next-to-global and global scope.
|
* #1913: C++, fix assert bug for enumerators in next-to-global and global scope.
|
||||||
* #1790: ``literalinclude`` strips empty lines at the head and tail
|
|
||||||
* #1802: load plugin themes automatically when theme.conf use it as 'inherit'. Thanks to
|
* #1802: load plugin themes automatically when theme.conf use it as 'inherit'. Thanks to
|
||||||
Takayuki Hirai.
|
Takayuki Hirai.
|
||||||
* #1794: custom theme extended from alabaster or sphinx_rtd_theme can't find base theme.
|
* #1794: custom theme extended from alabaster or sphinx_rtd_theme can't find base theme.
|
||||||
@ -47,15 +49,21 @@ Bugs fixed
|
|||||||
* #1942: Fix a KeyError in websupport.
|
* #1942: Fix a KeyError in websupport.
|
||||||
* #1903: Fix strange id generation for glossary terms.
|
* #1903: Fix strange id generation for glossary terms.
|
||||||
* #1796, On py3, automated .mo building cause UnicodeDecodeError
|
* #1796, On py3, automated .mo building cause UnicodeDecodeError
|
||||||
* Fix: ``make text`` will crush if a definition list item has more than 1 classifiers as:
|
|
||||||
* #1796: On py3, automated .mo building cause UnicodeDecodeError
|
|
||||||
* ``make text`` will crush if a definition list item has more than 1 classifiers as:
|
* ``make text`` will crush if a definition list item has more than 1 classifiers as:
|
||||||
* Fixed #1855: make gettext generates broken po file for definition lists with classifier.
|
|
||||||
``term : classifier1 : classifier2``.
|
``term : classifier1 : classifier2``.
|
||||||
* #1855: make gettext generates broken po file for definition lists with classifier.
|
* #1855: make gettext generates broken po file for definition lists with classifier.
|
||||||
* #1869: Fix problems when dealing with files containing non-ASCII characters. Thanks to
|
* #1869: Fix problems when dealing with files containing non-ASCII characters. Thanks to
|
||||||
Marvin Schmidt.
|
Marvin Schmidt.
|
||||||
* #1798: Fix building LaTeX with references in titles.
|
* #1798: Fix building LaTeX with references in titles.
|
||||||
|
* #1725: On py2 environment, doctest with using non-ASCII characters causes
|
||||||
|
``'ascii' codec can't decode byte`` exception.
|
||||||
|
* #1540: Fix RuntimeError with circular referenced toctree
|
||||||
|
* #1983: i18n translation feature breaks references which uses section name.
|
||||||
|
* #1990: Use caption of toctree to title of \tableofcontents in LaTeX
|
||||||
|
* #1987: Fix ampersand is ignored in ``:menuselection:`` and ``:guilabel:`` on LaTeX builder
|
||||||
|
* #1994: More supporting non-standard parser (like recommonmark parser) for Translation and
|
||||||
|
WebSupport feature. Now node.rawsource is fall backed to node.astext() during docutils
|
||||||
|
transforming.
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
2
setup.py
2
setup.py
@ -51,7 +51,7 @@ requires = [
|
|||||||
'Pygments>=2.0',
|
'Pygments>=2.0',
|
||||||
'docutils>=0.11',
|
'docutils>=0.11',
|
||||||
'snowballstemmer>=1.1',
|
'snowballstemmer>=1.1',
|
||||||
'babel>=1.3',
|
'babel>=1.3,!=2.0',
|
||||||
'alabaster>=0.7,<0.8',
|
'alabaster>=0.7,<0.8',
|
||||||
'sphinx_rtd_theme>=0.1,<0.2',
|
'sphinx_rtd_theme>=0.1,<0.2',
|
||||||
]
|
]
|
||||||
|
@ -160,10 +160,14 @@ class Builder(object):
|
|||||||
def compile_catalogs(self, catalogs, message):
|
def compile_catalogs(self, catalogs, message):
|
||||||
if not self.config.gettext_auto_build:
|
if not self.config.gettext_auto_build:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def cat2relpath(cat):
|
||||||
|
return path.relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
|
||||||
|
|
||||||
self.info(bold('building [mo]: ') + message)
|
self.info(bold('building [mo]: ') + message)
|
||||||
for catalog in self.app.status_iterator(
|
for catalog in self.app.status_iterator(
|
||||||
catalogs, 'writing output... ', darkgreen, len(catalogs),
|
catalogs, 'writing output... ', darkgreen, len(catalogs),
|
||||||
lambda c: c.mo_path):
|
cat2relpath):
|
||||||
catalog.write_mo(self.config.language)
|
catalog.write_mo(self.config.language)
|
||||||
|
|
||||||
def compile_all_catalogs(self):
|
def compile_all_catalogs(self):
|
||||||
|
@ -945,7 +945,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
|||||||
def assemble_doctree(self):
|
def assemble_doctree(self):
|
||||||
master = self.config.master_doc
|
master = self.config.master_doc
|
||||||
tree = self.env.get_doctree(master)
|
tree = self.env.get_doctree(master)
|
||||||
tree = inline_all_toctrees(self, set(), master, tree, darkgreen)
|
tree = inline_all_toctrees(self, set(), master, tree, darkgreen, [master])
|
||||||
tree['docname'] = master
|
tree['docname'] = master
|
||||||
self.env.resolve_references(tree, master, self)
|
self.env.resolve_references(tree, master, self)
|
||||||
self.fix_refuris(tree)
|
self.fix_refuris(tree)
|
||||||
|
@ -102,11 +102,22 @@ class LaTeXBuilder(Builder):
|
|||||||
doctree.settings = docsettings
|
doctree.settings = docsettings
|
||||||
doctree.settings.author = author
|
doctree.settings.author = author
|
||||||
doctree.settings.title = title
|
doctree.settings.title = title
|
||||||
|
doctree.settings.contentsname = self.get_contentsname(docname)
|
||||||
doctree.settings.docname = docname
|
doctree.settings.docname = docname
|
||||||
doctree.settings.docclass = docclass
|
doctree.settings.docclass = docclass
|
||||||
docwriter.write(doctree, destination)
|
docwriter.write(doctree, destination)
|
||||||
self.info("done")
|
self.info("done")
|
||||||
|
|
||||||
|
def get_contentsname(self, indexfile):
|
||||||
|
tree = self.env.get_doctree(indexfile)
|
||||||
|
contentsname = None
|
||||||
|
for toctree in tree.traverse(addnodes.toctree):
|
||||||
|
if toctree['caption']:
|
||||||
|
contentsname = toctree['caption']
|
||||||
|
break
|
||||||
|
|
||||||
|
return contentsname
|
||||||
|
|
||||||
def assemble_doctree(self, indexfile, toctree_only, appendices):
|
def assemble_doctree(self, indexfile, toctree_only, appendices):
|
||||||
self.docnames = set([indexfile] + appendices)
|
self.docnames = set([indexfile] + appendices)
|
||||||
self.info(darkgreen(indexfile) + " ", nonl=1)
|
self.info(darkgreen(indexfile) + " ", nonl=1)
|
||||||
@ -124,7 +135,7 @@ class LaTeXBuilder(Builder):
|
|||||||
new_sect += node
|
new_sect += node
|
||||||
tree = new_tree
|
tree = new_tree
|
||||||
largetree = inline_all_toctrees(self, self.docnames, indexfile, tree,
|
largetree = inline_all_toctrees(self, self.docnames, indexfile, tree,
|
||||||
darkgreen)
|
darkgreen, [indexfile])
|
||||||
largetree['docname'] = indexfile
|
largetree['docname'] = indexfile
|
||||||
for docname in appendices:
|
for docname in appendices:
|
||||||
appendix = self.env.get_doctree(docname)
|
appendix = self.env.get_doctree(docname)
|
||||||
|
@ -70,7 +70,7 @@ class ManualPageBuilder(Builder):
|
|||||||
tree = self.env.get_doctree(docname)
|
tree = self.env.get_doctree(docname)
|
||||||
docnames = set()
|
docnames = set()
|
||||||
largetree = inline_all_toctrees(self, docnames, docname, tree,
|
largetree = inline_all_toctrees(self, docnames, docname, tree,
|
||||||
darkgreen)
|
darkgreen, [docname])
|
||||||
self.info('} ', nonl=True)
|
self.info('} ', nonl=True)
|
||||||
self.env.resolve_references(largetree, docname, self)
|
self.env.resolve_references(largetree, docname, self)
|
||||||
# remove pending_xref nodes
|
# remove pending_xref nodes
|
||||||
|
@ -180,7 +180,7 @@ class TexinfoBuilder(Builder):
|
|||||||
new_sect += node
|
new_sect += node
|
||||||
tree = new_tree
|
tree = new_tree
|
||||||
largetree = inline_all_toctrees(self, self.docnames, indexfile, tree,
|
largetree = inline_all_toctrees(self, self.docnames, indexfile, tree,
|
||||||
darkgreen)
|
darkgreen, [indexfile])
|
||||||
largetree['docname'] = indexfile
|
largetree['docname'] = indexfile
|
||||||
for docname in appendices:
|
for docname in appendices:
|
||||||
appendix = self.env.get_doctree(docname)
|
appendix = self.env.get_doctree(docname)
|
||||||
|
@ -142,7 +142,7 @@ class Author(Directive):
|
|||||||
env = self.state.document.settings.env
|
env = self.state.document.settings.env
|
||||||
if not env.config.show_authors:
|
if not env.config.show_authors:
|
||||||
return []
|
return []
|
||||||
para = nodes.paragraph()
|
para = nodes.paragraph(translatable=False)
|
||||||
emph = nodes.emphasis()
|
emph = nodes.emphasis()
|
||||||
para += emph
|
para += emph
|
||||||
if self.name == 'sectionauthor':
|
if self.name == 'sectionauthor':
|
||||||
@ -205,7 +205,7 @@ class VersionChange(Directive):
|
|||||||
if len(self.arguments) == 2:
|
if len(self.arguments) == 2:
|
||||||
inodes, messages = self.state.inline_text(self.arguments[1],
|
inodes, messages = self.state.inline_text(self.arguments[1],
|
||||||
self.lineno+1)
|
self.lineno+1)
|
||||||
para = nodes.paragraph(self.arguments[1], '', *inodes)
|
para = nodes.paragraph(self.arguments[1], '', *inodes, translatable=False)
|
||||||
set_source_info(self, para)
|
set_source_info(self, para)
|
||||||
node.append(para)
|
node.append(para)
|
||||||
else:
|
else:
|
||||||
@ -218,13 +218,14 @@ class VersionChange(Directive):
|
|||||||
content.source = node[0].source
|
content.source = node[0].source
|
||||||
content.line = node[0].line
|
content.line = node[0].line
|
||||||
content += node[0].children
|
content += node[0].children
|
||||||
node[0].replace_self(nodes.paragraph('', '', content))
|
node[0].replace_self(nodes.paragraph('', '', content, translatable=False))
|
||||||
node[0].insert(0, nodes.inline('', '%s: ' % text,
|
node[0].insert(0, nodes.inline('', '%s: ' % text,
|
||||||
classes=['versionmodified']))
|
classes=['versionmodified']))
|
||||||
else:
|
else:
|
||||||
para = nodes.paragraph('', '',
|
para = nodes.paragraph('', '',
|
||||||
nodes.inline('', '%s.' % text,
|
nodes.inline('', '%s.' % text,
|
||||||
classes=['versionmodified']))
|
classes=['versionmodified']),
|
||||||
|
translatable=False)
|
||||||
node.append(para)
|
node.append(para)
|
||||||
env = self.state.document.settings.env
|
env = self.state.document.settings.env
|
||||||
# XXX should record node.source as well
|
# XXX should record node.source as well
|
||||||
|
@ -49,9 +49,11 @@ from sphinx.util.websupport import is_commentable
|
|||||||
from sphinx.errors import SphinxError, ExtensionError
|
from sphinx.errors import SphinxError, ExtensionError
|
||||||
from sphinx.locale import _
|
from sphinx.locale import _
|
||||||
from sphinx.versioning import add_uids, merge_doctrees
|
from sphinx.versioning import add_uids, merge_doctrees
|
||||||
from sphinx.transforms import DefaultSubstitutions, MoveModuleTargets, \
|
from sphinx.transforms import (
|
||||||
HandleCodeBlocks, AutoNumbering, SortIds, CitationReferences, Locale, \
|
DefaultSubstitutions, MoveModuleTargets, ApplySourceWorkaround,
|
||||||
RemoveTranslatableInline, SphinxContentsFilter, ExtraTranslatableNodes
|
HandleCodeBlocks, AutoNumbering, SortIds, CitationReferences, Locale,
|
||||||
|
RemoveTranslatableInline, SphinxContentsFilter, ExtraTranslatableNodes,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
orig_role_function = roles.role
|
orig_role_function = roles.role
|
||||||
@ -99,7 +101,7 @@ class SphinxStandaloneReader(standalone.Reader):
|
|||||||
"""
|
"""
|
||||||
Add our own transforms.
|
Add our own transforms.
|
||||||
"""
|
"""
|
||||||
transforms = [ExtraTranslatableNodes, Locale, CitationReferences,
|
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, Locale, CitationReferences,
|
||||||
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
|
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
|
||||||
AutoNumbering, SortIds, RemoveTranslatableInline]
|
AutoNumbering, SortIds, RemoveTranslatableInline]
|
||||||
|
|
||||||
|
@ -9,14 +9,16 @@
|
|||||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import codecs
|
import codecs
|
||||||
from os import path
|
from os import path
|
||||||
|
import doctest
|
||||||
|
|
||||||
from six import itervalues, StringIO, binary_type
|
from six import itervalues, StringIO, binary_type, text_type, PY2
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.parsers.rst import directives
|
from docutils.parsers.rst import directives
|
||||||
|
|
||||||
@ -26,13 +28,30 @@ from sphinx.util import force_decode
|
|||||||
from sphinx.util.nodes import set_source_info
|
from sphinx.util.nodes import set_source_info
|
||||||
from sphinx.util.compat import Directive
|
from sphinx.util.compat import Directive
|
||||||
from sphinx.util.console import bold
|
from sphinx.util.console import bold
|
||||||
|
from sphinx.util.osutil import fs_encoding
|
||||||
# circumvent relative import
|
|
||||||
doctest = __import__('doctest')
|
|
||||||
|
|
||||||
blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
|
blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
|
||||||
doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE)
|
doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE)
|
||||||
|
|
||||||
|
if PY2:
|
||||||
|
def doctest_encode(text, encoding):
|
||||||
|
if isinstance(text, text_type):
|
||||||
|
text = text.encode(encoding)
|
||||||
|
if text.startswith(codecs.BOM_UTF8):
|
||||||
|
text = text[len(codecs.BOM_UTF8):]
|
||||||
|
return text
|
||||||
|
else:
|
||||||
|
def doctest_encode(text, encoding):
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
class _SpoofOutSphinx(doctest._SpoofOut):
|
||||||
|
# override: convert console encoding to unicode
|
||||||
|
if PY2:
|
||||||
|
def getvalue(self):
|
||||||
|
result = doctest._SpoofOut.getvalue(self)
|
||||||
|
return result.decode('string_escape')
|
||||||
|
|
||||||
|
|
||||||
# set up the necessary directives
|
# set up the necessary directives
|
||||||
|
|
||||||
@ -165,6 +184,11 @@ class TestCode(object):
|
|||||||
|
|
||||||
|
|
||||||
class SphinxDocTestRunner(doctest.DocTestRunner):
|
class SphinxDocTestRunner(doctest.DocTestRunner):
|
||||||
|
def __init__(self, *args, **kw):
|
||||||
|
doctest.DocTestRunner.__init__(self, *args, **kw)
|
||||||
|
# Override a fake output target for capturing doctest output.
|
||||||
|
self._fakeout = _SpoofOutSphinx()
|
||||||
|
|
||||||
def summarize(self, out, verbose=None):
|
def summarize(self, out, verbose=None):
|
||||||
string_io = StringIO()
|
string_io = StringIO()
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
@ -358,19 +382,25 @@ Doctest summary
|
|||||||
return compile(code, name, self.type, flags, dont_inherit)
|
return compile(code, name, self.type, flags, dont_inherit)
|
||||||
|
|
||||||
def test_group(self, group, filename):
|
def test_group(self, group, filename):
|
||||||
|
if PY2:
|
||||||
|
filename_str = filename.encode(fs_encoding)
|
||||||
|
else:
|
||||||
|
filename_str = filename
|
||||||
|
|
||||||
ns = {}
|
ns = {}
|
||||||
|
|
||||||
def run_setup_cleanup(runner, testcodes, what):
|
def run_setup_cleanup(runner, testcodes, what):
|
||||||
examples = []
|
examples = []
|
||||||
for testcode in testcodes:
|
for testcode in testcodes:
|
||||||
examples.append(doctest.Example(testcode.code, '',
|
examples.append(doctest.Example(
|
||||||
|
doctest_encode(testcode.code, self.env.config.source_encoding), '',
|
||||||
lineno=testcode.lineno))
|
lineno=testcode.lineno))
|
||||||
if not examples:
|
if not examples:
|
||||||
return True
|
return True
|
||||||
# simulate a doctest with the code
|
# simulate a doctest with the code
|
||||||
sim_doctest = doctest.DocTest(examples, {},
|
sim_doctest = doctest.DocTest(examples, {},
|
||||||
'%s (%s code)' % (group.name, what),
|
'%s (%s code)' % (group.name, what),
|
||||||
filename, 0, None)
|
filename_str, 0, None)
|
||||||
sim_doctest.globs = ns
|
sim_doctest.globs = ns
|
||||||
old_f = runner.failures
|
old_f = runner.failures
|
||||||
self.type = 'exec' # the snippet may contain multiple statements
|
self.type = 'exec' # the snippet may contain multiple statements
|
||||||
@ -389,8 +419,9 @@ Doctest summary
|
|||||||
if len(code) == 1:
|
if len(code) == 1:
|
||||||
# ordinary doctests (code/output interleaved)
|
# ordinary doctests (code/output interleaved)
|
||||||
try:
|
try:
|
||||||
test = parser.get_doctest(code[0].code, {}, group.name,
|
test = parser.get_doctest(
|
||||||
filename, code[0].lineno)
|
doctest_encode(code[0].code, self.env.config.source_encoding), {},
|
||||||
|
group.name, filename_str, code[0].lineno)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.warn('ignoring invalid doctest code: %r' %
|
self.warn('ignoring invalid doctest code: %r' %
|
||||||
code[0].code,
|
code[0].code,
|
||||||
@ -416,12 +447,13 @@ Doctest summary
|
|||||||
exc_msg = m.group('msg')
|
exc_msg = m.group('msg')
|
||||||
else:
|
else:
|
||||||
exc_msg = None
|
exc_msg = None
|
||||||
example = doctest.Example(code[0].code, output,
|
example = doctest.Example(
|
||||||
|
doctest_encode(code[0].code, self.env.config.source_encoding), output,
|
||||||
exc_msg=exc_msg,
|
exc_msg=exc_msg,
|
||||||
lineno=code[0].lineno,
|
lineno=code[0].lineno,
|
||||||
options=options)
|
options=options)
|
||||||
test = doctest.DocTest([example], {}, group.name,
|
test = doctest.DocTest([example], {}, group.name,
|
||||||
filename, code[0].lineno, None)
|
filename_str, code[0].lineno, None)
|
||||||
self.type = 'exec' # multiple statements again
|
self.type = 'exec' # multiple statements again
|
||||||
# DocTest.__init__ copies the globs namespace, which we don't want
|
# DocTest.__init__ copies the globs namespace, which we don't want
|
||||||
test.globs = ns
|
test.globs = ns
|
||||||
|
@ -22,6 +22,7 @@ from sphinx.locale import _, init as init_locale
|
|||||||
from sphinx.util import split_index_msg
|
from sphinx.util import split_index_msg
|
||||||
from sphinx.util.nodes import (
|
from sphinx.util.nodes import (
|
||||||
traverse_translatable_index, extract_messages, LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
|
traverse_translatable_index, extract_messages, LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
|
||||||
|
apply_source_workaround,
|
||||||
)
|
)
|
||||||
from sphinx.util.osutil import ustrftime
|
from sphinx.util.osutil import ustrftime
|
||||||
from sphinx.util.i18n import find_catalog
|
from sphinx.util.i18n import find_catalog
|
||||||
@ -169,6 +170,18 @@ TRANSLATABLE_NODES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ApplySourceWorkaround(Transform):
|
||||||
|
"""
|
||||||
|
update source and rawsource attributes
|
||||||
|
"""
|
||||||
|
default_priority = 10
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
for n in self.document.traverse():
|
||||||
|
if isinstance(n, nodes.TextElement):
|
||||||
|
apply_source_workaround(n)
|
||||||
|
|
||||||
|
|
||||||
class ExtraTranslatableNodes(Transform):
|
class ExtraTranslatableNodes(Transform):
|
||||||
"""
|
"""
|
||||||
make nodes translatable
|
make nodes translatable
|
||||||
@ -277,8 +290,10 @@ class Locale(Transform):
|
|||||||
# document nameids mapping with new name.
|
# document nameids mapping with new name.
|
||||||
names = section_node.setdefault('names', [])
|
names = section_node.setdefault('names', [])
|
||||||
names.append(new_name)
|
names.append(new_name)
|
||||||
if old_name in names:
|
# Original section name (reference target name) should be kept to refer
|
||||||
names.remove(old_name)
|
# from other nodes which is still not translated or uses explicit target
|
||||||
|
# name like "`text to display <explicit target name_>`_"..
|
||||||
|
# So, `old_name` is still exist in `names`.
|
||||||
|
|
||||||
_id = self.document.nameids.get(old_name, None)
|
_id = self.document.nameids.get(old_name, None)
|
||||||
explicit = self.document.nametypes.get(old_name, None)
|
explicit = self.document.nametypes.get(old_name, None)
|
||||||
|
@ -50,6 +50,10 @@ def apply_source_workaround(node):
|
|||||||
# overwrite: ``term : classifier1 : classifier2`` -> ``term text``
|
# overwrite: ``term : classifier1 : classifier2`` -> ``term text``
|
||||||
node.rawsource = node.astext()
|
node.rawsource = node.astext()
|
||||||
|
|
||||||
|
# workaround: recommonmark-0.2.0 doesn't set rawsource attribute
|
||||||
|
if not node.rawsource:
|
||||||
|
node.rawsource = node.astext()
|
||||||
|
|
||||||
if node.source and node.rawsource:
|
if node.source and node.rawsource:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -74,18 +78,20 @@ IGNORED_NODES = (
|
|||||||
nodes.Inline,
|
nodes.Inline,
|
||||||
nodes.literal_block,
|
nodes.literal_block,
|
||||||
nodes.doctest_block,
|
nodes.doctest_block,
|
||||||
|
addnodes.versionmodified,
|
||||||
# XXX there are probably more
|
# XXX there are probably more
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def is_translatable(node):
|
def is_translatable(node):
|
||||||
if isinstance(node, nodes.TextElement):
|
if isinstance(node, nodes.TextElement):
|
||||||
apply_source_workaround(node)
|
|
||||||
|
|
||||||
if not node.source:
|
if not node.source:
|
||||||
return False # built-in message
|
return False # built-in message
|
||||||
if isinstance(node, IGNORED_NODES) and 'translatable' not in node:
|
if isinstance(node, IGNORED_NODES) and 'translatable' not in node:
|
||||||
return False
|
return False
|
||||||
|
if not node.get('translatable', True):
|
||||||
|
# not(node['translatable'] == True or node['translatable'] is None)
|
||||||
|
return False
|
||||||
# <field_name>orphan</field_name>
|
# <field_name>orphan</field_name>
|
||||||
# XXX ignore all metadata (== docinfo)
|
# XXX ignore all metadata (== docinfo)
|
||||||
if isinstance(node, nodes.field_name) and node.children[0] == 'orphan':
|
if isinstance(node, nodes.field_name) and node.children[0] == 'orphan':
|
||||||
@ -228,7 +234,7 @@ def process_index_entry(entry, targetid):
|
|||||||
return indexentries
|
return indexentries
|
||||||
|
|
||||||
|
|
||||||
def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc):
|
def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc, traversed):
|
||||||
"""Inline all toctrees in the *tree*.
|
"""Inline all toctrees in the *tree*.
|
||||||
|
|
||||||
Record all docnames in *docnameset*, and output docnames with *colorfunc*.
|
Record all docnames in *docnameset*, and output docnames with *colorfunc*.
|
||||||
@ -238,11 +244,13 @@ def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc):
|
|||||||
newnodes = []
|
newnodes = []
|
||||||
includefiles = map(text_type, toctreenode['includefiles'])
|
includefiles = map(text_type, toctreenode['includefiles'])
|
||||||
for includefile in includefiles:
|
for includefile in includefiles:
|
||||||
|
if includefile not in traversed:
|
||||||
try:
|
try:
|
||||||
|
traversed.append(includefile)
|
||||||
builder.info(colorfunc(includefile) + " ", nonl=1)
|
builder.info(colorfunc(includefile) + " ", nonl=1)
|
||||||
subtree = inline_all_toctrees(builder, docnameset, includefile,
|
subtree = inline_all_toctrees(builder, docnameset, includefile,
|
||||||
builder.env.get_doctree(includefile),
|
builder.env.get_doctree(includefile),
|
||||||
colorfunc)
|
colorfunc, traversed)
|
||||||
docnameset.add(includefile)
|
docnameset.add(includefile)
|
||||||
except Exception:
|
except Exception:
|
||||||
builder.warn('toctree contains ref to nonexisting '
|
builder.warn('toctree contains ref to nonexisting '
|
||||||
|
@ -43,6 +43,7 @@ HEADER = r'''%% Generated by Sphinx.
|
|||||||
\usepackage{sphinx}
|
\usepackage{sphinx}
|
||||||
\usepackage{multirow}
|
\usepackage{multirow}
|
||||||
%(usepackages)s
|
%(usepackages)s
|
||||||
|
%(contentsname)s
|
||||||
%(numfig_format)s
|
%(numfig_format)s
|
||||||
%(preamble)s
|
%(preamble)s
|
||||||
|
|
||||||
@ -159,6 +160,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
'longtable': '\\usepackage{longtable}',
|
'longtable': '\\usepackage{longtable}',
|
||||||
'usepackages': '',
|
'usepackages': '',
|
||||||
'numfig_format': '',
|
'numfig_format': '',
|
||||||
|
'contentsname': '',
|
||||||
'preamble': '',
|
'preamble': '',
|
||||||
'title': '',
|
'title': '',
|
||||||
'date': '',
|
'date': '',
|
||||||
@ -248,6 +250,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
return '\\usepackage{%s}' % (packagename,)
|
return '\\usepackage{%s}' % (packagename,)
|
||||||
usepackages = (declare_package(*p) for p in builder.usepackages)
|
usepackages = (declare_package(*p) for p in builder.usepackages)
|
||||||
self.elements['usepackages'] += "\n".join(usepackages)
|
self.elements['usepackages'] += "\n".join(usepackages)
|
||||||
|
if getattr(document.settings, 'contentsname', None):
|
||||||
|
self.elements['contentsname'] = \
|
||||||
|
self.babel_renewcommand(builder, '\\contentsname',
|
||||||
|
document.settings.contentsname)
|
||||||
self.elements['numfig_format'] = self.generate_numfig_format(builder)
|
self.elements['numfig_format'] = self.generate_numfig_format(builder)
|
||||||
# allow the user to override them all
|
# allow the user to override them all
|
||||||
self.elements.update(builder.config.latex_elements)
|
self.elements.update(builder.config.latex_elements)
|
||||||
@ -329,8 +335,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
encode('ascii', 'backslashreplace').decode('ascii').\
|
encode('ascii', 'backslashreplace').decode('ascii').\
|
||||||
replace('\\', '_')
|
replace('\\', '_')
|
||||||
|
|
||||||
def generate_numfig_format(self, builder):
|
def babel_renewcommand(self, builder, command, definition):
|
||||||
ret = []
|
|
||||||
if builder.config.language == 'ja':
|
if builder.config.language == 'ja':
|
||||||
babel_prefix = ''
|
babel_prefix = ''
|
||||||
babel_suffix = ''
|
babel_suffix = ''
|
||||||
@ -349,15 +354,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
babel_prefix = ''
|
babel_prefix = ''
|
||||||
babel_suffix = ''
|
babel_suffix = ''
|
||||||
|
|
||||||
|
return ('%s\\renewcommand{%s}{%s}%s\n' %
|
||||||
|
(babel_prefix, command, definition, babel_suffix))
|
||||||
|
|
||||||
|
def generate_numfig_format(self, builder):
|
||||||
|
ret = []
|
||||||
figure = self.builder.config.numfig_format['figure'].split('%s', 1)
|
figure = self.builder.config.numfig_format['figure'].split('%s', 1)
|
||||||
if len(figure) == 1:
|
if len(figure) == 1:
|
||||||
ret.append('\\def\\fnum@figure{%s}\n' %
|
ret.append('\\def\\fnum@figure{%s}\n' %
|
||||||
text_type(figure[0]).translate(tex_escape_map))
|
text_type(figure[0]).translate(tex_escape_map))
|
||||||
else:
|
else:
|
||||||
ret.append('%s\\renewcommand{\\figurename}{%s}%s\n' %
|
definition = text_type(figure[0]).translate(tex_escape_map)
|
||||||
(babel_prefix,
|
ret.append(self.babel_renewcommand(builder, '\\figurename', definition))
|
||||||
text_type(figure[0]).translate(tex_escape_map),
|
|
||||||
babel_suffix))
|
|
||||||
if figure[1]:
|
if figure[1]:
|
||||||
ret.append('\\makeatletter\n')
|
ret.append('\\makeatletter\n')
|
||||||
ret.append('\\def\\fnum@figure{\\figurename\\thefigure%s}\n' %
|
ret.append('\\def\\fnum@figure{\\figurename\\thefigure%s}\n' %
|
||||||
@ -369,10 +377,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
ret.append('\\def\\fnum@table{%s}\n' %
|
ret.append('\\def\\fnum@table{%s}\n' %
|
||||||
text_type(table[0]).translate(tex_escape_map))
|
text_type(table[0]).translate(tex_escape_map))
|
||||||
else:
|
else:
|
||||||
ret.append('%s\\renewcommand{\\tablename}{%s}%s\n' %
|
definition = text_type(table[0]).translate(tex_escape_map)
|
||||||
(babel_prefix,
|
ret.append(self.babel_renewcommand(builder, '\\tablename', definition))
|
||||||
text_type(table[0]).translate(tex_escape_map),
|
|
||||||
babel_suffix))
|
|
||||||
if table[1]:
|
if table[1]:
|
||||||
ret.append('\\makeatletter\n')
|
ret.append('\\makeatletter\n')
|
||||||
ret.append('\\def\\fnum@table{\\tablename\\thetable%s}\n' %
|
ret.append('\\def\\fnum@table{\\tablename\\thetable%s}\n' %
|
||||||
@ -1707,6 +1713,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
if classes in [['menuselection'], ['guilabel']]:
|
if classes in [['menuselection'], ['guilabel']]:
|
||||||
self.body.append(r'\emph{')
|
self.body.append(r'\emph{')
|
||||||
self.context.append('}')
|
self.context.append('}')
|
||||||
|
elif classes in [['accelerator']]:
|
||||||
|
self.body.append(r'\underline{')
|
||||||
|
self.context.append('}')
|
||||||
elif classes and not self.in_title:
|
elif classes and not self.in_title:
|
||||||
self.body.append(r'\DUspan{%s}{' % ','.join(classes))
|
self.body.append(r'\DUspan{%s}{' % ','.join(classes))
|
||||||
self.context.append('}')
|
self.context.append('}')
|
||||||
|
4
tests/roots/test-contentsname/bar.rst
Normal file
4
tests/roots/test-contentsname/bar.rst
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
===
|
||||||
|
Bar
|
||||||
|
===
|
||||||
|
|
4
tests/roots/test-contentsname/conf.py
Normal file
4
tests/roots/test-contentsname/conf.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
master_doc = 'index'
|
||||||
|
html_theme = 'classic'
|
4
tests/roots/test-contentsname/foo.rst
Normal file
4
tests/roots/test-contentsname/foo.rst
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
===
|
||||||
|
Foo
|
||||||
|
===
|
||||||
|
|
8
tests/roots/test-contentsname/index.rst
Normal file
8
tests/roots/test-contentsname/index.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
test-tocdepth
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:caption: Table of content
|
||||||
|
|
||||||
|
foo
|
||||||
|
bar
|
@ -127,3 +127,12 @@ Special directives
|
|||||||
|
|
||||||
import test_ext_doctest
|
import test_ext_doctest
|
||||||
test_ext_doctest.cleanup_call()
|
test_ext_doctest.cleanup_call()
|
||||||
|
|
||||||
|
non-ASCII result
|
||||||
|
----------------
|
||||||
|
|
||||||
|
>>> print('umlauts: äöü.')
|
||||||
|
umlauts: äöü.
|
||||||
|
>>> print('Japanese: 日本語')
|
||||||
|
Japanese: 日本語
|
||||||
|
|
||||||
|
@ -22,3 +22,4 @@ CONTENTS
|
|||||||
versionchange
|
versionchange
|
||||||
docfields
|
docfields
|
||||||
raw
|
raw
|
||||||
|
refs
|
||||||
|
85
tests/roots/test-intl/refs.po
Normal file
85
tests/roots/test-intl/refs.po
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: 1191 1.3\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2015-08-08 15:31+0900\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
|
msgid "Translation Tips"
|
||||||
|
msgstr "X TIPS"
|
||||||
|
|
||||||
|
msgid "A-1. Here's how you can `download Sphinx`_."
|
||||||
|
msgstr "A-1. HERE'S HOW YOU CAN `download Sphinx`_."
|
||||||
|
|
||||||
|
msgid "A-2. Here's how you can `download Sphinx`_."
|
||||||
|
msgstr "A-2. HERE'S HOW YOU CAN `A1 DOWNLOAD SPHINX`_."
|
||||||
|
|
||||||
|
msgid "A-3. Here's how you can `download Sphinx`_."
|
||||||
|
msgstr ""
|
||||||
|
"A-3. HERE'S HOW YOU CAN `A3 DOWNLOAD SPHINX <download Sphinx_>`_ AND `A3 DOWNLOAD "
|
||||||
|
"SPHINX <download Sphinx_>`_."
|
||||||
|
|
||||||
|
msgid "B-1. `Docutils site`_ and `Sphinx site`_."
|
||||||
|
msgstr "B-1. `Docutils site`_ and `Sphinx site`_."
|
||||||
|
|
||||||
|
msgid "B-2. `Docutils site`_ and `Sphinx site`_."
|
||||||
|
msgstr "B-2. `B1 DOCUTILS SITE`_ AND `B1 SPHINX SITE`_."
|
||||||
|
|
||||||
|
msgid "B-3. `Docutils site`_ and `Sphinx site`_."
|
||||||
|
msgstr "B-3. `B2 SPHINX SITE`_ AND `B2 DOCUTILS SITE`_."
|
||||||
|
|
||||||
|
msgid "B-4. `Docutils site`_ and `Sphinx site`_."
|
||||||
|
msgstr ""
|
||||||
|
"B-4. `B4 SPHINX SITE <Sphinx site_>`_ AND `B4 DOCUTILS SITE <Docutils "
|
||||||
|
"site_>`_."
|
||||||
|
|
||||||
|
msgid "B-5. `Docutils site`_ and `Sphinx site`_."
|
||||||
|
msgstr ""
|
||||||
|
"B-5. `B5 SPHINX SITE <Sphinx site_>`_ AND `B5 DOCUTILS SITE <Docutils "
|
||||||
|
"site_>`_\" AND `B5 SPHINX SITE <Sphinx site_>`_."
|
||||||
|
|
||||||
|
msgid "C-1. Link to `Translation Tips`_ section."
|
||||||
|
msgstr "C-1. LINK TO `Translation Tips`_ SECTION."
|
||||||
|
|
||||||
|
msgid "C-2. Link to `Translation Tips`_ section."
|
||||||
|
msgstr "C-2. LINK TO `X TIPS`_ SECTION."
|
||||||
|
|
||||||
|
msgid "C-3. Link to `Translation Tips`_ section."
|
||||||
|
msgstr "C-3. LINK TO `X TIPS <Translation Tips_>`_ SECTION."
|
||||||
|
|
||||||
|
msgid "C-4. Link to `Translation Tips`_ section."
|
||||||
|
msgstr ""
|
||||||
|
"C-4. LINK TO `X TIPS <Translation Tips_>`_ x `X TIPS <Translation Tips_>`_ "
|
||||||
|
"SECTION."
|
||||||
|
|
||||||
|
msgid "C-5. Link to `Translation Tips`_ section."
|
||||||
|
msgstr ""
|
||||||
|
"C-5. LINK TO `TRANS <X TIPS_>`_ x `LATION <X TIPS_>`_ "
|
||||||
|
|
||||||
|
msgid "D-1. Link to `Translation Tips`_ and `Next Section`_ section."
|
||||||
|
msgstr "D-1. LINK TO `Translation Tips`_ and `Next Section`_ SECTION."
|
||||||
|
|
||||||
|
msgid "D-2. Link to `Translation Tips`_ and `Next Section`_ section."
|
||||||
|
msgstr "D-2. LINK TO `X TIPS`_ AND `N SECTION`_ SECTION."
|
||||||
|
|
||||||
|
msgid "D-3. Link to `Translation Tips`_ and `Next Section`_ section."
|
||||||
|
msgstr "D-3. LINK TO `N SECTION`_ AND `X TIPS`_ SECTION."
|
||||||
|
|
||||||
|
msgid "D-4. Link to `Translation Tips`_ and `Next Section`_ section."
|
||||||
|
msgstr ""
|
||||||
|
"D-4. LINK TO `N SECTION <Next Section_>`_ AND `X TIPS <Translation Tips_>`_ "
|
||||||
|
"SECTION."
|
||||||
|
|
||||||
|
msgid "D-5. Link to `Translation Tips`_ and `Next Section`_ section."
|
||||||
|
msgstr ""
|
||||||
|
"D-5. LINK TO `Next <N SECTION_>`_ AND `Tips <X TIPS_>`_ "
|
||||||
|
|
||||||
|
msgid "Next Section"
|
||||||
|
msgstr "N SECTION"
|
||||||
|
|
47
tests/roots/test-intl/refs.txt
Normal file
47
tests/roots/test-intl/refs.txt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
References
|
||||||
|
===========
|
||||||
|
|
||||||
|
Translation Tips
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. _download Sphinx: https://pypi.python.org/pypi/sphinx
|
||||||
|
.. _Docutils site: http://docutils.sourceforge.net/
|
||||||
|
.. _Sphinx site: http://sphinx-doc.org/
|
||||||
|
|
||||||
|
|
||||||
|
A-1. Here's how you can `download Sphinx`_.
|
||||||
|
|
||||||
|
A-2. Here's how you can `download Sphinx`_.
|
||||||
|
|
||||||
|
A-3. Here's how you can `download Sphinx`_.
|
||||||
|
|
||||||
|
B-1. `Docutils site`_ and `Sphinx site`_.
|
||||||
|
|
||||||
|
B-2. `Docutils site`_ and `Sphinx site`_.
|
||||||
|
|
||||||
|
B-3. `Docutils site`_ and `Sphinx site`_.
|
||||||
|
|
||||||
|
B-4. `Docutils site`_ and `Sphinx site`_.
|
||||||
|
|
||||||
|
C-1. Link to `Translation Tips`_ section.
|
||||||
|
|
||||||
|
C-2. Link to `Translation Tips`_ section.
|
||||||
|
|
||||||
|
C-3. Link to `Translation Tips`_ section.
|
||||||
|
|
||||||
|
C-4. Link to `Translation Tips`_ section.
|
||||||
|
|
||||||
|
C-5. Link to `Translation Tips`_ section.
|
||||||
|
|
||||||
|
D-1. Link to `Translation Tips`_ and `Next Section`_ section.
|
||||||
|
|
||||||
|
D-2. Link to `Translation Tips`_ and `Next Section`_ section.
|
||||||
|
|
||||||
|
D-3. Link to `Translation Tips`_ and `Next Section`_ section.
|
||||||
|
|
||||||
|
D-4. Link to `Translation Tips`_ and `Next Section`_ section.
|
||||||
|
|
||||||
|
D-5. Link to `Translation Tips`_ and `Next Section`_ section.
|
||||||
|
|
||||||
|
Next Section
|
||||||
|
-------------
|
@ -275,3 +275,25 @@ def test_latex_add_latex_package(app, status, warning):
|
|||||||
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
|
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
|
||||||
assert '\\usepackage{foo}' in result
|
assert '\\usepackage{foo}' in result
|
||||||
assert '\\usepackage[baz]{bar}' in result
|
assert '\\usepackage[baz]{bar}' in result
|
||||||
|
|
||||||
|
|
||||||
|
@with_app(buildername='latex', testroot='contentsname')
|
||||||
|
def test_contentsname(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||||
|
print(result)
|
||||||
|
print(status.getvalue())
|
||||||
|
print(warning.getvalue())
|
||||||
|
assert ('\\addto\\captionsenglish{\\renewcommand{\\contentsname}{Table of content}}'
|
||||||
|
in result)
|
||||||
|
|
||||||
|
|
||||||
|
@with_app(buildername='latex', testroot='contentsname',
|
||||||
|
confoverrides={'language': 'ja'})
|
||||||
|
def test_contentsname_with_language_ja(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
result = (app.outdir / 'Python.tex').text(encoding='utf8')
|
||||||
|
print(result)
|
||||||
|
print(status.getvalue())
|
||||||
|
print(warning.getvalue())
|
||||||
|
assert '\\renewcommand{\\contentsname}{Table of content}' in result
|
||||||
|
@ -751,3 +751,11 @@ def test_additional_targets_should_be_translated(app, status, warning):
|
|||||||
expected_expr = """<img alt="IMG -> I18N" src="_images/i18n.png" />"""
|
expected_expr = """<img alt="IMG -> I18N" src="_images/i18n.png" />"""
|
||||||
yield assert_count(expected_expr, result, 1)
|
yield assert_count(expected_expr, result, 1)
|
||||||
|
|
||||||
|
|
||||||
|
@gen_with_intl_app('text', freshenv=True)
|
||||||
|
def test_references(app, status, warning):
|
||||||
|
app.builder.build_specific([app.srcdir / 'refs.txt'])
|
||||||
|
|
||||||
|
warnings = warning.getvalue().replace(os.sep, '/')
|
||||||
|
warning_expr = u'refs.txt:\\d+: ERROR: Unknown target name:'
|
||||||
|
yield assert_count(warning_expr, warnings, 0)
|
||||||
|
@ -109,7 +109,7 @@ def test_inline():
|
|||||||
yield (verify, ':guilabel:`&Foo -&&- &Bar`',
|
yield (verify, ':guilabel:`&Foo -&&- &Bar`',
|
||||||
u'<p><span class="guilabel"><span class="accelerator">F</span>oo '
|
u'<p><span class="guilabel"><span class="accelerator">F</span>oo '
|
||||||
'-&- <span class="accelerator">B</span>ar</span></p>',
|
'-&- <span class="accelerator">B</span>ar</span></p>',
|
||||||
r'\emph{\DUspan{accelerator}{F}oo -\&- \DUspan{accelerator}{B}ar}')
|
r'\emph{\underline{F}oo -\&- \underline{B}ar}')
|
||||||
|
|
||||||
# non-interpolation of dashes in option role
|
# non-interpolation of dashes in option role
|
||||||
yield (verify_re, ':option:`--with-option`',
|
yield (verify_re, ':option:`--with-option`',
|
||||||
|
@ -16,13 +16,24 @@ from docutils.utils import new_document
|
|||||||
from docutils import frontend
|
from docutils import frontend
|
||||||
|
|
||||||
from sphinx.util.nodes import extract_messages
|
from sphinx.util.nodes import extract_messages
|
||||||
|
from sphinx.transforms import ApplySourceWorkaround
|
||||||
|
|
||||||
|
|
||||||
def _get_doctree(text):
|
def _transform(doctree):
|
||||||
|
ApplySourceWorkaround(doctree).apply()
|
||||||
|
|
||||||
|
|
||||||
|
def create_new_document():
|
||||||
settings = frontend.OptionParser(
|
settings = frontend.OptionParser(
|
||||||
components=(rst.Parser,)).get_default_values()
|
components=(rst.Parser,)).get_default_values()
|
||||||
document = new_document('dummy.txt', settings)
|
document = new_document('dummy.txt', settings)
|
||||||
|
return document
|
||||||
|
|
||||||
|
|
||||||
|
def _get_doctree(text):
|
||||||
|
document = create_new_document()
|
||||||
rst.Parser().parse(text, document)
|
rst.Parser().parse(text, document)
|
||||||
|
_transform(document)
|
||||||
return document
|
return document
|
||||||
|
|
||||||
|
|
||||||
@ -119,3 +130,26 @@ def test_extract_messages():
|
|||||||
extract_messages(_get_doctree(text)),
|
extract_messages(_get_doctree(text)),
|
||||||
nodes.line, 2,
|
nodes.line, 2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_messages_without_rawsource():
|
||||||
|
"""
|
||||||
|
Check node.rawsource is fall-backed by using node.astext() value.
|
||||||
|
|
||||||
|
`extract_message` which is used from Sphinx i18n feature drop ``not node.rawsource`` nodes.
|
||||||
|
So, all nodes which want to translate must have ``rawsource`` value.
|
||||||
|
However, sometimes node.rawsource is not set.
|
||||||
|
|
||||||
|
For example: recommonmark-0.2.0 doesn't set rawsource to `paragraph` node.
|
||||||
|
|
||||||
|
refs #1994: Fall back to node's astext() during i18n message extraction.
|
||||||
|
"""
|
||||||
|
p = nodes.paragraph()
|
||||||
|
p.append(nodes.Text('test'))
|
||||||
|
p.append(nodes.Text('sentence'))
|
||||||
|
assert not p.rawsource # target node must not have rawsource value
|
||||||
|
document = create_new_document()
|
||||||
|
document.append(p)
|
||||||
|
_transform(document)
|
||||||
|
assert_node_count(extract_messages(document), nodes.TextElement, 1)
|
||||||
|
assert [m for n, m in extract_messages(document)][0], 'text sentence'
|
||||||
|
Loading…
Reference in New Issue
Block a user