From 62f52e2d6d252437b038f49ae5403d40094f82d6 Mon Sep 17 00:00:00 2001 From: Jonathan Druart <jonathan.druart@bugs.koha-community.org> Date: Tue, 27 Feb 2018 18:35:41 -0300 Subject: [PATCH] Bug 20307: Language overlay for authorised values --- C4/Koha.pm | 47 +++++------------- Koha/AuthorisedValue.pm | 55 ++++++++++++++++++++++ Koha/AuthorisedValues.pm | 30 +++++++++++- Koha/Schema/Result/AuthorisedValue.pm | 17 ++++++- Koha/Schema/Result/AuthorisedValueLocalization.pm | 32 +++++++++++++ admin/authorised_values.pl | 21 +++------ admin/localization.pl | 16 ++----- .../prog/en/modules/admin/authorised_values.tt | 47 ++++++++++++------ .../prog/en/modules/admin/localization.tt | 4 +- svc/localization | 29 ++++++------ 10 files changed, 204 insertions(+), 94 deletions(-) create mode 100644 Koha/Schema/Result/AuthorisedValueLocalization.pm diff --git a/C4/Koha.pm b/C4/Koha.pm index a15080998a..f198f5b1dc 100644 --- a/C4/Koha.pm +++ b/C4/Koha.pm @@ -547,43 +547,22 @@ sub GetAuthorisedValues { my $result = $cache->get_from_cache($cache_key); return $result if $result; + # FIXME Need to deal with $opac + my $avs = Koha::AuthorisedValues->search_with_localization( + { + ( $category ? ( category => $category ) : () ), + ( $branch_limit ? ( branchcode => $branch_limit ) : () ), + } + ); my @results; - my $dbh = C4::Context->dbh; - my $query = qq{ - SELECT DISTINCT av.* - FROM authorised_values av - }; - $query .= qq{ - LEFT JOIN authorised_values_branches ON ( id = av_id ) - } if $branch_limit; - my @where_strings; - my @where_args; - if($category) { - push @where_strings, "category = ?"; - push @where_args, $category; - } - if($branch_limit) { - push @where_strings, "( branchcode = ? OR branchcode IS NULL )"; - push @where_args, $branch_limit; - } - if(@where_strings > 0) { - $query .= " WHERE " . join(" AND ", @where_strings); - } - $query .= ' ORDER BY category, ' . ( - $opac ? 'COALESCE(lib_opac, lib)' - : 'lib, lib_opac' - ); - - my $sth = $dbh->prepare($query); + while ( my $av = $avs->next ) { + my $av_unblessed = $av->unblessed; + $av_unblessed->{translated_description} = $av->translated_description; + $av_unblessed->{lib} = $av->translated_description; + $av_unblessed->{lib_opac} = $av->translated_description; + push @results, $av_unblessed; - $sth->execute( @where_args ); - while (my $data=$sth->fetchrow_hashref) { - if ($opac && $data->{lib_opac}) { - $data->{lib} = $data->{lib_opac}; - } - push @results, $data; } - $sth->finish; $cache->set_in_cache( $cache_key, \@results, { expiry => 5 } ); return \@results; diff --git a/Koha/AuthorisedValue.pm b/Koha/AuthorisedValue.pm index 898b630279..b60c57d67d 100644 --- a/Koha/AuthorisedValue.pm +++ b/Koha/AuthorisedValue.pm @@ -21,7 +21,9 @@ use Modern::Perl; use Carp; +use C4::Languages; use Koha::Database; +use Koha::Localizations; use base qw(Koha::Object); @@ -143,6 +145,59 @@ sub opac_description { return $self->lib_opac() || $self->lib(); } +=head3 translated_description + +=cut + +sub translated_description { + my ( $self, $lang ) = @_; + if ( my $translated_description = eval { $self->get_column('translated_description') } ) { + # If the value has already been fetched (eg. from sarch_with_localization), + # do not search for it again + # Note: This is a bit hacky but should be fast + return $translated_description + ? $translated_description + : $self->lib; + } + $lang ||= C4::Languages::getlanguage; + my $translated_description = Koha::Localizations->search({ + code => $self->authorised_value, + entity => 'avs', + lang => $lang + })->next; + return $translated_description + ? $translated_description->translation + : $self->lib; +} + +=head3 translated_descriptions + +=cut + +sub translated_descriptions { + my ( $self ) = @_; + my @translated_descriptions = Koha::Localizations->search( + { entity => 'avs', + code => $self->authorised_value, + } + ); + return [ map { + { + lang => $_->lang, + translation => $_->translation, + } + } @translated_descriptions ]; +} + +=head3 image_location + +=cut + +sub image_location { + my ( $self, $interface ) = @_; + return C4::Koha::getitemtypeimagelocation( $interface, $self->SUPER::imageurl ); +} + =head3 _avb_resultset Returns the internal resultset or creates it if undefined diff --git a/Koha/AuthorisedValues.pm b/Koha/AuthorisedValues.pm index 5c73052802..bab3e0ce18 100644 --- a/Koha/AuthorisedValues.pm +++ b/Koha/AuthorisedValues.pm @@ -60,7 +60,10 @@ sub search { ] } : {}; - my $join = $branchcode ? { join => 'authorised_values_branches' } : {}; + + my @join = $attributes->{join} || (); + push @join, 'authorised_values_branches'; + my $join = { join => \@join }; $attributes //= {}; $attributes = { %$attributes, %$join }; return $self->SUPER::search( { %$params, %$or, }, $attributes ); @@ -108,7 +111,7 @@ sub find_by_koha_field { my $kohafield = $params->{kohafield}; my $authorised_value = $params->{authorised_value}; - my $av = $self->SUPER::search( + my $av = $self->search( { 'marc_subfield_structures.frameworkcode' => $frameworkcode, 'marc_subfield_structures.kohafield' => $kohafield, 'me.authorised_value' => $authorised_value, @@ -175,6 +178,29 @@ sub categories { return map $_->get_column('category'), $rs->all; } +=head3 search_with_localization + +my $avs = Koha::AuthorisedValues->search_with_localization + +=cut + +sub search_with_localization { + my ( $self, $params, $attributes ) = @_; + + my $language = C4::Languages::getlanguage(); + $Koha::Schema::Result::AuthorisedValue::LANGUAGE = $language; + $attributes->{order_by} = 'translated_description' unless exists $attributes->{order_by}; + $attributes->{join} = 'localization'; + $attributes->{'+select'} = [ + { + coalesce => [qw( localization.translation me.lib )], + -as => 'translated_description' + } + ]; + $self->search( $params, $attributes ); +} + + =head3 type =cut diff --git a/Koha/Schema/Result/AuthorisedValue.pm b/Koha/Schema/Result/AuthorisedValue.pm index 1a65d388c9..09acafc5e4 100644 --- a/Koha/Schema/Result/AuthorisedValue.pm +++ b/Koha/Schema/Result/AuthorisedValue.pm @@ -148,6 +148,21 @@ __PACKAGE__->has_many( # Created by DBIx::Class::Schema::Loader v0.07046 @ 2019-02-22 14:32:48 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hDlebhEn+f+thqwBo/LOqQ +# Use the ItemtypeLocalization view to create the join on localization +our $LANGUAGE; +__PACKAGE__->has_many( + "localization" => "Koha::Schema::Result::AuthorisedValueLocalization", + sub { + my $args = shift; + + die "no lang specified!" unless $LANGUAGE; + + return ({ + "$args->{self_alias}.authorised_value" => { -ident => "$args->{foreign_alias}.code" }, + "$args->{foreign_alias}.lang" => $LANGUAGE, + }); + + } +); -# You can replace this text with custom code or comments, and it will be preserved on regeneration 1; diff --git a/Koha/Schema/Result/AuthorisedValueLocalization.pm b/Koha/Schema/Result/AuthorisedValueLocalization.pm new file mode 100644 index 0000000000..fa2c69662b --- /dev/null +++ b/Koha/Schema/Result/AuthorisedValueLocalization.pm @@ -0,0 +1,32 @@ +package Koha::Schema::Result::AuthorisedValueLocalization; + +use base 'DBIx::Class::Core'; + +use Modern::Perl; + +__PACKAGE__->table_class('DBIx::Class::ResultSource::View'); + +__PACKAGE__->table('authorised_value_localizations'); +__PACKAGE__->result_source_instance->is_virtual(1); +__PACKAGE__->result_source_instance->view_definition( + "SELECT localization_id, code, lang, translation FROM localization WHERE entity='avs'" +); + +__PACKAGE__->add_columns( + "localization_id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "code", + { data_type => "varchar", is_nullable => 0, size => 64 }, + "lang", + { data_type => "varchar", is_nullable => 0, size => 25 }, + "translation", + { data_type => "text", is_nullable => 1 }, +); + +__PACKAGE__->belongs_to( + "authorised_value", + "Koha::Schema::Result::AuthorisedValue", + { code => 'authorised_value' } +); + +1; diff --git a/admin/authorised_values.pl b/admin/authorised_values.pl index 4f951291e4..4fa66bf33c 100755 --- a/admin/authorised_values.pl +++ b/admin/authorised_values.pl @@ -24,6 +24,7 @@ use C4::Auth; use C4::Context; use C4::Koha; use C4::Output; +use Carp::Always; use Koha::AuthorisedValues; use Koha::AuthorisedValueCategories; @@ -91,8 +92,11 @@ if ($op eq 'add_form') { imagesets => C4::Koha::getImageSets(), ); } + + my $translated_languages = C4::Languages::getTranslatedLanguages( undef , C4::Context->preference('template') ); $template->param( branches_loop => \@branches_loop, + can_be_translated => ( scalar(@$translated_languages) > 1 ? 1 : 0 ), ); } elsif ($op eq 'add') { @@ -220,23 +224,10 @@ if ( $op eq 'list' ) { $searchfield ||= $category_list[0]; - my @avs_by_category = Koha::AuthorisedValues->new->search( { category => $searchfield } ); - my @loop_data = (); - # builds value list - for my $av ( @avs_by_category ) { - my %row_data; # get a fresh hash for the row data - $row_data{category} = $av->category; - $row_data{authorised_value} = $av->authorised_value; - $row_data{lib} = $av->lib; - $row_data{lib_opac} = $av->lib_opac; - $row_data{imageurl} = getitemtypeimagelocation( 'intranet', $av->imageurl ); - $row_data{branches} = $av->branch_limitations; - $row_data{id} = $av->id; - push(@loop_data, \%row_data); - } + my $avs_by_category = Koha::AuthorisedValues->search_with_localization( { category => $searchfield } ); $template->param( - loop => \@loop_data, + authorised_values => $avs_by_category, category => $searchfield, categories => \@category_list, ); diff --git a/admin/localization.pl b/admin/localization.pl index f8bc553c05..368a3f5292 100755 --- a/admin/localization.pl +++ b/admin/localization.pl @@ -40,25 +40,17 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( my $entity = $query->param('entity'); my $code = $query->param('code'); -my $rs = Koha::Localizations->search( { entity => $entity, code => $code } ); -my @translations; -while ( my $s = $rs->next ) { - push @translations, - { id => $s->localization_id, - entity => $s->entity, - code => $s->code, - lang => $s->lang, - translation => $s->translation, - }; -} +my $interface = $query->param('interface'); +my $translations = Koha::Localizations->search( { entity => $entity, code => $code, interface => $interface } ); my $translated_languages = C4::Languages::getTranslatedLanguages( 'intranet', C4::Context->preference('template') ); $template->param( - translations => \@translations, + translations => $translations, languages => $translated_languages, entity => $entity, code => $code, + interface_side => $interface, # "interface" conflicts with existing variable's name ); output_html_with_http_headers $query, $cookie, $template->output; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt index 6ec9973a20..04c25bf536 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt @@ -74,11 +74,16 @@ </li> <li> <label for="lib">Description: </label> - <input type="text" name="lib" id="lib" value="[% lib | html %]" maxlength="200" /> + [% IF can_be_translated %] + <a href="/cgi-bin/koha/admin/localization.pl?entity=avs&code=[% authorised_value | uri %]&interface=intranet"" title="Translate description" rel="gb_page_center[600,500]"><i class="fa fa-pencil"></i> Translate into other languages</a> + [% END %] </li> <li> <label for="lib_opac">Description (OPAC): </label> <input type="text" name="lib_opac" id="lib_opac" value="[% lib_opac | html %]" maxlength="200" /> + [% IF can_be_translated %] + <a href="/cgi-bin/koha/admin/localization.pl?entity=avs&code=[% authorised_value | uri %]&interface=opac" title="Translate OPAC description" rel="gb_page_center[600,500]"><i class="fa fa-pencil"></i> Translate into other languages</a> + [% END %] </li> <li><label for="branches">Libraries limitation: </label> <select id="branches" name="branches" multiple size="10"> @@ -207,7 +212,7 @@ </p> </form> - [% IF loop %] + [% IF authorised_values.count %] <table id="table_authorized_values" class="authorized_values_table"> <thead><tr> @@ -219,30 +224,43 @@ <th>Actions</th> </tr> </thead><tbody> - [% FOREACH loo IN loop %] + [% FOREACH av IN authorised_values %] <tr> - <td>[% loo.authorised_value | html %]</td> - <td>[% loo.lib | html %]</td> - <td>[% loo.lib_opac | html %]</td> - <td>[% IF ( loo.imageurl ) %]<img src="[% loo.imageurl | url %]" alt=""/>[% ELSE %] [% END %]</td> + <td>[% av.authorised_value | html %]</td> + [% IF av.translated_descriptions.size %] + [% av.lib | html %] (default)<br/> + [% FOR description IN av.translated_descriptions %] + [% IF description.translation == av.translated_description %] + <b>[% description.translation | html %]</b> + [% ELSE %] + [% description.translation | html %] ([% description.lang | html %]) + [% END %] + <br/> + [% END %] + [% ELSE %] + [% av.lib |html %] + [% END %] + + <td>[% av.lib_opac | html %]</td> + <td>[% IF ( av.imageurl ) %]<img src="[% av.imageurl | url %]" alt=""/>[% ELSE %] [% END %]</td> <td> - [% IF loo.branches.size > 0 %] + [% IF av.branch_limitations.size > 0 %] [% branches_str = "" %] - [% FOREACH branch IN loo.branches %] + [% FOREACH branch IN av.branches_limitation %] [% branches_str = branches_str _ " " _ branch.branchname _ "(" _ branch.branchcode _ ")" %] [% END %] <span href="#" title="[% branches_str | html %]"> - [% IF loo.branches.size > 1 %] - [% loo.branches.size | html %] branches limitations + [% IF av.branches.size > 1 %] + [% av.branches_limitaion.size | html %] branches limitations [% ELSE %] - [% loo.branches.size | html %] branch limitation + [% av.branches_limitation.size | html %] branch limitation [% END %] [% ELSE %] No limitation [% END %] </td> - <td class="actions"><a href="/cgi-bin/koha/admin/authorised_values.pl?op=add_form&id=[% loo.id | uri %]" class="btn btn-default btn-xs"><i class="fa fa-pencil"></i> Edit</a> - <a class="delete btn btn-default btn-xs" href="/cgi-bin/koha/admin/authorised_values.pl?op=delete&searchfield=[% searchfield | uri %]&id=[% loo.id | uri %]"><i class="fa fa-trash"></i> Delete</a></td> + <td class="actions"><a href="/cgi-bin/koha/admin/authorised_values.pl?op=add_form&id=[% av.id | uri %]" class="btn btn-default btn-xs"><i class="fa fa-pencil"></i> Edit</a> + <a class="delete btn btn-default btn-xs" href="/cgi-bin/koha/admin/authorised_values.pl?op=delete&searchfield=[% searchfield | uri %]&id=[% av.id | uri %]"><i class="fa fa-trash"></i> Delete</a></td> </tr> [% END # /FOREACH loop %] </tbody></table> @@ -297,6 +315,7 @@ [% MACRO jsinclude BLOCK %] [% Asset.js("js/admin-menu.js") | $raw %] + [% INCLUDE 'greybox.inc' %] [% INCLUDE 'datatables.inc' %] <script> $(document).ready(function() { diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt index 6952ba03ab..918670fd9e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt @@ -11,6 +11,7 @@ <form id="add_translation" method="post"> <input type="hidden" name="entity" value="[% entity | html %]" /> <input type="hidden" name="code" value="[% code | html %]" /> + <input type="hidden" name="interface" value="[% interface_side | html %]" /> Lang: <select name="lang"> [% FOR language IN languages %] [% FOR sublanguage IN language.sublanguages_loop %] @@ -211,9 +212,10 @@ e.preventDefault(); var entity = $(this).find('input[name="entity"]').val(); var code = $(this).find('input[name="code"]').val(); + var interface = $(this).find('input[name="interface"]').val(); var lang = $(this).find('select[name="lang"] option:selected').val(); var translation = $(this).find('input[name="translation"]').val(); - var data = "entity=" + encodeURIComponent(entity) + "&code=" + encodeURIComponent(code) + "&lang=" + encodeURIComponent(lang) + "&translation=" + encodeURIComponent(translation); + var data = "entity=" + encodeURIComponent(entity) + "&code=" + encodeURIComponent(code) + "&interface=" + encodeURIComponent(interface) + "&lang=" + encodeURIComponent(lang) + "&translation=" + encodeURIComponent(translation); $.ajax({ data: data, type: 'POST', diff --git a/svc/localization b/svc/localization index 6eed60632c..02ec33f7d5 100755 --- a/svc/localization +++ b/svc/localization @@ -9,18 +9,14 @@ use Koha::Localizations; our ( $query, $response ) = C4::Service->init( parameters => 'manage_itemtypes' ); sub get_translations { - my $rs = Koha::Localizations->search({ entity => $query->param('entity'), code => $query->param('code') }); - my @translations; - while ( my $s = $rs->next ) { - push @translations, { - id => $s->localization_id, - entity => $s->entity, - code => $s->code, - lang => $s->lang, - translation => $s->translation, + my $translations = Koha::Localizations->search( + { + entity => $query->param('entity'), + code => $query->param('code'), + interface => $query->param('interface') } - } - $response->param( translations => \@translations ); + ); + $response->param( translations => $translations ); C4::Service->return_success( $response ); } @@ -64,13 +60,15 @@ sub add_translation { my $code = $query->param('code'); my $lang = $query->param('lang'); my $translation = $query->param('translation'); + my $interface = $query->param('interface') || undef; - unless ( Koha::Localizations->search({entity => $entity, code => $code, lang => $lang, })->count ) { + unless ( Koha::Localizations->search({entity => $entity, code => $code, interface => $interface, lang => $lang })->count ) { my $localization = Koha::Localization->new( { - entity => $entity, - code => $code, - lang => $lang, + entity => $entity, + interface => $interface, + code => $code, + lang => $lang, translation => $translation, } ); @@ -78,6 +76,7 @@ sub add_translation { $response->param( id => $localization->localization_id, entity => $localization->entity, + interface => $localization->interface, code => $localization->code, lang => $localization->lang, translation => $localization->translation, -- 2.11.0