Commit 2e9c2843 authored by sikeda's avatar sikeda
Browse files

[dev] Canonicalize incoming language codes with format of language tags:...

[dev] Canonicalize incoming language codes with format of language tags: Old-style codes in config files, session cache etc. would be intact but interpreted to new codes.


git-svn-id: https://subversion.renater.fr/sympa/branches/sympa-6.2-branch@8953 05aa8bb8-cd2b-0410-b1d7-8918dfa770ce
parent 38819a73
......@@ -902,16 +902,18 @@ sub load_charset {
s/\s*#.*//;
s/^\s+//;
next unless /\S/;
my ($locale, $cset) = split(/\s+/, $_);
my ($lang, $cset) = split(/\s+/, $_);
unless ($cset) {
&Log::do_log('err', 'Charset name is missing in configuration file %s line %d', $config_file, $.);
next;
}
unless ($locale =~ s/^([a-z]+)_([a-z]+)/lc($1).'_'.uc($2).$'/ei) { #'
&Log::do_log('err', 'Illegal locale name in configuration file %s line %d', $config_file, $.);
next;
unless ($lang and $lang = Language::CanonicLang($lang)) {
Log::do_log('err',
'Illegal lang name in configuration file %s line %d',
$config_file, $.);
next;
}
$charset->{$locale} = $cset;
$charset->{$lang} = $cset;
}
close CONFIG;
......
......@@ -11612,6 +11612,10 @@ sub _set_list_param {
);
}
}
## Canonicalize lang.
if ($config_attr eq 'lang' and $val) {
$val = $self->robot->best_language($val);
}
## Apply defaults.
......
......@@ -1955,19 +1955,19 @@ sub _urlize_part {
$parser->output_to_core(1);
my $new_part;
my $lang = &Language::GetLang();
my $charset = &Language::GetCharset();
my $lang = Language::GetLang();
my $charset = Language::GetCharset();
my $tt2_include_path = $list->get_etc_include_path('mail_tt2', $lang);
&tt2::parse_tt2(
{ 'file_name' => $file_name,
'file_url' => $file_url,
'file_url' => $file_url,
'file_size' => $size,
'charset' => $charset
},
'urlized_part.tt2',
\$new_part,
'urlized_part.tt2',
\$new_part,
$tt2_include_path
);
......
......@@ -199,6 +199,70 @@ sub is_listmaster {
return 0;
}
=head3 Internationalization
=over 4
=item best_language ( LANG, ... )
# To get site-wide best language.
$lang = Site->best_language('de', 'en-US;q=0.9');
# To get robot-wide best language.
$lang = $robot->best_language('de', 'en-US;q=0.9');
# To get list-specific best language.
$lang = $list->best_language('de', 'en-US;q=0.9');
Chooses best language under the context of List, Robot or Site.
Arguments are language codes (see L<Language>) or ones with quality value.
If no arguments are given, the value of C<HTTP_ACCEPT_LANGUAGE> environment
variable will be used.
Returns language tag or, if negotiation failed, lang of object.
=back
=cut
sub best_language {
my $self = shift;
my $accept_string = join ',', grep { $_ and $_ =~ /\S/ } @_;
$accept_string ||= $ENV{HTTP_ACCEPT_LANGUAGE} || '*';
my @supported_languages;
my %supported_languages;
my @langs = ();
my $lang;
if (ref $self eq 'List') {
@supported_languages = $self->robot->supported_languages;
} elsif (ref $self eq 'Robot' or !ref $self and $self eq 'Site') {
@supported_languages = $self->supported_languages;
} else {
croak 'bug in logic. Ask developer';
}
%supported_languages = map { $_ => 1 } @supported_languages;
$lang = $self->lang;
push @langs, $lang
if $supported_languages{$lang};
if (ref $self eq 'List') {
$lang = $self->robot->lang;
push @langs, $lang
if $supported_languages{$lang} and !grep { $_ eq $lang } @langs;
}
if (ref $self eq 'List' or ref $self eq 'Robot') {
$lang = Site->lang;
push @langs, $lang
if $supported_languages{$lang} and !grep { $_ eq $lang } @langs;
}
foreach $lang (@supported_languages) {
push @langs, $lang
if !grep { $_ eq $lang } @langs;
}
return Language::NegotiateLang($accept_string, @langs) || $self->lang;
}
=head3 Handling the Authentication Token
=over 4
......@@ -436,6 +500,10 @@ IN :
OUT : ref(ARRAY) of tt2 include path
Note:
As of 6.2a.34, argument $lang is recommended to be IETF language tag,
rather than locale name.
=back
=cut
......@@ -443,14 +511,29 @@ OUT : ref(ARRAY) of tt2 include path
sub get_etc_include_path {
Log::do_log('debug3', '(%s, %s, %s)', @_);
my $self = shift;
return [$self->_get_etc_include_path(@_)];
my $dir = shift;
my $lang = shift;
## Get language subdirectories.
my $lang_dirs = undef;
if ($lang) {
## For compatibility: add old-style "locale" directory at first.
my $old_lang = Language::Lang2Locale_old($lang);
if ($old_lang) {
$lang_dirs = [$old_lang];
} else {
$lang_dirs = [];
}
## Add lang itself and fallback directories.
push @$lang_dirs, Language::ImplicatedLangs($lang);
}
return [$self->_get_etc_include_path($dir, $lang_dirs)];
}
sub _get_etc_include_path {
#Log::do_log('debug3', '(%s, %s, %s)', @_);
my $self = shift;
my ($dir, $lang) = @_;
my ($dir, $lang_dirs) = @_; # shift is not used
my @include_path;
......@@ -464,8 +547,10 @@ sub _get_etc_include_path {
} else {
$path_list = $self->dir;
}
if ($lang) {
unshift @include_path, $path_list . '/' . $lang, $path_list;
if ($lang_dirs) {
unshift @include_path,
(map { $path_list . '/' . $_ } @$lang_dirs),
$path_list;
} else {
unshift @include_path, $path_list;
}
......@@ -477,9 +562,10 @@ sub _get_etc_include_path {
} else {
$path_family = $family->dir;
}
if ($lang) {
if ($lang_dirs) {
unshift @include_path,
$path_family . '/' . $lang, $path_family;
(map { $path_family . '/' . $_ } @$lang_dirs),
$path_family;
} else {
unshift @include_path, $path_family;
}
......@@ -493,8 +579,10 @@ sub _get_etc_include_path {
} else {
$path_family = $self->dir;
}
if ($lang) {
unshift @include_path, $path_family . '/' . $lang, $path_family;
if ($lang_dirs) {
unshift @include_path,
(map { $path_family . '/' . $_ } @$lang_dirs),
$path_family;
} else {
unshift @include_path, $path_family;
}
......@@ -508,8 +596,10 @@ sub _get_etc_include_path {
} else {
$path_robot = $self->etc;
}
if ($lang) {
unshift @include_path, $path_robot . '/' . $lang, $path_robot;
if ($lang_dirs) {
unshift @include_path,
(map { $path_robot . '/' . $_ } @$lang_dirs),
$path_robot;
} else {
unshift @include_path, $path_robot;
}
......@@ -525,10 +615,12 @@ sub _get_etc_include_path {
$path_etcbindir = Sympa::Constants::DEFAULTDIR;
$path_etcdir = Site->etc;
}
if ($lang) {
if ($lang_dirs) {
@include_path = (
$path_etcdir . '/' . $lang, $path_etcdir,
$path_etcbindir . '/' . $lang, $path_etcbindir
(map { $path_etcdir . '/' . $_ } @$lang_dirs),
$path_etcdir,
(map { $path_etcbindir . '/' . $_ } @$lang_dirs),
$path_etcbindir
);
} else {
@include_path = ($path_etcdir, $path_etcbindir);
......@@ -821,7 +913,7 @@ sub send_file {
}
## What file
my $lang = &Language::Lang2Locale($data->{'lang'});
my $lang = $data->{'lang'};
my $tt2_include_path = $self->get_etc_include_path('mail_tt2', $lang);
if (ref $self eq 'List') {
## list directory to get the 'info' file
......@@ -1324,7 +1416,8 @@ sub AUTOLOAD {
## getters for site/robot parameters.
$type->{'RobotParameter'} = 1
if grep { $_ eq $attr }
qw(blacklist loging_condition loging_for_module trusted_applications) or
qw(blacklist loging_condition loging_for_module
trusted_applications) or
grep { $_->{'name'} and $_->{'name'} eq $attr } @confdef::params;
## getters for attributes specific to global config.
$type->{'SiteAttribute'} = 1
......@@ -1465,6 +1558,42 @@ sub fullconfig {
return $fullconfig;
}
=over 4
=item lang
I<Getter>.
Gets "lang" parameter, canonicalized if possible.
=back
=cut
#FIXME: inefficient; would be cached.
sub lang {
my $self = shift;
my $lang;
croak "Can't modify \"lang\" attribute" if scalar @_ > 1;
if (ref $self and ref $self eq 'Robot' and
$self->{'etc'} ne Site->etc and
exists Site->robots_config->{$self->{'name'}}{'lang'}) {
$lang = Site->robots_config->{$self->{'name'}}{'lang'};
} elsif (ref $self and ref $self eq 'Robot' or
! ref $self and $self eq 'Site') {
croak "Can't call method \"lang\" on uninitialized $self class"
unless $Site::is_initialized;
$lang = $Conf::Conf{'lang'};
} else {
croak 'bug in loginc. Ask developer';
}
if ($lang) {
$lang = Language::CanonicLang($lang) || $lang;
}
return $lang;
}
=head3 Derived parameters
These are accessors derived from default parameters.
......@@ -1578,7 +1707,8 @@ sub supported_languages {
}
my @lang_list =
map { Language::Lang2Locale($_) } split /\s*,\s*/, $supported_lang;
grep { $_ and $_ = Language::CanonicLang($_) }
split /\s*,\s*/, $supported_lang;
return @lang_list if wantarray;
return \@lang_list;
}
......
......@@ -55,6 +55,11 @@ sub new {
my $self;
return undef unless $who;
## Canonicalize lang if possible
$values{'lang'} =
Language::CanonicLang($values{'lang'}) || $values{'lang'}
if $values{'lang'};
if (!($self = get_global_user($who))) {
## unauthenticated user would not be added to database.
$values{'email'} = $who;
......@@ -334,6 +339,12 @@ sub get_global_user {
&tools::decrypt_password($user->{'password'});
}
## Canonicalize lang if possible
if ($user->{'lang'}) {
$user->{'lang'} =
Language::CanonicLang($user->{'lang'}) || $user->{'lang'};
}
## Turn user_attributes into a hash
my $attributes = $user->{'attributes'};
if (defined $attributes and length $attributes) {
......@@ -428,6 +439,11 @@ sub update_global_user {
$values->{'password'} = &Auth::password_fingerprint($values->{'password'})
if ($values->{'password'});
## Canonicalize lang if possible.
$values->{'lang'} =
Language::CanonicLang($values->{'lang'}) || $values->{'lang'}
if $values->{'lang'};
my ($field, $value);
my ($user, $statement, $table);
......@@ -496,6 +512,11 @@ sub add_global_user {
$values->{'password'} = &Auth::password_fingerprint($values->{'password'})
if ($values->{'password'});
## Canonicalize lang if possible
$values->{'lang'} =
Language::CanonicLang($values->{'lang'}) || $values->{'lang'}
if $values->{'lang'};
return undef unless (my $who = &tools::clean_email($values->{'email'}));
return undef if (is_global_user($who));
......
......@@ -482,7 +482,8 @@ sub get_list_list_tpl {
$list_templates->{$template}{'path'} = $dir;
my $locale = &Language::Lang2Locale( &Language::GetLang());
my $locale = Language::Lang2Locale_old(Language::GetLang());
## FIXME: lang should be used instead of "locale".
## Look for a comment.tt2 in the appropriate locale first
if (-r $dir.'/'.$template.'/'.$locale.'/comment.tt2') {
$list_templates->{$template}{'comment'} =
......@@ -641,14 +642,14 @@ sub get_templates_list {
## The 'ignore_global' option allows to look for files at list level only
unless ($options->{'ignore_global'}) {
push @try, $distrib_dir ;
push @try, $site_dir ;
push @try, $distrib_dir;
push @try, $site_dir;
push @try, $robot_dir;
}
if (defined $list) {
$listdir = $list->dir.'/'.$type.'_tt2';
push @try, $listdir ;
push @try, $listdir;
}
my $i = 0 ;
......@@ -656,26 +657,49 @@ sub get_templates_list {
foreach my $dir (@try) {
next unless opendir (DIR, $dir);
foreach my $file ( grep (!/^\./,readdir(DIR))) {
foreach my $file (grep (!/^\./, readdir(DIR))) {
## Subdirectory for a lang
if (-d $dir.'/'.$file) {
my $lang = $file;
next unless opendir (LANGDIR, $dir.'/'.$lang);
foreach my $file (grep (!/^\./,readdir(LANGDIR))) {
next unless ($file =~ /\.tt2$/);
if ($dir eq $distrib_dir){$tpl->{$file}{'distrib'}{$lang} = $dir.'/'.$lang.'/'.$file;}
if ($dir eq $site_dir) {$tpl->{$file}{'site'}{$lang} = $dir.'/'.$lang.'/'.$file;}
if ($dir eq $robot_dir) {$tpl->{$file}{'robot'}{$lang} = $dir.'/'.$lang.'/'.$file;}
if ($dir eq $listdir) {$tpl->{$file}{'list'}{$lang} = $dir.'/'.$lang.'/'.$file;}
my $lang_dir = $file;
my $lang = Language::CanonicLang($lang_dir);
next unless $lang;
next unless opendir (LANGDIR, $dir . '/' . $lang_dir);
foreach my $file (grep (!/^\./, readdir(LANGDIR))) {
next unless $file =~ /\.tt2$/;
if ($dir eq $distrib_dir) {
$tpl->{$file}{'distrib'}{$lang} =
$dir . '/' . $lang_dir . '/' . $file;
}
if ($dir eq $site_dir) {
$tpl->{$file}{'site'}{$lang} =
$dir . '/' . $lang_dir . '/' . $file;
}
if ($dir eq $robot_dir) {
$tpl->{$file}{'robot'}{$lang} =
$dir . '/' . $lang_dir . '/' . $file;
}
if ($dir eq $listdir) {
$tpl->{$file}{'list'}{$lang} =
$dir . '/' . $lang_dir . '/' . $file;
}
}
closedir LANGDIR;
}else {
next unless ($file =~ /\.tt2$/);
if ($dir eq $distrib_dir){$tpl->{$file}{'distrib'}{'default'} = $dir.'/'.$file;}
if ($dir eq $site_dir) {$tpl->{$file}{'site'}{'default'} = $dir.'/'.$file;}
if ($dir eq $robot_dir) {$tpl->{$file}{'robot'}{'default'} = $dir.'/'.$file;}
if ($dir eq $listdir) {$tpl->{$file}{'list'}{'default'}= $dir.'/'.$file;}
if ($dir eq $distrib_dir) {
$tpl->{$file}{'distrib'}{'default'} = $dir . '/' . $file;
}
if ($dir eq $site_dir) {
$tpl->{$file}{'site'}{'default'} = $dir . '/' . $file;
}
if ($dir eq $robot_dir) {
$tpl->{$file}{'robot'}{'default'} = $dir . '/' . $file;
}
if ($dir eq $listdir) {
$tpl->{$file}{'list'}{'default'} = $dir . '/' . $file;
}
}
}
closedir DIR;
......@@ -696,6 +720,10 @@ sub get_template_path {
my $lang = shift || 'default';
my $list = shift;
##FIXME: path is fixed to older "locale".
my $locale;
$locale = Language::Lang2Locale_old($lang) unless $lang eq 'default';
unless ($type eq 'web' or $type eq 'mail') {
Log::do_log('info', 'internal error incorrect parameter');
return undef;
......@@ -719,7 +747,7 @@ sub get_template_path {
}
$dir .= '/'.$type.'_tt2';
$dir .= '/'.$lang unless $lang eq 'default';
$dir .= '/' . $locale unless $lang eq 'default';
return $dir.'/'.$tpl;
}
......@@ -3312,7 +3340,7 @@ sub wrap_text {
return $text unless $cols;
$text = Text::LineFold->new(
Language => &Language::GetLang(),
Language => Language::GetLang(),
OutputCharset => (&Encode::is_utf8($text)? '_UNICODE_': 'utf8'),
Prep => 'NONBREAKURI',
ColumnsMax => $cols
......
<?xml version="1.0" encoding="utf-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="[% lang_tag %]" xml:lang="[% lang_tag %]" xmlns="http://www.w3.org/1999/xhtml">
<html lang="[% lang %]" xml:lang="[% lang %]" xmlns="http://www.w3.org/1999/xhtml">
<!-- $Id$ -->
<head>
......
<?xml version="1.0" encoding="utf-8" ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="[% lang_tag %]" xml:lang="[% lang_tag %]" xmlns="http://www.w3.org/1999/xhtml">
<html lang="[% lang %]" xml:lang="[% lang %]" xmlns="http://www.w3.org/1999/xhtml">
<!-- $Id$ -->
<head>
......@@ -110,7 +110,7 @@
[% IF action == 'edit_list_request' || action == 'editfile' %]<br /><br />[% END %]
[% PROCESS "${action}.tt2" IF action %]
</div><!-- End div ContentBlock -->
<div class="top"><a href="#top" title="[%|loc%]Top of Page[%END%]"><img src="[% icons_url %]/top.png" alt="[%|loc%]Top of page[%END%]" /></a></div>
<div class="top"><a href="#top" title="[%|loc%]Top of Page[%END%]"><img src="[% icons_url %]/top.png" alt="[%|loc%]Top of Page[%END%]" /></a></div>
</div><!-- End div Paint -->
</div><!-- end div Stretcher -->
......
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="[% lang_tag %]" xml:lang="[% lang_tag %]" xmlns="http://www.w3.org/1999/xhtml">
<!-- $Id$ -->
<html lang="[% lang %]" xml:lang="[% lang %]" xmlns="http://www.w3.org/1999/xhtml">
<!-- $Id$ -->
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="[% css_url %]/style.css" type="text/css" media="screen" title="Derived from style Blank Canvas by tw3k AT tw3k.tw3k.q3machines.net" />
......
......@@ -144,6 +144,12 @@ sub load {
}
my %datas= &tools::string_2_hash($session->{'data'});
## canonicalize lang if possible.
$datas{'lang'} =
Language::CanonicLang($datas{'lang'}) || $datas{'lang'}
if $datas{'lang'};
foreach my $key (keys %datas) {$self->{$key} = $datas{$key};}
$self->{'id_session'} = $session->{'id_session'};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment