Adding language id to the body class in Drupal 8
When I started making sites with Drupal 8 I missed a special body class that I sometime need for theming as well as other times, and that's the language body class. When making multilingual sites this comes in handy sometimes. For Drupal 7 this was made possible by the Internationalization (i18n) module, but since that module has been moved into core in Drupal (source) that special body-class-adding-thingamajig seems to have vanished.
After facing the need of language id when making this site I started to search for a solution, but came up with very few answers. When I solved it I thought I could make a short entry to spread the knowledge.
My needs
Basically, I had two needs for the language class to be added to my theme.
- I wanted to hide some of the meny items depending on which language the content was presented in. (I later solved this in another way in my theme, but that was the initial need for a body class representing the current language.)
- I have two different RSS-feeds, one for posts in English and one for posts in Swedish. To make it work 100%, the path to the feed needed the language id as well. This was the latter need for me, and also the need that made it to the final site.
The theme
The themes I've used for Drupal 8 haven't had the language flag/path, but some themes may have implemented it, so if you have the path in the body class then you probably don't need to read this.
The example I'm going to show you is from the the Bootstrap Clean Blog, which I use for this site, and I will show you the code for adding the language id to it.
The files
In the theme folder of Bootstrap Clean Blog you need to locate two files:
- bootstrap_clean_blog.theme, which is in the root of the theme folder called bootstrap_clean_blog and
- html.html.twig which is located in the templates folder.
In bootstrap_clean_blog.theme (or any other .theme-file you might have in the theme you're using/developing) add the following code snippet to it:
function bootstrap_clean_blog_preprocess_html(&$variables) { $language = \Drupal::languageManager()->getCurrentLanguage()->getId(); $variables['language'] = $language; }
If you're using a different theme than Bootstrap Clean Blog, the name of the theme-file is something like XYZ.theme, where XYZ is the name (lowercase with underscores) of the theme. For example, if you're using the Pixture Reloaded theme, the theme-file is called pixture_reloaded.theme.
The code above calls for the language by getCurrentLanguage() and assigns the value to the variable $language. After that the value of $language is assigned to the global variable array $variables['language'].
You could shorten this down to
function bootstrap_clean_blog_preprocess_html(&$variables) { $variables['language'] = \Drupal::languageManager()->getCurrentLanguage()->getId(); }
but I wrote it on two separate rows to make it more clear. The shorter code snippet is quite allright, though, and you can use that in your .theme-file.
Next up: The TWIG-file
Allright, so far we've collected the language and stored it in a global variable. Now it's time to make it visible on the webpage, to print it. This is done via TWIG, a fast and secure template engine that Drupal 8 started using. To print the $variables['language'] you write the following "twig code" in your template where you want it to be printed.
{{ language }}
So, in my example, if we want to print it in the body class, I open up the template html.html.twig in the templates folder of the theme and search for the line where the body is set. It looks like this:
<body{{ attributes.addClass(body_classes) }}>
It prints the following HTML when rendered in a browser:
<body class="user-logged-in path-frontpage">
Though, we can't just add {{ language }} to the body tag since it won't be a part of the {{ attributes.addClass(body_classes) }}. Those are set a couple of lines up, but it's easy to fix it. They look like this:
{% set body_classes = [ logged_in ? 'user-logged-in', not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class, node_type ? 'node--type-' ~ node_type|clean_class, ] %}
In i similar way we add:
language ? 'lang-' ~ language|clean_class,
so the final result looks like this:
{% set body_classes = [ logged_in ? 'user-logged-in', not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class, node_type ? 'node--type-' ~ node_type|clean_class, language ? 'lang-' ~ language|clean_class, ] %}
Now comes the thing that's very important. After saving your theme-files, you must clear cache for the changes to appear. Click Configuration > Performance > Clear all cache. Then reload the page and check the source code of it et voilà - it works and the source code looks like this:
<body class="user-logged-in path-frontpage lang-en">
That's that. You can now use the class lang-en to distinguish your English pages and on your pages in another language it might look something like this:
<body class="user-logged-in path-node node--type-article lang-sv">
You can also use {{ language }} anywhere else, for example is you have the same need as I, to make a link language-dependant:
<a href="/{{ language }}/feed">RSS</a>
which gives you the following complete HTML
<a href="/sv/feed">RSS</a>
or
<a href="/en/feed">RSS</a>
if the visitor is on the English part of the site.
Hope this helped you in some way. Happy drupaling!