Sphinx 8.1.2__py3-none-any.whl → 8.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of Sphinx might be problematic. Click here for more details.
- sphinx/__init__.py +8 -4
- sphinx/__main__.py +2 -0
- sphinx/_cli/__init__.py +2 -5
- sphinx/_cli/util/colour.py +34 -11
- sphinx/_cli/util/errors.py +128 -61
- sphinx/addnodes.py +51 -35
- sphinx/application.py +362 -230
- sphinx/builders/__init__.py +87 -64
- sphinx/builders/_epub_base.py +65 -56
- sphinx/builders/changes.py +17 -23
- sphinx/builders/dirhtml.py +8 -13
- sphinx/builders/epub3.py +70 -38
- sphinx/builders/gettext.py +93 -73
- sphinx/builders/html/__init__.py +240 -186
- sphinx/builders/html/_assets.py +9 -2
- sphinx/builders/html/_build_info.py +3 -0
- sphinx/builders/latex/__init__.py +64 -54
- sphinx/builders/latex/constants.py +14 -11
- sphinx/builders/latex/nodes.py +2 -0
- sphinx/builders/latex/theming.py +8 -9
- sphinx/builders/latex/transforms.py +7 -5
- sphinx/builders/linkcheck.py +193 -149
- sphinx/builders/manpage.py +17 -17
- sphinx/builders/singlehtml.py +28 -16
- sphinx/builders/texinfo.py +28 -21
- sphinx/builders/text.py +10 -15
- sphinx/builders/xml.py +10 -19
- sphinx/cmd/build.py +49 -119
- sphinx/cmd/make_mode.py +35 -31
- sphinx/cmd/quickstart.py +78 -62
- sphinx/config.py +265 -163
- sphinx/directives/__init__.py +51 -54
- sphinx/directives/admonitions.py +107 -0
- sphinx/directives/code.py +24 -19
- sphinx/directives/other.py +21 -42
- sphinx/directives/patches.py +28 -16
- sphinx/domains/__init__.py +54 -31
- sphinx/domains/_domains_container.py +22 -17
- sphinx/domains/_index.py +5 -8
- sphinx/domains/c/__init__.py +366 -245
- sphinx/domains/c/_ast.py +378 -256
- sphinx/domains/c/_ids.py +89 -31
- sphinx/domains/c/_parser.py +283 -214
- sphinx/domains/c/_symbol.py +269 -198
- sphinx/domains/changeset.py +39 -24
- sphinx/domains/citation.py +54 -24
- sphinx/domains/cpp/__init__.py +517 -362
- sphinx/domains/cpp/_ast.py +999 -682
- sphinx/domains/cpp/_ids.py +133 -65
- sphinx/domains/cpp/_parser.py +746 -588
- sphinx/domains/cpp/_symbol.py +692 -489
- sphinx/domains/index.py +10 -8
- sphinx/domains/javascript.py +152 -74
- sphinx/domains/math.py +50 -40
- sphinx/domains/python/__init__.py +402 -211
- sphinx/domains/python/_annotations.py +134 -61
- sphinx/domains/python/_object.py +155 -68
- sphinx/domains/rst.py +94 -49
- sphinx/domains/std/__init__.py +510 -249
- sphinx/environment/__init__.py +345 -61
- sphinx/environment/adapters/asset.py +7 -1
- sphinx/environment/adapters/indexentries.py +15 -20
- sphinx/environment/adapters/toctree.py +19 -9
- sphinx/environment/collectors/__init__.py +3 -1
- sphinx/environment/collectors/asset.py +18 -15
- sphinx/environment/collectors/dependencies.py +8 -10
- sphinx/environment/collectors/metadata.py +6 -4
- sphinx/environment/collectors/title.py +3 -1
- sphinx/environment/collectors/toctree.py +4 -4
- sphinx/errors.py +1 -3
- sphinx/events.py +4 -4
- sphinx/ext/apidoc/__init__.py +66 -0
- sphinx/ext/apidoc/__main__.py +9 -0
- sphinx/ext/apidoc/_cli.py +356 -0
- sphinx/ext/apidoc/_extension.py +262 -0
- sphinx/ext/apidoc/_generate.py +356 -0
- sphinx/ext/apidoc/_shared.py +99 -0
- sphinx/ext/autodoc/__init__.py +837 -483
- sphinx/ext/autodoc/directive.py +57 -21
- sphinx/ext/autodoc/importer.py +184 -67
- sphinx/ext/autodoc/mock.py +25 -10
- sphinx/ext/autodoc/preserve_defaults.py +17 -9
- sphinx/ext/autodoc/type_comment.py +56 -29
- sphinx/ext/autodoc/typehints.py +49 -26
- sphinx/ext/autosectionlabel.py +28 -11
- sphinx/ext/autosummary/__init__.py +281 -142
- sphinx/ext/autosummary/generate.py +121 -51
- sphinx/ext/coverage.py +152 -91
- sphinx/ext/doctest.py +169 -101
- sphinx/ext/duration.py +12 -6
- sphinx/ext/extlinks.py +33 -21
- sphinx/ext/githubpages.py +8 -8
- sphinx/ext/graphviz.py +175 -109
- sphinx/ext/ifconfig.py +11 -6
- sphinx/ext/imgconverter.py +48 -25
- sphinx/ext/imgmath.py +127 -97
- sphinx/ext/inheritance_diagram.py +177 -103
- sphinx/ext/intersphinx/__init__.py +22 -13
- sphinx/ext/intersphinx/__main__.py +3 -1
- sphinx/ext/intersphinx/_cli.py +18 -14
- sphinx/ext/intersphinx/_load.py +91 -82
- sphinx/ext/intersphinx/_resolve.py +108 -74
- sphinx/ext/intersphinx/_shared.py +2 -2
- sphinx/ext/linkcode.py +28 -12
- sphinx/ext/mathjax.py +60 -29
- sphinx/ext/napoleon/__init__.py +19 -7
- sphinx/ext/napoleon/docstring.py +229 -231
- sphinx/ext/todo.py +44 -49
- sphinx/ext/viewcode.py +105 -57
- sphinx/extension.py +3 -1
- sphinx/highlighting.py +13 -7
- sphinx/io.py +9 -13
- sphinx/jinja2glue.py +29 -26
- sphinx/locale/__init__.py +8 -9
- sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ar/LC_MESSAGES/sphinx.po +2155 -2050
- sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bg/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/bn/LC_MESSAGES/sphinx.po +2175 -2070
- sphinx/locale/ca/LC_MESSAGES/sphinx.js +3 -3
- sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca/LC_MESSAGES/sphinx.po +2690 -2585
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.js +63 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ca@valencia/LC_MESSAGES/sphinx.po +4216 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cak/LC_MESSAGES/sphinx.po +2096 -1991
- sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cs/LC_MESSAGES/sphinx.po +2248 -2143
- sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/cy/LC_MESSAGES/sphinx.po +2201 -2096
- sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/da/LC_MESSAGES/sphinx.po +2282 -2177
- sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de/LC_MESSAGES/sphinx.po +2261 -2156
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/el/LC_MESSAGES/sphinx.po +2604 -2499
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eo/LC_MESSAGES/sphinx.po +2078 -1973
- sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es/LC_MESSAGES/sphinx.po +2633 -2528
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/et/LC_MESSAGES/sphinx.po +2449 -2344
- sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/eu/LC_MESSAGES/sphinx.po +2241 -2136
- sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fa/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fi/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr/LC_MESSAGES/sphinx.po +513 -509
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/gl/LC_MESSAGES/sphinx.po +2644 -2539
- sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/he/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi/LC_MESSAGES/sphinx.po +504 -500
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hr/LC_MESSAGES/sphinx.po +501 -497
- sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/hu/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/id/LC_MESSAGES/sphinx.po +2609 -2504
- sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/is/LC_MESSAGES/sphinx.po +499 -495
- sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/it/LC_MESSAGES/sphinx.po +2265 -2160
- sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ja/LC_MESSAGES/sphinx.po +2621 -2516
- sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ka/LC_MESSAGES/sphinx.po +2567 -2462
- sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ko/LC_MESSAGES/sphinx.po +2631 -2526
- sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lt/LC_MESSAGES/sphinx.po +2214 -2109
- sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/lv/LC_MESSAGES/sphinx.po +2218 -2113
- sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/mk/LC_MESSAGES/sphinx.po +2088 -1983
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +2247 -2142
- sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ne/LC_MESSAGES/sphinx.po +2227 -2122
- sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/nl/LC_MESSAGES/sphinx.po +2316 -2211
- sphinx/locale/pl/LC_MESSAGES/sphinx.js +2 -2
- sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pl/LC_MESSAGES/sphinx.po +2442 -2336
- sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +2657 -2552
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +2243 -2138
- sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ro/LC_MESSAGES/sphinx.po +2244 -2139
- sphinx/locale/ru/LC_MESSAGES/sphinx.js +1 -1
- sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ru/LC_MESSAGES/sphinx.po +2660 -2555
- sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/si/LC_MESSAGES/sphinx.po +2134 -2029
- sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sk/LC_MESSAGES/sphinx.po +2614 -2509
- sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sl/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/sphinx.pot +2069 -1964
- sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sq/LC_MESSAGES/sphinx.po +2661 -2556
- sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sr/LC_MESSAGES/sphinx.po +2213 -2108
- sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/sv/LC_MESSAGES/sphinx.po +2229 -2124
- sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/te/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/tr/LC_MESSAGES/sphinx.po +2608 -2503
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +2167 -2062
- sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/ur/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/vi/LC_MESSAGES/sphinx.po +2204 -2099
- sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/yue/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +2659 -2554
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
- sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +2045 -1940
- sphinx/parsers.py +8 -7
- sphinx/project.py +2 -2
- sphinx/pycode/__init__.py +31 -21
- sphinx/pycode/ast.py +6 -3
- sphinx/pycode/parser.py +14 -8
- sphinx/pygments_styles.py +4 -5
- sphinx/registry.py +192 -92
- sphinx/roles.py +58 -7
- sphinx/search/__init__.py +75 -54
- sphinx/search/en.py +11 -13
- sphinx/search/fi.py +1 -1
- sphinx/search/ja.py +8 -6
- sphinx/search/nl.py +1 -1
- sphinx/search/zh.py +19 -21
- sphinx/testing/fixtures.py +26 -29
- sphinx/testing/path.py +26 -62
- sphinx/testing/restructuredtext.py +14 -8
- sphinx/testing/util.py +21 -19
- sphinx/texinputs/make.bat.jinja +50 -50
- sphinx/texinputs/sphinx.sty +4 -3
- sphinx/texinputs/sphinxlatexadmonitions.sty +1 -1
- sphinx/texinputs/sphinxlatexobjects.sty +29 -10
- sphinx/themes/basic/static/searchtools.js +8 -5
- sphinx/theming.py +49 -61
- sphinx/transforms/__init__.py +17 -38
- sphinx/transforms/compact_bullet_list.py +5 -3
- sphinx/transforms/i18n.py +8 -21
- sphinx/transforms/post_transforms/__init__.py +142 -93
- sphinx/transforms/post_transforms/code.py +5 -5
- sphinx/transforms/post_transforms/images.py +28 -24
- sphinx/transforms/references.py +3 -1
- sphinx/util/__init__.py +109 -60
- sphinx/util/_files.py +39 -23
- sphinx/util/_importer.py +4 -1
- sphinx/util/_inventory_file_reader.py +76 -0
- sphinx/util/_io.py +2 -2
- sphinx/util/_lines.py +6 -3
- sphinx/util/_pathlib.py +40 -2
- sphinx/util/build_phase.py +2 -0
- sphinx/util/cfamily.py +19 -14
- sphinx/util/console.py +44 -179
- sphinx/util/display.py +9 -10
- sphinx/util/docfields.py +140 -122
- sphinx/util/docstrings.py +1 -1
- sphinx/util/docutils.py +118 -77
- sphinx/util/fileutil.py +25 -26
- sphinx/util/http_date.py +2 -0
- sphinx/util/i18n.py +77 -64
- sphinx/util/images.py +8 -6
- sphinx/util/inspect.py +147 -38
- sphinx/util/inventory.py +215 -116
- sphinx/util/logging.py +33 -33
- sphinx/util/matching.py +12 -4
- sphinx/util/nodes.py +18 -13
- sphinx/util/osutil.py +38 -39
- sphinx/util/parallel.py +22 -13
- sphinx/util/parsing.py +2 -1
- sphinx/util/png.py +6 -2
- sphinx/util/requests.py +33 -2
- sphinx/util/rst.py +3 -2
- sphinx/util/tags.py +1 -1
- sphinx/util/template.py +18 -10
- sphinx/util/texescape.py +8 -6
- sphinx/util/typing.py +148 -122
- sphinx/versioning.py +3 -3
- sphinx/writers/html.py +3 -1
- sphinx/writers/html5.py +63 -52
- sphinx/writers/latex.py +83 -67
- sphinx/writers/manpage.py +19 -38
- sphinx/writers/texinfo.py +47 -47
- sphinx/writers/text.py +50 -32
- sphinx/writers/xml.py +11 -8
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/LICENSE.rst +1 -1
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/METADATA +25 -15
- sphinx-8.2.0.dist-info/RECORD +606 -0
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/WHEEL +1 -1
- sphinx/builders/html/transforms.py +0 -90
- sphinx/ext/apidoc.py +0 -721
- sphinx/util/exceptions.py +0 -74
- sphinx-8.1.2.dist-info/RECORD +0 -598
- {sphinx-8.1.2.dist-info → sphinx-8.2.0.dist-info}/entry_points.txt +0 -0
sphinx/builders/gettext.py
CHANGED
|
@@ -2,25 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import codecs
|
|
5
6
|
import operator
|
|
7
|
+
import os
|
|
8
|
+
import os.path
|
|
6
9
|
import time
|
|
7
|
-
from codecs import open
|
|
8
10
|
from collections import defaultdict
|
|
9
|
-
from os import getenv,
|
|
11
|
+
from os import getenv, walk
|
|
10
12
|
from pathlib import Path
|
|
11
|
-
from typing import TYPE_CHECKING
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
12
14
|
from uuid import uuid4
|
|
13
15
|
|
|
14
16
|
from docutils import nodes
|
|
15
17
|
|
|
16
18
|
from sphinx import addnodes, package_dir
|
|
19
|
+
from sphinx._cli.util.colour import bold
|
|
17
20
|
from sphinx.builders import Builder
|
|
18
21
|
from sphinx.errors import ThemeError
|
|
19
22
|
from sphinx.locale import __
|
|
20
23
|
from sphinx.util import logging
|
|
21
|
-
from sphinx.util.console import bold
|
|
22
24
|
from sphinx.util.display import status_iterator
|
|
23
|
-
from sphinx.util.i18n import
|
|
25
|
+
from sphinx.util.i18n import docname_to_domain
|
|
24
26
|
from sphinx.util.index_entries import split_index_msg
|
|
25
27
|
from sphinx.util.nodes import extract_messages, traverse_translatable_index
|
|
26
28
|
from sphinx.util.osutil import canon_path, ensuredir, relpath
|
|
@@ -28,16 +30,16 @@ from sphinx.util.tags import Tags
|
|
|
28
30
|
from sphinx.util.template import SphinxRenderer
|
|
29
31
|
|
|
30
32
|
if TYPE_CHECKING:
|
|
31
|
-
import os
|
|
32
33
|
from collections.abc import Iterable, Iterator, Sequence
|
|
34
|
+
from typing import Any, Literal
|
|
33
35
|
|
|
34
36
|
from docutils.nodes import Element
|
|
35
37
|
|
|
36
38
|
from sphinx.application import Sphinx
|
|
37
|
-
from sphinx.
|
|
39
|
+
from sphinx.util.i18n import CatalogInfo
|
|
38
40
|
from sphinx.util.typing import ExtensionMetadata
|
|
39
41
|
|
|
40
|
-
DEFAULT_TEMPLATE_PATH =
|
|
42
|
+
DEFAULT_TEMPLATE_PATH = package_dir.joinpath('templates', 'gettext')
|
|
41
43
|
|
|
42
44
|
logger = logging.getLogger(__name__)
|
|
43
45
|
|
|
@@ -45,6 +47,12 @@ logger = logging.getLogger(__name__)
|
|
|
45
47
|
class Message:
|
|
46
48
|
"""An entry of translatable message."""
|
|
47
49
|
|
|
50
|
+
__slots__ = 'text', 'locations', 'uuids'
|
|
51
|
+
|
|
52
|
+
text: str
|
|
53
|
+
locations: list[tuple[str, int]]
|
|
54
|
+
uuids: list[str]
|
|
55
|
+
|
|
48
56
|
def __init__(
|
|
49
57
|
self, text: str, locations: list[tuple[str, int]], uuids: list[str]
|
|
50
58
|
) -> None:
|
|
@@ -52,48 +60,60 @@ class Message:
|
|
|
52
60
|
self.locations = locations
|
|
53
61
|
self.uuids = uuids
|
|
54
62
|
|
|
63
|
+
def __repr__(self) -> str:
|
|
64
|
+
return (
|
|
65
|
+
'Message('
|
|
66
|
+
f'text={self.text!r}, locations={self.locations!r}, uuids={self.uuids!r}'
|
|
67
|
+
')'
|
|
68
|
+
)
|
|
69
|
+
|
|
55
70
|
|
|
56
71
|
class Catalog:
|
|
57
72
|
"""Catalog of translatable messages."""
|
|
58
73
|
|
|
59
|
-
|
|
60
|
-
self.messages: list[str] = [] # retain insertion order
|
|
74
|
+
__slots__ = ('metadata',)
|
|
61
75
|
|
|
76
|
+
def __init__(self) -> None:
|
|
62
77
|
# msgid -> file, line, uid
|
|
63
78
|
self.metadata: dict[str, list[tuple[str, int, str]]] = {}
|
|
64
79
|
|
|
65
80
|
def add(self, msg: str, origin: Element | MsgOrigin) -> None:
|
|
66
81
|
if not hasattr(origin, 'uid'):
|
|
67
82
|
# Nodes that are replicated like todo don't have a uid,
|
|
68
|
-
# however
|
|
83
|
+
# however translation is also unnecessary.
|
|
69
84
|
return
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
line = origin.line
|
|
74
|
-
if line is None:
|
|
75
|
-
line = -1
|
|
76
|
-
self.metadata[msg].append((origin.source, line, origin.uid)) # type: ignore[arg-type]
|
|
85
|
+
msg_metadata = self.metadata.setdefault(msg, [])
|
|
86
|
+
line = line if (line := origin.line) is not None else -1
|
|
87
|
+
msg_metadata.append((origin.source or '', line, origin.uid))
|
|
77
88
|
|
|
78
89
|
def __iter__(self) -> Iterator[Message]:
|
|
79
|
-
for message in self.
|
|
80
|
-
positions = sorted(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
for message, msg_metadata in self.metadata.items():
|
|
91
|
+
positions = sorted(set(map(operator.itemgetter(0, 1), msg_metadata)))
|
|
92
|
+
uuids = list(map(operator.itemgetter(2), msg_metadata))
|
|
93
|
+
yield Message(text=message, locations=positions, uuids=uuids)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def messages(self) -> list[str]:
|
|
97
|
+
return list(self.metadata)
|
|
85
98
|
|
|
86
99
|
|
|
87
100
|
class MsgOrigin:
|
|
88
|
-
"""
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
"""Origin holder for Catalog message origin."""
|
|
102
|
+
|
|
103
|
+
__slots__ = 'source', 'line', 'uid'
|
|
104
|
+
|
|
105
|
+
source: str
|
|
106
|
+
line: int
|
|
107
|
+
uid: str
|
|
91
108
|
|
|
92
109
|
def __init__(self, source: str, line: int) -> None:
|
|
93
110
|
self.source = source
|
|
94
111
|
self.line = line
|
|
95
112
|
self.uid = uuid4().hex
|
|
96
113
|
|
|
114
|
+
def __repr__(self) -> str:
|
|
115
|
+
return f'<MsgOrigin {self.source}:{self.line}; uid={self.uid!r}>'
|
|
116
|
+
|
|
97
117
|
|
|
98
118
|
class GettextRenderer(SphinxRenderer):
|
|
99
119
|
def __init__(
|
|
@@ -136,9 +156,7 @@ class I18nTags(Tags):
|
|
|
136
156
|
|
|
137
157
|
|
|
138
158
|
class I18nBuilder(Builder):
|
|
139
|
-
"""
|
|
140
|
-
General i18n builder.
|
|
141
|
-
"""
|
|
159
|
+
"""General i18n builder."""
|
|
142
160
|
|
|
143
161
|
name = 'i18n'
|
|
144
162
|
versioning_method = 'text'
|
|
@@ -146,10 +164,8 @@ class I18nBuilder(Builder):
|
|
|
146
164
|
|
|
147
165
|
def init(self) -> None:
|
|
148
166
|
super().init()
|
|
149
|
-
self.env.set_versioning_method(
|
|
150
|
-
|
|
151
|
-
)
|
|
152
|
-
self.tags = I18nTags()
|
|
167
|
+
self.env.set_versioning_method(self.versioning_method, self.config.gettext_uuid)
|
|
168
|
+
self.tags = self.app.tags = I18nTags()
|
|
153
169
|
self.catalogs: defaultdict[str, Catalog] = defaultdict(Catalog)
|
|
154
170
|
|
|
155
171
|
def get_target_uri(self, docname: str, typ: str | None = None) -> str:
|
|
@@ -174,7 +190,7 @@ class I18nBuilder(Builder):
|
|
|
174
190
|
if not _is_node_in_substitution_definition(node):
|
|
175
191
|
catalog.add(msg, node)
|
|
176
192
|
|
|
177
|
-
if 'index' in self.
|
|
193
|
+
if 'index' in self.config.gettext_additional_targets:
|
|
178
194
|
# Extract translatable messages from index entries.
|
|
179
195
|
for node, entries in traverse_translatable_index(doctree):
|
|
180
196
|
for entry_type, value, _target_id, _main, _category_key in entries:
|
|
@@ -192,20 +208,20 @@ else:
|
|
|
192
208
|
ctime = time.strftime('%Y-%m-%d %H:%M%z', timestamp)
|
|
193
209
|
|
|
194
210
|
|
|
195
|
-
def should_write(filepath:
|
|
196
|
-
if not
|
|
211
|
+
def should_write(filepath: Path, new_content: str) -> bool:
|
|
212
|
+
if not filepath.exists():
|
|
197
213
|
return True
|
|
198
214
|
try:
|
|
199
|
-
with open(filepath, encoding='utf-8') as oldpot:
|
|
215
|
+
with codecs.open(str(filepath), encoding='utf-8') as oldpot:
|
|
200
216
|
old_content = oldpot.read()
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
217
|
+
old_header_index = old_content.index('"POT-Creation-Date:')
|
|
218
|
+
new_header_index = new_content.index('"POT-Creation-Date:')
|
|
219
|
+
old_body_index = old_content.index('"PO-Revision-Date:')
|
|
220
|
+
new_body_index = new_content.index('"PO-Revision-Date:')
|
|
221
|
+
return (
|
|
222
|
+
old_content[:old_header_index] != new_content[:new_header_index]
|
|
223
|
+
or new_content[new_body_index:] != old_content[old_body_index:]
|
|
224
|
+
)
|
|
209
225
|
except ValueError:
|
|
210
226
|
pass
|
|
211
227
|
|
|
@@ -222,9 +238,7 @@ def _is_node_in_substitution_definition(node: nodes.Node) -> bool:
|
|
|
222
238
|
|
|
223
239
|
|
|
224
240
|
class MessageCatalogBuilder(I18nBuilder):
|
|
225
|
-
"""
|
|
226
|
-
Builds gettext-style message catalogs (.pot files).
|
|
227
|
-
"""
|
|
241
|
+
"""Builds gettext-style message catalogs (.pot files)."""
|
|
228
242
|
|
|
229
243
|
name = 'gettext'
|
|
230
244
|
epilog = __('The message catalogs are in %(outdir)s.')
|
|
@@ -237,11 +251,11 @@ class MessageCatalogBuilder(I18nBuilder):
|
|
|
237
251
|
def _collect_templates(self) -> set[str]:
|
|
238
252
|
template_files = set()
|
|
239
253
|
for template_path in self.config.templates_path:
|
|
240
|
-
tmpl_abs_path =
|
|
254
|
+
tmpl_abs_path = self.app.srcdir / template_path
|
|
241
255
|
for dirpath, _dirs, files in walk(tmpl_abs_path):
|
|
242
256
|
for fn in files:
|
|
243
257
|
if fn.endswith('.html'):
|
|
244
|
-
filename =
|
|
258
|
+
filename = Path(dirpath, fn).as_posix()
|
|
245
259
|
template_files.add(filename)
|
|
246
260
|
return template_files
|
|
247
261
|
|
|
@@ -257,10 +271,10 @@ class MessageCatalogBuilder(I18nBuilder):
|
|
|
257
271
|
files, __('reading templates... '), 'purple', len(files), self.app.verbosity
|
|
258
272
|
):
|
|
259
273
|
try:
|
|
260
|
-
with open(template, encoding='utf-8') as f:
|
|
274
|
+
with codecs.open(template, encoding='utf-8') as f:
|
|
261
275
|
context = f.read()
|
|
262
276
|
for line, _meth, msg in extract_translations(context):
|
|
263
|
-
origin = MsgOrigin(template, line)
|
|
277
|
+
origin = MsgOrigin(source=template, line=line)
|
|
264
278
|
self.catalogs['sphinx'].add(msg, origin)
|
|
265
279
|
except Exception as exc:
|
|
266
280
|
msg = f'{template}: {exc!r}'
|
|
@@ -287,6 +301,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
|
|
287
301
|
'display_location': self.config.gettext_location,
|
|
288
302
|
'display_uuid': self.config.gettext_uuid,
|
|
289
303
|
}
|
|
304
|
+
catalog: Catalog
|
|
290
305
|
for textdomain, catalog in status_iterator(
|
|
291
306
|
self.catalogs.items(),
|
|
292
307
|
__('writing message catalogs... '),
|
|
@@ -296,7 +311,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
|
|
296
311
|
operator.itemgetter(0),
|
|
297
312
|
):
|
|
298
313
|
# noop if config.gettext_compact is set
|
|
299
|
-
ensuredir(
|
|
314
|
+
ensuredir(self.outdir / os.path.dirname(textdomain))
|
|
300
315
|
|
|
301
316
|
context['messages'] = list(catalog)
|
|
302
317
|
template_path = [
|
|
@@ -305,34 +320,39 @@ class MessageCatalogBuilder(I18nBuilder):
|
|
|
305
320
|
renderer = GettextRenderer(template_path, outdir=self.outdir)
|
|
306
321
|
content = renderer.render('message.pot.jinja', context)
|
|
307
322
|
|
|
308
|
-
pofn =
|
|
323
|
+
pofn = self.outdir / f'{textdomain}.pot'
|
|
309
324
|
if should_write(pofn, content):
|
|
310
|
-
with open(pofn, 'w', encoding='utf-8') as pofile:
|
|
325
|
+
with codecs.open(str(pofn), 'w', encoding='utf-8') as pofile:
|
|
311
326
|
pofile.write(content)
|
|
312
327
|
|
|
313
328
|
|
|
314
|
-
def _gettext_compact_validator(app: Sphinx, config: Config) -> None:
|
|
315
|
-
gettext_compact = config.gettext_compact
|
|
316
|
-
# Convert 0/1 from the command line to ``bool`` types
|
|
317
|
-
if gettext_compact == '0':
|
|
318
|
-
config.gettext_compact = False
|
|
319
|
-
elif gettext_compact == '1':
|
|
320
|
-
config.gettext_compact = True
|
|
321
|
-
|
|
322
|
-
|
|
323
329
|
def setup(app: Sphinx) -> ExtensionMetadata:
|
|
324
330
|
app.add_builder(MessageCatalogBuilder)
|
|
325
331
|
|
|
326
|
-
app.add_config_value('gettext_compact', True, 'gettext', {bool, str})
|
|
327
|
-
app.add_config_value('gettext_location', True, 'gettext')
|
|
328
|
-
app.add_config_value('gettext_uuid', False, 'gettext')
|
|
329
|
-
app.add_config_value('gettext_auto_build', True, 'env')
|
|
330
|
-
app.add_config_value('gettext_additional_targets', [], 'env', types={set, list})
|
|
331
332
|
app.add_config_value(
|
|
332
|
-
'
|
|
333
|
+
'gettext_compact', True, 'gettext', types=frozenset({bool, str})
|
|
334
|
+
)
|
|
335
|
+
app.add_config_value('gettext_location', True, 'gettext', types=frozenset({bool}))
|
|
336
|
+
app.add_config_value('gettext_uuid', False, 'gettext', types=frozenset({bool}))
|
|
337
|
+
app.add_config_value('gettext_auto_build', True, 'env', types=frozenset({bool}))
|
|
338
|
+
app.add_config_value(
|
|
339
|
+
'gettext_additional_targets',
|
|
340
|
+
[],
|
|
341
|
+
'env',
|
|
342
|
+
types=frozenset({frozenset, list, set, tuple}),
|
|
343
|
+
)
|
|
344
|
+
app.add_config_value(
|
|
345
|
+
'gettext_last_translator',
|
|
346
|
+
'FULL NAME <EMAIL@ADDRESS>',
|
|
347
|
+
'gettext',
|
|
348
|
+
types=frozenset({str}),
|
|
349
|
+
)
|
|
350
|
+
app.add_config_value(
|
|
351
|
+
'gettext_language_team',
|
|
352
|
+
'LANGUAGE <LL@li.org>',
|
|
353
|
+
'gettext',
|
|
354
|
+
types=frozenset({str}),
|
|
333
355
|
)
|
|
334
|
-
app.add_config_value('gettext_language_team', 'LANGUAGE <LL@li.org>', 'gettext')
|
|
335
|
-
app.connect('config-inited', _gettext_compact_validator, priority=800)
|
|
336
356
|
|
|
337
357
|
return {
|
|
338
358
|
'version': 'builtin',
|