20

i am trying to use the php gettext extension in php 5.5 (on win2008 server, using IIS7). I am doing this:

<?php

$locale = "es";
if (isSet($_GET["locale"])) $locale = $_GET["locale"];
putenv("LC_ALL=$locale");
setlocale(LC_ALL, $locale);
bindtextdomain("messages", "./locale");
textdomain("messages");

echo gettext("Hello world");

?>

With this folder structure in place:

locale/es/LC_MESSAGES/messages.mo

But it always just returns Hello world and not the correct translation which for now (based on my lack of spanish skills) is this in the messages.po file:

msgid ""
msgstr ""
"Project-Id-Version: TestXlations\n"
"POT-Creation-Date: 2014-04-19 08:15-0500\n"
"PO-Revision-Date: 2014-04-19 09:18-0500\n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.3\n"
"X-Poedit-Basepath: .\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-SearchPath-0: c:/dev\n"

msgid "Hello world"
msgstr "Hola World"

This fails from the cmd line and via IIS. So i it's seeing the gettext call, etc and executing it but it's not reading the translation file. how can i debug this further? even if remove the translation file, i get the same behavior.

glutz
  • 1,889
  • 7
  • 29
  • 44
  • 1
    Anyone? this is a real mess. i have seen no evidence that this is configured correctly or not online. the doc is basically terrible. does this actually work for anyone? – glutz Apr 19 '14 at 14:28
  • You need to declare the charset you are using in your MO file with `bind_textdomain_codeset()`, and you need to make sure that the locale you've generated uses the same charset as your MO file. Have a look at this article for more information: https://blog.terresquall.com/2020/09/troubleshooting-php-gettext/ – John Doe Sep 06 '20 at 16:05

7 Answers7

18

You should check returned values and know which function failed. It is not i18n specific but useful for any PHP scripts, or any programming language debugging.

<?php
$locale = 'es';
if (isset($_GET["locale"])) $locale = $_GET["locale"];

$domain = 'messages';

$results = putenv("LC_ALL=$locale");
if (!$results) {
    exit ('putenv failed');
}

// http://msdn.microsoft.com/en-us/library/39cwe7zf%28v=vs.100%29.aspx
$results = setlocale(LC_ALL, $locale, 'spanish');
if (!$results) {
    exit ('setlocale failed: locale function is not available on this platform, or the given local does not exist in this environment');
}

$results = bindtextdomain($domain, "./locales");
echo 'new text domain is set: ' . $results. "\n";

$results = textdomain($domain);
echo 'current message domain is set: ' . $results. "\n";

$results = gettext("Hello world");
if ($results === "Hello world") {
    echo "Original English was returned. Something wrong\n";
}
echo $results . "\n";
Blackbam
  • 17,496
  • 26
  • 97
  • 150
akky
  • 2,818
  • 21
  • 31
  • 5
    right. it all looks fine except the gettext call. Something wrong, indeed. – glutz Apr 22 '14 at 13:16
  • 4
    Same here. Really frustrating. Did you find out what your problem was? – philippe_b May 18 '15 at 14:20
  • @philippe_b I've just spent a good day on wondering why on earth this wasn't working - finally realised stupidly why. I was setting the `LC_ALL` to `fr_FR` (All ok, no error) however upon completion I was referring the user back to the original page; at that point - it had already lost the original `setlocale` as by that point - it's a new process and needed to be reset at the top of every page (or includes) with the choice retained in the session. I stupidly thought setting `setlocale` in itself would be a session! – MackieeE Mar 15 '16 at 00:29
  • 1
    Thanks for pinging me :) This is not the issue I had. I fixed it, but a few days after I posted here so I forgot to contribute. But I backup @jr997's answer below: the locale must be known by the OS, which is not obvious at all. – philippe_b Mar 15 '16 at 09:16
16

Do you find "es" in the output of 'locale -a' ? If not then you need to run the following command.

 sudo locale-gen es
shailesh gupta
  • 427
  • 1
  • 5
  • 14
  • 2
    I recently moved hosts, and my gettext stopped working. Checked locale -a and saw the locale was missing, added it and it started working again! – Klazen108 Feb 12 '16 at 03:42
  • 1
    Thanks for this - running locale-gen is now part of my server build scripts. – drchuck Jan 03 '18 at 15:27
11

Having the same problem on Linux, I came to this conclusion: even if you provide your own *.mo files for your project, the locale itself (es) must be known to the operating system.

Installing the requested locale at a system level fixed the problem for me.

See: locale-gen

It might not help with actually debugging gettext, but at least it's something you can try.

Blackbam
  • 17,496
  • 26
  • 97
  • 150
jr997
  • 457
  • 5
  • 5
  • 1
    When answering a question, try to be as concise, precise, and objective as possible. State this `if you provide your own *.mo files for your project, the locale itself (es) must be known to the operating system.`, then add a source, such as a link to a documentation backing this up..... `Installing the requested locale at a system level could fix the issue.` etc... refrain from stating comments/opinions on answers – Bonatti Dec 01 '15 at 16:45
6

As per not knowing which language pack to use on the OS, thankfully the setlocale() function allows for an array. As per the PHP Docs:

"If locale is an array or followed by additional parameters then each array element or parameter is tried to be set as new locale until success. This is useful if a locale is known under different names on different systems or for providing a fallback for a possibly not available locale"

With this, you can dig to find out locale the OS is falling back to by checking the set after:

$locales = array( "fr_FR", "fr_FR.UTF-8", "fr_FR.utf8", "fr-FR" );

if (( $setTo = setlocale( LC_ALL, $locales )) === FALSE )
{
    echo "Unable to set a locale that the OS recognises.";
    return false;
}
else
{
    echo "Set LC_ALL to " . $setTo; //echos fr_FR.utf8
    return true;
}

$setTo will be provided with the $locales value that was successful. This might be helpful when finding which locale to write a .po for.

As per written in my comments, I had the issue where I was not performing this setlocale() at the top of each script of every page request, as you'll need to retain the user's choice of language by session or database value. As I believed naively once it was set, it was set forever!

pkaeding
  • 36,513
  • 30
  • 103
  • 141
MackieeE
  • 11,751
  • 4
  • 39
  • 56
4

I know this question is old, but for anyone coming from Google I wanted to share my own experience.

I too had that issue after upgrading Debian from Stretch to Buster, and I've spent an embarrassing long time trying to debug this. I'm not exactly sure why, but in my case I managed to fix the issue simply by adding the following line in my code,

putenv('LANGUAGE=');

To my surprise, using gettext inside a PHP script when ran from the command line actually worked as expected, in contrast to when it was ran by Apache. After running the command locales from the terminal, I noticed that the LANGUAGE environment variable was in fact set to an empty string. While when ran by Apache it was set to en_US:en for whatever reason, as I discovered by using the getenv function.

I have no idea why setting the LANGUAGE environment variable to an empty string actually fixed the issue for me but it did. Hopefully someone will find this useful.

Manolis Agkopian
  • 1,033
  • 13
  • 22
1

It's a bit old question but here goes this answer in the hope of being useful for someone.

Try changing LC_ALL to LANG in the putenv function, from this:

$results = putenv("LC_ALL=$locale");

to this:

$results = putenv("LANG=$locale");

In the mac it was given problems with LC_ALL and probably it the same here .

Also check this answer in other cases https://stackoverflow.com/a/3535866/6628843

Hope it helps!

Community
  • 1
  • 1
user38561
  • 93
  • 2
  • 8
0

Try to set also env vars LC_LANG and LC_LANGUAGE not only the LC_ALL:

putenv("LC_ALL=$locale");
putenv("LC_LANG=$locale");
putenv("LC_LANGUAGE=$locale");