|  | # SPDX-License-Identifier: GPL-2.0 | 
|  | # | 
|  | # Copyright © 2023, Oracle and/or its affiliates. | 
|  | # Author: Vegard Nossum <vegard.nossum@oracle.com> | 
|  | # | 
|  | # Add translation links to the top of the document. | 
|  | # | 
|  |  | 
|  | import os | 
|  |  | 
|  | from docutils import nodes | 
|  | from docutils.transforms import Transform | 
|  |  | 
|  | import sphinx | 
|  | from sphinx import addnodes | 
|  | from sphinx.errors import NoUri | 
|  |  | 
|  | all_languages = { | 
|  | # English is always first | 
|  | None: 'English', | 
|  |  | 
|  | # Keep the rest sorted alphabetically | 
|  | 'zh_CN': 'Chinese (Simplified)', | 
|  | 'zh_TW': 'Chinese (Traditional)', | 
|  | 'it_IT': 'Italian', | 
|  | 'ja_JP': 'Japanese', | 
|  | 'ko_KR': 'Korean', | 
|  | 'sp_SP': 'Spanish', | 
|  | } | 
|  |  | 
|  | class LanguagesNode(nodes.Element): | 
|  | pass | 
|  |  | 
|  | class TranslationsTransform(Transform): | 
|  | default_priority = 900 | 
|  |  | 
|  | def apply(self): | 
|  | app = self.document.settings.env.app | 
|  | docname = self.document.settings.env.docname | 
|  |  | 
|  | this_lang_code = None | 
|  | components = docname.split(os.sep) | 
|  | if components[0] == 'translations' and len(components) > 2: | 
|  | this_lang_code = components[1] | 
|  |  | 
|  | # normalize docname to be the untranslated one | 
|  | docname = os.path.join(*components[2:]) | 
|  |  | 
|  | new_nodes = LanguagesNode() | 
|  | new_nodes['current_language'] = all_languages[this_lang_code] | 
|  |  | 
|  | for lang_code, lang_name in all_languages.items(): | 
|  | if lang_code == this_lang_code: | 
|  | continue | 
|  |  | 
|  | if lang_code is None: | 
|  | target_name = docname | 
|  | else: | 
|  | target_name = os.path.join('translations', lang_code, docname) | 
|  |  | 
|  | pxref = addnodes.pending_xref('', refdomain='std', | 
|  | reftype='doc', reftarget='/' + target_name, modname=None, | 
|  | classname=None, refexplicit=True) | 
|  | pxref += nodes.Text(lang_name) | 
|  | new_nodes += pxref | 
|  |  | 
|  | self.document.insert(0, new_nodes) | 
|  |  | 
|  | def process_languages(app, doctree, docname): | 
|  | for node in doctree.traverse(LanguagesNode): | 
|  | if app.builder.format not in ['html']: | 
|  | node.parent.remove(node) | 
|  | continue | 
|  |  | 
|  | languages = [] | 
|  |  | 
|  | # Iterate over the child nodes; any resolved links will have | 
|  | # the type 'nodes.reference', while unresolved links will be | 
|  | # type 'nodes.Text'. | 
|  | languages = list(filter(lambda xref: | 
|  | isinstance(xref, nodes.reference), node.children)) | 
|  |  | 
|  | html_content = app.builder.templates.render('translations.html', | 
|  | context={ | 
|  | 'current_language': node['current_language'], | 
|  | 'languages': languages, | 
|  | }) | 
|  |  | 
|  | node.replace_self(nodes.raw('', html_content, format='html')) | 
|  |  | 
|  | def setup(app): | 
|  | app.add_node(LanguagesNode) | 
|  | app.add_transform(TranslationsTransform) | 
|  | app.connect('doctree-resolved', process_languages) | 
|  |  | 
|  | return { | 
|  | 'parallel_read_safe': True, | 
|  | 'parallel_write_safe': True, | 
|  | } |