Bugzilla – Attachment 175238 Details for
Bug 38630
Make the REST API respect KohaOpacLanguage cookie
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 38630: Make the REST API respect KohaOpacLanguage cookie
Bug-38630-Make-the-REST-API-respect-KohaOpacLangua.patch (text/plain), 15.52 KB, created by
Julian Maurice
on 2024-12-05 11:23:44 UTC
(
hide
)
Description:
Bug 38630: Make the REST API respect KohaOpacLanguage cookie
Filename:
MIME Type:
Creator:
Julian Maurice
Created:
2024-12-05 11:23:44 UTC
Size:
15.52 KB
patch
obsolete
>From 718f2426e185f5db5e0ce7873bcbe491937f981f Mon Sep 17 00:00:00 2001 >From: Julian Maurice <julian.maurice@biblibre.com> >Date: Thu, 5 Dec 2024 11:24:33 +0100 >Subject: [PATCH] Bug 38630: Make the REST API respect KohaOpacLanguage cookie >MIME-Version: 1.0 >Content-Type: text/plain; charset=UTF-8 >Content-Transfer-Encoding: 8bit > >The REST API can return translated strings to the opac or staff >interface, so it should respect the KohaOpacLanguage cookie and return >translations in the same language than the interface. > >Test plan: >1. Do not apply patch yet >2. Log in to koha staff interface >3. Use the browser's devtools to get the value of CGISESSID cookie >4. Make sure you have at least 2 languages installed ('en' + another > one - I'll use 'fr-FR' as an example in this test plan) >5. Find an item and note its itemnumber and itemtype >6. Go translate this itemtype's description (admin » item types » edit > item type » translate). Add a translation for 'en' and another one > for your language. >7. Close your browser tab (do not logout) and restart Koha to flush the > memory cache. >8. Execute the following commands (replace variables by the correct > value): > > curl -sSL "$KOHA_URL/api/v1/items/$ITEMNUMBER" \ > -H 'x-koha-embed: +strings' \ > -H "Cookie: KohaOpacLanguage=en; CGISESSID=$CGISESSID" \ > | jq -r '._strings.item_type_id.str' > > If you do not have jq, it can be found in most distributions > packages. Or you could inspect the JSON manually at the path > /_strings/item_type_id/str > > Restart Koha again, and execute the same command but with your > language set in KohaOpacLanguage cookie: > > curl -sSL "$KOHA_URL/api/v1/items/$ITEMNUMBER" \ > -H 'x-koha-embed: +strings' \ > -H "Cookie: KohaOpacLanguage=fr-FR; CGISESSID=$CGISESSID" \ > | jq -r '._strings.item_type_id.str' > > Depending on how Koha sort the languages (not sure how it's done), > you should get either the 'en' one or the 'fr-FR' one, but the > important thing is you should get the same translation, no matter > what the value of KohaOpacLanguage is, which is the issue this patch > is trying to fix. >9. Apply the patch and restart Koha >10. Repeat step 8. This time you should get the translation > corresponding to the language set in KohaOpacLanguage cookie > >Side note: >* The need to restart Koha before each request is due to a bug (see bug > 38454). If already pushed when you're testing this one, you don't have > to restart. >--- > C4/Languages.pm | 81 ++++++++++++++++++++++++----------- > Koha/App/Intranet.pm | 1 + > Koha/App/Opac.pm | 1 + > Koha/App/Plugin/Language.pm | 72 +++++++++++++++++++++++++++++++ > Koha/Language.pm | 46 ++++++++++++++++++++ > Koha/REST/V1.pm | 1 + > Koha/REST/V1/Auth.pm | 5 --- > t/Languages.t | 31 +++++++++++++- > t/db_dependent/api/v1/items.t | 10 ++++- > 9 files changed, 216 insertions(+), 32 deletions(-) > create mode 100644 Koha/App/Plugin/Language.pm > create mode 100644 Koha/Language.pm > >diff --git a/C4/Languages.pm b/C4/Languages.pm >index a9f8295cf1..d482e5ed7c 100644 >--- a/C4/Languages.pm >+++ b/C4/Languages.pm >@@ -28,6 +28,7 @@ use List::MoreUtils qw( any ); > use C4::Context; > use Koha::Caches; > use Koha::Cache::Memory::Lite; >+use Koha::Language; > > our (@ISA, @EXPORT_OK); > BEGIN { >@@ -111,12 +112,17 @@ Returns a reference to an array of hashes: > =cut > > sub getTranslatedLanguages { >- my ($interface, $theme, $current_language, $which) = @_; >+ my ($interface, $theme, $current_language) = @_; > my @languages; >- my @enabled_languages = >- ( $interface && $interface eq 'intranet' ) >- ? split ",", C4::Context->preference('StaffInterfaceLanguages') >- : split ",", C4::Context->preference('OPACLanguages'); >+ >+ my @enabled_languages; >+ if ($interface) { >+ if ($interface eq 'intranet') { >+ @enabled_languages = split ",", C4::Context->preference('StaffInterfaceLanguages'); >+ } elsif ($interface eq 'opac') { >+ @enabled_languages = split ",", C4::Context->preference('OPACLanguages'); >+ } >+ } > > my $cache = Koha::Caches->get_instance; > my $cache_key = "languages_${interface}_${theme}"; >@@ -618,8 +624,26 @@ sub accept_language { > > =head2 getlanguage > >- Select a language based on the URL parameter 'language', a cookie, >- syspref available languages & browser >+Select a language based on: >+ >+=over >+ >+=item * the URL parameter 'language' (staff and opac interfaces only), >+ >+=item * the 'KohaOpacLanguage' cookie (staff and opac interfaces only), >+ >+=item * the language set by C<Koha::Language::set_requested_language> >+(interfaces other than staff and opac only). The REST API sets this to the >+value of 'KohaOpacLanguage' cookie, >+ >+=item * syspref StaffInterfaceLanguages (staff only) >+ >+=item * syspref OpacLanguages (opac only), >+ >+=item * HTTP header Accept-Language (more precisely, environment variable >+HTTP_ACCEPT_LANGUAGE) >+ >+=back > > =cut > >@@ -633,29 +657,36 @@ sub getlanguage { > return $cached if $cached; > } > >- $cgi //= CGI->new; > my $interface = C4::Context->interface; >- my $theme = C4::Context->preference( ( $interface eq 'opac' ) ? 'opacthemes' : 'template' ); >+ my $theme = ''; > my $language; >- >- my $preference_to_check = >- $interface eq 'intranet' ? 'StaffInterfaceLanguages' : 'OPACLanguages'; >- # Get the available/valid languages list > my @languages; >- my $preference_value = C4::Context->preference($preference_to_check); >- if ($preference_value) { >- @languages = split /,/, $preference_value; >- } > >- # Chose language from the URL >- my $cgi_param_language = $cgi->param( 'language' ); >- if ( defined $cgi_param_language && any { $_ eq $cgi_param_language } @languages) { >- $language = $cgi_param_language; >- } >+ if ($interface eq 'opac' || $interface eq 'intranet') { >+ $cgi //= CGI->new; >+ $theme = C4::Context->preference( ( $interface eq 'opac' ) ? 'opacthemes' : 'template' ); >+ >+ my $preference_to_check = >+ $interface eq 'intranet' ? 'StaffInterfaceLanguages' : 'OPACLanguages'; >+ # Get the available/valid languages list >+ my $preference_value = C4::Context->preference($preference_to_check); >+ if ($preference_value) { >+ @languages = split /,/, $preference_value; >+ } >+ >+ # Chose language from the URL >+ my $cgi_param_language = $cgi->param( 'language' ); >+ if ( defined $cgi_param_language && any { $_ eq $cgi_param_language } @languages) { >+ $language = $cgi_param_language; >+ } > >- # cookie >- if (not $language and my $cgi_cookie_language = $cgi->cookie('KohaOpacLanguage') ) { >- ( $language = $cgi_cookie_language ) =~ s/[^a-zA-Z_-]*//; # sanitize cookie >+ # cookie >+ if (not $language and my $cgi_cookie_language = $cgi->cookie('KohaOpacLanguage') ) { >+ ( $language = $cgi_cookie_language ) =~ s/[^a-zA-Z_-]*//; # sanitize cookie >+ } >+ } else { >+ @languages = map { $_->{rfc4646_subtag} } @{ getTranslatedLanguages($interface, $theme) }; >+ $language = Koha::Language->get_requested_language(); > } > > # HTTP_ACCEPT_LANGUAGE >diff --git a/Koha/App/Intranet.pm b/Koha/App/Intranet.pm >index 558de8da1c..5628174fdc 100644 >--- a/Koha/App/Intranet.pm >+++ b/Koha/App/Intranet.pm >@@ -39,6 +39,7 @@ sub startup { > $self->plugin('RESTV1'); > > $self->plugin('CSRF'); >+ $self->plugin('Language'); > > $self->hook(before_dispatch => \&_before_dispatch); > $self->hook(around_action => \&_around_action); >diff --git a/Koha/App/Opac.pm b/Koha/App/Opac.pm >index 1f722360e4..d41a704776 100644 >--- a/Koha/App/Opac.pm >+++ b/Koha/App/Opac.pm >@@ -39,6 +39,7 @@ sub startup { > $self->plugin('RESTV1'); > > $self->plugin('CSRF'); >+ $self->plugin('Language'); > > $self->hook(before_dispatch => \&_before_dispatch); > $self->hook(around_action => \&_around_action); >diff --git a/Koha/App/Plugin/Language.pm b/Koha/App/Plugin/Language.pm >new file mode 100644 >index 0000000000..c93e4fa95f >--- /dev/null >+++ b/Koha/App/Plugin/Language.pm >@@ -0,0 +1,72 @@ >+package Koha::App::Plugin::Language; >+ >+# 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>. >+ >+=head1 NAME >+ >+Koha::App::Plugin::Language >+ >+=head1 SYNOPSIS >+ >+ $app->plugin('Language'); >+ >+=head1 DESCRIPTION >+ >+Sets the current language based on request (cookies, headers, ...) >+ >+=cut >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Plugin'; >+ >+use Koha::Language; >+ >+=head1 METHODS >+ >+=head2 register >+ >+Called by Mojolicious when the plugin is loaded. >+ >+Defines an `around_action` hook that will sets the current language based on >+the current request. >+ >+=cut >+ >+sub register { >+ my ( $self, $app, $conf ) = @_; >+ >+ $app->hook( >+ around_action => sub { >+ my ( $next, $c, $action, $last ) = @_; >+ >+ # Make the value of Accept-Language header and KohaOpacLanguage >+ # cookie accessible to C4::Languages::getlanguage when not in a CGI >+ # context >+ >+ if ( my $accept_language = $c->req->headers->accept_language ) { >+ $ENV{HTTP_ACCEPT_LANGUAGE} = $accept_language; >+ } >+ if ( my $KohaOpacLanguage = $c->cookie('KohaOpacLanguage') ) { >+ Koha::Language->set_requested_language($KohaOpacLanguage); >+ } >+ >+ return $next->(); >+ } >+ ); >+} >+ >+1; >diff --git a/Koha/Language.pm b/Koha/Language.pm >new file mode 100644 >index 0000000000..1dcb58237e >--- /dev/null >+++ b/Koha/Language.pm >@@ -0,0 +1,46 @@ >+package Koha::Language; >+ >+=head1 NAME >+ >+Koha::Language >+ >+=head1 SYNOPSIS >+ >+ use Koha::Language; >+ >+ Koha::Language->set_requested_language('xx-XX'); >+ my $language = Koha::Language->get_requested_language(); >+ >+=head1 DESCRIPTION >+ >+This module is essentially a communication tool between the REST API and >+C4::Languages::getlanguage so that getlanguage can be aware of the value of >+KohaOpacLanguage cookie when not in CGI context. >+ >+It can also be used in other contexts, like command line scripts for instance. >+ >+=cut >+ >+use Modern::Perl; >+ >+use Koha::Cache::Memory::Lite; >+ >+use constant REQUESTED_LANGUAGE_CACHE_KEY => 'requested_language'; >+ >+sub set_requested_language { >+ my ($class, $language) = @_; >+ >+ my $cache = Koha::Cache::Memory::Lite->get_instance; >+ >+ $cache->set_in_cache(REQUESTED_LANGUAGE_CACHE_KEY, $language); >+} >+ >+sub get_requested_language { >+ my ($class) = @_; >+ >+ my $cache = Koha::Cache::Memory::Lite->get_instance; >+ >+ return $cache->get_from_cache(REQUESTED_LANGUAGE_CACHE_KEY); >+} >+ >+1; >diff --git a/Koha/REST/V1.pm b/Koha/REST/V1.pm >index 52bd15697e..1a3559bfdf 100644 >--- a/Koha/REST/V1.pm >+++ b/Koha/REST/V1.pm >@@ -153,6 +153,7 @@ sub startup { > $self->app->log->warn( "Warning: Failed to fetch oauth configuration: " . $_ ); > }; > >+ $self->plugin('Koha::App::Plugin::Language'); > $self->plugin('Koha::REST::Plugin::Pagination'); > $self->plugin('Koha::REST::Plugin::Query'); > $self->plugin('Koha::REST::Plugin::Objects'); >diff --git a/Koha/REST/V1/Auth.pm b/Koha/REST/V1/Auth.pm >index c10e81cf8a..dd59def5f1 100644 >--- a/Koha/REST/V1/Auth.pm >+++ b/Koha/REST/V1/Auth.pm >@@ -155,11 +155,6 @@ sub authenticate_api_request { > $c->stash_embed( { spec => $spec } ); > $c->stash_overrides(); > >- # FIXME: Remove once CGI is not used >- my $accept_language = $c->req->headers->accept_language; >- $ENV{HTTP_ACCEPT_LANGUAGE} = $accept_language >- if $accept_language; >- > my $cookie_auth = 0; > > my $authorization = $spec->{'x-koha-authorization'}; >diff --git a/t/Languages.t b/t/Languages.t >index 14c5d2866d..4b13d02cc2 100755 >--- a/t/Languages.t >+++ b/t/Languages.t >@@ -18,10 +18,11 @@ > # with Koha; if not, see <http://www.gnu.org/licenses>. > > use Modern::Perl; >-use Test::More tests => 4; >+use Test::More tests => 5; > use Test::MockModule; > use CGI qw ( -utf8 ); > use Koha::Cache::Memory::Lite; >+use Koha::Language; > > BEGIN { > use_ok('C4::Languages', qw( getlanguage )); >@@ -32,6 +33,7 @@ my @languages = (); # stores the list of active languages > my $return_undef = 0; > > my $module_context = Test::MockModule->new('C4::Context'); >+my $module_languages = Test::MockModule->new('C4::Languages'); > > $module_context->mock( > preference => sub { >@@ -46,6 +48,12 @@ $module_context->mock( > }, > ); > >+$module_languages->mock( >+ _get_language_dirs => sub { >+ return @languages >+ } >+); >+ > delete $ENV{HTTP_ACCEPT_LANGUAGE}; > > my $query = CGI->new(); >@@ -59,3 +67,24 @@ is(C4::Languages::getlanguage($query), 'en', 'default to English if no language > Koha::Cache::Memory::Lite->get_instance()->clear_from_cache('getlanguage'); > $return_undef = 1; > is(C4::Languages::getlanguage($query), 'en', 'default to English if no database'); >+ >+subtest 'when interface is not intranet or opac' => sub { >+ plan tests => 3; >+ >+ my $cache = Koha::Cache::Memory::Lite->get_instance; >+ C4::Context->interface('api'); >+ >+ @languages = ('fr-FR', 'de-DE', 'en'); >+ >+ $ENV{HTTP_ACCEPT_LANGUAGE} = 'de-DE'; >+ $cache->clear_from_cache('getlanguage'); >+ is(C4::Languages::getlanguage(), 'de-DE', 'Accept-Language HTTP header is respected'); >+ >+ Koha::Language->set_requested_language('fr-FR'); >+ $cache->clear_from_cache('getlanguage'); >+ is(C4::Languages::getlanguage(), 'fr-FR', 'but language requested through Koha::Language is prefered'); >+ >+ @languages = (); >+ $cache->clear_from_cache('getlanguage'); >+ is(C4::Languages::getlanguage(), 'en', 'fallback to english when no language is available'); >+}; >diff --git a/t/db_dependent/api/v1/items.t b/t/db_dependent/api/v1/items.t >index 63ca5f73db..bed68e490b 100755 >--- a/t/db_dependent/api/v1/items.t >+++ b/t/db_dependent/api/v1/items.t >@@ -32,6 +32,7 @@ use Mojo::JSON qw(encode_json); > use C4::Auth; > use Koha::Items; > use Koha::Database; >+use Koha::Language; > > my $schema = Koha::Database->new->schema; > my $builder = t::lib::TestBuilder->new; >@@ -256,7 +257,7 @@ subtest 'list_public() tests' => sub { > > subtest 'get() tests' => sub { > >- plan tests => 34; >+ plan tests => 37; > > $schema->storage->txn_begin; > >@@ -346,6 +347,13 @@ subtest 'get() tests' => sub { > ->json_is( '/not_for_loan_status' => 0, 'not_for_loan_status is 0' ) > ->json_is( '/effective_not_for_loan_status' => 3, 'effective_not_for_loan_status now picks up itemtype level - item-level_itypes:0' ); > >+ my $module = Test::MockModule->new('C4::Languages'); >+ $module->mock( _get_language_dirs => sub { return 'en', 'de-DE' } ); >+ $schema->resultset('Localization')->create({ entity => 'itemtypes', code => $itype->itemtype, lang => 'de-DE', translation => 'translated' }); >+ $t->get_ok( "//$userid:$password@/api/v1/items/" . $item->itemnumber, { 'X-Koha-Embed' => '+strings', Cookie => 'KohaOpacLanguage=de-DE', 'Accept-Language' => 'en' } ) >+ ->status_is( 200, 'SWAGGER3.2.2' ) >+ ->json_is( '/_strings/item_type_id/str' => 'translated', 'translations in _strings use language set in KohaOpacLanguage cookie' ); >+ > $schema->storage->txn_rollback; > }; > >-- >2.39.2
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 38630
:
175238
|
176226