From a3988d9826253a630437269b9b25dd90c9a0b0a3 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Thu, 30 Apr 2015 17:30:47 +0200 Subject: [PATCH] Bug 14100: [POC] Generic solution for language overlay This is a proof of concept! 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. Think further / Todo: 1/ Update all occurrences of the item type's description 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). --- C4/Koha.pm | 23 ++- Koha/Localization.pm | 13 ++ Koha/Localizations.pm | 19 ++ admin/itemtypes.pl | 40 ++-- admin/localization.pl | 54 ++++++ .../Bug_14100-add_table_localization.sql | 8 + installer/data/mysql/kohastructure.sql | 14 ++ .../prog/en/modules/admin/itemtypes.tt | 9 +- .../prog/en/modules/admin/localization.tt | 206 +++++++++++++++++++++ svc/localization | 92 +++++++++ 10 files changed, 456 insertions(+), 22 deletions(-) create mode 100644 Koha/Localization.pm create mode 100644 Koha/Localizations.pm create mode 100755 admin/localization.pl create mode 100644 installer/data/mysql/atomicupdate/Bug_14100-add_table_localization.sql create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt create mode 100755 svc/localization diff --git a/C4/Koha.pm b/C4/Koha.pm index 23fbfee..04fb5c4 100644 --- a/C4/Koha.pm +++ b/C4/Koha.pm @@ -253,15 +253,32 @@ sub GetItemTypes { my ( %params ) = @_; my $style = defined( $params{'style'} ) ? $params{'style'} : 'hash'; + my $language = C4::Languages::getlanguage(); + $language =~ s|^(.*)-.*$|$1|; # 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.gstrate, + 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 ) { diff --git a/Koha/Localization.pm b/Koha/Localization.pm new file mode 100644 index 0000000..40a3f62 --- /dev/null +++ b/Koha/Localization.pm @@ -0,0 +1,13 @@ +package Koha::Localization; + +use Modern::Perl; + +use Koha::Database; + +use base qw(Koha::Object); + +sub type { + return 'Localization'; +} + +1; diff --git a/Koha/Localizations.pm b/Koha/Localizations.pm new file mode 100644 index 0000000..aa3e183 --- /dev/null +++ b/Koha/Localizations.pm @@ -0,0 +1,19 @@ +package Koha::Localizations; + +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; diff --git a/admin/itemtypes.pl b/admin/itemtypes.pl index 9effa7e..8d9b4f9 100755 --- a/admin/itemtypes.pl +++ b/admin/itemtypes.pl @@ -52,19 +52,6 @@ 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() ... ] -} - my $input = new CGI; my $searchfield = $input->param('description'); my $script_name = "/cgi-bin/koha/admin/itemtypes.pl"; @@ -100,8 +87,28 @@ 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.gstrate, + 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(); + $language =~ s|^(.*)-.*$|$1|; + $sth->execute($language, $itemtype); $data = $sth->fetchrow_hashref; } @@ -245,7 +252,8 @@ elsif ( $op eq 'delete_confirmed' ) { ################## DEFAULT ################################## } else { # DEFAULT - my ($results) = StringSearch( $searchfield, 'web' ); + my $results = C4::Koha::GetItemTypes( style => 'array' ); + warn Data::Dumper::Dumper $results; my @loop; foreach my $itemtype ( @{$results} ) { $itemtype->{imageurl} = getitemtypeimagelocation( 'intranet', $itemtype->{imageurl} ); diff --git a/admin/localization.pl b/admin/localization.pl new file mode 100755 index 0000000..93dc4a8 --- /dev/null +++ b/admin/localization.pl @@ -0,0 +1,54 @@ +#!/usr/bin/perl + +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 $languages = [ map { + { + lang => $_->{subtag}, + description => ($_->{language_description} or $_->{description} or $_->{language}), + } +} @{ C4::Languages::getAllLanguages() } ]; + +$template->param( + translations => \@translations, + languages => $languages, + entity => $entity, + code => $code, +); + +output_html_with_http_headers $query, $cookie, $template->output; diff --git a/installer/data/mysql/atomicupdate/Bug_14100-add_table_localization.sql b/installer/data/mysql/atomicupdate/Bug_14100-add_table_localization.sql new file mode 100644 index 0000000..83bdb9d --- /dev/null +++ b/installer/data/mysql/atomicupdate/Bug_14100-add_table_localization.sql @@ -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; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index efb2f9a..e1882d4 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -3505,6 +3505,20 @@ CREATE TABLE items_search_fields ( ON DELETE SET NULL 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 */; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt index 2e61a16..ebbce22 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/itemtypes.tt @@ -20,6 +20,7 @@ Data deleted [% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'greybox.inc' %] [% INCLUDE 'datatables.inc' %] + + +
+ + + + + + + + + + + + + [% FOR t IN translations %] + + + + + + + + [% END %] + +
IdEntityCodeLangTranslation
[% t.id %][% t.entity %][% t.code %][% t.lang %][% t.translation %] +
+
+ + + Lang: + Translation: + +
+
+
+ + diff --git a/svc/localization b/svc/localization new file mode 100755 index 0000000..ebec0e2 --- /dev/null +++ b/svc/localization @@ -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 ], +); -- 2.1.0