Coverage for baibu/localization/models.py: 100%

52 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-10-06 13:07 +0000

1import uuid 

2 

3from django.conf import settings 

4from django.db import models 

5from django.utils import timezone 

6from django.utils.translation import gettext_lazy as _ 

7 

8 

9class TranslationSource(models.Model): 

10 """The interface strings extracted from the code (a gettext template). 

11 

12 The newest row is the current template. The file itself lives in private 

13 storage (``pot_key``). 

14 """ 

15 

16 id = models.UUIDField(primary_key=True, default=uuid.uuid7, editable=False) 

17 pot_key = models.CharField(max_length=512) 

18 # SHA-256 of the extracted entries, so an unchanged extraction is skipped. 

19 content_hash = models.CharField(max_length=64) 

20 entry_count = models.PositiveIntegerField(default=0) 

21 created_by = models.ForeignKey( 

22 settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="+" 

23 ) 

24 created_at = models.DateTimeField(default=timezone.now) 

25 

26 class Meta: 

27 ordering = ["-created_at"] 

28 get_latest_by = "created_at" 

29 verbose_name = _("Source strings") 

30 verbose_name_plural = _("Source strings") 

31 

32 def __str__(self) -> str: 

33 return f"Source strings of {self.created_at:%Y-%m-%d %H:%M}" 

34 

35 

36class TranslationCatalogue(models.Model): 

37 """The working copy (draft) of one language's interface translations.""" 

38 

39 language_code = models.CharField(_("Language"), max_length=24, unique=True) 

40 # The draft .po file in private storage. Replaced on every save. 

41 draft_key = models.CharField(max_length=512) 

42 # The template last merged into the draft. 

43 source = models.ForeignKey(TranslationSource, on_delete=models.SET_NULL, null=True, blank=True, related_name="+") 

44 updated_by = models.ForeignKey( 

45 settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="+" 

46 ) 

47 updated_at = models.DateTimeField(default=timezone.now) 

48 created_at = models.DateTimeField(auto_now_add=True) 

49 

50 class Meta: 

51 ordering = ["language_code"] 

52 verbose_name = _("Translation catalogue") 

53 verbose_name_plural = _("Translation catalogues") 

54 permissions = [("edit_translations", _("Can edit and publish interface translations"))] 

55 

56 def __str__(self) -> str: 

57 return self.language_code 

58 

59 

60class TranslationPublication(models.Model): 

61 """One publication of a language's translations: the audit trail. 

62 

63 Rows are never changed. Publishing again, or restoring an earlier 

64 version, adds a row; the newest row for a language is what the site uses. 

65 """ 

66 

67 id = models.UUIDField(primary_key=True, default=uuid.uuid7, editable=False) 

68 language_code = models.CharField(_("Language"), max_length=24, db_index=True) 

69 version = models.PositiveIntegerField() 

70 po_key = models.CharField(max_length=512) 

71 mo_key = models.CharField(max_length=512) 

72 total_count = models.PositiveIntegerField(default=0) 

73 translated_count = models.PositiveIntegerField(default=0) 

74 fuzzy_count = models.PositiveIntegerField(default=0) 

75 restored_from = models.ForeignKey( 

76 "self", on_delete=models.SET_NULL, null=True, blank=True, related_name="+", help_text=_("Set for a restore.") 

77 ) 

78 published_by = models.ForeignKey( 

79 settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="+" 

80 ) 

81 published_at = models.DateTimeField(default=timezone.now, db_index=True) 

82 

83 class Meta: 

84 ordering = ["-published_at"] 

85 verbose_name = _("Translation publication") 

86 verbose_name_plural = _("Translation publications") 

87 constraints = [ 

88 models.UniqueConstraint(fields=["language_code", "version"], name="localization_unique_version"), 

89 ] 

90 

91 def __str__(self) -> str: 

92 return f"{self.language_code} v{self.version}"