Add support for beta languages.
Whenever user selects a beta language on account settings page, show a page level warning message that this language is not fully translated along with action to revert. LEARNER-5654
This commit is contained in:
@@ -69,6 +69,16 @@ class DarkLangMiddleware(object):
|
||||
language_options.append(settings.LANGUAGE_CODE)
|
||||
return language_options
|
||||
|
||||
@property
|
||||
def beta_langs(self):
|
||||
"""
|
||||
Current list of released languages
|
||||
"""
|
||||
language_options = DarkLangConfig.current().beta_languages_list
|
||||
if settings.LANGUAGE_CODE not in language_options:
|
||||
language_options.append(settings.LANGUAGE_CODE)
|
||||
return language_options
|
||||
|
||||
def process_request(self, request):
|
||||
"""
|
||||
Prevent user from requesting un-released languages except by using the preview-lang query string.
|
||||
@@ -82,11 +92,18 @@ 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:
|
||||
dark_lang_config = DarkLangConfig.current()
|
||||
|
||||
if dark_lang_config.enable_beta_languages:
|
||||
langs = self.released_langs + self.beta_langs
|
||||
else:
|
||||
langs = self.released_langs
|
||||
|
||||
if lang_code in langs:
|
||||
match = lang_code
|
||||
else:
|
||||
lang_prefix = lang_code.partition('-')[0]
|
||||
for released_lang in self.released_langs:
|
||||
for released_lang in langs:
|
||||
released_prefix = released_lang.partition('-')[0]
|
||||
if lang_prefix == released_prefix:
|
||||
match = released_lang
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.12 on 2018-04-25 07:59
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dark_lang', '0002_data__enable_on_install'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='darklangconfig',
|
||||
name='beta_languages',
|
||||
field=models.TextField(blank=True, help_text=b'A comma-separated list of language codes to release to the public as beta languages.'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='darklangconfig',
|
||||
name='enable_beta_languages',
|
||||
field=models.BooleanField(default=False, help_text=b'Enable partially supported languages to display in language drop down.'),
|
||||
),
|
||||
]
|
||||
@@ -13,6 +13,14 @@ class DarkLangConfig(ConfigurationModel):
|
||||
blank=True,
|
||||
help_text="A comma-separated list of language codes to release to the public."
|
||||
)
|
||||
enable_beta_languages = models.BooleanField(
|
||||
default=False,
|
||||
help_text="Enable partially supported languages to display in language drop down."
|
||||
)
|
||||
beta_languages = models.TextField(
|
||||
blank=True,
|
||||
help_text="A comma-separated list of language codes to release to the public as beta languages."
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
return u"DarkLangConfig()"
|
||||
@@ -31,3 +39,18 @@ class DarkLangConfig(ConfigurationModel):
|
||||
# Put in alphabetical order
|
||||
languages.sort()
|
||||
return languages
|
||||
|
||||
@property
|
||||
def beta_languages_list(self):
|
||||
"""
|
||||
``released_languages`` as a list of language codes.
|
||||
|
||||
Example: ['it', 'de-at', 'es', 'pt-br']
|
||||
"""
|
||||
if not self.beta_languages.strip():
|
||||
return []
|
||||
|
||||
languages = [lang.lower().strip() for lang in self.beta_languages.split(',')]
|
||||
# Put in alphabetical order
|
||||
languages.sort()
|
||||
return languages
|
||||
|
||||
@@ -46,12 +46,20 @@ def released_languages():
|
||||
[Language(code='en', name=u'English'), Language(code='fr', name=u'Français')]
|
||||
|
||||
"""
|
||||
released_language_codes = DarkLangConfig.current().released_languages_list
|
||||
dark_lang_config = DarkLangConfig.current()
|
||||
released_language_codes = dark_lang_config.released_languages_list
|
||||
default_language_code = settings.LANGUAGE_CODE
|
||||
|
||||
if default_language_code not in released_language_codes:
|
||||
released_language_codes.append(default_language_code)
|
||||
released_language_codes.sort()
|
||||
|
||||
if dark_lang_config.enable_beta_languages:
|
||||
beta_language_codes = dark_lang_config.beta_languages_list
|
||||
|
||||
if beta_language_codes not in released_language_codes:
|
||||
released_language_codes = released_language_codes + beta_language_codes
|
||||
|
||||
released_language_codes.sort()
|
||||
|
||||
# Intersect the list of valid language tuples with the list
|
||||
# of released language codes
|
||||
|
||||
@@ -14,6 +14,7 @@ from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
|
||||
EN = language_api.Language('en', 'English')
|
||||
ES_419 = language_api.Language('es-419', u'Español (Latinoamérica)')
|
||||
LT_LT = language_api.Language('lt-lt', u'Lietuvių (Lietuva)')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -98,3 +99,22 @@ class LanguageApiTest(CacheIsolationTestCase):
|
||||
self.assertEqual("cs", all_languages[1][0])
|
||||
self.assertEqual(u"Hollandais", all_languages[0][1])
|
||||
self.assertEqual(u"Tchèque", all_languages[1][1])
|
||||
|
||||
def test_beta_languages(self):
|
||||
"""
|
||||
Tests for the beta languages.
|
||||
"""
|
||||
with override_settings(LANGUAGES=[EN, ES_419, LT_LT], LANGUAGE_CODE='en'):
|
||||
user = User()
|
||||
user.save()
|
||||
DarkLangConfig(
|
||||
released_languages='es-419',
|
||||
changed_by=user,
|
||||
enabled=True,
|
||||
beta_languages='lt-lt',
|
||||
enable_beta_languages=True
|
||||
).save()
|
||||
|
||||
released_languages = language_api.released_languages()
|
||||
expected_languages = [EN, ES_419, LT_LT]
|
||||
self.assertEqual(released_languages, expected_languages)
|
||||
|
||||
@@ -15,9 +15,11 @@ from edxmako.shortcuts import render_to_response
|
||||
from lms.djangoapps.commerce.models import CommerceConfiguration
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
|
||||
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
|
||||
from openedx.core.djangoapps.lang_pref.api import all_languages, released_languages
|
||||
from openedx.core.djangoapps.programs.models import ProgramsApiConfig
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preferences
|
||||
from openedx.core.lib.edx_api_utils import get_edx_api_data
|
||||
from openedx.core.lib.time_zone_utils import TIME_ZONE_CHOICES
|
||||
from openedx.features.enterprise_support.api import get_enterprise_customer_for_learner
|
||||
@@ -74,6 +76,15 @@ def account_settings_context(request):
|
||||
# it will be broken if exception raised
|
||||
user_orders = []
|
||||
|
||||
beta_language = {}
|
||||
dark_lang_config = DarkLangConfig.current()
|
||||
if dark_lang_config.enable_beta_languages:
|
||||
user_preferences = get_user_preferences(user)
|
||||
pref_language = user_preferences.get('pref-lang')
|
||||
if pref_language in dark_lang_config.beta_languages_list:
|
||||
beta_language['code'] = pref_language
|
||||
beta_language['name'] = settings.LANGUAGE_DICT.get(pref_language)
|
||||
|
||||
context = {
|
||||
'auth': {},
|
||||
'duplicate_provider': None,
|
||||
@@ -111,6 +122,7 @@ def account_settings_context(request):
|
||||
'ENABLE_ACCOUNT_DELETION', settings.FEATURES.get('ENABLE_ACCOUNT_DELETION', False)
|
||||
),
|
||||
'extended_profile_fields': _get_extended_profile_fields(),
|
||||
'beta_language': beta_language
|
||||
}
|
||||
|
||||
enterprise_customer = get_enterprise_customer_for_learner(site=request.site, user=request.user)
|
||||
|
||||
@@ -7,13 +7,17 @@ from django.contrib.messages.middleware import MessageMiddleware
|
||||
from django.urls import reverse
|
||||
from django.http import HttpRequest
|
||||
from django.test import TestCase
|
||||
from django.test.utils import override_settings
|
||||
from edx_rest_api_client import exceptions
|
||||
|
||||
from lms.djangoapps.commerce.models import CommerceConfiguration
|
||||
from lms.djangoapps.commerce.tests import factories
|
||||
from lms.djangoapps.commerce.tests.mocks import mock_get_orders
|
||||
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
|
||||
from openedx.core.djangoapps.lang_pref.tests.test_api import EN, LT_LT
|
||||
from openedx.core.djangoapps.programs.tests.mixins import ProgramsApiConfigMixin
|
||||
from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory
|
||||
from openedx.core.djangoapps.user_api.tests.factories import UserPreferenceFactory
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
from openedx.core.djangoapps.user_api.accounts.settings_views import account_settings_context, get_user_orders
|
||||
from student.tests.factories import UserFactory
|
||||
@@ -60,35 +64,47 @@ class AccountSettingsViewTest(ThirdPartyAuthTestMixin, TestCase, ProgramsApiConf
|
||||
@mock.patch('openedx.features.enterprise_support.api.get_enterprise_customer_for_learner')
|
||||
def test_context(self, mock_get_enterprise_customer_for_learner):
|
||||
self.request.site = SiteFactory.create()
|
||||
UserPreferenceFactory(user=self.user, key='pref-lang', value='lt-lt')
|
||||
DarkLangConfig(
|
||||
released_languages='en',
|
||||
changed_by=self.user,
|
||||
enabled=True,
|
||||
beta_languages='lt-lt',
|
||||
enable_beta_languages=True
|
||||
).save()
|
||||
mock_get_enterprise_customer_for_learner.return_value = {}
|
||||
context = account_settings_context(self.request)
|
||||
|
||||
user_accounts_api_url = reverse("accounts_api", kwargs={'username': self.user.username})
|
||||
self.assertEqual(context['user_accounts_api_url'], user_accounts_api_url)
|
||||
with override_settings(LANGUAGES=[EN, LT_LT], LANGUAGE_CODE='en'):
|
||||
context = account_settings_context(self.request)
|
||||
|
||||
user_preferences_api_url = reverse('preferences_api', kwargs={'username': self.user.username})
|
||||
self.assertEqual(context['user_preferences_api_url'], user_preferences_api_url)
|
||||
user_accounts_api_url = reverse("accounts_api", kwargs={'username': self.user.username})
|
||||
self.assertEqual(context['user_accounts_api_url'], user_accounts_api_url)
|
||||
|
||||
for attribute in self.FIELDS:
|
||||
self.assertIn(attribute, context['fields'])
|
||||
user_preferences_api_url = reverse('preferences_api', kwargs={'username': self.user.username})
|
||||
self.assertEqual(context['user_preferences_api_url'], user_preferences_api_url)
|
||||
|
||||
self.assertEqual(
|
||||
context['user_accounts_api_url'], reverse("accounts_api", kwargs={'username': self.user.username})
|
||||
)
|
||||
self.assertEqual(
|
||||
context['user_preferences_api_url'], reverse('preferences_api', kwargs={'username': self.user.username})
|
||||
)
|
||||
for attribute in self.FIELDS:
|
||||
self.assertIn(attribute, context['fields'])
|
||||
|
||||
self.assertEqual(context['duplicate_provider'], 'facebook')
|
||||
self.assertEqual(context['auth']['providers'][0]['name'], 'Facebook')
|
||||
self.assertEqual(context['auth']['providers'][1]['name'], 'Google')
|
||||
self.assertEqual(
|
||||
context['user_accounts_api_url'], reverse("accounts_api", kwargs={'username': self.user.username})
|
||||
)
|
||||
self.assertEqual(
|
||||
context['user_preferences_api_url'], reverse('preferences_api', kwargs={'username': self.user.username})
|
||||
)
|
||||
|
||||
self.assertEqual(context['sync_learner_profile_data'], False)
|
||||
self.assertEqual(context['edx_support_url'], settings.SUPPORT_SITE_LINK)
|
||||
self.assertEqual(context['enterprise_name'], None)
|
||||
self.assertEqual(
|
||||
context['enterprise_readonly_account_fields'], {'fields': settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS}
|
||||
)
|
||||
self.assertEqual(context['duplicate_provider'], 'facebook')
|
||||
self.assertEqual(context['auth']['providers'][0]['name'], 'Facebook')
|
||||
self.assertEqual(context['auth']['providers'][1]['name'], 'Google')
|
||||
|
||||
self.assertEqual(context['sync_learner_profile_data'], False)
|
||||
self.assertEqual(context['edx_support_url'], settings.SUPPORT_SITE_LINK)
|
||||
self.assertEqual(context['enterprise_name'], None)
|
||||
self.assertEqual(
|
||||
context['enterprise_readonly_account_fields'], {'fields': settings.ENTERPRISE_READONLY_ACCOUNT_FIELDS}
|
||||
)
|
||||
expected_beta_language = {'code': 'lt-lt', 'name': settings.LANGUAGE_DICT.get('lt-lt')}
|
||||
self.assertEqual(context['beta_language'], expected_beta_language)
|
||||
|
||||
@mock.patch('openedx.core.djangoapps.user_api.accounts.settings_views.get_enterprise_customer_for_learner')
|
||||
@mock.patch('openedx.features.enterprise_support.utils.third_party_auth.provider.Registry.get')
|
||||
|
||||
@@ -57,8 +57,10 @@ class Command(BaseCommand):
|
||||
|
||||
# Make sure we're changing to a code that actually exists. Presumably it's safe to move away from a code that
|
||||
# doesn't.
|
||||
dark_lang_config = DarkLangConfig.current()
|
||||
langs = [lang_code[0] for lang_code in settings.LANGUAGES]
|
||||
langs += DarkLangConfig.current().released_languages_list
|
||||
langs += dark_lang_config.released_languages_list
|
||||
langs += dark_lang_config.beta_languages_list if dark_lang_config.enable_beta_languages else []
|
||||
|
||||
if new_lang_code not in langs:
|
||||
raise CommandError('{} is not a configured language code in settings.LANGUAGES '
|
||||
|
||||
Reference in New Issue
Block a user