• strict warning: Non-static method view::load() should not be called statically in /home1/eangkasa/public_html/sites/all/modules/views/views.module on line 879.
  • strict warning: Declaration of views_handler_argument::init() should be compatible with views_handler::init(&$view, $options) in /home1/eangkasa/public_html/sites/all/modules/views/handlers/views_handler_argument.inc on line 745.
  • strict warning: Declaration of views_handler_filter::options_validate() should be compatible with views_handler::options_validate($form, &$form_state) in /home1/eangkasa/public_html/sites/all/modules/views/handlers/views_handler_filter.inc on line 589.
  • strict warning: Declaration of views_handler_filter::options_submit() should be compatible with views_handler::options_submit($form, &$form_state) in /home1/eangkasa/public_html/sites/all/modules/views/handlers/views_handler_filter.inc on line 589.
  • strict warning: Declaration of views_handler_filter_node_status::operator_form() should be compatible with views_handler_filter::operator_form(&$form, &$form_state) in /home1/eangkasa/public_html/sites/all/modules/views/modules/node/views_handler_filter_node_status.inc on line 14.
  • strict warning: Non-static method view::load() should not be called statically in /home1/eangkasa/public_html/sites/all/modules/views/views.module on line 879.
  • warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /home1/eangkasa/public_html/sites/all/modules/counter/counter.module on line 136.
  • warning: strtotime(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /home1/eangkasa/public_html/sites/all/modules/counter/counter.module on line 159.
  • warning: strtotime(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone. in /home1/eangkasa/public_html/sites/all/modules/counter/counter.module on line 159.
  • strict warning: Non-static method view::load() should not be called statically in /home1/eangkasa/public_html/sites/all/modules/views/views.module on line 879.
  • strict warning: Declaration of views_handler_field_comment::init() should be compatible with views_handler_field::init(&$view, $options) in /home1/eangkasa/public_html/sites/all/modules/views/modules/comment/views_handler_field_comment.inc on line 50.
  • strict warning: Declaration of views_handler_field_comment_username::init() should be compatible with views_handler_field::init(&$view, $options) in /home1/eangkasa/public_html/sites/all/modules/views/modules/comment/views_handler_field_comment_username.inc on line 48.
  • strict warning: Declaration of views_plugin_row::options_validate() should be compatible with views_plugin::options_validate(&$form, &$form_state) in /home1/eangkasa/public_html/sites/all/modules/views/plugins/views_plugin_row.inc on line 135.
  • strict warning: Declaration of views_plugin_row::options_submit() should be compatible with views_plugin::options_submit(&$form, &$form_state) in /home1/eangkasa/public_html/sites/all/modules/views/plugins/views_plugin_row.inc on line 135.
  • strict warning: Non-static method view::load() should not be called statically in /home1/eangkasa/public_html/sites/all/modules/views/views.module on line 879.
  • strict warning: Non-static method view::load() should not be called statically in /home1/eangkasa/public_html/sites/all/modules/views/views.module on line 879.

Setting up multilingual site with Drupal Internationalization (i18n)

The following tutorial will explain a step by step process on building a Multilanguage site with Drupal. On today’s era, it is considered a good approach to have a bilingual site, one in English and one other in your local language to get a wider range of visitors and members.

1. Installing the required modules

Download the i18n modules and install as usual

Activate the core module: Locale & Content Translation


2. Installing the default language for your content (.po files)

Go to Translations project on Drupal by visiting http://drupal.org/project/Translations
Look for your native language translation, in my case it would be Indonesian Translation

Download the .tar.gz file
Extract the file into your site’s server through FTP such as FileZilla. First of all, extract the .tar.gz file in your local desktop, afterwards you are supposed to have a directory structure such as below:

Finally, transfer the whole directory into your drupal root site.
If you have access to CPanel File Manager and more convenient with it rather than FileZilla, then follow the video tutorial below from Lullabot (starting from min 05:19) explaining how to extract the .tar.gz file into your drupal root site. Or you can download the video tutorial through Here as a backup purpose.


3. Setting up your default language

Go to administer -> site configuration -> languages (admin/settings/language), pick your default language, in my case it would be Indonesian.

Choose edit and adapt any changes according to your preference.

Go to configure tab under languages, and set your language negotiation to determine the site’s presentation language.

If you prefer not to display the content translation links under each node, then Go to Multilingual system tab under languages, and tick on “Hide content translation links”.

If you started and install your site by using English as the default language, how do you setup your native language in my case all Indonesian nodes as plain http://www.example.com and English nodes as http://www.example.com/en?

Go to administer -> site configuration -> language (admin/settings/language) and edit each language. Modify the path prefix for each language, set Indonesian path prefix to “none” and English path prefix to “en”.


4. Enabling multilingual support for your Content Types

Go to administer -> content management -> content types
Choose the content types which are regularly translated into another language.
Click on edit and set the multilingual support to “enabled, with translation” under Workflow settings


5. Creating translations

Pick any node you want to translate and click on edit.
If you have correctly enabled the “multilingual support” for content types as marked in step number 4, you should have a language option (English & Indonesian for my case).

Set it to your chosen default language as marked in step number 3 (Indonesian for my case)
Save the node and additional “Translate” tab should appear besides the “Edit” tab

Click on translate and choose on “add to translation” to create a translation node, by default the language will be set to the opposite language (English for my case).

Save the translation node


6. Manual translation of user defined strings by using Translate Interface

Most of the time, the translation project (collection of .po files) doesn’t have a complete translation of all user defined strings.  For your information, the Indonesian translation isn’t completed yet, for a rough estimation it only covers up to 60% while the rest should be done manually by yourself through Translate Interface.

Additionally, this translation may cover only for default (core) modules, not for all optional modules downloadable through Drupal site.


7. Translation of site’s variable by defining i18n variables in the Config file (sites/default/settings.php)

Site’s variable such as site mission, site footer, contact form information or even primary links & secondary links can be set according to the current language. This necessarily means, if you are on Indonesian language, you can write down Indonesian content  for site mission and by switching (using language switcher module presumably) to English language, then you can eventually setup another English content, and it won’t alter the Indonesian content.

For your information, if you see a note saying “This is a multilingual variable” that means the variable can be addressed with different contents according to the current language.

  1. /**
  2. * Multilingual settings
  3. *
  4. * This is a collection of variables that can be set up for each language when i18n is enabled.
  5. * These are the basic ones for Drupal core, but you can add your own here.
  6. */
  7. $conf['i18n_variables'] = array(
  8. 'site_name',
  9. 'site_footer',
  10. 'site_slogan',
  11. 'site_mission',
  12. 'anonymous',
  13. // Different front page for each language
  14. // 'site_frontpage',
  15. // Primary and secondary links
  16. 'menu_primary_links_source',
  17. 'menu_secondary_links_source',
  18. // Contact form information
  19. 'contact_form_information',
  20. 'user_mail_password_reset_body',
  21. 'user_mail_password_reset_subject',
  22. 'user_mail_register_admin_created_body',
  23. 'user_mail_register_admin_created_subject',
  24. 'user_mail_register_no_approval_required_body',
  25. 'user_mail_register_no_approval_required_subject',
  26. 'user_mail_register_pending_approval_body',
  27. 'user_mail_register_pending_approval_subject',
  28. 'user_mail_status_activated_body',
  29. 'user_mail_status_activated_subject',
  30. 'user_mail_status_blocked_body',
  31. 'user_mail_status_blocked_subject',
  32. 'user_mail_status_deleted_body',
  33. 'user_mail_status_deleted_subject',
  34. 'user_picture_guidelines',
  35. 'user_registration_help',
  36. 'user_location_google_key', // So that we get a different item for each subdomain
  37. );


8. Primary Links and/or Secondary Links multilingual support

Unfortunately, we often have primary links and/or secondary links being displayed not in a block, for your information we can easily differentiate each block per language however we should discuss more to that on the next procedure, as for now we should focus on primary and/or secondary links.

In most situations, our primary and/or secondary links will be rendered on the page.tpl.php with the following code:

  1. <?php if (isset($primary_links)) : ?>
  2. <?php print theme('links', $primary_links, array('id' => 'menu')) ?>
  3. <?php endif; ?>
  4. <?php if (isset($secondary_links)) : ?>
  5. <?php print theme('links', $secondary_links, array('class' => 'links secondary-links')) ?>
  6. <?php endif; ?>

We can arrange the 2 of them using the technique shown on the previous step (step number 7) by using multilingual variable. What you have to do is simply create 2 separate menus, one menu for Indonesian while the other for English menu. Afterwards, go to administer -> site building -> menus -> select on Settings tab.

Notice the multilingual variable under Source for primary links and secondary links. Allocate the Indonesian menu that you have previously created into the primary and/or secondary links if you are currently on Indonesian language, and use language switcher to switch into English language and appropriately change the source for primary and secondary links with English menu.


9. Blocks & Views multilingual support

Setting up blocks with multilingual support seems pretty straightforward because it has such capability by default. You can setup which block to appear under what language by selecting on multilingual settings under each block as depicted below (normally, we would make a separate block for each language, for my case I would have to make 2 separate blocks to be displayed under my Indonesian and English language):

Views are normally displayed within a block, but how do you actually filter the content itself so that it only displayed those contents belongs to a certain language. The answer lies on adding another filter of node translation language as current user’s language. It can be directly added by editing the View.


10. Forum & Taxonomy multilingual support

There are plenty of ways to arrange taxonomy terms to appear only under user’s current language. For a multilingual forum, I much prefer using “Per language terms. Different terms will be allowed for each language and they can be translated” which means you have to make a different set of terms for each language separately. Meanwhile, if you “Localize the terms” you can only translate the title and not the URL address,  from the SEO point of view, it’s not considered a good approach, since the URL address seems to be misleading compared to the real content.

I do realize that by selecting “per language terms” I’m actually building 2 different set of forums, which’s a real hassle and not really adopting the Drupal i18n. For an instance, if you are posting in an Indonesian forum, the content won’t appear under English forum, and vice versa. Meanwhile, if you are using localize terms, the container & forum name will be translated and both Indonesian & English forum are pointing to the same address. Afterwards, you could translate each node posted to cover both languages.

However, how do you enforce Indonesian users to translate their posts to English content? It’s practically impossible approach in real life environment. The English members will definitely feel uncomfortable and upset if they are on an English forum and seeing unexpected Indonesian contents being posted there. Therefore, I must recommend to abandon the translation approach of every content posted in a forum and using “per language terms” to build 2 set of forums, one for Indonesian and the other for English forum. Thus, Indonesian members can only post to the Indonesian forum and vice versa. Somehow, we are still utilizing Drupal internationalization limited to taxonomy terms not for forum nodes, because the node isn’t being translated but instead we are creating 2 different (unconnected) nodes.

At this stage, I won’t cover the usage of Views and Taxonomy terms, as I haven’t got a chance to test it myself.


11. Adding a language switcher (language icons)

Go to administer -> blocks -> activate / enable the language switcher block, in most cases you would want to locate the language switcher not in a block but instead somewhere on the top bar. The following PHP snippet below can perform such task (normally, you would copy & paste it under page.tpl.php):

  1. <?php
  2. // this is copy&paste from locale_block in locale.module
  3. $languages = language_list('enabled');
  4. $links = array();
  5. foreach ($languages[1] as $language) {
  6. if ($language->language != $current) {
  7. $links[$language->language] = array(
  8. 'href' => $_GET['q'],<br />
  9. 'title' => $language->native,
  10. 'language' => $language,
  11. 'attributes' => array('class' => 'language-link'),
  12. );
  13. }
  14. }
  16. // this adds the real paths, i.e. if we are on a german page,
  17. // the british flag will point to en/english_alias instead of
  18. // en/node_with_german_content
  19. translation_translation_link_alter($links, $_GET['q']);
  21. // This one adds extended languages, i.e. those that are not enabled.
  22. // Disable if you want only flags for enabled languages.
  23. i18n_translation_link_alter($links, $_GET['q']);
  25. // now add or replace text links by flags, according to your i18n settings.
  26. if (function_exists('languageicons_translation_link_alter'))
  27. languageicons_translation_link_alter($links, $_GET['q']);
  29. // Or do your own stuff, e.g. set the flags and no lang names,
  30. // no matter what the i18n icon settings say.
  31. //if ($icon = theme('languageicons_icon', $language, NULL)) {
  32. // $links[$language->language]['title'] = theme('languageicons_place', $link['title'], $icon);
  33. // $links[$language->language]['html'] = TRUE;
  34. //}
  36. // remove the current language again. We cannot do that
  37. // earlier because i18n_translation_link_alter would add it
  38. // again, thinking it was an extendeg language because it
  39. // was not yet contained in $links. If you don't use
  40. // i18n_translation_link_alter, you can also make a case distinction
  41. // in the foreach loop
  42. $current = i18n_get_lang();
  43. unset($links[$current]);
  45. // format as you like, e.g.
  46. echo theme('links', $links, array());
  47. ?>

Installing Language Icons module is strongly recommended as it’s a good approach to design. Simply install and active the module as usual and it will automatically add a language icon besides each enabled language under the language switcher block. Not all languages are currently supported meaning there are some languages with no associated icons, so don’t be surprised if a language icon doesn’t appear next to your language after successfully installing the module.


12. Contact form multilingual support

Install the tContact module to enable each Contact Category per language.

Afterwards, add 2 categories one for Indonesian and the other for English, and set the Language option appropriately. This is useful for setting up different auto-reply for different customers.

Go to administer -> site building -> contact form -> Settings tab
Edit the additional information (the text to appear above your contact form) based on your current language. Rest assured that this is a multilingual variable if you have properly added a multilingual variable in the Config file (sites/default/settings.php).

Use the translate interface where appropriate to translate some of the user defined strings on the form such as “Contact” page title and remaining field titles.
The Primary links menu name for Contact can be translated easily to “Contact” and “Kontak” since I have been using 2 separates menus for both my English and Indonesian language. These 2 menus are pointing to the same URL address which is “contact”, but have different titles editable through the Menu setting.



pathauto & token

Hi, thanks for this write up. It's so much better than the drupal handbook! Not just the write up but the formatting as well, very legible. (What i would give to kill Garland and the cursed 3-column setup of drupal.org. Hopefully the redsign will be implemented as scheduled january 15th 2010.) Anyway, following along with your tutorial i came to step 10. Forum & Taxonomy multilingual support, where you sayMeanwhile, if you “Localize the terms” you can only translate the title and not the URL addressBut what if you would use the pathauto module with token module enabled? It would allow you to set up a content type specific automatic url translation, where you could mimic the translation path for your forum entries, even though they're not literal translations but completely seperate environments. That should do what you want: have all English forumcontent exist at a seperate path even though it has no relation to the original forum content. You could then still use taxonomy or flag on every post to limit search to the proper language, right?Cheers, Willem (The Netherlands)    

No worries, glad to help

No worries, glad to help :)

Hahaha, yeah mate, drupal 6 currently lacks in theming, but as soon as drupal 7 comes out early next year, the theming should looks much better :)

Aha, i haven't really thought of your method, however briefly i can say your way seems logical, perhaps you can test it on your site and give us a feedback later on. One other thing, what i refer as "unable to translate the URL address", i was actually referring to the forum container URL address, not the thread title, as you have mentioned before we can rename the URL address for thread title using pathauto module.

Thus, if you're using the "localize the terms", the forum container name will be adjusted according to the current language, however, the URL address for those forum containers won't change.

One other thing, i reckon you are missing my point there. I would say using "per language terms" to build 2 completely separate forum is more suitable rather than "localize the terms", as the end user won't bother to translate each of their posts.

Hopefully, you understand what i'm trying to say, pardon my english :)

Translate forgotten Password email

Would you happen to know how can you get the forgotten password email to translate to the current browser language? It seems this function function _user_mail_text($key, $language = NULL, $variables = array()) {Defaults to the system variables table if there is a value there. Thanks for your help in advanced!

see point no.7, after you

see point no.7, after you have modified the settings.php with the additional information, you should be able to see "This is a multilingual variable" under "Password recovery email". afterwards, depending on your current browser language, you can modify the content inside "Password recovery email".

Drupal 6 Language Switcher Block

Great Article.Do you know how to remove the large word "Languages" from the language switcher block? I like the icons and text next to each language type, but that word Languages above them is ruining my menu!Thanks for any help!Ken Hoffhoffk@piedmonthealth.org

Drupal 6 Language Switcher Block

First, thanks for this very useful, and easy to understand, how-to about internationalization. Second, @hoff :To remove the "Language" title of the language switcher block :- go in Admin / Build / Block to manage block.I suppose you have the "Language switcher" in the left sidebar- configure this "Language switcher" block- in "Block title", leave blank use the default title... but you can chose <none> to display no title I hope it will help you. ;-)

@hoffk try didier's solution,

@hoffk try didier's solution, it has to work :)@didier thanks mate :)

Thank You!

Thank you so much for this article. Very clear and detailed. Drupal can be so frustrating sometimes, but your article helps clarify a lot.