aboutsummaryrefslogtreecommitdiff
path: root/core/translations.py
blob: 918adbe7453e980d468c0757c3bb745e41ac4667 (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
from django.db import models
from django.utils.translation import get_language, gettext_lazy as _

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


class Translation(models.Model):
    """Base abstract model for translations"""

    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 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