Bug 14100: Generic solution for language overlay - Item types

Test plan:
1/ update the Schema (misc/devel/update_dbix_class_files.pl)
2/ Translate templates for some languages (es-DE, de-DE for instance)
3/ Enable them in the pref (search for 'lang') for the staff interface
4/ Go on the item type admin page (admin/itemtypes.pl)
5/ Edit one
6/ Click on the 'translate for other languages' link
7/ You are now on the interface to translate the item type's description
in the languages you want. So translate some :)
8/ Go back on the item type list view (admin/itemtypes.pl)
9/ You should see the original description (non translated)
10/ Switch the language
11/ You should see the translated description in the correct language.
If the description is non translated, the original description is
displayed.

12/ On the different page where the item type is displayed, confirm that
the translated description appears.

Think further / Todo:
1/ Update all occurrences of the item type's description (DONE)
2/ Implement for authorised values
3/ Implement for syspref value (at least textarea)
4/ Implement for branch names
5/ Centralize all the translation on a single page in the admin area
...
N/ Implement a webservice to centralize all the translations and give
the ability to sync the item types/authorised values description with
the rest of the world (push and pull).

Signed-off-by: Josef Moravec <josef.moravec@gmail.com>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This commit is contained in:
Jonathan Druart 2015-04-30 17:30:47 +02:00 committed by Tomas Cohen Arazi
parent 66e9384df9
commit 0f63f89f66
19 changed files with 581 additions and 90 deletions

View File

@ -3027,13 +3027,12 @@ sub PrepareItemrecordDisplay {
#----- itemtypes
} elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
my $sth = $dbh->prepare( "SELECT itemtype,description FROM itemtypes ORDER BY description" );
$sth->execute;
my $itemtypes = GetItemTypes( style => 'array' );
push @authorised_values, ""
unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
push @authorised_values, $itemtype;
$authorised_lib{$itemtype} = $description;
for my $itemtype ( @$itemtypes ) {
push @authorised_values, $itemtype->{itemtype};
$authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
}
#---- class_sources
} elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {

View File

@ -254,15 +254,30 @@ sub GetItemTypes {
my ( %params ) = @_;
my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash';
my $language = C4::Languages::getlanguage();
# returns a reference to a hash of references to itemtypes...
my %itemtypes;
my $dbh = C4::Context->dbh;
my $query = qq|
SELECT *
my $query = q|
SELECT
itemtypes.itemtype,
itemtypes.description,
itemtypes.rentalcharge,
itemtypes.notforloan,
itemtypes.imageurl,
itemtypes.summary,
itemtypes.checkinmsg,
itemtypes.checkinmsgtype,
itemtypes.sip_media_type,
COALESCE( localization.translation, itemtypes.description ) AS translated_description
FROM itemtypes
LEFT JOIN localization ON itemtypes.itemtype = localization.code
AND localization.entity = 'itemtypes'
AND localization.lang = ?
ORDER BY itemtype
|;
my $sth = $dbh->prepare($query);
$sth->execute;
$sth->execute( $language );
if ( $style eq 'hash' ) {
while ( my $IT = $sth->fetchrow_hashref ) {
@ -540,14 +555,30 @@ Defaults to intranet.
sub getitemtypeinfo {
my ($itemtype, $interface) = @_;
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
$sth->execute($itemtype);
my $res = $sth->fetchrow_hashref;
my $dbh = C4::Context->dbh;
my $language = C4::Languages::getlanguage();
my $it = $dbh->selectrow_hashref(q|
SELECT
itemtypes.itemtype,
itemtypes.description,
itemtypes.rentalcharge,
itemtypes.notforloan,
itemtypes.imageurl,
itemtypes.summary,
itemtypes.checkinmsg,
itemtypes.checkinmsgtype,
itemtypes.sip_media_type,
COALESCE( localization.translation, itemtypes.description ) AS translated_description
FROM itemtypes
LEFT JOIN localization ON itemtypes.itemtype = localization.code
AND localization.entity = 'itemtypes'
AND localization.lang = ?
WHERE itemtypes.itemtype = ?
|, undef, $language, $itemtype );
$res->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $res->{imageurl} );
$it->{imageurl} = getitemtypeimagelocation( ( ( defined $interface && $interface eq 'opac' ) ? 'opac' : 'intranet' ), $it->{imageurl} );
return $res;
return $it;
}
=head2 getitemtypeimagedir

View File

@ -1873,15 +1873,9 @@ sub searchResults {
#Build itemtype hash
#find itemtype & itemtype image
my %itemtypes;
$bsth =
$dbh->prepare(
"SELECT itemtype,description,imageurl,summary,notforloan FROM itemtypes"
);
$bsth->execute();
while ( my $bdata = $bsth->fetchrow_hashref ) {
foreach (qw(description imageurl summary notforloan)) {
$itemtypes{ $bdata->{'itemtype'} }->{$_} = $bdata->{$_};
}
my $itemtypes = GetItemTypes( style => 'array' );
for my $itemtype ( @$itemtypes ) {
$itemtypes{ $itemtype->{itemtype} } = $itemtype;
}
#search item field code

28
Koha/Localization.pm Normal file
View File

@ -0,0 +1,28 @@
package Koha::Localization;
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Koha; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
use Modern::Perl;
use Koha::Database;
use base qw(Koha::Object);
sub type {
return 'Localization';
}
1;

34
Koha/Localizations.pm Normal file
View File

@ -0,0 +1,34 @@
package Koha::Localizations;
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Koha; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
use Modern::Perl;
use Koha::Database;
use Koha::Localization;
use base qw(Koha::Objects);
sub type {
return 'Localization';
}
sub object_class {
return 'Koha::Localization';
}
1;

View File

@ -27,11 +27,8 @@ use C4::Koha;
sub GetDescription {
my ( $self, $itemtype ) = @_;
my $query = "SELECT description FROM itemtypes WHERE itemtype = ?";
my $sth = C4::Context->dbh->prepare($query);
$sth->execute($itemtype);
my $d = $sth->fetchrow_hashref();
return $d->{description}
my $itemtype = C4::Koha::getitemtypeinfo( $itemtype );
return $itemtype->{translated_description};
}

View File

@ -52,18 +52,7 @@ use C4::Context;
use C4::Auth;
use C4::Output;
sub StringSearch {
my ( $searchstring, $type ) = @_;
my $dbh = C4::Context->dbh;
$searchstring =~ s/\'/\\\'/g;
my @data = split( ' ', $searchstring );
my $sth = $dbh->prepare(
"SELECT * FROM itemtypes WHERE (description LIKE ?) ORDER BY itemtype"
);
$sth->execute("$data[0]%");
return $sth->fetchall_arrayref({}); # return ref-to-array of ref-to-hashes
# like [ fetchrow_hashref(), fetchrow_hashref() ... ]
}
use Koha::Localizations;
my $input = new CGI;
my $searchfield = $input->param('description');
@ -99,8 +88,26 @@ if ( $op eq 'add_form' ) {
#---- if primkey exists, it's a modify action, so read values to modify...
my $data;
if ($itemtype) {
my $sth = $dbh->prepare("select * from itemtypes where itemtype=?");
$sth->execute($itemtype);
my $sth = $dbh->prepare(q|
SELECT
itemtypes.itemtype,
itemtypes.description,
itemtypes.rentalcharge,
itemtypes.notforloan,
itemtypes.imageurl,
itemtypes.summary,
itemtypes.checkinmsg,
itemtypes.checkinmsgtype,
itemtypes.sip_media_type,
COALESCE( localization.translation, itemtypes.description ) AS translated_description
FROM itemtypes
LEFT JOIN localization ON itemtypes.itemtype = localization.code
AND localization.entity='itemtypes'
AND localization.lang = ?
WHERE itemtype = ?
|);
my $language = C4::Languages::getlanguage();
$sth->execute($language, $itemtype);
$data = $sth->fetchrow_hashref;
}
@ -259,11 +266,24 @@ elsif ( $op eq 'delete_confirmed' ) {
}
if ( $op eq 'list' ) {
my ($results) = StringSearch( $searchfield, 'web' );
my $results = C4::Koha::GetItemTypes( style => 'array' );
my @loop;
foreach my $itemtype ( @{$results} ) {
$itemtype->{imageurl} = getitemtypeimagelocation( 'intranet', $itemtype->{imageurl} );
$itemtype->{rentalcharge} = sprintf( '%.2f', $itemtype->{rentalcharge} );
my @translated_descriptions = Koha::Localizations->search(
{ entity => 'itemtypes',
code => $itemtype->{itemtype},
}
);
$itemtype->{translated_descriptions} = [ map {
{
lang => $_->lang,
translation => $_->translation,
}
} @translated_descriptions ];
push( @loop, $itemtype );
}

64
admin/localization.pl Executable file
View File

@ -0,0 +1,64 @@
#!/usr/bin/perl
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use C4::Auth;
use C4::Output;
use Koha::Localization;
use Koha::Localizations;
use CGI qw( -utf8 );
my $query = new CGI;
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
{ template_name => "admin/localization.tt",
authnotrequired => 0,
flagsrequired => { parameters => 'parameters_remaining_permissions' },
query => $query,
type => "intranet",
debug => 1,
}
);
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 $translated_languages = C4::Languages::getTranslatedLanguages( 'intranet', C4::Context->preference('template') );
$template->param(
translations => \@translations,
languages => $translated_languages,
entity => $entity,
code => $code,
);
output_html_with_http_headers $query, $cookie, $template->output;

View File

@ -83,23 +83,17 @@ sub build_authorized_values_list {
push @authorised_values, $branchcode;
$authorised_lib{$branchcode} = $branchname;
}
#----- itemtypes
}
elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
my $sth =
$dbh->prepare(
"select itemtype,description from itemtypes order by description");
$sth->execute;
push @authorised_values, ""
unless ( $tagslib->{$tag}->{$subfield}->{mandatory}
&& ( $value || $tagslib->{$tag}->{$subfield}->{defaultvalue} ) );
my $itemtype;
while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
push @authorised_values, $itemtype;
$authorised_lib{$itemtype} = $description;
my $itemtypes = GetItemTypes( style => 'array' );
for my $itemtype ( @$itemtypes ) {
push @authorised_values, $itemtype->{itemtype};
$authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
}
$value = $itemtype unless ($value);

View File

@ -266,7 +266,7 @@ foreach my $advanced_srch_type (@advanced_search_types) {
my %row =( number=>$cnt++,
ccl => "$itype_or_itemtype,phr",
code => $thisitemtype,
description => $itemtypes->{$thisitemtype}->{'description'},
description => $itemtypes->{$thisitemtype}->{translated_description},
imageurl=> getitemtypeimagelocation( 'intranet', $itemtypes->{$thisitemtype}->{'imageurl'} ),
);
push @itypesloop, \%row;

View File

@ -184,26 +184,19 @@ sub build_authorized_values_list {
$authorised_lib{$thisbranch} = $branches->{$thisbranch}->{'branchname'};
}
#----- itemtypes
}
elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
my $sth =
$dbh->prepare(
"select itemtype,description from itemtypes order by description");
$sth->execute;
push @authorised_values, ""
unless ( $tagslib->{$tag}->{$subfield}->{mandatory}
&& ( $value || $tagslib->{$tag}->{$subfield}->{defaultvalue} ) );
my $itemtype;
while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
push @authorised_values, $itemtype;
$authorised_lib{$itemtype} = $description;
my $itemtypes = GetItemTypes( style => 'array' );
for my $itemtype ( @$itemtypes ) {
push @authorised_values, $itemtype->{itemtype};
$authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
}
$value = $itemtype unless ($value);
#---- class_sources
}
elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "cn_source" ) {
push @authorised_values, ""

View File

@ -177,13 +177,12 @@ sub generate_subfield_form {
}
elsif ( $subfieldlib->{authorised_value} eq "itemtypes" ) {
push @authorised_values, "" unless ( $subfieldlib->{mandatory} );
my $sth = $dbh->prepare("SELECT itemtype,description FROM itemtypes ORDER BY description");
$sth->execute;
while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
push @authorised_values, $itemtype;
$authorised_lib{$itemtype} = $description;
my $itemtypes = GetItemTypes( style => 'array' );
for my $itemtype ( @$itemtypes ) {
push @authorised_values, $itemtype->{itemtype};
$authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
}
unless ( $value ) {
my $itype_sth = $dbh->prepare("SELECT itemtype FROM biblioitems WHERE biblionumber = ?");
$itype_sth->execute( $biblionumber );

View File

@ -0,0 +1,8 @@
CREATE TABLE `localization` (
localization_id int(11) NOT NULL AUTO_INCREMENT,
entity varchar(16) COLLATE utf8_unicode_ci NOT NULL,
code varchar(64) COLLATE utf8_unicode_ci NOT NULL,
lang varchar(25) COLLATE utf8_unicode_ci NOT NULL,
translation text COLLATE utf8_unicode_ci,
PRIMARY KEY (localization_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

View File

@ -3563,6 +3563,20 @@ CREATE TABLE `additional_field_values` (
CONSTRAINT `afv_fk` FOREIGN KEY (`field_id`) REFERENCES `additional_fields` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- Table structure for table 'localization'
--
DROP TABLE IF EXISTS localization;
CREATE TABLE `localization` (
localization_id int(11) NOT NULL AUTO_INCREMENT,
entity varchar(16) COLLATE utf8_unicode_ci NOT NULL,
code varchar(64) COLLATE utf8_unicode_ci NOT NULL,
lang varchar(25) COLLATE utf8_unicode_ci NOT NULL, --could be a foreign key
translation text COLLATE utf8_unicode_ci,
PRIMARY KEY (localization_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;

View File

@ -20,6 +20,7 @@ Data deleted
</title>
[% INCLUDE 'doc-head-close.inc' %]
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
[% INCLUDE 'greybox.inc' %]
[% INCLUDE 'datatables.inc' %]
<script type="text/javascript">
//<![CDATA[
@ -124,7 +125,9 @@ Item types administration
</li>
[% END %]
<li>
<label for="description" class="required">Description: </label><input type="text" id="description" name="description" size="48" value="[% description |html %]" required="required" /> <span class="required">Required</span></li>
<label for="description" class="required">Description: </label><input type="text" id="description" name="description" size="48" value="[% description |html %]" required="required" /> <span class="required">Required</span>
<a href="/cgi-bin/koha/admin/localization.pl?entity=itemtypes&code=[% itemtype %]" title="Translate" rel="gb_page_center[600,500]"><i class="icon-edit"></i> Translate for other languages</a>
</li>
<li>
<span class="label">Search category</span>
<select id="searchcategory" name="searchcategory">
@ -143,7 +146,6 @@ Item types administration
</select>
(Options are defined as the authorized values for the ITEMTYPECAT category)
</li>
[% IF ( noItemTypeImages ) %]
<li><span class="label">Image: </span>Item type images are disabled. To enable them, turn off the <a href="/cgi-bin/koha/admin/preferences.pl?op=search&amp;searchfield=noItemTypeImages">noItemTypeImages system preference</a></li></ol>
[% ELSE %]</ol>
@ -281,7 +283,7 @@ Item types administration
<td>[% itemtype %]</td>
</tr>
<tr><th scope="row">Description</th><td>[% description %]</td></tr>
<tr><th scope="row">Description</th><td>[% translated_description %]</td></tr>
<tr><th scope="row">Loan length</th><td>[% loanlength %]</td></tr>
<tr><th scope="row">Rental charge</th><td>[% rentalcharge %]</td></tr></table>
<form action="[% script_name %]" method="post">
@ -319,7 +321,21 @@ Item types administration
[% loo.itemtype %]
</a>
</td>
<td>[% loo.description %]</td>
<td>
[% IF loo.translated_descriptions.size %]
[% loo.description %] (default)<br/>
[% FOR description IN loo.translated_descriptions %]
[% IF description.translation == loo.translated_description %]
<b>[% description.translation %]</b>
[% ELSE %]
[% description.translation %] ([% description.lang %])
[% END %]
<br/>
[% END %]
[% ELSE %]
[% loo.description %]
[% END %]
</td>
<td>[% loo.searchcategory %]</td>
<td>[% IF ( loo.notforloan ) %]Yes[% ELSE %]&nbsp;[% END %]</td>
<td>[% IF ( loo.hideinopac ) %]Yes[% ELSE %]&nbsp;[% END %]</td>

View File

@ -0,0 +1,212 @@
[% INCLUDE 'doc-head-open.inc' %]
<title>Koha &rsaquo; Localization</title>
[% INCLUDE 'doc-head-close.inc' %]
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
[% INCLUDE 'greybox.inc' %]
[% INCLUDE 'datatables.inc' %]
<script type="text/javascript">
//<![CDATA[
function show_message( params ) {
var type = params.type;
var data = params.data;
var messages = $("#messages");
var message;
if ( type == 'success_on_update' ) {
message = $('<div class="dialog message"></div>');
message.text("Entity %s (code %s) for lang %s has correctly been updated with '%s'".format(data.entity, data.code, data.lang, data.translation));
} else if ( type == 'error_on_update' ) {
message = $('<div class="dialog alert"></div>');
message.text("An error occurred when updating this translation");
} else if ( type == 'success_on_delete' ) {
message = $('<div class="dialog message"></div>');
message.text("The translation (id %s) has been removed successfully".format(data.id));
} else if ( type == 'error_on_delete' ) {
message = $('<div class="dialog alert"></div>');
message.text("An error occurred when deleting this translation");
} else if ( type == 'success_on_insert' ) {
message = $('<div class="dialog message"></div>');
message.text("Translation (id %s) has been added successfully".format(data.id));
} else if ( type == 'error_on_insert' ) {
message = $('<div class="dialog alert"></div>');
message.text("An error occurred when adding this translation");
}
$(messages).append(message);
setTimeout(function(){
message.hide()
}, 3000);
}
function send_update_request( data, cell ) {
$.ajax({
data: data,
type: 'PUT',
url: '/cgi-bin/koha/svc/localization',
success: function (data) {
if ( data.is_changed ) {
$(cell).css('background-color', '#00FF00');
show_message({ type: 'success_on_update', data: data });
}
if ( $(cell).hasClass('lang') ) {
$(cell).text(data.lang)
} else if ( $(cell).hasClass('translation') ) {
$(cell).text(data.translation)
}
},
error: function (data) {
$(cell).css('background-color', '#FF0000');
if ( $(cell).hasClass('lang') ) {
$(cell).text(data.lang)
} else if ( $(cell).hasClass('translation') ) {
$(cell).text(data.translation)
}
show_message({ type: 'error_on_update', data: data });
},
});
}
function send_delete_request( id, cell ) {
$.ajax({
type: 'DELETE',
url: '/cgi-bin/koha/svc/localization/?id='+id,
success: function (data) {
$("#localization").DataTable().row( '#row_id_' + id ).remove().draw();
show_message({ type: 'success_on_delete', data: data });
},
error: function (data) {
$(cell).css('background-color', '#FF0000');
show_message({ type: 'error_on_delete', data: data });
},
});
}
$(document).ready(function() {
$(".dialog").hide();
var table = $("#localization").DataTable($.extend(true, {}, dataTablesDefaults, {
'bPaginate': false,
}));
var languages_select = $('<select name="lang"></select>');
[% FOR language IN languages %]
var option = $('<option value="[% language.lang %]">[% language.description %]</option>');
$(languages_select).append(option);
[% END %]
$("td.translation").on('focus', function(){
$(this).css('background-color', '');
});
$("td.lang").on('click', function(){
var td = this;
var lang = $(td).text();
$(td).css('background-color', '');
var my_select = $(languages_select).clone();
$(my_select).find('option[value="' + lang + '"]').attr('selected', 'selected');
$(my_select).on('click', function(e){
e.stopPropagation();
});
$(my_select).on('change', function(){
var tr = $(this).parent().parent();
var id = $(tr).data('id');
var lang = $(this).find('option:selected').val();
var data = "id=" + encodeURIComponent(id) + "&lang=" + encodeURIComponent(lang);
send_update_request( data, td );
});
$(my_select).on('blur', function(){
$(td).html(lang);
});
$(this).html(my_select);
});
$("td.translation").on('blur', function(){
var tr = $(this).parent();
var id = $(tr).data('id');
var translation = $(this).text();
var data = "id=" + encodeURIComponent(id) + "&translation=" + encodeURIComponent(translation);
send_update_request( data, this );
});
$("a.delete").on('click', function(){
if ( confirm(_("Are you sure you want to delete this translation?")) ) {
var td = $(this).parent();
var tr = $(td).parent();
var id = $(tr).data('id');
send_delete_request( id, td );
}
});
$("#add_translation").on('submit', function(e){
e.preventDefault();
var entity = $(this).find('input[name="entity"]').val();
var code = $(this).find('input[name="code"]').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);
$.ajax({
data: data,
type: 'POST',
url: '/cgi-bin/koha/svc/localization',
success: function (data) {
// FIXME Should append the delete link
table.row.add( [ data.id, data.entity, data.code, data.lang, data.translation, "" ] ).draw();
show_message({ type: 'success_on_insert', data: data });
},
error: function (data) {
show_message({ type: 'error_on_insert', data: data });
},
});
});
});
//]]>
</script>
</head>
<body id="admin_localization" class="admin">
<div id="main">
<table id="localization">
<thead>
<tr>
<th>Id</th>
<th>Entity</th>
<th>Code</th>
<th>Lang</th>
<th>Translation</th>
<th></th>
</tr>
</thead>
<tbody>
[% FOR t IN translations %]
<tr id="row_id_[% t.id %]" data-id="[% t.id %]">
<td>[% t.id %]</td>
<td>[% t.entity %]</td>
<td>[% t.code %]</td>
<td class="lang">[% t.lang %]</td>
<td class="translation" contenteditable="true">[% t.translation %]</td>
<td><a class="delete" title="Delete this translation"><i class="icon-remove"></i></a</td>
</tr>
[% END %]
</tbody>
</table>
<form id="add_translation" method="post">
<input type="hidden" name="entity" value="[% entity %]" />
<input type="hidden" name="code" value="[% code %]" />
Lang: <select name="lang">
[% FOR language IN languages %]
[% FOR sublanguage IN language.sublanguages_loop %]
[% IF language.plural %]
<option value="[% sublanguage.rfc4646_subtag %]">[% sublanguage.native_description %] [% sublanguage.region_description %] ([% sublanguage.rfc4646_subtag %])</option>
[% ELSE %]
<option value="[% sublanguage.rfc4646_subtag %]">[% sublanguage.native_description %] ([% sublanguage.rfc4646_subtag %])</option>
[% END %]
[% END %]
[% END %]
</select>
Translation: <input type="text" name="translation" />
<input type="submit" value="Add" />
</form>
<div id="messages"></div>
</div>
</body>
</html>

View File

@ -83,9 +83,7 @@ my $sql = '
branchname,
items.itype,
itemtype_item.description AS itype_description,
biblioitems.itemtype,
itemtype_bib.description AS itemtype_description,
borrowernumber,
surname,
@ -103,8 +101,6 @@ my $sql = '
LEFT JOIN biblioitems USING ( biblionumber )
LEFT JOIN borrowers USING ( borrowernumber )
LEFT JOIN branches ON ( issues.branchcode = branches.branchcode )
LEFT JOIN itemtypes itemtype_bib ON ( biblioitems.itemtype = itemtype_bib.itemtype )
LEFT JOIN itemtypes itemtype_item ON ( items.itype = itemtype_item.itemtype )
WHERE borrowernumber
';
@ -145,13 +141,14 @@ while ( my $c = $sth->fetchrow_hashref() ) {
my ( $renewals_count, $renewals_allowed, $renewals_remaining ) =
GetRenewCount( $c->{borrowernumber}, $c->{itemnumber} );
my $itemtype = C4::Koha::getitemtypeinfo( $item_level_itypes ? $c->{itype} : $c->{itemtype} );
my $checkout = {
DT_RowId => $c->{itemnumber} . '-' . $c->{borrowernumber},
title => $c->{title},
author => $c->{author},
barcode => $c->{barcode},
itemtype => $item_level_itypes ? $c->{itype} : $c->{itemtype},
itemtype_description => $item_level_itypes ? $c->{itype_description} : $c->{itemtype_description},
itemtype_description => $itemtype->{translated_description},
location => $c->{location} ? GetAuthorisedValueByCode( 'LOC', $c->{location} ) : q{},
itemnotes => $c->{itemnotes},
branchcode => $c->{branchcode},

92
svc/localization Executable file
View File

@ -0,0 +1,92 @@
#!/usr/bin/perl
use Modern::Perl;
use C4::Service;
use Koha::Localizations;
our ( $query, $response ) = C4::Service->init( parameters => 'parameters_remaining_permissions' );
sub get_translations {
my $rs = Koha::Localizations->search({ type => $query->param('type'), code => $query->param('code') });
my @translations;
while ( my $s = $rs->next ) {
push @translations, {
id => $s->localization_id,
type => $s->type,
code => $s->code,
lang => $s->lang,
translation => $s->translation,
}
}
$response->param( translations => \@translations );
C4::Service->return_success( $response );
}
sub update_translation {
my $id = $query->param('id');
my $translation = $query->param('translation');
my $lang = $query->param('lang');
my $localization = Koha::Localizations->find( $id );
if ( defined $lang and $localization->lang ne $lang ) {
$localization->lang( $lang )
}
if ( defined $translation and $localization->translation ne $translation ) {
$localization->translation( $translation )
}
my $is_changed;
if ( $localization->is_changed ) {
$is_changed = 1;
$localization->store;
}
$response->param(
id => $localization->localization_id,
entity => $localization->entity,
code => $localization->code,
lang => $localization->lang,
translation => $localization->translation,
is_changed => $is_changed,
);
C4::Service->return_success( $response );
}
sub add_translation {
my $entity = $query->param('entity');
my $code = $query->param('code');
my $lang = $query->param('lang');
my $translation = $query->param('translation');
my $localization = Koha::Localization->new(
{
entity => $entity,
code => $code,
lang => $lang,
translation => $translation,
}
);
$localization->store;
$localization->localization_id;
$response->param(
id => $localization->localization_id,
entity => $localization->entity,
code => $localization->code,
lang => $localization->lang,
translation => $localization->translation,
);
C4::Service->return_success( $response );
}
sub delete_translation {
my $id = $query->param('id');
Koha::Localizations->find($id)->delete;
$response->param( id => $id );
C4::Service->return_success( $response );
}
C4::Service->dispatch(
[ 'GET /', [ 'id' ], \&get_translations ],
[ 'PUT /', [ 'id' ], \&update_translation ],
[ 'POST /', [ 'entity', 'code', 'lang', 'translation' ], \&add_translation ],
[ 'DELETE /', ['id'], \&delete_translation ],
);

View File

@ -355,14 +355,13 @@ foreach my $tag (sort keys %{$tagslib}) {
}
$value = "";
}
elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
push @authorised_values, "";
my $sth = $dbh->prepare("select itemtype,description from itemtypes order by description");
$sth->execute;
while ( my ( $itemtype, $description ) = $sth->fetchrow_array ) {
push @authorised_values, $itemtype;
$authorised_lib{$itemtype} = $description;
}
elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq "itemtypes" ) {
push @authorised_values, "";
my $itemtypes = GetItemTypes( style => 'array' );
for my $itemtype ( @$itemtypes ) {
push @authorised_values, $itemtype->{itemtype};
$authorised_lib{$itemtype->{itemtype}} = $itemtype->{translated_description};
}
$value = "";
#---- class_sources