Skip to content

Commit a0cca5c

Browse files
authored
Merge pull request #1973 from rtibbles/language_switcher
Language switcher
2 parents a433643 + 0d981e6 commit a0cca5c

File tree

9 files changed

+226
-57
lines changed

9 files changed

+226
-57
lines changed

kolibri/core/assets/src/core-app/apiSpec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import kNavbar from '../views/k-navbar';
4040
import kNavbarButton from '../views/k-navbar/button';
4141
import kNavbarLink from '../views/k-navbar/link';
4242
import logo from '../views/logo';
43+
import languageSwitcher from '../views/language-switcher';
4344
import immersiveFullScreen from '../views/immersive-full-screen';
4445
import elapsedTime from '../views/elapsed-time';
4546
import pointsIcon from '../views/points-icon';
@@ -104,6 +105,7 @@ export default {
104105
kBreadcrumbs,
105106
kCheckbox,
106107
kRadioButton,
108+
languageSwitcher,
107109
},
108110
router,
109111
mixins: {

kolibri/core/assets/src/styles/main.styl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ html
2828
// https://davidwalsh.name/html5-boilerplate
2929
font-size: 100%
3030
text-size-adjust: 100%
31-
overflow: hidden
3231
box-sizing: border-box
33-
3432
// from normalize v5
3533
line-height: 1.15
3634

kolibri/core/assets/src/views/app-bar/index.vue

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
<div slot="actions">
1111
<slot name="app-bar-actions"/>
1212
<ui-button
13-
v-if="isUserLoggedIn"
1413
icon="person"
1514
type="primary"
1615
color="primary"
@@ -19,10 +18,13 @@
1918
ref="accountButton"
2019
class="username-text">
2120
<template v-if="windowSize.breakpoint > 2">
22-
{{ username }}
23-
<template v-if="isSuperuser">{{ $tr('superuser') }}</template>
24-
<template v-if="isAdmin">{{ $tr('admin') }}</template>
25-
<template v-if="isCoach">{{ $tr('coach') }}</template>
21+
<template v-if="isUserLoggedIn">
22+
{{ username }}
23+
<template v-if="isSuperuser">{{ $tr('superuser') }}</template>
24+
<template v-if="isAdmin">{{ $tr('admin') }}</template>
25+
<template v-if="isCoach">{{ $tr('coach') }}</template>
26+
</template>
27+
<template v-else>{{ $tr('guest') }}</template>
2628
</template>
2729
<ui-menu
2830
slot="dropdown"
@@ -31,14 +33,7 @@
3133
@select="optionSelected"
3234
/>
3335
</ui-button>
34-
<a v-else href="/user">
35-
<ui-button
36-
type="primary"
37-
color="primary"
38-
:ariaLabel="$tr('signIn')">
39-
{{ $tr('signIn') }}
40-
</ui-button>
41-
</a>
36+
<language-switcher :modalOpen="showLanguageModal" @close="showLanguageModal=false"/>
4237
</div>
4338
</ui-toolbar>
4439

@@ -60,6 +55,8 @@
6055
import uiIconButton from 'keen-ui/src/UiIconButton';
6156
import uiMenu from 'keen-ui/src/UiMenu';
6257
import uiButton from 'keen-ui/src/UiButton';
58+
import { redirectBrowser } from '../../utils/browser';
59+
import languageSwitcher from '../language-switcher';
6360
export default {
6461
mixins: [responsiveWindow],
6562
name: 'appBar',
@@ -71,6 +68,8 @@
7168
superuser: '(Device owner)',
7269
admin: '(Admin)',
7370
coach: '(Coach)',
71+
guest: 'Guest',
72+
languageSwitchMenuOption: 'Change language',
7473
},
7574
props: {
7675
title: {
@@ -86,23 +85,41 @@
8685
required: true,
8786
},
8887
},
88+
data: () => ({
89+
showLanguageModal: false,
90+
}),
8991
components: {
9092
uiToolbar,
9193
uiIconButton,
9294
uiMenu,
9395
uiButton,
96+
languageSwitcher,
9497
},
9598
computed: {
9699
accountMenuOptions() {
100+
const changeLanguage = {
101+
id: 'language',
102+
label: this.$tr('languageSwitchMenuOption'),
103+
};
104+
if (this.isUserLoggedIn) {
105+
return [
106+
{
107+
id: 'profile',
108+
label: this.$tr('profile'),
109+
},
110+
changeLanguage,
111+
{
112+
id: 'signOut',
113+
label: this.$tr('signOut'),
114+
},
115+
];
116+
}
97117
return [
98118
{
99-
id: 'profile',
100-
label: this.$tr('profile'),
101-
},
102-
{
103-
id: 'signOut',
104-
label: this.$tr('signOut'),
119+
id: 'signIn',
120+
label: this.$tr('signIn'),
105121
},
122+
changeLanguage,
106123
];
107124
},
108125
},
@@ -115,6 +132,10 @@
115132
case 'signOut':
116133
this.kolibriLogout();
117134
break;
135+
case 'signIn':
136+
redirectBrowser();
137+
case 'language':
138+
this.showLanguageModal = true;
118139
default:
119140
break;
120141
}

kolibri/core/assets/src/views/core-base.vue

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
:navShown="navShown"
1111
:height="headerHeight">
1212
<div slot="app-bar-actions" class="app-bar-actions">
13-
<language-switcher/>
1413
<slot name="app-bar-actions"/>
1514
</div>
1615
</app-bar>
@@ -50,7 +49,6 @@
5049
import sideNav from 'kolibri.coreVue.components.sideNav';
5150
import errorBox from './error-box';
5251
import loadingSpinner from 'kolibri.coreVue.components.loadingSpinner';
53-
import languageSwitcher from './language-switcher';
5452
import Vue from 'kolibri.lib.vue';
5553
5654
export default {
@@ -83,7 +81,6 @@
8381
sideNav,
8482
errorBox,
8583
loadingSpinner,
86-
languageSwitcher,
8784
},
8885
vuex: {
8986
getters: {
@@ -160,7 +157,6 @@
160157
161158
.content-container
162159
position: absolute
163-
overflow-y: scroll
164160
overflow-x: hidden
165161
right: 0
166162
bottom: 0
Lines changed: 123 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,101 @@
11
<template>
22

3-
<dropdown-menu
4-
:name="currentLanguageName"
5-
:options="languageOptions"
6-
:inAppBar="inAppBar"
7-
:displayDisabledAsSelected="true"
8-
:disabled="disabled"
9-
type="primary"
10-
color="primary"
11-
icon="language"
12-
@select="switchLanguage"
13-
/>
3+
<div>
4+
<div v-if="footer" class="page-footer">
5+
<ul class="language-list">
6+
<li v-for="language in languageOptions" :class="selectedLanguage===language.code ? 'selected item' : 'choice item'" @click="setAndSwitchLanguage(language.code)">
7+
{{ language.name }}
8+
</li>
9+
</ul>
10+
</div>
11+
<core-modal
12+
v-if="showModal"
13+
:title="$tr('changeLanguageModalHeader')"
14+
@cancel="closeModal">
15+
<p>{{ $tr('changeLanguageSubHeader') }}</p>
16+
<k-radio-button
17+
v-for="language in languageOptions"
18+
class="choice"
19+
:key="language.code"
20+
:radiovalue="language.code"
21+
:value="selectedLanguage"
22+
:label="language.name"
23+
v-model="selectedLanguage"
24+
/>
25+
<div class="footer">
26+
<k-button :text="$tr('cancelButtonText')" :raised="false" :disabled="disabled" @click="closeModal"/>
27+
<k-button :text="$tr('confirmButtonText')" :primary="true" :disabled="disabled" @click="switchLanguage"/>
28+
</div>
29+
</core-modal>
30+
</div>
1431

1532
</template>
1633

1734

1835
<script>
1936
20-
import orderBy from 'lodash/orderBy';
21-
import dropdownMenu from 'kolibri.coreVue.components.dropdownMenu';
37+
import coreModal from 'kolibri.coreVue.components.coreModal';
38+
import kButton from 'kolibri.coreVue.components.kButton';
39+
import kRadioButton from 'kolibri.coreVue.components.kRadioButton';
2240
import { httpClient } from 'kolibri.client';
2341
import { availableLanguages, currentLanguage } from 'kolibri.utils.i18n';
2442
export default {
25-
name: 'languageSwitcher',
26-
components: { dropdownMenu },
43+
name: 'languageSwitcherModalDialog',
44+
components: { coreModal, kButton, kRadioButton },
45+
$trs: {
46+
changeLanguageModalHeader: 'Change language',
47+
changeLanguageSubHeader: 'Select the language you want to view Kolibri in',
48+
cancelButtonText: 'Cancel',
49+
confirmButtonText: 'Confirm',
50+
},
2751
computed: {
2852
languageOptions() {
29-
return orderBy(availableLanguages, language => language.code, ['asc']).map(language => ({
30-
id: language.code,
31-
label: language.name,
32-
disabled: language.code === currentLanguage,
33-
}));
53+
return Object.keys(availableLanguages)
54+
.sort((a, b) => {
55+
if (a === currentLanguage) {
56+
return -1;
57+
}
58+
if (b === currentLanguage) {
59+
return 1;
60+
}
61+
if (a[0] < b[0]) {
62+
return -1;
63+
}
64+
if (b[0] < a[0]) {
65+
return 1;
66+
}
67+
return 0;
68+
})
69+
.map(key => availableLanguages[key]);
3470
},
3571
currentLanguageName() {
3672
return availableLanguages[currentLanguage].name;
3773
},
74+
showModal() {
75+
return this.modalOpen || this.internalModalOpen;
76+
},
3877
},
3978
props: {
40-
inAppBar: {
79+
footer: {
80+
type: Boolean,
81+
default: false,
82+
},
83+
modalOpen: {
4184
type: Boolean,
42-
default: true,
85+
default: false,
4386
},
4487
},
4588
data: () => ({
4689
disabled: false,
90+
selectedLanguage: currentLanguage,
91+
internalModalOpen: false,
4792
}),
4893
methods: {
49-
switchLanguage(language) {
94+
switchLanguage() {
5095
this.disabled = true;
5196
const path = this.Kolibri.urls['kolibri:set_language']();
5297
const entity = {
53-
language: language.id,
98+
language: this.selectedLanguage,
5499
};
55100
httpClient({
56101
path,
@@ -59,10 +104,63 @@
59104
global.location.reload(true);
60105
});
61106
},
107+
setAndSwitchLanguage(languageCode) {
108+
if (languageCode != this.selectedLanguage) {
109+
this.selectedLanguage = languageCode;
110+
this.switchLanguage();
111+
}
112+
},
113+
closeModal() {
114+
this.internalModalOpen = false;
115+
this.$emit('close');
116+
},
117+
setModalOpen() {
118+
console.log('setting open');
119+
this.internalModalOpen = true;
120+
},
62121
},
63122
};
64123
65124
</script>
66125

67126

68-
<style lang="stylus"></style>
127+
<style lang="stylus">
128+
129+
@require '~kolibri.styles.definitions'
130+
131+
h1, p
132+
color: black
133+
134+
.choice
135+
color: $core-action-normal
136+
137+
.selected
138+
font-weight: bold
139+
140+
.page-footer
141+
padding-left: 32px
142+
padding-top: 16px
143+
padding-bottom: 16px
144+
text-align: center
145+
button
146+
float: right
147+
position: absolute
148+
149+
.prompt
150+
padding-right: 16px
151+
152+
.language-list
153+
list-style: none
154+
margin: 0
155+
padding: 0
156+
text-align: initial
157+
display: inline-block
158+
159+
.item
160+
display: inline-block
161+
padding-top: 6px
162+
padding-right: 20px
163+
&.choice
164+
cursor: pointer
165+
166+
</style>

kolibri/core/urls.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@
3333
from __future__ import absolute_import, print_function, unicode_literals
3434

3535
from django.conf import settings
36-
from django.conf.urls import include, url
36+
from django.conf.urls import url
3737
from django.conf.urls.static import static
3838
from kolibri.content.utils import paths
3939
from kolibri.plugins.registry import get_urls as plugin_urls
4040

41+
from .views import set_language
42+
4143
app_name = 'kolibri'
4244

4345

@@ -46,4 +48,4 @@
4648
urlpatterns += static(paths.get_content_storage_url("/"), document_root=settings.CONTENT_STORAGE_DIR)
4749
urlpatterns += static(paths.get_content_database_url("/"), document_root=settings.CONTENT_DATABASE_DIR)
4850

49-
urlpatterns += [url(r'^i18n/', include('django.conf.urls.i18n'))]
51+
urlpatterns += [url(r'^i18n/setlang/$', set_language, name='set_language')]

0 commit comments

Comments
 (0)