Centralize management of client's language in LL::NG::Commmon::CGI (Lemonldap-369)

This commit is contained in:
François-Xavier Deltombe 2012-02-15 11:58:32 +00:00
parent 88646e8a0f
commit c4bf8af37a
16 changed files with 126 additions and 126 deletions

View File

@ -47,6 +47,7 @@ sub new {
$self->{_prm}->{$_} = $self->param($_);
$self->delete($_);
}
$self->{lang} = extract_lang();
bless $self, $class;
return $self;
}
@ -327,6 +328,21 @@ sub _sub {
}
}
##@method string extract_lang
#@return array of user's preferred languages (two letters)
sub extract_lang {
my $self = shift;
my @langs = split /,\s*/, ( $ENV{HTTP_ACCEPT_LANGUAGE} || "" );
my @res = ();
foreach (@langs) {
# languages are supposed to be sorted by preference
# only 2-letters lang tags are considered
my $lang = (split /;/)[0];
push @res, $lang if (length($lang) == 2);
}
return \@res;
}
##@method void translate_template(string text_ref, string lang)
# translate_template is used as an HTML::Template filter to tranlate strings in
# the wanted language
@ -336,12 +352,6 @@ sub _sub {
sub translate_template {
my $self = shift;
my $text_ref = shift;
my $lang = shift || $ENV{HTTP_ACCEPT_LANGUAGE};
# Get the lang code (2 letters)
$lang = lc($lang);
$lang =~ s/-/_/g;
$lang =~ s/^(..).*$/$1/;
# Decode UTF-8
utf8::decode($$text_ref);
@ -349,12 +359,13 @@ sub translate_template {
# Test if a translation is available for the selected language
# If not available, return the first translated string
# <lang en="Please enter your credentials" fr="Merci de vous autentifier"/>
if ( $$text_ref =~ m/$lang=\"(.*?)\"/ ) {
$$text_ref =~ s/<lang.*$lang=\"(.*?)\".*?\/>/$1/gx;
}
else {
$$text_ref =~ s/<lang\s+\w+=\"(.*?)\".*?\/>/$1/gx;
foreach (@{ $self->{lang} }) {
if ( $$text_ref =~ m/$_=\"(.*?)\"/ ) {
$$text_ref =~ s/<lang.*$_=\"(.*?)\".*?\/>/$1/gx;
return;
}
}
$$text_ref =~ s/<lang\s+\w+=\"(.*?)\".*?\/>/$1/gx;
}
##@method void session_template(string text_ref)

View File

@ -7,7 +7,7 @@
package My::Portal;
use strict;
use Test::More tests => 10;
use Test::More tests => 17;
use_ok('Lemonldap::NG::Common::CGI');
#our @ISA = qw('Lemonldap::NG::Common::CGI');
@ -82,6 +82,25 @@ SKIP: {
$cgi->{mySubtest} = sub { return 'OK2' };
ok( $cgi->_sub('mySubtest') eq 'OK2', '_sub mechanism 2' );
# Test extract_lang
my $lang;
ok( $lang = $cgi->extract_lang(),
'extract_lang 0 with void "Accept-language"' );
ok( scalar(@$lang) == 0, 'extract_lang 1 with void "Accept-language"' );
my $cgi2;
$ENV{SCRIPT_NAME} = '/test.pl';
$ENV{SCRIPT_FILENAME} = 't/20-Common-CGI.t';
$ENV{REQUEST_METHOD} = 'GET';
$ENV{REQUEST_URI} = '/';
$ENV{QUERY_STRING} = '';
$ENV{HTTP_ACCEPT_LANGUAGE} = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3';
ok( ( $cgi2 = Lemonldap::NG::Common::CGI->new() ), 'New CGI' );
ok( $lang = $cgi2->extract_lang(), 'extract_lang' );
ok( $lang->[0] eq 'fr', 'extract_lang' );
ok( $lang->[1] eq 'en', 'extract_lang' );
ok( scalar(@$lang) == 2, 'extract_lang' );
# SOAP
eval { require SOAP::Lite };
skip "SOAP::Lite is not installed, so CGI SOAP functions will not work", 3

View File

@ -310,7 +310,7 @@ sub en {
singleSession => 'One session only by user',
singleUserByIP => 'One user by IP address',
slaveAuthnLevel => 'Authentication level',
slaveMasterIP => 'master\'s IP address',
slaveMasterIP => 'Master\'s IP address',
slaveParams => 'Slave parameters',
slaveUserHeader => "Header for user login",
SMTPAuthPass => 'SMTP password',

View File

@ -791,10 +791,7 @@ sub extractFormInfo {
return $urlcheck unless ( $urlcheck == PE_OK );
# IDP list
my $html = "<h3>"
. &Lemonldap::NG::Portal::_i18n::msg( PM_SAML_IDPSELECT,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. "</h3>\n<table>\n";
my $html = "<h3>" . $self->msg(PM_SAML_IDPSELECT) . "</h3>\n<table>\n";
foreach ( keys %{ $self->{_idpList} } ) {
$html .=
@ -807,8 +804,7 @@ sub extractFormInfo {
$html .=
'<tr><td><input type="checkbox" name="cookie_type" value="1"></td><td>'
. &Lemonldap::NG::Portal::_i18n::msg( PM_REMEMBERCHOICE,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. $self->msg(PM_REMEMBERCHOICE)
. "</td></tr></table>\n"
# URL
@ -850,8 +846,7 @@ sub extractFormInfo {
# Choosen IDP
my $html = '<h3>'
. &Lemonldap::NG::Portal::_i18n::msg( PM_SAML_IDPCHOOSEN,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. $self->msg(PM_SAML_IDPCHOOSEN)
. "</h3>\n" . "<h4>"
. $self->{_idpList}->{$idp}->{name}
. "</h4>\n"

View File

@ -95,7 +95,7 @@ sub display {
AUTH_USER => $auth_user,
AUTOCOMPLETE => $self->{portalAutocomplete},
NEWWINDOW => $self->{portalOpenLinkInNewWindow},
AUTH_ERROR => $self->error( undef, $self->{menuError} ),
AUTH_ERROR => $self->error( $self->{menuError} ),
AUTH_ERROR_TYPE => $self->error_type( $self->{menuError} ),
DISPLAY_TAB => $self->{menuDisplayTab},
LOGOUT_URL => "$ENV{SCRIPT_NAME}?logout=1",

View File

@ -90,12 +90,7 @@ sub issuerForUnAuthUser {
# Display a link to the provided URL
$self->lmLog( "Logout URL $logout_url will be displayed", 'debug' );
$self->info(
"<h3>"
. &Lemonldap::NG::Portal::_i18n::msg( PM_BACKTOCASURL,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. "</h3>"
);
$self->info( "<h3>" . $self->msg(PM_BACKTOCASURL) . "</h3>" );
$self->info("<p><a href=\"$logout_url\">$logout_url</a></p>");
$self->{activeTimer} = 0;
@ -665,12 +660,7 @@ sub issuerForAuthUser {
# Display a link to the provided URL
$self->lmLog( "Logout URL $logout_url will be displayed", 'debug' );
$self->info(
"<h3>"
. &Lemonldap::NG::Portal::_i18n::msg( PM_BACKTOCASURL,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. "</h3>"
);
$self->info( "<h3>" . $self->msg(PM_BACKTOCASURL) . "</h3>" );
$self->info("<p><a href=\"$logout_url\">$logout_url</a></p>");
$self->{activeTimer} = 0;

View File

@ -238,7 +238,7 @@ sub _openIDResponse {
$self->info(
'<h3>'
. sprintf(
&Lemonldap::NG::Portal::_i18n::msg(PM_OPENID_EXCHANGE),
$self->msg(PM_OPENID_EXCHANGE),
$data->{trust_root}
)
. "</h3>"

View File

@ -193,11 +193,10 @@ sub issuerForUnAuthUser {
$self->{_proxiedArtifact} = $artifact;
# Create a back link on SP displayed on login page
my $html = "<a href=\"" . $self->referer() . "\">";
$html .=
&Lemonldap::NG::Portal::_i18n::msg( PM_BACKTOSP,
$ENV{HTTP_ACCEPT_LANGUAGE} );
$html .= "</a>";
my $html =
"<a href=\"" . $self->referer() . "\">"
. $self->msg(PM_BACKTOSP)
. "</a>";
$self->loginInfo($html);
return PE_OK;
@ -1715,9 +1714,7 @@ sub issuerForAuthUser {
$self->info(
"<h3>"
. &Lemonldap::NG::Portal::_i18n::msg
( Lemonldap::NG::Portal::Simple::PM_CDC_WRITER,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. $self->msg(PM_CDC_WRITER)
. "</h3>"
);

View File

@ -43,7 +43,7 @@ sub sregHook {
if ( $v =~ Lemonldap::NG::Common::Regexp::HTTP_URI ) {
$self->{_openIdTrustExtMsg} .=
'<dl><dt>'
. &Lemonldap::NG::Portal::_i18n::msg(PM_OPENID_PA)
. $self->msg(PM_OPENID_PA)
. "&nbsp;:</dt><dd><a href=\"$v\">$v</a></dd></dl>";
# Question: is it important to notify policy changes ?
@ -91,12 +91,7 @@ sub sregHook {
);
$self->info(
'<h3>'
. sprintf(
&Lemonldap::NG::Portal::_i18n::msg(PM_OPENID_RPNS),
$k
)
. '</h3>'
'<h3>' . sprintf( $self->msg(PM_OPENID_RPNS), $k ) . '</h3>'
);
return ( 0, {} );
}
@ -178,7 +173,7 @@ sub sregHook {
else {
$self->{_openIdTrustExtMsg} .=
"<h3>" . &Lemonldap::NG::Portal::_i18n::msg(PM_OPENID_AP) . "</h3>\n";
"<h3>" . $self->msg(PM_OPENID_AP) . "</h3>\n";
$self->{_openIdTrustExtMsg} .= "<table class=\"openidsreg\">\n";

View File

@ -166,7 +166,7 @@ SOAP mode authentication (client) :
# If authentication failed, display error
if ( $res->{error} ) {
print STDERR "Error: " . $soap->error( 'fr', $res->{error} )->result();
print STDERR "Error: " . $soap->error( $res->{error} )->result();
}
# print session-ID

View File

@ -771,27 +771,40 @@ _RETURN $string Error string
=cut
##@method string error(string lang, int code)
# error calls Portal/_i18n.pm to display error in the wanted language.
#@param $lang optional (browser language is used instead)
##@method string msg(int code)
# calls Portal/_i18n.pm to display message in the client's language.
#@param $code message code
#@return message
sub msg {
my $self = shift;
my $code = shift;
return &Lemonldap::NG::Portal::_i18n::msg($code, $self->{lang});
}
##@method string error(int code)
# calls Portal/_i18n.pm to display error in the client's language.
#@param $code optional error code
#@return error message
sub error {
my $self = shift;
my $lang = shift || $ENV{HTTP_ACCEPT_LANGUAGE};
my $code = shift || $self->{error};
my $msg;
# Check for customized message
$msg = $self->{ "error_" . $lang . "_" . $code }
|| $self->{ "error_" . $code };
foreach (@{ $self->{lang} }) {
if ( $self->{ "error_" . $_ . "_" . $code } ) {
$msg = $self->{ "error_" . $_ . "_" . $code };
last;
}
}
$msg ||= $self->{ "error_" . $code };
# Use customized message or built-in message
if ($msg) {
$self->lmLog( "Use customized message for error $code", 'debug' );
}
else {
$msg = &Lemonldap::NG::Portal::_i18n::error( $code, $lang );
$msg = &Lemonldap::NG::Portal::_i18n::error($code, $self->{lang});
}
# Return message
@ -1668,11 +1681,7 @@ sub controlExistingSession {
"Create iFrames to forward logout to services",
'debug' );
$self->info(
"<h3>"
. &Lemonldap::NG::Portal::_i18n::msg
(Lemonldap::NG::Portal::Simple::PM_LOGOUT) . "</h3>"
);
$self->info( "<h3>" . $self->msg(PM_LOGOUT) . "</h3>" );
foreach ( keys %{ $self->{logoutServices} } ) {
my $logoutServiceName = $_;
@ -2049,7 +2058,7 @@ sub registerLogin {
# Gather current login's parameters
my $login = $self->_sumUpSession( $self->{sessionInfo}, 1 );
$login->{error} = $self->error( undef, $errorCode )
$login->{error} = $self->error($errorCode)
if ($errorCode);
# Add current login into history
@ -2113,13 +2122,11 @@ sub removeOther {
}
$self->info(
$self->mkSessionArray(
$self->{deleted},
&Lemonldap::NG::Portal::_i18n::msg(PM_SESSIONS_DELETED), 1
)
$self->{deleted}, $self->msg(PM_SESSIONS_DELETED), 1 )
) if ( $self->{notifyDeleted} and @{ $self->{deleted} } );
$self->info(
$self->mkSessionArray( $self->{otherSessions},
&Lemonldap::NG::Portal::_i18n::msg(PM_OTHER_SESSIONS), 1 )
$self->mkSessionArray(
$self->{otherSessions}, $self->msg(PM_OTHER_SESSIONS), 1 )
. $self->_mkRemoveOtherLink()
) if ( $self->{notifyOther} and @{ $self->{otherSessions} } );
PE_OK;
@ -2156,13 +2163,13 @@ sub mkSessionArray {
$tmp .= "<table class=\"info\"><tbody>";
$tmp .= "<tr>";
$tmp .= "<th>" . &Lemonldap::NG::Portal::_i18n::msg(PM_USER) . "</th>"
$tmp .= "<th>" . $self->msg(PM_USER) . "</th>"
if ($displayUser);
$tmp .= "<th>" . &Lemonldap::NG::Portal::_i18n::msg(PM_DATE) . "</th>";
$tmp .= "<th>" . &Lemonldap::NG::Portal::_i18n::msg(PM_IP) . "</th>";
$tmp .= "<th>" . $self->msg(PM_DATE) . "</th>";
$tmp .= "<th>" . $self->msg(PM_IP) . "</th>";
$tmp .= "<th>" . $self->{sessionDataToRemember}->{$_} . "</th>"
foreach ( keys %{ $self->{sessionDataToRemember} } );
$tmp .= '<th>' . &Lemonldap::NG::Portal::_i18n::msg(PM_ERROR_MSG) . '</th>'
$tmp .= '<th>' . $self->msg(PM_ERROR_MSG) . '</th>'
if ($displayError);
$tmp .= '</tr>';
@ -2192,7 +2199,7 @@ sub _mkRemoveOtherLink {
return
"<p class=\"removeOther\"><a href=\"$link\" onclick=\"_go=0\">"
. &Lemonldap::NG::Portal::_i18n::msg(PM_REMOVE_OTHER_SESSIONS)
. $self->msg(PM_REMOVE_OTHER_SESSIONS)
. "</a></p>";
}
@ -2586,7 +2593,7 @@ SOAP mode authentication (client) :
# If authentication failed, display error
if ( $res->{error} ) {
print STDERR "Error: " . $soap->error( 'fr', $res->{error} )->result();
print STDERR "Error: " . $soap->error( $res->{error} )->result();
}
# print session-ID

View File

@ -171,8 +171,7 @@ sub userBind {
$self->{portal}->info(
"<h3>"
. $resp->grace_authentications_remaining . " "
. &Lemonldap::NG::Portal::_i18n::msg( PM_PP_GRACE,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. $self->msg(PM_PP_GRACE)
. "</h3>"
);
}
@ -180,8 +179,7 @@ sub userBind {
$self->{portal}->info(
"<h3>"
. $resp->time_before_expiration . " "
. &Lemonldap::NG::Portal::_i18n::msg( PM_PP_EXP_WARNING,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. $self->msg(PM_PP_EXP_WARNING)
. "</h3>"
);
}

View File

@ -62,7 +62,7 @@ sub proxyQuery {
if ( $res->{error} ) {
$self->_sub( 'userError',
"Authentication failed for $self->{user} "
. $soap->error( 'fr', $res->{error} )->result() );
. $soap->error( $res->{error} )->result() );
return PE_BADCREDENTIALS;
}
$self->{_remoteId} = $res->{cookies}->{ $self->{remoteCookieName} }

View File

@ -2649,9 +2649,7 @@ sub sendLogoutRequestToProviders {
# Header of the block which will be displayed to the user, if needed.
$info .= '<h3>'
. &Lemonldap::NG::Portal::_i18n::msg
( Lemonldap::NG::Portal::Simple::PM_SAML_SPLOGOUT,
$ENV{HTTP_ACCEPT_LANGUAGE} )
. $self->msg (Lemonldap::NG::Portal::Simple::PM_SAML_SPLOGOUT)
. '</h3>'
. '<table class="sloState">';
@ -2683,7 +2681,6 @@ sub sendLogoutRequestToProviders {
$self->info($info) if $providersCount;
return $providersCount;
}
## @method boolean checkSignatureStatus(Lasso::Profile profile)

View File

@ -10,44 +10,13 @@ package Lemonldap::NG::Portal::_i18n;
use AutoLoader qw(AUTOLOAD);
our $VERSION = '1.2.0';
## @fn string error(int error,string lang)
# @param $error Number of error to resolve
# @param $lang Language or Accepted-Language HTTP header string
# @return Error string for the $code in the $lang language
sub error {
my ( $error, $lang ) = splice @_;
$lang = lc($lang);
$lang =~ s/-/_/g;
$error = 0 if ( $error < 0 );
foreach ( split( /[,;]/, $lang ) ) {
next if /=/;
if ( __PACKAGE__->can("error_$_") ) {
return &{"error_$_"}->[$error];
}
s/^(..).*$/$1/;
if ( __PACKAGE__->can("error_$_") ) {
return &{"error_$_"}->[$error];
}
}
return &error_en->[$error];
}
## @fn string msg(int msg,string lang)
## @fn string msg(int msg, array ref lang)
# @param $msg Number of msg to resolve
# @param $lang Language or Accepted-Language HTTP header string
# @return Error string for the $code in the $lang language
# @param $lang Array ref for 2-letters languages (e.g. ['es', 'fr'])
# @return Message string in the first matching language
sub msg {
my ( $msg, $lang ) = splice @_;
$lang ||= $ENV{HTTP_ACCEPT_LANGUAGE};
$lang = lc($lang);
$lang =~ s/-/_/g;
$msg = 0 if ( $msg < 0 );
foreach ( split( /[,;]/, $lang ) ) {
next if /=/;
if ( __PACKAGE__->can("msg_$_") ) {
return &{"msg_$_"}->[$msg];
}
s/^(..).*$/$1/;
foreach ( @{ $lang } ) {
if ( __PACKAGE__->can("msg_$_") ) {
return &{"msg_$_"}->[$msg];
}
@ -55,6 +24,21 @@ sub msg {
return &msg_en->[$msg];
}
## @fn string error(int error, array ref lang)
# @param $error Number of error to resolve
# @param $lang Array ref for 2-letters languages (e.g. ['es', 'fr'])
# @return Error string in the first matching language
sub error {
my ( $error, $lang ) = splice @_;
$error = 0 if ( $error < 0 );
foreach ( @{ $lang } ) {
if ( __PACKAGE__->can("error_$_") ) {
return &{"error_$_"}->[$error];
}
}
return &error_en->[$error];
}
1;
__END__

View File

@ -15,7 +15,7 @@ BEGIN {
our %tr_msg = ( fr => 'French', );
}
use Test::More tests => 7 + ( keys(%tr_err) * 2 ) + ( keys(%tr_msg) * 2 );
use Test::More tests => 8 + ( keys(%tr_err) * 2 ) + ( keys(%tr_msg) * 2 );
BEGIN { use_ok('Lemonldap::NG::Portal::Simple') }
@ -30,12 +30,19 @@ foreach ( keys %tr_err ) {
ok( $#tmp == $#en, "$tr_err{$_} translation count (" . scalar(@tmp) . ')' );
}
my $p = bless {}, 'Lemonldap::NG::Portal::Simple';
$p->{error} = 10;
$ENV{HTTP_ACCEPT_LANGUAGE} = 'fr';
my $p1 = bless {}, 'Lemonldap::NG::Portal::Simple';
$p1->{error} = 10;
$p1->{lang} = ['en', 'fr'];
my $p2 = bless {}, 'Lemonldap::NG::Portal::Simple';
$p2->{error} = 5;
$p2->{lang} = [];
my $p3 = bless {}, 'Lemonldap::NG::Portal::Simple';
$p3->{error} = 10;
$p3->{lang} = ['fr', 'es', 'en'];
ok( $p->error() eq $p->error('fr'), 'HTTP_ACCEPT_LANGUAGE mechanism 1' );
ok( $p->error() ne $p->error('ro'), 'HTTP_ACCEPT_LANGUAGE mechanism 2' );
ok( $p1->error() eq $p2->error(10), 'HTTP_ACCEPT_LANGUAGE mechanism 1' );
ok( $p1->error() ne $p2->error(), 'HTTP_ACCEPT_LANGUAGE mechanism 2' );
ok( $p1->error() ne $p3->error(), 'HTTP_ACCEPT_LANGUAGE mechanism 3' );
ok( @en = @{&Lemonldap::NG::Portal::_i18n::msg_en},
'English messages translation' );