Infiniroot Blog: We sometimes write, too.

Of course we cannot always share details about our work with customers, but nevertheless it is nice to show our technical achievements and share some of our implemented solutions.

PHP: Translations with gettext not working in Apache mod_php but works on command line (caused by mod_perl)

Published on November 17th 2020


A very strange problem occurred recently on a Debian 10 (Buster, current stable release): PHP translations using gettext did not work. And to our big surprise this wasn't caused by a wrong usage of gettext or wrong translations files (po and mo), but rather by the Apache module mod_perl. But let's get into the details.

A simple PHP translation using gettext

Note: This article will not explain how po and mo files work in combination with gettext. For a good introduction visit this tutorial.

The following file translate.php was created with the following content:

$ cat translate.php
<?php
// Set locale
putenv("LC_ALL=de_CH.UTF-8");
setlocale(LC_ALL, 'de_CH.UTF-8');

// Select translation file
bindtextdomain("homepage", "./locale");
textdomain("homepage");

$results = gettext("Dedicated Hosting Description");
if ($results === "Dedicated Hosting Description") {
    echo "Original English was returned. Something wrong\n";
} else {
    echo $results;
}

?>

A few explanations concerning this code:

gettext translation doesn't seem to work

But as soon as translate.php was opened in a browser, the text was not translated:

At this point we assumed a problem in the PHP code. Multiple changes to the code were applied, including:

But nothing worked. We already prepared the text to ask a question on Stackoverflow (and be ready to get insulted) when the PHP script was also launched with the PHP command line (CLI).

Actually gettext translation works, but only on the CLI

To our big surprise, the German translation was returned, when the PHP script was called with the php7.3 cli:

$ php7.3 translate.php
Das ist der deutsche Text.

Wow. So the translation actually works; gettext is working just fine! To compare this again with a browser output, curl was used:

$ curl localhost/translate.php
Original English was returned. Something wrong

And again the translation doesn't work.

Fact now: The PHP translation works fine but as soon as the PHP script is opened via Apache (using mod_php), the translations don't work.

mod_perl is to blame

On the research why this happens, one hint was found on a question on Stackoverflow: Gettext not working through php-cli, but works in php-apache. The title itself was already intriguing enough although the problem description is the exact opposite of what we were running into.

Although not really relevant to the OP's question, one suggested answer was:

I just found a solution to the opposite problem: Gettext not working through php-apache, but working in php-cli. [...] Strangely, I just disabled the perl module in Apache and the problem disappeared.

Wait. What?! Why would mod_perl be interfering in a PHP code? We indeed had mod_perl enabled on this web server (for one particular Perl based web-application) so we decided to temporarily disable mod_perl - just for the sake of testing all possible workarounds.

# a2dismod perl
# systemctl restart apache2

And then, all of a sudden, the German translation was showing up in the curl response:

$ curl localhost/translate.php
Das ist der deutsche Text.

Is it really mod_perl or did a simple Apache restart fix something? Let's enable mod_perl and test again:

# a2enmod perl
# systemctl restart apache2

$ curl localhost/translate.php
Original English was returned. Something wrong

The problem is indeed caused by mod_perl. Mind. Blown.

Following up on (existing?) bugs

Now that we knew that mod_perl is causing this weird problem, there are two possible ways to solve this on this particular Apache web server:

  • Disable mod_perl for good
  • Switch from mod_php to PHP-FPM; as the root problem seems to be a locale issue within Apache (triggered by mod_perl), this problem should not happen if PHP is loaded outside of Apache, namely as a PHP-FPM daemon

More interestingly (for the geeks like us) is to find more information on this problem. The closest report to this bug can be found in Mageia Linux's Bugzilla: Bug 25411 Installing apache-mod_perl implies that setlocale has no effect in PHP. In fact, this does sound like the exact same behavior/bug. As Mageia is, according to Distrowatch, an independant Linux distribution and therefore not based on Debian, it does indicate that this is an upstream bug of the Apache mod_perl project.

To make sure this is handled in Debian and that Debian maintainers inform upstream, a new Debian bug report was created against the libapache2-mod-perl2 package: Bug #974922 mod_perl interferes with mod_php locales, unable to use gettext translations.

To complete the picture here, this issue happens on these versions and can be reproduced:

$ dpkg -l| egrep "(libapache2-mod-perl|libapache2-mod-php7.3|apache2-bin)" | awk '{print $2" "$3}'
apache2-bin 2.4.38-3+deb10u3
libapache2-mod-perl2 2.0.10-3
libapache2-mod-php7.3 7.3.19-1~deb10u1