forked from sio2project/oioioi
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SIO-2107 Add multiple language support for News
Adding the possibility to create different title/content versions of a News instance for each language supported by application. Change-Id: If72cdae6c5d499114f7bde92dc0ea67ca0c08ae5
- Loading branch information
Showing
17 changed files
with
497 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Constructs an object which will control behaviour of translations formset | ||
// (a set of forms containing different translations of some content). | ||
// You may want to override some of it's parameters - pass them in a dictionary | ||
// as the first argument: | ||
// - 'select': a jQuery-wrapped HTMLSelectElement that is used to choose a displayed translation, | ||
// - 'formGetter': a function returning forms (as jQuery objects) for a given language, | ||
// - 'requiredFieldsSelector': a CSS selector string, matching the inputs of required fields. | ||
function TranslationFormset(parameters) { | ||
for (var parameter in parameters) { | ||
if (typeof(this[parameter]) === 'undefined') { | ||
throw "Sorry, parameter '" + parameter + "' passed to TranslationFormset is not recognized."; | ||
} else { | ||
this[parameter] = parameters[parameter]; | ||
} | ||
} | ||
|
||
var tFormset = this; | ||
|
||
this.select.change(function() { | ||
if (!this.value) { | ||
tFormset.hideTranslation(tFormset.currentLang); | ||
} else { | ||
tFormset.showTranslation(this.value); | ||
} | ||
}); | ||
|
||
// For each form in a formset, Django adds a checkbox indicating deletion of the | ||
// form's instance. We hide the checkbox (along with it's parent-label) from | ||
// the user and check/uncheck it in TranslationFormset's internal functions. | ||
$('input[name*="DELETE"]').parent().hide(); | ||
|
||
|
||
// Find the forms that should be visible (translations already created by user) according | ||
// to POST data and display them - with forms containing errors at the beginning. | ||
var notDeletedForms = []; | ||
var notDeletedFormsWithErrors = []; | ||
|
||
this.forms().each(function(index, form) { | ||
var $form = $(form); | ||
|
||
var requiredFields = $form.find(tFormset.requiredFieldsSelector); | ||
form.tf__requiredFields = requiredFields.get(); | ||
|
||
tFormset.computeFormDeletion($form); | ||
requiredFields.change(tFormset.computeFormDeletion.bind(tFormset, $form)); | ||
|
||
if (!tFormset.formDeleted($form)) { | ||
if ($form.find('.has-error').length > 0) { | ||
notDeletedFormsWithErrors.push($form); | ||
} else { | ||
notDeletedForms.push($form); | ||
} | ||
} | ||
}); | ||
|
||
// Forms for created translations, the ones containing errors at the beginning. | ||
notDeletedForms = notDeletedFormsWithErrors.concat(notDeletedForms); | ||
|
||
notDeletedForms.forEach(function(form) { | ||
var lang = form.data('lang'); | ||
tFormset.addTranslation(lang); | ||
}); | ||
|
||
// The form from the first column is always required. | ||
this.formDeleted($('.first-column'), false); | ||
} | ||
|
||
$.extend(TranslationFormset.prototype, { | ||
select: $('#translation-select'), | ||
forms: function (lang) { return lang ? $('#form-' + lang) : $('[id^=form-]'); }, | ||
requiredFieldsSelector: '', | ||
currentLang: '', | ||
|
||
hideTranslation: function(lang) { | ||
if (lang) { | ||
this.forms(lang).css('display', 'none'); | ||
} | ||
if (lang === this.currentLang) { | ||
this.currentLang = ''; | ||
} | ||
}, | ||
showTranslation: function(lang) { | ||
var form = this.forms(lang); | ||
|
||
// Hide previously displayed form - only one form per column. | ||
this.hideTranslation(this.currentLang); | ||
|
||
form.css('display', 'block'); | ||
this.select.val(lang); | ||
this.currentLang = lang; | ||
}, | ||
addTranslation: function(lang) { | ||
// Mark new languages' form as not deleted. | ||
this.formDeleted(this.forms(lang), false); | ||
|
||
// If there's an empty column - display it with the new translation form. | ||
if (this.currentLang === '') { | ||
this.showTranslation(lang); | ||
} | ||
}, | ||
formDeleted: function(form, value) { | ||
if (arguments.length < 2) { | ||
return form.find('input[name*="DELETE"]').prop('checked'); | ||
} else { | ||
return form.find('input[name*="DELETE"]').prop('checked', value); | ||
} | ||
}, | ||
computeFormDeletion: function(form) { | ||
if (form.get(0).tf__requiredFields.every(this.fieldIsEmpty)) { | ||
this.formDeleted(form, true); | ||
} else if (this.formDeleted(form)) { | ||
this.formDeleted(form, false); | ||
} | ||
}, | ||
fieldIsEmpty: function(field) { | ||
return !field.value; | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#translation-formset { | ||
padding-bottom: 50px; | ||
|
||
.first-column { | ||
float: left; | ||
width: 50%; | ||
padding-right: 15px; | ||
} | ||
|
||
.second-column { | ||
float: right; | ||
width: 50%; | ||
padding-left: 15px; | ||
|
||
select { | ||
display: inline-block; | ||
width: initial; | ||
} | ||
|
||
.translation-form { | ||
display: none; | ||
|
||
.delete-translation { | ||
margin: 20px 0 10px; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
oioioi/base/templates/ingredients/translation-formset.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
{% load i18n staticfiles compress %} | ||
{% get_current_language as LANGUAGE_CODE %} | ||
|
||
<div id="translation-formset" class="clearfix"> | ||
{{ formset.management_form }} | ||
|
||
{% if formset.non_form_errors %} | ||
<div class="form-group"> | ||
{% for error in formset.non_form_errors %} | ||
<div class="alert alert-danger" role="alert"> | ||
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> | ||
<span class="sr-only">{% trans "Error" %}:</span> | ||
{{ error }} | ||
</div> | ||
{% endfor %} | ||
</div> | ||
{% endif %} | ||
|
||
<div class="clearfix"> | ||
<div class="first-column"> | ||
<label>{% trans "Current language" %}:</label> | ||
{{ LANGUAGE_CODE|language_name_translated }} | ||
</div> | ||
<div class="second-column"> | ||
<label for="translation-select">{% trans "Tranlation language" %}:</label> | ||
<select id="translation-select" class="form-control"> | ||
<option value="">------</option> | ||
{% for lang_short, lang_name in LANGUAGES %} | ||
{% if lang_short != LANGUAGE_CODE %} | ||
<option value="{{ lang_short }}"> | ||
{{ lang_short|language_name_translated }} | ||
</option> | ||
{% endif %} | ||
{% endfor %} | ||
</select> | ||
</div> | ||
</div> | ||
|
||
<div class="first-column"> | ||
{% for form in formset %} | ||
{% if form.language.value == LANGUAGE_CODE %} | ||
{% include "ingredients/form.html" %} | ||
{% endif %} | ||
{% endfor %} | ||
</div> | ||
|
||
<div class="second-column"> | ||
{% for form in formset %} | ||
{% if form.language.value != LANGUAGE_CODE %} | ||
<div id="form-{{ form.language.value }}" class="translation-form" data-lang="{{ form.language.value }}"> | ||
{% include "ingredients/form.html" %} | ||
</div> | ||
{% endif %} | ||
{% endfor %} | ||
</div> | ||
</div> | ||
|
||
{% compress js %} | ||
<script type="text/javascript" src="{% static 'js/translation-formset.js' %}"></script> | ||
{% endcompress %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,19 @@ | ||
[ | ||
{ | ||
"fields": { | ||
"date": "2016-03-14T19:00:32.428Z", | ||
"content": "This is a test", | ||
"title": "Test news" | ||
}, | ||
"model": "newsfeed.news", | ||
"pk": 1 | ||
"fields": { | ||
"date": "2018-04-23T20:54:17.274Z" | ||
}, | ||
"model": "newsfeed.news", | ||
"pk": 1 | ||
}, | ||
{ | ||
"model": "newsfeed.newslanguageversion", | ||
"pk": 2, | ||
"fields": { | ||
"news": 1, | ||
"language": "en", | ||
"title": "Test news", | ||
"content": "This is a test" | ||
} | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,37 @@ | ||
from django import forms | ||
from django.conf import settings | ||
from django.forms import modelformset_factory | ||
from django.utils.translation import ugettext_lazy as _ | ||
|
||
from oioioi.newsfeed.models import News | ||
from oioioi.newsfeed.models import NewsLanguageVersion | ||
|
||
|
||
class NewsForm(forms.ModelForm): | ||
class NewsLanguageVersionForm(forms.ModelForm): | ||
class Meta(object): | ||
model = News | ||
fields = ['title', 'content'] | ||
model = NewsLanguageVersion | ||
fields = ['language', 'title', 'content', ] | ||
|
||
language = forms.ChoiceField( | ||
label=_("Language"), | ||
choices=settings.LANGUAGES, | ||
widget=forms.HiddenInput(), | ||
) | ||
|
||
title = forms.CharField( | ||
label=_("Title"), | ||
max_length=255, | ||
widget=forms.TextInput(attrs={'class': 'input-xxlarge'})) | ||
label=_("Title"), | ||
max_length=255, | ||
widget=forms.TextInput(attrs={'class': 'input-xxlarge'}), | ||
) | ||
|
||
content = forms.CharField( | ||
label=_("Content"), | ||
widget=forms.Textarea(attrs={'class': 'input-xxlarge', | ||
'rows': 10})) | ||
label=_("Content"), | ||
widget=forms.Textarea(attrs={'class': 'input-xxlarge', | ||
'rows': 10}), | ||
) | ||
|
||
|
||
NewsLanguageVersionFormset = modelformset_factory( | ||
NewsLanguageVersion, form=NewsLanguageVersionForm, | ||
extra=len(settings.LANGUAGES), min_num=1, max_num=len(settings.LANGUAGES), | ||
validate_min=True, validate_max=True, can_delete=True, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# -*- coding: utf-8 -*- | ||
# Generated by Django 1.9.13 on 2018-04-25 19:02 | ||
from __future__ import unicode_literals | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('newsfeed', '0001_initial'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='NewsLanguageVersion', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('language', models.CharField(max_length=6, verbose_name='language code')), | ||
('title', models.CharField(max_length=255, verbose_name='title')), | ||
('content', models.TextField(verbose_name='content')), | ||
('news', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='versions', to='newsfeed.News')), | ||
], | ||
), | ||
migrations.AlterField( | ||
model_name='news', | ||
name='content', | ||
field=models.TextField(blank=True, null=True, verbose_name='content'), | ||
), | ||
migrations.AlterField( | ||
model_name='news', | ||
name='title', | ||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='title'), | ||
), | ||
] |
44 changes: 44 additions & 0 deletions
44
oioioi/newsfeed/migrations/0003_news_data_to_newslanguageversion.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import unicode_literals | ||
|
||
from django.conf import settings | ||
from django.db import migrations | ||
|
||
|
||
def move_news_data_to_newslanguageversion(apps, schema_editor): | ||
News = apps.get_model('newsfeed', 'News') | ||
NewsLanguageVersion = apps.get_model('newsfeed', 'NewsLanguageVersion') | ||
|
||
for news in News.objects.all(): | ||
news_content = NewsLanguageVersion(news=news, language=settings.LANGUAGE_CODE, | ||
title=news.title, content=news.content) | ||
news_content.save() | ||
|
||
|
||
def reverse_news_data_migration(apps, schema_editor): | ||
News = apps.get_model('newsfeed', 'News') | ||
NewsLanguageVersion = apps.get_model('newsfeed', 'NewsLanguageVersion') | ||
|
||
for news in News.objects.all(): | ||
try: | ||
default_news_content = news.versions.get( | ||
language=settings.LANGUAGE_CODE) | ||
except NewsLanguageVersion.DoesNotExist: | ||
default_news_content = news.versions.first() | ||
|
||
if default_news_content is not None: | ||
news.title = default_news_content.title | ||
news.content = default_news_content.content | ||
news.save() | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('newsfeed', '0002_newslanguageversion'), | ||
] | ||
|
||
operations = [ | ||
migrations.RunPython(move_news_data_to_newslanguageversion, | ||
reverse_news_data_migration) | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# -*- coding: utf-8 -*- | ||
from __future__ import unicode_literals | ||
|
||
from django.db import migrations | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('newsfeed', '0003_news_data_to_newslanguageversion'), | ||
] | ||
|
||
operations = [ | ||
migrations.RemoveField( | ||
model_name='news', | ||
name='content', | ||
), | ||
migrations.RemoveField( | ||
model_name='news', | ||
name='title', | ||
), | ||
] |
Oops, something went wrong.