From 64778cdf69806d310d7ef0ea46383f1562317187 Mon Sep 17 00:00:00 2001 From: asadiqbal <aiqbal@edx.org> Date: Mon, 1 Feb 2016 17:32:50 +0500 Subject: [PATCH] WL-272 --- cms/envs/bok_choy.env.json | 3 +- cms/envs/common.py | 8 +++ cms/static/cms/js/require-config.js | 4 ++ cms/static/js/factories/base.js | 2 +- cms/static/sass/elements/_header.scss | 28 ++++++++-- cms/templates/widgets/header.html | 28 +++++++++- cms/urls.py | 8 +++ common/djangoapps/lang_pref/middleware.py | 30 ++++++---- .../lang_pref/tests/test_middleware.py | 25 ++++++++- .../djangoapps/lang_pref/tests/test_views.py | 38 +++++++++++++ common/djangoapps/lang_pref/views.py | 22 ++++++++ .../templates/static_content.html | 5 ++ .../static/js/fixtures/lang-edx-fixture.html | 2 +- common/static/js/src/lang_edx.js | 56 ++++++++++++------- common/test/acceptance/pages/studio/index.py | 11 ++++ .../tests/studio/test_studio_home.py | 39 +++++++++++++ lms/envs/common.py | 2 +- lms/static/sass/shared/_header.scss | 5 +- lms/templates/navigation.html | 54 +++++++++--------- lms/urls.py | 3 + 20 files changed, 300 insertions(+), 73 deletions(-) create mode 100644 common/djangoapps/lang_pref/tests/test_views.py create mode 100644 common/djangoapps/lang_pref/views.py diff --git a/cms/envs/bok_choy.env.json b/cms/envs/bok_choy.env.json index 52fc8842025..ce0d95e8d3b 100644 --- a/cms/envs/bok_choy.env.json +++ b/cms/envs/bok_choy.env.json @@ -76,7 +76,8 @@ "PREVIEW_LMS_BASE": "localhost:8003", "ALLOW_ALL_ADVANCED_COMPONENTS": true, "ENABLE_CONTENT_LIBRARIES": true, - "ENABLE_SPECIAL_EXAMS": true + "ENABLE_SPECIAL_EXAMS": true, + "SHOW_LANGUAGE_SELECTOR": true }, "FEEDBACK_SUBMISSION_EMAIL": "", "GITHUB_REPO_ROOT": "** OVERRIDDEN **", diff --git a/cms/envs/common.py b/cms/envs/common.py index 997a8b83811..03a275ebabd 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -190,6 +190,9 @@ FEATURES = { 'ENABLE_SPECIAL_EXAMS': False, 'ORGANIZATIONS_APP': False, + + # Show Language selector + 'SHOW_LANGUAGE_SELECTOR': False, } ENABLE_JASMINE = False @@ -328,6 +331,9 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.messages.middleware.MessageMiddleware', 'track.middleware.TrackMiddleware', + # This is used to set or update the user language preferences. + 'lang_pref.middleware.LanguagePreferenceMiddleware', + # Allows us to dark-launch particular languages 'dark_lang.middleware.DarkLangMiddleware', @@ -1111,6 +1117,8 @@ OAUTH_OIDC_ISSUER = 'https://www.example.com/oauth2' # 5 minute expiration time for JWT id tokens issued for external API requests. OAUTH_ID_TOKEN_EXPIRATION = 5 * 60 +USERNAME_PATTERN = r'(?P<username>[\w.@+-]+)' + # Partner support link for CMS footer PARTNER_SUPPORT_EMAIL = '' diff --git a/cms/static/cms/js/require-config.js b/cms/static/cms/js/require-config.js index 167ed761748..190ae8ebe93 100644 --- a/cms/static/cms/js/require-config.js +++ b/cms/static/cms/js/require-config.js @@ -87,6 +87,7 @@ "ova": 'js/vendor/ova/ova', "catch": 'js/vendor/ova/catch/js/catch', "handlebars": 'js/vendor/ova/catch/js/handlebars-1.1.2', + "lang_edx": "js/src/lang_edx", // end of Annotation tool files // externally hosted files @@ -196,6 +197,9 @@ "tinymce": { exports: "tinymce" }, + "lang_edx": { + deps: ["jquery"] + }, "mathjax": { exports: "MathJax", init: function() { diff --git a/cms/static/js/factories/base.js b/cms/static/js/factories/base.js index b33a8123faf..305705dea13 100644 --- a/cms/static/js/factories/base.js +++ b/cms/static/js/factories/base.js @@ -1,2 +1,2 @@ define(['js/base', 'coffee/src/main', 'js/src/logger', 'datepair', 'accessibility', -'ieshim', 'tooltip_manager']); +'ieshim', 'tooltip_manager', 'lang_edx']); diff --git a/cms/static/sass/elements/_header.scss b/cms/static/sass/elements/_header.scss index e538dfd9202..386e30ee148 100644 --- a/cms/static/sass/elements/_header.scss +++ b/cms/static/sass/elements/_header.scss @@ -43,8 +43,19 @@ vertical-align: middle; } + .user-language-selector { + width: 120px; + display: inline-block; + margin: 0 10px 0 5px; + vertical-align: sub; + + .language-selector { + width: 120px; + } + } + .nav-account { - width: 100%; + width: auto; } // basic layout - nav items @@ -208,6 +219,13 @@ } } } + + .settings-language-form { + margin-top: 4px; + .language-selector { + width: 130px; + } + } } // ==================== @@ -229,11 +247,11 @@ .is-signedin { .wrapper-l { - width: flex-grid(9,12); + width: flex-grid(8,12); } .wrapper-r { - width: flex-grid(3,12); + width: flex-grid(4,12); } .branding { @@ -253,11 +271,11 @@ .wrapper-header { .wrapper-l { - width: flex-grid(9,12); + width: flex-grid(8,12); } .wrapper-r { - width: flex-grid(3,12); + width: flex-grid(4,12); } .branding { diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html index 6f229fe86a6..2cfa82bcc6c 100644 --- a/cms/templates/widgets/header.html +++ b/cms/templates/widgets/header.html @@ -6,7 +6,6 @@ from contentstore.context_processors import doc_url %> <%page args="online_help_token"/> - <div class="wrapper-header wrapper" id="view-top"> <header class="primary" role="banner"> @@ -188,6 +187,32 @@ </div> <div class="wrapper wrapper-r"> + % if static.show_language_selector(): + <% languages = static.get_released_languages() %> + % if len(languages) > 1: + <nav class="user-language-selector"> + <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}"> + % if user.is_authenticated(): + <input title="preference api" type="hidden" id="preference-api-url" class="url-endpoint" value="${reverse('preferences_api', kwargs={'username': user.username})}" data-user-is-authenticated="true"> + % else: + <input title="session update url" type="hidden" id="update-session-url" class="url-endpoint" value="${reverse('session_language')}" data-user-is-authenticated="false"> + % endif + <label><span class="sr">${_("Choose Language")}</span> + <select class="input select language-selector" 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> + </nav> + % endif + % endif % if user.is_authenticated(): <nav class="nav-account nav-is-signedin nav-dd ui-right" aria-label="${_('Account')}"> <h2 class="sr">${_("Account Navigation")}</h2> @@ -195,7 +220,6 @@ <li class="nav-item nav-account-help"> <h3 class="title"><span class="label"><a href="${get_online_help_info(online_help_token)['doc_url']}" title="${_("Contextual Online Help")}" target="_blank">${_("Help")}</a></span></h3> </li> - <li class="nav-item nav-account-user"> <h3 class="title"><span class="label"><span class="label-prefix sr">${_("Currently signed in as:")}</span><span class="account-username" title="${ user.username }">${ user.username }</span></span> <i class="icon fa fa-caret-down ui-toggle-dd"></i></h3> diff --git a/cms/urls.py b/cms/urls.py index 2b85e924719..cfd79baea75 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -52,6 +52,14 @@ urlpatterns = patterns( url(r'^heartbeat$', include('heartbeat.urls')), url(r'^user_api/', include('openedx.core.djangoapps.user_api.legacy_urls')), + + url(r'^i18n/', include('django.conf.urls.i18n')), + + # User API endpoints + url(r'^api/user/', include('openedx.core.djangoapps.user_api.urls')), + + # Update session view + url(r'^lang_pref/session_language', 'lang_pref.views.update_session_language', name='session_language'), ) # User creation and updating views diff --git a/common/djangoapps/lang_pref/middleware.py b/common/djangoapps/lang_pref/middleware.py index 7fdd29e985e..ad94534eeca 100644 --- a/common/djangoapps/lang_pref/middleware.py +++ b/common/djangoapps/lang_pref/middleware.py @@ -2,7 +2,7 @@ Middleware for Language Preferences """ -from openedx.core.djangoapps.user_api.preferences.api import get_user_preference +from openedx.core.djangoapps.user_api.preferences.api import get_user_preference, delete_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 @@ -21,20 +21,26 @@ class LanguagePreferenceMiddleware(object): """ If a user's UserPreference contains a language preference, use the user's preference. """ + languages = released_languages() + system_released_languages = [seq[0] for seq in languages] + # If the user is logged in, check for their language preference if request.user.is_authenticated(): # Get the user's language preference user_pref = get_user_preference(request.user, LANGUAGE_KEY) # 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 + if user_pref in system_released_languages: + request.session[LANGUAGE_SESSION_KEY] = user_pref + else: + delete_user_preference(request.user, LANGUAGE_KEY) + else: + preferred_language = request.META.get('HTTP_ACCEPT_LANGUAGE', '') + lang_headers = [seq[0] for seq in parse_accept_lang_header(preferred_language)] + + # Setting the session language to the browser language, if it is supported. + for browser_lang in lang_headers: + if browser_lang in system_released_languages: + if request.session.get(LANGUAGE_SESSION_KEY, None) is None: + request.session[LANGUAGE_SESSION_KEY] = unicode(browser_lang) + break diff --git a/common/djangoapps/lang_pref/tests/test_middleware.py b/common/djangoapps/lang_pref/tests/test_middleware.py index 47405fecac3..0166c46747e 100644 --- a/common/djangoapps/lang_pref/tests/test_middleware.py +++ b/common/djangoapps/lang_pref/tests/test_middleware.py @@ -7,6 +7,7 @@ from lang_pref.middleware import LanguagePreferenceMiddleware 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 +from student.tests.factories import AnonymousUserFactory import mock @@ -20,6 +21,7 @@ class TestUserPreferenceMiddleware(TestCase): self.middleware = LanguagePreferenceMiddleware() self.session_middleware = SessionMiddleware() self.user = UserFactory.create() + self.anonymous_user = AnonymousUserFactory() self.request = RequestFactory().get('/somewhere') self.request.user = self.user self.request.META['HTTP_ACCEPT_LANGUAGE'] = 'ar;q=1.0' # pylint: disable=no-member @@ -30,12 +32,16 @@ class TestUserPreferenceMiddleware(TestCase): self.middleware.process_request(self.request) self.assertNotIn(LANGUAGE_SESSION_KEY, self.request.session) + @mock.patch('lang_pref.middleware.released_languages', mock.Mock(return_value=[('eo', 'esperanto')])) def test_language_in_user_prefs(self): # language set in the user preferences and not the session set_user_preference(self.user, LANGUAGE_KEY, 'eo') 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=[('en', 'english'), ('eo', 'esperanto')] + )) def test_language_in_session(self): # language set in both the user preferences and session, # preference should get precedence. The session will hold the last value, @@ -53,16 +59,29 @@ class TestUserPreferenceMiddleware(TestCase): 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. + test: browser language should be set in user session if it is supported by system for unauthenticated user. """ - self.assertEquals(get_user_preference(self.request.user, LANGUAGE_KEY), None) + self.request.user = self.anonymous_user 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. + test: browser language should not be set in user session if it is not supported by system. """ + self.request.user = self.anonymous_user self.middleware.process_request(self.request) self.assertNotEqual(self.request.session.get(LANGUAGE_SESSION_KEY), 'ar') # pylint: disable=no-member + + @mock.patch('lang_pref.middleware.released_languages', mock.Mock( + return_value=[('en', 'english'), ('ar', 'arabic')] + )) + def test_delete_user_lang_preference_not_supported_by_system(self): + """ + test: user preferred language has been removed from user preferences model if it is not supported by system + for authenticated users. + """ + set_user_preference(self.user, LANGUAGE_KEY, 'eo') + self.middleware.process_request(self.request) + self.assertEqual(get_user_preference(self.request.user, LANGUAGE_KEY), None) diff --git a/common/djangoapps/lang_pref/tests/test_views.py b/common/djangoapps/lang_pref/tests/test_views.py new file mode 100644 index 00000000000..055345c0175 --- /dev/null +++ b/common/djangoapps/lang_pref/tests/test_views.py @@ -0,0 +1,38 @@ +""" +Tests: lang pref views +""" +import json +from django.test import TestCase +from django.test.client import RequestFactory +from django.core.urlresolvers import reverse +from student.tests.factories import UserFactory +from django.utils.translation import LANGUAGE_SESSION_KEY +from django.contrib.sessions.middleware import SessionMiddleware +from django.utils.translation import get_language + + +class TestLangPrefView(TestCase): + """ + Language preference view tests. + """ + + def setUp(self): + super(TestLangPrefView, self).setUp() + self.session_middleware = SessionMiddleware() + self.user = UserFactory.create() + self.request = RequestFactory().get('/somewhere') + self.request.user = self.user + self.session_middleware.process_request(self.request) + + def test_language_session_update(self): + # test language session updating correctly. + self.request.session[LANGUAGE_SESSION_KEY] = 'ar' # pylint: disable=no-member + response = self.client.patch(reverse("session_language"), json.dumps({'pref-lang': 'eo'})) + self.assertEqual(response.status_code, 200) + self.client.get('/') + self.assertEquals(get_language(), 'eo') + + response = self.client.patch(reverse("session_language"), json.dumps({'pref-lang': 'en'})) + self.assertEqual(response.status_code, 200) + self.client.get('/') + self.assertEquals(get_language(), 'en') diff --git a/common/djangoapps/lang_pref/views.py b/common/djangoapps/lang_pref/views.py new file mode 100644 index 00000000000..e444724fb9d --- /dev/null +++ b/common/djangoapps/lang_pref/views.py @@ -0,0 +1,22 @@ +""" +Language Preference Views +""" +import json +from django.conf import settings +from django.views.decorators.csrf import ensure_csrf_cookie +from django.utils.translation import LANGUAGE_SESSION_KEY +from lang_pref import LANGUAGE_KEY +from django.http import HttpResponse + + +@ensure_csrf_cookie +def update_session_language(request): + """ + Update the language session key. + """ + if request.method == 'PATCH': + data = json.loads(request.body) + language = data.get(LANGUAGE_KEY, settings.LANGUAGE_CODE) + if request.session.get(LANGUAGE_SESSION_KEY, None) != language: + request.session[LANGUAGE_SESSION_KEY] = unicode(language) + return HttpResponse(200) diff --git a/common/djangoapps/pipeline_mako/templates/static_content.html b/common/djangoapps/pipeline_mako/templates/static_content.html index 68c0263dca8..20e527f5c98 100644 --- a/common/djangoapps/pipeline_mako/templates/static_content.html +++ b/common/djangoapps/pipeline_mako/templates/static_content.html @@ -6,6 +6,7 @@ from mako.exceptions import TemplateLookupException from openedx.core.djangoapps.theming.helpers import get_page_title_breadcrumbs, get_value, get_template_path, get_themed_template_path, is_request_in_themed_site from certificates.api import get_asset_url_by_slug +from lang_pref.api import released_languages %> <%def name='url(file, raw=False)'><% @@ -132,3 +133,7 @@ else: <%def name="show_language_selector()"><% return settings.FEATURES.get('SHOW_LANGUAGE_SELECTOR', False) %></%def> + +<%def name="get_released_languages()"><% + return released_languages() +%></%def> diff --git a/common/static/js/fixtures/lang-edx-fixture.html b/common/static/js/fixtures/lang-edx-fixture.html index aaf95bed5f3..fe7cb1acc28 100644 --- a/common/static/js/fixtures/lang-edx-fixture.html +++ b/common/static/js/fixtures/lang-edx-fixture.html @@ -1,5 +1,5 @@ <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/"> + <input title="preference api" class="url-endpoint" type="hidden" id="preference-api-url" value="/api/user/v1/preferences/test1/" data-user-is-authenticated="true"> <label><span class="sr">Choose Language</span> <select class="input select" id="settings-language-value" name="language"> <option value="en" selected="selected">English</option> diff --git a/common/static/js/src/lang_edx.js b/common/static/js/src/lang_edx.js index 65eb686c653..263ad3a560d 100644 --- a/common/static/js/src/lang_edx.js +++ b/common/static/js/src/lang_edx.js @@ -1,12 +1,9 @@ -var edx = edx || {}, - Language = (function() { +var Language = (function() { 'use strict'; - var preference_api_url, - settings_language_selector, + var 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(); @@ -18,32 +15,49 @@ var edx = edx || {}, */ listenForLanguagePreferenceChange: function() { settings_language_selector.change(function(event) { - var language = this.value; + var language = this.value, + url = $('.url-endpoint').val(), + is_user_authenticated = JSON.parse($('.url-endpoint').data('user-is-authenticated')); 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()); + self.submitAjaxRequest(language, url, function() { + if (is_user_authenticated) { + // User language preference has been set successfully + // Now submit the form in success callback. + $('#language-settings-form').submit(); + } else { + self.refresh(); } - }).done(function () { - // User language preference has been set successfully - // Now submit the form in success callback. - $("#language-settings-form").submit(); - }).fail(function() { - self.refresh(); }); }); }, + /** + * Send an ajax request to set user language preferences. + */ + submitAjaxRequest: function(language, url, callback) { + + $.ajax({ + type: 'PATCH', + data: JSON.stringify({'pref-lang': language}) , + url: url, + dataType: 'json', + contentType: 'application/merge-patch+json', + notifyOnError: false, + beforeSend: function (xhr) { + xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); + } + }).done(function () { + callback(); + }).fail(function() { + self.refresh(); + }); + }, + /** * refresh the page. */ refresh: function () { - // reloading the page so we can get the latest state of realsesd languages from model + // reloading the page so we can get the latest state of released languages from model location.reload(); } diff --git a/common/test/acceptance/pages/studio/index.py b/common/test/acceptance/pages/studio/index.py index 3d2a3fdf9f3..f6f122e5813 100644 --- a/common/test/acceptance/pages/studio/index.py +++ b/common/test/acceptance/pages/studio/index.py @@ -225,6 +225,17 @@ class DashboardPage(PageObject): return True return False + @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') + class DashboardPageWithPrograms(DashboardPage): """ diff --git a/common/test/acceptance/tests/studio/test_studio_home.py b/common/test/acceptance/tests/studio/test_studio_home.py index d5309c16c90..3142d6b78a8 100644 --- a/common/test/acceptance/tests/studio/test_studio_home.py +++ b/common/test/acceptance/tests/studio/test_studio_home.py @@ -10,6 +10,11 @@ from ...fixtures.programs import ProgramsFixture from ...pages.studio.auto_auth import AutoAuthPage from ...pages.studio.library import LibraryEditPage from ...pages.studio.index import DashboardPage, DashboardPageWithPrograms +from ...pages.lms.account_settings import AccountSettingsPage +from ..helpers import ( + select_option_by_text, + get_selected_option_text +) class CreateLibraryTest(WebAppTest): @@ -139,3 +144,37 @@ class DashboardProgramsTabTest(WebAppTest): self.dashboard_page.visit() self.assertFalse(self.dashboard_page.is_programs_tab_present()) self.assertFalse(self.dashboard_page.is_new_program_button_present()) + + +class StudioLanguageTest(WebAppTest): + """ Test suite for the Studio Language """ + def setUp(self): + super(StudioLanguageTest, self).setUp() + self.dashboard_page = DashboardPage(self.browser) + self.account_settings = AccountSettingsPage(self.browser) + AutoAuthPage(self.browser).visit() + + def test_studio_language_change(self): + """ + Scenario: Ensure that language selection is working fine. + First I go to the user dashboard page in studio. 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. + """ + dummy_language = u'Dummy Language (Esperanto)' + 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) + self.dashboard_page.wait_for_ajax() + self.account_settings.visit() + self.assertEqual(self.account_settings.value_for_dropdown_field('pref-lang'), dummy_language) + self.assertEqual( + get_selected_option_text(language_selector), + u'Dummy Language (Esperanto)' + ) diff --git a/lms/envs/common.py b/lms/envs/common.py index be786340a2b..f874a9a7ef1 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -365,7 +365,7 @@ FEATURES = { # Enable LTI Provider feature. 'ENABLE_LTI_PROVIDER': False, - # Show LMS Language selector + # Show Language selector. 'SHOW_LANGUAGE_SELECTOR': False, } diff --git a/lms/static/sass/shared/_header.scss b/lms/static/sass/shared/_header.scss index d1dc31e846c..670077a258c 100644 --- a/lms/static/sass/shared/_header.scss +++ b/lms/static/sass/shared/_header.scss @@ -119,7 +119,10 @@ header.global { margin: 0; .settings-language-form { - margin-top: 4px; + margin: 4px; + .language-selector { + width: 120px; + } } > .primary { diff --git a/lms/templates/navigation.html b/lms/templates/navigation.html index 962153e5d10..1405b9c7bd3 100644 --- a/lms/templates/navigation.html +++ b/lms/templates/navigation.html @@ -14,7 +14,6 @@ from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_ 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. @@ -38,7 +37,6 @@ site_status_msg = get_site_status_msg(course_id) </div> % endif </%block> - <header id="global-navigation" class="global ${"slim" if course else ""}" > <nav class="nav-wrapper" aria-label="${_('Global')}"> <h1 class="logo"> @@ -79,28 +77,6 @@ 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> @@ -186,7 +162,35 @@ site_status_msg = get_site_status_msg(course_id) </%block> </ol> % endif - </nav> + % if static.show_language_selector(): + <% languages = static.get_released_languages() %> + % if len(languages) > 1: + <ol class="user"> + <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}"> + % if user.is_authenticated(): + <input title="preference api" type="hidden" class="url-endpoint" value="${reverse('preferences_api', kwargs={'username': user.username})}" data-user-is-authenticated="true"> + % else: + <input title="session update url" type="hidden" class="url-endpoint" value="${reverse('session_language')}" data-user-is-authenticated="false"> + % endif + <label><span class="sr">${_("Choose Language")}</span> + <select class="input select language-selector" 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> + </ol> + % endif + % endif + </nav> </header> % if course: <!--[if lte IE 9]> diff --git a/lms/urls.py b/lms/urls.py index dc201de5d03..078797bf3a8 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -103,6 +103,9 @@ urlpatterns = ( url(r'^rss_proxy/', include('rss_proxy.urls', namespace='rss_proxy')), url(r'^api/organizations/', include('organizations.urls', namespace='organizations')), + # Update session view + url(r'^lang_pref/session_language', 'lang_pref.views.update_session_language', name='session_language'), + # Multiple course modes and identity verification # TODO Namespace these! url(r'^course_modes/', include('course_modes.urls')), -- GitLab