diff --git a/symposion/boxes/models.py b/symposion/boxes/models.py index d9e57bd7..65e38d7b 100644 --- a/symposion/boxes/models.py +++ b/symposion/boxes/models.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals from django.db import models from django.contrib.auth.models import User from django.utils.encoding import python_2_unicode_compatible +from django.utils.translation import ugettext_lazy as _ import reversion @@ -11,17 +12,17 @@ from markitup.fields import MarkupField @python_2_unicode_compatible class Box(models.Model): - label = models.CharField(max_length=100, db_index=True) + label = models.CharField(max_length=100, db_index=True, verbose_name=_("Label")) content = MarkupField(blank=True) - created_by = models.ForeignKey(User, related_name="boxes") - last_updated_by = models.ForeignKey(User, related_name="updated_boxes") + created_by = models.ForeignKey(User, related_name="boxes", verbose_name=_("Created by")) + last_updated_by = models.ForeignKey(User, related_name="updated_boxes", verbose_name=_("Last updated by")) def __str__(self): return self.label class Meta: - verbose_name_plural = "boxes" - + verbose_name = _("Box") + verbose_name_plural = _("Boxes") reversion.register(Box) diff --git a/symposion/cms/models.py b/symposion/cms/models.py index 1a5980a3..9c8ce003 100644 --- a/symposion/cms/models.py +++ b/symposion/cms/models.py @@ -40,6 +40,10 @@ class Page(models.Model): def __str__(self): return self.title + class Meta: + verbose_name = _("page") + verbose_name_plural = _("pages") + @models.permalink def get_absolute_url(self): return ("cms_page", [self.path]) diff --git a/symposion/conference/apps.py b/symposion/conference/apps.py index b9e64c13..45e19ffb 100644 --- a/symposion/conference/apps.py +++ b/symposion/conference/apps.py @@ -1,8 +1,9 @@ from __future__ import unicode_literals from django.apps import AppConfig +from django.utils.translation import ugettext_lazy as _ class ConferenceConfig(AppConfig): name = "symposion.conference" label = "symposion_conference" - verbose_name = "Symposion Conference" + verbose_name = _("Symposion Conference") diff --git a/symposion/conference/models.py b/symposion/conference/models.py index d5876ffd..ae6c1bea 100644 --- a/symposion/conference/models.py +++ b/symposion/conference/models.py @@ -15,11 +15,11 @@ class Conference(models.Model): the full conference for a specific year, e.g. US PyCon 2012. """ - title = models.CharField(_("title"), max_length=100) + title = models.CharField(_("Title"), max_length=100) # when the conference runs - start_date = models.DateField(_("start date"), null=True, blank=True) - end_date = models.DateField(_("end date"), null=True, blank=True) + start_date = models.DateField(_("Start date"), null=True, blank=True) + end_date = models.DateField(_("End date"), null=True, blank=True) # timezone the conference is in timezone = TimeZoneField(blank=True, verbose_name=_("timezone")) @@ -53,14 +53,14 @@ class Section(models.Model): scheduling process. """ - conference = models.ForeignKey(Conference, verbose_name=_("conference")) + conference = models.ForeignKey(Conference, verbose_name=_("Conference")) - name = models.CharField(_("name"), max_length=100) - slug = models.SlugField() + name = models.CharField(_("Name"), max_length=100) + slug = models.SlugField(verbose_name=_("Slug")) # when the section runs - start_date = models.DateField(_("start date"), null=True, blank=True) - end_date = models.DateField(_("end date"), null=True, blank=True) + start_date = models.DateField(_("Start date"), null=True, blank=True) + end_date = models.DateField(_("End date"), null=True, blank=True) def __str__(self): return "%s %s" % (self.conference, self.name) diff --git a/symposion/forms.py b/symposion/forms.py index 09fc5d4f..bdaf89ae 100644 --- a/symposion/forms.py +++ b/symposion/forms.py @@ -6,13 +6,14 @@ except ImportError: from django import forms import account.forms +from django.utils.translation import ugettext_lazy as _ class SignupForm(account.forms.SignupForm): - first_name = forms.CharField() - last_name = forms.CharField() - email_confirm = forms.EmailField(label="Confirm Email") + first_name = forms.CharField(label=_("First name")) + last_name = forms.CharField(label=_("Last name")) + email_confirm = forms.EmailField(label=_("Confirm Email")) def __init__(self, *args, **kwargs): super(SignupForm, self).__init__(*args, **kwargs) @@ -32,7 +33,7 @@ class SignupForm(account.forms.SignupForm): if email: if email != email_confirm: raise forms.ValidationError( - "Email address must match previously typed email address") + _("Email address must match previously typed email address")) return email_confirm diff --git a/symposion/proposals/actions.py b/symposion/proposals/actions.py index 5c747219..eeeb6289 100644 --- a/symposion/proposals/actions.py +++ b/symposion/proposals/actions.py @@ -2,10 +2,11 @@ from __future__ import unicode_literals import csv from django.http import HttpResponse +from django.utils.translation import ugettext_lazy as _ -def export_as_csv_action(description="Export selected objects as CSV file", - fields=None, exclude=None, header=True): +def export_as_csv_action(description=None, fields=None, exclude=None, + header=True): """ This function returns an export csv action 'fields' and 'exclude' work like in Django ModelForm @@ -32,5 +33,7 @@ def export_as_csv_action(description="Export selected objects as CSV file", writer.writerow( [unicode(getattr(obj, field)).encode("utf-8", "replace") for field in field_names]) return response + if description is None: + description = _("Export selected objects as CSV file") export_as_csv.short_description = description return export_as_csv diff --git a/symposion/proposals/apps.py b/symposion/proposals/apps.py index e0adc66d..613471ce 100644 --- a/symposion/proposals/apps.py +++ b/symposion/proposals/apps.py @@ -1,8 +1,9 @@ from __future__ import unicode_literals from django.apps import AppConfig +from django.utils.translation import ugettext_lazy as _ class ProposalsConfig(AppConfig): name = "symposion.proposals" label = "symposion_proposals" - verbose_name = "Symposion Proposals" + verbose_name = _("Symposion Proposals") diff --git a/symposion/proposals/forms.py b/symposion/proposals/forms.py index ff857a3c..8d48c409 100644 --- a/symposion/proposals/forms.py +++ b/symposion/proposals/forms.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals from django import forms from django.db.models import Q +from django.utils.translation import ugettext_lazy as _ from symposion.proposals.models import SupportingDocument # from markitup.widgets import MarkItUpWidget @@ -12,7 +13,7 @@ from symposion.proposals.models import SupportingDocument class AddSpeakerForm(forms.Form): email = forms.EmailField( - label="Email address of new speaker (use their email address, not yours)" + label=_("Email address of new speaker (use their email address, not yours)") ) def __init__(self, *args, **kwargs): @@ -27,7 +28,7 @@ class AddSpeakerForm(forms.Form): ).exists() if exists: raise forms.ValidationError( - "This email address has already been invited to your talk proposal" + _("This email address has already been invited to your talk proposal") ) return value diff --git a/symposion/proposals/models.py b/symposion/proposals/models.py index ab68bcec..e979f7a8 100644 --- a/symposion/proposals/models.py +++ b/symposion/proposals/models.py @@ -34,12 +34,12 @@ class ProposalSection(models.Model): * closed is NULL or False """ - section = models.OneToOneField(Section) + section = models.OneToOneField(Section, verbose_name=_("Section")) - start = models.DateTimeField(null=True, blank=True) - end = models.DateTimeField(null=True, blank=True) - closed = models.NullBooleanField() - published = models.NullBooleanField() + start = models.DateTimeField(null=True, blank=True, verbose_name=_("Start")) + end = models.DateTimeField(null=True, blank=True, verbose_name=_("End")) + closed = models.NullBooleanField(verbose_name=_("Closed")) + published = models.NullBooleanField(verbose_name=_("Published")) @classmethod def available(cls): @@ -71,10 +71,10 @@ class ProposalKind(models.Model): to distinguish the section as well as the kind. """ - section = models.ForeignKey(Section, related_name="proposal_kinds") + section = models.ForeignKey(Section, related_name="proposal_kinds", verbose_name=_("Section")) name = models.CharField(_("Name"), max_length=100) - slug = models.SlugField() + slug = models.SlugField(verbose_name=_("Slug")) def __str__(self): return self.name @@ -85,9 +85,9 @@ class ProposalBase(models.Model): objects = InheritanceManager() - kind = models.ForeignKey(ProposalKind) + kind = models.ForeignKey(ProposalKind, verbose_name=_("Kind")) - title = models.CharField(max_length=100) + title = models.CharField(max_length=100, verbose_name=_("Title")) description = models.TextField( _("Brief Description"), max_length=400, # @@@ need to enforce 400 in UI @@ -101,6 +101,7 @@ class ProposalBase(models.Model): "target='_blank'>Markdown.") ) additional_notes = MarkupField( + _("Addtional Notes"), blank=True, help_text=_("Anything else you'd like the program committee to know when making their " "selection: your past experience, etc. This is not made public. Edit using " @@ -110,8 +111,9 @@ class ProposalBase(models.Model): submitted = models.DateTimeField( default=now, editable=False, + verbose_name=_("Submitted") ) - speaker = models.ForeignKey(Speaker, related_name="proposals") + speaker = models.ForeignKey(Speaker, related_name="proposals", verbose_name=_("Speaker")) def additional_speaker_validator(self, a_speaker): if a_speaker.speaker.email == self.speaker.email: @@ -120,8 +122,9 @@ class ProposalBase(models.Model): raise ValidationError(_("%s has already been in speakers.") % a_speaker.speaker.email) additional_speakers = models.ManyToManyField(Speaker, through="AdditionalSpeaker", - blank=True, validators=[additional_speaker_validator]) - cancelled = models.BooleanField(default=False) + blank=True, verbose_name=_("Addtional speakers"), + validators=[additional_speaker_validator]) + cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled")) def can_edit(self): return True @@ -179,12 +182,14 @@ class AdditionalSpeaker(models.Model): (SPEAKING_STATUS_DECLINED, _("Declined")), ] - speaker = models.ForeignKey(Speaker) - proposalbase = models.ForeignKey(ProposalBase) - status = models.IntegerField(choices=SPEAKING_STATUS, default=SPEAKING_STATUS_PENDING) + speaker = models.ForeignKey(Speaker, verbose_name=_("Speaker")) + proposalbase = models.ForeignKey(ProposalBase, verbose_name=_("Proposalbase")) + status = models.IntegerField(choices=SPEAKING_STATUS, default=SPEAKING_STATUS_PENDING, verbose_name=_("Status")) class Meta: unique_together = ("speaker", "proposalbase") + verbose_name = _("Addtional speaker") + verbose_name_plural = _("Additional speakers") def __str__(self): if self.status is self.SPEAKING_STATUS_PENDING: @@ -203,14 +208,14 @@ def uuid_filename(instance, filename): class SupportingDocument(models.Model): - proposal = models.ForeignKey(ProposalBase, related_name="supporting_documents") + proposal = models.ForeignKey(ProposalBase, related_name="supporting_documents", verbose_name=_("Proposal")) - uploaded_by = models.ForeignKey(User) + uploaded_by = models.ForeignKey(User, verbose_name=_("Uploaded by")) - created_at = models.DateTimeField(default=now) + created_at = models.DateTimeField(default=now, verbose_name=_("Created at")) - file = models.FileField(upload_to=uuid_filename) - description = models.CharField(max_length=140) + file = models.FileField(upload_to=uuid_filename, verbose_name=_("File")) + description = models.CharField(max_length=140, verbose_name=_("Description")) def download_url(self): return reverse("proposal_document_download", diff --git a/symposion/proposals/views.py b/symposion/proposals/views.py index 28ce6f67..3259a3d3 100644 --- a/symposion/proposals/views.py +++ b/symposion/proposals/views.py @@ -88,7 +88,7 @@ def proposal_submit_kind(request, kind_slug): proposal.speaker = speaker_profile proposal.save() form.save_m2m() - messages.success(request, "Proposal submitted.") + messages.success(request, _("Proposal submitted.")) if "add-speakers" in request.POST: return redirect("proposal_speaker_manage", proposal.pk) return redirect("dashboard") diff --git a/symposion/reviews/apps.py b/symposion/reviews/apps.py index 38d419e7..4973fa43 100644 --- a/symposion/reviews/apps.py +++ b/symposion/reviews/apps.py @@ -1,8 +1,9 @@ from __future__ import unicode_literals from django.apps import AppConfig +from django.utils.translation import ugettext_lazy as _ class ReviewsConfig(AppConfig): name = "symposion.reviews" label = "symposion_reviews" - verbose_name = "Symposion Reviews" + verbose_name = _("Symposion Reviews") diff --git a/symposion/reviews/forms.py b/symposion/reviews/forms.py index 9d49a257..e4660cfb 100644 --- a/symposion/reviews/forms.py +++ b/symposion/reviews/forms.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals from django import forms +from django.utils.translation import ugettext_lazy as _ from markitup.widgets import MarkItUpWidget @@ -36,6 +37,7 @@ class SpeakerCommentForm(forms.ModelForm): class BulkPresentationForm(forms.Form): talk_ids = forms.CharField( + label=_("Talk ids"), max_length=500, - help_text="Provide a comma seperated list of talk ids to accept." + help_text=_("Provide a comma seperated list of talk ids to accept.") ) diff --git a/symposion/reviews/models.py b/symposion/reviews/models.py index 35ebd925..9957aa1f 100644 --- a/symposion/reviews/models.py +++ b/symposion/reviews/models.py @@ -8,6 +8,7 @@ from django.db.models import Q from django.db.models.signals import post_save from django.contrib.auth.models import User +from django.utils.translation import ugettext_lazy as _ from markitup.fields import MarkupField @@ -32,10 +33,10 @@ class Votes(object): MINUS_ONE = "−1" CHOICES = [ - (PLUS_ONE, u"+1 — Good proposal and I will argue for it to be accepted."), - (PLUS_ZERO, u"+0 — OK proposal, but I will not argue for it to be accepted."), - (MINUS_ZERO, u"−0 — Weak proposal, but I will not argue strongly against acceptance."), - (MINUS_ONE, u"−1 — Serious issues and I will argue to reject this proposal."), + (PLUS_ONE, _("+1 — Good proposal and I will argue for it to be accepted.")), + (PLUS_ZERO, _("+0 — OK proposal, but I will not argue for it to be accepted.")), + (MINUS_ZERO, _("−0 — Weak proposal, but I will not argue strongly against acceptance.")), + (MINUS_ONE, _("−1 — Serious issues and I will argue to reject this proposal.")), ] VOTES = Votes() @@ -48,18 +49,18 @@ class ReviewAssignment(models.Model): NUM_REVIEWERS = 3 ORIGIN_CHOICES = [ - (AUTO_ASSIGNED_INITIAL, "auto-assigned, initial"), - (OPT_IN, "opted-in"), - (AUTO_ASSIGNED_LATER, "auto-assigned, later"), + (AUTO_ASSIGNED_INITIAL, _("auto-assigned, initial")), + (OPT_IN, _("opted-in")), + (AUTO_ASSIGNED_LATER, _("auto-assigned, later")), ] - proposal = models.ForeignKey(ProposalBase) - user = models.ForeignKey(User) + proposal = models.ForeignKey(ProposalBase, verbose_name=_("Proposal")) + user = models.ForeignKey(User, verbose_name=_("User")) - origin = models.IntegerField(choices=ORIGIN_CHOICES) + origin = models.IntegerField(choices=ORIGIN_CHOICES, verbose_name=_("Origin")) - assigned_at = models.DateTimeField(default=datetime.now) - opted_out = models.BooleanField(default=False) + assigned_at = models.DateTimeField(default=datetime.now, verbose_name=_("Assigned at")) + opted_out = models.BooleanField(default=False, verbose_name=_("Opted out")) @classmethod def create_assignments(cls, proposal, origin=AUTO_ASSIGNED_INITIAL): @@ -93,27 +94,29 @@ class ReviewAssignment(models.Model): class ProposalMessage(models.Model): - proposal = models.ForeignKey(ProposalBase, related_name="messages") - user = models.ForeignKey(User) + proposal = models.ForeignKey(ProposalBase, related_name="messages", verbose_name=_("Proposal")) + user = models.ForeignKey(User, verbose_name=_("User")) - message = MarkupField() - submitted_at = models.DateTimeField(default=datetime.now, editable=False) + message = MarkupField(verbose_name=_("Message")) + submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at")) class Meta: ordering = ["submitted_at"] + verbose_name = _("proposal message") + verbose_name_plural = _("proposal messages") class Review(models.Model): VOTES = VOTES - proposal = models.ForeignKey(ProposalBase, related_name="reviews") - user = models.ForeignKey(User) + proposal = models.ForeignKey(ProposalBase, related_name="reviews", verbose_name=_("Proposal")) + user = models.ForeignKey(User, verbose_name=_("User")) # No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel # like some complicated encoding system. - vote = models.CharField(max_length=2, blank=True, choices=VOTES.CHOICES) - comment = MarkupField() - submitted_at = models.DateTimeField(default=datetime.now, editable=False) + vote = models.CharField(max_length=2, blank=True, choices=VOTES.CHOICES, verbose_name=_("Vote")) + comment = MarkupField(verbose_name=_("Comment")) + submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at")) def save(self, **kwargs): if self.vote: @@ -181,20 +184,26 @@ class Review(models.Model): def section(self): return self.proposal.kind.section.slug + class Meta: + verbose_name = _("review") + verbose_name_plural = _("reviews") + class LatestVote(models.Model): VOTES = VOTES - proposal = models.ForeignKey(ProposalBase, related_name="votes") - user = models.ForeignKey(User) + proposal = models.ForeignKey(ProposalBase, related_name="votes", verbose_name=_("Proposal")) + user = models.ForeignKey(User, verbose_name=_("User")) # No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel # like some complicated encoding system. - vote = models.CharField(max_length=2, choices=VOTES.CHOICES) - submitted_at = models.DateTimeField(default=datetime.now, editable=False) + vote = models.CharField(max_length=2, choices=VOTES.CHOICES, verbose_name=_("Vote")) + submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at")) class Meta: unique_together = [("proposal", "user")] + verbose_name = _("latest vote") + verbose_name_plural = _("latest votes") def css_class(self): return { @@ -206,25 +215,25 @@ class LatestVote(models.Model): class ProposalResult(models.Model): - proposal = models.OneToOneField(ProposalBase, related_name="result") - score = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.00")) - comment_count = models.PositiveIntegerField(default=0) - vote_count = models.PositiveIntegerField(default=0) - plus_one = models.PositiveIntegerField(default=0) - plus_zero = models.PositiveIntegerField(default=0) - minus_zero = models.PositiveIntegerField(default=0) - minus_one = models.PositiveIntegerField(default=0) + proposal = models.OneToOneField(ProposalBase, related_name="result", verbose_name=_("Proposal")) + score = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.00"), verbose_name=_("Score")) + comment_count = models.PositiveIntegerField(default=0, verbose_name=_("Comment count")) + vote_count = models.PositiveIntegerField(default=0, verbose_name=_("Vote count")) + plus_one = models.PositiveIntegerField(default=0, verbose_name=_("Plus one")) + plus_zero = models.PositiveIntegerField(default=0, verbose_name=_("Plus zero")) + minus_zero = models.PositiveIntegerField(default=0, verbose_name=_("Minus zero")) + minus_one = models.PositiveIntegerField(default=0, verbose_name=_("Minus one")) accepted = models.NullBooleanField(choices=[ (True, "accepted"), (False, "rejected"), (None, "undecided"), - ], default=None) + ], default=None, verbose_name=_("Accepted")) status = models.CharField(max_length=20, choices=[ - ("accepted", "accepted"), - ("rejected", "rejected"), - ("undecided", "undecided"), - ("standby", "standby"), - ], default="undecided") + ("accepted", _("accepted")), + ("rejected", _("rejected")), + ("undecided", _("undecided")), + ("standby", _("standby")), + ], default="undecided", verbose_name=_("Status")) @classmethod def full_calculate(cls): @@ -280,35 +289,47 @@ class ProposalResult(models.Model): model = self.__class__ model._default_manager.filter(pk=self.pk).update(score=ProposalScoreExpression()) + class Meta: + verbose_name = _("proposal_result") + verbose_name_plural = _("proposal_results") + class Comment(models.Model): - proposal = models.ForeignKey(ProposalBase, related_name="comments") - commenter = models.ForeignKey(User) - text = MarkupField() + proposal = models.ForeignKey(ProposalBase, related_name="comments", verbose_name=_("Proposal")) + commenter = models.ForeignKey(User, verbose_name=_("Commenter")) + text = MarkupField(verbose_name=_("Text")) # Or perhaps more accurately, can the user see this comment. - public = models.BooleanField(choices=[(True, "public"), (False, "private")], default=False) - commented_at = models.DateTimeField(default=datetime.now) + public = models.BooleanField(choices=[(True, _("public")), (False, _("private"))], default=False, verbose_name=_("Public")) + commented_at = models.DateTimeField(default=datetime.now, verbose_name=_("Commented at")) + + class Meta: + verbose_name = _("comment") + verbose_name_plural = _("comments") class NotificationTemplate(models.Model): - label = models.CharField(max_length=100) - from_address = models.EmailField() - subject = models.CharField(max_length=100) - body = models.TextField() + label = models.CharField(max_length=100, verbose_name=_("Label")) + from_address = models.EmailField(verbose_name=_("From address")) + subject = models.CharField(max_length=100, verbose_name=_("Subject")) + body = models.TextField(verbose_name=_("Body")) + + class Meta: + verbose_name = _("notification template") + verbose_name_plural = _("notification templates") class ResultNotification(models.Model): - proposal = models.ForeignKey(ProposalBase, related_name="notifications") + proposal = models.ForeignKey(ProposalBase, related_name="notifications", verbose_name=_("Proposal")) template = models.ForeignKey(NotificationTemplate, null=True, blank=True, - on_delete=models.SET_NULL) - timestamp = models.DateTimeField(default=datetime.now) - to_address = models.EmailField() - from_address = models.EmailField() - subject = models.CharField(max_length=100) - body = models.TextField() + on_delete=models.SET_NULL, verbose_name=_("Template")) + timestamp = models.DateTimeField(default=datetime.now, verbose_name=_("Timestamp")) + to_address = models.EmailField(verbose_name=_("To address")) + from_address = models.EmailField(verbose_name=_("From address")) + subject = models.CharField(max_length=100, verbose_name=_("Subject")) + body = models.TextField(verbose_name=_("Body")) def recipients(self): for speaker in self.proposal.speakers(): diff --git a/symposion/schedule/models.py b/symposion/schedule/models.py index 8792b47f..22aad378 100644 --- a/symposion/schedule/models.py +++ b/symposion/schedule/models.py @@ -1,10 +1,12 @@ from __future__ import unicode_literals + import datetime from django.core.exceptions import ObjectDoesNotExist from django.contrib.auth.models import User from django.db import models from django.utils.encoding import python_2_unicode_compatible +from django.utils.translation import ugettext_lazy as _ from markitup.fields import MarkupField @@ -16,22 +18,24 @@ from symposion.speakers.models import Speaker @python_2_unicode_compatible class Schedule(models.Model): - section = models.OneToOneField(Section) - published = models.BooleanField(default=True) - hidden = models.BooleanField("Hide schedule from overall conference view", default=False) + section = models.OneToOneField(Section, verbose_name=_("Section")) + published = models.BooleanField(default=True, verbose_name=_("Published")) + hidden = models.BooleanField(_("Hide schedule from overall conference view"), default=False) def __str__(self): return "%s Schedule" % self.section class Meta: ordering = ["section"] + verbose_name = _('Schedule') + verbose_name_plural = _('Schedules') @python_2_unicode_compatible class Day(models.Model): - schedule = models.ForeignKey(Schedule) - date = models.DateField() + schedule = models.ForeignKey(Schedule, verbose_name=_("Schedule")) + date = models.DateField(verbose_name=_("Date")) def __str__(self): return "%s" % self.date @@ -39,18 +43,24 @@ class Day(models.Model): class Meta: unique_together = [("schedule", "date")] ordering = ["date"] + verbose_name = _("date") + verbose_name_plural = _("dates") @python_2_unicode_compatible class Room(models.Model): - schedule = models.ForeignKey(Schedule) - name = models.CharField(max_length=65) - order = models.PositiveIntegerField() + schedule = models.ForeignKey(Schedule, verbose_name=_("Schedule")) + name = models.CharField(max_length=65, verbose_name=_("Name")) + order = models.PositiveIntegerField(verbose_name=_("Order")) def __str__(self): return self.name + class Meta: + verbose_name = _("Room") + verbose_name_plural = _("Rooms") + @python_2_unicode_compatible class SlotKind(models.Model): @@ -59,21 +69,25 @@ class SlotKind(models.Model): break, lunch, or X-minute talk. """ - schedule = models.ForeignKey(Schedule) - label = models.CharField(max_length=50) + schedule = models.ForeignKey(Schedule, verbose_name=_("schedule")) + label = models.CharField(max_length=50, verbose_name=_("Label")) def __str__(self): return self.label + class Meta: + verbose_name = _("Slot kind") + verbose_name_plural = _("Slot kinds") + @python_2_unicode_compatible class Slot(models.Model): - day = models.ForeignKey(Day) - kind = models.ForeignKey(SlotKind) - start = models.TimeField() - end = models.TimeField() - content_override = MarkupField(blank=True) + day = models.ForeignKey(Day, verbose_name=_("Day")) + kind = models.ForeignKey(SlotKind, verbose_name=_("Kind")) + start = models.TimeField(verbose_name=_("Start")) + end = models.TimeField(verbose_name=_("End")) + content_override = MarkupField(blank=True, verbose_name=_("Content override")) def assign(self, content): """ @@ -137,6 +151,8 @@ class Slot(models.Model): class Meta: ordering = ["day", "start", "end"] + verbose_name = _("slot") + verbose_name_plural = _("slots") @python_2_unicode_compatible @@ -145,8 +161,8 @@ class SlotRoom(models.Model): Links a slot with a room. """ - slot = models.ForeignKey(Slot) - room = models.ForeignKey(Room) + slot = models.ForeignKey(Slot, verbose_name=_("Slot")) + room = models.ForeignKey(Room, verbose_name=_("Room")) def __str__(self): return "%s %s" % (self.room, self.slot) @@ -154,21 +170,23 @@ class SlotRoom(models.Model): class Meta: unique_together = [("slot", "room")] ordering = ["slot", "room__order"] + verbose_name = _("Slot room") + verbose_name_plural = _("Slot rooms") @python_2_unicode_compatible class Presentation(models.Model): - slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr") - title = models.CharField(max_length=100) - description = MarkupField() - abstract = MarkupField() - speaker = models.ForeignKey(Speaker, related_name="presentations") + slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr", verbose_name=_("Slot")) + title = models.CharField(max_length=100, verbose_name=_("Title")) + description = MarkupField(verbose_name=_("Description")) + abstract = MarkupField(verbose_name=_("Abstract")) + speaker = models.ForeignKey(Speaker, related_name="presentations", verbose_name=_("Speaker")) additional_speakers = models.ManyToManyField(Speaker, related_name="copresentations", - blank=True) - cancelled = models.BooleanField(default=False) - proposal_base = models.OneToOneField(ProposalBase, related_name="presentation") - section = models.ForeignKey(Section, related_name="presentations") + blank=True, verbose_name=_("Additional speakers")) + cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled")) + proposal_base = models.OneToOneField(ProposalBase, related_name="presentation", verbose_name=_("Proposal base")) + section = models.ForeignKey(Section, related_name="presentations", verbose_name=_("Section")) @property def number(self): @@ -191,13 +209,15 @@ class Presentation(models.Model): class Meta: ordering = ["slot"] + verbose_name = _("presentation") + verbose_name_plural = _("presentations") @python_2_unicode_compatible class Session(models.Model): - day = models.ForeignKey(Day, related_name="sessions") - slots = models.ManyToManyField(Slot, related_name="sessions") + day = models.ForeignKey(Day, related_name="sessions", verbose_name=_("Day")) + slots = models.ManyToManyField(Slot, related_name="sessions", verbose_name=_("Slots")) def sorted_slots(self): return self.slots.order_by("start") @@ -227,6 +247,10 @@ class Session(models.Model): ) return "" + class Meta: + verbose_name = _("Session") + verbose_name_plural = _("Sessions") + @python_2_unicode_compatible class SessionRole(models.Model): @@ -235,19 +259,21 @@ class SessionRole(models.Model): SESSION_ROLE_RUNNER = 2 SESSION_ROLE_TYPES = [ - (SESSION_ROLE_CHAIR, "Session Chair"), - (SESSION_ROLE_RUNNER, "Session Runner"), + (SESSION_ROLE_CHAIR, _("Session Chair")), + (SESSION_ROLE_RUNNER, _("Session Runner")), ] - session = models.ForeignKey(Session) - user = models.ForeignKey(User) - role = models.IntegerField(choices=SESSION_ROLE_TYPES) - status = models.NullBooleanField() + session = models.ForeignKey(Session, verbose_name=_("Session")) + user = models.ForeignKey(User, verbose_name=_("User")) + role = models.IntegerField(choices=SESSION_ROLE_TYPES, verbose_name=_("Role")) + status = models.NullBooleanField(verbose_name=_("Status")) submitted = models.DateTimeField(default=datetime.datetime.now) class Meta: unique_together = [("session", "user", "role")] + verbose_name = _("Session role") + verbose_name_plural = _("Session roles") def __str__(self): return "%s %s: %s" % (self.user, self.session, diff --git a/symposion/speakers/apps.py b/symposion/speakers/apps.py index afcad95a..bd6024ba 100644 --- a/symposion/speakers/apps.py +++ b/symposion/speakers/apps.py @@ -1,8 +1,9 @@ from __future__ import unicode_literals from django.apps import AppConfig +from django.utils.translation import ugettext_lazy as _ class SpeakersConfig(AppConfig): name = "symposion.speakers" label = "symposion_speakers" - verbose_name = "Symposion Speakers" + verbose_name = _("Symposion Speakers") diff --git a/symposion/speakers/models.py b/symposion/speakers/models.py index 0e272db8..e7942b47 100644 --- a/symposion/speakers/models.py +++ b/symposion/speakers/models.py @@ -1,9 +1,11 @@ from __future__ import unicode_literals -import datetime -from django.utils.encoding import python_2_unicode_compatible -from django.db import models +import datetime + from django.core.urlresolvers import reverse +from django.db import models +from django.utils.encoding import python_2_unicode_compatible +from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User @@ -18,24 +20,28 @@ class Speaker(models.Model): (2, "Two") ] - user = models.OneToOneField(User, null=True, related_name="speaker_profile") - name = models.CharField(max_length=100, help_text=("As you would like it to appear in the " - "conference program.")) - biography = MarkupField(blank=True, help_text=("A little bit about you. Edit using " - "" - "Markdown.")) - photo = models.ImageField(upload_to="speaker_photos", blank=True) - annotation = models.TextField() # staff only - invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True) - invite_token = models.CharField(max_length=40, db_index=True) + user = models.OneToOneField(User, null=True, related_name="speaker_profile", verbose_name=_("User")) + name = models.CharField(verbose_name=_("Name"), max_length=100, + help_text=_("As you would like it to appear in the" + " conference program.")) + biography = MarkupField(blank=True, help_text=_("A little bit about you. Edit using " + "" + "Markdown."), verbose_name=_("Biography")) + photo = models.ImageField(upload_to="speaker_photos", blank=True, verbose_name=_("Photo")) + annotation = models.TextField(verbose_name=_("Annotation")) # staff only + invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True, verbose_name=_("Invite_email")) + invite_token = models.CharField(max_length=40, db_index=True, verbose_name=_("Invite token")) created = models.DateTimeField( default=datetime.datetime.now, - editable=False + editable=False, + verbose_name=_("Created") ) class Meta: ordering = ['name'] + verbose_name = _("Speaker") + verbose_name_plural = _("Speakers") def __str__(self): if self.user: diff --git a/symposion/speakers/views.py b/symposion/speakers/views.py index 12e88607..5fa1c45b 100644 --- a/symposion/speakers/views.py +++ b/symposion/speakers/views.py @@ -6,6 +6,7 @@ from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User +from django.utils.translation import ugettext_lazy as _ from symposion.proposals.models import ProposalBase from symposion.speakers.forms import SpeakerForm @@ -34,7 +35,7 @@ def speaker_create(request): if not found: speaker.invite_email = None speaker.save() - messages.success(request, "Speaker profile created.") + messages.success(request, _("Speaker profile created.")) return redirect("dashboard") else: form = SpeakerForm(initial={"name": request.user.get_full_name()}) @@ -62,7 +63,7 @@ def speaker_create_staff(request, pk): speaker = form.save(commit=False) speaker.user = user speaker.save() - messages.success(request, "Speaker profile created.") + messages.success(request, _("Speaker profile created.")) return redirect("user_list") else: form = SpeakerForm(initial={"name": user.get_full_name()}) @@ -89,8 +90,8 @@ def speaker_create_token(request, token): ).update( speaker=existing_speaker ) - messages.info(request, ("You have been associated with all pending " - "talk proposals")) + messages.info(request, _("You have been associated with all pending " + "talk proposals")) return redirect("dashboard") else: if not request.user.is_authenticated(): diff --git a/symposion/sponsorship/admin.py b/symposion/sponsorship/admin.py index 61080171..39f66f80 100644 --- a/symposion/sponsorship/admin.py +++ b/symposion/sponsorship/admin.py @@ -69,9 +69,9 @@ class SponsorAdmin(admin.ModelAdmin): # @@@ kinda ugly but using choices= on NullBooleanField is broken form = super(SponsorAdmin, self).get_form(*args, **kwargs) form.base_fields["active"].widget.choices = [ - (u"1", _("unreviewed")), - (u"2", _("approved")), - (u"3", _("rejected")) + ("1", _("unreviewed")), + ("2", _("approved")), + ("3", _("rejected")) ] return form diff --git a/symposion/sponsorship/apps.py b/symposion/sponsorship/apps.py index 80bf19d1..92ee49cd 100644 --- a/symposion/sponsorship/apps.py +++ b/symposion/sponsorship/apps.py @@ -1,7 +1,9 @@ +from __future__ import unicode_literals from django.apps import AppConfig +from django.utils.translation import ugettext_lazy as _ class SponsorshipConfig(AppConfig): name = "symposion.sponsorship" label = "symposion_sponsorship" - verbose_name = "Symposion Sponsorship" + verbose_name = _("Symposion Sponsorship") diff --git a/symposion/sponsorship/forms.py b/symposion/sponsorship/forms.py index edde8bd1..1ca959a5 100644 --- a/symposion/sponsorship/forms.py +++ b/symposion/sponsorship/forms.py @@ -3,6 +3,7 @@ from django import forms from django.forms.models import inlineformset_factory, BaseInlineFormSet from django.contrib.admin.widgets import AdminFileWidget +from django.utils.translation import ugettext_lazy as _ from symposion.sponsorship.models import Sponsor, SponsorBenefit @@ -65,7 +66,7 @@ class SponsorBenefitsInlineFormSet(BaseInlineFormSet): # provide word limit as help_text if form.instance.benefit.type == "text" and form.instance.max_words: - form.fields[field].help_text = u"maximum %s words" % form.instance.max_words + form.fields[field].help_text = _("maximum %s words") % form.instance.max_words # use admin file widget that shows currently uploaded file if field == "upload": diff --git a/symposion/sponsorship/models.py b/symposion/sponsorship/models.py index 02bacd69..20d4de09 100644 --- a/symposion/sponsorship/models.py +++ b/symposion/sponsorship/models.py @@ -48,16 +48,16 @@ BENEFITS = [ @python_2_unicode_compatible class SponsorLevel(models.Model): - conference = models.ForeignKey(Conference, verbose_name=_("conference")) - name = models.CharField(_("name"), max_length=100) - order = models.IntegerField(_("order"), default=0) - cost = models.PositiveIntegerField(_("cost")) - description = models.TextField(_("description"), blank=True, help_text=_("This is private.")) + conference = models.ForeignKey(Conference, verbose_name=_("Conference")) + name = models.CharField(_("Name"), max_length=100) + order = models.IntegerField(_("Order"), default=0) + cost = models.PositiveIntegerField(_("Cost")) + description = models.TextField(_("Description"), blank=True, help_text=_("This is private.")) class Meta: ordering = ["conference", "order"] - verbose_name = _("sponsor level") - verbose_name_plural = _("sponsor levels") + verbose_name = _("Sponsor level") + verbose_name_plural = _("Sponsor levels") def __str__(self): return "%s %s" % (self.conference, self.name) @@ -69,22 +69,22 @@ class SponsorLevel(models.Model): @python_2_unicode_compatible class Sponsor(models.Model): - applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), + applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("Applicant"), null=True) name = models.CharField(_("Sponsor Name"), max_length=100) display_url = models.URLField(_("display URL"), blank=True) - external_url = models.URLField(_("external URL")) - annotation = models.TextField(_("annotation"), blank=True) + external_url = models.URLField(_("External URL")) + annotation = models.TextField(_("Annotation"), blank=True) contact_name = models.CharField(_("Contact Name"), max_length=100) - contact_email = models.EmailField(_(u"Contact Email")) + contact_email = models.EmailField(_("Contact Email")) level = models.ForeignKey(SponsorLevel, verbose_name=_("level")) added = models.DateTimeField(_("added"), default=datetime.datetime.now) active = models.BooleanField(_("active"), default=False) # Denormalization (this assumes only one logo) sponsor_logo = models.ForeignKey("SponsorBenefit", related_name="+", null=True, blank=True, - editable=False) + editable=False, verbose_name=_("Sponsor logo")) # Whether things are complete # True = complete, False = incomplate, Null = n/a for this sponsor level @@ -99,8 +99,8 @@ class Sponsor(models.Model): return self.name class Meta: - verbose_name = _("sponsor") - verbose_name_plural = _("sponsors") + verbose_name = _("Sponsor") + verbose_name_plural = _("Sponsors") ordering = ['name'] def save(self, *args, **kwargs): @@ -213,12 +213,12 @@ post_save.connect(_check_level_change, sender=Sponsor) BENEFIT_TYPE_CHOICES = [ - ("text", "Text"), - ("richtext", "Rich Text"), - ("file", "File"), - ("weblogo", "Web Logo"), - ("simple", "Simple"), - ("option", "Option") + ("text", _("Text")), + ("file", _("File")), + ("richtext", _("Rich Text")), + ("weblogo", _("Web Logo")), + ("simple", _("Simple")), + ("option", _("Option")) ] CONTENT_TYPE_CHOICES = [ @@ -231,10 +231,10 @@ CONTENT_TYPE_CHOICES = [ @python_2_unicode_compatible class Benefit(models.Model): - name = models.CharField(_("name"), max_length=100) - description = models.TextField(_("description"), blank=True) - type = models.CharField(_("type"), choices=BENEFIT_TYPE_CHOICES, - max_length=10, default="simple") + name = models.CharField(_("Name"), max_length=100) + description = models.TextField(_("Description"), blank=True) + type = models.CharField(_("Type"), choices=BENEFIT_TYPE_CHOICES, max_length=10, + default="simple") content_type = models.CharField(_("content type"), choices=CONTENT_TYPE_CHOICES, max_length=20, default="simple") @@ -245,15 +245,17 @@ class Benefit(models.Model): @python_2_unicode_compatible class BenefitLevel(models.Model): - benefit = models.ForeignKey(Benefit, related_name="benefit_levels", verbose_name=_("benefit")) - level = models.ForeignKey(SponsorLevel, related_name="benefit_levels", verbose_name=_("level")) + benefit = models.ForeignKey(Benefit, related_name="benefit_levels", verbose_name=_("Benefit")) + level = models.ForeignKey(SponsorLevel, related_name="benefit_levels", verbose_name=_("Level")) # default limits for this benefit at given level - max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True) - other_limits = models.CharField(_("other limits"), max_length=200, blank=True) + max_words = models.PositiveIntegerField(_("Max words"), blank=True, null=True) + other_limits = models.CharField(_("Other limits"), max_length=200, blank=True) class Meta: ordering = ["level"] + verbose_name = _("Benefit level") + verbose_name_plural = _("Benefit levels") def __str__(self): return "%s - %s" % (self.level, self.benefit) @@ -262,18 +264,18 @@ class BenefitLevel(models.Model): @python_2_unicode_compatible class SponsorBenefit(models.Model): - sponsor = models.ForeignKey(Sponsor, related_name="sponsor_benefits", verbose_name=_("sponsor")) - benefit = models.ForeignKey(Benefit, related_name="sponsor_benefits", verbose_name=_("benefit")) - active = models.BooleanField(default=True) + sponsor = models.ForeignKey(Sponsor, related_name="sponsor_benefits", verbose_name=_("Sponsor")) + benefit = models.ForeignKey(Benefit, related_name="sponsor_benefits", verbose_name=_("Benefit")) + active = models.BooleanField(default=True, verbose_name=_("Active")) # Limits: will initially be set to defaults from corresponding BenefitLevel - max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True) - other_limits = models.CharField(_("other limits"), max_length=200, blank=True) + max_words = models.PositiveIntegerField(_("Max words"), blank=True, null=True) + other_limits = models.CharField(_("Other limits"), max_length=200, blank=True) # Data: zero or one of these fields will be used, depending on the # type of the Benefit (text, file, or simple) - text = models.TextField(_("text"), blank=True) - upload = models.FileField(_("file"), blank=True, upload_to="sponsor_files") + text = models.TextField(_("Text"), blank=True) + upload = models.FileField(_("File"), blank=True, upload_to="sponsor_files") # Whether any assets required from the sponsor have been provided # (e.g. a logo file for a Web logo benefit). @@ -281,6 +283,8 @@ class SponsorBenefit(models.Model): class Meta: ordering = ["-active"] + verbose_name = _("Sponsor benefit") + verbose_name_plural = _("Sponsor benefits") def __str__(self): return "%s - %s (%s)" % (self.sponsor, self.benefit, self.benefit_type) @@ -296,8 +300,8 @@ class SponsorBenefit(models.Model): num_words = len(self.text.split()) if self.max_words and num_words > self.max_words: raise ValidationError( - "Sponsorship level only allows for %s words, you provided %d." % ( - self.max_words, num_words)) + _("Sponsorship level only allows for %(word)s words, you provided %(num)d.") % { + "word": self.max_words, "num": num_words}) def data_fields(self): """ diff --git a/symposion/sponsorship/views.py b/symposion/sponsorship/views.py index 68dcf5a1..1fa5cf2b 100644 --- a/symposion/sponsorship/views.py +++ b/symposion/sponsorship/views.py @@ -7,16 +7,14 @@ import time from zipfile import ZipFile, ZipInfo from django.conf import settings - +from django.contrib import messages +from django.contrib.admin.views.decorators import staff_member_required +from django.contrib.auth.decorators import login_required from django.http import Http404, HttpResponse from django.shortcuts import render_to_response, redirect, get_object_or_404 from django.template import RequestContext from django.utils.translation import ugettext_lazy as _ -from django.contrib import messages -from django.contrib.admin.views.decorators import staff_member_required -from django.contrib.auth.decorators import login_required - from symposion.sponsorship.forms import SponsorApplicationForm, \ SponsorDetailsForm, SponsorBenefitsFormSet from symposion.sponsorship.models import Benefit, Sponsor, SponsorBenefit, \ @@ -91,7 +89,7 @@ def sponsor_detail(request, pk): form.save() formset.save() - messages.success(request, "Sponsorship details have been updated") + messages.success(request, _("Sponsorship details have been updated")) return redirect("dashboard") else: diff --git a/symposion/teams/forms.py b/symposion/teams/forms.py index 579c08cf..aea42279 100644 --- a/symposion/teams/forms.py +++ b/symposion/teams/forms.py @@ -3,6 +3,7 @@ from django import forms from django.utils.html import escape from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User @@ -11,8 +12,9 @@ from symposion.teams.models import Membership class TeamInvitationForm(forms.Form): - email = forms.EmailField(help_text=("email address must be that of an account on this " - "conference site")) + email = forms.EmailField(label=_("Email"), + help_text=_("email address must be that of an account on this " + "conference site")) def __init__(self, *args, **kwargs): self.team = kwargs.pop("team") @@ -23,7 +25,7 @@ class TeamInvitationForm(forms.Form): email = cleaned_data.get("email") if email is None: - raise forms.ValidationError("valid email address required") + raise forms.ValidationError(_("valid email address required")) try: user = User.objects.get(email=email) @@ -31,16 +33,16 @@ class TeamInvitationForm(forms.Form): # eventually we can invite them but for now assume they are # already on the site raise forms.ValidationError( - mark_safe("no account with email address %s found on this conference " - "site" % escape(email))) + mark_safe(_("no account with email address %s found on this conference " + "site") % escape(email))) state = self.team.get_state_for_user(user) if state in ["member", "manager"]: - raise forms.ValidationError("user already in team") + raise forms.ValidationError(_("user already in team")) if state in ["invited"]: - raise forms.ValidationError("user already invited to team") + raise forms.ValidationError(_("user already invited to team")) self.user = user self.state = state diff --git a/symposion/teams/models.py b/symposion/teams/models.py index 6e783d2e..ec4d5e45 100644 --- a/symposion/teams/models.py +++ b/symposion/teams/models.py @@ -1,37 +1,44 @@ from __future__ import unicode_literals + import datetime from django.db import models +from django.utils.encoding import python_2_unicode_compatible +from django.utils.translation import ugettext_lazy as _ + +from django.contrib.auth.models import Permission, User import reversion -from django.contrib.auth.models import Permission, User -from django.utils.encoding import python_2_unicode_compatible - TEAM_ACCESS_CHOICES = [ - ("open", "open"), - ("application", "by application"), - ("invitation", "by invitation") + ("open", _("open")), + ("application", _("by application")), + ("invitation", _("by invitation")) ] @python_2_unicode_compatible class Team(models.Model): - slug = models.SlugField(unique=True) - name = models.CharField(max_length=100) - description = models.TextField(blank=True) - access = models.CharField(max_length=20, choices=TEAM_ACCESS_CHOICES) + slug = models.SlugField(unique=True, verbose_name=_("Slug")) + name = models.CharField(max_length=100, verbose_name=_("Name")) + description = models.TextField(blank=True, verbose_name=_("Description")) + access = models.CharField(max_length=20, choices=TEAM_ACCESS_CHOICES, + verbose_name=_("Access")) # member permissions - permissions = models.ManyToManyField(Permission, blank=True, related_name="member_teams") + permissions = models.ManyToManyField(Permission, blank=True, + related_name="member_teams", + verbose_name=_("Permissions")) # manager permissions manager_permissions = models.ManyToManyField(Permission, blank=True, - related_name="manager_teams") + related_name="manager_teams", + verbose_name=_("Manager permissions")) - created = models.DateTimeField(default=datetime.datetime.now, editable=False) + created = models.DateTimeField(default=datetime.datetime.now, + editable=False, verbose_name=_("Created")) @models.permalink def get_absolute_url(self): @@ -58,23 +65,32 @@ class Team(models.Model): def managers(self): return self.memberships.filter(state="manager") + class Meta: + verbose_name = _('Team') + verbose_name_plural = _('Teams') MEMBERSHIP_STATE_CHOICES = [ - ("applied", "applied"), - ("invited", "invited"), - ("declined", "declined"), - ("rejected", "rejected"), - ("member", "member"), - ("manager", "manager"), + ("applied", _("applied")), + ("invited", _("invited")), + ("declined", _("declined")), + ("rejected", _("rejected")), + ("member", _("member")), + ("manager", _("manager")), ] class Membership(models.Model): - user = models.ForeignKey(User, related_name="memberships") - team = models.ForeignKey(Team, related_name="memberships") - state = models.CharField(max_length=20, choices=MEMBERSHIP_STATE_CHOICES) - message = models.TextField(blank=True) + user = models.ForeignKey(User, related_name="memberships", + verbose_name=_("User")) + team = models.ForeignKey(Team, related_name="memberships", + verbose_name=_("Team")) + state = models.CharField(max_length=20, choices=MEMBERSHIP_STATE_CHOICES, + verbose_name=_("State")) + message = models.TextField(blank=True, verbose_name=_("Message")) + class Meta: + verbose_name = _("Membership") + verbose_name_plural = _("Memberships") reversion.register(Membership) diff --git a/symposion/teams/views.py b/symposion/teams/views.py index 83e26d3c..3a245a84 100644 --- a/symposion/teams/views.py +++ b/symposion/teams/views.py @@ -6,6 +6,7 @@ from django.contrib.auth.decorators import login_required from django.contrib import messages from symposion.utils.mail import send_email +from django.utils.translation import ugettext_lazy as _ from symposion.teams.forms import TeamInvitationForm from symposion.teams.models import Team, Membership @@ -67,7 +68,7 @@ def team_detail(request, slug): if form.is_valid(): form.invite() send_email([form.user.email], "teams_user_invited", context={"team": team}) - messages.success(request, "Invitation created.") + messages.success(request, _("Invitation created.")) return redirect("team_detail", slug=slug) else: form = TeamInvitationForm(team=team) @@ -95,7 +96,7 @@ def team_join(request, slug): membership, created = Membership.objects.get_or_create(team=team, user=request.user) membership.state = "member" membership.save() - messages.success(request, "Joined team.") + messages.success(request, _("Joined team.")) return redirect("team_detail", slug=slug) else: return redirect("team_detail", slug=slug) @@ -111,7 +112,7 @@ def team_leave(request, slug): if can_leave(team, request.user) and request.method == "POST": membership = Membership.objects.get(team=team, user=request.user) membership.delete() - messages.success(request, "Left team.") + messages.success(request, _("Left team.")) return redirect("dashboard") else: return redirect("team_detail", slug=slug) @@ -133,7 +134,7 @@ def team_apply(request, slug): "team": team, "user": request.user }) - messages.success(request, "Applied to join team.") + messages.success(request, _("Applied to join team.")) return redirect("team_detail", slug=slug) else: return redirect("team_detail", slug=slug) @@ -149,7 +150,7 @@ def team_promote(request, pk): if membership.state == "member": membership.state = "manager" membership.save() - messages.success(request, "Promoted to manager.") + messages.success(request, _("Promoted to manager.")) return redirect("team_detail", slug=membership.team.slug) @@ -163,7 +164,7 @@ def team_demote(request, pk): if membership.state == "manager": membership.state = "member" membership.save() - messages.success(request, "Demoted from manager.") + messages.success(request, _("Demoted from manager.")) return redirect("team_detail", slug=membership.team.slug) @@ -177,7 +178,7 @@ def team_accept(request, pk): if membership.state == "applied": membership.state = "member" membership.save() - messages.success(request, "Accepted application.") + messages.success(request, _("Accepted application.")) return redirect("team_detail", slug=membership.team.slug) @@ -191,5 +192,5 @@ def team_reject(request, pk): if membership.state == "applied": membership.state = "rejected" membership.save() - messages.success(request, "Rejected application.") + messages.success(request, _("Rejected application.")) return redirect("team_detail", slug=membership.team.slug)