【问题标题】:GetText on Windows 10 XAMPP doesn't translate my textWindows 10 XAMPP 上的 GetText 无法翻译我的文本
【发布时间】:2020-06-12 23:11:21
【问题描述】:

GetText 让我发疯了几个小时,我无法让它工作。

这是我的message.po文件的内容:

msgid ""
msgstr ""
"Project-Id-Version: TEST\n"
"POT-Creation-Date: 2020-06-13 00:44+0200\n"
"PO-Revision-Date: 2020-06-13 00:53+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: nl_BE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "foo"
msgstr "bar"

msgid "fizz"
msgstr "buzz"

存储到

./locale/nl_BE/LC_MESSAGES/messages.po

我使用msgfmt 命令将它编译成.MO 文件。

并尝试使其与以下 PHP 代码一起工作

<?php
putenv('LC_ALL=nl_BE');
setlocale(LC_ALL, 'nl_BE');
bindtextdomain("messages", "./locale");
textdomain("messages");
echo _("foo");
echo _("fizz");

输出:

>php test.php
foofizz

你得到相同的结果吗?知道为什么它不起作用吗?

不确定是否相关,但我使用的是 Windows 10。我的 PHP 版本是 PHP 7.2.28(安装了 XAMPP)

另外,phpinfo() 声明 gettext 已启用:

获取文本

GetText 支持 => 启用

非常感谢任何帮助!

【问题讨论】:

  • 在服务器上尝试命令locale -a看是否安装了语言环境nl_BE。如果没有,请安装它或使用已安装的语言环境进行测试。
  • 是的,这是 XAMPP 的语言环境问题。我终于卸载了 XAMPP,改用 WSL+ Ubuntu 和一个“真正的”Apache 服务器。

标签: php xampp internationalization gettext


【解决方案1】:

这是 2009 年以来已知的 Windows PHP 问题,PHP 团队中似乎没有人关心。

一整天后,我终于找到了一个我可以接受的解决方法。

这里或其他地方的答案都没有帮助我,也没有被遗弃的 gettext 替换脚本 - 但它帮助我找到了问题。

我什至更改了 Windows 语言环境 - 没有帮助 - 而且我不想更改我的 Windows 语言,因为我需要在我的网站脚本上调试即时语言更改,并且每次翻译更改都必须重新启动是没有选择的;- )

我已经安装了其他语言和本地人,但没有任何帮助。

问题是你可以做任何你想做的事,但至少我的 WIN10 64pro DID 除了我的主要 Windows 语言之外,从不查看任何其他文件夹

/de_DE/LC_MESSAGES 

我删除了与 gettext 和
的功能无关的任何内容 这五行仍然作为最低可重现的工作示例。

$path= "C:/xampp/htdocs/locale";
$domain = 'messages';
bindtextdomain($domain, $path);
textdomain($domain);
print _("The string you want to translate" );

所以我的想法是更改这 5 行中的任何内容以显示不同的语言

路径也可以是相对的,例如realpath('./locale'));

我发现在 bindtextdomain 被一个工作的 .mp 文件调用之后 您必须重新启动 APACHE!再次返回默认值,因为显然语言字符串被缓存在任何地方。

所以改变它以获得不同翻译的解决方案不起作用。

所以我研究了第二个参数:$domain 并且测试表明这非常适合我的目的。

将其更改为错误并重新加载原始未翻译文本后显示。 将其改回正确的文本后,立即显示翻译文本。

我感觉很棒

现在我想显示两种以上的语言。

我重命名了塞尔维亚西里尔字母! pig 示例代码的 .mo 和 .po 文件到 message1.po 和 message1.mo 并将它们移动到

/de_DE/LC_MESSAGES 

我现在里面有 4 个文件

message.mo      //german translation compiled
message.po     //german translation original
message1.po    // serbian cyrillic original
message1.po    // serbian cyrillic original

并将第二行设置为“message1”

  $domain = 'messages1';

并且显示了西里尔代码!!

我的 Windows 中没有任何西里尔文语言,没有 serbian local ,什么都没有。 只有英语和德语。

这意味着至少在安装了德语的 Windows 10 中,没有必要安装语言或区域设置来使 gettext 正常工作! (我不知道这是否也是真实的中国......但那是另一回事)

因此,如果您有一个远程 Linux 服务器并且想要测试您的国际化,您所要做的就是

1.) 复制所有 messages.po 和 -mo 文件
将它们全部重命名为所需的名称

例如messages_de.po /..mo 或 German.po .. 随便你

将所有这些文件放入您安装的 Windows 语言名称的文件夹中

例如/de_DE/ 或 /en_US/

并将消息变量更改为所需的值

您可能会说“我不想更改我的代码 OM 部署”

然后您只需在 Apache 中设置一个环境变量,并且仅当脚本在您的本地 Windows 机器上运行且环境上下文为“dev”时,然后运行 ​​Windows 解决方法。在您的远程生产系统上,您运行标准的 gettext 初始化。

if  (getenv("SERVER_CONTEXT") == "dev")  
{
    switch (GET('lang')) { 
    case "de":
    $domain="messages_de";
    break;
    case "fr": 
    $domain = "messages_fr"; 
     break;
     default:  //untranslated english texts  
     $domain = ""; 

}
        $path= "C:/xampp/htdocs/locale";
        bindtextdomain($domain, $path);
        textdomain($domain);

}
 elseif (getenv("SERVER_CONTEXT") == "prod"))  

{ the standard gettext initialization for the remote host }


        print _("The string you want to translate" );

在您的 Windows 机器上,您的默认语言目录中应该还有以下 4 个文件:

messages_fr.mo     
messages_fr.po     
messages_de.po    
messages_de.po    

注意:对于系统的自动检测步骤,您需要两个小的配置更改:

在 Apache 配置中,在 Windows 机器的虚拟主机中设置以下变量:

SetEnv SERVER_CONTEXT "dev"

在远程生产系统的 virthost 的 Apache 配置中:

SetEnv SERVER_CONTEXT "prod"

【讨论】:

    【解决方案2】:

    这里实际的“错误”是你没有检查setlocale()的返回值。

    我对PHP的了解不够,所以我用C解释一下。

    函数setlocale()有三种不同的风格:

    1. setlocale(LC_ALL, ""):根据当前用户的环境变量设置locale。这对 PHP 来说几乎没有意义,因为当前用户是运行 Web 服务器的用户。如果成功,它将返回一个标识当前语言环境设置的字符串。
    2. setlocale(LC_ALL, "nl_BE"):尝试选择语言环境“nl_BE”。如果语言环境定义“nl_BE”对服务器无效(= 未安装),它将返回 NULL。如果成功,它将返回一个标识当前语言环境设置的字符串。
    3. setlocale(LC_ALL, NULL):此调用查询类别LC_ALL 的当前区域设置。当您请求翻译字符串时,这就是 gettext 运行时所做的。它首先查询当前选择的语言环境,以便加载正确的翻译目录。

    发生了什么事?

    您尝试切换到具有风味#2 的语言环境nl_BE,但实际上失败了,因为服务器上未安装语言环境nl_BE。失败意味着语言环境没有改变。无论之前选择的区域设置如何,仍将被选中。

    稍后,您尝试使用 gettext 快捷方式 _("foobar") 检索翻译后的字符串。 gettext 运行时将使用风味#3 来查询当前选定的语言环境。这将返回nl_BE,因为风味#2 调用由于缺少语言环境安装而失败,然后返回原始未翻译的字符串。更准确地说:使用成功选择的最后一个语言环境。

    从 Web 应用程序的角度来看,这种行为可能看起来很愚蠢。为什么在 po/mo 文件中提供所有翻译时还需要语言环境定义?

    Gettext 不是为此而生的。它是为桌面应用程序设计的。

    在桌面应用程序中,在程序启动时忽略setlocale() 的返回值非常有意义。如果未安装所需的语言环境,则回退到默认语言环境(en_US aka C aka POSIX)非常有意义。

    但为什么 gettext 运行时“拒绝”使用应用程序附带的 .mo 文件,只是因为运行时系统没有安装相应的语言环境?

    您的程序附带的翻译不仅有语言环境类别LC_MESSAGES。还有其他类别,例如LC_TIME,其中包含工作日和月份名称的翻译,LC_CURRENCY 用于货币名称。而LC_MESSAGES 类别也用于选择系统消息的翻译,例如“没有这样的文件或目录”。

    gettext 运行时确保程序消息始终保持一致,并且不会混合语言和字符编码。对于许多 Web 应用程序来说,这似乎过于严格,但 gettext 并不是为 Web 应用程序设计的。

    如果这种严格性不适合您的用例,请编写您自己的忽略系统区域设置的小型 gettext 运行时。对于 Perl,这已经存在:https://metacpan.org/pod/Locale::gettext_dumb(是的,我是作者)。或者向 PHP gettext 环境的维护者建议一个类似的解决方案,该解决方案只是忽略所选语言环境是否实际安装在服务器上。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-31
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多