Commit 58665dd5 by christopher lee Committed by Christopher Lee

Add multilingual content for Subjects

parent a4994b7d
...@@ -181,7 +181,11 @@ class PersonFilter(filters.FilterSet): ...@@ -181,7 +181,11 @@ class PersonFilter(filters.FilterSet):
class SubjectFilter(filters.FilterSet): class SubjectFilter(filters.FilterSet):
language_code = filters.CharFilter(method='_set_language')
def _set_language(self, queryset, _, language_code):
return queryset.language(language_code)
class Meta: class Meta:
model = Subject model = Subject
fields = ('slug', ) fields = ('slug', 'language_code')
...@@ -163,6 +163,9 @@ class FAQSerializer(serializers.ModelSerializer): ...@@ -163,6 +163,9 @@ class FAQSerializer(serializers.ModelSerializer):
class SubjectSerializer(serializers.ModelSerializer): class SubjectSerializer(serializers.ModelSerializer):
"""Serializer for the ``Subject`` model.""" """Serializer for the ``Subject`` model."""
name = serializers.CharField(source='name_t')
subtitle = serializers.CharField(source='subtitle_t')
description = serializers.CharField(source='description_t')
@classmethod @classmethod
def prefetch_queryset(cls): def prefetch_queryset(cls):
......
...@@ -949,11 +949,11 @@ class SubjectSerializerTests(TestCase): ...@@ -949,11 +949,11 @@ class SubjectSerializerTests(TestCase):
serializer = SubjectSerializer(subject) serializer = SubjectSerializer(subject)
expected = { expected = {
'name': subject.name, 'name': subject.name_t,
'description': subject.description, 'description': subject.description_t,
'banner_image_url': subject.banner_image_url, 'banner_image_url': subject.banner_image_url,
'card_image_url': subject.card_image_url, 'card_image_url': subject.card_image_url,
'subtitle': subject.subtitle, 'subtitle': subject.subtitle_t,
'slug': subject.slug, 'slug': subject.slug,
'uuid': str(subject.uuid), 'uuid': str(subject.uuid),
} }
......
...@@ -3,6 +3,7 @@ from django.http import HttpResponseRedirect ...@@ -3,6 +3,7 @@ from django.http import HttpResponseRedirect
from django.urls import reverse from django.urls import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from parler.admin import TranslatableAdmin
from course_discovery.apps.course_metadata.exceptions import ( from course_discovery.apps.course_metadata.exceptions import (
MarketingSiteAPIClientException, MarketingSitePublisherException MarketingSiteAPIClientException, MarketingSitePublisherException
...@@ -220,11 +221,13 @@ class OrganizationAdmin(admin.ModelAdmin): ...@@ -220,11 +221,13 @@ class OrganizationAdmin(admin.ModelAdmin):
@admin.register(Subject) @admin.register(Subject)
class SubjectAdmin(admin.ModelAdmin): class SubjectAdmin(TranslatableAdmin):
list_display = ('uuid', 'name', 'slug',) # These fields are excluded here because they will be removed in favor of the translated fields.
exclude = ('name', 'subtitle', 'description')
list_display = ('uuid', 'name_t', 'slug',)
list_filter = ('partner',) list_filter = ('partner',)
readonly_fields = ('uuid',) readonly_fields = ('uuid',)
search_fields = ('uuid', 'name', 'slug',) search_fields = ('uuid', 'name_t', 'slug',)
@admin.register(Person) @admin.register(Person)
......
...@@ -143,15 +143,27 @@ class SubjectMarketingSiteDataLoader(AbstractMarketingSiteDataLoader): ...@@ -143,15 +143,27 @@ class SubjectMarketingSiteDataLoader(AbstractMarketingSiteDataLoader):
slug = data['field_subject_url_slug'] slug = data['field_subject_url_slug']
defaults = { defaults = {
'uuid': data['uuid'], 'uuid': data['uuid'],
'name': data['title'], 'name_t': data['title'],
'description': self.clean_html(data['body']['value']), 'description_t': self.clean_html(data['body']['value']),
'subtitle': self.clean_html(data['field_subject_subtitle']['value']), 'subtitle_t': self.clean_html(data['field_subject_subtitle']['value']),
'card_image_url': self._get_nested_url(data.get('field_subject_card_image')), 'card_image_url': self._get_nested_url(data.get('field_subject_card_image')),
# NOTE (CCB): This is not a typo. Yes, the banner image for subjects is in a field with xseries in the name. # NOTE (CCB): This is not a typo. Yes, the banner image for subjects is in a field with xseries in the name.
'banner_image_url': self._get_nested_url(data.get('field_xseries_banner_image')) 'banner_image_url': self._get_nested_url(data.get('field_xseries_banner_image'))
} }
subject, __ = Subject.objects.update_or_create(slug=slug, partner=self.partner, defaults=defaults)
# There is a bug with django-parler when using django's update_or_create() so we manually update or create.
try:
subject = Subject.objects.get(slug=slug, partner=self.partner)
for key, value in defaults.items():
setattr(subject, key, value)
subject.save()
except Subject.DoesNotExist:
new_values = {'slug': slug, 'partner': self.partner}
new_values.update(defaults)
subject = Subject(**new_values)
subject.save()
logger.info('Processed subject with slug [%s].', slug) logger.info('Processed subject with slug [%s].', slug)
return subject return subject
......
...@@ -146,9 +146,9 @@ class SubjectMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMix ...@@ -146,9 +146,9 @@ class SubjectMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMix
subject = Subject.objects.get(slug=slug, partner=self.partner) subject = Subject.objects.get(slug=slug, partner=self.partner)
expected_values = { expected_values = {
'uuid': UUID(data['uuid']), 'uuid': UUID(data['uuid']),
'name': data['title'], 'name_t': data['title'],
'description': self.loader.clean_html(data['body']['value']), 'description_t': self.loader.clean_html(data['body']['value']),
'subtitle': self.loader.clean_html(data['field_subject_subtitle']['value']), 'subtitle_t': self.loader.clean_html(data['field_subject_subtitle']['value']),
'card_image_url': data['field_subject_card_image']['url'], 'card_image_url': data['field_subject_card_image']['url'],
'banner_image_url': data['field_xseries_banner_image']['url'], 'banner_image_url': data['field_xseries_banner_image']['url'],
} }
...@@ -166,6 +166,28 @@ class SubjectMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMix ...@@ -166,6 +166,28 @@ class SubjectMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMix
for datum in api_data: for datum in api_data:
self.assert_subject_loaded(datum) self.assert_subject_loaded(datum)
@responses.activate
def test_ingest2(self):
self.mock_login_response()
api_data = self.mock_api()
for data in api_data:
subject_data = {
'uuid': UUID(data['uuid']),
'name_t': data['title'],
'description_t': self.loader.clean_html(data['body']['value']),
'subtitle_t': self.loader.clean_html(data['field_subject_subtitle']['value']),
'card_image_url': data['field_subject_card_image']['url'],
'banner_image_url': data['field_xseries_banner_image']['url'],
}
slug = data['field_subject_url_slug']
Subject.objects.create(slug=slug, partner=self.partner, **subject_data)
self.loader.ingest()
for datum in api_data:
self.assert_subject_loaded(datum)
class SchoolMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMixin, TestCase): class SchoolMarketingSiteDataLoaderTests(AbstractMarketingSiteDataLoaderTestMixin, TestCase):
loader_class = SchoolMarketingSiteDataLoader loader_class = SchoolMarketingSiteDataLoader
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-09-19 19:27
from __future__ import unicode_literals
import django.db.models.deletion
import django_extensions
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('course_metadata', '0059_auto_20171002_1705'),
]
operations = [
migrations.CreateModel(
name='SubjectTranslation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('language_code', models.CharField(db_index=True, max_length=15, verbose_name='Language')),
('name_t', models.CharField(max_length=255)),
('subtitle_t', models.CharField(blank=True, max_length=255, null=True)),
('description_t', models.TextField(blank=True, null=True)),
('master',
models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations',
to='course_metadata.Subject')),
],
options={
'verbose_name': 'Subject model translations',
},
),
migrations.AlterField(
model_name='subject',
name='slug',
field=django_extensions.db.fields.AutoSlugField(blank=True, editable=False,
help_text='Leave this field blank to have the value generated automatically.',
populate_from='name_t'),
),
migrations.AlterUniqueTogether(
name='subject',
unique_together=set([('partner', 'slug'), ('partner', 'uuid')]),
),
migrations.AlterUniqueTogether(
name='subjecttranslation',
unique_together=set([('language_code', 'master')]),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11.3 on 2017-09-11 17:06
from __future__ import unicode_literals
import logging
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import migrations
logger = logging.getLogger(__name__)
def forwards_func(apps, schema_editor):
Subject = apps.get_model('course_metadata', 'Subject')
SubjectTranslation = apps.get_model('course_metadata', 'SubjectTranslation')
for subject in Subject.objects.all():
SubjectTranslation.objects.create(
master_id=subject.pk,
language_code=settings.PARLER_DEFAULT_LANGUAGE_CODE,
name_t=subject.name,
subtitle_t=subject.subtitle,
description_t=subject.description
)
def backwards_func(apps, schema_editor):
Subject = apps.get_model('course_metadata', 'Subject')
SubjectTranslation = apps.get_model('course_metadata', 'SubjectTranslation')
for subject in Subject.objects.all():
try:
translation = SubjectTranslation.objects.filter(master_id=subject.pk)
subject.name = translation.name_t
subject.subtitle = translation.subtitle_t
subject.description = translation.description_t
subject.save() # Note this only calls Model.save()
except ObjectDoesNotExist:
# nothing to migrate
logger.exception('Migrating data from SubjectTranslation for master_id={} DoesNotExist'.format(subject.pk))
class Migration(migrations.Migration):
dependencies = [
('course_metadata', '0060_create_subjecttranslations_models'),
]
operations = [
migrations.RunPython(forwards_func, backwards_func),
]
...@@ -7,6 +7,7 @@ from uuid import uuid4 ...@@ -7,6 +7,7 @@ from uuid import uuid4
import pytz import pytz
import waffle import waffle
from django.core.exceptions import ValidationError
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.functional import cached_property
...@@ -15,6 +16,7 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -15,6 +16,7 @@ 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
from haystack.query import SearchQuerySet from haystack.query import SearchQuerySet
from parler.models import TranslatableModel, TranslatedFieldsModel
from solo.models import SingletonModel from solo.models import SingletonModel
from sortedm2m.fields import SortedManyToManyField from sortedm2m.fields import SortedManyToManyField
from stdimage.models import StdImageField from stdimage.models import StdImageField
...@@ -111,7 +113,7 @@ class LevelType(AbstractNamedModel): ...@@ -111,7 +113,7 @@ class LevelType(AbstractNamedModel):
pass pass
class Subject(TimeStampedModel): class Subject(TranslatableModel, TimeStampedModel):
""" Subject model. """ """ Subject model. """
uuid = models.UUIDField(blank=False, null=False, default=uuid4, editable=False, verbose_name=_('UUID')) uuid = models.UUIDField(blank=False, null=False, default=uuid4, editable=False, verbose_name=_('UUID'))
name = models.CharField(max_length=255, blank=False, null=False) name = models.CharField(max_length=255, blank=False, null=False)
...@@ -119,7 +121,7 @@ class Subject(TimeStampedModel): ...@@ -119,7 +121,7 @@ class Subject(TimeStampedModel):
description = models.TextField(blank=True, null=True) description = models.TextField(blank=True, null=True)
banner_image_url = models.URLField(blank=True, null=True) banner_image_url = models.URLField(blank=True, null=True)
card_image_url = models.URLField(blank=True, null=True) card_image_url = models.URLField(blank=True, null=True)
slug = AutoSlugField(populate_from='name', editable=True, blank=True, slug = AutoSlugField(populate_from='name_t', editable=True, blank=True,
help_text=_('Leave this field blank to have the value generated automatically.')) help_text=_('Leave this field blank to have the value generated automatically.'))
partner = models.ForeignKey(Partner) partner = models.ForeignKey(Partner)
...@@ -128,11 +130,31 @@ class Subject(TimeStampedModel): ...@@ -128,11 +130,31 @@ class Subject(TimeStampedModel):
class Meta: class Meta:
unique_together = ( unique_together = (
('partner', 'name'),
('partner', 'slug'), ('partner', 'slug'),
('partner', 'uuid'), ('partner', 'uuid'),
) )
def validate_unique(self, *args, **kwargs):
super(Subject, self).validate_unique(*args, **kwargs)
qs = Subject.objects.filter(partner=self.partner_id)
if qs.filter(translations__name_t=self.name_t).exists():
raise ValidationError({'name_t': ['Subject with this Name and Partner already exists', ]})
class SubjectTranslation(TranslatedFieldsModel):
master = models.ForeignKey(Subject, related_name='translations', null=True)
name_t = models.CharField(max_length=255, blank=False, null=False)
subtitle_t = models.CharField(max_length=255, blank=True, null=True)
description_t = models.TextField(blank=True, null=True)
def __str__(self):
return self.name_t
class Meta:
unique_together = ('language_code', 'master')
verbose_name = _('Subject model translations')
class Prerequisite(AbstractNamedModel): class Prerequisite(AbstractNamedModel):
""" Prerequisite model. """ """ Prerequisite model. """
......
...@@ -41,8 +41,8 @@ class SubjectFactory(factory.DjangoModelFactory): ...@@ -41,8 +41,8 @@ class SubjectFactory(factory.DjangoModelFactory):
class Meta: class Meta:
model = Subject model = Subject
name = FuzzyText() name_t = FuzzyText() # TODO Switch to 'name' when 'name_t' is renamed.
description = FuzzyText() description_t = FuzzyText()
banner_image_url = FuzzyURL() banner_image_url = FuzzyURL()
card_image_url = FuzzyURL() card_image_url = FuzzyURL()
partner = factory.SubFactory(PartnerFactory) partner = factory.SubFactory(PartnerFactory)
......
...@@ -6,11 +6,13 @@ import ddt ...@@ -6,11 +6,13 @@ import ddt
import mock import mock
from dateutil.parser import parse from dateutil.parser import parse
from django.conf import settings from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import IntegrityError from django.db import IntegrityError
from django.db.models.functions import Lower from django.db.models.functions import Lower
from django.test import TestCase from django.test import TestCase
from freezegun import freeze_time from freezegun import freeze_time
from course_discovery.apps.api.tests.mixins import SiteMixin
from course_discovery.apps.core.models import Currency from course_discovery.apps.core.models import Currency
from course_discovery.apps.core.tests.helpers import make_image_file from course_discovery.apps.core.tests.helpers import make_image_file
from course_discovery.apps.core.tests.mixins import ElasticsearchTestMixin from course_discovery.apps.core.tests.mixins import ElasticsearchTestMixin
...@@ -18,8 +20,7 @@ from course_discovery.apps.core.utils import SearchQuerySetWrapper ...@@ -18,8 +20,7 @@ from course_discovery.apps.core.utils import SearchQuerySetWrapper
from course_discovery.apps.course_metadata.choices import CourseRunStatus, ProgramStatus from course_discovery.apps.course_metadata.choices import CourseRunStatus, ProgramStatus
from course_discovery.apps.course_metadata.models import ( from course_discovery.apps.course_metadata.models import (
FAQ, AbstractMediaModel, AbstractNamedModel, AbstractValueModel, CorporateEndorsement, Course, CourseRun, FAQ, AbstractMediaModel, AbstractNamedModel, AbstractValueModel, CorporateEndorsement, Course, CourseRun,
Endorsement, Seat, SeatType Endorsement, Seat, SeatType, Subject)
)
from course_discovery.apps.course_metadata.publishers import ( from course_discovery.apps.course_metadata.publishers import (
CourseRunMarketingSitePublisher, ProgramMarketingSitePublisher CourseRunMarketingSitePublisher, ProgramMarketingSitePublisher
) )
...@@ -487,8 +488,8 @@ class ProgramTests(TestCase): ...@@ -487,8 +488,8 @@ class ProgramTests(TestCase):
return factories.ProgramFactory(type=program_type, courses=[course_run.course]) return factories.ProgramFactory(type=program_type, courses=[course_run.course])
def assert_one_click_purchase_ineligible_program( def assert_one_click_purchase_ineligible_program(
self, end=None, enrollment_start=None, enrollment_end=None, seat_type=Seat.VERIFIED, self, end=None, enrollment_start=None, enrollment_end=None, seat_type=Seat.VERIFIED,
upgrade_deadline=None, one_click_purchase_enabled=True, excluded_course_runs=None, program_type=None upgrade_deadline=None, one_click_purchase_enabled=True, excluded_course_runs=None, program_type=None
): ):
course_run = factories.CourseRunFactory( course_run = factories.CourseRunFactory(
end=end, enrollment_start=enrollment_start, enrollment_end=enrollment_end end=end, enrollment_start=enrollment_start, enrollment_end=enrollment_end
...@@ -1009,3 +1010,29 @@ class FAQTests(TestCase): ...@@ -1009,3 +1010,29 @@ class FAQTests(TestCase):
question = 'test question' question = 'test question'
faq = FAQ.objects.create(question=question, answer='test') faq = FAQ.objects.create(question=question, answer='test')
self.assertEqual(str(faq), question) self.assertEqual(str(faq), question)
class SubjectTests(SiteMixin, TestCase):
""" Tests of the Multilingual Subject model. """
def test_partner_name_t_uniqueness(self):
dummy_url = "http://www.example.com"
Subject.objects.create(
name="name1",
name_t="aaa",
partner_id=self.partner.id,
banner_image_url=dummy_url,
card_image_url=dummy_url)
invalid_subject = Subject(
name="name2",
name_t="aaa",
partner_id=self.partner.id,
banner_image_url=dummy_url,
card_image_url=dummy_url)
with self.assertRaises(ValidationError) as validation_error:
invalid_subject.full_clean()
self.assertEqual(
str(validation_error.exception),
"{'name_t': ['Subject with this Name and Partner already exists']}")
...@@ -3,7 +3,7 @@ import pytest ...@@ -3,7 +3,7 @@ import pytest
from django.apps import apps from django.apps import apps
from factory import DjangoModelFactory from factory import DjangoModelFactory
from course_discovery.apps.course_metadata.models import DataLoaderConfig from course_discovery.apps.course_metadata.models import DataLoaderConfig, SubjectTranslation
from course_discovery.apps.course_metadata.tests import factories from course_discovery.apps.course_metadata.tests import factories
...@@ -25,7 +25,7 @@ class TestCacheInvalidation: ...@@ -25,7 +25,7 @@ class TestCacheInvalidation:
# connecting to. We want to test each of them. # connecting to. We want to test each of them.
for model in apps.get_app_config('course_metadata').get_models(): for model in apps.get_app_config('course_metadata').get_models():
# Ignore models that aren't exposed by the API or are only used for testing. # Ignore models that aren't exposed by the API or are only used for testing.
if model == DataLoaderConfig or 'abstract' in model.__name__.lower(): if model in [DataLoaderConfig, SubjectTranslation] or 'abstract' in model.__name__.lower():
continue continue
factory = factory_map.get(model) factory = factory_map.get(model)
......
...@@ -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: 2017-10-06 12:30+0500\n" "POT-Creation-Date: 2017-10-06 17:23+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"
...@@ -286,6 +286,10 @@ msgid "Leave this field blank to have the value generated automatically." ...@@ -286,6 +286,10 @@ msgid "Leave this field blank to have the value generated automatically."
msgstr "" msgstr ""
#: apps/course_metadata/models.py #: apps/course_metadata/models.py
msgid "Subject model translations"
msgstr ""
#: apps/course_metadata/models.py
msgid "" msgid ""
"Logo to be displayed on certificates. If this logo is the same as " "Logo to be displayed on certificates. If this logo is the same as "
"logo_image_url, copy and paste the same value to both fields." "logo_image_url, copy and paste the same value to both fields."
......
...@@ -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: 2017-10-06 12:30+0500\n" "POT-Creation-Date: 2017-10-06 17:23+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: 2017-10-06 12:30+0500\n" "POT-Creation-Date: 2017-10-06 17:23+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"
...@@ -339,6 +339,10 @@ msgstr "" ...@@ -339,6 +339,10 @@ msgstr ""
"ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#" "ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
#: apps/course_metadata/models.py #: apps/course_metadata/models.py
msgid "Subject model translations"
msgstr "Süßjéçt mödél tränslätïöns Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
#: apps/course_metadata/models.py
msgid "" msgid ""
"Logo to be displayed on certificates. If this logo is the same as " "Logo to be displayed on certificates. If this logo is the same as "
"logo_image_url, copy and paste the same value to both fields." "logo_image_url, copy and paste the same value to both fields."
......
...@@ -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: 2017-10-06 12:30+0500\n" "POT-Creation-Date: 2017-10-06 17:23+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"
......
...@@ -55,6 +55,7 @@ THIRD_PARTY_APPS = [ ...@@ -55,6 +55,7 @@ THIRD_PARTY_APPS = [
'taggit_serializer', 'taggit_serializer',
'solo', 'solo',
'webpack_loader', 'webpack_loader',
'parler',
] ]
PROJECT_APPS = [ PROJECT_APPS = [
...@@ -110,9 +111,21 @@ DATABASES = { ...@@ -110,9 +111,21 @@ DATABASES = {
} }
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/ # See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en'
LANGUAGE_CODE = 'en-us' PARLER_DEFAULT_LANGUAGE_CODE = LANGUAGE_CODE
PARLER_LANGUAGES = {
1: (
{'code': LANGUAGE_CODE, },
),
'default': {
'fallbacks': [PARLER_DEFAULT_LANGUAGE_CODE],
'hide_untranslated': False,
}
}
TIME_ZONE = 'UTC' TIME_ZONE = 'UTC'
......
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