提问人:DevelJoe 提问时间:9/8/2023 最后编辑:DevelJoe 更新时间:9/8/2023 访问量:55
通过通过 SSH 执行的 PHP 脚本运行时,Gettext 回退到非根语言的英语
Gettext falls back to English for non-root language when running via PHP script executed over SSH
问:
我正在准备一个服务器端基于 PHP 的应用程序,并使用本机 gettext 函数实现翻译。
为了加载应该用于检索 gettext 翻译的区域设置,我遵循文档并使用以下命令:
// Set language to German
putenv('LC_ALL=de_DE');
setlocale(LC_ALL, 'de_DE');
到目前为止,对于我的 REST API 来说,这始终以可靠的方式工作,它以链接/描述的方式使用 gettext 翻译。但是,我有一个情况,它没有像我预期的那样工作。
我有以下PHP脚本:
$locales = [
'de_CH',
'en_GB',
'fr_FR',
'es_ES',
'pt_PT',
'it_IT'
];
$textdomain_loaded = false;
foreach ($locales as $locale_value) {
var_dump(putenv("LC_ALL=$locale_value.UTF-8"));
var_dump(
setlocale(
LC_ALL,
"$locale_value.UTF-8"
)
);
if ($textdomain_loaded === false) {
bindtextdomain(
domain : 'firstdomain',
directory: ROOT . '/translations'
);
bindtextdomain(
domain : 'seconddomain',
directory: ROOT . '/translations'
);
// Set default textdomain to be first, as most translations are retrieved from there
textdomain('firstdomain');
$textdomain_loaded = true;
}
var_dump(_(message: 'Beispiel'));
}
所有 .mo 文件都已正确翻译和生成。
如果我通过脚本()执行脚本,则只需通过以下方式调用脚本.sh
.zsh
php -r 'require "path/to/php/script.php"; MyClass::for_loop();'
或者,如果我向执行脚本的控制器触发 HTTP 请求,则会得到以下输出:
bool(true)
string(11) "de_CH.UTF-8"
string(8) "Beispiel"
bool(true)
string(11) "en_GB.UTF-8"
string(7) "Example"
bool(true)
string(11) "fr_FR.UTF-8"
string(7) "Exemple"
bool(true)
string(11) "es_ES.UTF-8"
string(7) "Ejemplo"
bool(true)
string(11) "pt_PT.UTF-8"
string(7) "Esemplo"
bool(true)
string(11) "it_IT.UTF-8"
string(7) "Esempio“
但是,如果我通过终端中的 ssh 连接在服务器上执行完全相同的脚本(当然具有相应的改编路径,但完全相同的 php 脚本),我得到的输出是:.sh
bool(true)
string(11) "de_CH.UTF-8"
string(8) "Beispiel"
bool(true)
string(11) "en_GB.UTF-8"
string(7) "Example"
bool(true)
string(11) "fr_FR.UTF-8"
string(7) "Example"
bool(true)
string(11) "es_ES.UTF-8"
string(7) "Example"
bool(true)
string(11) "pt_PT.UTF-8"
string(7) "Example"
bool(true)
string(11) "it_IT.UTF-8"
string(7) "Example“
因此,语言环境(环境和 PHP 语言环境)的切换似乎有效,但检索到的 gettext 翻译总是回退到英语翻译。
我已经在我的服务器上运行了;我设置/调用的所有语言环境都定义/安装在我的服务器上。locale -a
运行时,我可以在输出中看到以下部分:gettext --help
Standard search directory: /usr/local/share/locale
如上所述,我的文件存储在根目录下,例如:.mo
translations
/translations/en_GB.UTF-8/LC_MESSAGES/firstdomain.mo
/translations/en_GB.UTF-8/LC_MESSAGES/seconddomain.mo
/translations/fr_FR.UTF-8/LC_MESSAGES/firstdomain.mo
/translations/fr_FR.UTF-8/LC_MESSAGES/seconddomain.mo
依此类推,对于上面指定的所有(非德语,因为 MSGID 是德语/德语是根语言)区域设置。
所以我的问题是,为什么会发生这个问题?
我发现它实际上是英语被用作非德语gettext检索的默认翻译语言。例如,如果用 的内容覆盖文件,则上面的输出显示,如果脚本在服务器上按 ssh 运行:/translations/en_GB.UTF-8/LC_MESSAGES/firstdomain.mo
/translations/pt_PT.UTF-8/LC_MESSAGES/firstdomain.mo
bool(true)
string(11) "de_CH.UTF-8"
string(8) "Beispiel"
bool(true)
string(11) "en_GB.UTF-8"
string(7) "Esemplo"
bool(true)
string(11) "fr_FR.UTF-8"
string(7) "Esemplo"
bool(true)
string(11) "es_ES.UTF-8"
string(7) "Esemplo"
bool(true)
string(11) "pt_PT.UTF-8"
string(7) "Esemplo"
bool(true)
string(11) "it_IT.UTF-8"
string(7) "Esemplo“
因此,脚本似乎总是回退到通过文件提供的翻译,但只有在脚本是按 ssh 终端会话运行时才回退的。为什么?/translations/en_GB.UTF-8/LC_MESSAGES/firstdomain.mo
笔记:
在设置语言环境之前执行,或者如此处所述,没有更改任何内容。putenv("LANGUAGE=");
putenv("LC_ALL=");
在设置语言环境之前执行,无论是使用语言环境,包括或排除后缀,还是仅使用前两个字符串字符,就像这里所做的那样,也没有解决问题。putenv("LANGUAGE=");
.UTF-8
按照这里提到的去做也没有奏效。putenv('LANGUAGE=nl_NL');
我注意到 setlocale
的 PHP 手册中关于“多线程服务器 API”的注释,并看到了这个现有的问题,但我不确定这是否与这种情况相关。
我现在发现,如果我更换部件,我实际上可以在本地重现我从服务器获得的输出:
var_dump(putenv("LC_ALL=$locale_value.UTF-8"));
var_dump(
setlocale(
LC_ALL,
"$locale_value.UTF-8"
)
);
跟:
var_dump(putenv("LANG=$locale_value.UTF-8"));
对我来说,这表明出于某种原因,
putenv("LC_ALL=$locale_value.UTF-8");
setlocale(LC_ALL,"$locale_value.UTF-8");
在本地运行脚本时切换 gettext 语言环境就足够了,但在 Apache 服务器上切换语言环境是不够的/忽略的。
答:
多亏了这个神圣帖子的公认答案,我才能找到解决方案。更改上面的代码示例:
foreach ($locales as $locale_value) {
var_dump(putenv("LC_ALL=$locale_value.UTF-8"));
var_dump(
setlocale(
LC_ALL,
"$locale_value.UTF-8"
)
);
if ($textdomain_loaded === false) {
bindtextdomain(
domain : 'firstdomain',
directory: ROOT . '/translations'
);
bindtextdomain(
domain : 'seconddomain',
directory: ROOT . '/translations'
);
// Set default textdomain to be first, as most translations are retrieved from there
textdomain('firstdomain');
$textdomain_loaded = true;
}
var_dump(_(message: 'Beispiel'));
}
对此:
foreach ($locales as $locale_value) {
var_dump(putenv("LC_ALL=$locale_value.UTF-8"));
var_dump(
setlocale(
LC_ALL,
"$locale_value.UTF-8"
)
);
bindtextdomain(
domain : 'firstdomain',
directory: ROOT . '/translations'
);
bindtextdomain(
domain : 'seconddomain',
directory: ROOT . '/translations'
);
// Set default textdomain to be first, as most translations are retrieved from there
textdomain('firstdomain');
var_dump(_(message: 'Beispiel'));
}
也就是说,为每次迭代重新启动 textdomain 启动和绑定。对于通常的PHP进程,这似乎不是必需的,但是如果您通过ssh命令在以PHP-FPM(FCGI)身份运行PHP的Apache服务器上运行PHP脚本,则它是必需的。为什么它能成功?绝对没有线索;仍然会对原因非常感兴趣。
评论
php
评论