我目前正致力于将大型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),但希望我只是遗漏了一些可以解决我的问题......
答案 0 :(得分:0)
您可以使用 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);
};
<强>富/ 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
会受到影响,因为它们是基于线程的。