PHP DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Internationalization and Localization with PHP
Pages: 1, 2

Message Objects



These phrases can also be stored as function return values instead of strings in an array. Storing the phrases as functions removes the need to use printf(). Functions that return a sentence look like this:

<?php
// English version
function i_am_X_years_old($age){
    return "I am $age years old.";
}

// Spanish version
function i am_X_years_old($age){
    return "Tengo $age años.";
}
?>

If some parts of the message catalog belong in an array, and some parts belong in functions, an object is a helpful container for a language's message catalog. A base object and two simple message catalogs look like this:

<?php
class pc_MC_Base {
    var $messages;
    var $lang;

    function msg($s) {
        if (isset($this->messages[$s])) {
            return $this->messages[$s];
        } else {
            error_log("l10n error:LANG:" . 
                "$this->lang,message:'$s'");
                }
        }
}

class pc_MC_es_US extends pc_MC_Base {
    function pc_MC_es_US() {
        $this->lang ='es_US';
        $this->messages = array(
            'chicken' => 'pollo',
            'cow' => 'vaca',
            'horse' => 'caballo'
        );
    }

    function i_am_X_years_old($age){
        return "Tengo $age años";
    }
}

class pc_MC_en_US extends pc_MC_Base {
    function pc_MC_en_US() {
        $this->lang ='en_US';
        $this->messages = array(
            'chicken' => 'chicken',
            'cow' => 'cow',
            'horse' => 'horse'
        );
    }

    function i_am_X_years_old($age) {
        return "I am $age years old.";
    }
}
?>

Each message catalog object extends the pc_MC_Base class to get the msg() method, and then defines its own messages (in its constructor) and its own functions that return phrases. Here's how to print text in Spanish:

<?php
$MC = new pc_MC_es_US;
print $MC->msg('cow');
print $MC->i_am_X_years_old(15);
?>

To print the same text in English, $MC just needs to be instantiated as a pc_MC_en_US object instead of a pc_MC_es_US object. The rest of the code remains unchanged.

Localizing Images

Images need to be localized when you want to display images containing text in locale-appropriate languages.

Make an image directory for each locale you want to support, as well as a global image directory for images that have no locale-specific information. Create copies of each locale-specific image in the appropriate directories. Make sure that these images have the same filenames. Instead of printing image URLs directly, use a wrapper method similar to the msg() method demonstrated earlier.

The img() wrapper method looks for a locale-specific version of an image first, then a global one. If neither are present, it logs an error message. Building upon the pc_MC_Base class, the new class looks like this:

<?php
class pc_MC_Base {
    var $messages;
    var $images;
    var $lang;

    var $image_base_path = '/usr/local/www/images';
    var $image_base_url = '/images';

    function msg($s) {
        if (isset($this->messages[$s])) {
            return $this->messages[$s];
        } else {
            error_log("l10n error:LANG:" . 
                "$this->lang,message:'$s'");
        }
    }

    function img($f) {
        if (is_readable("$this->image_base_path/" . 
            "$this->lang/$f")) {
            print "$this->image_base_url/$this->lang/$f";
        } elseif (is_readable("$this->image_base_path/" .
            "global/$f")) {
            print "$this->image_base_url/global/$f";
        } else {
            error_log("l10n error:LANG:" .
                      "$this->lang,image:'$f'");
        }
    }
}
?>

The img() method needs to know both the path to the image file in the filesystem ($image_base_path) and the path to the image from the base URL of your site ($image_base_url). It uses the first to test if the file can be read and the second to construct an appropriate URL for the image.

A localized image must have the same filename in each localization directory. For example, an image that says "New!" on a yellow starburst should be called new.gif in both the images/en_US directory and the images/es_US directory, even though the file images/es_US/new.gif is a picture of a yellow starburst with the word "¡Nuevo!" on it. Don't forget that the alt text you display in your image tags also needs to be localized. A complete localized <img> tag looks like this:

<?php
$MC = new pc_MC_es_US;

printf('<img src="%s" alt="%s">',
    $MC->img('cancel.png'), $MC->msg('Cancel'));
?>

If the localized versions of a particular image have varied dimensions, store image height and width in the message catalog as well:

<?php
printf('<img src="%s" alt="%s" ' .
    'height="%d" width="%d">',
    $MC->img('cancel.png'), $MC->msg('Cancel'),
        $MC->msg('img-cancel-height'), 
        $MC->msg('img-cancel-width'));
?>

The localized messages for img-cancel-height and img-cancel-width are not text strings, but integers that describe the dimensions of the cancel.png image in each locale.

If you use a consistent naming convention for your variable and file names, create an imgsrc() method to simplify matters:

<?php
function imgsrc($img) {
    $src = $this->img("$img.png");
    $alt = $this->msg(ucfirst($img));
    $height = $this->msg("img-$src-height");
    $width = $this->msg("img-$src-width");
    return sprintf('<img src="%s" alt="%s" ' .
                   'height="%d" width="%d">', 
                   $src, $alt, $height, $width);
}
?>

To get the same results as the Cancel button example before, call it like this:

<?php
$MC = new pc_MC_es_US;

print $MC->imgsrc('cancel');
?>

Conclusion

With help of the msg() and img() methods, you can quickly create message objects that allow you to localize your Web site using 100 percent pure PHP. Because it's an all-PHP solution, you can reuse all your existing code, and you don't need to install any new extensions. However, if you need to share message catalogs among many applications, PHP supports gettext. See Joao Prado Maia's article for more details on using gettext with PHP.

As you can see, internationalizing your PHP applications is not a labor of Hercules. When you organize your localizations within an object hierarchy, it's easy to extend your classes to support new countries and regions without difficulties.

Adam Trachtenberg is the manager of technical evangelism for eBay and is the author of two O'Reilly books, "Upgrading to PHP 5" and "PHP Cookbook." In February he will be speaking at Web Services Edge 2005 on "Developing E-Commerce Applications with Web Services" and at the O'Reilly booth at LinuxWorld on "Writing eBay Web Services Applications with PHP 5."


Return to the PHP DevCenter.


Valuable Online Certification Training

Online Certification for Your Career
Earn a Certificate for Professional Development from the University of Illinois Office of Continuing Education upon completion of each online certificate program.

PHP/SQL Programming Certificate — The PHP/SQL Programming Certificate series is comprised of four courses covering beginning to advanced PHP programming, beginning to advanced database programming using the SQL language, database theory, and integrated Web 2.0 programming using PHP and SQL on the Unix/Linux mySQL platform.

Enroll today!


Sponsored by: