Multilingual websites and webapplications using PHP and Smarty, part 1: detecting languages and locales

Joor Loohuis, July 12, 2009, 14355 views.

Supporting more than one language in a website or webapplication has become a core feature of many projects. This series of articles explains how you can detect languages and locales, and how you can use Smarty to produce interfaces with support for languages and locales that are easy to maintain.

Tags: , , , , , ,

Gradually, owners of websites and webapplications are realizing that the Internet doesn't stop at the border. To many people familiar with how the Internet works this might appear obvious, but you have to take into consideration that for many of these owners the website is not their core business, but a channel of communication or sales. Often it only becomes apparent at a later stage that a site that was originally targeted at a specific country or region attracts visitors and customers from other language areas.

For those not yet familiar with NLS (Native Language Support), as it is called, there are a few aspects to it, which will be discussed in episodes on this blog. First and foremost, just translating a website is not all there is to it. Depending on the country, there may be different conventions for writing time and date values, currency, and various other data. The combination of a language and these conventions is called a locale. Besides NLS, there are two terms that you will encounter that pertain to supporting multiple languages in software:

internationalization (an 'i', 18 letters, and an 'n') is the process of designing (or adapting) software so that multiple languages and regions can be supported and new languages and regions can be easily added
localization (an 'L', 10 letters, and an 'n') is the process of adding a language or locale to software that is internationalized

This article on i18n and L10n for websites and webapplications will be divided in three episodes:

  1. this first episode will address detecting the language and locale of a user based on the information the user transmits.
  2. the second episode will address one important part of NLS in the form of an easy and extensible way of implementing multiple languages in Smarty templates.
  3. the third and final episode will discuss how to select the correct locale, so that the correct conventions are used for displaying data.


Selecting the correct language and locale is done by analyzing some information that is sent by the browser with each request. One of the headers that is sent is the Accept-Language header, which contains the languages the user has selected she or he can read, including the order of preference preference of these languages. In any proper browser, this can be configured in the preferences. Most users of Internet Explorer however are restricted to the locale of their Windows environment. The value of this header needs a little processing in order to extract the correct values. A typical header may look like:

Accept-Language: en-us,en;q=0.7,nl;q=0.3

The value is a list of acceptable languages, separated by commas. Each language may be supplemented with a quality factor q that indicates the relative preference. So the value above states something like 'I prefer US English, but I'll settle for any other English locale, and if that is not available, I also read any Dutch locale'. Obviously, from this information it is possible to decide which language and locale have the users preference, and based on this the user can be redirected to the right part of the website, or other actions can be triggered. For websites and webapplications based on PHP and Smarty there are basically two ways of using the language information from the request to set the language and locale.


One approach to handling languages in a website is to redirect the visitor to a section of the website based on the language preferences. This has the advantage that it works for both static HTML sites and sites that use templates to display dynamic data which needs to be localized. The language redirection can be implemented as a short PHP script like this:

// language redirector, stored as /index.php
// supported languages
$languages = array('en', 'nl');
$accept_languages = split(',', $_SERVER"HTTP_ACCEPT_LANGUAGE");
// iterate over accepted languages
while ($accept = array_shift($accept_languages)) {
    // split language from quality
    $parts = split(';', $accept);
    // get the language
    $lang = preg_replace('/-.*/', '', $parts0);
    // check supported languages
    if (in_array($lang, $languages)) {
        header("Location: /$lang/index.php");
// default language if no supported language is accepted
header("Location: /en/index.php");

Here we use the PHP variable $_SERVER['HTTP_ACCEPT_LANGUAGE'], which contains the value of the Accept-Language header of the request. It is split on comma's, to retrieve the individual languages, over which we iterate. Then we separate the language part from rest of the locale and the quality, and compare it with a list of languages we support. If there is a match, we redirect to the part of the site we set up for that language. If none of the acceptable languages is supported, we redirect to a default language. Note that the languages are processed in order of preference of the visitor. All you need now is a site with directories for each language you intend to support. One major advantage of this approach is that you can set up different content for the supported languages. For example, you could separate your site in national and international sections. Another advantage is that this language detection only affects the index page of the site, and doesn't interfere if the visitor selects a specific language section at a later stage.

Resource loading in templates

If you need to detect the preferred language in a Smarty template, the procedure is more or less the same. The preferred language can be extracted by using a few template constructs.

{assign var=accept_languages value=','|split:$smarty.server.HTTP_ACCEPT_LANGUAGE}
{assign var=$lang value=$accept_languages0|regex_replace:'#|\W.*#':''}

Here we split the Accept-Language header and assign it to an array. Consequently, we extract the most preferred language, and assign it to the $lang template variable. In the case where redirection is used as described above, extraction of the language should be done from the requested script name in stead of the request headers.

{assign var=$lang value=$smarty.server.SCRIPT_NAME|regex_replace:'#(^/|\W.*)#':''}

How you actually apply the language depends on the setup of your website or application. We will discuss ways of selecting languages and locales in the followups to this article.

Social networking: Tweet this article on Twitter Pass on this article on LinkedIn Bookmark this article on Google Bookmark this article on Yahoo! Bookmark this article on Technorati Bookmark this article on Delicious Share this article on Facebook Digg this article on Digg Submit this article to Reddit Thumb this article up at StumbleUpon Submit this article to Furl


respond to this article