当通过 SSH 执行的 PHP 脚本运行时,Gettext 对于非 root 语言会回退到英语

问题描述 投票:0回答:1

我正在准备一个应用程序,其服务器端基于 PHP,并使用本机 gettext 函数实现翻译。

要加载应该用于检索 gettext 翻译的语言环境,我按照文档并使用 this:

// 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 连接在服务器上执行完全相同的

.sh
脚本(当然具有相应调整的路径,但完全相同的 php 脚本),我得到的输出是:

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

等等,对于上面指定的所有(非德语,因为 msgids 是德语/德语是根语言)区域设置。

所以我的问题是,为什么会出现这个问题?

我发现实际上是英语被用作非德语 gettext 检索的默认翻译语言。例如,如果您使用

/translations/en_GB.UTF-8/LC_MESSAGES/firstdomain.mo
的内容覆盖
/translations/pt_PT.UTF-8/LC_MESSAGES/firstdomain.mo
文件,则上面的输出将显示(如果脚本在服务器上通过 ssh 运行):

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“

因此,脚本似乎总是回退到通过文件提供的翻译

/translations/en_GB.UTF-8/LC_MESSAGES/firstdomain.mo
,但仅限于每个 ssh 终端会话运行脚本的情况。 为什么?

注意事项:

在设置区域设置之前执行

putenv("LANGUAGE=");
操作,或按照
此处
所述执行 putenv("LC_ALL="); 操作不会改变任何内容。

在设置区域设置之前执行

putenv("LANGUAGE=");
,无论是否使用区域设置,包括或排除
.UTF-8
后缀,或者仅像 here 那样完成前两个字符串字符也无法解决问题。

按照

here
所述进行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 服务器上切换语言环境还不够/可以忽略。

php multithreading apache localization gettext
1个回答
0
投票
感谢

this神圣帖子的接受答案,我可以找到解决方案。更改上面的代码示例:

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: MES_ROOT . '/translations' ); bindtextdomain( domain : 'seconddomain', directory: MES_ROOT . '/translations' ); // Set default textdomain to be first, as most translations are retrieved from there textdomain('firstdomain'); var_dump(_(message: 'Beispiel')); }
也就是说,每次迭代都重新启动文本域初始化和绑定。对于通常的 PHP 进程,这似乎不是必需的,但如果您在通过 ssh 命令将 PHP 作为 PHP-FPM (FCGI) 运行的 Apache 服务器上运行 PHP 脚本,则这是必需的。为什么它成功了?完全没有头绪!

© www.soinside.com 2019 - 2024. All rights reserved.