
Zur deutschen Version wechseln…
The i18n package is a punch of classes for internationalization. It gives you the possibility to maintain multilanguage webpages more easily. The translation strings are stored in flat text files, special Gettext files which are basically precompiled translation files or in a MySQL database. And it works independently from PHP’s setlocale function.
First, to avoid problems, make sure that for all pages that use the package you start and end your scripts with:
ob_start();
				session_start();
and
ob_end_flush();
Let’s start with one of the base classes, the language class. It’s propose is to determinate the preferred locale of the user, by looking at the HTTP_ACCEPT_LANGUAGE header an the users IP address.
First create a new object:
include('class.Language.inc.php');
				$lg = new Language();
Let’s say the user has set his browser to “German – Austria” (de-at). Now get your information with those methods:
$lg->getLocale() outputs de_at (the hyphen is
				replaced with	an underscore)
				$lg->getLang() outputs de
				$lg->getCountry() outputs at
Of course some users have set more than one locale. To get those informations use:
$lg->getUserRawArray() to get an array with all locales accepted
				by the	user
				$lg->getUserLangArray() for all Languages
				$lg->getUserCountryArray() for all countries
But what if the user has set no specific country code or no locale information could be found at all? That’s where the default values kick in. Stuff like this is saved in the i18n_settings.ini file:
[Language]
				default_locale = "en"
				default_language = "en"
				default_country = "us"
To retrieve those settings in your script use
 $lg->getDefaultLocale()
				$lg->getDefaultLanguage()
				$lg->getDefaultCountry()
But there are much more settings for the package you can change in the i18n_settings.ini file:
You can also force a specific locale to overrule all other locale sources when you create a language object:
$lg_gb = new Language('en_gb');
Now that was the language class. Now we want to use the information from it for translations. For this use the Translation class which extends the language class.
include('class.Translator.inc.php');
				$translation = new Translator('','frontpage, everypage');
Now this class takes two arguments. The first on is the same like in the language
				class to overrule the locale settings and force a specific locale. The second
				argument is needed if you work with flat translation files or	Gettext files.
				The second argument is a comma-separated list of one ore more
				filenames without the extension (you set this in the i18n_settings.ini file).
				This files have to be placed in the language subdirectory under	the “locale” directory
				if you use flat text files or in the “LC_MESSAGES“ subdirectory
				of the language subdirectory if you work with Gettext files.
				The language directory itself has to be named properly like a
				locale or language according to the ISO standard. (examples: “it”, “de_at”, “en_gb”,…).
				If you use MySQL then the second argument is the namespace column
				in the translation table. Whenever you create a new translation object it
				preselects all translations with that namespace into an array to prevent
				firing a SELECT	statement at the database for every translation.
				You can also create some alias languages. If you have a folder “en” with
				all your translations and you want to add a new folder “en_gb” which
				uses the same translations, just place a file called “redirect” (without
				an extension) there which contains the actual language where the translations
				can be found (in this case “en”). Remember, alias languages don't
				work in MySQL modus!
There are already a couple of example files in the package, so take a look at them to see how your translation files have to look like. If you want to use Gettext files, search the web for tutorials on how to create them. I’m not going into this here…
When creating a new translator object the list of preferred user locales from
				the language class and available translations in the locale folder are compared
				and the most likely translation is chosen. Also the getLocale(), getLang() and getCountry() methods
				are not returning the preferred user values anymore, but those of the most
				likely translation available.
Now that you have created a MySQL table or translation file (and placed it
				in the correct directory) you can start translating in your scripts using
				the translate() method.
echo $translation->translate('no_records_found');
“no_records_found” is the translation string to look for in the MySQL table or translation file. If you not only want to translate the string, but also html encode it at the same time use:
echo $translation->translateEncode('no_records_found');
To encode even more special characters, like “×”, “„”, “‡”… you can use the translateEncodePlus method:
echo $translation->translateEncodePlus('no_records_found');
There are also some shortcuts so you don’t have to write the long method name all the time:
echo $translation->_('no_records_found'); = translate
				echo $translation->__('no_records_found'); =	translateEncode
echo $translation->___('no_records_found'); =	translateEncodePlus
If no translation string was found you will see an error message in your script:
ERROR TRANSLATING: »» no_records_foun ««
You can turn off error reporting in the i18n_settings.ini file. In this case only the untranslated string will be returned.
If you use Gettext files, using the translate methods can be a bit more complicated if you use more that one translation file in one script. you have to pass the name of the translation file as a second value if the string is not located in the first language file from the file list you have used when creating the object:
echo $translation->translate('another_string', 'translationfile2');
				echo $translation->translateEncode('another_string', 'translationfile2');
				echo $translation->_('another_string', 'translationfile2');
				echo $translation->__('another_string', 'translationfile2');
You can also change the language of the translator object during use if you like:
$translation2 = new Translator('de','frontpage, everypage');
				echo $translation2->_('good_morning');
				$translation2->changeLocale('en');
				echo $translation2->_('good_morning');
first it would output Guten Morgen, the second time Good Morning.
Other methods in this class:
$translation->getLanguageFilesArray() returns an array with
				all available	valid languages found under the “locale” folder.
				$translation->getModus() returns “gettext”, “inc” or “mysql” (whatever
				you use)
				$translation->getRealLocale() returns the real locale if
				the chosen one	is just an alias.
Now we know how to make our scripts multilingual, but how can the user choose
				a different language?
				For this you need the ChooseLanguage class which extends the
				Translator class by a couple of methods:
include('class.ChooseLanguage.inc.php');
				$translation3 = new ChooseLanguage('','frontpage, everypage');
				echo	$translation3->returnDropdownLang();
This outputs a <select> form element with all available
				languages. You have to add the other form elements in the scripts yourself.
				Just make sure that the form URL is points to a script which calls the ChooseLanguage
				class	again. If you don’t want to use a dropdown menu you can make
				the form	elements yourself. Just be sure that they are named “locale” and
				have the locale as the value. Example:
<input type="hidden" name="locale" value="en">
Other functions in the ChooseLanguage class:
$translation3->countStrings(); returns the number of strings
				found in the	selected translations files or MySQL table
				$translation3->countLanguages(); returns the number of languages
				available
Based on these language and translation classes there are a couple of other classes to format numbers, dates, values… depending on the chosen locale:
include('class.FormatDate.inc.php');
				$fd = new FormatDate();
				$timestamp = $fd->ISOdatetimeToUnixtimestamp('2003-12-24 13:45:00');
				echo $fd->longDateTime($timestamp);
This would format the date '2003-12-24 13:45:00'. If you have chosen the locale “de” it would output:
Mittwoch, 24. Dezember 2003 – 13.45 Uhr
if the locale is “it” it would output
Mercoledì, 24 dicembre 2003 – 13.45
The methods shortDate(), shortTime(), shortDateTime(), middleDate(), middleTime(), middleDateTime(), longDate(), longTime(), longDateTime() all
	take a timestamp as a value and output the according	strings.
To give the user more options on how dates/times should be displayed you can
				use the ChooseFormatDate class to output a dropdown <select> box
				just like the ChooseLanguage class does to give the user the possibility
to select	normal date format, ISO date format or swatch date format.
Numbers are also written differently depending on the language. In German the English written number 123456.789 would be written as 123 456,789
include('class.FormatNumber.inc.php');
				$fn = new FormatNumber();
				echo $fn->number(123456.789, 2);
This method formats a number. The second argument is the number of digits
				that should	be displayed. The percent() methods works the same
				way.
				When formatting currencies you have more arguments to pass to
				the method:
$fn->currency(99.90, 'full', 'gb', FALSE);
This would output 99,90 Pfund in German
				and 99.90 Pound in English. The first argument is the number,
				the second tell how	the currency	should be marked: full means
				that the full currency	name is	displayed (in this example “Pound”), short would
				output the short currency name (here “GBP”) and symbol would
				output the currency symbol (here “£”).
				The thirds argument is the country of the currency (here “Great Britain”)
				and the last argument tells whether the major currency should be forced to
				display or not. Example:
$fn->currency(0.99, 'full', 'de', FALSE); outputs 99
								Cent
				$fn->currency(0.99, 'full', 'de', TRUE); outputs 0.99
				Euro
Settings for this class can be changed in thel10n.ini file.
This class contains only the US measure system and the metric system.
include('class.FormatMeasure.inc.php');
				$fn = new FormatMeasure ('si','uscs');
This created a new object where the input values are in the metric system and the output values are US measure system. If no second argument for the output is given, the class chooses it by looking at the locale set by the translator class.
There available Methods are linear(), surface(), capacity(), cooking(), liquid() and temperature().
				Most of them in this class take three arguments. The first one is the number,
				the second and third are the input and output	format. For	example for the linear() method
				these formats would	be:
0: mm|in,
				1: cm|ft,
				2: dm|yd,
				3: m|fur,
				4: km|mi,
Please see the class documentation for all the formats for the different methods. Settings for this class can be changed in thel10n.ini file.
Two language based methods are available.	The wordFilter() method
				replaces “bad” words, like curses for example, with “*” signs.
				A commaseperated list can be defined in the l10n.ini file.
The method filterSpecialWords() searches for special words in
				a string and formats them with the HTML tags abbr, acronym or dfn.
				The words and related description strings can be changed in the words.ini file,
				which is placed in every language subdirectory.
With the shared memory functions enabled, ini files are only read
				once on first access an are written to the servers memory. This way the files
				don’t have to be read with every page access. By default this is disabled.
				To enable it, you have to set the $use_shared_mem variable in
				the I18N class to TRUE.
				Once in the shared memory, changes	to one of the ini file won’t have
				any effect until you reset the shared memory blocks. You can do this by setting
				the $flush_sm variable	to TRUE (also in the I18N class).
If you would like to use another database instead of MySQL you have to rewrite
				the code manually. I don’t plan to use some sort of DB abstract layer
				to	keep the classes independent from any framework.
				I also haven’t worked with PEAR yet,
				so I don’t know how hard it would be to implement they DB class. But
				you could try and	let me know :-)
All the database code can be found in the Translator and ChooseLanguage class.
				The connection is	created in the setConnection() method. SQL
				Queries	are made in the methods checkLocale(), languagesFilesList(), readLanguageFile(), translate(), getLastUpdateDate() and countStrings().
If you use some sort of caching mechanism then you can use the getLastUpdateDate() method
				from the Translator class (available since version 1.54). It returns the
				most current modification date of the selected translation files. If you
				use MySQL then it returns the most current modification date of all the strings
				of the selected namespaces. You can compare the returned UNIX timestamp with
				the dates of your cached	files	to	see if	they need to be updated.
The classes haven’t been tested with smarty yet, but if you do it this way smarty should cache each language version separately.
php file:
$smarty->assign('LANG_fist_name', $translator->__('first_name'));
				$smarty->assign('LANG_last_name', $translator->__('last_name'));
…
				$smarty->display('template_filename.tpl', $translator->getLocale());
template_filename.tpl:
<html><body><p>{$LANG_first_name} {$LANG_last_name}</p></body></html>
 Author: Flaimo
				Date: 2003-06-13
				URLs:
				Project homepage
				Example script