Windows 10 XAMPP 上的 GetText 无法翻译我的文本



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

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

msgid ""
msgstr ""
"Project-Id-Version: TESTn"
"POT-Creation-Date: 2020-06-13 00:44+0200n"
"PO-Revision-Date: 2020-06-13 00:53+0200n"
"Last-Translator: n"
"Language-Team: n"
"Language: nl_BEn"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
"Content-Transfer-Encoding: 8bitn"
msgid "foo"
msgstr "bar"
msgid "fizz"
msgstr "buzz"

它被存储到

./locale/nl_BE/LC_MESSAGES/messages.po

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

并尝试使其与以下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 已启用:

获取文本

获取文本支持 => 已启用

任何帮助真的非常感谢!

这是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'));

我发现在绑定文本域被调用后,使用一个有效的 .mp 文件 你必须重新启动阿帕奇!! 再次返回到默认值,因为语言字符串显然缓存在任何地方。

因此,更改它以获得不同翻译的解决方案不起作用。

所以我研究了第二个论点:$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

并将第二行设置为"消息 1">

$domain = 'messages1';

西里尔文代码被破坏了!!

我的窗户上既没有加载西里尔语言,也没有塞尔维亚本地语,什么都没有。 只有英语和德语。

这意味着至少在安装了德语的 Windows 10 中,无需安装语言或区域设置即可使 gettext 正常工作! (我不认为这是否也是中国人...但那是另一回事)

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

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

例如 messages_de.po/..莫或德国.po..随心所欲

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

例如 /de_DE/或/en_US/

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

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

然后,您只需在 Apache 中设置一个环境变量,并且仅当脚本在具有环境上下文"dev"的本地主机 Windows 计算机上运行时,才运行 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"

在远程生产系统的虚拟主机的 Apache 配置中:

SetEnv SERVER_CONTEXT "prod"

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

我没有足够的PHP,所以我用C解释它。

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

  1. setlocale(LC_ALL, ""):根据当前用户的环境变量设置区域设置。这对于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又名C又名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 环境的维护者建议一个类似的解决方案,该解决方案只是忽略所选语言环境是否实际安装在服务器上。

最新更新