Localizing a WordPress Blog
There are many translation plugins available for WordPress, and most of them deal with translations of articles. This might be of interest for others, but not for me. If you have a blog with visitors from various language background, because you are living abroad, or writing in several languages, you might feel tempted to provide visitors with a localized “environment”, meaning that as much as possible is translated into the native language of the visitor, without actually translating content – but allowing to.
In my case I am writing mostly in English and Japanese, but sometimes (in former times) in Italian and now and then in my mother tongue, German. Visitors from my site are from all over the world, but at least for Japanese visitors I wanted to provide a localized environment. This blog describes how to get as much as possible translated of your blog, and here I mean not the actual articles, because this is the easy part and most translation plugins handle that fine, but the things around the articles (categories, tags, headers, …).
Starting point and aims
My starting point was a blog where I already had language added as extra taxonomy, and have tagged all articles with a language. But I didn’t have any other translation plugin installed or used. Furthermore, I am using a child theme of the main theme in use (that is always a good idea anyway!). And of course, the theme you are using should be prepared for translation, that is that most literal strings in the theme source code are wrapped in __( ... ) or _e( ... ) calls. And by the way, if you don’t have the language taxonomy, don’t worry, that will come in automatically.
One more thing: The following descriptions are not for the very beginner. I expect certain fluency with WordPress, where for example themese and plugins keep their files, as well as PHP programming experience is needed for some of the steps.
With this starting point my aims were quite clear:
- allow for translation of articles
- translate as much as possible of the surroundings
- auto-selection of language either depending on article or on browser language of visitor
- by default show all articles independent of selected language
- if possible, keep database clean as far as possible
Translation plugins
There is a huge bunch of translation plugins, localization plugins, or internationalization plugins out there, and it is hard to select one. I don’t say that what I propose here is the optimal solution, just one that I was pointed at by a colleague, namely utilizing the xili-language plugin.
Installation and initial setup
Not much to say here, just follow the usual procedure (search, install, activate), followed by the initial setup of xili-language. If you haven’t had a language taxonomy by now, you can add languages from the preference page of xili-language, first tab. After having added some languages you should have something similar to the above screen shot. Having defined your languages, you can assign a language to your articles, but for now nothing has actually changed on the blog pages.
As I already mentioned, I assume that you are using a child theme. In this case you should consult the fourth tab of the xili-language settings page, called Managing language files, where on the right you should see / set up things in a way that translations in the child theme override the ones in the main theme, see screen shot on the right. I just mention here that there is another xili plugin, xili-dictionary, that can do a lot of things for you when it comes to translation – but I couldn’t figure out its operation mode, so I switched back (i.e., uninstalled that plugin) and used normal .po/.mo files as described in the next section.
Adding translations – po and mo files
Translations are handled in normal (at least for the Unix world) gettext format. Matthias wrote about this in this blog. In principle you have to:
- create a directory languages in your child theme folder
- create there .po file named local-LL.po or local-LL_DD.po, where LL and LL_DD are the same as the values in the field ISO Names in the list of defined languages (see above)
- convert the .po files to .mo files using
msgfmt local-LL.po -o local-LL.mo
The contents of the po files are described in Matthias’ blog, and in the following when I say add a translation, then I mean: adding a stanza
msgid "some string"
msgstr "translation of some string"
to the po file, and not forgetting to recompile it to mo file.
So let us go through a list of changes I made to translate various pieces of the blog appearance:
Translation of categories
This is the easiest part, simply throw in the names of your categories into the respective local-DD_LL.po file, and be ready. In my case I used local-ja.po which besides other categories contains stanzas like:
msgid "Travel"
msgstr "旅行"
Translation of widget titles
In most cases the widget titles are already automatically translated, if the plugin/widget author cared for it, meaning that he called the widget_title filter on the title. If this does not happen, please report this to the widget/plugin author. I have done this for example for the simple links plugin, which I use for various elements of the side-bar. The author was extremely responsive and the fix will be in the next release is already in the latest release – big thanks!
Translation of tags
This is a bit a problem, as the tags appear in various places on my blog: next to the title line and the footer of each blog, as well as in the tag cloud in the side bar.
Furthermore, I want to translate tags instead of having related tag groups as provided by xili tidy tags plugin, so we have to deal with the various appearances of tags one by one:
Tags on the main page – shown by the theme
This is the easier part – in my case I had already a customized content.php and content-single.php in my child theme folder. If not, you need to copy the one from the parent theme and change the appearance of it to translate tags. Since this is something that depends on the specific theme, I cannot give detailed advice, but if you see something like:
$tags_list = get_the_tag_list( '', __( ', ', 'mistylake' ) );
(here the get_the_tag_list is the important part), then you can replace this by the following code:
$posttags = get_the_tags();
$first = 1;
$tag_list = '';
if ($posttags) {
foreach($posttags as $tag) {
if ($first == 1) {
$first = 0;
} else {
$tag_list = $tag_list . __( ', ', 'mistylake' );
}
$tag_list = $tag_list . '' . __($tag->name, 'mistylake') . '';
}
}
(there are for sure simpler ways …) This code loops over the tags and translates them using the __ function. Note that the second parameter must be the text domain of the parent theme.
If you have done this right and the web site is still running (I recommend testing it on a test installation – I had white pages many times due to php programming errors), and of course you have actual translations available and are looking at a localized version of the web site, then the list of tags as shown by your theme should be translated.
Tag cloud widget
This one is a tricky one: The tag cloud widget comes by default with WordPress, but doesn’t translate the tags. I tried a few variants (e.g. creating a new widget as extension of the original tag cloud widget, and only changing the respective functions), but that didn’t work out at all. I finally resorted to a trick: Reading the code of the original widget, I saw that it applies the tag-sort-filter filter on the array of tags. That allows us to hook into the tag cloud creating and translate the tags.
You have to add the following code to your child theme’s functions.php:
function translate_instead_of_sort($tags) {
foreach ( (array) $tags as $tag ) {
$tag->name = __( $tag->name , 'mistylake' );
}
return $tags;
}
add_action('tag_cloud_sort', 'translate_instead_of_sort');
(again, don’t forget to change the text domain in the __(.., ..) call!) There might be some more things one could do, like changing the priority to be used after the sorting, or sort directly, but I haven’t played around with that. Using the above code and translating several of the tags, the tag cloud now looks like the screenshot on the right – I know, it could use some tweaking. Also, now the untranslated tags are sorted all before the translated, things one probably can address with the priority of the filter.
Having done the above things, my blog page when Japanese is selected is now mostly in Japanese, with of course the exception the actual articles, which are in a variety of languages.
Open problems
There are a few things I haven’t managed till now to translate, and they are mostly related to the Jetpack plugin, but not only:
- translation of the calendar – it is strange that although this is a standard widget of WordPress, the translation somehow does not work out there
- transalation of the meta text entries (Log in, RSS feed, …) – interestingly, even adding the translation of these strings did not help get them translated
- translation of simple links text fields – here I haven’t invested by now
- translation of (Jetpack) subscribe to this blog widget
I have a few ideas how to tackle this problem: With Jetpack the biggest problem seems that all the strings are translated in a different text domain. So one should be able to add some code to the functions.php to override/add translations to the jetpack text domain. But somehow it didn’t work out in my case. The same goes for things that are in the WordPress core and use the translation functions without a text domain – so I guess the translation function will use the main WordPress translation files/text domain.
Conclusion
The good thing of the xili-language plugin is that it does not change the actual posts (some plugins save the translations in the the post text), and is otherwise not too intrusive IMHO. Still, it falls short of allowing to translate various parts of the blog, including the widget areas.
I am not sure whether there are better plugins for this usage scenario, I would be surprised if not, but all the plugins I have seen were doing a bit too much on the article translation side and not enough on the translation of the surroundings side.
In any case, I would like to see more separation between the functionality of localization (translating the interface) and translation (translating the content). But at the moment I don’t have enough impetus to write my own plugin for this.
If you have any suggestions for improvement, please let me know!
Enjoy.
It’s amazing how very few websites seem to consider doing that when they’re available in multiple languages. Instead they use ridiculous stuff like location, if they do.
Indeed. For now I am doing it based on content, but this is only because it makes it easier for me to test changes. When I’m content I’ll switch to selection based on the browser language, which is the only reasonable way in my opinion. Location is brain-damaged, completely. And based on content is strange, because I might want to check out an article in a language I hardly understand, but still want to see the rest in a comprehensible way.
Well, of course you should always have an easy override available. 🙂