Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class PeopleGroup(
The visibility setting of the group.
"""

_auto_translated_fields: List[str] = [
auto_translated_fields: List[str] = [
"name",
"html:description",
"short_description",
Expand Down Expand Up @@ -265,7 +265,7 @@ class ProjectUser(
"""

organization_query_string: str = "groups__organizations"
_auto_translated_fields: List[str] = [
auto_translated_fields: List[str] = [
"html:description",
"short_description",
"job",
Expand Down
2 changes: 1 addition & 1 deletion apps/announcements/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Announcement(
Date of the last change made to the announcement.
"""

_auto_translated_fields: List[str] = ["title", "html:description"]
auto_translated_fields: List[str] = ["title", "html:description"]

class AnnouncementType(models.TextChoices):
NONE = ("na", "Not applicable")
Expand Down
4 changes: 2 additions & 2 deletions apps/feedbacks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class Comment(HasAutoTranslatedFields, HasOwner, ProjectRelated, models.Model):
History of the object.
"""

_auto_translated_fields: List[str] = ["html:content"]
auto_translated_fields: List[str] = ["html:content"]

project = HistoricForeignKey(
"projects.Project", on_delete=models.CASCADE, related_name="comments"
Expand Down Expand Up @@ -200,7 +200,7 @@ class Review(HasAutoTranslatedFields, HasOwner, ProjectRelated, models.Model):
Date of the last change made to the review.
"""

_auto_translated_fields: List[str] = ["html:description", "title"]
auto_translated_fields: List[str] = ["html:description", "title"]

description = models.TextField(blank=True)
title = models.CharField(max_length=100)
Expand Down
10 changes: 5 additions & 5 deletions apps/files/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class AttachmentLink(
A link that is attached to a project.
"""

_auto_translated_fields: list[str] = ["title", "description"]
auto_translated_fields: list[str] = ["title", "description"]

project = models.ForeignKey(
"projects.Project", on_delete=models.CASCADE, related_name="links"
Expand Down Expand Up @@ -147,7 +147,7 @@ class OrganizationAttachmentFile(
An attachment file that is related to an organization.
"""

_auto_translated_fields: list[str] = ["title", "description"]
auto_translated_fields: list[str] = ["title", "description"]

organization = models.ForeignKey(
"organizations.Organization",
Expand Down Expand Up @@ -178,7 +178,7 @@ class AttachmentFile(
An attachment file that is related to a project.
"""

_auto_translated_fields: list[str] = ["title", "description"]
auto_translated_fields: list[str] = ["title", "description"]

project = models.ForeignKey(
"projects.Project", on_delete=models.CASCADE, related_name="files"
Expand Down Expand Up @@ -439,7 +439,7 @@ class ProjectUserAttachmentFile(HasAutoTranslatedFields, HasOwner, models.Model)
An attachment file that is related to a project.
"""

_auto_translated_fields: list[str] = ["title", "description"]
auto_translated_fields: list[str] = ["title", "description"]

owner = models.ForeignKey(
"accounts.ProjectUser", on_delete=models.CASCADE, related_name="files"
Expand All @@ -465,7 +465,7 @@ class ProjectUserAttachmentLink(HasAutoTranslatedFields, HasOwner, models.Model)
A link that is attached to a project.
"""

_auto_translated_fields: list[str] = ["title", "description"]
auto_translated_fields: list[str] = ["title", "description"]

owner = models.ForeignKey(
"accounts.ProjectUser", on_delete=models.CASCADE, related_name="links"
Expand Down
4 changes: 2 additions & 2 deletions apps/invitations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Invitation(HasAutoTranslatedFields, HasOwner, OrganizationRelated, models.
A link that allows a user to join an organization.
"""

_auto_translated_fields: List[str] = ["description"]
auto_translated_fields: List[str] = ["description"]

organization = models.ForeignKey(
"organizations.Organization", on_delete=models.CASCADE
Expand Down Expand Up @@ -54,7 +54,7 @@ class AccessRequest(HasAutoTranslatedFields, OrganizationRelated, models.Model):
It can be created by an existing user or by a new user.
"""

_auto_translated_fields: List[str] = ["message"]
auto_translated_fields: List[str] = ["message"]

class Status(models.TextChoices):
PENDING = "pending"
Expand Down
6 changes: 3 additions & 3 deletions apps/newsfeed/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class News(HasAutoTranslatedFields, OrganizationRelated, models.Model):
If the news is visible by all the users, connected or not, member of a group or not.
"""

_auto_translated_fields: List[str] = ["title", "html:content"]
auto_translated_fields: List[str] = ["title", "html:content"]

title = models.CharField(max_length=255, verbose_name=("title"))
content = models.TextField(blank=True, default="")
Expand Down Expand Up @@ -139,7 +139,7 @@ class Instruction(HasAutoTranslatedFields, OrganizationRelated, HasOwner, models
If the news is visible by all the users, connected or not, member of a group or not.
"""

_auto_translated_fields: List[str] = ["title", "html:content"]
auto_translated_fields: List[str] = ["title", "html:content"]

owner = models.ForeignKey(
"accounts.ProjectUser",
Expand Down Expand Up @@ -204,7 +204,7 @@ class Event(HasAutoTranslatedFields, OrganizationRelated, models.Model):
If the news is visible by all the users, connected or not, member of a group or not.
"""

_auto_translated_fields: List[str] = ["title", "html:content"]
auto_translated_fields: List[str] = ["title", "html:content"]

title = models.CharField(max_length=255, verbose_name=("title"))
content = models.TextField(blank=True, default="")
Expand Down
9 changes: 5 additions & 4 deletions apps/organizations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class Organization(
"""

organization_query_string: str = ""
_auto_translated_fields: List[str] = [
auto_translated_fields: List[str] = [
"name",
"dashboard_title",
"dashboard_subtitle",
Expand Down Expand Up @@ -406,7 +406,7 @@ class Template(HasAutoTranslatedFields, OrganizationRelated, models.Model):
Project's comment content placeholder.
"""

_auto_translated_fields: List[str] = [
auto_translated_fields: List[str] = [
"name",
"html:description",
"project_title",
Expand Down Expand Up @@ -494,7 +494,7 @@ class ProjectCategory(
History of the object.
"""

_auto_translated_fields: List[str] = ["name", "html:description"]
auto_translated_fields: List[str] = ["name", "html:description"]
slugified_fields: List[str] = ["name"]
slug_prefix: str = "category"

Expand Down Expand Up @@ -618,7 +618,8 @@ class TermsAndConditions(HasAutoTranslatedFields, OrganizationRelated, models.Mo
Model to store the terms and conditions for an organization.
"""

_auto_translated_fields: List[str] = ["html:content"]
auto_translated_fields: List[str] = ["html:content"]
auto_translate_all_languages: bool = True

organization = models.OneToOneField(
"organizations.Organization",
Expand Down
16 changes: 8 additions & 8 deletions apps/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class Project(

slugified_fields: List[str] = ["title"]
slug_prefix: str = "project"
_auto_translated_fields: List[str] = ["title", "html:description", "purpose"]
auto_translated_fields: List[str] = ["title", "html:description", "purpose"]

class PublicationStatus(models.TextChoices):
"""Visibility setting of a project."""
Expand Down Expand Up @@ -203,7 +203,7 @@ class LifeStatus(models.TextChoices):
m2m_fields=[tags, categories],
excluded_fields=[
f"{field.split(':', 1)[1] if ':' in field else field}_{lang}"
for field in _auto_translated_fields
for field in auto_translated_fields
for lang in settings.REQUIRED_LANGUAGES
],
)
Expand Down Expand Up @@ -725,7 +725,7 @@ class BlogEntry(
Date of the last change made to the blog entry.
"""

_auto_translated_fields: List[str] = ["title", "html:content"]
auto_translated_fields: List[str] = ["title", "html:content"]

project = models.ForeignKey(
Project, on_delete=models.CASCADE, related_name="blog_entries"
Expand Down Expand Up @@ -811,7 +811,7 @@ class Goal(
Status of the Goal.
"""

_auto_translated_fields: List[str] = ["title", "html:description"]
auto_translated_fields: List[str] = ["title", "html:description"]

class GoalStatus(models.TextChoices):
NONE = "na"
Expand Down Expand Up @@ -887,7 +887,7 @@ class Location(
Type of the location (team or impact).
"""

_auto_translated_fields: List[str] = ["title", "description"]
auto_translated_fields: List[str] = ["title", "description"]

class LocationType(models.TextChoices):
"""Type of a location."""
Expand Down Expand Up @@ -956,7 +956,7 @@ class ProjectMessage(
Images used by the message.
"""

_auto_translated_fields: List[str] = ["html:content"]
auto_translated_fields: List[str] = ["html:content"]

project = models.ForeignKey(
"projects.Project",
Expand Down Expand Up @@ -1028,7 +1028,7 @@ class ProjectTab(
Description of the tab.
"""

_auto_translated_fields: List[str] = ["title", "html:description"]
auto_translated_fields: List[str] = ["title", "html:description"]

class TabType(models.TextChoices):
"""Type of a tab."""
Expand Down Expand Up @@ -1076,7 +1076,7 @@ class ProjectTabItem(
project_query_string: str = "tab__project"
organization_query_string: str = "tab__project__organizations"

_auto_translated_fields: List[str] = ["title", "html:content"]
auto_translated_fields: List[str] = ["title", "html:content"]

tab = models.ForeignKey(
"projects.ProjectTab", on_delete=models.CASCADE, related_name="items"
Expand Down
2 changes: 1 addition & 1 deletion apps/projects/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ def get_delta(version) -> Dict[str, str]:
previous,
excluded_fields=[
f"{field}_{lang}"
for field in Project.auto_translated_fields
for field in Project._auto_translated_fields
for lang in settings.REQUIRED_LANGUAGES
],
)
Expand Down
4 changes: 2 additions & 2 deletions apps/skills/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class TagClassification(
Users are allowed to create their own tags and classifications.
"""

_auto_translated_fields: List[str] = ["title", "description"]
auto_translated_fields: List[str] = ["title", "description"]
slugified_fields: List[str] = ["title"]
slug_prefix: str = "tag-classification"
reserved_slugs = ["enabled-for-projects", "enabled-for-skills"]
Expand Down Expand Up @@ -317,7 +317,7 @@ class MentoringMessage(
"""

organization_query_string: str = "mentoring__organization"
_auto_translated_fields: List[str] = ["content"]
auto_translated_fields: List[str] = ["content"]

mentoring = models.ForeignKey(
"skills.Mentoring", on_delete=models.CASCADE, related_name="messages"
Expand Down
2 changes: 1 addition & 1 deletion services/crisalid/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class DocumentType(models.TextChoices):
WORKING_PAPER = "Working Paper"
UNKNOWN = "Unknown"

_auto_translated_fields = ["title", "description"]
auto_translated_fields = ["title", "description"]

title = models.TextField()
description = models.TextField(default="")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def add_arguments(self, parser):

def init_autotranslated_fields(self, queryset: QuerySet[T]):
content_type = ContentType.objects.get_for_model(queryset.model)
translated_fields = queryset.model.auto_translated_fields
translated_fields = queryset.model._auto_translated_fields
initial_count = AutoTranslatedField.objects.count()
AutoTranslatedField.objects.bulk_create(
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ class Command(BaseCommand):
def init_autotranslated_fields(self, queryset: QuerySet[T]):
"""
Create AutoTranslatedField entries for new fields marked for
auto-translation in the model's `auto_translated_fields`.
auto-translation in the model's `_auto_translated_fields`.
"""
content_type = ContentType.objects.get_for_model(queryset.model)
translated_fields = queryset.model.auto_translated_fields
translated_fields = queryset.model._auto_translated_fields
initial_count = AutoTranslatedField.objects.count()
AutoTranslatedField.objects.bulk_create(
[
Expand All @@ -45,11 +45,11 @@ def init_autotranslated_fields(self, queryset: QuerySet[T]):
def delete_autotranslated_fields(self, queryset: QuerySet[T]):
"""
Delete AutoTranslatedField entries for fields that are no longer
marked for auto-translation in the model's `auto_translated_fields`.
marked for auto-translation in the model's `_auto_translated_fields`.
"""
model = queryset.model
content_type = ContentType.objects.get_for_model(model)
translated_fields = model.auto_translated_fields
translated_fields = model._auto_translated_fields
initial_count = AutoTranslatedField.objects.count()
AutoTranslatedField.objects.filter(content_type=content_type).exclude(
field_name__in=translated_fields
Expand Down
27 changes: 17 additions & 10 deletions services/translator/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ class TranslatedModelMeta(models.base.ModelBase):
"""

def __new__(cls, name, bases, attrs):
for field in attrs.get("_auto_translated_fields", []):
for field in attrs.get("auto_translated_fields", []):
field_type, field = (
field.split(":", 1) if ":" in field else ("plain", field)
)
attrs["auto_translated_fields"] = attrs.get(
"auto_translated_fields", []
attrs["_auto_translated_fields"] = attrs.get(
"_auto_translated_fields", []
) + [field]
if field_type == "html":
attrs["html_auto_translated_fields"] = attrs.get(
"html_auto_translated_fields", []
attrs["_html_auto_translated_fields"] = attrs.get(
"_html_auto_translated_fields", []
) + [field]
base_field = attrs[field]
attrs[f"{field}_detected_language"] = models.CharField(
Expand All @@ -56,23 +56,30 @@ class HasAutoTranslatedFields(metaclass=TranslatedModelMeta):

Models based on this mixin must implement the following attribute:
- `auto_translated_fields`: A list of field names that should be automatically
translated.
translated. If a field is of type HTML, it should be suffixed with `:html`
Example: autotrans_set_in_class: List[str] = ["title", "html:content"]
- `auto_translate_all_languages`: A boolean indicating whether to translate
the fields into all supported languages or only into the related organization's
languages. This is useful for content that can be used across multiple organizations.

When the model is saved, it will check if any of the translated fields
have changed. If they have, it will create or update an `AutoTranslatedField`
instance for each field, marking it as not up to date. This allows the system
to know that the translations need to be updated.
"""

_auto_translated_fields: List[str] = []
auto_translated_fields: List[str] = []
html_auto_translated_fields: List[str] = []
auto_translate_all_languages: bool = False

_auto_translated_fields: List[str] = []
_html_auto_translated_fields: List[str] = []
_original_auto_translated_fields_values: Dict[str, str] = {}

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._original_auto_translated_fields_values = {
field: self.__dict__.get(field, "") for field in self.auto_translated_fields
field: self.__dict__.get(field, "")
for field in self._auto_translated_fields
}

def update_translated_fields(self, force_update: bool = True):
Expand All @@ -88,7 +95,7 @@ def update_translated_fields(self, force_update: bool = True):
have not changed. Defaults to True.
"""
content_type = ContentType.objects.get_for_model(self.__class__)
for field in self._auto_translated_fields:
for field in self.auto_translated_fields:
field_type, field = (
field.split(":", 1)
if ":" in field
Expand Down
Loading