aboutsummaryrefslogtreecommitdiff
path: root/administration/annoucements/models.py
blob: d03c96c533577aae97541f3338a8c3655fac8ff6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
from django.conf import settings
from django.db import models
from django.utils import timezone

LANGUAGE_CHOICES = [
    ("en", "English"),
    ("ja", "Japanese"),
    ("es", "Spanish"),
    ("fr", "French"),
    ("de", "German"),
    ("zh", "Chinese"),
    ("ko", "Korean"),
]


class Translation(models.Model):
    language = models.CharField(max_length=2, choices=LANGUAGE_CHOICES)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True


class AnnouncementTranslation(Translation):
    announcement = models.ForeignKey(
        "Announcement", on_delete=models.CASCADE, related_name="translations"
    )
    content = models.TextField()

    class Meta:
        unique_together = ("announcement", "language")


class TranslatableMixin:
    @classmethod
    def translate_queryset(cls, queryset, language_code="en"):
        processed_objects = set()
        return [obj.translate(language_code, processed_objects) for obj in queryset]

    def translate(self, language_code="en", processed_objects=None):
        if processed_objects is None:
            processed_objects = set()

        instance_id = f"{self.__class__.__name__}_{self.pk}"
        if instance_id in processed_objects:
            return self

        processed_objects.add(instance_id)
        translation = self.get_translation(language_code)

        if translation:
            translated_fields = [
                field.name
                for field in translation._meta.get_fields()
                if not field.is_relation
                and field.name not in ["id", "language", "created_at", "updated_at"]
            ]

            for field_name in translated_fields:
                translated_value = getattr(translation, field_name, None)
                if translated_value is not None:
                    setattr(self, field_name, translated_value)

        self._translate_relations(language_code, processed_objects)
        return self

    def _translate_relations(self, language_code, processed_objects):
        for field in self._meta.get_fields():
            if not hasattr(field, "related_model") or not hasattr(
                field.related_model, "translate"
            ):
                continue

            if field.one_to_many or field.many_to_many:
                related_manager = getattr(self, field.name, None)
                if related_manager and hasattr(related_manager, "all"):
                    for obj in related_manager.all():
                        obj.translate(language_code, processed_objects)

            elif field.many_to_one or field.one_to_one:
                related_obj = getattr(self, field.name, None)
                if related_obj and hasattr(related_obj, "translate"):
                    related_obj.translate(language_code, processed_objects)

    def get_translation(self, language_code):
        try:
            return self.translations.get(language=language_code)
        except self.translations.model.DoesNotExist:
            return None


class Announcement(TranslatableMixin, models.Model):
    content = models.TextField()
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
    is_public = models.BooleanField(default=False)
    is_new = models.BooleanField(default=True)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.content[:50] + "..." if len(self.content) > 50 else self.content

    def save(self, *args, **kwargs):
        if not self.created_at:
            self.created_at = timezone.now()
        return super().save(*args, **kwargs)