Skip to content

Commit 14821a9

Browse files
authored
Merge pull request #10091 from Jean-Abou-Samra/sorted-glossary
In translated docs, sort glossaries by translated terms
2 parents 3ed9265 + 0269bec commit 14821a9

File tree

6 files changed

+125
-55
lines changed

6 files changed

+125
-55
lines changed

doc/usage/restructuredtext/directives.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,9 @@ Glossary
831831
.. versionchanged:: 1.4
832832
Index key for glossary term should be considered *experimental*.
833833

834+
.. versionchanged:: 4.4
835+
In internationalized documentation, the ``:sorted:`` flag sorts
836+
according to translated terms.
834837

835838
Meta-information markup
836839
-----------------------

sphinx/domains/std.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"""
1010

1111
import re
12-
import unicodedata
1312
import warnings
1413
from copy import copy
1514
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional,
@@ -336,6 +335,7 @@ class Glossary(SphinxDirective):
336335
def run(self) -> List[Node]:
337336
node = addnodes.glossary()
338337
node.document = self.state.document
338+
node['sorted'] = ('sorted' in self.options)
339339

340340
# This directive implements a custom format of the reST definition list
341341
# that allows multiple lines of terms before the definition. This is
@@ -400,9 +400,8 @@ def run(self) -> List[Node]:
400400
was_empty = False
401401

402402
# now, parse all the entries into a big definition list
403-
items = []
403+
items: List[nodes.definition_list_item] = []
404404
for terms, definition in entries:
405-
termtexts: List[str] = []
406405
termnodes: List[Node] = []
407406
system_messages: List[Node] = []
408407
for line, source, lineno in terms:
@@ -416,7 +415,6 @@ def run(self) -> List[Node]:
416415
node_id=None, document=self.state.document)
417416
term.rawsource = line
418417
system_messages.extend(sysmsg)
419-
termtexts.append(term.astext())
420418
termnodes.append(term)
421419

422420
termnodes.extend(system_messages)
@@ -426,16 +424,10 @@ def run(self) -> List[Node]:
426424
self.state.nested_parse(definition, definition.items[0][1],
427425
defnode)
428426
termnodes.append(defnode)
429-
items.append((termtexts,
430-
nodes.definition_list_item('', *termnodes)))
427+
items.append(nodes.definition_list_item('', *termnodes))
431428

432-
if 'sorted' in self.options:
433-
items.sort(key=lambda x:
434-
unicodedata.normalize('NFD', x[0][0].lower()))
435-
436-
dlist = nodes.definition_list()
429+
dlist = nodes.definition_list('', *items)
437430
dlist['classes'].append('glossary')
438-
dlist.extend(item[1] for item in items)
439431
node += dlist
440432
return messages + [node]
441433

sphinx/transforms/__init__.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
"""
1010

1111
import re
12+
import unicodedata
1213
import warnings
13-
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Tuple
14+
from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Tuple, cast
1415

1516
from docutils import nodes
1617
from docutils.nodes import Element, Node, Text
@@ -405,6 +406,24 @@ def apply(self, **kwargs: Any) -> None:
405406
node.attributes.update(info)
406407

407408

409+
class GlossarySorter(SphinxTransform):
410+
"""Sort glossaries that have the ``sorted`` flag."""
411+
# This must be done after i18n, therefore not right
412+
# away in the glossary directive.
413+
default_priority = 500
414+
415+
def apply(self, **kwargs: Any) -> None:
416+
for glossary in self.document.findall(addnodes.glossary):
417+
if glossary["sorted"]:
418+
definition_list = cast(nodes.definition_list, glossary[0])
419+
definition_list[:] = sorted(
420+
definition_list,
421+
key=lambda item: unicodedata.normalize(
422+
'NFD',
423+
cast(nodes.term, item)[0].astext().lower())
424+
)
425+
426+
408427
def setup(app: "Sphinx") -> Dict[str, Any]:
409428
app.add_transform(ApplySourceWorkaround)
410429
app.add_transform(ExtraTranslatableNodes)
@@ -420,6 +439,7 @@ def setup(app: "Sphinx") -> Dict[str, Any]:
420439
app.add_transform(SphinxSmartQuotes)
421440
app.add_transform(DoctreeReadEvent)
422441
app.add_transform(ManpageLink)
442+
app.add_transform(GlossarySorter)
423443

424444
return {
425445
'version': 'builtin',

tests/roots/test-intl/glossary_terms.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,18 @@ i18n with glossary terms
1212
The corresponding glossary #2
1313

1414
link to :term:`Some term`.
15+
16+
Translated glossary should be sorted by translated terms:
17+
18+
.. glossary::
19+
:sorted:
20+
21+
AAA
22+
Define AAA
23+
24+
CCC
25+
EEE
26+
Define CCC
27+
28+
BBB
29+
Define BBB
Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,59 @@
1-
# SOME DESCRIPTIVE TITLE.
2-
# Copyright (C) 2012, foof
3-
# This file is distributed under the same license as the foo package.
4-
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5-
#
6-
#, fuzzy
7-
msgid ""
8-
msgstr ""
9-
"Project-Id-Version: sphinx 1.0\n"
10-
"Report-Msgid-Bugs-To: \n"
11-
"POT-Creation-Date: 2013-01-29 14:10+0000\n"
12-
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13-
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14-
"Language-Team: LANGUAGE <LL@li.org>\n"
15-
"MIME-Version: 1.0\n"
16-
"Content-Type: text/plain; charset=UTF-8\n"
17-
"Content-Transfer-Encoding: 8bit\n"
18-
19-
msgid "i18n with glossary terms"
20-
msgstr "I18N WITH GLOSSARY TERMS"
21-
22-
msgid "Some term"
23-
msgstr "SOME NEW TERM"
24-
25-
msgid "The corresponding glossary"
26-
msgstr "THE CORRESPONDING GLOSSARY"
27-
28-
msgid "Some other term"
29-
msgstr "SOME OTHER NEW TERM"
30-
31-
msgid "The corresponding glossary #2"
32-
msgstr "THE CORRESPONDING GLOSSARY #2"
33-
34-
msgid "link to :term:`Some term`."
35-
msgstr "LINK TO :term:`SOME NEW TERM`."
1+
# SOME DESCRIPTIVE TITLE.
2+
# Copyright (C) 2012, foof
3+
# This file is distributed under the same license as the foo package.
4+
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5+
#
6+
#, fuzzy
7+
msgid ""
8+
msgstr ""
9+
"Project-Id-Version: sphinx 1.0\n"
10+
"Report-Msgid-Bugs-To: \n"
11+
"POT-Creation-Date: 2013-01-29 14:10+0000\n"
12+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14+
"Language-Team: LANGUAGE <LL@li.org>\n"
15+
"MIME-Version: 1.0\n"
16+
"Content-Type: text/plain; charset=UTF-8\n"
17+
"Content-Transfer-Encoding: 8bit\n"
18+
19+
msgid "i18n with glossary terms"
20+
msgstr "I18N WITH GLOSSARY TERMS"
21+
22+
msgid "Some term"
23+
msgstr "SOME NEW TERM"
24+
25+
msgid "The corresponding glossary"
26+
msgstr "THE CORRESPONDING GLOSSARY"
27+
28+
msgid "Some other term"
29+
msgstr "SOME OTHER NEW TERM"
30+
31+
msgid "The corresponding glossary #2"
32+
msgstr "THE CORRESPONDING GLOSSARY #2"
33+
34+
msgid "link to :term:`Some term`."
35+
msgstr "LINK TO :term:`SOME NEW TERM`."
36+
37+
msgid "Translated glossary should be sorted by translated terms:"
38+
msgstr "TRANSLATED GLOSSARY SHOULD BE SORTED BY TRANSLATED TERMS:"
39+
40+
msgid "BBB"
41+
msgstr "TRANSLATED TERM XXX"
42+
43+
msgid "Define BBB"
44+
msgstr "DEFINE XXX"
45+
46+
msgid "AAA"
47+
msgstr "TRANSLATED TERM YYY"
48+
49+
msgid "Define AAA"
50+
msgstr "DEFINE YYY"
51+
52+
msgid "CCC"
53+
msgstr "TRANSLATED TERM ZZZ"
54+
55+
msgid "EEE"
56+
msgstr "VVV"
57+
58+
msgid "Define CCC"
59+
msgstr "DEFINE ZZZ"

tests/test_intl.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,29 @@ def test_text_glossary_term(app, warning):
241241
app.build()
242242
# --- glossary terms: regression test for #1090
243243
result = (app.outdir / 'glossary_terms.txt').read_text()
244-
expect = ("18. I18N WITH GLOSSARY TERMS"
245-
"\n****************************\n"
246-
"\nSOME NEW TERM"
247-
"\n THE CORRESPONDING GLOSSARY\n"
248-
"\nSOME OTHER NEW TERM"
249-
"\n THE CORRESPONDING GLOSSARY #2\n"
250-
"\nLINK TO *SOME NEW TERM*.\n")
244+
expect = (r"""18. I18N WITH GLOSSARY TERMS
245+
****************************
246+
247+
SOME NEW TERM
248+
THE CORRESPONDING GLOSSARY
249+
250+
SOME OTHER NEW TERM
251+
THE CORRESPONDING GLOSSARY #2
252+
253+
LINK TO *SOME NEW TERM*.
254+
255+
TRANSLATED GLOSSARY SHOULD BE SORTED BY TRANSLATED TERMS:
256+
257+
TRANSLATED TERM XXX
258+
DEFINE XXX
259+
260+
TRANSLATED TERM YYY
261+
DEFINE YYY
262+
263+
TRANSLATED TERM ZZZ
264+
VVV
265+
DEFINE ZZZ
266+
""")
251267
assert result == expect
252268
warnings = getwarning(warning)
253269
assert 'term not in glossary' not in warnings

0 commit comments

Comments
 (0)