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
|
||||
----------
|
||||
|
||||
* #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
|
||||
lines after class definitions.
|
||||
* #1790: ``literalinclude`` strips empty lines at the head and tail.
|
||||
* #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
|
||||
Takayuki Hirai.
|
||||
* #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.
|
||||
* #1903: Fix strange id generation for glossary terms.
|
||||
* #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:
|
||||
* Fixed #1855: make gettext generates broken po file for definition lists with classifier.
|
||||
``term : classifier1 : classifier2``.
|
||||
* #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
|
||||
Marvin Schmidt.
|
||||
* #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
|
||||
-------------
|
||||
|
2
setup.py
2
setup.py
@ -51,7 +51,7 @@ requires = [
|
||||
'Pygments>=2.0',
|
||||
'docutils>=0.11',
|
||||
'snowballstemmer>=1.1',
|
||||
'babel>=1.3',
|
||||
'babel>=1.3,!=2.0',
|
||||
'alabaster>=0.7,<0.8',
|
||||
'sphinx_rtd_theme>=0.1,<0.2',
|
||||
]
|
||||
|
@ -160,10 +160,14 @@ class Builder(object):
|
||||
def compile_catalogs(self, catalogs, message):
|
||||
if not self.config.gettext_auto_build:
|
||||
return
|
||||
|
||||
def cat2relpath(cat):
|
||||
return path.relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
|
||||
|
||||
self.info(bold('building [mo]: ') + message)
|
||||
for catalog in self.app.status_iterator(
|
||||
catalogs, 'writing output... ', darkgreen, len(catalogs),
|
||||
lambda c: c.mo_path):
|
||||
cat2relpath):
|
||||
catalog.write_mo(self.config.language)
|
||||
|
||||
def compile_all_catalogs(self):
|
||||
|
@ -945,7 +945,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
def assemble_doctree(self):
|
||||
master = self.config.master_doc
|
||||
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
|
||||
self.env.resolve_references(tree, master, self)
|
||||
self.fix_refuris(tree)
|
||||
|
@ -102,11 +102,22 @@ class LaTeXBuilder(Builder):
|
||||
doctree.settings = docsettings
|
||||
doctree.settings.author = author
|
||||
doctree.settings.title = title
|
||||
doctree.settings.contentsname = self.get_contentsname(docname)
|
||||
doctree.settings.docname = docname
|
||||
doctree.settings.docclass = docclass
|
||||
docwriter.write(doctree, destination)
|
||||
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):
|
||||
self.docnames = set([indexfile] + appendices)
|
||||
self.info(darkgreen(indexfile) + " ", nonl=1)
|
||||
@ -124,7 +135,7 @@ class LaTeXBuilder(Builder):
|
||||
new_sect += node
|
||||
tree = new_tree
|
||||
largetree = inline_all_toctrees(self, self.docnames, indexfile, tree,
|
||||
darkgreen)
|
||||
darkgreen, [indexfile])
|
||||
largetree['docname'] = indexfile
|
||||
for docname in appendices:
|
||||
appendix = self.env.get_doctree(docname)
|
||||
|
@ -70,7 +70,7 @@ class ManualPageBuilder(Builder):
|
||||
tree = self.env.get_doctree(docname)
|
||||
docnames = set()
|
||||
largetree = inline_all_toctrees(self, docnames, docname, tree,
|
||||
darkgreen)
|
||||
darkgreen, [docname])
|
||||
self.info('} ', nonl=True)
|
||||
self.env.resolve_references(largetree, docname, self)
|
||||
# remove pending_xref nodes
|
||||
|
@ -180,7 +180,7 @@ class TexinfoBuilder(Builder):
|
||||
new_sect += node
|
||||
tree = new_tree
|
||||
largetree = inline_all_toctrees(self, self.docnames, indexfile, tree,
|
||||
darkgreen)
|
||||
darkgreen, [indexfile])
|
||||
largetree['docname'] = indexfile
|
||||
for docname in appendices:
|
||||
appendix = self.env.get_doctree(docname)
|
||||
|
@ -142,7 +142,7 @@ class Author(Directive):
|
||||
env = self.state.document.settings.env
|
||||
if not env.config.show_authors:
|
||||
return []
|
||||
para = nodes.paragraph()
|
||||
para = nodes.paragraph(translatable=False)
|
||||
emph = nodes.emphasis()
|
||||
para += emph
|
||||
if self.name == 'sectionauthor':
|
||||
@ -205,7 +205,7 @@ class VersionChange(Directive):
|
||||
if len(self.arguments) == 2:
|
||||
inodes, messages = self.state.inline_text(self.arguments[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)
|
||||
node.append(para)
|
||||
else:
|
||||
@ -218,13 +218,14 @@ class VersionChange(Directive):
|
||||
content.source = node[0].source
|
||||
content.line = node[0].line
|
||||
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,
|
||||
classes=['versionmodified']))
|
||||
else:
|
||||
para = nodes.paragraph('', '',
|
||||
nodes.inline('', '%s.' % text,
|
||||
classes=['versionmodified']))
|
||||
classes=['versionmodified']),
|
||||
translatable=False)
|
||||
node.append(para)
|
||||
env = self.state.document.settings.env
|
||||
# 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.locale import _
|
||||
from sphinx.versioning import add_uids, merge_doctrees
|
||||
from sphinx.transforms import DefaultSubstitutions, MoveModuleTargets, \
|
||||
HandleCodeBlocks, AutoNumbering, SortIds, CitationReferences, Locale, \
|
||||
RemoveTranslatableInline, SphinxContentsFilter, ExtraTranslatableNodes
|
||||
from sphinx.transforms import (
|
||||
DefaultSubstitutions, MoveModuleTargets, ApplySourceWorkaround,
|
||||
HandleCodeBlocks, AutoNumbering, SortIds, CitationReferences, Locale,
|
||||
RemoveTranslatableInline, SphinxContentsFilter, ExtraTranslatableNodes,
|
||||
)
|
||||
|
||||
|
||||
orig_role_function = roles.role
|
||||
@ -99,7 +101,7 @@ class SphinxStandaloneReader(standalone.Reader):
|
||||
"""
|
||||
Add our own transforms.
|
||||
"""
|
||||
transforms = [ExtraTranslatableNodes, Locale, CitationReferences,
|
||||
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, Locale, CitationReferences,
|
||||
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
|
||||
AutoNumbering, SortIds, RemoveTranslatableInline]
|
||||
|
||||
|
@ -9,14 +9,16 @@
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import codecs
|
||||
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.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.compat import Directive
|
||||
from sphinx.util.console import bold
|
||||
|
||||
# circumvent relative import
|
||||
doctest = __import__('doctest')
|
||||
from sphinx.util.osutil import fs_encoding
|
||||
|
||||
blankline_re = re.compile(r'^\s*<BLANKLINE>', 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
|
||||
|
||||
@ -165,6 +184,11 @@ class TestCode(object):
|
||||
|
||||
|
||||
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):
|
||||
string_io = StringIO()
|
||||
old_stdout = sys.stdout
|
||||
@ -358,19 +382,25 @@ Doctest summary
|
||||
return compile(code, name, self.type, flags, dont_inherit)
|
||||
|
||||
def test_group(self, group, filename):
|
||||
if PY2:
|
||||
filename_str = filename.encode(fs_encoding)
|
||||
else:
|
||||
filename_str = filename
|
||||
|
||||
ns = {}
|
||||
|
||||
def run_setup_cleanup(runner, testcodes, what):
|
||||
examples = []
|
||||
for testcode in testcodes:
|
||||
examples.append(doctest.Example(testcode.code, '',
|
||||
lineno=testcode.lineno))
|
||||
examples.append(doctest.Example(
|
||||
doctest_encode(testcode.code, self.env.config.source_encoding), '',
|
||||
lineno=testcode.lineno))
|
||||
if not examples:
|
||||
return True
|
||||
# simulate a doctest with the code
|
||||
sim_doctest = doctest.DocTest(examples, {},
|
||||
'%s (%s code)' % (group.name, what),
|
||||
filename, 0, None)
|
||||
filename_str, 0, None)
|
||||
sim_doctest.globs = ns
|
||||
old_f = runner.failures
|
||||
self.type = 'exec' # the snippet may contain multiple statements
|
||||
@ -389,8 +419,9 @@ Doctest summary
|
||||
if len(code) == 1:
|
||||
# ordinary doctests (code/output interleaved)
|
||||
try:
|
||||
test = parser.get_doctest(code[0].code, {}, group.name,
|
||||
filename, code[0].lineno)
|
||||
test = parser.get_doctest(
|
||||
doctest_encode(code[0].code, self.env.config.source_encoding), {},
|
||||
group.name, filename_str, code[0].lineno)
|
||||
except Exception:
|
||||
self.warn('ignoring invalid doctest code: %r' %
|
||||
code[0].code,
|
||||
@ -416,12 +447,13 @@ Doctest summary
|
||||
exc_msg = m.group('msg')
|
||||
else:
|
||||
exc_msg = None
|
||||
example = doctest.Example(code[0].code, output,
|
||||
exc_msg=exc_msg,
|
||||
lineno=code[0].lineno,
|
||||
options=options)
|
||||
example = doctest.Example(
|
||||
doctest_encode(code[0].code, self.env.config.source_encoding), output,
|
||||
exc_msg=exc_msg,
|
||||
lineno=code[0].lineno,
|
||||
options=options)
|
||||
test = doctest.DocTest([example], {}, group.name,
|
||||
filename, code[0].lineno, None)
|
||||
filename_str, code[0].lineno, None)
|
||||
self.type = 'exec' # multiple statements again
|
||||
# DocTest.__init__ copies the globs namespace, which we don't want
|
||||
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.nodes import (
|
||||
traverse_translatable_index, extract_messages, LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
|
||||
apply_source_workaround,
|
||||
)
|
||||
from sphinx.util.osutil import ustrftime
|
||||
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):
|
||||
"""
|
||||
make nodes translatable
|
||||
@ -277,8 +290,10 @@ class Locale(Transform):
|
||||
# document nameids mapping with new name.
|
||||
names = section_node.setdefault('names', [])
|
||||
names.append(new_name)
|
||||
if old_name in names:
|
||||
names.remove(old_name)
|
||||
# Original section name (reference target name) should be kept to refer
|
||||
# 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)
|
||||
explicit = self.document.nametypes.get(old_name, None)
|
||||
|
@ -50,6 +50,10 @@ def apply_source_workaround(node):
|
||||
# overwrite: ``term : classifier1 : classifier2`` -> ``term text``
|
||||
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:
|
||||
return
|
||||
|
||||
@ -74,18 +78,20 @@ IGNORED_NODES = (
|
||||
nodes.Inline,
|
||||
nodes.literal_block,
|
||||
nodes.doctest_block,
|
||||
addnodes.versionmodified,
|
||||
# XXX there are probably more
|
||||
)
|
||||
|
||||
|
||||
def is_translatable(node):
|
||||
if isinstance(node, nodes.TextElement):
|
||||
apply_source_workaround(node)
|
||||
|
||||
if not node.source:
|
||||
return False # built-in message
|
||||
if isinstance(node, IGNORED_NODES) and 'translatable' not in node:
|
||||
return False
|
||||
if not node.get('translatable', True):
|
||||
# not(node['translatable'] == True or node['translatable'] is None)
|
||||
return False
|
||||
# <field_name>orphan</field_name>
|
||||
# XXX ignore all metadata (== docinfo)
|
||||
if isinstance(node, nodes.field_name) and node.children[0] == 'orphan':
|
||||
@ -228,7 +234,7 @@ def process_index_entry(entry, targetid):
|
||||
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*.
|
||||
|
||||
Record all docnames in *docnameset*, and output docnames with *colorfunc*.
|
||||
@ -238,23 +244,25 @@ def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc):
|
||||
newnodes = []
|
||||
includefiles = map(text_type, toctreenode['includefiles'])
|
||||
for includefile in includefiles:
|
||||
try:
|
||||
builder.info(colorfunc(includefile) + " ", nonl=1)
|
||||
subtree = inline_all_toctrees(builder, docnameset, includefile,
|
||||
builder.env.get_doctree(includefile),
|
||||
colorfunc)
|
||||
docnameset.add(includefile)
|
||||
except Exception:
|
||||
builder.warn('toctree contains ref to nonexisting '
|
||||
'file %r' % includefile,
|
||||
builder.env.doc2path(docname))
|
||||
else:
|
||||
sof = addnodes.start_of_file(docname=includefile)
|
||||
sof.children = subtree.children
|
||||
for sectionnode in sof.traverse(nodes.section):
|
||||
if 'docname' not in sectionnode:
|
||||
sectionnode['docname'] = includefile
|
||||
newnodes.append(sof)
|
||||
if includefile not in traversed:
|
||||
try:
|
||||
traversed.append(includefile)
|
||||
builder.info(colorfunc(includefile) + " ", nonl=1)
|
||||
subtree = inline_all_toctrees(builder, docnameset, includefile,
|
||||
builder.env.get_doctree(includefile),
|
||||
colorfunc, traversed)
|
||||
docnameset.add(includefile)
|
||||
except Exception:
|
||||
builder.warn('toctree contains ref to nonexisting '
|
||||
'file %r' % includefile,
|
||||
builder.env.doc2path(docname))
|
||||
else:
|
||||
sof = addnodes.start_of_file(docname=includefile)
|
||||
sof.children = subtree.children
|
||||
for sectionnode in sof.traverse(nodes.section):
|
||||
if 'docname' not in sectionnode:
|
||||
sectionnode['docname'] = includefile
|
||||
newnodes.append(sof)
|
||||
toctreenode.parent.replace(toctreenode, newnodes)
|
||||
return tree
|
||||
|
||||
|
@ -43,6 +43,7 @@ HEADER = r'''%% Generated by Sphinx.
|
||||
\usepackage{sphinx}
|
||||
\usepackage{multirow}
|
||||
%(usepackages)s
|
||||
%(contentsname)s
|
||||
%(numfig_format)s
|
||||
%(preamble)s
|
||||
|
||||
@ -159,6 +160,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
'longtable': '\\usepackage{longtable}',
|
||||
'usepackages': '',
|
||||
'numfig_format': '',
|
||||
'contentsname': '',
|
||||
'preamble': '',
|
||||
'title': '',
|
||||
'date': '',
|
||||
@ -248,6 +250,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
return '\\usepackage{%s}' % (packagename,)
|
||||
usepackages = (declare_package(*p) for p in builder.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)
|
||||
# allow the user to override them all
|
||||
self.elements.update(builder.config.latex_elements)
|
||||
@ -329,8 +335,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
encode('ascii', 'backslashreplace').decode('ascii').\
|
||||
replace('\\', '_')
|
||||
|
||||
def generate_numfig_format(self, builder):
|
||||
ret = []
|
||||
def babel_renewcommand(self, builder, command, definition):
|
||||
if builder.config.language == 'ja':
|
||||
babel_prefix = ''
|
||||
babel_suffix = ''
|
||||
@ -349,15 +354,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
babel_prefix = ''
|
||||
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)
|
||||
if len(figure) == 1:
|
||||
ret.append('\\def\\fnum@figure{%s}\n' %
|
||||
text_type(figure[0]).translate(tex_escape_map))
|
||||
else:
|
||||
ret.append('%s\\renewcommand{\\figurename}{%s}%s\n' %
|
||||
(babel_prefix,
|
||||
text_type(figure[0]).translate(tex_escape_map),
|
||||
babel_suffix))
|
||||
definition = text_type(figure[0]).translate(tex_escape_map)
|
||||
ret.append(self.babel_renewcommand(builder, '\\figurename', definition))
|
||||
if figure[1]:
|
||||
ret.append('\\makeatletter\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' %
|
||||
text_type(table[0]).translate(tex_escape_map))
|
||||
else:
|
||||
ret.append('%s\\renewcommand{\\tablename}{%s}%s\n' %
|
||||
(babel_prefix,
|
||||
text_type(table[0]).translate(tex_escape_map),
|
||||
babel_suffix))
|
||||
definition = text_type(table[0]).translate(tex_escape_map)
|
||||
ret.append(self.babel_renewcommand(builder, '\\tablename', definition))
|
||||
if table[1]:
|
||||
ret.append('\\makeatletter\n')
|
||||
ret.append('\\def\\fnum@table{\\tablename\\thetable%s}\n' %
|
||||
@ -1707,6 +1713,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
if classes in [['menuselection'], ['guilabel']]:
|
||||
self.body.append(r'\emph{')
|
||||
self.context.append('}')
|
||||
elif classes in [['accelerator']]:
|
||||
self.body.append(r'\underline{')
|
||||
self.context.append('}')
|
||||
elif classes and not self.in_title:
|
||||
self.body.append(r'\DUspan{%s}{' % ','.join(classes))
|
||||
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
|
||||
test_ext_doctest.cleanup_call()
|
||||
|
||||
non-ASCII result
|
||||
----------------
|
||||
|
||||
>>> print('umlauts: äöü.')
|
||||
umlauts: äöü.
|
||||
>>> print('Japanese: 日本語')
|
||||
Japanese: 日本語
|
||||
|
||||
|
@ -22,3 +22,4 @@ CONTENTS
|
||||
versionchange
|
||||
docfields
|
||||
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')
|
||||
assert '\\usepackage{foo}' 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" />"""
|
||||
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`',
|
||||
u'<p><span class="guilabel"><span class="accelerator">F</span>oo '
|
||||
'-&- <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
|
||||
yield (verify_re, ':option:`--with-option`',
|
||||
|
@ -16,13 +16,24 @@ from docutils.utils import new_document
|
||||
from docutils import frontend
|
||||
|
||||
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(
|
||||
components=(rst.Parser,)).get_default_values()
|
||||
document = new_document('dummy.txt', settings)
|
||||
return document
|
||||
|
||||
|
||||
def _get_doctree(text):
|
||||
document = create_new_document()
|
||||
rst.Parser().parse(text, document)
|
||||
_transform(document)
|
||||
return document
|
||||
|
||||
|
||||
@ -119,3 +130,26 @@ def test_extract_messages():
|
||||
extract_messages(_get_doctree(text)),
|
||||
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