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 9import os 10 11from docutils import nodes 12from docutils.transforms import Transform 13 14import sphinx 15from sphinx import addnodes 16from sphinx.errors import NoUri 17 18all_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 31class LanguagesNode(nodes.Element): 32 def __init__(self, current_language, *args, **kwargs): 33 super().__init__(*args, **kwargs) 34 35 self.current_language = current_language 36 37class 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 71def 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 93def 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 } 102