Language Based Stylesheet Switching in Your Theme

multilingual DrupalTheming in Drupal is the one layer that seems to have shown the most steady improvement since the introduction of phpTemplate around version 4.5. With each new release it gets easier and easier to bend Drupal to your will and have it display a pixel perfect version of your design.

In Drupal 6 we saw the introduction of powerful .info files that you can use to tell the theme system more about your specific theme. Things like its name, whether its a subtheme, what core Drupal system variables it supports, which features are configurable and which style sheets to use and load for different media.

By defining which style sheets to load in the .info file you don't need to know any PHP (or where you'd use that PHP) to include several style sheets into your site's pages. This really is a great feature. But, what if there are situations when you don't want those style sheets to show up? Or you'd rather have different style sheets load? Well, in those situations you're still going to have to get familiar with some PHP, Drupal's preprocess functions and drupal_get_css().

I recently found myself needing to switch style sheets based on language. Drupal already has some built in code to handle style sheet switching if the defined languages in your site are right to left (RTL) languages. In those cases you simply need to include style sheets with an -rtl suffix in the style sheet name (e.g. style-rtl.css). And when a RTL language is selected, Drupal will take care of loading the -rtl.css file. (For more detailed information see "Supporting "right to left" (RTL) languages" in the handbook.) But what if like me you want Drupal to load a different style sheets for each of your non RTL languages?

After my first bit of investigation, I'd actually come across a hook I'd never run into before hook_system_info_alter which allows modules to alter the .info file of any other module or theme. This would include altering the part of the theme .info file that defines what style sheets to load. But, upon reading the documentation I realized it only gets called when Drupal's caching is rebuilt or when visiting the admin/build/theme page. In other words not on every page load nor when the language is switched.

But, since this is a presentation layer job we're trying to achieve the logical place to look is the theming layer. And in the theme layer, we are specifically looking at information being loaded into a page. Actually, we are looking for a way to modify something before it is loaded into the page.tpl.php file.

Luckily Drupal 6 has Drupal pre-process functions just for this sort of thing. Since it is the 'page' we're interested in we want to make use of the themename_preprocess_page() function.

This function gets passed a $vars array by reference. This array contains the variables and their values that will be passed into the page.tpl.php file. By the time themename_preprocess_page() is called it is already populated with $vars['css'] and $vars['styles'], but you have a chance to change their values.

So if you wanted to change the style sheets based on language you could use some code similar to this.

<pre>
function foo_preprocess_page(&$vars, $hook) {
  global $language;
  if ($language->language != 'en') {
    foreach ($vars['css']['all']['theme'] as $stylesheet => $value) {
      if (strstr($stylesheet, path_to_theme())) {
        $stylesheet = str_replace('.css', '-'. $language->language .'.css', $stylesheet);
      }
      $sheets[$stylesheet] = $value;
    }
    $vars['css']['all']['theme'] = $sheets;
    $vars['styles'] = drupal_get_css($vars['css']);
  }
}
</pre>

In a nutshell, this code checks to see if the current language is not english (could be adjusted to test if its not the 'default' language). If not, then find the style sheets loaded by your current theme and change them to load style sheets with a language suffix. It then repopulates the $vars['css'] and $vars['styles'] with their new values.

Having this exact code run would require that you have a copy of each of your style sheets for each language that your user could switch to reside in your theme's folder. Those style sheets would have to be named in the following format orginalname-langcode.css (e.g. style-fr.css).

I suppose this concept could be expanded to write a module that would allow an administrator to select which of the theme's style sheets to replace (instead of replacing them all) and for which languages to do it. Or, you can simply adjust the logic in the above function to suit your specific needs.

As always, leave a comment if you have a question, different solution or have suggestions on improving the information provided here.

May 6th 2009 12AM
By: andre

 

Comments

Great but how to test it?

I am evaluating Drupal 6 for multilingual site (zh,fr,en,ru,es,ar), and this is the missing part I have been looking for days.

I have the code at the top of page.tpl.php and corresponding stylesheet files
style-fr.css, style-ar.css... in place but doesn't take effect.

In this Drupal multilingual support evaluation process I admit that my PHP skills are basic.

Please advise us.
Definitively this should be a module

<?php
function foo_preprocess_page(&$vars, $hook) {
global $language;
if ($language->language != 'en') {
foreach ($vars['css']['all']['theme'] as $stylesheet => $value) {
if (strstr($stylesheet, path_to_theme())) {
$stylesheet = str_replace('.css', '-'. $language->language .'.css', $stylesheet);
}
$sheets[$stylesheet] = $value;
}
$vars['css']['all']['theme'] = $sheets;
$vars['styles'] = drupal_get_css($vars['css']);
}
}
?>

Please made a module.

Please made a module.

I try it but not working,

I try it but not working, Please hlep me in detail
I wrok on drupal 6, And I enable to LTR language one is default english
and another is Hindi(Indic).
please mention the file name where I write this code,
I made a theme named cdraw, So please tele me where i have to change the code.
Thanks

Please which files I have to

Please which files I have to edit?? is it works for 5.x?
i need help, i will appreciate it, Thanks

worked like charm. Comment

worked like charm. Comment from Benjamin also worked great. Thanks

Posting Emailed Comment

Check if file exists and only use then

You could also check if the file for an alternate language stylesheet
exists, and only try to load it then. Not tested at all, but it seems this
could be added inside that if:

<pre>
<?php
      $stylesheet_lan
= str_replace('.css', '-'. $language->language
.'.css', $stylesheet);
     
$stylesheet = (file_exists($stylesheet_lan)) ? $stylesheet_lan :
$stylesheet;
?>

</pre>

benjamin, Agaric Design Collective

This is great

Great writeup; thanks a lot!