translations.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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. import os
  9. from docutils import nodes
  10. from docutils.transforms import Transform
  11. import sphinx
  12. from sphinx import addnodes
  13. from sphinx.errors import NoUri
  14. all_languages = {
  15. # English is always first
  16. None: 'English',
  17. # Keep the rest sorted alphabetically
  18. 'zh_CN': 'Chinese (Simplified)',
  19. 'zh_TW': 'Chinese (Traditional)',
  20. 'it_IT': 'Italian',
  21. 'ja_JP': 'Japanese',
  22. 'ko_KR': 'Korean',
  23. 'sp_SP': 'Spanish',
  24. }
  25. class LanguagesNode(nodes.Element):
  26. pass
  27. class TranslationsTransform(Transform):
  28. default_priority = 900
  29. def apply(self):
  30. app = self.document.settings.env.app
  31. docname = self.document.settings.env.docname
  32. this_lang_code = None
  33. components = docname.split(os.sep)
  34. if components[0] == 'translations' and len(components) > 2:
  35. this_lang_code = components[1]
  36. # normalize docname to be the untranslated one
  37. docname = os.path.join(*components[2:])
  38. new_nodes = LanguagesNode()
  39. new_nodes['current_language'] = all_languages[this_lang_code]
  40. for lang_code, lang_name in all_languages.items():
  41. if lang_code == this_lang_code:
  42. continue
  43. if lang_code is None:
  44. target_name = docname
  45. else:
  46. target_name = os.path.join('translations', lang_code, docname)
  47. pxref = addnodes.pending_xref('', refdomain='std',
  48. reftype='doc', reftarget='/' + target_name, modname=None,
  49. classname=None, refexplicit=True)
  50. pxref += nodes.Text(lang_name)
  51. new_nodes += pxref
  52. self.document.insert(0, new_nodes)
  53. def process_languages(app, doctree, docname):
  54. for node in doctree.traverse(LanguagesNode):
  55. if app.builder.format not in ['html']:
  56. node.parent.remove(node)
  57. continue
  58. languages = []
  59. # Iterate over the child nodes; any resolved links will have
  60. # the type 'nodes.reference', while unresolved links will be
  61. # type 'nodes.Text'.
  62. languages = list(filter(lambda xref:
  63. isinstance(xref, nodes.reference), node.children))
  64. html_content = app.builder.templates.render('translations.html',
  65. context={
  66. 'current_language': node['current_language'],
  67. 'languages': languages,
  68. })
  69. node.replace_self(nodes.raw('', html_content, format='html'))
  70. def setup(app):
  71. app.add_node(LanguagesNode)
  72. app.add_transform(TranslationsTransform)
  73. app.connect('doctree-resolved', process_languages)
  74. return {
  75. 'parallel_read_safe': True,
  76. 'parallel_write_safe': True,
  77. }