Столкновение между несколькими локалями в настройке mod_perl? - PullRequest
1 голос
/ 07 декабря 2011

В настоящее время я работаю над интернационализацией большого веб-приложения на Perl / Mason (Perl 5.8.0, Mason 1.48, mod_perl & Apache).При выборе модуля локализации я решил использовать Locale :: TextDomain вместо Locale :: Maketext, главным образом потому, что поддержка множественного числа последних не так хороша, как хотелось бы.

Зависание, которое я испытываю с Locale :: TextDomain, заключается в том, что он решает, какой каталог использовать для переводов на основе локали процесса.Когда я понял это, я забеспокоился о том, как это повлияет на мое приложение, если я хочу, чтобы пользователи могли использовать разные языковые стандарты - возможно ли, что изменение языкового стандарта в соответствии с настройками одного пользователя повлияет на сеанс другого пользователя?Например, может ли быть ситуация, когда английский пользователь получил страницу на немецком языке, потому что сеанс немецкого пользователя изменил локаль процесса?Я не очень хорошо осведомлен о том, как работает модель потоков / процессов Apache, хотя кажется, что если несколько пользователей могут обслуживаться одним потоком, это может произойти.

Этот поток электронной почты будетуказать, что это возможно; здесь ОП описывает ситуацию, о которой я думаю.

Если это так, могу ли я предотвратить этот сценарий, продолжая использовать Locale :: TextDomain?Я полагаю, я всегда мог взломать модуль для загрузки каталогов в зависимости от локали (возможно, используя DBD :: PO), но, надеюсь, я просто упускаю что-то, что решит мою проблему ...

1 Ответ

0 голосов
/ 08 декабря 2011

Вы полностью избегаете проблем setlocale, используя вместо этого web_set_locale.

(Это сообщение в списке рассылки предшествует добавлению этой функции примерно на 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, который изолирует запросы как процессы;однако worker и event затронуты, потому что они основаны на потоке.

...