Localising sites can be a chore, but PHP has the venerable setlocale() to use system locales. These are like templates or profiles that describe how various types of data should be displayed. Should a price have a comma or point to indicate the decimals? When printing a date should PHP output Monday or Montag?

All of these considerations are locale specific and they map to a geographical area. Various cultures have their own standards for displaying this kind of information not to mention different languages to accommodate. This is why the locale name first specifies the language (en - English) and then the geographic location (GB - Great Britain).

The full locale name would look like en_GB to match ISO639 and RFC1766.

To find the list of locales that your system has available you can run a simple Linux command.

locale -a

This will return a simple list of locale files; something like the following:

C
C.UTF-8
POSIX
en_AG
en_AG.utf8
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8

If the locale you need is not there then you will need to install it on your machine. In my case I wanted to use a Spanish locale (es_ES) and as you can see from the list above it is not currently available.

First check if your system can install the required locale by browsing through the supported locales with:

less /usr/share/i18n/SUPPORTED

Having spotted the locale you wish to install you can now compile it from the sources on your machine.

sudo locale-gen es_ES es_ES.utf8

Alternatively, if you’re on Ubuntu, you can install it from the package repository using apt-get.

sudo apt-get install language-pack-es

Where es at the end is the language you want to install.

You can now run locale -a again and you will see your new locale available in the returned list. A further test you can do before moving to PHP is to run the locale from the command line. Firstly though you need to take a note of you current locale:

echo "$LC_ALL"

Make sure you keep the local that is printed to hand as you’re going to want to switch back to it later.

To change the default locale to es_ES on the command line you would first set value of the LC_ALL environment variable.

export LC_ALL=es_ES

Now we can do a simple test by printing out the current month and ensuring it is using our desired locale.

date +B%

The month should have been printed out in the language of the current locale - in my case this is Spanish so it would be Julio.

Now that is tested we can switch back to your original locale using that same export method from before.

export LC_ALL=en_GB

In my case I am switching back to en_GB, but you will want to substitute that for the locale you noted down earlier - you did note it down didn’t you?

This is great - we’ve now got a working locale that we can use from PHP to localise our content. (You may need to restart the webserver if you’re using one).

My concern here is to change the locale for dates (LC_TIME), but you can find out the other constants by looking at the relevant PHP manual page. For the remainder of this article I will concentrate on the time.

The first thing we must do is set the locale against the time.

setlocale(LC_TIME, 'es_ES');

Now to actually print a date you will need to make use of the strftime() function which basically wraps the date command we were using from the command line earlier.

echo strftime('%B'); // junio

You should note that the defacto PHP date handling functionality does not respect the prevailing locale like strftime() does.

echo date('F'); // June

Also the same is true of PHP’s DateTime classes too.

$date = new DateTime();
echo $date->format('F'); // June

One way around this is to pass the date out as a timestamp from DateTime and then format it using the strftime() function:

$date = new DateTime();
echo strftime("%B", $date->getTimestamp()); // junio

This is fine, but it does mean that you’re going to miss out on the time zone power of the DateTime library and have to revert back to using date_default_timezone_set to set the current time zone instead. By doing this you will miss out on the time zone conversion trick I wrote about previously; Convert UTC to local time.

Additionally strftime() does not support dates before the UNIX epoch (January 1, 1970). If these caveats are not a concern the setlocale() can provide a helpful way of localising the output of your PHP code.

Finally, there is a big red warning on the PHP manual page for setlocale() that applies to those running multithreaded servers:

Warning The locale information is maintained per process, not per thread. If you are running PHP on a multithreaded server API like IIS, HHVM or Apache on Windows, you may experience sudden changes in locale settings while a script is running, though the script itself never called setlocale(). This happens due to other scripts running in different threads of the same process at the same time, changing the process-wide locale using setlocale().

Another way around this is to use the Intl extension for PHP with its IntlDateFormatter class, but that is another post!