PHP Internationalization and Localization
Managing Localization Resources
Problem
You need to keep track of your various message catalogs and images.
Solution
Store each message catalog as a serialized PHP array that maps message keys to locale-specific message values. Or, if you need interoperability with ICU-aware tools or other languages, use the ResourceBundle class.
Discussion
At its heart, a message catalog is just a mapping from keys to values. An English message catalog may map HELLO_WORLD to “Hello, World” but a Spanish one maps it to “Hola, Mundo.”
A simple way to manage these catalogs is to treat them as PHP arrays and then load them from files (and save them to files) as serialized arrays. Shows a short program that defines some message catalogs and saves them to files.
Example Saving message catalogs as serialized arrays
$messages = array();
$messages['en_US'] =
array('FAVORITE_FOODS' => 'My favorite food is {0}.',
'FRIES' => 'french fries',
'CANDY' => 'candy',
'CHIPS' => 'potato chips',
'EGGPLANT' => 'eggplant');
$messages['en_GB'] =
array('FAVORITE_FOODS' => 'My favourite food is {0}.',
'FRIES' => 'chips',
'CANDY' => 'sweets',
'CHIPS' => 'crisps',
'EGGPLANT' => 'aubergine');
foreach ($messages as $locale => $entries) {
file_put_contents(__DIR__ . "/$locale.ser", serialize($entries));
}
Example Using message catalogs from serialized arrays
/* This might come from user input or the browser */
define('LOCALE', 'en_US');
/* If you can't trust the locale, add some error checking
* in case the file doesn't exist or can't be
* unserialized. */
$messages = unserialize(file_get_contents(__DIR__ . '/' . LOCALE . '.ser'));
$candy = new MessageFormatter(LOCALE, $messages['CANDY']);
$favs = new MessageFormatter(LOCALE, $messages['FAVORITE_FOODS']);
print $favs->format(array($candy->format(array()))) . "\n";
Treating message catalogs as serialized PHP arrays is straightforward. However, it is a PHP-specific format. ICU defines a generic format, called a “resource bundle” for sharing data such as message catalogs between different programs and tools. If you’re working with localization tools or other programming languages that understand ICU resource bundles, use the ResourceBundle class to manage them.
Creating ICU resource bundles involves creating a text file in the proper format, and then running ICU’s genrb tool to produce the compiled “binary” version of the bundle. The following examples assume an ICU resource bundle with the following contents:
en_US {
FAVORITE_FOODS { "My favorite food is {0}." }
FRIES { french fries }
CANDY { candy }
CHIPS { potato chips }
EGGPLANT { eggplant }
}
This resource bundle is compiled by genrb to a file named en_US.res. The en_US, for the locale, is taken from the top-level table name in the file. The .res suffix is the default suffix genrb gives to all compiled resource bundles.
Example Using message catalogs from resource bundles
define('LOCALE', 'en_US');
$bundle = new ResourceBundle(LOCALE, __DIR__);
$candy = new MessageFormatter(LOCALE, $bundle->get('CANDY'));
$favs = new MessageFormatter(LOCALE, $bundle->get('FAVORITE_FOODS'));
print $favs->format(array($candy->format(array()))) . "\n";
In the two arguments to the ResourceBundle constructor indicate how to find the right compiled resource bundle. The second argument is the directory to look in for the file, and the first argument is the locale name, which is normally the basename of the file. Once the ResourceBundle has been instantiated, you access individual elements in the bundle with the get() method. The code to print out My favorite food is candy. is almost identical. The only difference is the syntax for retrieving the message strings from the resource bundle, rather then as array elements.
No comments:
Post a Comment