Sep 19, 2014 Tag: Ablog
ABlog is Ahmet Bakan’s fantastic Sphinx extension for creating blogs. At the moment as of version 0.3 it lacks support for switching languages on a per post or per page basis. ABlog is OpenSource software and available from Github.This post offers a working solution.
Here we go:
Provide some settings in the Sphinx configuration data in conf.py:
# [1] http://ablog.readthedocs.org/manual/ablog-configuration-options/#confval-blog_default_language
blog_default_language = 'en'
# [2] http://sphinx-doc.org/config.html#confval-language
# ATTENTION:
# This option 'language' must be present. Otherwise Sphinx doesn't invoke translation services at all.
language = blog_default_language
# [3] http://ablog.readthedocs.org/manual/ablog-configuration-options/#confval-blog_languages
blog_languages = {
'en': (u'English', None),
'de': (u'Deutsch', None),
}
[1] blog_default_language, [2] language, [3] blog_languages
Some more preparations: At the end of the Blog constructor we create a
translator instance for each blog language. In ablog/blog.py
:
class Blog(object):
"""Handle blog operations."""
# ...
def _init(self, app):
"""Instantiate Blog."""
# ...
# add our Blog instance to the application so we can find it
# when coming from the application
self.app.ablog = self
# prepare a dictionary with translators for the blog languages
self.translators = {}
if self.app:
# construct locale_dirs in the same way Sphinx does
from sphinx import package_dir, locale
if self.app.config.language is not None:
locale_dirs = ([None, os.path.join(package_dir, 'locale')] +
[os.path.join(self.app.srcdir, x) for x in self.app.config.locale_dirs])
else:
locale_dirs = []
for language in self.app.config.blog_languages.keys():
translator, has_translation = locale.init(locale_dirs, language)
self.translators[language] = translator if has_translation else None
Specify the language of a post in the post directive:
.. post:: Sep 19, 2014
:language: de
For normal pages (non-posts) specify the language in the document’s metadata. Internally the builder can access this metadata.
.. coding: -*- utf-8 -*- ÄÖÜ
.. the following meta data must appear BEFORE anything else
and BEFORE the page title
:language: de
:orphan: yes
============
Page title
============
Tip: Add the :orphan:
field too to suppress Sphinx’s warning that a document isn’t
included in any toctree.
Each document is rendered in its individual context. We can hook into
the procedure of setting that up. In ablog/__init__.py
:
from .post import ( # ...PostDirective, PostListDirective, UpdateDirective,
html_page_context)
def setup(app):
"""Setup ABlog extension."""
# ...
app.connect('html-page-context', html_page_context)
Now let’s tweak the context of a document’s rendering process. We provide
htmllang
, a variable with a value like ‘en’ or ‘de’ that denotes the language
of the page contents. And, if available, we provide the gettext()
function for that language. In ablog/post.py
we add:
# coming from:
# self.app.emit('html-page-context', pagename, templatename, ctx, event_arg)
# with arguments:
# app, pagename, templatename, ctx, event_arg
#
def html_page_context(app, docname, templatename, ctx, *args, **kwargs):
htmllang = app.config.blog_default_language
postinfo = app.env.ablog_posts.get(docname)
# is it a post?
if postinfo:
languages = postinfo[0].get('language')
if languages:
htmllang = languages[0]
# query the documents metadata otherwise
else:
htmllang = app.env.metadata.get(docname, {}).get('language', htmllang)
ctx['htmllang'] = htmllang
translator = app.ablog.translators.get(htmllang)
if translator:
ctx['gettext'] = translator.gettext
I’m using this technique in this blog - it works :-)
What do you think?