Localizing PHP Applications “The Right Way”, Part 1

Abdullah Abouzekry

New audiences around the world access the Internet every second, most of whom would be delighted to find your content in their mother tongue. You might think you only need a good translator to translate the user interface of your website, an easy task nowadays given how easy it is to find one, but the bigger challenge isn’t translating or writing multilingual content… it’s writing the code behind the scenes.

Localizing software applications in general used to be a cumbersome and error-prone task resulting in a lot of messy code. Some developers even use different versions of code for the same application but for different locales, which makes managing the codebase practically impossible. Enter gettext, the wonderful open-source tool that will make your life easier by allowing you to concentrate on your code. Localization becomes a matter of writing separate translation files for the target language, which can easily be done by a translator using Poedit. If you master gettext for PHP, you will find extending your application’s global reach really can be just a matter of translation!

In this series of articles you will learn how to gettext to localize your PHP application. Part 1 will provide just a quick foray into gettext. Each subsequent part will build on preceding parts, teaching you how to handle multiple translation domains, plural forms, and even how you can automate some of the localization process.

Preparing the Environment

I prefer to make sure my environment is set up properly before I start learning something new, since having everything up and running correctly makes it easier to test what I learn step-by-step. Here is a checklist of things you need to have installed before going any further:

  • PHP 5.x on Apache (or whichever web server you prefer), with the gettext extension enabled. You can always get the latest PHP for your platform at www.php.net.
  • Poedit, a cross-platform editor for gettext catalogs. It’s a really nice tool that lets you keep your translations separate from your application code. You can get a copy from www.poedit.net

Regardless of your platform, to use gettext from PHP you will need to have the gettext library installed and the PHP extension that hooks into the library.

Ubuntu/Debian users can use apt-get and Fedora/CentOS/Redhat users can use yum to install the gettext library. If you’re using another unix-like system, go to www.gnu.org/s/gettext and get a copy of gettext that is compatible with your platform. Windows users can download the latest executable and install it from gnuwin32.sourceforge.net/packages/gettext.htm.

After you install the library, you need to enable the PHP extension for gettext by editing php.ini and adding a single line:

# for Windows users
# for *nix users

Then, install Poedit which will be used later. You can download a copy from www.poedit.net.

Hello World with gettext

In your web root directory, create a sandbox directory for playing with gettext named TestI18N (I18N stands for Internationalization). Within the TestI18N directory, create the following hierarchy:

directory structure

In future projects, you can really name the parent directory and the Locale directory any name you want, but en_US and LC_MESSAGES are standard names which are used by gettext. en_US stands for the name of the locale and is made up of two parts. The first part is a two-letter lowercase abbreviation for the language according to the ISO 639-1 specification. The second part after the underscore is a two-letter uppercase country code according to the ISO 3166-1 alpha-2 specification. en_US thus means the language is English as spoken in the United States.

Next, make sure Poedit is working correctly on your platform. Launch the program and choose from the top menu bar File > New Catalog. In the settings window, fill in the information below skipping the plural forms field for now:

poedit settings window

Click OK and then save the file as messages.po inside the LC_MESSAGES directory you created earlier.

Now close Poedit, and use your favorite text editor to open messages.po… yes, it is an ordinary text file! you can edit it by hand, but to save ourselves some hassle we let Poedit create the main definitions for us. Leave an empty line after the lines that are already in the file and add the following:

#Test token 1
msgstr "Hello World!"

#Test token 2
msgstr "Testing translation..."

Save messages.po and close it, and then re-open it in Poedit.

In Poedit, choose File > Save or click the Save Catalog entry in the icon bar. The reason we are saving the PO file in Poedit is because they need to be compiled into a special format usable by gettext. After you save it in Poedit, you will see a new file has been created in the same directory with the same name but with the extension .mo. If you were to continue to modify and save the PO file with a regular text editor, you would need to compile it using the pocompile command. The extra compilation step isn’t necessary if you use Poedit because it automatically compiles the file anytime you save it.

Back in the TestI18N directory, create a file named test-locale.php with the following code:

// I18N support information here
$language = "en_US";
putenv("LANG=" . $language); 
setlocale(LC_ALL, $language);

// Set the text domain as "messages"
$domain = "messages";
bindtextdomain($domain, "Locale"); 
bind_textdomain_codeset($domain, 'UTF-8');


echo _("HELLO_WORLD");

Open TestI18N/test-locale.php in your browser. If everything is installed correctly and working fine, you will see Hello World displayed on the page.


When it comes to localizing your PHP application, you may have a lot of options at your disposal. We chose to use the GNU gettext library and its PHP extension, a powerful and easy approach that localizes the application “The right way!” In this installment you saw what’s needed to install gettext and the PHP extension, briefly used Poedit, and whetted your appetite with a simple Hello World script. Part 2 will use this as a basis for learning more about gettext; I’ll explain each function introduced in the Hello World script as well as how the gettext library works.

Image via sgame / Shutterstock