apache 当通过在SSH上执行的PHP脚本运行时,对于非根语言,Gettext福尔斯会返回到英语

qyzbxkaa  于 2023-10-23  发布在  Apache
关注(0)|答案(1)|浏览(115)

我正在准备一个应用程序,它的服务器端基于PHP,翻译使用原生的gettext函数实现。
为了加载应该用于检索gettext翻译的locale,我遵循文档并使用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
等等,对于上面指定的所有区域设置(非德语,因为msgid是德语/德语是根语言)。

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

我发现实际上英语被用作非德语gettext检索的默认翻译语言。例如,如果你用/translations/pt_PT.UTF-8/LC_MESSAGES/firstdomain.mo的内容覆盖/translations/en_GB.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终端会话中运行的,则只返回到通过文件/translations/en_GB.UTF-8/LC_MESSAGES/firstdomain.mo提供的翻译。为什么

注意:

在设置区域设置之前执行putenv("LANGUAGE=");,或者像here那样执行putenv("LC_ALL=");,都不会改变任何东西。
在设置locale之前执行putenv("LANGUAGE=");,无论是使用locale,包括或排除.UTF-8后缀,还是像here那样只使用前两个字符串字符,也没有解决问题。
执行putenv('LANGUAGE=nl_NL');(如here所述)也没有达到目的。
我注意到the PHP manual for setlocale中关于“多线程服务器API”的注解,并看到了this existing question,但我不确定这是否与本例相关。
我现在发现,如果我替换零件,我实际上可以在本地重现从服务器获得的输出:

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服务器上切换区域设置是不够的/被忽略的。

bfhwhh0e

bfhwhh0e1#

感谢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: 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的Apache服务器上以PHP-FPM(FCGI)运行PHP脚本,那么它是必需的。为什么会这样?完全没有线索;仍然会对其中的原因非常感兴趣

相关问题