Personal website with Sphinx

Sphinx primarily is a documentation generator for source code, for programs. Its main focus is not on automatic documentation like Doxygen or JavaDoc, but it can do this as well. The main mode of operation is to write reStructuredText documents and compile them into HTML (or LaTeX or ePub) documents.

The Python documentation is an example for the output of Sphinx. One can see that the output is tailored to a manual with sections that have some particular order.

My personal website does not have the structure of this manual, I rather think it has a tree like organization where every branch is more of less independent of everything else. Compiling this into a long document with sections would not make too much sense.

One can still use Sphinx for personal websites, with a few tweaks.

Theme

The first thing one might do is to create a personal theme. This theme then contains different navigation constructs to give the user access to the three structure directly.

Sphinx will parse the theme with Jinja2 and put your content into the block body. This means that you have to create a regular HTML document that serves as a layout template for the whole site. Then you insert

{% block body %} {% endblock %}

where you want to have the main text content that is generated by Sphinx. In order to get a tree like navigation, like I have here on this site, include this in the template:

{{ toctree(maxdepth=-1, titles_only=True, includehidden=True) }}

That generates the whole "table of contents tree" with infinite depth, showing only the page titles (as opposed to the headings in the pages as well).

The remainder are small things to round it off. I made a breadcrumb navigation like so:

{%- for parent in parents %}
→ <a href="{{ parent.link|e }}" {% if loop.last %} {{ accesskey("U") }} {% endif %}>
    {{ parent.title }}
</a>
{%- endfor %}
{% if title|striptags != "<no title>": %}
{{ title }}
{% endif %}

New gettext strings in template

Sphinx has some strings from the standard template translated into multiple languages. Those are stored in the compiled file /usr/share/locale/de/LC_MESSAGES/sphinx.mo, at least on my Ubuntu 14.10 machine. Strings from your template will not be translated directly. Sphinx has the feature to extract the paragraphs and string from your source and create translation files (.po) for them. None of this is done for your template, such that you have to do this manually.

The first thing is to extract the strings from the template:

xgettext --from-code utf-8 --language Python -o theme.pot _themes/mu/layout.html

Then I translate them and merge them with the other messages that came with Sphinx with this makefile target:

sphinx.mo: _locale/de/LC_MESSAGES/theme.po
        msgfmt -o $@ <(msgcat <(msgunfmt /usr/share/locale/de/LC_MESSAGES/sphinx.mo) $^)

Getting the language into the template

There are cases where the content should differ between the different languages. For the hyphenation, I need to put the language into the body tag. It seems to be quite hard to get the language in the template.

Although you can specify the language as a command line argument for sphinx-build, you do not see that in the conf.py, the variable language is just to the default there. This means that I had to create two configuration files that include the main one to set the language in the configuration directly. I then use this in my makefile to generate the German output:

$(sphinxbuild) -b html -d _build/doctrees/de -c _config/de . $(b)/de

My doctrees go into a different directory for each language such that they do not overwrite each other. Before I did that, each run would completely start from scratch.

In the file _config/de/conf.py I have this:

language = 'de'

filename = '../../conf.py'
exec(open(filename).read())

There is a similar config file for English. In the main conf.py, I removed the line which set the language to something. Instead, I have this construct:

l = 'en'

try:
    l = language
except NameError:
    pass

html_theme_options = {
    'lang': l,
}

Then, in the _themes/mu/theme.conf I have this, among other things:

[options]
lang = en

All this then allows me to use {{ lang }} inside the layout.html file.

I have filed a bug about this upstream.