From 45bcdf802738d3baa8286baddf5b1d7a384dda5e Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 24 Jul 2023 16:46:04 +0200 Subject: [PATCH 1/2] Documentation about `translated=True` attribute on nodes Minimal explanation with a full extension example about how the `translated=True` attribute injected by `sphinx.transforms.i18n.Locale` can be used to extend Sphinx's functionality. Related #1246 --- doc/usage/advanced/intl.rst | 114 ++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/doc/usage/advanced/intl.rst b/doc/usage/advanced/intl.rst index 1a98ebb1f31..c8522eea76b 100644 --- a/doc/usage/advanced/intl.rst +++ b/doc/usage/advanced/intl.rst @@ -340,6 +340,120 @@ There is a `sphinx translation page`_ for Sphinx (master) documentation. Detail is here: https://docs.transifex.com/getting-started-1/translators + +Using Sphinx's internals to extend translations functionality +------------------------------------------------------------- + +.. versionadded:: 7.1.0 + +During the build process, Sphinx marks each translated node that with a ``translated=True`` attribute, +meaning it was able to find the translated version of the paragraph to the target language. +Developers and users with coding knowledge, can be benefit from this attribute to build extensions around translations. + +The following example shows a minimal Sphinx extension that covers 3 different usage for this attribute: + +* Mark untranslated paragraphs with a different background color using +* Calculate translated percentage per page and total +* Use a custom substitution to show the translated percentage of the page + + +.. code:: python + :caption: translated.py + + import docutils + from sphinx.transforms import SphinxTransform + + + class TranslationsManipulation(SphinxTransform): + default_priority = 50 + + def apply(self, **kwargs): + filename = self.document.get('source') # absolute source filename + + # Default values for current source filename + self.app._translations[filename] = { + 'total': 0, + 'translated': 0, + } + + # Traverse all the nodes of the document + for node in self.document.traverse(): + if not hasattr(node, 'get'): + # Discard nodes we cannot access to its attributes + continue + + if any([isinstance(child, docutils.nodes.Text) for child in node.children]): + # Only work over nodes with a text child + if node.get('translated', False): + # Increase the translated nodes + self.app._translations[filename]['translated'] += 1 + css_class = self.app.env.config.translated_class + else: + css_class = self.app.env.config.untranslated_class + + # Append our custom untranslated CSS class to the node + classes = node.get('classes', []) + classes.append(css_class) + node.replace_attr('classes', classes) + + # Increase the total of nodes + self.app._translations[filename]['total'] += 1 + + + # Calculate total percentage of the page translated + self.app._translations[filename]['percentage'] = ( + self.app._translations[filename]['translated'] / + self.app._translations[filename]['total'] + ) * 100 + + # Handle substitutions (used as ``|translated-page-percentage|`` in .rst source files) + substitution = 'translated-page-percentage' + for ref in self.document.findall(docutils.nodes.substitution_reference): + refname = ref['refname'] + if refname == substitution: + text = self.app._translations[filename]['percentage'] + newnode = docutils.nodes.Text(text) + if 'classes' in ref: + ref.replace_attr('classes', []) + ref.replace_self(newnode) + + + def setup(app): + """ + Setup ``translated`` Sphinx extension. + """ + # CSS class to add to translated nodes + app.add_config_value('translated_class', 'translated', 'env') + app.add_config_value('untranslated_class', 'untranslated', 'env') + + # Add the CSS file with our custom styles + app.add_css_file('translated.css') + + app.add_transform(TranslationsManipulation) + + # Define an internal variable to store translated percentages + app._translations = {} + + return { + 'version': '0.1', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } + +The ``.css`` added looks like the following: + +.. code:: css + :caption: _static/translated.css + + .translated { + background-color: rgba(0, 255, 0, .20) + } + + .untranslated { + background-color: rgba(255, 0, 0, .20) + } + + .. rubric:: Footnotes .. [1] See the `GNU gettext utilities From 734f5880ba338457214efc041f1760357081e806 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:16:07 +0100 Subject: [PATCH 2/2] :caption: doesn't work on ``.. code::`` --- doc/usage/advanced/intl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/usage/advanced/intl.rst b/doc/usage/advanced/intl.rst index c8522eea76b..ee5dcc2866c 100644 --- a/doc/usage/advanced/intl.rst +++ b/doc/usage/advanced/intl.rst @@ -357,7 +357,7 @@ The following example shows a minimal Sphinx extension that covers 3 different u * Use a custom substitution to show the translated percentage of the page -.. code:: python +.. code-block:: python :caption: translated.py import docutils @@ -442,7 +442,7 @@ The following example shows a minimal Sphinx extension that covers 3 different u The ``.css`` added looks like the following: -.. code:: css +.. code-block:: css :caption: _static/translated.css .translated {