mod_perl设置中多个locale之间的冲突



我目前正在国际化一个大型Perl/Mason web应用程序(Perl 5.8.0, Mason 1.48, mod_perl &Apache)。在选择本地化模块时,我决定使用Locale::TextDomain而不是Locale::Maketext,主要是因为后者的复数形式支持不像我希望的那样好。

我在Locale::TextDomain遇到的问题是,它根据进程的语言环境来解析翻译使用哪个目录。当我意识到这一点时,我开始担心,如果我希望用户能够使用不同的语言环境,这将如何影响我的应用程序——为了适应一个用户的设置而改变语言环境,是否有可能影响另一个用户的会话?例如,是否存在这样一种情况:由于德语用户的会话更改了进程的语言环境,英语用户收到了德语页面?我不是很了解Apache的线程/进程模型是如何工作的,尽管似乎如果多个用户可以由同一个线程服务,这可能会发生。

这个电子邮件线程将表明这是可能的;这里的OP描述了我正在考虑的情况。

如果这是真的,是否有一种方法可以防止这种情况,而仍然使用Locale::TextDomain?我想我总是可以破解模块加载目录在一个独立的地区(可能使用DBD::PO),但希望我只是错过了一些东西,将解决我的问题…

使用web_set_locale可以完全避免setlocale的问题。

(邮件列表上的消息比添加该功能早了大约4年。)


编辑:你是正确的,全局行为在Apache子节点中持续存在,导致错误的行为。

我写了一个测试用例:

app.psgi

use 5.010;
use strictures;
use Foo::Bar qw(run);
my $app = sub {
    my ($env) = @_;
    run($env);
};

Foo/Bar.pm

package Foo::Bar;
use 5.010;
use strictures;
use Encode qw(encode);
use File::Basename qw(basename);
use Locale::TextDomain __PACKAGE__, '/tmp/Foo-Bar/share/locale';
use Locale::Util qw(web_set_locale);
use Plack::Request qw();
use Sub::Exporter -setup => { exports => [ 'run' ] };
our $DEFAULT_LANGUAGE = 'en'; # untranslated source strings
sub run {
    my ($env) = @_;
    my $req = Plack::Request->new($env);
    web_set_locale($env->{HTTP_ACCEPT_LANGUAGE}, undef, undef, [
        map { basename $_ } grep { -d } glob '/tmp/Foo-Bar/share/locale/*'
    ]); # XXX here
    return $req
        ->new_response(
            200, 
            ['Content-Type' => 'text/plain; charset=UTF-8'],
            [encode('UTF-8', __ 'Hello, world!')],
        )->finalize;
}

应用程序作为PerlResponseHandler运行。当用户请求无法设置的语言时,调用静默失败,上次成功使用的语言仍然启用。

解决这个问题的技巧是始终设置为具有回退机制的语言。在标记XXX的地方,添加代码or web_set_locale($DEFAULT_LANGUAGE),这样尽管使用全局设置,行为不能持续,因为我们保证每个请求设置/更改一次。


编辑2:进一步的测试表明,它不是线程安全的,对不起。只使用prefork MPM,它将请求作为进程隔离;但是workerevent受到影响,因为它们是基于线程的。

相关内容

  • 没有找到相关文章

最新更新