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 618-625 sub accept_language { Link Here
618
624
619
=head2 getlanguage
625
=head2 getlanguage
620
626
621
    Select a language based on the URL parameter 'language', a cookie,
627
Select a language based on:
622
    syspref available languages & browser
628
629
=over
630
631
=item * the URL parameter 'language' (staff and opac interfaces only),
632
633
=item * the 'KohaOpacLanguage' cookie (staff and opac interfaces only),
634
635
=item * the language set by C<Koha::Language::set_requested_language>
636
(interfaces other than staff and opac only). The REST API sets this to the
637
value of 'KohaOpacLanguage' cookie,
638
639
=item * syspref StaffInterfaceLanguages (staff only)
640
641
=item * syspref OpacLanguages (opac only),
642
643
=item * HTTP header Accept-Language (more precisely, environment variable
644
HTTP_ACCEPT_LANGUAGE)
645
646
=back
623
647
624
=cut
648
=cut
625
649
Lines 633-661 sub getlanguage { Link Here
633
        return $cached if $cached;
657
        return $cached if $cached;
634
    }
658
    }
635
659
636
    $cgi //= CGI->new;
637
    my $interface = C4::Context->interface;
660
    my $interface = C4::Context->interface;
638
    my $theme = C4::Context->preference( ( $interface eq 'opac' ) ? 'opacthemes' : 'template' );
661
    my $theme = '';
639
    my $language;
662
    my $language;
640
641
    my $preference_to_check =
642
      $interface eq 'intranet' ? 'StaffInterfaceLanguages' : 'OPACLanguages';
643
    # Get the available/valid languages list
644
    my @languages;
663
    my @languages;
645
    my $preference_value = C4::Context->preference($preference_to_check);
646
    if ($preference_value) {
647
        @languages = split /,/, $preference_value;
648
    }
649
664
650
    # Chose language from the URL
665
    if ($interface eq 'opac' || $interface eq 'intranet') {
651
    my $cgi_param_language = $cgi->param( 'language' );
666
        $cgi //= CGI->new;
652
    if ( defined $cgi_param_language && any { $_ eq $cgi_param_language } @languages) {
667
        $theme = C4::Context->preference( ( $interface eq 'opac' ) ? 'opacthemes' : 'template' );
653
        $language = $cgi_param_language;
668
654
    }
669
        my $preference_to_check =
670
          $interface eq 'intranet' ? 'StaffInterfaceLanguages' : 'OPACLanguages';
671
        # Get the available/valid languages list
672
        my $preference_value = C4::Context->preference($preference_to_check);
673
        if ($preference_value) {
674
            @languages = split /,/, $preference_value;
675
        }
676
677
        # Chose language from the URL
678
        my $cgi_param_language = $cgi->param( 'language' );
679
        if ( defined $cgi_param_language && any { $_ eq $cgi_param_language } @languages) {
680
            $language = $cgi_param_language;
681
        }
655
682
656
    # cookie
683
        # cookie
657
    if (not $language and my $cgi_cookie_language = $cgi->cookie('KohaOpacLanguage') ) {
684
        if (not $language and my $cgi_cookie_language = $cgi->cookie('KohaOpacLanguage') ) {
658
        ( $language = $cgi_cookie_language ) =~ s/[^a-zA-Z_-]*//; # sanitize cookie
685
            ( $language = $cgi_cookie_language ) =~ s/[^a-zA-Z_-]*//; # sanitize cookie
686
        }
687
    } else {
688
        @languages = map { $_->{rfc4646_subtag} } @{ getTranslatedLanguages($interface, $theme) };
689
        $language = Koha::Language->get_requested_language();
659
    }
690
    }
660
691
661
    # HTTP_ACCEPT_LANGUAGE
692
    # 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