您可以通过使用来完全避免这些setlocale
问题web_set_locale
。
(邮件列表上的那条消息比该功能的添加早了大约 4 年。)
编辑:您是正确的,Apache 子代中持续存在全局行为,导致错误行为。
我写了一个测试用例:
应用程序.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;但是worker
并且event
受到影响,因为它们是基于线程的。