Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate theme #21

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install dev requirements
run: pip install -r requirements_dev.txt
- name: Check black
run: black --check iati_sphinx_theme
- name: Check isort
run: isort --check-only iati_sphinx_theme
- name: Check flake8
run: flake8 iati_sphinx_theme
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dev requirements
run: pip install -r requirements_dev.txt
- name: Check black
run: black --check iati_sphinx_theme docs
- name: Check isort
run: isort --check-only iati_sphinx_theme docs
- name: Check flake8
run: flake8 iati_sphinx_theme docs
- name: Check mypy
run: mypy iati_sphinx_theme docs
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ dist

# Node
node_modules

# Translations
.doctrees
*.mo
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
MESSAGE_CATALOG_NAME = sphinx

.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " extract to extract translatable strings into POT files"
@echo " init to initialise a PO file for a new language"
@echo " update to update existing PO files"
@echo " compile to compile updated PO files"

.PHONY: extract
extract:
pybabel extract -o iati_sphinx_theme/locale/$(MESSAGE_CATALOG_NAME).pot -F babel.cfg iati_sphinx_theme

.PHONY: init
init:
pybabel init -i iati_sphinx_theme/locale/$(MESSAGE_CATALOG_NAME).pot -d iati_sphinx_theme/locale --domain=$(MESSAGE_CATALOG_NAME) -l ${lang}

.PHONY: update
update:
pybabel update -i iati_sphinx_theme/locale/$(MESSAGE_CATALOG_NAME).pot -d iati_sphinx_theme/locale --domain=${MESSAGE_CATALOG_NAME}

.PHONE: compile
compile:
pybabel compile --directory=iati_sphinx_theme/locale --domain=${MESSAGE_CATALOG_NAME}
42 changes: 38 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ pip install -r requirements_dev.txt
### Run linting

```
black iati_sphinx_theme/
isort iati_sphinx_theme/
flake8 iati_sphinx_theme/
mypy iati_sphinx_theme/
black iati_sphinx_theme/ docs/
isort iati_sphinx_theme/ docs/
flake8 iati_sphinx_theme/ docs/
mypy iati_sphinx_theme/ docs/
```

### Documentation with live preview
Expand Down Expand Up @@ -73,3 +73,37 @@ To run a local version of the theme with another project, e.g. `my-docs`, take t
pip install sphinx-autobuild
sphinx-autobuild docs docs/_build/html
```

### Translation

Follow the steps below to translate the theme's built-in strings from the HTML templates in the `iati_sphinx_theme` directory.
The message catalog name is `sphinx.[pot|po|mo]` and is found in the `iati_sphinx_theme/locale` directory.
These are bundled with the published theme in order for consumers to have access to the translations.

A `Makefile` exists to make running the commands easier:

1. Extract text into `.pot` files

```
make extract
```

2. Update existing `.po` files based on `.pot` files

```
make update
```

3. Optionally, initialise a `.po` file for a new language

```
make init lang=es
```

4. Add translations to the `.po` files

5. Compile to `.mo` files (only applies to the theme's built-in strings, so that they can be bundled with the theme)

```
make compile
```
6 changes: 6 additions & 0 deletions babel.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# See https://github.com/python-babel/babel/blob/2a1709a7768f6f07c3d2dbfdb03d3c8a6bd80aef/docs/messages.rst#extraction-method-mapping-and-configuration
[python: **.py]
[jinja2: **.html]
encoding = utf-8
ignore_tags = script,style
include_attrs = alt title summary placeholder
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need these lines for Jinja2, or are they just applicable to Genshi?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they are unneeded, have removed

3 changes: 1 addition & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = "IATI Sphinx Theme"
copyright = "2024 IATI Secretariat"
author = "IATI Secretariat"
language = "en"

Expand All @@ -22,13 +21,13 @@
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]


# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = "iati_sphinx_theme"
html_theme_options = {
"github_repository": "https://github.com/IATI/sphinx-theme",
"header_title_text": "IATI Sphinx Theme",
"languages": {
"en": "English",
},
Expand Down
70 changes: 69 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,32 @@ This theme has multiple options, which can be configured using the :code:`html_t

html_theme_options = {
"github_repository": "https://github.com/organisation/repository",
"header_title_text": "Title",
"languages": {
"en": "English",
},
"plausible_domain": "example.com"
}

There is more information on each option below.

:code:`github_repository`
-------------------
-------------------------

This should be a link to the Github repository for the documentation site, and is used to link to the source code in the footer of the site.

:code:`header_title_text`
-------------------------

The site's title to display in the header and navigation.

:code:`languages`
-----------------

A dictionary of languages which the documentation is available in, used to populate the language switcher component.

For each entry, the keys (:code:`en`) is used to send the user to the correct site, and the value (:code:`English`) is displayed in the language switcher.

:code:`plausible_domain`
------------------------

Expand All @@ -59,3 +75,55 @@ For example, for the Sphinx site :code:`docs.example.com`, use :code:`example.co
html_theme_options = {
"plausible_domain": "example.com"
}

Translation
===========

The IATI Sphinx Theme is translatable.

Strings built into the theme will be translated automatically into supported languages.
The following languages are currently supported:

- English (:code:`en`)
- French (:code:`fr`)
- Spanish (:code:`es`)

User-defined strings must be translated by the user of the theme.
These are configured in your :code:`conf.py` file under :code:`html_theme_options`.
In order to translate these, complete the following steps in the same location as the `conf.py` file:

1. Mark strings as translatable using :code:`sphinx.locale.get_translation`, usually renamed to :code:`_()`.

.. code-block:: python

import os
from sphinx.locale import get_translation

MESSAGE_CATALOG_NAME = "iati-sphinx-theme"
_ = get_translation(MESSAGE_CATALOG_NAME)

html_theme_options = {
"header_title_text": _("Title"),
}

def setup(app):
locale_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "locale")
app.add_message_catalog(MESSAGE_CATALOG_NAME, locale_path)

2. Extract translatable strings to :code:`locale/iati-sphinx-theme.pot`.

.. code-block::

pybabel extract conf.py -o locale/iati-sphinx-theme.pot

3. Create or update :code:`.po` files for desired languages.

.. code-block::

# To add a new language
pybabel init -i locale/iati-sphinx-theme.pot -d locale --domain=iati-sphinx-theme -l es

# To update an existing language
pybabel update -i locale/iati-sphinx-theme.pot -d locale --domain=iati-sphinx-theme -l es

4. Continue with your project's usual translation workflow.
4 changes: 4 additions & 0 deletions iati_sphinx_theme/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""A sphinx theme for IATI documentation sites."""

from datetime import datetime
from os import path

import sphinx.application
Expand All @@ -10,4 +11,7 @@ def setup(app: sphinx.application.Sphinx) -> None:
app.config["html_permalinks_icon"] = "#"
app.config["html_favicon"] = "static/favicon-16x16.png"
app.config["html_context"]["language"] = app.config["language"]
app.config["html_context"]["current_year"] = datetime.now().year
app.add_js_file("language-switcher.js")
locale_path = path.join(path.abspath(path.dirname(__file__)), "locale")
app.add_message_catalog("sphinx", locale_path)
12 changes: 6 additions & 6 deletions iati_sphinx_theme/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
<div class="iati-footer__section iati-footer__section--first">
<div class="iati-footer__container">
<div class="iati-footer-block">
<h2 class="iati-footer-block__title">Additional information</h2>
<h2 class="iati-footer-block__title">{{ _("Additional Information") }}</h2>
<div class="iati-footer-block__content">
<p>Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.</p>
<p>{% trans url="https://www.sphinx-doc.org/" %}Created using <a href="{{ url }}">Sphinx</a> {{ sphinx_version }}.{% endtrans %}</p>
{% if theme_github_repository %}
<p>Source code on <a href="{{ theme_github_repository }}">GitHub</a>.</p>
<p>{% trans url=theme_github_repository %}Source code at <a href="{{ url }}">GitHub</a>.{% endtrans %}</p>
{% endif %}
<p>Documentation licensed under <a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.</p>
<p>{% trans url="https://creativecommons.org/licenses/by/4.0/" %}Documentation licensed under <a href="{{ url }}">CC BY 4.0</a>.{% endtrans %}</p>
</div>
</div>
</div>
Expand All @@ -20,10 +20,10 @@ <h2 class="iati-footer-block__title">Additional information</h2>
<div class="iati-footer__container">
<nav>
<ul class="iati-piped-list iati-footer__legal-nav">
<li><a href="https://iatistandard.org/en/privacy-policy/">Privacy Policy</a></li>
<li><a href="https://iatistandard.org/en/privacy-policy/">{{ _("Privacy Policy") }}</a></li>
<li>
<span>
{{ copyright_block() }}
&copy; {% trans %}Copyright {{ current_year }} United Nations Development Programme, on behalf of the IATI Secretariat{% endtrans %}
</span>
</li>
</ul>
Expand Down
24 changes: 12 additions & 12 deletions iati_sphinx_theme/header.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
{% set general_nav_items = [
{"text": "About IATI", "link": "https://iatistandard.org/en/about/"},
{"text": "Use Data", "link": "https://iatistandard.org/en/using-data/"},
{"text": "Publish Data", "link": "https://iatistandard.org/en/guidance/publishing-data/"},
{"text": "Contact", "link": "https://iatistandard.org/guidance/get-support/"},
{"text": _("About IATI"), "link": "https://iatistandard.org/en/about/"},
{"text": _("Use Data"), "link": "https://iatistandard.org/en/using-data/"},
{"text": _("Publish Data"), "link": "https://iatistandard.org/en/guidance/publishing-data/"},
{"text": _("Contact"), "link": "https://iatistandard.org/guidance/get-support/"},
] %}

<div class="iati-mobile-nav js-iati-mobile-nav">
<div class="iati-mobile-nav__overlay js-iati-mobile-overlay"></div>
<nav class="iati-mobile-nav__menu">
<div class="iati-mobile-nav__header">
<h2 class="iati-mobile-nav__label">Menu</h2>
<h2 class="iati-mobile-nav__label">{{ _("Menu") }}</h2>
<button class="iati-menu-toggle iati-menu-toggle--close js-iati-menu-toggle-close">
<span>Close</span>
<span>{{ _("Close") }}</span>
</button>
</div>
<ul>
<li class="iati-mobile-nav__item">
<a href="{{ pathto('', 1) }}" class="iati-mobile-nav__link">{{ _(project) }}</a>
<a href="{{ pathto('', 1) }}" class="iati-mobile-nav__link">{{ _(theme_header_title_text) }}</a>
</li>
</ul>
<ul>
Expand Down Expand Up @@ -56,25 +56,25 @@ <h2 class="iati-mobile-nav__label">Menu</h2>
{%- include "language-switcher.html" %}

<a href="{{ pathto('search') }}" class="iati-button iati-button--light">
<span>Search</span>
<span>{{ _("Search") }}</span>
<img class="iati-button__icon" alt="" src="{{ pathto('_static/icon-search.svg', 1) }}">
</a>

<button class="iati-menu-toggle iati-menu-toggle--open js-iati-menu-toggle-open">
<span class="iati-menu-toggle__label">Menu</span>
<span class="iati-menu-toggle__label">{{ _("Menu") }}</span>
</button>
</div>

<div class="iati-header-title">
<p class="iati-header-title__eyebrow">IATI Tools</p>
<p class="iati-header-title__heading">{{ _(project) }}</p>
<p class="iati-header-title__eyebrow">{{ _("IATI Tools") }}</p>
<p class="iati-header-title__heading">{{ _(theme_header_title_text) }}</p>
</div>

<div class="iati-header__nav">
<nav>
<ul class="iati-tool-nav">
<li>
<a href="{{ pathto('', 1) }}" class="iati-tool-nav-link">{{ _(project) }}</a>
<a href="{{ pathto('', 1) }}" class="iati-tool-nav-link">{{ _(theme_header_title_text) }}</a>
</li>
</ul>
</nav>
Expand Down
2 changes: 1 addition & 1 deletion iati_sphinx_theme/language-switcher.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="iati-country-switcher">
<label for="iati-country-switcher" class="iati-country-switcher__label">Choose your language</label>
<label for="iati-country-switcher" class="iati-country-switcher__label">{{ _("Choose your language") }}</label>
<select id="iati-country-switcher" class="iati-country-switcher__control">
{% for language_code in theme_languages %}
<option value="{{ language_code }}" {% if language_code == language %}selected{% endif %}>
Expand Down
Loading
Loading