diff --git a/cms/djangoapps/contentstore/courseware_index.py b/cms/djangoapps/contentstore/courseware_index.py
index 5f4f48dcb6..06f7f5384b 100644
--- a/cms/djangoapps/contentstore/courseware_index.py
+++ b/cms/djangoapps/contentstore/courseware_index.py
@@ -540,6 +540,7 @@ class CourseAboutSearchIndexer(object):
AboutInfo("enrollment_end", AboutInfo.PROPERTY, AboutInfo.FROM_COURSE_PROPERTY),
AboutInfo("org", AboutInfo.PROPERTY, AboutInfo.FROM_COURSE_PROPERTY),
AboutInfo("modes", AboutInfo.PROPERTY, AboutInfo.FROM_COURSE_MODE),
+ AboutInfo("language", AboutInfo.PROPERTY, AboutInfo.FROM_COURSE_PROPERTY),
]
@classmethod
diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index b13c341070..d26d393b0a 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -1022,6 +1022,14 @@ class ContentStoreTest(ContentStoreTestCase):
"""Test new course creation - happy path"""
self.assert_created_course()
+ @override_settings(DEFAULT_COURSE_LANGUAGE='hr')
+ def test_create_course_default_language(self):
+ """Test new course creation and verify default language"""
+ test_course_data = self.assert_created_course()
+ course_id = _get_course_id(self.store, test_course_data)
+ course_module = self.store.get_course(course_id)
+ self.assertEquals(course_module.language, 'hr')
+
def test_create_course_with_dots(self):
"""Test new course creation with dots in the name"""
self.course_data['org'] = 'org.foo.bar'
diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py
index a102083735..a060f21eac 100644
--- a/cms/djangoapps/contentstore/tests/test_course_settings.py
+++ b/cms/djangoapps/contentstore/tests/test_course_settings.py
@@ -50,6 +50,7 @@ class CourseDetailsTestCase(CourseTestCase):
self.assertIsNone(details.syllabus, "syllabus somehow initialized" + str(details.syllabus))
self.assertIsNone(details.intro_video, "intro_video somehow initialized" + str(details.intro_video))
self.assertIsNone(details.effort, "effort somehow initialized" + str(details.effort))
+ self.assertIsNone(details.language, "language somehow initialized" + str(details.language))
def test_encoder(self):
details = CourseDetails.fetch(self.course.id)
@@ -62,6 +63,7 @@ class CourseDetailsTestCase(CourseTestCase):
self.assertIsNone(jsondetails['syllabus'], "syllabus somehow initialized")
self.assertIsNone(jsondetails['intro_video'], "intro_video somehow initialized")
self.assertIsNone(jsondetails['effort'], "effort somehow initialized")
+ self.assertIsNone(jsondetails['language'], "language somehow initialized")
def test_ooc_encoder(self):
"""
@@ -116,6 +118,11 @@ class CourseDetailsTestCase(CourseTestCase):
CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).course_image_name,
jsondetails.course_image_name
)
+ jsondetails.language = "hr"
+ self.assertEqual(
+ CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).language,
+ jsondetails.language
+ )
@override_settings(MKTG_URLS={'ROOT': 'dummy-root'})
def test_marketing_site_fetch(self):
@@ -316,6 +323,7 @@ class CourseDetailsViewTest(CourseTestCase):
self.alter_field(url, details, 'intro_video', "intro_video")
self.alter_field(url, details, 'effort', "effort")
self.alter_field(url, details, 'course_image_name', "course_image_name")
+ self.alter_field(url, details, 'language', "en")
def compare_details_with_encoding(self, encoded, details, context):
"""
@@ -330,6 +338,7 @@ class CourseDetailsViewTest(CourseTestCase):
self.assertEqual(details['intro_video'], encoded.get('intro_video', None), context + " intro_video not ==")
self.assertEqual(details['effort'], encoded['effort'], context + " efforts not ==")
self.assertEqual(details['course_image_name'], encoded['course_image_name'], context + " images not ==")
+ self.assertEqual(details['language'], encoded['language'], context + " languages not ==")
def compare_date_fields(self, details, encoded, context, field):
"""
diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py
index 87dd6c6c99..4fe48d432c 100644
--- a/cms/djangoapps/contentstore/views/course.py
+++ b/cms/djangoapps/contentstore/views/course.py
@@ -693,6 +693,9 @@ def create_new_course_in_store(store, user, org, number, run, fields):
definition_data = {'wiki_slug': wiki_slug}
fields.update(definition_data)
+ # Set default language from settings
+ fields.update({'language': getattr(settings, 'DEFAULT_COURSE_LANGUAGE', 'en')})
+
with modulestore().default_store(store):
# Creating the course raises DuplicateCourseError if an existing course with this org/name is found
new_course = modulestore().create_course(
@@ -868,6 +871,7 @@ def settings_handler(request, course_key_string):
'short_description_editable': short_description_editable,
'upload_asset_url': upload_asset_url,
'course_handler_url': reverse_course_url('course_handler', course_key),
+ 'language_options': settings.ALL_LANGUAGES,
}
if prerequisite_course_enabled:
courses, in_process_course_actions = get_courses_accessible_to_user(request)
diff --git a/cms/djangoapps/models/settings/course_details.py b/cms/djangoapps/models/settings/course_details.py
index e2f8119841..0b81444ab5 100644
--- a/cms/djangoapps/models/settings/course_details.py
+++ b/cms/djangoapps/models/settings/course_details.py
@@ -33,6 +33,7 @@ class CourseDetails(object):
self.org = org
self.course_id = course_id
self.run = run
+ self.language = None
self.start_date = None # 'start'
self.end_date = None # 'end'
self.enrollment_start = None
@@ -80,6 +81,7 @@ class CourseDetails(object):
course_details.pre_requisite_courses = descriptor.pre_requisite_courses
course_details.course_image_name = descriptor.course_image
course_details.course_image_asset_path = course_image_url(descriptor)
+ course_details.language = descriptor.language
# Default course license is "All Rights Reserved"
course_details.license = getattr(descriptor, "license", "all-rights-reserved")
@@ -180,6 +182,10 @@ class CourseDetails(object):
descriptor.license = jsondict['license']
dirty = True
+ if 'language' in jsondict and jsondict['language'] != descriptor.language:
+ descriptor.language = jsondict['language']
+ dirty = True
+
if dirty:
module_store.update_item(descriptor, user.id)
diff --git a/cms/djangoapps/models/settings/course_metadata.py b/cms/djangoapps/models/settings/course_metadata.py
index 2f22ba400f..e5f049e150 100644
--- a/cms/djangoapps/models/settings/course_metadata.py
+++ b/cms/djangoapps/models/settings/course_metadata.py
@@ -43,6 +43,7 @@ class CourseMetadata(object):
'entrance_exam_id',
'is_entrance_exam',
'in_entrance_exam',
+ 'language',
]
@classmethod
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 39a3008c30..87450f3f75 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -874,6 +874,10 @@ MAX_ASSET_UPLOAD_FILE_SIZE_URL = ""
### Default value for entrance exam minimum score
ENTRANCE_EXAM_MIN_SCORE_PCT = 50
+### Default language for a new course
+DEFAULT_COURSE_LANGUAGE = "en"
+
+
################ ADVANCED_COMPONENT_TYPES ###############
ADVANCED_COMPONENT_TYPES = [
diff --git a/cms/static/js/models/settings/course_details.js b/cms/static/js/models/settings/course_details.js
index 6f8487697e..a9f70eac7e 100644
--- a/cms/static/js/models/settings/course_details.js
+++ b/cms/static/js/models/settings/course_details.js
@@ -6,6 +6,7 @@ var CourseDetails = Backbone.Model.extend({
org : '',
course_id: '',
run: '',
+ language: '',
start_date: null, // maps to 'start'
end_date: null, // maps to 'end'
enrollment_start: null,
diff --git a/cms/static/js/spec/views/settings/main_spec.js b/cms/static/js/spec/views/settings/main_spec.js
index f489732eab..e691c12061 100644
--- a/cms/static/js/spec/views/settings/main_spec.js
+++ b/cms/static/js/spec/views/settings/main_spec.js
@@ -30,7 +30,8 @@ define([
pre_requisite_courses : [],
entrance_exam_enabled : '',
entrance_exam_minimum_score_pct: '50',
- license: null
+ license: null,
+ language: ''
},
mockSettingsPage = readFixtures('mock/mock-settings-page.underscore');
@@ -154,5 +155,28 @@ define([
);
AjaxHelpers.respondWithJson(requests, expectedJson);
});
+
+ it('should save language as part of course details', function(){
+ var requests = AjaxHelpers.requests(this);
+ var expectedJson = $.extend(true, {}, modelData, {
+ language: 'en',
+ });
+ $('#course-language').val('en').trigger('change');
+ expect(this.model.get('language')).toEqual('en');
+ this.view.saveView();
+ AjaxHelpers.expectJsonRequest(
+ requests, 'POST', urlRoot, expectedJson
+ );
+ });
+
+ it('should not error if about_page_editable is False', function(){
+ var requests = AjaxHelpers.requests(this);
+ // if about_page_editable is false, there is no section.course_details
+ $('.course_details').remove();
+ expect(this.model.get('language')).toEqual('');
+ this.view.saveView();
+ AjaxHelpers.expectJsonRequest(requests, 'POST', urlRoot, modelData);
+ });
+
});
});
diff --git a/cms/static/js/views/settings/main.js b/cms/static/js/views/settings/main.js
index 2a66802c94..78b5dbc491 100644
--- a/cms/static/js/views/settings/main.js
+++ b/cms/static/js/views/settings/main.js
@@ -24,6 +24,7 @@ var DetailsView = ValidatingView.extend({
initialize : function() {
this.fileAnchorTemplate = _.template(' <%= filename %>');
// fill in fields
+ this.$el.find("#course-language").val(this.model.get('language'));
this.$el.find("#course-organization").val(this.model.get('org'));
this.$el.find("#course-number").val(this.model.get('course_id'));
this.$el.find("#course-name").val(this.model.get('run'));
@@ -93,6 +94,7 @@ var DetailsView = ValidatingView.extend({
return this;
},
fieldToSelectorMap : {
+ 'language' : 'course-language',
'start_date' : "course-start",
'end_date' : 'course-end',
'enrollment_start' : 'enrollment-start',
@@ -166,6 +168,9 @@ var DetailsView = ValidatingView.extend({
updateModel: function(event) {
switch (event.currentTarget.id) {
+ case 'course-language':
+ this.setField(event);
+ break;
case 'course-image-url':
this.setField(event);
var url = $(event.currentTarget).val();
diff --git a/cms/templates/js/mock/mock-settings-page.underscore b/cms/templates/js/mock/mock-settings-page.underscore
index 41a00463b0..1422279fb9 100644
--- a/cms/templates/js/mock/mock-settings-page.underscore
+++ b/cms/templates/js/mock/mock-settings-page.underscore
@@ -90,4 +90,21 @@
+
+Course Details
+ Provide useful information about your course
+
+
+${_('Course Details')}
+ ${_('Provide useful information about your course')}
+
+
+