Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
99b883b7
Commit
99b883b7
authored
9 years ago
by
asadiqbal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WL-243 LMS Language Selection
parent
0c55f17d
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
256 additions
and
4 deletions
+256
-4
common/djangoapps/lang_pref/middleware.py
+12
-0
common/djangoapps/lang_pref/tests/test_middleware.py
+21
-1
common/djangoapps/pipeline_mako/templates/static_content.html
+4
-0
common/static/js/fixtures/lang-edx-fixture.html
+9
-0
common/static/js/spec/lang_edx_spec.js
+60
-0
common/static/js/src/lang_edx.js
+55
-0
common/test/acceptance/pages/lms/dashboard.py
+11
-0
common/test/acceptance/tests/lms/test_lms.py
+50
-1
lms/envs/bok_choy.env.json
+2
-1
lms/envs/common.py
+4
-0
lms/static/js/views/fields.js
+1
-1
lms/static/sass/shared/_header.scss
+4
-0
lms/templates/navigation.html
+23
-0
No files found.
common/djangoapps/lang_pref/middleware.py
View file @
99b883b7
...
...
@@ -5,6 +5,8 @@ Middleware for Language Preferences
from
openedx.core.djangoapps.user_api.preferences.api
import
get_user_preference
from
lang_pref
import
LANGUAGE_KEY
from
django.utils.translation
import
LANGUAGE_SESSION_KEY
from
django.utils.translation.trans_real
import
parse_accept_lang_header
from
lang_pref.api
import
released_languages
class
LanguagePreferenceMiddleware
(
object
):
...
...
@@ -26,3 +28,13 @@ class LanguagePreferenceMiddleware(object):
# Set it to the LANGUAGE_SESSION_KEY (Django-specific session setting governing language pref)
if
user_pref
:
request
.
session
[
LANGUAGE_SESSION_KEY
]
=
user_pref
else
:
# Setting the session language to the browser language, if it is supported.
preferred_language
=
request
.
META
.
get
(
'HTTP_ACCEPT_LANGUAGE'
,
''
)
lang_headers
=
[
seq
[
0
]
for
seq
in
parse_accept_lang_header
(
preferred_language
)]
languages
=
released_languages
()
for
browser_lang
in
lang_headers
:
if
browser_lang
in
[
seq
[
0
]
for
seq
in
languages
]:
if
request
.
session
.
get
(
LANGUAGE_SESSION_KEY
,
None
)
!=
browser_lang
:
request
.
session
[
LANGUAGE_SESSION_KEY
]
=
unicode
(
browser_lang
)
break
This diff is collapsed.
Click to expand it.
common/djangoapps/lang_pref/tests/test_middleware.py
View file @
99b883b7
...
...
@@ -4,9 +4,10 @@ from django.contrib.sessions.middleware import SessionMiddleware
from
django.utils.translation
import
LANGUAGE_SESSION_KEY
from
lang_pref.middleware
import
LanguagePreferenceMiddleware
from
openedx.core.djangoapps.user_api.preferences.api
import
set_user_preference
from
openedx.core.djangoapps.user_api.preferences.api
import
set_user_preference
,
get_user_preference
from
lang_pref
import
LANGUAGE_KEY
from
student.tests.factories
import
UserFactory
import
mock
class
TestUserPreferenceMiddleware
(
TestCase
):
...
...
@@ -21,6 +22,7 @@ class TestUserPreferenceMiddleware(TestCase):
self
.
user
=
UserFactory
.
create
()
self
.
request
=
RequestFactory
()
.
get
(
'/somewhere'
)
self
.
request
.
user
=
self
.
user
self
.
request
.
META
[
'HTTP_ACCEPT_LANGUAGE'
]
=
'ar;q=1.0'
# pylint: disable=no-member
self
.
session_middleware
.
process_request
(
self
.
request
)
def
test_no_language_set_in_session_or_prefs
(
self
):
...
...
@@ -46,3 +48,21 @@ class TestUserPreferenceMiddleware(TestCase):
self
.
middleware
.
process_request
(
self
.
request
)
self
.
assertEquals
(
self
.
request
.
session
[
LANGUAGE_SESSION_KEY
],
'eo'
)
@mock.patch
(
'lang_pref.middleware.released_languages'
,
mock
.
Mock
(
return_value
=
[(
'eo'
,
'dummy Esperanto'
),
(
'ar'
,
'arabic'
)]))
def
test_supported_browser_language_in_session
(
self
):
"""
test: browser language should be set in user preferences if it is supported by system.
"""
self
.
assertEquals
(
get_user_preference
(
self
.
request
.
user
,
LANGUAGE_KEY
),
None
)
self
.
middleware
.
process_request
(
self
.
request
)
self
.
assertEqual
(
self
.
request
.
session
[
LANGUAGE_SESSION_KEY
],
'ar'
)
# pylint: disable=no-member
@mock.patch
(
'lang_pref.middleware.released_languages'
,
mock
.
Mock
(
return_value
=
[(
'en'
,
'english'
)]))
def
test_browser_language_not_be_in_session
(
self
):
"""
test: browser language should not be set in user preferences if it is not supported by system.
"""
self
.
middleware
.
process_request
(
self
.
request
)
self
.
assertNotEqual
(
self
.
request
.
session
.
get
(
LANGUAGE_SESSION_KEY
),
'ar'
)
# pylint: disable=no-member
This diff is collapsed.
Click to expand it.
common/djangoapps/pipeline_mako/templates/static_content.html
View file @
99b883b7
...
...
@@ -124,3 +124,7 @@ else:
<
%
def
name=
"is_request_in_themed_site()"
><
%
return
is_request_in_themed_site
()
%
></
%
def>
<
%
def
name=
"show_language_selector()"
><
%
return
settings
.
FEATURES
.
get
('
SHOW_LANGUAGE_SELECTOR
',
False
)
%
></
%
def>
This diff is collapsed.
Click to expand it.
common/static/js/fixtures/lang-edx-fixture.html
0 → 100644
View file @
99b883b7
<form
action=
"/i18n/setlang/"
method=
"post"
class=
"settings-language-form"
id=
"language-settings-form"
>
<input
title=
"preference api"
type=
"hidden"
id=
"preference-api-url"
value=
"/api/user/v1/preferences/test1/"
>
<label><span
class=
"sr"
>
Choose Language
</span>
<select
class=
"input select"
id=
"settings-language-value"
name=
"language"
>
<option
value=
"en"
selected=
"selected"
>
English
</option>
<option
value=
"ar"
>
Arabic
</option>
</select>
</label>
</form>
This diff is collapsed.
Click to expand it.
common/static/js/spec/lang_edx_spec.js
0 → 100644
View file @
99b883b7
/*global Language:true*/
(
function
()
{
'use strict'
;
describe
(
'Language change test for lang-edx.js'
,
function
()
{
var
lang_selector
,
deferred
;
beforeEach
(
function
()
{
loadFixtures
(
'js/fixtures/lang-edx-fixture.html'
);
lang_selector
=
$
(
'#settings-language-value'
);
deferred
=
$
.
Deferred
();
});
it
(
"can spy on language selector change event"
,
function
()
{
spyOnEvent
(
lang_selector
,
'change'
);
lang_selector
.
trigger
(
'change'
);
expect
(
'change'
).
toHaveBeenTriggeredOn
(
lang_selector
);
});
it
(
"should make an AJAX request to the correct URL"
,
function
()
{
spyOn
(
$
,
'ajax'
).
andReturn
(
deferred
);
Language
.
init
();
lang_selector
.
trigger
(
'change'
);
expect
(
$
.
ajax
.
mostRecentCall
.
args
[
0
].
url
).
toEqual
(
"/api/user/v1/preferences/test1/"
);
});
it
(
"should make an AJAX request with correct type"
,
function
()
{
spyOn
(
$
,
'ajax'
).
andReturn
(
deferred
);
Language
.
init
();
lang_selector
.
trigger
(
'change'
);
expect
(
$
.
ajax
.
mostRecentCall
.
args
[
0
].
type
).
toEqual
(
"PATCH"
);
});
it
(
"should make an AJAX request with correct data"
,
function
()
{
spyOn
(
$
,
'ajax'
).
andReturn
(
deferred
);
Language
.
init
();
lang_selector
.
val
(
'ar'
);
lang_selector
.
trigger
(
'change'
);
expect
(
$
.
ajax
.
mostRecentCall
.
args
[
0
].
data
).
toEqual
(
'{"pref-lang":"ar"}'
);
// change to 'en' from 'ar'
lang_selector
.
val
(
'en'
);
lang_selector
.
trigger
(
'change'
);
expect
(
$
.
ajax
.
mostRecentCall
.
args
[
0
].
data
).
toEqual
(
'{"pref-lang":"en"}'
);
});
it
(
"should call refresh on ajax failure"
,
function
()
{
spyOn
(
$
,
'ajax'
).
andCallFake
(
function
()
{
var
d
=
$
.
Deferred
();
d
.
reject
();
return
d
.
promise
();
});
Language
.
init
();
spyOn
(
Language
,
'refresh'
);
lang_selector
.
trigger
(
'change'
);
expect
(
Language
.
refresh
).
toHaveBeenCalled
();
});
});
}).
call
(
this
);
This diff is collapsed.
Click to expand it.
common/static/js/src/lang_edx.js
0 → 100644
View file @
99b883b7
var
edx
=
edx
||
{},
Language
=
(
function
()
{
'use strict'
;
var
preference_api_url
,
settings_language_selector
,
self
=
null
;
return
{
init
:
function
()
{
preference_api_url
=
$
(
'#preference-api-url'
).
val
();
settings_language_selector
=
$
(
'#settings-language-value'
);
self
=
this
;
this
.
listenForLanguagePreferenceChange
();
},
/**
* Listener on changing language from selector.
* Send an ajax request to save user language preferences.
*/
listenForLanguagePreferenceChange
:
function
()
{
settings_language_selector
.
change
(
function
(
event
)
{
var
language
=
this
.
value
;
event
.
preventDefault
();
$
.
ajax
({
type
:
'PATCH'
,
data
:
JSON
.
stringify
({
'pref-lang'
:
language
})
,
url
:
preference_api_url
,
dataType
:
'json'
,
contentType
:
"application/merge-patch+json"
,
beforeSend
:
function
(
xhr
)
{
xhr
.
setRequestHeader
(
"X-CSRFToken"
,
$
(
'#csrf_token'
).
val
());
}
}).
done
(
function
()
{
// User language preference has been set successfully
// Now submit the form in success callback.
$
(
"#language-settings-form"
).
submit
();
}).
fail
(
function
()
{
self
.
refresh
();
});
});
},
/**
* refresh the page.
*/
refresh
:
function
()
{
// reloading the page so we can get the latest state of realsesd languages from model
location
.
reload
();
}
};
})();
$
(
document
).
ready
(
function
()
{
'use strict'
;
Language
.
init
();
});
This diff is collapsed.
Click to expand it.
common/test/acceptance/pages/lms/dashboard.py
View file @
99b883b7
...
...
@@ -192,3 +192,14 @@ class DashboardPage(PageObject):
Click on `Account` link.
"""
self
.
q
(
css
=
'.dropdown-menu li a'
)
.
nth
(
2
)
.
click
()
@property
def
language_selector
(
self
):
"""
return language selector
"""
self
.
wait_for_element_visibility
(
'#settings-language-value'
,
'Language selector element is available'
)
return
self
.
q
(
css
=
'#settings-language-value'
)
This diff is collapsed.
Click to expand it.
common/test/acceptance/tests/lms/test_lms.py
View file @
99b883b7
...
...
@@ -16,7 +16,9 @@ from ..helpers import (
load_data_str
,
generate_course_key
,
select_option_by_value
,
element_has_text
element_has_text
,
select_option_by_text
,
get_selected_option_text
)
from
...pages.lms
import
BASE_URL
from
...pages.lms.account_settings
import
AccountSettingsPage
...
...
@@ -1130,3 +1132,50 @@ class NotLiveRedirectTest(UniqueCourseTest):
'The course you are looking for does not start until'
,
page
.
banner_text
)
@attr
(
'shard_1'
)
class
LMSLanguageTest
(
UniqueCourseTest
):
""" Test suite for the LMS Language """
def
setUp
(
self
):
super
(
LMSLanguageTest
,
self
)
.
setUp
()
self
.
dashboard_page
=
DashboardPage
(
self
.
browser
)
self
.
account_settings
=
AccountSettingsPage
(
self
.
browser
)
AutoAuthPage
(
self
.
browser
)
.
visit
()
def
test_lms_language_change
(
self
):
"""
Scenario: Ensure that language selection is working fine.
First I go to the user dashboard page in LMS. I can see 'English' is selected by default.
Then I choose 'Dummy Language' from drop down (at top of the page).
Then I visit the student account settings page and I can see the language has been updated to 'Dummy Language'
in both drop downs.
After that I select the 'English' language and visit the dashboard page again.
Then I can see that top level language selector persist its value to 'English'.
"""
self
.
dashboard_page
.
visit
()
language_selector
=
self
.
dashboard_page
.
language_selector
self
.
assertEqual
(
get_selected_option_text
(
language_selector
),
u'English'
)
select_option_by_text
(
language_selector
,
'Dummy Language (Esperanto)'
)
self
.
dashboard_page
.
wait_for_ajax
()
self
.
account_settings
.
visit
()
self
.
assertEqual
(
self
.
account_settings
.
value_for_dropdown_field
(
'pref-lang'
),
u'Dummy Language (Esperanto)'
)
self
.
assertEqual
(
get_selected_option_text
(
language_selector
),
u'Dummy Language (Esperanto)'
)
# changed back to English language.
select_option_by_text
(
language_selector
,
'English'
)
self
.
account_settings
.
wait_for_ajax
()
self
.
assertEqual
(
self
.
account_settings
.
value_for_dropdown_field
(
'pref-lang'
),
u'English'
)
self
.
dashboard_page
.
visit
()
self
.
assertEqual
(
get_selected_option_text
(
language_selector
),
u'English'
)
This diff is collapsed.
Click to expand it.
lms/envs/bok_choy.env.json
View file @
99b883b7
...
...
@@ -88,7 +88,8 @@
"MODE_CREATION_FOR_TESTING"
:
true
,
"AUTOMATIC_VERIFY_STUDENT_IDENTITY_FOR_TESTING"
:
true
,
"ENABLE_COURSE_DISCOVERY"
:
true
,
"ENABLE_SPECIAL_EXAMS"
:
true
"ENABLE_SPECIAL_EXAMS"
:
true
,
"SHOW_LANGUAGE_SELECTOR"
:
true
},
"FEEDBACK_SUBMISSION_EMAIL"
:
""
,
"GITHUB_REPO_ROOT"
:
"** OVERRIDDEN **"
,
...
...
This diff is collapsed.
Click to expand it.
lms/envs/common.py
View file @
99b883b7
...
...
@@ -367,6 +367,9 @@ FEATURES = {
# Enable LTI Provider feature.
'ENABLE_LTI_PROVIDER'
:
False
,
# Show LMS Language selector
'SHOW_LANGUAGE_SELECTOR'
:
False
,
}
# Ignore static asset files on import which match this pattern
...
...
@@ -1249,6 +1252,7 @@ base_application_js = [
'js/src/ie_shim.js'
,
'js/src/accessibility_tools.js'
,
'js/toggle_login_modal.js'
,
'js/src/lang_edx.js'
,
]
dashboard_js
=
(
...
...
This diff is collapsed.
Click to expand it.
lms/static/js/views/fields.js
View file @
99b883b7
...
...
@@ -114,7 +114,7 @@
this
.
showNotificationMessage
(
successMessage
);
if
(
this
.
options
.
refreshPageOnSave
)
{
document
.
location
.
reload
(
);
location
.
reload
(
true
);
}
var
view
=
this
;
...
...
This diff is collapsed.
Click to expand it.
lms/static/sass/shared/_header.scss
View file @
99b883b7
...
...
@@ -118,6 +118,10 @@ header.global {
margin-top
:
(
$baseline
/
4
);
padding-left
:
0
;
.settings-language-form
{
margin-top
:
4px
;
}
>
.primary
{
display
:
block
;
@include
float
(
left
);
...
...
This diff is collapsed.
Click to expand it.
lms/templates/navigation.html
View file @
99b883b7
...
...
@@ -11,6 +11,7 @@ from lms.djangoapps.ccx.overrides import get_current_ccx
from
branding
import
api
as
branding_api
#
app
that
handles
site
status
messages
from
status
.
status
import
get_site_status_msg
from
lang_pref
.
api
import
released_languages
%
>
## Provide a hook for themes to inject branding on top.
...
...
@@ -75,6 +76,28 @@ site_status_msg = get_site_status_msg(course_id)
</
%
block>
</ol>
<ol
class=
"user"
>
% if static.show_language_selector():
<
%
languages =
released_languages()
%
>
% if len(languages) > 1:
<li
class=
"primary"
>
<form
action=
"/i18n/setlang/"
method=
"post"
class=
"settings-language-form"
id=
"language-settings-form"
>
<input
type=
"hidden"
id=
"csrf_token"
name=
"csrfmiddlewaretoken"
value=
"${csrf_token}"
>
<input
title=
"preference api"
type=
"hidden"
id=
"preference-api-url"
value=
"${reverse('preferences_api', kwargs={'username': user.username})}"
>
<label><span
class=
"sr"
>
${_("Choose Language")}
</span>
<select
class=
"input select"
id=
"settings-language-value"
name=
"language"
>
% for language in languages:
% if language[0] == LANGUAGE_CODE:
<option
value=
"${language[0]}"
selected=
"selected"
>
${language[1]}
</option>
% else:
<option
value=
"${language[0]}"
>
${language[1]}
</option>
% endif
% endfor
</select>
</label>
</form>
</li>
% endif
% endif
<li
class=
"primary"
>
<a
href=
"${reverse('dashboard')}"
class=
"user-link"
>
<span
class=
"sr"
>
${_("Dashboard for:")}
</span>
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment