【问题标题】:Clash Between Multiple Locales in a mod_perl Setting?mod_perl设置中多个语言环境之间的冲突?
【发布时间】:2011-12-07 18:17:41
【问题描述】:

我目前正在致力于国际化大型 Perl/Mason Web 应用程序(Perl 5.8.0、Mason 1.48、mod_perl 和 Apache)。在选择本地化模块时,我决定使用 Locale::TextDomain 而不是 Locale::Maketext,主要是因为后者的复数形式支持不如我想的那么好。

我对 Locale::TextDomain 的困扰在于它会根据进程的语言环境来解析要用于翻译的目录。当我意识到这一点时,我担心如果我希望用户能够使用不同的语言环境,这将如何影响我的应用程序——改变语言环境以适应一个用户的设置是否会影响另一个用户的会话?例如,是否会出现这样一种情况:由于德国用户的会话更改了进程的区域设置,因此英语用户收到了德语页面?我不太了解 Apache 的线程/进程模型是如何工作的,但似乎如果多个用户可以由同一个线程提供服务,这可能会发生。

This email thread 表示这是可能的; here OP 描述了我正在考虑的情况。

如果这是真的,有没有办法可以在仍然使用 Locale::TextDomain 的同时防止这种情况?我想我总是可以破解模块以独立于语言环境(可能使用 DBD::PO)加载目录,但希望我只是错过了一些可以解决我的问题的东西......

【问题讨论】:

    标签: perl internationalization mod-perl mason


    【解决方案1】:

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

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


    编辑:您是正确的,Apache 子代中持续存在全局行为,导致buggy behaviour

    我写了一个测试用例:

    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 会受到影响,因为它们是基于线程的。

    【讨论】:

    • 是否有比 CPAN 页面说 web_set_locale 是线程安全的文档?根据该链接上的文档,web_set_locale 调用 Locale::Util::set_locale,其文档指定它使用 POSIX::setlocale——我的印象是 web_set_locale 实际上并没有解决这个问题,但我可能遗漏了一些重要的东西。
    猜你喜欢
    • 2010-09-09
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    • 2013-01-10
    • 2020-04-05
    相关资源
    最近更新 更多