Support For Multiple Languages in WordPress

Introduction

Foreign visitors have pointed out to me that they sometimes read my blog using translation functions in their their webbrowsing software, most notably „Google Translate“ which is directly built into Google Chrome. That translation function does a good job, but sometimes produces oddities, for example it attempts to translate my lastname, which is also a valid German vocable.

That problem was quickly addressed by adding the class="notranslate" plus the HTML5 language attribute translate="no" to a <span> surrounding my name. But this incident contrasted a deeper problem that has been troubeling me for a while now.

Analysis

My blog contains postings in two different languages, English and German. WordPress however sets the HTML5 language attribute lang="de-DE" to the <html> element of every page, because that is the global setting for this blog. This causes browsers and indexers to make wrong assumptions about the language the content is in.

I believe that there are solutions that equip WordPress blogs with multi-language functionality, but they are more geared towards every part and every entry of my blog having a translated counterpart in every supported language. I have decided against those solutions:

  • First of all, that was a translation effort that I can not undertake or maintain. I do not want to translate anything at all.
  • My problem is more specific: I need specific entries in my blog indicated to be in a specific language.
  • Only the markup itself must be extended with meta-information in the form of certain HTML5 language attributes being set to appropriate values, so that the client-side tools can do their job properly.

Implementation Part 1: Custom Field Setup

I have implemented a solution on top of the free edition of the „Advanced Custom Fields“ plugin for WordPress (in the following in short „ACF“).

Using ACF, I have defined a custom field „language“ that accepts either „de-DE“ or „en-US“ as values. Now, in my post editor I have a dropdown menu where I can choose the language that the text I am writing is in.

Implementation Part 2: Surrounding Blocks of Content

I have implemented a WordPress plugin of my own where I evaluate that setting and surround the content of the post accordingly if that custom „language“ field is set. It roughly goes like this:

function tksls_lang_title($title, $post_id) {
    if(!is_admin()) {
        $lang = get_field('language', $post_id, false);

        if(!empty($lang))
            $title = '<div lang="'.$lang.'">'.$title.'</div>';
    }
    return $title;
}

add_filter('the_title', 'tksls_lang_title');

function tksls_lang_content($content='') {
    if(!is_admin()) {
        global $post;

        if(isset($post->ID)) {
            $lang = get_field('language', $post->ID, false);

            if(!empty($lang))
                $content = '<div lang="'.$lang.'">'.$content.'</div>';
        }
    }
    return $content;
}

add_filter('the_content', 'tksls_lang_content');

Notes

  • The surrounding <div lang="..."> element is not introduced if „lang“ is unset; in that case the attribute lang="..." from the <html> element applies.
  • The clauses if(is_admin()) are neccessary (at least for the hook the_title) so not to mess up display of the entries in the WordPress admin interface.
  • get_field() is a function from the ACF API. The third argument set to false means not to return the human readable description of the option (ACF documentation calls it the „formatted value“) but its internal identifier instead. That way I can display „English (US)“ in my editor dropdown box and use the internal identifier „en-US“ directly for generating markup.

Implementation Part 3: Setting Language of Document

I find it reasonable that if a document holds only a single post then the language of the document is the language of the post since everything else in that document (navigation, banners etc.) are just secondary structures. In this case, and if the post languages deviates from the blog language, I find it preferable to modify the attribute lang="..." of the <html> element.

This done by the plugin using the language_attributes hook:

function tksls_lang_language_attributes($language_attributes) {
    if(is_singular('post')) {
        global $post;

        $lang = get_field('language', $post->ID, false);

        if(!empty($lang))
            $language_attributes = 'lang="'.$lang.'"';
    }

    return $language_attributes;
}

add_filter('language_attributes', 'tksls_lang_language_attributes');

Notes

  • I can do it this way since the WordPress theme framework I use (Thematic) supports that hook in its header.php; but I understand that not every theme does that.

References