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:
Waheed Ahmed
2018-04-25 13:36:34 +05:00
parent 945debb00f
commit d76a2463fa
16 changed files with 330 additions and 91 deletions

View File

@@ -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

View File

@@ -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.'),
),
]

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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')

View File

@@ -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 '