From 40818e3cc2edfd6aee7c6556fda979d5b2512765 Mon Sep 17 00:00:00 2001 From: Marcel de Rooy Date: Fri, 28 Jun 2013 11:21:22 +0200 Subject: [PATCH] Bug 10509: Using i18n function for translation of MySQL web installer files This patch makes the changes needed to progressively use a i18n function to translate strings in the web installer's MySQL files. The English scripts may contain fields like i18n(columnvalue); for English i18n(a) is a, but for the other languages i18n(a) is the translation of a. The corresponding script in the language folder contains the i18n definition. The work is done in such a way that current installations are not affected. Subsequent patches will make the changes in the .sql files themselves. This can be done per folder, per language. Using the extension .i18n in the last subfolder name triggers the new translation mechanism. (See also test plan.) In Installer.pm the all_languages parameter is removed from load_sql_in_order. This code was not used. This change also affects the call in install.pl. The most important change is the use of a new subroutine _run_mysql_file in load_sql. This new routine contains the above logic. Although I also tested changing marc_framework_sql_list and sample_data_sql_list, it proved imo to be easier (and more maintainable) to do this via load_sql. Test plan: Since no .sql files are changed in this patch, please test if you can install English and e.g. German (or another one) in the web installer without any changes. Bonus points for the following additional tests :) They serve to illustrate the i18n concept more clearly. 1) Place in en/mandatory/userflags.sql around a few strings i18n('...'). Run English install again and check the userflags table. No changes expected. 2) Place in de-DE/mandatory/userflags.sql i18n around a few strings too. Also precede the insert statements with this definition: DROP FUNCTION IF EXISTS i18n; CREATE FUNCTION i18n (d text) RETURNS text DETERMINISTIC RETURN concat(d,'xx'); Now run German install again; some of the userflag strings (with i18n) should now end with xx. 3) Before retesting German install, make some changes: Edit en/optional/sample_holidays.sql. Add i18n calls around strings. Create an additional folder optional.i18n in de-DE. Copy sample_holidays.sql and sample_holidays.txt from de-DE/optional. Edit de-DE/optional.i18n/sample_holidays.sql. Remove all text! Add: DROP FUNCTION IF EXISTS i18n; CREATE FUNCTION i18n (d text) RETURNS text DETERMINISTIC RETURN CASE d WHEN 'Sundays' THEN 'Sonntag' ELSE d END; Now run German install again; in the optional part of the install mark sample holidays (in the last section standing separately; do not confuse with the other one). Check the repeatable_holidays table afterwards. The string above should have been translated only, the others are still English. Undo the changes in .sql files; remove optional.i18n folder. Signed-off-by: Kyle M Hall --- C4/Installer.pm | 66 +++++++++++++++++++++++++++++++++++++------------- installer/install.pl | 14 +++------- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/C4/Installer.pm b/C4/Installer.pm index 5bb9662..089c093 100644 --- a/C4/Installer.pm +++ b/C4/Installer.pm @@ -35,7 +35,7 @@ C4::Installer my $all_languages = getAllLanguages(); my $error = $installer->load_db_schema(); my $list = $installer->sql_file_list('en', 'marc21', { optional => 1, mandatory => 1 }); - my ($fwk_language, $error_list) = $installer->load_sql_in_order($all_languages, @$list); + my ($fwk_language, $error_list) = $installer->load_sql_in_order(@$list); $installer->set_version_syspref(); $installer->set_marcflavour_syspref('MARC21'); @@ -173,6 +173,7 @@ sub marc_framework_sql_list { $cell{"frameworks"} = \@fwks; $cell{"label"} = ucfirst($requirelevel); + $cell{label} =~ s/\.i18n$//; # remove extension from label $cell{"code"} = lc($requirelevel); push @fwklist, \%cell; } @@ -250,6 +251,7 @@ sub sample_data_sql_list { $cell{"frameworks"} = \@fwks; $cell{"label"} = ucfirst($requirelevel); + $cell{label} =~ s/\.i18n$//; # remove extension from label $cell{"code"} = lc($requirelevel); push @levellist, \%cell; } @@ -313,7 +315,7 @@ sub load_db_schema { =head2 load_sql_in_order - my ($fwk_language, $list) = $installer->load_sql_in_order($all_languages, @sql_list); + my ($list) = $installer->load_sql_in_order(@sql_list); Given a list of SQL scripts supplied in C<@sql_list>, loads each of them into the database and sets the FrameworksLoaded system preference to names @@ -332,14 +334,10 @@ The return value C<$list> is an arrayref containing a hashref for each a list of hashrefs containing a list of each script load and any error messages associated with the loading of each script. -B The C<$fwk_language> code probably doesn't belong and needs to be -moved to a different method. - =cut sub load_sql_in_order { my $self = shift; - my $all_languages = shift; my @sql_list = @_; my $lang; @@ -377,15 +375,6 @@ sub load_sql_in_order { chop $systempreference; my @list; map { push @list, { "level" => $_, "fwklist" => $hashlevel{$_} } } keys %hashlevel; - my $fwk_language; - for my $each_language (@$all_languages) { - - # warn "CODE".$each_language->{'language_code'}; - # warn "LANG:".$lang; - if ( $lang eq $each_language->{'language_code'} ) { - $fwk_language = $each_language->{language_locale_name}; - } - } my $updateflag = $self->{'dbh'}->do( "UPDATE systempreferences set value=\"$systempreference\" where variable='FrameworksLoaded'" @@ -397,7 +386,7 @@ sub load_sql_in_order { my $rq = $self->{'dbh'}->prepare($string); $rq->execute; } - return ($fwk_language, \@list); + return \@list; } =head2 set_marcflavour_syspref @@ -495,7 +484,7 @@ sub load_sql { . ( $self->{user} ? " -u $self->{user} " : "" ) . ( $self->{password} ? " -p'$self->{password}'" : "" ) . " $self->{dbname} "; - $error = qx($strcmd --default-character-set=utf8 <$filename 2>&1 1>/dev/null); + $error = _run_mysql_file($strcmd, $filename); } elsif ( $self->{dbms} eq 'Pg' ) { $cmd = qx(which psql 2>/dev/null || whereis psql 2>/dev/null); chomp $cmd; @@ -520,6 +509,49 @@ sub load_sql { return $error; } +sub _run_mysql_file { + my ($cmd, $filename) = @_; + my $i18n_drop='DROP FUNCTION IF EXISTS i18n;'; + my $i18n_fake='CREATE FUNCTION i18n (d text) '. + 'RETURNS text DETERMINISTIC RETURN d;'; + my $utf8= '--default-character-set=utf8'; + my $error=''; + if( $filename =~ /installer\/data\/mysql\/en\//i || + $filename !~ /\.i18n\/[^\/]+\.sql$/i ) { #en or old style + $error= qx($cmd $utf8 -e '$i18n_drop $i18n_fake' 2>&1 1>/dev/null); + #make sure i18n does not translate + $error.= qx($cmd $utf8 <$filename 2>&1 1>/dev/null); + #run sql with inserts + } + else { #new i18n style: redefine i18n function and run english insert + foreach my $f ($filename, _tr_sql_fname($filename) ) { + $error.= qx($cmd $utf8 <$f 2>&1 1>/dev/null); + } + } + return $error; +} + +sub _tr_sql_fname { + #Convert native name to English equivalent + #Translating subfolder names is still needed + my $file= shift; + $file=~ s/\.i18n(\/[^\/]+)$/$1/; #strip i18n from last subfolder + $file=~ s/(?<=installer\/data\/mysql\/)[^\/]+/en/; + #paranoid lookbehind or just being cautious :) change language to en + my $trans= { '1-obligatoire' => 'mandatory', '2-optionel' => 'optional', + 'obligatoire' => 'mandatory', 'optionel' => 'optional', + '1-obligatorisk' => 'mandatory', '2-valgfritt' => 'optional', + 'obligatorisk' => 'mandatory', 'valgfritt' => 'optional', + 'necessari' => 'mandatory', 'opzionali' => 'optional', + }; + foreach my $sub (keys %$trans) { + my $t=$trans->{lc $sub}; + $file=~ s/(installer\/data\/mysql\/.*)\/$sub\//$1\/$t\//gi; + #again ensure that we are only in last part of path + } + return $file; +} + =head2 get_file_path_from_name my $filename = $installer->get_file_path_from_name('script_name'); diff --git a/installer/install.pl b/installer/install.pl index 58388cb..7ea6be5 100755 --- a/installer/install.pl +++ b/installer/install.pl @@ -18,14 +18,11 @@ my $query = new CGI; my $step = $query->param('step'); my $language = $query->param('language'); -my ( $template, $loggedinuser, $cookie ); - -my $all_languages = getAllLanguages(); - if ( defined($language) ) { C4::Templates::setlanguagecookie( $query, $language, "install.pl?step=1" ); } -( $template, $loggedinuser, $cookie ) = get_template_and_user( + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { template_name => "installer/step" . ( $step ? $step : 1 ) . ".tmpl", query => $query, @@ -201,11 +198,8 @@ elsif ( $step && $step == 3 ) { # 1ST install, 3rd sub-step : insert the SQL files the user has selected # - my ($fwk_language, $list) = $installer->load_sql_in_order($all_languages, $query->param('framework')); - $template->param( - "fwklanguage" => $fwk_language, - "list" => $list - ); + my $list = $installer->load_sql_in_order( $query->param('framework') ); + $template->param( "list" => $list ); $template->param( "$op" => 1 ); } elsif ( $op && $op eq 'selectframeworks' ) { -- 1.7.2.5