Commit 8f3c748f by Matthew Piatetsky Committed by GitHub

Merge pull request #387 from edx/ECOM-5946

ECOM-5946 Allow course length in program to be represented as a range of weeks
parents e60e33c9 486b157d
...@@ -674,10 +674,11 @@ class ProgramSerializer(MinimalProgramSerializer): ...@@ -674,10 +674,11 @@ class ProgramSerializer(MinimalProgramSerializer):
class Meta(MinimalProgramSerializer.Meta): class Meta(MinimalProgramSerializer.Meta):
model = Program model = Program
fields = MinimalProgramSerializer.Meta.fields + ( fields = MinimalProgramSerializer.Meta.fields + (
'overview', 'weeks_to_complete', 'min_hours_effort_per_week', 'max_hours_effort_per_week', 'video', 'overview', 'weeks_to_complete', 'weeks_to_complete_min', 'weeks_to_complete_max',
'expected_learning_items', 'faq', 'credit_backing_organizations', 'corporate_endorsements', 'min_hours_effort_per_week', 'max_hours_effort_per_week', 'video', 'expected_learning_items',
'job_outlook_items', 'individual_endorsements', 'languages', 'transcript_languages', 'subjects', 'faq', 'credit_backing_organizations', 'corporate_endorsements', 'job_outlook_items',
'price_ranges', 'staff', 'credit_redemption_overview', 'individual_endorsements', 'languages', 'transcript_languages', 'subjects', 'price_ranges',
'staff', 'credit_redemption_overview',
) )
......
...@@ -592,6 +592,8 @@ class ProgramSerializerTests(MinimalProgramSerializerTests): ...@@ -592,6 +592,8 @@ class ProgramSerializerTests(MinimalProgramSerializerTests):
'job_outlook_items': [item.value for item in program.job_outlook_items.all()], 'job_outlook_items': [item.value for item in program.job_outlook_items.all()],
'languages': [serialize_language_to_code(l) for l in program.languages], 'languages': [serialize_language_to_code(l) for l in program.languages],
'weeks_to_complete': program.weeks_to_complete, 'weeks_to_complete': program.weeks_to_complete,
'weeks_to_complete_min': program.weeks_to_complete_min,
'weeks_to_complete_max': program.weeks_to_complete_max,
'max_hours_effort_per_week': program.max_hours_effort_per_week, 'max_hours_effort_per_week': program.max_hours_effort_per_week,
'min_hours_effort_per_week': program.min_hours_effort_per_week, 'min_hours_effort_per_week': program.min_hours_effort_per_week,
'overview': program.overview, 'overview': program.overview,
......
...@@ -66,7 +66,7 @@ class ProgramViewSetTests(SerializationMixin, APITestCase): ...@@ -66,7 +66,7 @@ class ProgramViewSetTests(SerializationMixin, APITestCase):
def test_retrieve(self): def test_retrieve(self):
""" Verify the endpoint returns the details for a single program. """ """ Verify the endpoint returns the details for a single program. """
program = self.create_program() program = self.create_program()
with self.assertNumQueries(72): with self.assertNumQueries(75):
self.assert_retrieve_success(program) self.assert_retrieve_success(program)
@ddt.data(True, False) @ddt.data(True, False)
...@@ -76,7 +76,7 @@ class ProgramViewSetTests(SerializationMixin, APITestCase): ...@@ -76,7 +76,7 @@ class ProgramViewSetTests(SerializationMixin, APITestCase):
for course in course_list: for course in course_list:
CourseRunFactory(course=course) CourseRunFactory(course=course)
program = ProgramFactory(courses=course_list, order_courses_by_start_date=order_courses_by_start_date) program = ProgramFactory(courses=course_list, order_courses_by_start_date=order_courses_by_start_date)
with self.assertNumQueries(82): with self.assertNumQueries(87):
self.assert_retrieve_success(program) self.assert_retrieve_success(program)
self.assertEqual(course_list, list(program.courses.all())) # pylint: disable=no-member self.assertEqual(course_list, list(program.courses.all())) # pylint: disable=no-member
...@@ -84,7 +84,7 @@ class ProgramViewSetTests(SerializationMixin, APITestCase): ...@@ -84,7 +84,7 @@ class ProgramViewSetTests(SerializationMixin, APITestCase):
""" Verify the endpoint returns data for a program even if the program's courses have no course runs. """ """ Verify the endpoint returns data for a program even if the program's courses have no course runs. """
course = CourseFactory() course = CourseFactory()
program = ProgramFactory(courses=[course]) program = ProgramFactory(courses=[course])
with self.assertNumQueries(46): with self.assertNumQueries(49):
self.assert_retrieve_success(program) self.assert_retrieve_success(program)
def assert_list_results(self, url, expected, expected_query_count, extra_context=None): def assert_list_results(self, url, expected, expected_query_count, extra_context=None):
......
...@@ -5,6 +5,7 @@ import logging ...@@ -5,6 +5,7 @@ import logging
from urllib.parse import parse_qs, urlencode, urlparse from urllib.parse import parse_qs, urlencode, urlparse
from uuid import UUID from uuid import UUID
from dateutil import rrule
import pytz import pytz
import requests import requests
from django.db.models import Q from django.db.models import Q
...@@ -449,6 +450,9 @@ class CourseMarketingSiteDataLoader(AbstractMarketingSiteDataLoader): ...@@ -449,6 +450,9 @@ class CourseMarketingSiteDataLoader(AbstractMarketingSiteDataLoader):
language = language_tags[0] if language_tags else None language = language_tags[0] if language_tags else None
start = data.get('field_course_start_date') start = data.get('field_course_start_date')
start = datetime.datetime.fromtimestamp(int(start), tz=pytz.UTC) if start else None start = datetime.datetime.fromtimestamp(int(start), tz=pytz.UTC) if start else None
end = data.get('field_course_end_date')
end = datetime.datetime.fromtimestamp(int(end), tz=pytz.UTC) if end else None
weeks_to_complete = data.get('field_course_required_weeks')
defaults = { defaults = {
'key': key, 'key': key,
...@@ -464,6 +468,12 @@ class CourseMarketingSiteDataLoader(AbstractMarketingSiteDataLoader): ...@@ -464,6 +468,12 @@ class CourseMarketingSiteDataLoader(AbstractMarketingSiteDataLoader):
'hidden': self.get_hidden(data), 'hidden': self.get_hidden(data),
} }
if weeks_to_complete:
defaults['weeks_to_complete'] = int(weeks_to_complete)
elif start and end:
weeks_to_complete = rrule.rrule(rrule.WEEKLY, dtstart=start, until=end).count()
defaults['weeks_to_complete'] = int(weeks_to_complete)
try: try:
course_run, __ = CourseRun.objects.update_or_create(key__iexact=key, defaults=defaults) course_run, __ = CourseRun.objects.update_or_create(key__iexact=key, defaults=defaults)
except TypeError: except TypeError:
......
...@@ -4,6 +4,7 @@ import math ...@@ -4,6 +4,7 @@ import math
from urllib.parse import parse_qs, urlparse from urllib.parse import parse_qs, urlparse
from uuid import UUID from uuid import UUID
from dateutil import rrule
import ddt import ddt
import mock import mock
import pytz import pytz
...@@ -470,6 +471,9 @@ class CourseMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMixi ...@@ -470,6 +471,9 @@ class CourseMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMixi
language = self.loader.get_language_tags_from_names(language_names).first() language = self.loader.get_language_tags_from_names(language_names).first()
start = data.get('field_course_start_date') start = data.get('field_course_start_date')
start = datetime.datetime.fromtimestamp(int(start), tz=pytz.UTC) if start else None start = datetime.datetime.fromtimestamp(int(start), tz=pytz.UTC) if start else None
end = data.get('field_course_end_date')
end = datetime.datetime.fromtimestamp(int(end), tz=pytz.UTC) if end else None
weeks_to_complete = data.get('field_course_required_weeks')
expected_values = { expected_values = {
'key': data['field_course_id'], 'key': data['field_course_id'],
...@@ -483,6 +487,12 @@ class CourseMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMixi ...@@ -483,6 +487,12 @@ class CourseMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMixi
'hidden': self.loader.get_hidden(data), 'hidden': self.loader.get_hidden(data),
} }
if weeks_to_complete:
expected_values['weeks_to_complete'] = int(weeks_to_complete)
elif start and end:
weeks_to_complete = rrule.rrule(rrule.WEEKLY, dtstart=start, until=end).count()
expected_values['weeks_to_complete'] = int(weeks_to_complete)
for field, value in expected_values.items(): for field, value in expected_values.items():
self.assertEqual(getattr(course_run, field), value) self.assertEqual(getattr(course_run, field), value)
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('course_metadata', '0030_create_refresh_command_switches'),
]
operations = [
migrations.AddField(
model_name='courserun',
name='weeks_to_complete',
field=models.PositiveSmallIntegerField(null=True, blank=True, help_text='This field is now deprecated (ECOM-6021).Estimated number of weeks needed to complete a course run.'),
),
]
...@@ -9,6 +9,7 @@ import pytz ...@@ -9,6 +9,7 @@ import pytz
import waffle import waffle
from django.db import models, transaction from django.db import models, transaction
from django.db.models.query_utils import Q from django.db.models.query_utils import Q
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_extensions.db.fields import AutoSlugField from django_extensions.db.fields import AutoSlugField
from django_extensions.db.models import TimeStampedModel from django_extensions.db.models import TimeStampedModel
...@@ -352,6 +353,9 @@ class CourseRun(TimeStampedModel): ...@@ -352,6 +353,9 @@ class CourseRun(TimeStampedModel):
max_effort = models.PositiveSmallIntegerField( max_effort = models.PositiveSmallIntegerField(
null=True, blank=True, null=True, blank=True,
help_text=_('Estimated maximum number of hours per week needed to complete a course run.')) help_text=_('Estimated maximum number of hours per week needed to complete a course run.'))
weeks_to_complete = models.PositiveSmallIntegerField(
null=True, blank=True,
help_text=_('Estimated number of weeks needed to complete this course run.'))
language = models.ForeignKey(LanguageTag, null=True, blank=True) language = models.ForeignKey(LanguageTag, null=True, blank=True)
transcript_languages = models.ManyToManyField(LanguageTag, blank=True, related_name='transcript_courses') transcript_languages = models.ManyToManyField(LanguageTag, blank=True, related_name='transcript_courses')
pacing_type = models.CharField(max_length=255, db_index=True, null=True, blank=True, pacing_type = models.CharField(max_length=255, db_index=True, null=True, blank=True,
...@@ -599,7 +603,11 @@ class Program(TimeStampedModel): ...@@ -599,7 +603,11 @@ class Program(TimeStampedModel):
excluded_course_runs = models.ManyToManyField(CourseRun, blank=True) excluded_course_runs = models.ManyToManyField(CourseRun, blank=True)
partner = models.ForeignKey(Partner, null=True, blank=False) partner = models.ForeignKey(Partner, null=True, blank=False)
overview = models.TextField(null=True, blank=True) overview = models.TextField(null=True, blank=True)
weeks_to_complete = models.PositiveSmallIntegerField(null=True, blank=True) # The weeks_to_complete field is now deprecated
weeks_to_complete = models.PositiveSmallIntegerField(
null=True, blank=True,
help_text=_('This field is now deprecated (ECOM-6021).'
'Estimated number of weeks needed to complete a course run belonging to this program.'))
min_hours_effort_per_week = models.PositiveSmallIntegerField(null=True, blank=True) min_hours_effort_per_week = models.PositiveSmallIntegerField(null=True, blank=True)
max_hours_effort_per_week = models.PositiveSmallIntegerField(null=True, blank=True) max_hours_effort_per_week = models.PositiveSmallIntegerField(null=True, blank=True)
authoring_organizations = SortedManyToManyField(Organization, blank=True, related_name='authored_programs') authoring_organizations = SortedManyToManyField(Organization, blank=True, related_name='authored_programs')
...@@ -636,6 +644,19 @@ class Program(TimeStampedModel): ...@@ -636,6 +644,19 @@ class Program(TimeStampedModel):
def __str__(self): def __str__(self):
return self.title return self.title
@cached_property
def _course_run_weeks_to_complete(self):
return [course_run.weeks_to_complete for course_run in self.course_runs
if course_run.weeks_to_complete is not None]
@property
def weeks_to_complete_min(self):
return min(self._course_run_weeks_to_complete) if self._course_run_weeks_to_complete else None
@property
def weeks_to_complete_max(self):
return max(self._course_run_weeks_to_complete) if self._course_run_weeks_to_complete else None
@property @property
def marketing_url(self): def marketing_url(self):
if self.marketing_slug: if self.marketing_slug:
......
...@@ -126,6 +126,7 @@ class CourseRunFactory(factory.DjangoModelFactory): ...@@ -126,6 +126,7 @@ class CourseRunFactory(factory.DjangoModelFactory):
max_effort = FuzzyInteger(10, 20) max_effort = FuzzyInteger(10, 20)
pacing_type = FuzzyChoice([name for name, __ in CourseRunPacing.choices]) pacing_type = FuzzyChoice([name for name, __ in CourseRunPacing.choices])
slug = FuzzyText() slug = FuzzyText()
weeks_to_complete = FuzzyInteger(1)
@factory.post_generation @factory.post_generation
def staff(self, create, extracted, **kwargs): def staff(self, create, extracted, **kwargs):
......
...@@ -311,6 +311,14 @@ class ProgramTests(MarketingSitePublisherTestMixin): ...@@ -311,6 +311,14 @@ class ProgramTests(MarketingSitePublisherTestMixin):
"""Verify that a program is properly converted to a str.""" """Verify that a program is properly converted to a str."""
self.assertEqual(str(self.program), self.program.title) self.assertEqual(str(self.program), self.program.title)
def test_weeks_to_complete_range(self):
""" Verify that weeks to complete range works correctly """
weeks_to_complete_values = [course_run.weeks_to_complete for course_run in self.course_runs]
expected_min = min(weeks_to_complete_values) if weeks_to_complete_values else None
expected_max = max(weeks_to_complete_values) if weeks_to_complete_values else None
self.assertEqual(self.program.weeks_to_complete_min, expected_min)
self.assertEqual(self.program.weeks_to_complete_max, expected_max)
def test_marketing_url(self): def test_marketing_url(self):
""" Verify the property creates a complete marketing URL. """ """ Verify the property creates a complete marketing URL. """
expected = '{root}/{type}/{slug}'.format(root=self.program.partner.marketing_site_url_root.strip('/'), expected = '{root}/{type}/{slug}'.format(root=self.program.partner.marketing_site_url_root.strip('/'),
......
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-10-13 14:43+0000\n" "POT-Creation-Date: 2016-10-19 18:33+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
...@@ -28,31 +28,31 @@ msgid "" ...@@ -28,31 +28,31 @@ msgid ""
"parameter." "parameter."
msgstr "" msgstr ""
#: course_discovery/apps/api/serializers.py:292 #: course_discovery/apps/api/serializers.py:293
msgid "Number of courses contained in this catalog" msgid "Number of courses contained in this catalog"
msgstr "" msgstr ""
#: course_discovery/apps/api/serializers.py:295 #: course_discovery/apps/api/serializers.py:296
msgid "Usernames of users with explicit access to view this catalog" msgid "Usernames of users with explicit access to view this catalog"
msgstr "" msgstr ""
#: course_discovery/apps/api/serializers.py:351 #: course_discovery/apps/api/serializers.py:352
msgid "Language in which the course is administered" msgid "Language in which the course is administered"
msgstr "" msgstr ""
#: course_discovery/apps/api/serializers.py:400 #: course_discovery/apps/api/serializers.py:407
msgid "Dictionary mapping course run IDs to boolean values" msgid "Dictionary mapping course run IDs to boolean values"
msgstr "" msgstr ""
#: course_discovery/apps/api/serializers.py:480 #: course_discovery/apps/api/serializers.py:495
msgid "Dictionary mapping course IDs to boolean values" msgid "Dictionary mapping course IDs to boolean values"
msgstr "" msgstr ""
#: course_discovery/apps/api/serializers.py:623 #: course_discovery/apps/api/serializers.py:638
msgid "Languages that course runs in this program are offered in." msgid "Languages that course runs in this program are offered in."
msgstr "" msgstr ""
#: course_discovery/apps/api/serializers.py:627 #: course_discovery/apps/api/serializers.py:642
msgid "" msgid ""
"Languages that course runs in this program have available transcripts in." "Languages that course runs in this program have available transcripts in."
msgstr "" msgstr ""
...@@ -231,128 +231,132 @@ msgstr "" ...@@ -231,128 +231,132 @@ msgstr ""
msgid "Deleted" msgid "Deleted"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/forms.py:76 #: course_discovery/apps/course_metadata/forms.py:79
msgid "" msgid ""
"Programs can only be activated if they have a marketing slug and a banner " "Programs can only be activated if they have a marketing slug and a banner "
"image." "image."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:74 #: course_discovery/apps/course_metadata/models.py:75
msgid "Facebook" msgid "Facebook"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:75 #: course_discovery/apps/course_metadata/models.py:76
msgid "Twitter" msgid "Twitter"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:76 #: course_discovery/apps/course_metadata/models.py:77
msgid "Blog" msgid "Blog"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:77 #: course_discovery/apps/course_metadata/models.py:78
msgid "Others" msgid "Others"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:111 #: course_discovery/apps/course_metadata/models.py:112
#: course_discovery/apps/course_metadata/models.py:155 #: course_discovery/apps/course_metadata/models.py:156
#: course_discovery/apps/course_metadata/models.py:185 #: course_discovery/apps/course_metadata/models.py:186
#: course_discovery/apps/course_metadata/models.py:233 #: course_discovery/apps/course_metadata/models.py:234
#: course_discovery/apps/course_metadata/models.py:324 #: course_discovery/apps/course_metadata/models.py:325
#: course_discovery/apps/course_metadata/models.py:574 #: course_discovery/apps/course_metadata/models.py:578
msgid "UUID" msgid "UUID"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:118 #: course_discovery/apps/course_metadata/models.py:119
msgid "Leave this field blank to have the value generated automatically." msgid "Leave this field blank to have the value generated automatically."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:197 #: course_discovery/apps/course_metadata/models.py:198
msgid "People" msgid "People"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:249 #: course_discovery/apps/course_metadata/models.py:250
msgid "Course number format e.g CS002x, BIO1.1x, BIO1.2x" msgid "Course number format e.g CS002x, BIO1.1x, BIO1.2x"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:332 #: course_discovery/apps/course_metadata/models.py:333
msgid "" msgid ""
"Title specific for this run of a course. Leave this value blank to default " "Title specific for this run of a course. Leave this value blank to default "
"to the parent course's title." "to the parent course's title."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:341 #: course_discovery/apps/course_metadata/models.py:342
msgid "" msgid ""
"Short description specific for this run of a course. Leave this value blank " "Short description specific for this run of a course. Leave this value blank "
"to default to the parent course's short_description attribute." "to default to the parent course's short_description attribute."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:346 #: course_discovery/apps/course_metadata/models.py:347
msgid "" msgid ""
"Full description specific for this run of a course. Leave this value blank " "Full description specific for this run of a course. Leave this value blank "
"to default to the parent course's full_description attribute." "to default to the parent course's full_description attribute."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:351 #: course_discovery/apps/course_metadata/models.py:352
#: course_discovery/apps/publisher/models.py:193 #: course_discovery/apps/publisher/models.py:193
msgid "" msgid ""
"Estimated minimum number of hours per week needed to complete a course run." "Estimated minimum number of hours per week needed to complete a course run."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:354 #: course_discovery/apps/course_metadata/models.py:355
#: course_discovery/apps/publisher/models.py:196 #: course_discovery/apps/publisher/models.py:196
msgid "" msgid ""
"Estimated maximum number of hours per week needed to complete a course run." "Estimated maximum number of hours per week needed to complete a course run."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:461 #: course_discovery/apps/course_metadata/models.py:358
msgid "Estimated number of weeks needed to complete this course run."
msgstr ""
#: course_discovery/apps/course_metadata/models.py:465
msgid "Archived" msgid "Archived"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:463 #: course_discovery/apps/course_metadata/models.py:467
msgid "Current" msgid "Current"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:465 #: course_discovery/apps/course_metadata/models.py:469
msgid "Starting Soon" msgid "Starting Soon"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:467 #: course_discovery/apps/course_metadata/models.py:471
msgid "Upcoming" msgid "Upcoming"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:503 #: course_discovery/apps/course_metadata/models.py:507
#: course_discovery/apps/publisher/models.py:280 #: course_discovery/apps/publisher/models.py:280
msgid "Honor" msgid "Honor"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:504 #: course_discovery/apps/course_metadata/models.py:508
#: course_discovery/apps/publisher/models.py:281 #: course_discovery/apps/publisher/models.py:281
msgid "Audit" msgid "Audit"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:505 #: course_discovery/apps/course_metadata/models.py:509
#: course_discovery/apps/publisher/models.py:282 #: course_discovery/apps/publisher/models.py:282
msgid "Verified" msgid "Verified"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:506 #: course_discovery/apps/course_metadata/models.py:510
msgid "Professional" msgid "Professional"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:507 #: course_discovery/apps/course_metadata/models.py:511
#: course_discovery/apps/publisher/models.py:285 #: course_discovery/apps/publisher/models.py:285
msgid "Credit" msgid "Credit"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:554 #: course_discovery/apps/course_metadata/models.py:558
msgid "FAQ" msgid "FAQ"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:555 #: course_discovery/apps/course_metadata/models.py:559
msgid "FAQs" msgid "FAQs"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:564 #: course_discovery/apps/course_metadata/models.py:568
msgid "" msgid ""
"Seat types that qualify for completion of programs of this type. Learners " "Seat types that qualify for completion of programs of this type. Learners "
"completing associated courses, but enrolled in other seat types, will NOT " "completing associated courses, but enrolled in other seat types, will NOT "
...@@ -360,37 +364,43 @@ msgid "" ...@@ -360,37 +364,43 @@ msgid ""
"program." "program."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:576 #: course_discovery/apps/course_metadata/models.py:580
msgid "The user-facing display title for this Program." msgid "The user-facing display title for this Program."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:578 #: course_discovery/apps/course_metadata/models.py:582
msgid "A brief, descriptive subtitle for the Program." msgid "A brief, descriptive subtitle for the Program."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:581 #: course_discovery/apps/course_metadata/models.py:585
msgid "The lifecycle status of this Program." msgid "The lifecycle status of this Program."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:585 #: course_discovery/apps/course_metadata/models.py:589
msgid "Slug used to generate links to the marketing site" msgid "Slug used to generate links to the marketing site"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:589 #: course_discovery/apps/course_metadata/models.py:593
msgid "" msgid ""
"If this box is not checked, courses will be ordered as in the courses select " "If this box is not checked, courses will be ordered as in the courses select "
"box above." "box above."
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:611 #: course_discovery/apps/course_metadata/models.py:603
msgid ""
"This field is now deprecated (ECOM-6021).Estimated number of weeks needed to "
"complete a course run belonging to this program."
msgstr ""
#: course_discovery/apps/course_metadata/models.py:619
msgid "Image used atop detail pages" msgid "Image used atop detail pages"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:612 #: course_discovery/apps/course_metadata/models.py:620
msgid "Image used for discovery cards" msgid "Image used for discovery cards"
msgstr "" msgstr ""
#: course_discovery/apps/course_metadata/models.py:624 #: course_discovery/apps/course_metadata/models.py:632
msgid "The description of credit redemption for courses in program" msgid "The description of credit redemption for courses in program"
msgstr "" msgstr ""
......
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-10-13 14:43+0000\n" "POT-Creation-Date: 2016-10-19 18:34+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
......
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-10-13 14:43+0000\n" "POT-Creation-Date: 2016-10-19 18:33+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
...@@ -376,6 +376,12 @@ msgstr "" ...@@ -376,6 +376,12 @@ msgstr ""
"Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυ#" "Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυ#"
#: course_discovery/apps/course_metadata/models.py #: course_discovery/apps/course_metadata/models.py
msgid "Estimated number of weeks needed to complete this course run."
msgstr ""
"Éstïmätéd nümßér öf wééks néédéd tö çömplété thïs çöürsé rün. Ⱡ'σяєм ιρѕυм "
"∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
#: course_discovery/apps/course_metadata/models.py
msgid "Archived" msgid "Archived"
msgstr "Àrçhïvéd Ⱡ'σяєм ιρѕυм ∂#" msgstr "Àrçhïvéd Ⱡ'σяєм ιρѕυм ∂#"
...@@ -472,6 +478,14 @@ msgstr "" ...@@ -472,6 +478,14 @@ msgstr ""
" ßöx äßövé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#" " ßöx äßövé. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє#"
#: course_discovery/apps/course_metadata/models.py #: course_discovery/apps/course_metadata/models.py
msgid ""
"This field is now deprecated (ECOM-6021).Estimated number of weeks needed to"
" complete a course run belonging to this program."
msgstr ""
"Thïs fïéld ïs nöw dépréçätéd (ÉÇÖM-6021).Éstïmätéd nümßér öf wééks néédéd tö"
" çömplété ä çöürsé rün ßélöngïng tö thïs prögräm. Ⱡ'σяєм #"
#: course_discovery/apps/course_metadata/models.py
msgid "Image used atop detail pages" msgid "Image used atop detail pages"
msgstr "Ìmägé üséd ätöp détäïl pägés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#" msgstr "Ìmägé üséd ätöp détäïl pägés Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#"
......
...@@ -7,7 +7,7 @@ msgid "" ...@@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-10-13 14:43+0000\n" "POT-Creation-Date: 2016-10-19 18:34+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
......
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