Blog customizations

Translations: br
Jul 24, 2021

Part of the "One year of blog" series:

  1. One year of blog
  2. Blog customizations

I've been using pelican as my static blog generator since I started this blog about one year ago. It only took a bit of configuration to get the blog up and running, and a bit of searching through pelicanthemes to find nikhil-theme which is the theme I'm still using.

While the base blog setup was easily done, it wasn't perfectly suited for my needs. This is when I started customizing a few things to make it fit my use. Thankfully pelican is really customizable, even offering a plugin interface in addition to the normal configurations. It is also written in python, so if all fails, I can always hack a patch together to get the job done 😝.

So as promised in the previous post, in this one I will talk about the main customizations I did to my blog so far. Throughout the text I'll link to the commits where I did the changes mentioned here.

Customizations

Pelican plugins

The most impactful customizations I did were probably the pelican plugins I added. These aren't my own modifications, but given their importance I want to describe them.

The two plugins I'm currently using are i18n_subsites and series, and they were really easy to find from the plugin repository.

i18n_subsites is great for my dual-language blog. By default, pelican supports only translating blog posts as standalone texts so that each translated post has links the translations. But what I really wanted was to have two versions of my blog, one in english and another in portuguese. Each with all the interface in its own language as well as only showing the posts of that language. This plugin enables exactly that.

It is a bit confusing to understand how to correctly configure it at first, mainly the template localization part, but hey, I learned about Jinja2 and gettext! Relevant commits: 1 (it was part of the initial commit, sorry), 2, 3, 4 and 5.

series I added a bit later. It's very simple but useful. In fact you can see it in action in this same post at the top. It's what enables me to make this post part of a series of posts and link to the other ones. Relevant commits: 1.

Separate RSS feed for each i18n sub-site

Also on the subject of translation, since I wanted separate sub-sites for each language, it also made sense to have a separate RSS feed for each of them. In the end this turned out to be a single line change, even though it took me a while to figure out how to do it. Relevant commits: 1.

Automatic language detection from filename

Another customization related to translations (it was a big thing for my blog! 😝) was setting the language of the post automatically from the file name. Since I already want the file for each translation of a post have the language in its name, this saves me from needing to input the language header as well.

For example, the files for this post are called 07-blog-custom-en.rst, for the english version, and 07-blog-custom-br.rst for the portuguese version. Normally I'd also need to set a lang metadata header for each one with the corresponding language, but with this change it is set automatically πŸ™‚. Relevant commits: 1 (again, part of the initial commit πŸ˜…) and 2.

Icon setting for pages

When I was setting up the navbar on the top, I wanted to add an icon to each entry, to make it very clear what each one does. But the About page, unlike the others, is a page generated from rst and automatically added to the bar, so I couldn't set its icon in the HTML directly.

To solve this I created a custom icon metadata header that holds the FontAwesome icon name for the icon that will be displayed for the page on the bar. Then I just added the name of that "info circle" icon for the About page and now it looks much better πŸ™‚. Relevant commits: 1.

Fix for literal rendering in rst

Let's wrap the post with the biggest change 😝.

First of all, some context: When I started the blog, I wrote the posts in Markdown. But a few months later I learned about reStructuredText (from here on, referred to as rst) because it was used in the Linux Kernel documentation, and started using it even more when I discovered rst2pdf, which I won't go into detail since I still plan on writing about it eventually. The point is that I started writing my blog posts in rst instead since it was supported by pelican.

But one really annoying issue I faced is that the default HTML generator for rst translates literal blocks into <tt> tags. This tag is deprecated in HTML5, and the whole world uses <code> for inline code, including my theme, which meant literals didn't render right. (There are reasons rst doesn't use <code> for literals, but for my blog they aren't relevant)

I could have just adapted my theme to workaround it, but that would be hiding the problem: The deprecated <tt> tag would still be there for the world to see.

At first, I worked around this issue by using the code role explicitly:

The following is a rst literal, so it will be inside a <tt> tag: ``blah``
The following uses the code role, so it will be inside a <code> tag: :code:`blah`

That is obviously a too cumbersome syntax for a blog that frequently uses inline code, so I got tired of it quickly. I then started overriding the default role to be code, and using single ticks instead of the double ticks syntax for literals:

.. default-role:: code

Now the following will use the code role: `blah`

Since the text is inside single ticks but doesn't have a role specified, it uses the default one. Way better, but I still needed to write that default-role definition at the beginning of each document...

Finally, I thought of an even better solution: Create an rst reader plugin for pelican which overrides the default reader only when parsing literals, in order to output <code> instead of <tt>.

This honestly was easier than I expected. It just took a bit of copying from pelican's and Sphinx's readers and worked perfectly! Now I could finally write plain rst literals and have them be converted to <code> tags without any additional work πŸ™‚. Relevant commits: 1 and 2 (this is just me updating all blog texts to use the new syntax).

Conclusion

With these customizations, I have a blog I'm very comfortable with, both when writing and reading it. These changes I showed were the ones I thought were the most interesting, but naturally the whole code is open, so feel free to check the rest of it.