How to debug gettext not working in PHP?
Asked Answered
X

7

21

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.

Xanthic answered 19/4, 2014 at 13:45 Comment(2)
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?Xanthic
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: blog.terresquall.com/2020/09/troubleshooting-php-gettextSoubrette
C
19

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";
Cammiecammy answered 20/4, 2014 at 2:24 Comment(4)
right. it all looks fine except the gettext call. Something wrong, indeed.Xanthic
Same here. Really frustrating. Did you find out what your problem was?Outride
@Outride 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!Gorilla
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.Outride
P
17

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

 sudo locale-gen es
Phyletic answered 22/7, 2014 at 17:4 Comment(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!Visser
Thanks for this - running locale-gen is now part of my server build scripts.Alica
W
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.

Windbound answered 1/12, 2015 at 16:26 Comment(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 answersCathead
G
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!

Gorilla answered 15/3, 2016 at 9:57 Comment(0)
D
5

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.

Dominik answered 1/1, 2021 at 21:9 Comment(4)
Thanks a lot! I lost quite a bit of time on that one. +1Synthetic
Thanks, that was what worked for me as wellShowing
Amazing. Spend all day but this unexpected solution fixed all. Thanks!Purple
The only working solution. Thanks a lot!Vernon
J
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://mcmap.net/q/658877/-php-gettext-problems

Hope it helps!

Jeffry answered 10/2, 2017 at 19:22 Comment(0)
M
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");
Mccord answered 24/10, 2017 at 20:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.