【问题标题】:How to debug gettext not working in PHP?如何调试 gettext 在 PHP 中不起作用?
【发布时间】:2014-06-03 22:46:25
【问题描述】:

我正在尝试在 php 5.5 中使用 php gettext 扩展(在 win2008 服务器上,使用 IIS7)。我正在这样做:

<?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");

?>

有了这个文件夹结构:

locale/es/LC_MESSAGES/messages.mo

但它总是只返回 Hello world 而不是正确的翻译,目前(基于我缺乏西班牙语技能)在 messages.po 文件中是这样的:

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"

这从 cmd 行和通过 IIS 失败。所以我看到 gettext 调用等并执行它,但它没有读取翻译文件。我该如何进一步调试?即使删除翻译文件,我也会得到相同的行为。

【问题讨论】:

  • 有人吗?这真是一团糟。我没有看到任何证据表明配置正确或不在线。医生基本上很糟糕。这对任何人都有效吗?
  • 您需要在 MO 文件中使用bind_textdomain_codeset() 声明您正在使用的字符集,并且您需要确保您生成的语言环境使用与您的 MO 文件相同的字符集。查看这篇文章了解更多信息:blog.terresquall.com/2020/09/troubleshooting-php-gettext

标签: php localization internationalization gettext setlocale


【解决方案1】:

您应该检查返回值并知道哪个函数失败了。它不是 i18n 特定的,但对任何 PHP 脚本或任何编程语言调试都很有用。

<?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";

【讨论】:

  • 正确。除了 gettext 调用外,一切看起来都很好。确实有问题。
  • 这里也一样。真令人沮丧。你发现你的问题是什么了吗?
  • @philippe_b 我​​刚刚度过了美好的一天,想知道为什么这到底是行不通的——终于愚蠢地意识到了为什么。我将LC_ALL 设置为fr_FR(一切正常,没有错误)但是完成后我将用户引回原始页面;那时 - 它已经失去了原来的 setlocale 到那时 - 这是一个新过程,需要在每个页面(或包含)的顶部重置,并在会话中保留选择。我愚蠢地认为设置setlocale 本身就是一个会话!
  • 感谢您 ping 我 :) 这不是我遇到的问题。我修复了它,但是在我在这里发布几天后,所以我忘记了贡献。但我在下面备份@jr997 的答案:操作系统必须知道语言环境,这一点都不明显。
【解决方案2】:

您在 'locale -a' 的输出中找到“es”吗?如果没有,那么您需要运行以下命令。

 sudo locale-gen es

【讨论】:

  • 我最近移动了主机,我的 gettext 停止工作。检查 locale -a 并发现 locale 丢失,添加它并再次开始工作!
  • 感谢您的支持 - 运行 locale-gen 现在是我的服务器构建脚本的一部分。
【解决方案3】:

在 Linux 上遇到同样的问题,我得出了这样的结论: 即使您为您的项目提供自己的 *.mo 文件,语言环境本身 (es)必须为操作系统所知。

在系统级别安装请求的语言环境为我解决了这个问题。

见:locale-gen

实际上调试 gettext 可能无济于事,但至少你可以尝试一下。

【讨论】:

  • 回答问题时,尽量做到简洁、准确和客观。声明此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 could fix the issue. 等...不要在答案中声明 cmets/opinions
【解决方案4】:

由于不知道在操作系统上使用哪种语言包,幸好setlocale() 函数允许使用数组。根据PHP Docs

"如果语言环境是一个数组或后跟附加参数,则尝试将每个数组元素或参数设置为新的语言环境,直到成功。如果一个语言环境在不同系统上以不同的名称已知或用于提供回退,这很有用对于可能不可用的语言环境”

有了这个,你可以通过检查之后的集合来挖掘操作系统正在回退的语言环境:

$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 将提供成功的 $locales 值。这在查找为哪个语言环境编写 .po 时可能会有所帮助。

根据我的 cmets 中所写,我遇到的问题是我没有在每个页面请求的每个脚本的顶部执行此 setlocale(),因为您需要保留用户通过会话或数据库选择的语言价值。正如我天真地相信,一旦它被设定,它就永远被设定了!

【讨论】:

    【解决方案5】:

    这是一个有点老的问题,但这里是这个答案,希望对某人有用。

    尝试在putenv 函数中将LC_ALL 更改为LANG,如下:

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

    到这里:

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

    在 mac 中,LC_ALL 出现问题,这里可能也一样。

    在其他情况下也请检查此答案 https://stackoverflow.com/a/3535866/6628843

    希望对你有帮助!

    【讨论】:

      【解决方案6】:

      尝试同时设置环境变量LC_LANGLC_LANGUAGE,而不仅仅是LC_ALL

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

      【讨论】:

        【解决方案7】:

        我知道这个问题很老了,但是对于来自 Google 的任何人,我想分享我自己的经验。

        在将 Debian 从 Stretch 升级到 Buster 后,我也遇到了这个问题,我花了很长时间尝试调试这个问题。我不确定为什么,但就我而言,我只需在代码中添加以下行即可解决问题,

        putenv('LANGUAGE=');
        

        令我惊讶的是,从命令行运行时在 PHP 脚本中使用 gettext 实际工作正常,与 Apache 运行时相比。从终端运行命令locales 后,我注意到LANGUAGE 环境变量实际上设置为空字符串。当由 Apache 运行时,无论出于何种原因,它都设置为 en_US:en,正如我通过使用 getenv 函数发现的那样。

        我不知道为什么将LANGUAGE 环境变量设置为空字符串实际上为我解决了这个问题,但它确实解决了。希望有人会觉得这很有用。

        【讨论】:

        • 非常感谢!我在那个上浪费了很多时间。 +1
        • 谢谢,这对我也有用
        猜你喜欢
        • 2018-04-10
        • 1970-01-01
        • 2011-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-22
        相关资源
        最近更新 更多