As I have said before, gettext is a very interesting framework for i18n and i10n.

Now the question is, how do I apply this to web applications? Actually, I'm going to restrict my discussion here to PHP since this is what I'm working with right now... but you should expect similar behaviour when using other web development tools that integrate gettext.

First of all, the good news: PHP fully supports gettext since version 3.0.7. So it's been used for a long time and you can even find tutorials on the net.

PHP/Gettext in action

Let me sum it up with a little code snippet:

// Specify location of translation tables :
bindtextdomain( 'messages', dirname(__FILE__).'/../locales');
// Choose domain: (name of the .mo files)
textdomain( 'messages' );

echo 'Using default settings...';
echo '<br />"Users": <strong>', _('Users'), '</strong>';

echo '<hr />Activate: ', $locale, '';
putenv( 'LC_ALL='.$locale );

echo '<br />"Users": <strong>', _('Users'), '</strong>';

echo '<hr />Sleep...';
sleep( 5 );

echo '<hr />"Users": <strong>', _('Users'), '</strong>';

What this will do is:

  1. Display the default translation for the word "Users" in the current locale.
  2. Activate the requested locale, and display the new translation of "Users"
  3. Wait for 5 seconds and display the translation again. (Maybe you already feel the beast comming... ;) )

And so it goes... look at the screenshot above: the default locale is French/France but the translations are nicely displayed in English, Dutch, Sweedish and... French.

So far, so good... you can spend weeks contemplating the magic of gettext... But beware of the day you'll move this to production!

Actually, all you need to do is test this a little more in depth. This is why I have included the 5 seconds sleep! :> This is what happens when you take advantage of this 5 second delay to refresh all 4 windows in a row without waiting for the first one to update before you refresh all the others:

PHP/Gettext killed in action

Take a close look. It's completely messed up! >:-(

Why this? Because when PHP is running as an Apache module, each page gets handled by a separated thread of the same process. And the problem is, you set the language by writing a variable to the environment (puttenv()). That's how gettext works. Unfortunately, changing the environment affects the whole process... thus all running (sleeping indeed ;) ) threads for that process!

There is no way around that in gettext. The only thing you can do is run PHP with CGI instead of as a module. With CGI, each request spawns its own process... making the environment safe... but at the cost of poor performance... :no:

The real problem here is that gettext has been designed to localize programs and to run them in a single language environment. Web applications are, by essence, destined to be used in a multilingual mode, where every concurrent user might use a different language. Sadly enough, this is beyond the scope of gettext! XX(

The real question is: what were the guys who implemented gettext into PHP thinking? :?: Oh yeah... probably CGI... Then mention it in the manual! Damn it! >:XX

Personnaly I consider gettext support in PHP only as a demo tool for localized .PO/.MO files and I definitely need to write a thread safe implementation... I'm working on it... and while I'm at it, I'll add real multingual support! :yes:

PS: Tests done with plain vanilla Apache/1.3.28 (Win32) PHP/4.3.2


Comments from long ago:

Comment from: dAniel

I use the following code for gettext initialisation (i12n :)):

function init_gettext($language){ putenv(‘LANGUAGE=’.$language); putenv(‘LANG=’.$language); // Specify location of translation tables bindtextdomain (“messages”, “./locale”); // Choose domain textdomain (“messages”);

if ($language==‘de’) $loc = setlocale (LC_ALL, ‘de_DE@euro’, ‘de_DE’, ‘de’, ‘ge’); else $loc=setlocale(LC_ALL, ’en’,’en_US’); }

and could not recognize your above mentioned problem.

This was my testcode and it always resulted in the correct displaying:

echo ‘using ‘.$site->lang; echo _(‘welcome on thequod.de’); sleep(5); if ($site->lang==‘de’) $site->lang=‘en’; else $site->lang=‘de’; init_gettext($site->lang); echo ‘using ‘.$site->lang; echo _(‘welcome on thequod.de’);

The tricky thing about init_gettext() is, that my remote server needs the setlocale() command, where my local server does not.

2003-09-29 17-40

Comment from: François PLANQUE

You probably use PHP through CGI and not through and Apache module.

Gettext works fine if you use CGI. It does not if you use mod_php.

2003-09-29 18-25

Comment from: dAniel

No, I use it as a module. LoadModule php4_module c:/www/php/sapi/php4apache.dll

But there is no clue about mod_php in phpinfo(), where my server says ‘mod_php’.

See http://blueye.kicks-ass.net/iphp.php (local) and http://thequod.de/iphp.php (remote).

2003-09-29 19-04

Comment from: abbi

i love u

2003-12-15 18-53

Comment from: guest

From the PHP manual:

“Adds setting to the server environment. The environment variable will only exist for the duration of the current request. At the end of the request the environment is restored to its original state.”

2004-06-10 15-03

Comment from: dAniel hAhler

Without having looked at the gettext implementation in PHP recently, I’d say it really cannot be as bad as you’ve outlined (in 2003).

2006-03-09 02-24

Comment from: François Planque

Yeah right! Everyone has upgraded Windows XP/2003 Server, Apache 1.3 and PHP 4 since 2003. It’s a known fact that these versions are no longer in use, except by a tight minority…

(95% is a minority, isn’t it?)

2006-03-15 21-35