diff --git a/.gitignore b/.gitignore index 28b7d6492..62bcb3e7f 100644 --- a/.gitignore +++ b/.gitignore @@ -46,10 +46,6 @@ coverage.xml *.cover .hypothesis/ -# Translations -*.mo -*.pot - # Django stuff: *.log local_settings.py diff --git a/MANIFEST.in b/MANIFEST.in index 5fc45e8d0..7c869bb77 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ +include babel.cfg include MANIFEST.in include LICENSE include README.md diff --git a/babel.cfg b/babel.cfg new file mode 100644 index 000000000..fb61a5494 --- /dev/null +++ b/babel.cfg @@ -0,0 +1,5 @@ +# See https://github.com/sphinx-doc/sphinx/blob/4.x/babel.cfg +[jinja2: **.html] +encoding = utf-8 +ignore_tags = script,style +include_attrs = alt title summary placeholder diff --git a/docs/contributing.rst b/docs/contributing.rst index 542ea2489..079e85ab6 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -284,6 +284,75 @@ is required. The steps are roughly: - potentially remove the font being replaced from ``package.json`` and re-run ``yarn`` - commit all of the changed files +Internationalization +==================== + +Internationalization (I18N) and localization (L10N) is performed using `Gettext `__. Gettext reads a program's source and extracts text that has been marked as translatable, known as "source strings." Gettext uses three types of files: + +PO file (``.po``) + A `Portable Object (PO) file `__ is made up of many entries, each entry holding the relation between a source string and its translation. The source string is introduced by the keyword ``msgid``, and the translation, by ``msgstr``. In a given PO file, all translations are expressed in a single target language. PO files are also known as message catalogs. + + Entries begin with comments, on lines all starting with the character ``#``. Comments are created and maintained by Gettext. Comment lines starting with ``#:`` contain references to the program's source. These references allow a human translator to find the source strings in their original context. Comment lines starting with ``#,`` contain flags like ``python-format``, which indicates that the source string contains placeholders like ``%(copyright)s``. +POT file (``.pot``) + A Portable Object Template (POT) file is the same as a PO file, except the translations are empty, so that it can be used as a template for new languages. +MO file (``.mo``) + A Machine Object (MO) file is a binary version of a PO file. PO files are compiled to MO files, which are required by Gettext. + +I18N and L10N are deep topics. Here, we only cover the bare minimum needed to fulfill basics technical tasks. You might like: + +- `Internationalis(z)ing Code `__ by Computerphile on YouTube +- `Falsehoods Programmers Believe About Language `__ by Ben Hamill + +.. _adding-natural-language-text: + +Adding natural language text +---------------------------- + +All natural language text must be marked as translatable, so that it can be extracted by Gettext and translated by humans. + +Jinja2 provides a ``trans`` block and a ``_()`` function to mark text as translatable. `Please refer to the Jinja2 documentation `__. Remember to `manually escape `__ variables if needed. + +Then, complete the steps for :ref:`changing-natural-language-text`. + +.. _changing-natural-language-text: + +Changing natural language text +------------------------------ + +#. Edit the natural language text as desired. + +#. Update the message catalog template (POT file): + + .. code-block:: bash + + python setup.py extract_messages + +#. Update the message catalogs (PO files): + + .. code-block:: bash + + python setup.py update_catalog + +.. _translating-the-theme: + +Translating the theme +--------------------- + +These steps use the Spanish language as an example. To translate the theme to another language, replace ``es`` with the language's two-letter lowercase `ISO 639-1 code `__. + +#. If the language's code matches no sub-directory of the `pydata_sphinx_theme/locale `__ directory, initialize the language's message catalog (PO file): + + .. code-block:: bash + + python setup.py init_catalog -l es + +#. Edit the language's message catalog at ``pydata_sphinx_theme/locale/es/LC_MESSAGES/sphinx.po``. For each source string introduced by the ``msgid`` keyword, add its translation after the ``msgstr`` keyword. + +#. Compile the message catalogs of every language. This creates or updates the MO files: + +.. code-block:: bash + + python setup.py compile_catalog Contributing changes ==================== diff --git a/docs/user_guide/i18n.rst b/docs/user_guide/i18n.rst new file mode 100644 index 000000000..e88fb9976 --- /dev/null +++ b/docs/user_guide/i18n.rst @@ -0,0 +1,69 @@ +Internationalization +==================== + +This theme contains translatable strings. There are two kinds of strings contained in this theme, with slightly different steps to translate each. + +**Built-in strings** are hard-coded in the theme's templates, and will automatically be translated if the language is `supported `__. To add another language, see :ref:`translating-the-theme`. + +**Configurable strings** are user-defined in ``html_theme_options`` (see :doc:`options` for examples). To translate these strings, see the section below. + +Translating configurable strings +-------------------------------- + +These are instructions for translating configurable strings (those that are customizable in ``html_theme_options``). +The instructions assume that you store your translations in a ``locale`` directory under your documentation directory, and that you want to use ``theme`` as the name of the message catalog for these strings. + +#. In your ``conf.py`` file: + + .. code-block:: python + + import os.path + from sphinx.locale import get_translation + + catalog = "theme" + _ = get_translation(catalog) + + html_theme_options = { + "search_bar_text": _("Search the docs..."), + + # You only need to translate the following if you use these features. + "icon_links_label": _("Quick Links"), + "icon_links": [ + { + "name": _("GitHub"), + "url": "https://github.com//", + "icon": "fab fa-github-square", + }, + ], + "external_links": [ + { + "name": _("link-one-name"), + "url": "https://", + }, + ], + } + + def setup(app): + locale_dir = os.path.join(os.path.abspath(os.path.dirname(__file__), "locale") + + app.add_message_catalog(catalog, locale_dir) + +#. Extract the strings to translate: + + .. code-block:: bash + + pybabel extract . -o locale/theme.pot + +#. Create a message catalog (changing the ``--locale`` option as desired): + + .. code-block:: bash + + pybabel init --input-file=locale/theme.pot --domain=theme --output-dir=locale --locale=fr + +#. Translate the message catalog by editing the file. + +#. Compile the message catalog: + + .. code-block:: bash + + pybabel compile --directory=locale --domain=theme diff --git a/docs/user_guide/index.rst b/docs/user_guide/index.rst index eeb675ce9..d6978a21c 100644 --- a/docs/user_guide/index.rst +++ b/docs/user_guide/index.rst @@ -10,3 +10,4 @@ User Guide configuring sections customizing + i18n diff --git a/pydata_sphinx_theme/__init__.py b/pydata_sphinx_theme/__init__.py index d9e7e9ec6..1511af041 100644 --- a/pydata_sphinx_theme/__init__.py +++ b/pydata_sphinx_theme/__init__.py @@ -517,6 +517,9 @@ def setup(app): app.add_html_theme("pydata_sphinx_theme", theme_path) app.set_translator("html", BootstrapHTML5Translator) + # https://www.sphinx-doc.org/en/master/extdev/i18n.html#extension-internationalization-i18n-and-localization-l10n-using-i18n-api + app.add_message_catalog("sphinx", os.path.join(theme_path, "locale")) + # Read the Docs uses ``readthedocs`` as the name of the build, and also # uses a special "dirhtml" builder so we need to replace these both with # our custom HTML builder @@ -529,7 +532,7 @@ def setup(app): # Update templates for sidebar pkgdir = os.path.abspath(os.path.dirname(__file__)) - path_templates = os.path.join(pkgdir, "_templates") + path_templates = os.path.join(pkgdir, "templates") app.config.templates_path.append(path_templates) return {"parallel_read_safe": True, "parallel_write_safe": True} diff --git a/pydata_sphinx_theme/icon-links.html b/pydata_sphinx_theme/icon-links.html index 4dd3aa921..2f8ff425a 100644 --- a/pydata_sphinx_theme/icon-links.html +++ b/pydata_sphinx_theme/icon-links.html @@ -1,20 +1,20 @@ {%- macro icon_link_nav_item(url, icon, name) -%} {%- if url | length > 2 %} {%- endif -%} {%- endmacro -%} -