Skip to main content
`Ctrl`+`K`

# Source code for pydata_sphinx_theme.translator

    """A custom Sphinx HTML Translator for Bootstrap layout."""

    import types

    from sphinx.application import Sphinx
    from sphinx.ext.autosummary import autosummary_table
    from sphinx.util import logging

    logger = logging.getLogger(__name__)

    class BootstrapHTML5TranslatorMixin:
        """Mixin HTML Translator for a Bootstrap-ified Sphinx layout.

        Only a couple of functions have been overridden to produce valid HTML to be
        directly styled with Bootstrap, and fulfill acessibility best practices.
        """

        def __init__(self, *args, **kwds):
            super().__init__(*args, **kwds)
            self.settings.table_style = "table"

        def starttag(self, *args, **kwargs):
            """Perform small modifications to tags.

            - ensure aria-level is set for any tag with heading role
            """
            if kwargs.get("ROLE") == "heading" and "ARIA-LEVEL" not in kwargs:
                kwargs["ARIA-LEVEL"] = "2"

            return super().starttag(*args, **kwargs)

        def visit_table(self, node):
            """
            Custom visit table method.

            Copy of sphinx source to *not* add 'docutils' and 'align-default' classes but
            add 'table' class.
            """
            # init the attributes
            atts = {}

            self._table_row_indices.append(0)

            # get the classes
            classes = [cls.strip(" \t\n") for cls in self.settings.table_style.split(",")]

            # we're looking at the 'real_table', which is wrapped by an autosummary
            if isinstance(node.parent, autosummary_table):
                classes += ["autosummary"]

            # add the width if set in a style attribute
            if "width" in node:
                atts["style"] = f"width: {node['width']}"

            # add specific class if align is set
            if "align" in node:
                classes.append(f"table-{node['align']}")

            # put table within a scrollable container (for tables that are too wide)
            self.body.append('<div class="pst-scrollable-table-container">')

            tag = self.starttag(node, "table", CLASS=" ".join(classes), **atts)
            self.body.append(tag)

        def depart_table(self, node):
            """
            Custom depart_table method to close the scrollable div we add in
            visit_table.
            """
            super().depart_table(node)
            self.body.append("</div>\n")

    def setup_translators(app: Sphinx):
        """
        Add bootstrap HTML functionality if we are using an HTML translator.

        This re-uses the pre-existing Sphinx translator and adds extra functionality
        defined in ``BootstrapHTML5TranslatorMixin``.
        This way we can retain the original translator's
        behavior and configuration, and _only_ add the extra bootstrap rules.
        If we don't detect an HTML-based translator, then we do nothing.
        """
        # Do not add the mixin if the builder format is not HTML:
        if app.builder.format != "html":
            return

        if not app.registry.translators.items():
            try:
                default_translator_class = app.builder.default_translator_class
            except AttributeError:
                # some builders, e.g. linkcheck, do not define 'default_translator_class'
                return

            translator = types.new_class(
                "BootstrapHTML5Translator",
                (
                    BootstrapHTML5TranslatorMixin,
                    default_translator_class,
                ),
                {},
            )
            app.set_translator(app.builder.name, translator, override=True)
        else:
            for name, klass in app.registry.translators.items():
                translator = types.new_class(
                    "BootstrapHTML5Translator",
                    (
                        BootstrapHTML5TranslatorMixin,
                        klass,
                    ),
                    {},
                )
                app.set_translator(name, translator, override=True)