Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: translations: add translations links when they exist

Add a new Sphinx extension that knows about the translations of kernel
documentation and can insert links to the translations at the top of
the document.

It basically works like this:

1. Register a new node type, LanguagesNode.

2. Register a new transform, TranslationsTransform, that inserts a new
LanguageNode at the top of every document. The LanguageNode contains
"pending references" to translations of the document. The key here
is that these are pending (i.e. unresolved) references that may or
may not actually exist.

3. Register a 'doctree-resolved' event that iterates over all the
LanguageNode nodes. Any unresolved references are filtered out; the
list of resolved references is passed to the 'translations.html'
template and rendered as an HTML node (if HTML output is selected).

Testing: make htmldocs, make latexdocs with Sphinx v4.3.2 and Firefox.

v2:
- changed bar into a drop-down menu
- fixed language labels
- fixed hysteresis reported by Akira Yokosawa

Cc: Federico Vaga <federico.vaga@vaga.pv.it>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Akira Yokosawa <akiyks@gmail.com>
Cc: Yanteng Si <siyanteng@loongson.cn>
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Link: https://lore.kernel.org/r/20231215123701.2712807-1-vegard.nossum@oracle.com

authored by

Vegard Nossum and committed by
Jonathan Corbet
7418ec5b dcd39fa2

+170 -1
+1 -1
Documentation/conf.py
··· 55 55 extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 56 56 'kfigure', 'sphinx.ext.ifconfig', 'automarkup', 57 57 'maintainers_include', 'sphinx.ext.autosectionlabel', 58 - 'kernel_abi', 'kernel_feat'] 58 + 'kernel_abi', 'kernel_feat', 'translations'] 59 59 60 60 if major >= 3: 61 61 if (major > 3) or (minor > 0 or patch >= 2):
+53
Documentation/sphinx-static/custom.css
··· 83 83 h3.kernel-toc-contents { display: inline; } 84 84 div.kerneltoc a { color: black; } 85 85 } 86 + 87 + /* Language selection menu */ 88 + 89 + div.admonition { 90 + /* 91 + * Make sure we don't overlap notes and warnings at the top of the 92 + * document. 93 + */ 94 + clear: both; 95 + } 96 + 97 + div.language-selection { 98 + background: #eeeeee; 99 + border: 1px solid #cccccc; 100 + margin-bottom: 1em; 101 + padding: .5em; 102 + 103 + position: relative; 104 + float: right; 105 + } 106 + 107 + div.language-selection a { 108 + display: block; 109 + padding: 0.5em; 110 + color: #333333; 111 + text-decoration: none; 112 + } 113 + 114 + div.language-selection ul { 115 + display: none; 116 + position: absolute; 117 + 118 + /* Align with the parent div */ 119 + top: 100%; 120 + right: 0; 121 + margin: 0; 122 + 123 + list-style: none; 124 + 125 + background: #fafafa; 126 + border: 1px solid #cccccc; 127 + 128 + /* Never break menu item lines */ 129 + white-space: nowrap; 130 + } 131 + 132 + div.language-selection:hover ul { 133 + display: block; 134 + } 135 + 136 + div.language-selection ul li:hover { 137 + background: #dddddd; 138 + }
+15
Documentation/sphinx/templates/translations.html
··· 1 + <!-- SPDX-License-Identifier: GPL-2.0 --> 2 + <!-- Copyright © 2023, Oracle and/or its affiliates. --> 3 + 4 + {# Create a language menu for translations #} 5 + {% if languages|length > 0: %} 6 + <div class="language-selection"> 7 + {{ current_language }} 8 + 9 + <ul> 10 + {% for ref in languages: %} 11 + <li><a href="{{ ref.refuri }}">{{ ref.astext() }}</a></li> 12 + {% endfor %} 13 + </ul> 14 + </div> 15 + {% endif %}
+101
Documentation/sphinx/translations.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Copyright © 2023, Oracle and/or its affiliates. 4 + # Author: Vegard Nossum <vegard.nossum@oracle.com> 5 + # 6 + # Add translation links to the top of the document. 7 + # 8 + 9 + import os 10 + 11 + from docutils import nodes 12 + from docutils.transforms import Transform 13 + 14 + import sphinx 15 + from sphinx import addnodes 16 + from sphinx.errors import NoUri 17 + 18 + all_languages = { 19 + # English is always first 20 + None: 'English', 21 + 22 + # Keep the rest sorted alphabetically 23 + 'zh_CN': 'Chinese (Simplified)', 24 + 'zh_TW': 'Chinese (Traditional)', 25 + 'it_IT': 'Italian', 26 + 'ja_JP': 'Japanese', 27 + 'ko_KR': 'Korean', 28 + 'sp_SP': 'Spanish', 29 + } 30 + 31 + class LanguagesNode(nodes.Element): 32 + def __init__(self, current_language, *args, **kwargs): 33 + super().__init__(*args, **kwargs) 34 + 35 + self.current_language = current_language 36 + 37 + class TranslationsTransform(Transform): 38 + default_priority = 900 39 + 40 + def apply(self): 41 + app = self.document.settings.env.app 42 + docname = self.document.settings.env.docname 43 + 44 + this_lang_code = None 45 + components = docname.split(os.sep) 46 + if components[0] == 'translations' and len(components) > 2: 47 + this_lang_code = components[1] 48 + 49 + # normalize docname to be the untranslated one 50 + docname = os.path.join(*components[2:]) 51 + 52 + new_nodes = LanguagesNode(all_languages[this_lang_code]) 53 + 54 + for lang_code, lang_name in all_languages.items(): 55 + if lang_code == this_lang_code: 56 + continue 57 + 58 + if lang_code is None: 59 + target_name = docname 60 + else: 61 + target_name = os.path.join('translations', lang_code, docname) 62 + 63 + pxref = addnodes.pending_xref('', refdomain='std', 64 + reftype='doc', reftarget='/' + target_name, modname=None, 65 + classname=None, refexplicit=True) 66 + pxref += nodes.Text(lang_name) 67 + new_nodes += pxref 68 + 69 + self.document.insert(0, new_nodes) 70 + 71 + def process_languages(app, doctree, docname): 72 + for node in doctree.traverse(LanguagesNode): 73 + if app.builder.format not in ['html']: 74 + node.parent.remove(node) 75 + continue 76 + 77 + languages = [] 78 + 79 + # Iterate over the child nodes; any resolved links will have 80 + # the type 'nodes.reference', while unresolved links will be 81 + # type 'nodes.Text'. 82 + languages = list(filter(lambda xref: 83 + isinstance(xref, nodes.reference), node.children)) 84 + 85 + html_content = app.builder.templates.render('translations.html', 86 + context={ 87 + 'current_language': node.current_language, 88 + 'languages': languages, 89 + }) 90 + 91 + node.replace_self(nodes.raw('', html_content, format='html')) 92 + 93 + def setup(app): 94 + app.add_node(LanguagesNode) 95 + app.add_transform(TranslationsTransform) 96 + app.connect('doctree-resolved', process_languages) 97 + 98 + return { 99 + 'parallel_read_safe': True, 100 + 'parallel_write_safe': True, 101 + }