Commit b42a7a1c by Albert St. Aubin

Removed the Darklang preview-lang and clear-lang parameters and added the new…

Removed the Darklang preview-lang and clear-lang parameters and added the new DarkLang settings form at /update_lang

Remove the DarkLang middleware from the LMS

Created and basic routing to the update_lang page for the GET Request
TNL-4742

Basic form functionality

Working example in LMS of the form to set the language

Login now required to change the preview language, and corrected some minor bugs

Updates to move the template code to lms and to correct minor defects
TNL-4742

Added template for preview_lang.html to cms
TNL-4742

Changed filename of darklang.py to api.py to match convention
TNL-4742

Updated and refactored the Darklang tests
TNL-4742

Updated comments in tests
TNL-4742

Formating updates
TNL-4742

Updated comments and formatting
TNL-4742

Corrected i18n tests and corrected PEP8 format issues
TNL-4742

Code Lint/PEP-8 corrections and upates
TNL-4742

Removed constant that was not needed (to be squashed)
TNL-4742

Added init method to clear up PEP8 Warnings (will squash)
TNL-4742

PEP-8/Lint issue resolved (squash)

Updated for i18n
TNL-4742

Refactored the preview_lang.html page to use a common included template

Refactoring and changes from PR comments
TNL-4742

Correction for safecommit violation (Squash)
TNL-4742

PR changes and refactoring (Squash)

Updates to reduce changes made in the urls used
TNL-4742

Removed unneeded aria-described by and bug in MAKO Template (squash)
TNK-4742

Updated docstring comments

Clarified form response text

Minor PR request (Squash)

Refactoring of how the responses are generated within the DarkLang views file

A series of refactors in response to PR comments

Method name change for clarity in reponse to PR comments (Squash)

Updates to tests per PR requests (Squash)

Minor comment updates for clarity and PR requests (Squash)

Updated per PR comments and added a test for empty preview_language

Layout and code style updates (Squash)

Updated test to contain method in the request.

Removed the Darklang preview-lang and clear-lang parameters and added the new DarkLang settings form at /update_lang

Refactored tests and added some tests for coverage, corrected defect with empty input codes

Removed unused and obsolete code

Corrected test errors, resolved PR comments, and updated comments to clarify testing
TNL-4742

Updated tests to deal with Pylint quality issue (Squash)

Updated tests to better reflect test case and PR updates (Squash)
parent 99eb795a
## Override the default styles_version to the Pattern Library version (version 2)
<%! main_css = "style-main-v2" %>
<%page expression_filter="h"/>
<%!
from django.utils.translation import ugettext as _
%>
<%inherit file="../base.html" />
<%block name="title">${_("Preview Language Setting")}</%block>
<%block name="bodyclass">is-signedin pattern-library</%block>
<%block name="content">
<%include file="/darklang/preview_lang_include.html" />
</%block>
......@@ -55,6 +55,9 @@ urlpatterns = patterns(
# Update session view
url(r'^lang_pref/session_language', 'lang_pref.views.update_session_language', name='session_language'),
# Darklang View to change the preview language (or dark language)
url(r'^update_lang/', include('dark_lang.urls', namespace='darklang')),
)
# User creation and updating views
......
"""
Middleware for dark-launching languages. These languages won't be used
when determining which translation to give a user based on their browser
header, but can be selected by setting the ``preview-lang`` query parameter
to the language code.
Adding the query parameter ``clear-lang`` will reset the language stored
in the user's session.
header, but can be selected by setting the Preview Languages on the Dark
Language setting page.
This middleware must be placed before the LocaleMiddleware, but after
the SessionMiddleware.
......@@ -15,16 +12,29 @@ from django.conf import settings
from dark_lang import DARK_LANGUAGE_KEY
from dark_lang.models import DarkLangConfig
from openedx.core.djangoapps.user_api.preferences.api import (
delete_user_preference, get_user_preference, set_user_preference
get_user_preference
)
from lang_pref import LANGUAGE_KEY
from django.utils.translation.trans_real import parse_accept_lang_header
from django.utils.translation import LANGUAGE_SESSION_KEY
# If django 1.7 or higher is used, the right-side can be updated with new-style codes.
CHINESE_LANGUAGE_CODE_MAP = {
# The following are the new-style language codes for chinese language
'zh-hans': 'zh-CN', # Chinese (Simplified),
'zh-hans-cn': 'zh-CN', # Chinese (Simplified, China)
'zh-hans-sg': 'zh-CN', # Chinese (Simplified, Singapore)
'zh-hant': 'zh-TW', # Chinese (Traditional)
'zh-hant-hk': 'zh-HK', # Chinese (Traditional, Hongkong)
'zh-hant-mo': 'zh-TW', # Chinese (Traditional, Macau)
'zh-hant-tw': 'zh-TW', # Chinese (Traditional, Taiwan)
# The following are the old-style language codes that django does not recognize
'zh-mo': 'zh-TW', # Chinese (Traditional, Macau)
'zh-sg': 'zh-CN', # Chinese (Simplified, Singapore)
}
def dark_parse_accept_lang_header(accept):
'''
def _dark_parse_accept_lang_header(accept):
"""
The use of 'zh-cn' for 'Simplified Chinese' and 'zh-tw' for 'Traditional Chinese'
are now deprecated, as discussed here: https://code.djangoproject.com/ticket/18419.
The new language codes 'zh-hans' and 'zh-hant' are now used since django 1.7.
......@@ -34,7 +44,7 @@ def dark_parse_accept_lang_header(accept):
This function can keep compatibility between the old and new language codes. If one
day edX uses django 1.7 or higher, this function can be modified to support the old
language codes until there are no browsers use them.
'''
"""
browser_langs = parse_accept_lang_header(accept)
django_langs = []
for lang, priority in browser_langs:
......@@ -43,21 +53,6 @@ def dark_parse_accept_lang_header(accept):
return django_langs
# If django 1.7 or higher is used, the right-side can be updated with new-style codes.
CHINESE_LANGUAGE_CODE_MAP = {
# The following are the new-style language codes for chinese language
'zh-hans': 'zh-CN', # Chinese (Simplified),
'zh-hans-cn': 'zh-CN', # Chinese (Simplified, China)
'zh-hans-sg': 'zh-CN', # Chinese (Simplified, Singapore)
'zh-hant': 'zh-TW', # Chinese (Traditional)
'zh-hant-hk': 'zh-HK', # Chinese (Traditional, Hongkong)
'zh-hant-mo': 'zh-TW', # Chinese (Traditional, Macau)
'zh-hant-tw': 'zh-TW', # Chinese (Traditional, Taiwan)
# The following are the old-style language codes that django does not recognize
'zh-mo': 'zh-TW', # Chinese (Traditional, Macau)
'zh-sg': 'zh-CN', # Chinese (Simplified, Singapore)
}
class DarkLangMiddleware(object):
"""
......@@ -66,7 +61,6 @@ class DarkLangMiddleware(object):
This is configured by creating ``DarkLangConfig`` rows in the database,
using the django admin site.
"""
@property
def released_langs(self):
"""
......@@ -89,21 +83,16 @@ class DarkLangMiddleware(object):
def _fuzzy_match(self, lang_code):
"""Returns a fuzzy match for lang_code"""
match = None
if lang_code in self.released_langs:
return lang_code
lang_prefix = lang_code.partition('-')[0]
for released_lang in self.released_langs:
released_prefix = released_lang.partition('-')[0]
if lang_prefix == released_prefix:
return released_lang
return None
def _format_accept_value(self, lang, priority=1.0):
"""
Formats lang and priority into a valid accept header fragment.
"""
return "{};q={}".format(lang, priority)
match = lang_code
else:
lang_prefix = lang_code.partition('-')[0]
for released_lang in self.released_langs:
released_prefix = released_lang.partition('-')[0]
if lang_prefix == released_prefix:
match = released_lang
return match
def _clean_accept_headers(self, request):
"""
......@@ -115,10 +104,11 @@ class DarkLangMiddleware(object):
return
new_accept = []
for lang, priority in dark_parse_accept_lang_header(accept):
for lang, priority in _dark_parse_accept_lang_header(accept):
fuzzy_code = self._fuzzy_match(lang.lower())
if fuzzy_code:
new_accept.append(self._format_accept_value(fuzzy_code, priority))
# Formats lang and priority into a valid accept header fragment.
new_accept.append("{};q={}".format(fuzzy_code, priority))
new_accept = ", ".join(new_accept)
......@@ -126,29 +116,11 @@ class DarkLangMiddleware(object):
def _activate_preview_language(self, request):
"""
If the request has the get parameter ``preview-lang``,
and that language doesn't appear in ``self.released_langs``,
then set the session LANGUAGE_SESSION_KEY to that language.
Check the user's dark language setting in the session and apply it
"""
auth_user = request.user.is_authenticated()
if 'clear-lang' in request.GET:
# delete the session language key (if one is set)
if LANGUAGE_SESSION_KEY in request.session:
del request.session[LANGUAGE_SESSION_KEY]
if auth_user:
# Reset user's dark lang preference to null
delete_user_preference(request.user, DARK_LANGUAGE_KEY)
# Get & set user's preferred language
user_pref = get_user_preference(request.user, LANGUAGE_KEY)
if user_pref:
request.session[LANGUAGE_SESSION_KEY] = user_pref
return
# Get the user's preview lang - this is either going to be set from a query
# param `?preview-lang=xx`, or we may have one already set as a dark lang preference.
preview_lang = request.GET.get('preview-lang', None)
if not preview_lang and auth_user:
preview_lang = None
if auth_user:
# Get the request user's dark lang preference
preview_lang = get_user_preference(request.user, DARK_LANGUAGE_KEY)
......@@ -158,8 +130,3 @@ class DarkLangMiddleware(object):
# Set the session key to the requested preview lang
request.session[LANGUAGE_SESSION_KEY] = preview_lang
# Make sure that we set the requested preview lang as the dark lang preference for the
# user, so that the lang_pref middleware doesn't clobber away the dark lang preview.
if auth_user:
set_user_preference(request.user, DARK_LANGUAGE_KEY, preview_lang)
"""
Tests of DarkLangMiddleware
"""
from django.contrib.auth.models import User
from django.http import HttpRequest
import unittest
import ddt
from django.http import HttpRequest
from django.test import TestCase
from django.test.client import Client
from django.utils.translation import LANGUAGE_SESSION_KEY
from mock import Mock
import unittest
from dark_lang.middleware import DarkLangMiddleware
from dark_lang.models import DarkLangConfig
from django.utils.translation import LANGUAGE_SESSION_KEY
from student.tests.factories import UserFactory
UNSET = object()
......@@ -34,23 +32,23 @@ class DarkLangMiddlewareTests(TestCase):
"""
def setUp(self):
super(DarkLangMiddlewareTests, self).setUp()
self.user = User()
self.user = UserFactory.build(username='test', email='test@edx.org', password='test_password')
self.user.save()
self.client = Client()
self.client.login(username=self.user.username, password='test_password')
DarkLangConfig(
released_languages='rel',
changed_by=self.user,
enabled=True
).save()
def process_request(self, language_session_key=UNSET, accept=UNSET, preview_lang=UNSET, clear_lang=UNSET):
def process_middleware_request(self, language_session_key=UNSET, accept=UNSET):
"""
Build a request and then process it using the ``DarkLangMiddleware``.
Args:
language_session_key (str): The language code to set in request.session[LANUGAGE_SESSION_KEY]
accept (str): The accept header to set in request.META['HTTP_ACCEPT_LANGUAGE']
preview_lang (str): The value to set in request.GET['preview_lang']
clear_lang (str): The value to set in request.GET['clear_lang']
"""
session = {}
set_if_set(session, LANGUAGE_SESSION_KEY, language_session_key)
......@@ -58,17 +56,16 @@ class DarkLangMiddlewareTests(TestCase):
meta = {}
set_if_set(meta, 'HTTP_ACCEPT_LANGUAGE', accept)
get = {}
set_if_set(get, 'preview-lang', preview_lang)
set_if_set(get, 'clear-lang', clear_lang)
request = Mock(
spec=HttpRequest,
session=session,
META=meta,
GET=get,
user=UserFactory()
GET={},
method='GET',
user=self.user
)
# Process it through the Middleware to ensure the language is available as expected.
self.assertIsNone(DarkLangMiddleware().process_request(request))
return request
......@@ -83,31 +80,31 @@ class DarkLangMiddlewareTests(TestCase):
)
def test_empty_accept(self):
self.assertAcceptEquals(UNSET, self.process_request())
self.assertAcceptEquals(UNSET, self.process_middleware_request())
def test_wildcard_accept(self):
self.assertAcceptEquals('*', self.process_request(accept='*'))
self.assertAcceptEquals('*', self.process_middleware_request(accept='*'))
def test_malformed_accept(self):
self.assertAcceptEquals('', self.process_request(accept='xxxxxxxxxxxx'))
self.assertAcceptEquals('', self.process_request(accept='en;q=1.0, es-419:q-0.8'))
self.assertAcceptEquals('', self.process_middleware_request(accept='xxxxxxxxxxxx'))
self.assertAcceptEquals('', self.process_middleware_request(accept='en;q=1.0, es-419:q-0.8'))
def test_released_accept(self):
self.assertAcceptEquals(
'rel;q=1.0',
self.process_request(accept='rel;q=1.0')
self.process_middleware_request(accept='rel;q=1.0')
)
def test_unreleased_accept(self):
self.assertAcceptEquals(
'rel;q=1.0',
self.process_request(accept='rel;q=1.0, unrel;q=0.5')
self.process_middleware_request(accept='rel;q=1.0, unrel;q=0.5')
)
def test_accept_with_syslang(self):
self.assertAcceptEquals(
'en;q=1.0, rel;q=0.8',
self.process_request(accept='en;q=1.0, rel;q=0.8, unrel;q=0.5')
self.process_middleware_request(accept='en;q=1.0, rel;q=0.8, unrel;q=0.5')
)
def test_accept_multiple_released_langs(self):
......@@ -119,17 +116,17 @@ class DarkLangMiddlewareTests(TestCase):
self.assertAcceptEquals(
'rel;q=1.0, unrel;q=0.5',
self.process_request(accept='rel;q=1.0, unrel;q=0.5')
self.process_middleware_request(accept='rel;q=1.0, unrel;q=0.5')
)
self.assertAcceptEquals(
'rel;q=1.0, unrel;q=0.5',
self.process_request(accept='rel;q=1.0, notrel;q=0.3, unrel;q=0.5')
self.process_middleware_request(accept='rel;q=1.0, notrel;q=0.3, unrel;q=0.5')
)
self.assertAcceptEquals(
'rel;q=1.0, unrel;q=0.5',
self.process_request(accept='notrel;q=0.3, rel;q=1.0, unrel;q=0.5')
self.process_middleware_request(accept='notrel;q=0.3, rel;q=1.0, unrel;q=0.5')
)
def test_accept_released_territory(self):
......@@ -138,17 +135,17 @@ class DarkLangMiddlewareTests(TestCase):
# (Otherwise, the user will actually end up getting the server default)
self.assertAcceptEquals(
'rel;q=1.0, rel;q=0.5',
self.process_request(accept='rel-ter;q=1.0, rel;q=0.5')
self.process_middleware_request(accept='rel-ter;q=1.0, rel;q=0.5')
)
def test_accept_mixed_case(self):
self.assertAcceptEquals(
'rel;q=1.0, rel;q=0.5',
self.process_request(accept='rel-TER;q=1.0, REL;q=0.5')
self.process_middleware_request(accept='rel-TER;q=1.0, REL;q=0.5')
)
DarkLangConfig(
released_languages=('REL-TER'),
released_languages='REL-TER',
changed_by=self.user,
enabled=True
).save()
......@@ -157,7 +154,7 @@ class DarkLangMiddlewareTests(TestCase):
# fuzzy match to "rel-ter", in addition to "rel-ter" exact matching "rel-ter"
self.assertAcceptEquals(
'rel-ter;q=1.0, rel-ter;q=0.5',
self.process_request(accept='rel-ter;q=1.0, rel;q=0.5')
self.process_middleware_request(accept='rel-ter;q=1.0, rel;q=0.5')
)
@ddt.data(
......@@ -175,7 +172,7 @@ class DarkLangMiddlewareTests(TestCase):
self.assertAcceptEquals(
expected,
self.process_request(accept=accept_header)
self.process_middleware_request(accept=accept_header)
)
def test_partial_match_esar_es(self):
......@@ -188,7 +185,7 @@ class DarkLangMiddlewareTests(TestCase):
self.assertAcceptEquals(
'es;q=1.0',
self.process_request(accept='es-AR;q=1.0, pt;q=0.5')
self.process_middleware_request(accept='es-AR;q=1.0, pt;q=0.5')
)
@ddt.data(
......@@ -207,7 +204,7 @@ class DarkLangMiddlewareTests(TestCase):
).save()
self.assertAcceptEquals(
expected,
self.process_request(accept=accept_header)
self.process_middleware_request(accept=accept_header)
)
@unittest.skip("This won't work until fallback is implemented for LA country codes. See LOC-86")
......@@ -229,55 +226,100 @@ class DarkLangMiddlewareTests(TestCase):
self.assertAcceptEquals(
'es-419;q=1.0',
self.process_request(accept='{};q=1.0, pt;q=0.5'.format(latin_america_code))
self.process_middleware_request(accept='{};q=1.0, pt;q=0.5'.format(latin_america_code))
)
def assertSessionLangEquals(self, value, request):
def assert_session_lang_equals(self, value, session):
"""
Assert that the LANGUAGE_SESSION_KEY set in request.session is equal to value
Assert that the LANGUAGE_SESSION_KEY set in session is equal to value
"""
self.assertEquals(
value,
request.session.get(LANGUAGE_SESSION_KEY, UNSET)
session.get(LANGUAGE_SESSION_KEY, UNSET)
)
def _post_set_preview_lang(self, preview_language):
"""
Sends a post request to set the preview language
"""
return self.client.post('/update_lang/', {'preview_lang': preview_language, 'set_language': 'set_language'})
def _post_clear_preview_lang(self):
"""
Sends a post request to Clear the preview language
"""
return self.client.post('/update_lang/', {'reset': 'reset'})
def _set_client_session_language(self, session_language):
"""
Set the session language in the Client
"""
session = self.client.session
session[LANGUAGE_SESSION_KEY] = session_language
session.save()
def test_preview_lang_with_released_language(self):
# Preview lang should always override selection.
self.assertSessionLangEquals(
# Preview lang should always override selection
self._post_set_preview_lang('rel')
# Refresh the page with a get request to confirm the preview language was set
self.client.get('/home')
self.assert_session_lang_equals(
'rel',
self.process_request(preview_lang='rel')
self.client.session
)
self.assertSessionLangEquals(
# Set the session language and ensure that the preview language overrides
self._set_client_session_language('notrel')
self._post_set_preview_lang('rel')
self.client.get('/home')
self.assert_session_lang_equals(
'rel',
self.process_request(preview_lang='rel', language_session_key='notrel')
self.client.session
)
def test_preview_lang_with_dark_language(self):
self.assertSessionLangEquals(
self._post_set_preview_lang('unrel')
self.client.get('/home')
self.assert_session_lang_equals(
'unrel',
self.process_request(preview_lang='unrel')
self.client.session
)
self.assertSessionLangEquals(
# Test a clear and then a set of the preview language
self._post_clear_preview_lang()
self._post_set_preview_lang('unrel')
self.client.get('/home')
self.assert_session_lang_equals(
'unrel',
self.process_request(preview_lang='unrel', language_session_key='notrel')
self.client.session
)
def test_clear_lang(self):
self.assertSessionLangEquals(
UNSET,
self.process_request(clear_lang=True)
def test_empty_preview_language(self):
# When posting an empty preview_language the currently set language should not change
self._set_client_session_language('rel')
self._post_set_preview_lang(' ')
self.client.get('/home')
self.assert_session_lang_equals(
'rel',
self.client.session
)
self.assertSessionLangEquals(
def test_clear_lang(self):
# Clear a language when no language was set
self._post_clear_preview_lang()
self.client.get('/home')
self.assert_session_lang_equals(
UNSET,
self.process_request(clear_lang=True, language_session_key='rel')
self.client.session
)
self.assertSessionLangEquals(
# Set a language and clear it to ensure the clear is working as expected
self._post_set_preview_lang('notclear')
self._post_clear_preview_lang()
self.client.get('/home')
self.assert_session_lang_equals(
UNSET,
self.process_request(clear_lang=True, language_session_key='unrel')
self.client.session
)
def test_disabled(self):
......@@ -285,22 +327,25 @@ class DarkLangMiddlewareTests(TestCase):
self.assertAcceptEquals(
'notrel;q=0.3, rel;q=1.0, unrel;q=0.5',
self.process_request(accept='notrel;q=0.3, rel;q=1.0, unrel;q=0.5')
self.process_middleware_request(accept='notrel;q=0.3, rel;q=1.0, unrel;q=0.5')
)
self.assertSessionLangEquals(
# With DarkLang disabled the clear should not change the session language
self._set_client_session_language('rel')
self._post_clear_preview_lang()
self.client.get('/home')
self.assert_session_lang_equals(
'rel',
self.process_request(clear_lang=True, language_session_key='rel')
self.client.session
)
self.assertSessionLangEquals(
# Test that setting the preview language with DarkLang disabled does nothing
self._set_client_session_language('unrel')
self._post_set_preview_lang('rel')
self.client.get('/home')
self.assert_session_lang_equals(
'unrel',
self.process_request(clear_lang=True, language_session_key='unrel')
)
self.assertSessionLangEquals(
'rel',
self.process_request(preview_lang='unrel', language_session_key='rel')
self.client.session
)
def test_accept_chinese_language_codes(self):
......@@ -312,5 +357,5 @@ class DarkLangMiddlewareTests(TestCase):
self.assertAcceptEquals(
'zh-cn;q=1.0, zh-tw;q=0.5, zh-hk;q=0.3',
self.process_request(accept='zh-Hans;q=1.0, zh-Hant-TW;q=0.5, zh-HK;q=0.3')
self.process_middleware_request(accept='zh-Hans;q=1.0, zh-Hant-TW;q=0.5, zh-HK;q=0.3')
)
"""
Contains all the URLs for the Dark Language Support App
"""
from django.conf.urls import patterns, url
from dark_lang import views
urlpatterns = patterns(
'',
url(r'^$', views.DarkLangView.as_view(), name='preview_lang'),
)
"""
Views file for the Darklang Django App
"""
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.utils.translation import LANGUAGE_SESSION_KEY
from django.utils.translation import ugettext as _
from django.views.generic.base import View
from openedx.core.djangoapps.user_api.preferences.api import (
delete_user_preference, get_user_preference, set_user_preference
)
from openedx.core.lib.api.view_utils import view_auth_classes
from dark_lang import DARK_LANGUAGE_KEY
from dark_lang.models import DarkLangConfig
from edxmako.shortcuts import render_to_response
from lang_pref import LANGUAGE_KEY
LANGUAGE_INPUT_FIELD = 'preview_lang'
@view_auth_classes()
class DarkLangView(View):
"""
View used when a user is attempting to change the preview language using Darklang.
Expected Behavior:
GET - returns a form for setting/resetting the user's dark language
POST - updates or clears the setting to the given dark language
"""
template_name = 'darklang/preview_lang.html'
@method_decorator(login_required)
def get(self, request):
"""
Returns the Form for setting/resetting a User's dark language setting
Arguments:
request (Request): The Django Request Object
Returns:
HttpResponse: View containing the form for setting the preview lang
"""
context = {
'disable_courseware_js': True,
'uses_pattern_library': True
}
return render_to_response(self.template_name, context)
@method_decorator(login_required)
def post(self, request):
"""
Sets or clears the DarkLang depending on the incoming post data.
Arguments:
request (Request): The Django Request Object
Returns:
HttpResponse: View containing the form for setting the preview lang with the status
included in the context
"""
return self.process_darklang_request(request)
def process_darklang_request(self, request):
"""
Proccess the request to Set or clear the DarkLang depending on the incoming request.
Arguments:
request (Request): The Django Request Object
Returns:
HttpResponse: View containing the form for setting the preview lang with the status
included in the context
"""
context = {
'disable_courseware_js': True,
'uses_pattern_library': True
}
response = None
if not DarkLangConfig.current().enabled:
message = _('Preview Language is currently disabled')
context.update({'form_submit_message': message})
context.update({'success': False})
response = render_to_response(self.template_name, context, request=request)
elif 'set_language' in request.POST:
# Set the Preview Language
response = self._set_preview_language(request, context)
elif 'reset' in request.POST:
# Reset and clear the language preference
response = self._clear_preview_language(request, context)
return response
def _set_preview_language(self, request, context):
"""
Set the Preview language
Arguments:
request (Request): The incoming Django Request
context dict: The basic context for the Response
Returns:
HttpResponse: View containing the form for setting the preview lang with the status
included in the context
"""
message = None
show_refresh_message = False
preview_lang = request.POST.get(LANGUAGE_INPUT_FIELD, '')
if not preview_lang.strip():
message = _('Language code not provided')
else:
# Set the session key to the requested preview lang
request.session[LANGUAGE_SESSION_KEY] = preview_lang
# Make sure that we set the requested preview lang as the dark lang preference for the
# user, so that the lang_pref middleware doesn't clobber away the dark lang preview.
auth_user = request.user
if auth_user:
set_user_preference(request.user, DARK_LANGUAGE_KEY, preview_lang)
message = _('Language set to language code: {preview_language_code}').format(
preview_language_code=preview_lang
)
show_refresh_message = True
context.update({'form_submit_message': message})
context.update({'success': show_refresh_message})
response = render_to_response(self.template_name, context)
return response
def _clear_preview_language(self, request, context):
"""
Clears the dark language preview
Arguments:
request (Request): The incoming Django Request
context dict: The basic context for the Response
Returns:
HttpResponse: View containing the form for setting the preview lang with the status
included in the context
"""
# delete the session language key (if one is set)
if LANGUAGE_SESSION_KEY in request.session:
del request.session[LANGUAGE_SESSION_KEY]
user_pref = ''
auth_user = request.user
if auth_user:
# Reset user's dark lang preference to null
delete_user_preference(auth_user, DARK_LANGUAGE_KEY)
# Get & set user's preferred language
user_pref = get_user_preference(auth_user, LANGUAGE_KEY)
if user_pref:
request.session[LANGUAGE_SESSION_KEY] = user_pref
if user_pref is None:
message = _('Language reset to the default language code')
else:
message = _("Language reset to user's preference: {preview_language_code}").format(
preview_language_code=user_pref
)
context.update({'form_submit_message': message})
context.update({'success': True})
return render_to_response(self.template_name, context)
<%!
from django.utils.translation import ugettext as _
%>
<%page expression_filter="h"/>
<h1>
${_("Preview Language Setting")}
</h1>
<div >
<form class="form" action="/update_lang/" method="post">
<fieldset class="form-group">
<div class="field">
<label class="field-label">${_("Language Code")}
<input class="field-input input-text" type="text" name="preview_lang"
placeholder="${_('For example use en for English')}" />
</label>
</div>
</fieldset>
<div class="form-actions">
<button class="btn-brand btn-base" type="submit" name="set_language" value="set_language">${_("Submit")}</button>
<button class="btn-brand btn-base" type="submit" name="reset" value="reset">${_("Reset")}</button>
</div>
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }"/>
</form>
<br/>
% if not form_submit_message is UNDEFINED:
<h3 class="alert-title"> ${form_submit_message}</h3>
% if success:
<p class="alert-copy-with-title">
${_("Please refresh the page to see the changes applied.")}
</p>
% endif
% endif
</div>
......@@ -2,29 +2,34 @@
Tests i18n in courseware
"""
import re
from nose.plugins.attrib import attr
from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse, NoReverseMatch
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.client import Client
from django.utils import translation
from nose.plugins.attrib import attr
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
from dark_lang.models import DarkLangConfig
from lang_pref import LANGUAGE_KEY
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
from student.tests.factories import UserFactory, RegistrationFactory, UserProfileFactory
from student.tests.factories import UserFactory
class BaseI18nTestCase(TestCase):
"""
Base utilities for i18n test classes to derive from
"""
preview_language_url = '/update_lang/'
url = reverse('dashboard')
site_lang = settings.LANGUAGE_CODE
pwd = 'test_password'
def setUp(self):
super(BaseI18nTestCase, self).setUp()
self.addCleanup(translation.deactivate)
self.client = Client()
self.create_user()
def assert_tag_has_attr(self, content, tag, attname, value):
"""Assert that a tag in `content` has a certain value in a certain attribute."""
......@@ -47,6 +52,22 @@ class BaseI18nTestCase(TestCase):
enabled=True
).save()
def create_user(self):
"""
Creates the user log in
"""
# Create one user and save it to the database
email = 'test@edx.org'
self.user = UserFactory.build(username='test', email=email, password=self.pwd)
self.user.save()
def user_login(self):
"""
Log the user in
"""
# Get the login url & log in our user
self.client.login(username=self.user.username, password=self.pwd)
@attr('shard_1')
class I18nTestCase(BaseI18nTestCase):
......@@ -96,35 +117,44 @@ class I18nRegressionTests(BaseI18nTestCase):
def test_unreleased_lang_resolution(self):
# Regression test; LOC-85
self.release_languages('fa')
self.user_login()
# We've released 'fa', AND we have language files for 'fa-ir' but
# we want to keep 'fa-ir' as a dark language. Requesting 'fa-ir'
# in the http request (NOT with the ?preview-lang query param) should
# receive files for 'fa'
response = self.client.get('/', HTTP_ACCEPT_LANGUAGE='fa-ir')
response = self.client.get(self.url, HTTP_ACCEPT_LANGUAGE='fa-ir')
self.assert_tag_has_attr(response.content, "html", "lang", "fa")
# Now try to access with dark lang
response = self.client.get('/?preview-lang=fa-ir')
self.client.post(self.preview_language_url, {'preview_lang': 'fa-ir', 'set_language': 'set_language'})
response = self.client.get(self.url)
self.assert_tag_has_attr(response.content, "html", "lang", "fa-ir")
def test_preview_lang(self):
self.user_login()
# Regression test; LOC-87
self.release_languages('es-419')
site_lang = settings.LANGUAGE_CODE
# Visit the front page; verify we see site default lang
response = self.client.get('/')
response = self.client.get(self.url)
self.assert_tag_has_attr(response.content, "html", "lang", site_lang)
# Verify we can switch language using the preview-lang query param
response = self.client.get('/?preview-lang=eo')
# Set the language
self.client.post(self.preview_language_url, {'preview_lang': 'eo', 'set_language': 'set_language'})
response = self.client.get(self.url)
self.assert_tag_has_attr(response.content, "html", "lang", "eo")
# We should be able to see released languages using preview-lang, too
response = self.client.get('/?preview-lang=es-419')
self.client.post(self.preview_language_url, {'preview_lang': 'es-419', 'set_language': 'set_language'})
response = self.client.get(self.url)
self.assert_tag_has_attr(response.content, "html", "lang", "es-419")
# Clearing the language should go back to site default
response = self.client.get('/?clear-lang')
self.client.post(self.preview_language_url, {'reset': 'reset'})
response = self.client.get(self.url)
self.assert_tag_has_attr(response.content, "html", "lang", site_lang)
......@@ -137,32 +167,7 @@ class I18nLangPrefTests(BaseI18nTestCase):
"""
def setUp(self):
super(I18nLangPrefTests, self).setUp()
# Create one user and save it to the database
email = 'test@edx.org'
pwd = 'test_password'
self.user = UserFactory.build(username='test', email=email)
self.user.set_password(pwd)
self.user.save()
# Create a registration for the user
RegistrationFactory(user=self.user)
# Create a profile for the user
UserProfileFactory(user=self.user)
# Create the test client
self.client = Client()
# Get the login url & log in our user
try:
login_url = reverse('login_post')
except NoReverseMatch:
login_url = reverse('login')
self.client.post(login_url, {'email': email, 'password': pwd})
# Url and site lang vars for tests to use
self.url = reverse('dashboard')
self.site_lang = settings.LANGUAGE_CODE
self.user_login()
def test_lang_preference(self):
# Regression test; LOC-87
......@@ -190,12 +195,16 @@ class I18nLangPrefTests(BaseI18nTestCase):
# Set user language preference
set_user_preference(self.user, LANGUAGE_KEY, 'ar')
# Verify preview-lang takes precedence
response = self.client.get('{}?preview-lang=eo'.format(self.url))
self.client.post(self.preview_language_url, {'preview_lang': 'eo', 'set_language': 'set_language'})
response = self.client.get(self.url)
self.assert_tag_has_attr(response.content, "html", "lang", 'eo')
# Hitting another page should keep the dark language set.
response = self.client.get(reverse('courses'))
self.assert_tag_has_attr(response.content, "html", "lang", "eo")
# Clearing language must set language back to preference language
response = self.client.get('{}?clear-lang'.format(self.url))
self.client.post(self.preview_language_url, {'reset': 'reset'})
response = self.client.get(self.url)
self.assert_tag_has_attr(response.content, "html", "lang", 'ar')
## Override the default styles_version to the Pattern Library version (version 2)
<%! main_css = "style-main-v2" %>
<%page expression_filter="h"/>
<%!
from django.utils.translation import ugettext as _
%>
<%inherit file="/main.html" />
<%block name="pagetitle">${_("Preview Language Setting")}</%block>
<%block name="nav_skip"></%block>
<%block name="bodyclass">pattern-library</%block>
<%block name="content">
<%include file="/darklang/preview_lang_include.html" />
</%block>
......@@ -114,6 +114,7 @@ urlpatterns = (
url(r'^course_modes/', include('course_modes.urls')),
url(r'^verify_student/', include('verify_student.urls')),
url(r'^update_lang/', include('dark_lang.urls', namespace='darklang')),
# URLs for API access management
url(r'^api-admin/', include('openedx.core.djangoapps.api_admin.urls', namespace='api_admin')),
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment