Skip to content
Open
5 changes: 3 additions & 2 deletions hypha/addressfield/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _

from .widgets import AddressWidget

Expand Down Expand Up @@ -49,7 +50,7 @@ def clean(self, value, **kwargs):
try:
country_data = self.data[country]
except KeyError:
raise ValidationError("Invalid country selected") from None
raise ValidationError(_("Invalid country selected")) from None

fields = flatten_data(country_data["fields"])

Expand All @@ -59,7 +60,7 @@ def clean(self, value, **kwargs):
if missing_fields:
missing_field_name = [fields[field]["label"] for field in missing_fields]
raise ValidationError(
"Please provide data for: {}".format(", ".join(missing_field_name))
_("Please provide data for: {}").format(", ".join(missing_field_name))
)

return super().clean(value, **kwargs)
Expand Down
4 changes: 2 additions & 2 deletions hypha/apply/activity/adapters/activity_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,9 @@ def handle_report_frequency(self, config, **kwargs):

def handle_skipped_report(self, report, **kwargs):
if report.skipped:
return "Skipped a Report"
return _("Skipped a Report")
else:
return "Marked a Report as required"
return _("Marked a Report as required")

def handle_update_invoice_status(self, invoice, **kwargs):
base_message = _("Updated Invoice status to: {invoice_status}.")
Expand Down
9 changes: 6 additions & 3 deletions hypha/apply/activity/adapters/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.conf import settings
from django.contrib import messages
from django.utils.translation import gettext as _

from hypha.apply.activity.options import MESSAGES

Expand Down Expand Up @@ -192,11 +193,13 @@ def process_send(

if not settings.SEND_MESSAGES:
if recipient:
debug_message = "{} [to: {}]: {}".format(
self.adapter_type, recipient, message
debug_message = _("{adapter} [to: {recipient}]: {message}").format(
adapter=self.adapter_type, recipient=recipient, message=message
)
else:
debug_message = "{}: {}".format(self.adapter_type, message)
debug_message = _("{adapter}: {message}").format(
adapter=self.adapter_type, message=message
)
messages.add_message(request, messages.DEBUG, debug_message)

def create_logs(self, message, recipient, *events):
Expand Down
8 changes: 5 additions & 3 deletions hypha/apply/activity/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ class Meta:
"assign_to",
)
labels = {
"visibility": "Visible to",
"message": "Message",
"visibility": _("Visible to"),
"message": _("Message"),
}
help_texts = {
"visibility": "Select a relevant user role. Staff can view every comment."
"visibility": _(
"Select a relevant user role. Staff can view every comment."
)
}
widgets = {
"visibility": forms.RadioSelect(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Generated by Django 5.2.12 on 2026-03-31 09:50

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("activity", "0088_activity_deleted"),
]

operations = [
migrations.AlterModelOptions(
name="activity",
options={
"base_manager_name": "objects",
"ordering": ["-timestamp"],
"verbose_name": "activity",
"verbose_name_plural": "activities",
},
),
migrations.AlterModelOptions(
name="activityattachment",
options={
"verbose_name": "activity attachment",
"verbose_name_plural": "activity attachments",
},
),
migrations.AlterModelOptions(
name="event",
options={"verbose_name": "event", "verbose_name_plural": "events"},
),
migrations.AlterModelOptions(
name="message",
options={"verbose_name": "message", "verbose_name_plural": "messages"},
),
migrations.AlterField(
model_name="activity",
name="message",
field=models.TextField(verbose_name="message"),
),
migrations.AlterField(
model_name="activity",
name="visibility",
field=models.CharField(
choices=[
("applicant", "Applicants"),
("team", "Staff only"),
("reviewers", "Reviewers"),
("partners", "Partners"),
("all", "All"),
("applicant partners", "Applicants & Partners"),
],
default="applicant",
max_length=30,
verbose_name="visibility",
),
),
]
22 changes: 20 additions & 2 deletions hypha/apply/activity/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from django.utils import timezone
from django.utils.text import get_valid_filename
from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy

from hypha.apply.utils.storage import PrivateStorage

Expand Down Expand Up @@ -175,6 +176,10 @@ class ActivityAttachment(models.Model):
upload_to=get_attachment_upload_path, storage=PrivateStorage()
)

class Meta:
verbose_name = gettext_lazy("activity attachment")
verbose_name_plural = gettext_lazy("activity attachments")

@property
def filename(self):
return os.path.basename(self.file.name)
Expand All @@ -201,9 +206,12 @@ class Activity(models.Model):
source_object_id = models.PositiveIntegerField(blank=True, null=True, db_index=True)
source = GenericForeignKey("source_content_type", "source_object_id")

message = models.TextField()
message = models.TextField(gettext_lazy("message"))
visibility = models.CharField(
choices=list(VISIBILITY.items()), default=APPLICANT, max_length=30
gettext_lazy("visibility"),
choices=list(VISIBILITY.items()),
default=APPLICANT,
max_length=30,
)

# Fields for handling versioning of the comment activity models
Expand Down Expand Up @@ -232,6 +240,8 @@ class Activity(models.Model):
class Meta:
ordering = ["-timestamp"]
base_manager_name = "objects"
verbose_name = gettext_lazy("activity")
verbose_name_plural = gettext_lazy("activities")

def get_absolute_url(self):
# coverup for both submission and project as source.
Expand Down Expand Up @@ -330,6 +340,10 @@ class Event(models.Model):
object_id = models.PositiveIntegerField(blank=True, null=True)
source = GenericForeignKey("content_type", "object_id")

class Meta:
verbose_name = gettext_lazy("event")
verbose_name_plural = gettext_lazy("events")

def __str__(self):
if self.source and hasattr(self.source, "title"):
return f"{self.by} {self.get_type_display()} - {self.source.title}"
Expand Down Expand Up @@ -365,6 +379,10 @@ class Message(models.Model):
sent_in_email_digest = models.BooleanField(default=False)
objects = MessagesQueryset.as_manager()

class Meta:
verbose_name = gettext_lazy("message")
verbose_name_plural = gettext_lazy("messages")

def __str__(self):
return f"[{self.type}][{self.status}] {self.content}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
hx-target="this"
hx-swap="outerHTML transition:true"
hx-select=".h-timeline"
>Show more...</a>
>{% trans "Show more..." %}</a>
{% endif %}
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
{% for role in activity.user.get_role_names %}
<span
class="inline-block py-0.5 px-2 text-sm font-semibold rounded-xl border border-gray-300 text-fg-muted"
data-tippy-content="This user is a {{ role }}"
data-tippy-content="{% blocktrans %}This user is a {{ role }}{% endblocktrans %}"
>
{{ role }}
</span>
Expand All @@ -34,7 +34,7 @@
{% endif %}

<a href="#communications--{{activity.id}}" class="hover:underline">
<span class="text-fg-muted">commented</span>
<span class="text-fg-muted">{% trans "commented" %}</span>
<relative-time
class="text-fg-muted"
datetime="{{ activity.timestamp|date:"c" }}"
Expand All @@ -58,7 +58,7 @@

{% with activity.visibility|visibility_display:request.user as visibility_text %}
<span class="flex gap-1 items-center py-0.5 px-1.5 text-xs uppercase rounded-xl border border-gray-300 text-fg-muted"
data-tippy-content="This is visible to {{ visibility_text }}">
data-tippy-content="{% blocktrans %}This is visible to {{ visibility_text }}{% endblocktrans %}">
{% heroicon_outline "eye" size=14 class="inline" aria_hidden=true %}
{{ visibility_text }}
</span>
Expand Down
9 changes: 5 additions & 4 deletions hypha/apply/activity/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.core.paginator import Paginator
from django.shortcuts import get_object_or_404, render
from django.utils.decorators import method_decorator
from django.utils.translation import gettext as _
from django.views.decorators.http import require_http_methods
from django.views.generic import ListView
from rolepermissions.checkers import has_object_permission
Expand Down Expand Up @@ -57,10 +58,10 @@ def edit_comment(request, pk):
activity = get_object_or_404(Activity, id=pk)

if activity.type != COMMENT or activity.user != request.user:
raise PermissionError("You can only edit your own comments")
raise PermissionDenied(_("You can only edit your own comments"))

if activity.deleted:
raise PermissionError("You can not edit a deleted comment")
raise PermissionDenied(_("You can not edit a deleted comment"))

if request.GET.get("action") == "cancel":
return render(
Expand Down Expand Up @@ -88,10 +89,10 @@ def delete_comment(request, pk):
activity = get_object_or_404(Activity, id=pk)

if activity.type != COMMENT or activity.user != request.user:
raise PermissionError("You can only delete your own comments")
raise PermissionDenied(_("You can only delete your own comments"))

if activity.deleted:
raise PermissionError("You can not delete a deleted comment")
raise PermissionDenied(_("You can not delete a deleted comment"))

if request.method == "DELETE":
activity = services.delete_comment(activity)
Expand Down
3 changes: 2 additions & 1 deletion hypha/apply/categories/admin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.urls import re_path
from django.utils.translation import gettext_lazy as _
from wagtail_modeladmin.options import ModelAdmin

from hypha.apply.utils.admin import AdminIcon
Expand All @@ -9,7 +10,7 @@


class CategoryAdmin(ModelAdmin):
menu_label = "Category Questions"
menu_label = _("Category Questions")
menu_icon = str(AdminIcon.CATEGORY)
model = Category

Expand Down
10 changes: 7 additions & 3 deletions hypha/apply/categories/admin_helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.contrib.admin.utils import quote
from django.utils.translation import gettext as _
from wagtail_modeladmin.helpers import ButtonHelper


Expand Down Expand Up @@ -33,9 +34,12 @@ def add_child_button(self, pk, child_verbose_name, **kwargs):
)
return {
"classname": classname,
"label": "Add %s %s" % (child_verbose_name, self.verbose_name),
"title": "Add %s %s under this one"
% (child_verbose_name, self.verbose_name),
"label": _("Add {child_verbose_name} {verbose_name}").format(
child_verbose_name=child_verbose_name, verbose_name=self.verbose_name
),
"title": _("Add {child_verbose_name} {verbose_name} under this one").format(
child_verbose_name=child_verbose_name, verbose_name=self.verbose_name
),
"url": self.url_helper.get_action_url("add_child", quote(pk)),
}

Expand Down
11 changes: 6 additions & 5 deletions hypha/apply/categories/admin_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.contrib.admin.utils import unquote
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from wagtail_modeladmin.views import CreateView


Expand All @@ -18,11 +19,11 @@ def __init__(self, model_admin, parent_pk):

def get_page_title(self):
"""Generate a title that explains you are adding a child."""
title = super().get_page_title()
return title + " %s %s for %s" % (
self.model.node_child_verbose_name,
self.opts.verbose_name,
self.parent_instance,
return _("{title} {child_verbose_name} {verbose_name} for {parent}").format(
title=super().get_page_title(),
child_verbose_name=self.model.node_child_verbose_name,
verbose_name=self.opts.verbose_name,
parent=self.parent_instance,
)

def get_initial(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.2.11 on 2026-03-03 14:58

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("categories", "0007_rename_meta_terms_to_tags"),
]

operations = [
migrations.AlterModelOptions(
name="category",
options={"verbose_name": "Category", "verbose_name_plural": "Categories"},
),
migrations.AlterModelOptions(
name="option",
options={"verbose_name": "option", "verbose_name_plural": "options"},
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 5.2.12 on 2026-03-31 09:50

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("categories", "0008_alter_category_options_alter_option_options"),
]

operations = [
migrations.AlterField(
model_name="metaterm",
name="is_archived",
field=models.BooleanField(
default=False,
help_text="Archived terms can be viewed but not set on content.",
verbose_name="archived",
),
),
]
Loading
Loading