View | Details | Raw Unified | Return to bug 38630
Collapse All | Expand All

(-)a/C4/Languages.pm (-25 / +56 lines)
Lines 28-33 use List::MoreUtils qw( any ); Link Here
28
use C4::Context;
28
use C4::Context;
29
use Koha::Caches;
29
use Koha::Caches;
30
use Koha::Cache::Memory::Lite;
30
use Koha::Cache::Memory::Lite;
31
use Koha::Language;
31
32
32
our (@ISA, @EXPORT_OK);
33
our (@ISA, @EXPORT_OK);
33
BEGIN {
34
BEGIN {
Lines 111-122 Returns a reference to an array of hashes: Link Here
111
=cut
112
=cut
112
113
113
sub getTranslatedLanguages {
114
sub getTranslatedLanguages {
114
    my ($interface, $theme, $current_language, $which) = @_;
115
    my ($interface, $theme, $current_language) = @_;
115
    my @languages;
116
    my @languages;
116
    my @enabled_languages =
117
117
      ( $interface && $interface eq 'intranet' )
118
    my @enabled_languages;
118
      ? split ",", C4::Context->preference('StaffInterfaceLanguages')
119
    if ($interface) {
119
      : split ",", C4::Context->preference('OPACLanguages');
120
        if ($interface eq 'intranet') {
121
            @enabled_languages = split ",", C4::Context->preference('StaffInterfaceLanguages');
122
        } elsif ($interface eq 'opac') {
123
            @enabled_languages = split ",", C4::Context->preference('OPACLanguages');
124
        }
125
    }
120
126
121
    my $cache = Koha::Caches->get_instance;
127
    my $cache = Koha::Caches->get_instance;
122
    my $cache_key = "languages_${interface}_${theme}";
128
    my $cache_key = "languages_${interface}_${theme}";
Lines 640-647 sub accept_language { Link Here
640
646
641
=head2 getlanguage
647
=head2 getlanguage
642
648
643
    Select a language based on the URL parameter 'language', a cookie,
649
Select a language based on:
644
    syspref available languages & browser
650
651
=over
652
653
=item * the URL parameter 'language' (staff and opac interfaces only),
654
655
=item * the 'KohaOpacLanguage' cookie (staff and opac interfaces only),
656
657
=item * the language set by C<Koha::Language::set_requested_language>
658
(interfaces other than staff and opac only). The REST API sets this to the
659
value of 'KohaOpacLanguage' cookie,
660
661
=item * syspref StaffInterfaceLanguages (staff only)
662
663
=item * syspref OpacLanguages (opac only),
664
665
=item * HTTP header Accept-Language (more precisely, environment variable
666
HTTP_ACCEPT_LANGUAGE)
667
668
=back
645
669
646
=cut
670
=cut
647
671
Lines 655-683 sub getlanguage { Link Here
655
        return $cached if $cached;
679
        return $cached if $cached;
656
    }
680
    }
657
681
658
    $cgi //= CGI->new;
659
    my $interface = C4::Context->interface;
682
    my $interface = C4::Context->interface;
660
    my $theme = C4::Context->preference( ( $interface eq 'opac' ) ? 'opacthemes' : 'template' );
683
    my $theme = '';
661
    my $language;
684
    my $language;
662
663
    my $preference_to_check =
664
      $interface eq 'intranet' ? 'StaffInterfaceLanguages' : 'OPACLanguages';
665
    # Get the available/valid languages list
666
    my @languages;
685
    my @languages;
667
    my $preference_value = C4::Context->preference($preference_to_check);
668
    if ($preference_value) {
669
        @languages = split /,/, $preference_value;
670
    }
671
686
672
    # Chose language from the URL
687
    if ($interface eq 'opac' || $interface eq 'intranet') {
673
    my $cgi_param_language = $cgi->param( 'language' );
688
        $cgi //= CGI->new;
674
    if ( defined $cgi_param_language && any { $_ eq $cgi_param_language } @languages) {
689
        $theme = C4::Context->preference( ( $interface eq 'opac' ) ? 'opacthemes' : 'template' );
675
        $language = $cgi_param_language;
690
676
    }
691
        my $preference_to_check =
692
          $interface eq 'intranet' ? 'StaffInterfaceLanguages' : 'OPACLanguages';
693
        # Get the available/valid languages list
694
        my $preference_value = C4::Context->preference($preference_to_check);
695
        if ($preference_value) {
696
            @languages = split /,/, $preference_value;
697
        }
698
699
        # Chose language from the URL
700
        my $cgi_param_language = $cgi->param( 'language' );
701
        if ( defined $cgi_param_language && any { $_ eq $cgi_param_language } @languages) {
702
            $language = $cgi_param_language;
703
        }
677
704
678
    # cookie
705
        # cookie
679
    if (not $language and my $cgi_cookie_language = $cgi->cookie('KohaOpacLanguage') ) {
706
        if (not $language and my $cgi_cookie_language = $cgi->cookie('KohaOpacLanguage') ) {
680
        ( $language = $cgi_cookie_language ) =~ s/[^a-zA-Z_-]*//; # sanitize cookie
707
            ( $language = $cgi_cookie_language ) =~ s/[^a-zA-Z_-]*//; # sanitize cookie
708
        }
709
    } else {
710
        @languages = map { $_->{rfc4646_subtag} } @{ getTranslatedLanguages($interface, $theme) };
711
        $language = Koha::Language->get_requested_language();
681
    }
712
    }
682
713
683
    # HTTP_ACCEPT_LANGUAGE
714
    # HTTP_ACCEPT_LANGUAGE
(-)a/Koha/App/Intranet.pm (+1 lines)
Lines 39-44 sub startup { Link Here
39
    $self->plugin('RESTV1');
39
    $self->plugin('RESTV1');
40
40
41
    $self->plugin('CSRF');
41
    $self->plugin('CSRF');
42
    $self->plugin('Language');
42
43
43
    $self->hook(before_dispatch => \&_before_dispatch);
44
    $self->hook(before_dispatch => \&_before_dispatch);
44
    $self->hook(around_action => \&_around_action);
45
    $self->hook(around_action => \&_around_action);
(-)a/Koha/App/Opac.pm (+1 lines)
Lines 39-44 sub startup { Link Here
39
    $self->plugin('RESTV1');
39
    $self->plugin('RESTV1');
40
40
41
    $self->plugin('CSRF');
41
    $self->plugin('CSRF');
42
    $self->plugin('Language');
42
43
43
    $self->hook(before_dispatch => \&_before_dispatch);
44
    $self->hook(before_dispatch => \&_before_dispatch);
44
    $self->hook(around_action => \&_around_action);
45
    $self->hook(around_action => \&_around_action);
(-)a/Koha/App/Plugin/Language.pm (+72 lines)
Line 0 Link Here
1
package Koha::App::Plugin::Language;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
=head1 NAME
19
20
Koha::App::Plugin::Language
21
22
=head1 SYNOPSIS
23
24
    $app->plugin('Language');
25
26
=head1 DESCRIPTION
27
28
Sets the current language based on request (cookies, headers, ...)
29
30
=cut
31
32
use Modern::Perl;
33
34
use Mojo::Base 'Mojolicious::Plugin';
35
36
use Koha::Language;
37
38
=head1 METHODS
39
40
=head2 register
41
42
Called by Mojolicious when the plugin is loaded.
43
44
Defines an `around_action` hook that will sets the current language based on
45
the current request.
46
47
=cut
48
49
sub register {
50
    my ( $self, $app, $conf ) = @_;
51
52
    $app->hook(
53
        around_action => sub {
54
            my ( $next, $c, $action, $last ) = @_;
55
56
            # Make the value of Accept-Language header and KohaOpacLanguage
57
            # cookie accessible to C4::Languages::getlanguage when not in a CGI
58
            # context
59
60
            if ( my $accept_language = $c->req->headers->accept_language ) {
61
                $ENV{HTTP_ACCEPT_LANGUAGE} = $accept_language;
62
            }
63
            if ( my $KohaOpacLanguage = $c->cookie('KohaOpacLanguage') ) {
64
                Koha::Language->set_requested_language($KohaOpacLanguage);
65
            }
66
67
            return $next->();
68
        }
69
    );
70
}
71
72
1;
(-)a/Koha/Language.pm (+46 lines)
Line 0 Link Here
1
package Koha::Language;
2
3
=head1 NAME
4
5
Koha::Language
6
7
=head1 SYNOPSIS
8
9
    use Koha::Language;
10
11
    Koha::Language->set_requested_language('xx-XX');
12
    my $language = Koha::Language->get_requested_language();
13
14
=head1 DESCRIPTION
15
16
This module is essentially a communication tool between the REST API and
17
C4::Languages::getlanguage so that getlanguage can be aware of the value of
18
KohaOpacLanguage cookie when not in CGI context.
19
20
It can also be used in other contexts, like command line scripts for instance.
21
22
=cut
23
24
use Modern::Perl;
25
26
use Koha::Cache::Memory::Lite;
27
28
use constant REQUESTED_LANGUAGE_CACHE_KEY => 'requested_language';
29
30
sub set_requested_language {
31
    my ($class, $language) = @_;
32
33
    my $cache = Koha::Cache::Memory::Lite->get_instance;
34
35
    $cache->set_in_cache(REQUESTED_LANGUAGE_CACHE_KEY, $language);
36
}
37
38
sub get_requested_language {
39
    my ($class) = @_;
40
41
    my $cache = Koha::Cache::Memory::Lite->get_instance;
42
43
    return $cache->get_from_cache(REQUESTED_LANGUAGE_CACHE_KEY);
44
}
45
46
1;
(-)a/Koha/REST/V1.pm (+1 lines)
Lines 153-158 sub startup { Link Here
153
        $self->app->log->warn( "Warning: Failed to fetch oauth configuration: " . $_ );
153
        $self->app->log->warn( "Warning: Failed to fetch oauth configuration: " . $_ );
154
    };
154
    };
155
155
156
    $self->plugin('Koha::App::Plugin::Language');
156
    $self->plugin('Koha::REST::Plugin::Pagination');
157
    $self->plugin('Koha::REST::Plugin::Pagination');
157
    $self->plugin('Koha::REST::Plugin::Query');
158
    $self->plugin('Koha::REST::Plugin::Query');
158
    $self->plugin('Koha::REST::Plugin::Objects');
159
    $self->plugin('Koha::REST::Plugin::Objects');
(-)a/Koha/REST/V1/Auth.pm (-5 lines)
Lines 155-165 sub authenticate_api_request { Link Here
155
    $c->stash_embed( { spec => $spec } );
155
    $c->stash_embed( { spec => $spec } );
156
    $c->stash_overrides();
156
    $c->stash_overrides();
157
157
158
    # FIXME: Remove once CGI is not used
159
    my $accept_language = $c->req->headers->accept_language;
160
    $ENV{HTTP_ACCEPT_LANGUAGE} = $accept_language
161
        if $accept_language;
162
163
    my $cookie_auth = 0;
158
    my $cookie_auth = 0;
164
159
165
    my $authorization = $spec->{'x-koha-authorization'};
160
    my $authorization = $spec->{'x-koha-authorization'};
(-)a/t/Languages.t (-1 / +30 lines)
Lines 18-27 Link Here
18
# with Koha; if not, see <http://www.gnu.org/licenses>.
18
# with Koha; if not, see <http://www.gnu.org/licenses>.
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
use Test::More tests => 4;
21
use Test::More tests => 5;
22
use Test::MockModule;
22
use Test::MockModule;
23
use CGI qw ( -utf8 );
23
use CGI qw ( -utf8 );
24
use Koha::Cache::Memory::Lite;
24
use Koha::Cache::Memory::Lite;
25
use Koha::Language;
25
26
26
BEGIN {
27
BEGIN {
27
    use_ok('C4::Languages', qw( getlanguage ));
28
    use_ok('C4::Languages', qw( getlanguage ));
Lines 32-37 my @languages = (); # stores the list of active languages Link Here
32
my $return_undef = 0;
33
my $return_undef = 0;
33
34
34
my $module_context = Test::MockModule->new('C4::Context');
35
my $module_context = Test::MockModule->new('C4::Context');
36
my $module_languages = Test::MockModule->new('C4::Languages');
35
37
36
$module_context->mock(
38
$module_context->mock(
37
    preference => sub {
39
    preference => sub {
Lines 46-51 $module_context->mock( Link Here
46
  },
48
  },
47
);
49
);
48
50
51
$module_languages->mock(
52
    _get_language_dirs => sub {
53
        return @languages
54
    }
55
);
56
49
delete $ENV{HTTP_ACCEPT_LANGUAGE};
57
delete $ENV{HTTP_ACCEPT_LANGUAGE};
50
58
51
my $query = CGI->new();
59
my $query = CGI->new();
Lines 59-61 is(C4::Languages::getlanguage($query), 'en', 'default to English if no language Link Here
59
Koha::Cache::Memory::Lite->get_instance()->clear_from_cache('getlanguage');
67
Koha::Cache::Memory::Lite->get_instance()->clear_from_cache('getlanguage');
60
$return_undef = 1;
68
$return_undef = 1;
61
is(C4::Languages::getlanguage($query), 'en', 'default to English if no database');
69
is(C4::Languages::getlanguage($query), 'en', 'default to English if no database');
70
71
subtest 'when interface is not intranet or opac' => sub {
72
    plan tests => 3;
73
74
    my $cache = Koha::Cache::Memory::Lite->get_instance;
75
    C4::Context->interface('api');
76
77
    @languages = ('fr-FR', 'de-DE', 'en');
78
79
    $ENV{HTTP_ACCEPT_LANGUAGE} = 'de-DE';
80
    $cache->clear_from_cache('getlanguage');
81
    is(C4::Languages::getlanguage(), 'de-DE', 'Accept-Language HTTP header is respected');
82
83
    Koha::Language->set_requested_language('fr-FR');
84
    $cache->clear_from_cache('getlanguage');
85
    is(C4::Languages::getlanguage(), 'fr-FR', 'but language requested through Koha::Language is prefered');
86
87
    @languages = ();
88
    $cache->clear_from_cache('getlanguage');
89
    is(C4::Languages::getlanguage(), 'en', 'fallback to english when no language is available');
90
};
(-)a/t/db_dependent/api/v1/items.t (-2 / +9 lines)
Lines 32-37 use Mojo::JSON qw(encode_json); Link Here
32
use C4::Auth;
32
use C4::Auth;
33
use Koha::Items;
33
use Koha::Items;
34
use Koha::Database;
34
use Koha::Database;
35
use Koha::Language;
35
36
36
my $schema  = Koha::Database->new->schema;
37
my $schema  = Koha::Database->new->schema;
37
my $builder = t::lib::TestBuilder->new;
38
my $builder = t::lib::TestBuilder->new;
Lines 256-262 subtest 'list_public() tests' => sub { Link Here
256
257
257
subtest 'get() tests' => sub {
258
subtest 'get() tests' => sub {
258
259
259
    plan tests => 34;
260
    plan tests => 37;
260
261
261
    $schema->storage->txn_begin;
262
    $schema->storage->txn_begin;
262
263
Lines 346-351 subtest 'get() tests' => sub { Link Here
346
      ->json_is( '/not_for_loan_status' => 0, 'not_for_loan_status is 0' )
347
      ->json_is( '/not_for_loan_status' => 0, 'not_for_loan_status is 0' )
347
      ->json_is( '/effective_not_for_loan_status' => 3, 'effective_not_for_loan_status now picks up itemtype level - item-level_itypes:0' );
348
      ->json_is( '/effective_not_for_loan_status' => 3, 'effective_not_for_loan_status now picks up itemtype level - item-level_itypes:0' );
348
349
350
    my $module = Test::MockModule->new('C4::Languages');
351
    $module->mock( _get_language_dirs => sub { return 'en', 'de-DE' } );
352
    $schema->resultset('Localization')->create({ entity => 'itemtypes', code => $itype->itemtype, lang => 'de-DE', translation => 'translated' });
353
    $t->get_ok( "//$userid:$password@/api/v1/items/" . $item->itemnumber, { 'X-Koha-Embed' => '+strings', Cookie => 'KohaOpacLanguage=de-DE', 'Accept-Language' => 'en' } )
354
      ->status_is( 200, 'SWAGGER3.2.2' )
355
      ->json_is( '/_strings/item_type_id/str' => 'translated', 'translations in _strings use language set in KohaOpacLanguage cookie' );
356
349
    $schema->storage->txn_rollback;
357
    $schema->storage->txn_rollback;
350
};
358
};
351
359
352
- 

Return to bug 38630