diff --git a/apps/account/admin/location.py b/apps/account/admin/location.py
index c1740e3..60cb326 100644
--- a/apps/account/admin/location.py
+++ b/apps/account/admin/location.py
@@ -54,6 +54,7 @@ class LocationHistoryAdmin(ModelAdmin):
return instance.at_time.strftime("%Y-%m-%d %H:%M") if instance.at_time else "-"
+
# Register with both admin sites
project_admin_site.register(LocationHistory, LocationHistoryAdmin)
dovoodi_admin_site.register(LocationHistory, LocationHistoryAdmin)
\ No newline at end of file
diff --git a/apps/account/admin/notification.py b/apps/account/admin/notification.py
index b17d676..f62ff66 100644
--- a/apps/account/admin/notification.py
+++ b/apps/account/admin/notification.py
@@ -1,12 +1,14 @@
-from ajaxdatatable.admin import AjaxDatatable
-
-from apps.account.models import User, Notification
-
-@admin.register(Notification)
-class NotificationAdmin(AjaxDatatable):
- list_display = ('title', 'user', 'is_read', 'created_at')
- list_filter = ('is_read', 'created_at')
- search_fields = ('title', 'message', 'user__fullname')
- list_editable = ('is_read',)
- ordering = ('-created_at',)
- autocomplete_fields = ['user',]
\ No newline at end of file
+from django.contrib import admin
+from django.utils.translation import gettext_lazy as _
+from ajaxdatatable.admin import AjaxDatatable
+
+from apps.account.models import User, Notification
+
+@admin.register(Notification)
+class NotificationAdmin(AjaxDatatable):
+ list_display = ('title', 'user', 'is_read', 'created_at')
+ list_filter = ('is_read', 'created_at')
+ search_fields = ('title', 'message', 'user__fullname')
+ list_editable = ('is_read',)
+ ordering = ('-created_at',)
+ autocomplete_fields = ['user',]
\ No newline at end of file
diff --git a/apps/account/admin/professor.py b/apps/account/admin/professor.py
index 82fecc0..0014d42 100644
--- a/apps/account/admin/professor.py
+++ b/apps/account/admin/professor.py
@@ -19,7 +19,7 @@ from apps.account.models import ProfessorUser
class ProfessorUserCreationForm(UserCreationForm):
phone_number = PhoneNumberField(
- help_text="Enter the phone number in international format. Example: +989012023212",
+ help_text=_("Enter the phone number in international format. Example: +989012023212"),
required=False
)
@@ -42,11 +42,11 @@ class ProfessorUserAdmin(UserAdmin, AjaxDatatable):
'classes': ('wide',),
'fields': ('fullname', 'email', 'phone_number',),
}),
- ('other', {
+ (_('other'), {
'classes': ('wide',),
'fields': ('avatar', 'info', 'skill'),
}),
- ('Password', {
+ (_('Password'), {
'classes': ('wide',),
'fields': ('password1', 'password2'),
}),
@@ -72,7 +72,7 @@ class ProfessorUserAdmin(UserAdmin, AjaxDatatable):
if existing_user:
# If user exists and is already a professor, show error
if existing_user.user_type == User.UserType.PROFESSOR:
- messages.error(request, f"A professor with the email {email} already exists.")
+ messages.error(request, _("A professor with the email {email} already exists.").format(email=email))
return
# اضافه کردن نقش professor بدون حذف نقشهای قبلی
@@ -93,7 +93,7 @@ class ProfessorUserAdmin(UserAdmin, AjaxDatatable):
existing_user.save()
# Show success message
- messages.success(request, f"The user with email {email} has been converted to a professor.")
+ messages.success(request, _("The user with email {email} has been converted to a professor.").format(email=email))
# Set obj to None to prevent further processing
obj = None
@@ -106,11 +106,12 @@ class ProfessorUserAdmin(UserAdmin, AjaxDatatable):
obj.add_role('professor')
super().save_model(request, obj, form, change)
- @admin.display(description='Phone Number')
+ @admin.display(description=_('Phone Number'))
def _phone_number(self, obj):
return obj.phone_number
+
def get_readonly_fields(self, request, obj=None):
"""
Restrict the ability to modify groups to superusers only.
diff --git a/apps/account/admin/student.py b/apps/account/admin/student.py
index a7cc389..96f1213 100644
--- a/apps/account/admin/student.py
+++ b/apps/account/admin/student.py
@@ -1,7 +1,7 @@
from django.contrib import admin
from django.contrib.auth.forms import UserChangeForm, UsernameField
from django.contrib.auth.admin import UserAdmin
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext_lazy as _, ngettext
from rest_framework.authtoken.models import TokenProxy
from ajaxdatatable.admin import AjaxDatatable
from unfold.admin import TabularInline, StackedInline
@@ -29,11 +29,11 @@ class StudentUserAdmin(UserAdmin, AjaxDatatable):
'classes': ('wide',),
'fields': ('fullname', 'email', 'phone_number',),
}),
- ('other', {
+ (_('other'), {
'classes': ('wide',),
'fields': ('avatar', 'info'),
}),
- ('Password', {
+ (_('Password'), {
'classes': ('wide',),
'fields': ('password1', 'password2'),
}),
@@ -48,7 +48,7 @@ class StudentUserAdmin(UserAdmin, AjaxDatatable):
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined', 'fcm')}),
)
- @admin.display(description='Phone Number')
+ @admin.display(description=_('Phone Number'))
def _phone_number(self, obj):
return obj.phone_number
@@ -56,7 +56,8 @@ class StudentUserAdmin(UserAdmin, AjaxDatatable):
def enrolled_courses_count(self, obj):
"""نمایش تعداد دورههای شرکت کرده"""
count = obj.participated_courses.filter(is_active=True).count()
- return f"{count} دوره"
+ return ngettext("{count} course", "{count} courses", count).format(count=count)
+
def get_queryset(self, request):
diff --git a/apps/account/admin/user.py b/apps/account/admin/user.py
index 049aace..91c5eba 100644
--- a/apps/account/admin/user.py
+++ b/apps/account/admin/user.py
@@ -5,7 +5,7 @@ from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
from django.contrib.auth.models import Group
from django.db import models
from django.utils.html import format_html
-from django.utils.translation import gettext_lazy as _
+from django.utils.translation import gettext_lazy as _, ngettext
from django.templatetags.static import static
from rest_framework.authtoken.models import TokenProxy
@@ -278,7 +278,7 @@ class StudentUserAdmin(UserAdmin):
birthdate = instance.birthdate
age = today.year - birthdate.year - ((today.month, today.day) < (birthdate.month, birthdate.day))
formatted_date = birthdate.strftime("%Y-%m-%d")
- return format_html('{}', f"Born on {formatted_date}", age)
+ return format_html('{}', _("Born on {date}").format(date=formatted_date), age)
@display(description=_("Courses"), dropdown=True)
def courses_count(self, instance: StudentUser):
@@ -304,11 +304,12 @@ class StudentUserAdmin(UserAdmin):
return "-"
return {
- "title": f"{total} {_('courses')}",
+ "title": ngettext("{total} course", "{total} courses", total).format(total=total),
"items": items,
"striped": True,
}
+
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related(
"participated_courses",
@@ -443,11 +444,12 @@ class ProfessorUserAdmin(UserAdmin):
return "-"
return {
- "title": f"{total} {_('courses')}",
+ "title": ngettext("{total} course", "{total} courses", total).format(total=total),
"items": items,
"striped": True,
}
+
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related("courses")
@@ -466,7 +468,7 @@ class GroupAdmin(BaseGroupAdmin, ModelAdmin):
@display(description=_("Permissions"))
def permissions_count(self, obj):
count = obj.permissions.count()
- return f"{count} {_('permissions')}" if count > 0 else "-"
+ return ngettext("{count} permission", "{count} permissions", count).format(count=count) if count > 0 else "-"
# =========================================================
diff --git a/apps/account/migrations/0003_alter_clientuser_options_and_more.py b/apps/account/migrations/0003_alter_clientuser_options_and_more.py
new file mode 100644
index 0000000..ee01b33
--- /dev/null
+++ b/apps/account/migrations/0003_alter_clientuser_options_and_more.py
@@ -0,0 +1,127 @@
+# Generated by Django 5.2.12 on 2026-05-04 12:53
+
+import dj_language.field
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('account', '0002_alter_user_email_alter_user_username'),
+ ('dj_language', '0002_auto_20220120_1344'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='clientuser',
+ options={'ordering': ('-id',), 'verbose_name': 'User', 'verbose_name_plural': 'Users'},
+ ),
+ migrations.AlterModelOptions(
+ name='locationhistory',
+ options={'verbose_name': 'Location History', 'verbose_name_plural': 'Location History'},
+ ),
+ migrations.AlterModelOptions(
+ name='loginhistory',
+ options={'verbose_name': 'Login History', 'verbose_name_plural': 'Login Histories'},
+ ),
+ migrations.AlterModelOptions(
+ name='notification',
+ options={'verbose_name': 'Notification', 'verbose_name_plural': 'Notifications'},
+ ),
+ migrations.AlterModelOptions(
+ name='user',
+ options={'ordering': ('-id',), 'verbose_name': 'User', 'verbose_name_plural': 'Users'},
+ ),
+ migrations.AlterField(
+ model_name='locationhistory',
+ name='at_time',
+ field=models.DateTimeField(auto_now_add=True, verbose_name='at time'),
+ ),
+ migrations.AlterField(
+ model_name='locationhistory',
+ name='ip',
+ field=models.CharField(blank=True, max_length=255, null=True, verbose_name='ip'),
+ ),
+ migrations.AlterField(
+ model_name='locationhistory',
+ name='selected_manually',
+ field=models.BooleanField(blank=True, null=True, verbose_name='selected manually'),
+ ),
+ migrations.AlterField(
+ model_name='locationhistory',
+ name='timezone',
+ field=models.CharField(blank=True, max_length=60, null=True, verbose_name='timezone'),
+ ),
+ migrations.AlterField(
+ model_name='locationhistory',
+ name='user',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='location_history', to=settings.AUTH_USER_MODEL, verbose_name='user'),
+ ),
+ migrations.AlterField(
+ model_name='loginhistory',
+ name='at_time',
+ field=models.DateTimeField(auto_now_add=True, verbose_name='at time'),
+ ),
+ migrations.AlterField(
+ model_name='loginhistory',
+ name='device_os',
+ field=models.CharField(blank=True, max_length=16, null=True, verbose_name='Device os'),
+ ),
+ migrations.AlterField(
+ model_name='loginhistory',
+ name='ip',
+ field=models.CharField(max_length=255, null=True, verbose_name='ip'),
+ ),
+ migrations.AlterField(
+ model_name='loginhistory',
+ name='timezone',
+ field=models.CharField(blank=True, max_length=100, null=True, verbose_name='timezone'),
+ ),
+ migrations.AlterField(
+ model_name='loginhistory',
+ name='user',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_history', to=settings.AUTH_USER_MODEL, verbose_name='user'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='avatar',
+ field=models.ImageField(blank=True, max_length=512, null=True, upload_to='users/avatars/%Y/%m/', verbose_name='Avatar'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='deleted_at',
+ field=models.DateTimeField(blank=True, null=True, verbose_name='deleted at'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='device_os',
+ field=models.CharField(choices=[('android', 'android'), ('apple', 'apple'), ('web', 'web')], max_length=16, null=True, verbose_name='device os'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='fcm',
+ field=models.CharField(blank=True, max_length=512, null=True, verbose_name='fcm'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='is_staff',
+ field=models.BooleanField(default=False, verbose_name='is staff'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='language',
+ field=dj_language.field.LanguageField(default=69, limit_choices_to={'status': True}, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='dj_language.language', verbose_name='Language'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='skill',
+ field=models.CharField(blank=True, max_length=512, null=True, verbose_name='skill'),
+ ),
+ migrations.AlterField(
+ model_name='user',
+ name='slug',
+ field=models.SlugField(blank=True, max_length=255, null=True, unique=True, verbose_name='slug'),
+ ),
+ ]
diff --git a/apps/account/models/groups.py b/apps/account/models/groups.py
index 3831644..8cb926d 100644
--- a/apps/account/models/groups.py
+++ b/apps/account/models/groups.py
@@ -1,95 +1,96 @@
-from apps.account.models import User
-from apps.account.manager import *
-
-from django.contrib.auth.models import Group
-
-
-
-
-
-class ProfessorUser(User):
- objects = ProfessorUserManager()
-
- def save(self, *args, **kwargs):
- self.user_type = User.UserType.PROFESSOR
- super().save(*args, **kwargs)
-
- group, _ = Group.objects.get_or_create(name="Professor Group")
- self.groups.add(group)
-
- class Meta:
- proxy = True
- verbose_name = "Professor User"
- verbose_name_plural = "Professor Users"
-
-
-
-
-class ClientUser(User):
- objects = ClientUserManager()
-
- def save(self, *args, **kwargs):
- self.user_type = User.UserType.CLIENT
- super().save(*args, **kwargs)
-
- group, _ = Group.objects.get_or_create(name="Client Group")
- self.groups.add(group)
-
-
- class Meta:
- proxy = True
-
- verbose_name = 'user'
- verbose_name_plural = 'users'
- ordering = ('-id',)
-
-
-
-class AdminUser(User):
- objects = AdminUserManager()
-
- def save(self, *args, **kwargs):
- self.user_type = User.UserType.ADMIN
- super().save(*args, **kwargs)
-
- group, _ = Group.objects.get_or_create(name="Admin Group")
- self.groups.add(group)
-
- class Meta:
- proxy = True
- verbose_name = "Admin User"
- verbose_name_plural = "Admin Users"
-
-
-
-class SuperAdminUser(User):
- objects = SuperAdminUserManager()
-
- def save(self, *args, **kwargs):
- self.user_type = User.UserType.SUPER_ADMIN
- self.is_staff = True
- super().save(*args, **kwargs)
-
-
-
- class Meta:
- proxy = True
- verbose_name = "Super Admin User"
- verbose_name_plural = "Super Admin Users"
-
-
-
-class StudentUser(User):
- objects = StudentUserManager()
-
- def save(self, *args, **kwargs):
- self.user_type = User.UserType.STUDENT
- super().save(*args, **kwargs)
-
- group, _ = Group.objects.get_or_create(name="Student Group")
- self.groups.add(group)
-
- class Meta:
- proxy = True
- verbose_name = "Student User"
- verbose_name_plural = "Student Users"
\ No newline at end of file
+from django.utils.translation import gettext_lazy as _
+from apps.account.models import User
+from apps.account.manager import *
+
+from django.contrib.auth.models import Group
+
+
+
+
+
+class ProfessorUser(User):
+ objects = ProfessorUserManager()
+
+ def save(self, *args, **kwargs):
+ self.user_type = User.UserType.PROFESSOR
+ super().save(*args, **kwargs)
+
+ group, _ = Group.objects.get_or_create(name="Professor Group")
+ self.groups.add(group)
+
+ class Meta:
+ proxy = True
+ verbose_name = _("Professor User")
+ verbose_name_plural = _("Professor Users")
+
+
+
+
+class ClientUser(User):
+ objects = ClientUserManager()
+
+ def save(self, *args, **kwargs):
+ self.user_type = User.UserType.CLIENT
+ super().save(*args, **kwargs)
+
+ group, _ = Group.objects.get_or_create(name="Client Group")
+ self.groups.add(group)
+
+
+ class Meta:
+ proxy = True
+
+ verbose_name = _('User')
+ verbose_name_plural = _('Users')
+ ordering = ('-id',)
+
+
+
+class AdminUser(User):
+ objects = AdminUserManager()
+
+ def save(self, *args, **kwargs):
+ self.user_type = User.UserType.ADMIN
+ super().save(*args, **kwargs)
+
+ group, _ = Group.objects.get_or_create(name="Admin Group")
+ self.groups.add(group)
+
+ class Meta:
+ proxy = True
+ verbose_name = _("Admin User")
+ verbose_name_plural = _("Admin Users")
+
+
+
+class SuperAdminUser(User):
+ objects = SuperAdminUserManager()
+
+ def save(self, *args, **kwargs):
+ self.user_type = User.UserType.SUPER_ADMIN
+ self.is_staff = True
+ super().save(*args, **kwargs)
+
+
+
+ class Meta:
+ proxy = True
+ verbose_name = _("Super Admin User")
+ verbose_name_plural = _("Super Admin Users")
+
+
+
+class StudentUser(User):
+ objects = StudentUserManager()
+
+ def save(self, *args, **kwargs):
+ self.user_type = User.UserType.STUDENT
+ super().save(*args, **kwargs)
+
+ group, _ = Group.objects.get_or_create(name="Student Group")
+ self.groups.add(group)
+
+ class Meta:
+ proxy = True
+ verbose_name = _("Student User")
+ verbose_name_plural = _("Student Users")
\ No newline at end of file
diff --git a/apps/account/models/notification.py b/apps/account/models/notification.py
index 8286fed..d9394a7 100644
--- a/apps/account/models/notification.py
+++ b/apps/account/models/notification.py
@@ -1,11 +1,11 @@
from django.db import models
-from django.utils.translation import gettext as _
+from django.utils.translation import gettext_lazy as _
class Notification(models.Model):
class ServiceChoices(models.TextChoices):
- IMAM_JAVAD = 'imam-javad', 'Imam Javad'
- DOBOODI = 'doboodi', 'Doboodi'
+ IMAM_JAVAD = 'imam-javad', _('Imam Javad')
+ DOBOODI = 'doboodi', _('Doboodi')
title = models.CharField(max_length=255, verbose_name=_('title'))
message = models.TextField(max_length=512, verbose_name=_('message'))
@@ -20,6 +20,11 @@ class Notification(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'), null=True)
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'), null=True)
+ class Meta:
+ verbose_name = _('Notification')
+ verbose_name_plural = _('Notifications')
+
def __str__(self):
return self.title
+
diff --git a/apps/account/models/user.py b/apps/account/models/user.py
index 89e8f57..b565d72 100644
--- a/apps/account/models/user.py
+++ b/apps/account/models/user.py
@@ -14,65 +14,65 @@ from apps.account.manager import UserManager
class User(AbstractUser):
class DeviceOs(models.TextChoices):
- android = 'android', 'android'
- apple = 'apple', 'apple'
- web = 'web', 'web'
+ android = 'android', _('android')
+ apple = 'apple', _('apple')
+ web = 'web', _('web')
class UserType(models.TextChoices):
- PROFESSOR = 'professor', 'Professor'
- CLIENT = 'client', 'Client'
- STUDENT = 'student', "Student"
- ADMIN = 'admin', 'Admin'
- SUPER_ADMIN = 'super_admin', 'Super Admin'
+ PROFESSOR = 'professor', _('Professor')
+ CLIENT = 'client', _('Client')
+ STUDENT = 'student', _("Student")
+ ADMIN = 'admin', _('Admin')
+ SUPER_ADMIN = 'super_admin', _('Super Admin')
class GenderChoices(models.TextChoices):
- MALE = 'male', 'Male'
- FEMALE = 'female', 'Female'
+ MALE = 'male', _('Male')
+ FEMALE = 'female', _('Female')
last_name = None
first_name = None
username = models.CharField(unique=True, null=True, blank=True, max_length=150,
- verbose_name=_("Username"),
- error_messages={'unique': _("A user with that username already exists.")})
+ verbose_name=_("Username"),
+ error_messages={'unique': _("A user with that username already exists.")})
email = models.EmailField(unique=True, verbose_name=_("Email Address"),
- help_text=_("Enter the user's email address."),
- null=True, blank=True,
- error_messages={'unique': _("A user with that email already exists.")})
+ help_text=_("Enter the user's email address."),
+ null=True, blank=True,
+ error_messages={'unique': _("A user with that email already exists.")})
fullname = models.CharField(max_length=255, verbose_name=_("Full Name"),
- help_text=_("Enter the full name of the user."),
- null=True, blank=True)
+ help_text=_("Enter the full name of the user."),
+ null=True, blank=True)
birthdate = models.DateField(verbose_name=_('birthdate'), null=True, blank=True)
- avatar = models.ImageField(max_length=512, null=True, blank=True, upload_to='users/avatars/%Y/%m/')
+ avatar = models.ImageField(max_length=512, null=True, blank=True, upload_to='users/avatars/%Y/%m/', verbose_name=_('Avatar'))
phone_number = PhoneNumberField(
validators=[validate_possible_number],
null=True,
blank=True,
verbose_name=_('Phone Number'),
- help_text="e.g., +49 151 12345678"
+ help_text=_("e.g., +49 151 12345678")
)
- language = LanguageField(null=True)
+ language = LanguageField(null=True, verbose_name=_('Language'))
- gender = models.CharField(max_length=20, choices=GenderChoices.choices, null=True, blank=True, verbose_name=_('Gender'), help_text="Select the user's gender.")
- user_type = models.CharField(max_length=20, choices=UserType.choices, default=UserType.CLIENT, verbose_name="User Type", help_text="Type of the user.")
- date_joined = models.DateTimeField(auto_now_add=True, verbose_name="Date Joined", help_text="The date and time the user registered.")
+ gender = models.CharField(max_length=20, choices=GenderChoices.choices, null=True, blank=True, verbose_name=_('Gender'), help_text=_("Select the user's gender."))
+ user_type = models.CharField(max_length=20, choices=UserType.choices, default=UserType.CLIENT, verbose_name=_("User Type"), help_text=_("Type of the user."))
+ date_joined = models.DateTimeField(auto_now_add=True, verbose_name=_("Date Joined"), help_text=_("The date and time the user registered."))
city = models.CharField(verbose_name=_('City'), max_length=255, null=True, blank=True)
country = models.CharField(max_length=255, verbose_name=_('country'), null=True, blank=True)
device_id = models.CharField(verbose_name=_('device id'), max_length=255, null=True, blank=True)
- device_os = models.CharField(choices=DeviceOs.choices, null=True, max_length=16)
+ device_os = models.CharField(choices=DeviceOs.choices, null=True, max_length=16, verbose_name=_('device os'))
user_agent = models.TextField(verbose_name=_('user agent'), null=True, blank=True)
client_ip = models.TextField(verbose_name=_('client ip'), null=True, blank=True)
- fcm = models.CharField(max_length=512, null=True, blank=True)
- slug = models.SlugField(max_length=255, unique=True, null=True, blank=True)
+ fcm = models.CharField(max_length=512, null=True, blank=True, verbose_name=_('fcm'))
+ slug = models.SlugField(max_length=255, unique=True, null=True, blank=True, verbose_name=_('slug'))
experience_years = models.PositiveIntegerField(default=0, verbose_name=_('Experience years'))
- is_staff = models.BooleanField(default=False)
- is_active = models.BooleanField(default=True, verbose_name="Active", help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.")
- deleted_at = models.DateTimeField(null=True, blank=True)
- info = models.TextField(verbose_name="Info", null=True, blank=True)
- skill = models.CharField(max_length=512, null=True, blank=True)
+ is_staff = models.BooleanField(default=False, verbose_name=_('is staff'))
+ is_active = models.BooleanField(default=True, verbose_name=_("Active"), help_text=_("Designates whether this user should be treated as active. Unselect this instead of deleting accounts."))
+ deleted_at = models.DateTimeField(null=True, blank=True, verbose_name=_('deleted at'))
+ info = models.TextField(verbose_name=_("Info"), null=True, blank=True)
+ skill = models.CharField(max_length=512, null=True, blank=True, verbose_name=_('skill'))
objects = UserManager()
@@ -286,8 +286,8 @@ class User(AbstractUser):
class Meta:
ordering = ("-id",)
- verbose_name = "All Users"
- verbose_name_plural = "All Users"
+ verbose_name = _("User")
+ verbose_name_plural = _("Users")
unique_together = (
'email',
)
@@ -295,26 +295,35 @@ class User(AbstractUser):
class LoginHistory(models.Model):
- user = models.ForeignKey("account.User", on_delete=models.CASCADE, related_name='login_history')
+ user = models.ForeignKey("account.User", on_delete=models.CASCADE, related_name='login_history', verbose_name=_('user'))
lat = models.FloatField(verbose_name=_('lat'), null=True, blank=True)
lon = models.FloatField(verbose_name=_('lon'), null=True, blank=True)
country = models.CharField(max_length=255, verbose_name=_('country'), null=True, blank=True)
city = models.CharField(max_length=255, verbose_name=_('city'), null=True, blank=True)
- ip = models.CharField(max_length=255, null=True)
- timezone = models.CharField(max_length=100, null=True, blank=True)
+ ip = models.CharField(max_length=255, null=True, verbose_name=_('ip'))
+ timezone = models.CharField(max_length=100, null=True, blank=True, verbose_name=_('timezone'))
user_agent = models.TextField(verbose_name=_('user agent'), null=True, blank=True)
- device_os = models.CharField(max_length=16, null=True, blank=True)
- at_time = models.DateTimeField(auto_now_add=True)
+ device_os = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Device os'))
+ at_time = models.DateTimeField(auto_now_add=True, verbose_name=_('at time'))
+
+ class Meta:
+ verbose_name = _('Login History')
+ verbose_name_plural = _('Login Histories')
class LocationHistory(models.Model):
- user = models.ForeignKey("account.User", on_delete=models.CASCADE, related_name='location_history')
+ user = models.ForeignKey("account.User", on_delete=models.CASCADE, related_name='location_history', verbose_name=_('user'))
lat = models.FloatField(verbose_name=_('lat'))
lon = models.FloatField(verbose_name=_('lon'))
country = models.CharField(max_length=255, verbose_name=_('country'), null=True, blank=True)
city = models.CharField(max_length=255, verbose_name=_('city'), null=True, blank=True)
- selected_manually = models.BooleanField(null=True, blank=True)
- ip = models.CharField(max_length=255, null=True, blank=True)
- timezone = models.CharField(null=True, blank=True, max_length=60)
- at_time = models.DateTimeField(auto_now_add=True)
+ selected_manually = models.BooleanField(null=True, blank=True, verbose_name=_('selected manually'))
+ ip = models.CharField(max_length=255, null=True, blank=True, verbose_name=_('ip'))
+ timezone = models.CharField(null=True, blank=True, max_length=60, verbose_name=_('timezone'))
+ at_time = models.DateTimeField(auto_now_add=True, verbose_name=_('at time'))
+
+ class Meta:
+ verbose_name = _('Location History')
+ verbose_name_plural = _('Location History')
+
diff --git a/apps/certificate/migrations/0002_alter_certificate_course_and_more.py b/apps/certificate/migrations/0002_alter_certificate_course_and_more.py
new file mode 100644
index 0000000..ba8c885
--- /dev/null
+++ b/apps/certificate/migrations/0002_alter_certificate_course_and_more.py
@@ -0,0 +1,36 @@
+# Generated by Django 5.2.12 on 2026-05-04 12:53
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('account', '0003_alter_clientuser_options_and_more'),
+ ('certificate', '0001_initial'),
+ ('course', '0006_alter_course_professor_alter_course_video_file_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='certificate',
+ name='course',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_certificates', to='course.course', verbose_name='Course'),
+ ),
+ migrations.AlterField(
+ model_name='certificate',
+ name='created_at',
+ field=models.DateTimeField(auto_now_add=True, verbose_name='Created at'),
+ ),
+ migrations.AlterField(
+ model_name='certificate',
+ name='status',
+ field=models.CharField(choices=[('pending', 'pending'), ('approved', 'approved'), ('canceled', 'canceled')], default='pending', max_length=10, verbose_name='Status'),
+ ),
+ migrations.AlterField(
+ model_name='certificate',
+ name='student',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='certificates', to='account.studentuser', verbose_name='Student'),
+ ),
+ ]
diff --git a/apps/certificate/models.py b/apps/certificate/models.py
index 835f4ed..9a321ee 100644
--- a/apps/certificate/models.py
+++ b/apps/certificate/models.py
@@ -14,12 +14,12 @@ class Certificate(models.Model):
('canceled', _('canceled')),
]
- student = models.ForeignKey(StudentUser, on_delete=models.CASCADE, related_name='certificates')
- course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='course_certificates')
- status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='pending')
+ student = models.ForeignKey(StudentUser, on_delete=models.CASCADE, related_name='certificates', verbose_name=_('Student'))
+ course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='course_certificates', verbose_name=_('Course'))
+ status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='pending', verbose_name=_('Status'))
certificate_file = models.FileField(upload_to='certificates/', null=True, blank=True, verbose_name=_('certificate_file'))
- created_at = models.DateTimeField(auto_now_add=True)
+ created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('Created at'))
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
diff --git a/apps/course/admin/live_session.py b/apps/course/admin/live_session.py
index 01ff51d..9c571fd 100644
--- a/apps/course/admin/live_session.py
+++ b/apps/course/admin/live_session.py
@@ -22,6 +22,15 @@ from django.contrib.auth import get_user_model
User = get_user_model()
+# 🔔 CUSTOM FILTER: Only show active, non-guest users in the right sidebar filter
+class ActiveUserDropdownFilter(MultipleRelatedDropdownFilter):
+ def field_choices(self, field, request, model_admin):
+ return field.get_choices(
+ include_blank=False,
+ limit_choices_to={'is_active': True, 'email__isnull': False}
+ )
+
+
# --- WIDTH ENFORCEMENT & PLACEHOLDER TEXT FOR DROPDOWNS ---
class MinWidthInlineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
@@ -62,7 +71,7 @@ class LiveSessionUserInline(StackedInline):
verbose_name = _("Session User")
verbose_name_plural = _("Session Users")
- # 🔔 FILTER THE USER DROPDOWN TO ONLY SHOW ACTIVE & NON-GUEST USERS
+ # 🔔 FILTER THE USER DROPDOWN IN THE FORM ITSELF
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "user":
kwargs["queryset"] = User.objects.filter(is_active=True, email__isnull=False)
@@ -113,7 +122,7 @@ class LiveSessionUserAdmin(ModelAdmin):
list_display = ("user", "session", "role", "is_online", "entered_at", "exited_at")
list_filter = (
("session", MultipleRelatedDropdownFilter),
- ("user", MultipleRelatedDropdownFilter),
+ ("user", ActiveUserDropdownFilter), # 🔔 APPLIED CUSTOM FILTER HERE!
("role", ChoicesDropdownFilter),
("entered_at", RangeDateFilter),
("is_online", admin.BooleanFieldListFilter),
@@ -134,7 +143,7 @@ class LiveSessionUserAdmin(ModelAdmin):
def get_role_choices(self, request):
return USER_ROLE_CHOICES
- # 🔔 FILTER THE STANDALONE ADMIN FORM AS WELL JUST IN CASE
+ # FILTER THE STANDALONE ADMIN FORM AS WELL JUST IN CASE
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "user":
kwargs["queryset"] = User.objects.filter(is_active=True, email__isnull=False)
diff --git a/apps/course/migrations/0006_alter_course_professor_alter_course_video_file_and_more.py b/apps/course/migrations/0006_alter_course_professor_alter_course_video_file_and_more.py
new file mode 100644
index 0000000..84fe8a8
--- /dev/null
+++ b/apps/course/migrations/0006_alter_course_professor_alter_course_video_file_and_more.py
@@ -0,0 +1,31 @@
+# Generated by Django 5.2.12 on 2026-05-04 12:53
+
+import apps.course.models.course
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('account', '0003_alter_clientuser_options_and_more'),
+ ('course', '0005_alter_course_discount_percentage'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='course',
+ name='professor',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='courses', to='account.professoruser', verbose_name='Professor'),
+ ),
+ migrations.AlterField(
+ model_name='course',
+ name='video_file',
+ field=models.FileField(blank=True, null=True, upload_to=apps.course.models.course.course_file_upload_to, verbose_name='Video File'),
+ ),
+ migrations.AlterField(
+ model_name='course',
+ name='video_link',
+ field=models.CharField(blank=True, max_length=500, null=True, verbose_name='Video Link'),
+ ),
+ ]
diff --git a/apps/course/models/course.py b/apps/course/models/course.py
index 86a6ed2..227c483 100644
--- a/apps/course/models/course.py
+++ b/apps/course/models/course.py
@@ -69,7 +69,8 @@ class Course(models.Model):
professor = models.ForeignKey(
ProfessorUser,
on_delete=models.CASCADE,
- related_name="courses"
+ related_name="courses",
+ verbose_name=_("Professor")
)
thumbnail = models.ImageField(upload_to="courses/thumbnails/", verbose_name=_('Thumbnail'))
@@ -81,9 +82,10 @@ class Course(models.Model):
video_file = models.FileField(
upload_to=course_file_upload_to,
null=True,
- blank=True
+ blank=True,
+ verbose_name=_("Video File")
)
- video_link = models.CharField(max_length=500, null=True, blank=True)
+ video_link = models.CharField(max_length=500, null=True, blank=True, verbose_name=_("Video Link"))
is_online = models.BooleanField(default=False, verbose_name=_('Is Online Course'))
online_link = models.CharField(max_length=500, null=True, blank=True, verbose_name=_('Online Class Link'))
diff --git a/locale/ru/LC_MESSAGES/django.po b/locale/ru/LC_MESSAGES/django.po
index a9f3a04..69068a2 100644
--- a/locale/ru/LC_MESSAGES/django.po
+++ b/locale/ru/LC_MESSAGES/django.po
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-05-03 16:36+0330\n"
+"POT-Creation-Date: 2026-05-04 12:19+0330\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -22,6 +22,7 @@ msgstr ""
"(n%100>=11 && n%100<=14)? 2 : 3);\n"
#: .\apps\account\admin\location.py:21 .\apps\account\admin\location.py:22
+#: .\apps\account\models\user.py:326 .\apps\account\models\user.py:327
msgid "Location History"
msgstr "История местоположений"
@@ -40,14 +41,29 @@ msgstr "Местоположение"
msgid "Date & Time"
msgstr "Дата и время"
+#: .\apps\account\admin\professor.py:22
+msgid "Enter the phone number in international format. Example: +989012023212"
+msgstr "Введите номер телефона в международном формате. Пример: +989012023212"
+
+#: .\apps\account\admin\professor.py:45 .\apps\account\admin\student.py:32
+#, fuzzy
+#| msgid "Other"
+msgid "other"
+msgstr "Другой"
+
+#: .\apps\account\admin\professor.py:49 .\apps\account\admin\student.py:36
+#: .\apps\account\admin\user.py:87
+msgid "Password"
+msgstr "Пароль"
+
#: .\apps\account\admin\professor.py:59 .\apps\account\admin\student.py:45
msgid "Personal info"
msgstr "Личная информация"
#: .\apps\account\admin\professor.py:60 .\apps\account\admin\student.py:46
#: .\apps\account\admin\user.py:91 .\apps\account\admin\user.py:115
-#: .\apps\account\admin\user.py:138 .\apps\account\admin\user.py:401
-#: .\apps\account\admin\user.py:463 .\apps\account\admin\user.py:466
+#: .\apps\account\admin\user.py:138 .\apps\account\admin\user.py:402
+#: .\apps\account\admin\user.py:465 .\apps\account\admin\user.py:468
#: .\templates\admin\filer\folder\directory_table.html:129
msgid "Permissions"
msgstr "Права доступа"
@@ -57,18 +73,37 @@ msgstr "Права доступа"
msgid "Important dates"
msgstr "Важные даты"
+#: .\apps\account\admin\professor.py:75
+#, fuzzy, python-brace-format
+#| msgid "A user with this email already exists."
+msgid "A professor with the email {email} already exists."
+msgstr "Пользователь с таким email уже существует."
+
+#: .\apps\account\admin\professor.py:96
+#, python-brace-format
+msgid "The user with email {email} has been converted to a professor."
+msgstr "Пользователь с email {email} был преобразован в профессора."
+
+#: .\apps\account\admin\professor.py:109 .\apps\account\admin\student.py:51
+#: .\apps\account\models\user.py:51
+msgid "Phone Number"
+msgstr "Номер телефона"
+
#: .\apps\account\admin\student.py:55
msgid "Enrolled Courses"
msgstr "Записанные курсы"
+
+#: .\apps\account\admin\student.py:59
+#, fuzzy, python-brace-format
+#| msgid "courses"
+msgid "{count} courses"
+msgstr "{count} курсов"
+
#: .\apps\account\admin\user.py:47
msgid "A user with this email already exists."
msgstr "Пользователь с таким email уже существует."
-#: .\apps\account\admin\user.py:87
-msgid "Password"
-msgstr "Пароль"
-
#: .\apps\account\admin\user.py:99 .\apps\account\admin\user.py:143
#: .\apps\blog\admin.py:67 .\apps\blog\admin.py:109
msgid "Basic Information"
@@ -87,6 +122,7 @@ msgid "Authentication"
msgstr "Аутентификация"
#: .\apps\account\admin\user.py:159 .\apps\account\admin\user.py:196
+#: .\apps\account\models\user.py:58
msgid "Date Joined"
msgstr "Дата регистрации"
@@ -106,13 +142,14 @@ msgstr "Участие в курсе"
msgid "Course Participations"
msgstr "Участия в курсах"
-#: .\apps\account\admin\user.py:216 .\apps\course\models\course.py:95
+#: .\apps\account\admin\user.py:216 .\apps\course\models\course.py:98
#: .\templates\course\course_stats.html:106
msgid "Course Status"
msgstr "Статус курса"
-#: .\apps\account\admin\user.py:222 .\apps\account\admin\user.py:407
-#: .\apps\course\admin\course.py:287
+#: .\apps\account\admin\user.py:222 .\apps\account\admin\user.py:408
+#: .\apps\account\models\user.py:22 .\apps\course\admin\course.py:287
+#: .\apps\course\models\course.py:73
msgid "Professor"
msgstr "Профессор"
@@ -120,7 +157,8 @@ msgstr "Профессор"
msgid "password"
msgstr "пароль"
-#: .\apps\account\admin\user.py:257 .\apps\course\admin\course.py:485
+#: .\apps\account\admin\user.py:257 .\apps\account\models\user.py:24
+#: .\apps\certificate\models.py:17 .\apps\course\admin\course.py:485
#: .\apps\course\models\lesson.py:125 .\apps\course\models\participant.py:13
#: .\templates\course\course_analytics.html:186
msgid "Student"
@@ -130,35 +168,44 @@ msgstr "Студент"
msgid "Age"
msgstr "Возраст"
-#: .\apps\account\admin\user.py:283 .\apps\account\admin\user.py:423
-#: .\apps\course\admin\course.py:64 .\apps\course\models\course.py:154
+#: .\apps\account\admin\user.py:281
+#, python-brace-format
+msgid "Born on {date}"
+msgstr "Дата рождения: {date}"
+
+#: .\apps\account\admin\user.py:283 .\apps\account\admin\user.py:424
+#: .\apps\course\admin\course.py:64 .\apps\course\models\course.py:157
#: .\config\settings\base.py:480 .\config\settings\base.py:630
#: .\config\settings\base.py:642
msgid "Courses"
msgstr "Курсы"
-#: .\apps\account\admin\user.py:307 .\apps\account\admin\user.py:446
-msgid "courses"
-msgstr "курсы"
+#: .\apps\account\admin\user.py:307 .\apps\account\admin\user.py:447
+#, fuzzy, python-brace-format
+#| msgid "Total Score"
+msgid "{total} courses"
+msgstr "Общий балл"
-#: .\apps\account\admin\user.py:320 .\apps\course\admin\course.py:35
+#: .\apps\account\admin\user.py:321 .\apps\course\admin\course.py:35
msgid "Course Categories"
msgstr "Категории курсов"
-#: .\apps\account\admin\user.py:332 .\apps\course\admin\course.py:51
+#: .\apps\account\admin\user.py:333 .\apps\course\admin\course.py:51
msgid "Edit"
msgstr "Редактировать"
-#: .\apps\account\admin\user.py:338
+#: .\apps\account\admin\user.py:339
msgid "Select Existing User"
msgstr "Выбрать существующего пользователя"
-#: .\apps\account\admin\user.py:339
+#: .\apps\account\admin\user.py:340
msgid "Choose an existing user to upgrade to Professor."
msgstr "Выберите существующего пользователя, чтобы назначить его профессором."
-#: .\apps\account\admin\user.py:469
-msgid "permissions"
+#: .\apps\account\admin\user.py:471
+#, fuzzy, python-brace-format
+#| msgid "permissions"
+msgid "{count} permissions"
msgstr "права доступа"
#: .\apps\account\middleware\admin_access.py:107
@@ -169,6 +216,77 @@ msgstr "У вас ограниченный доступ как у професс
msgid "You do not have permission to access this page."
msgstr "У вас нет прав для доступа к этой странице."
+#: .\apps\account\models\groups.py:23
+#, fuzzy
+#| msgid "Professors"
+msgid "Professor User"
+msgstr "Профессора"
+
+#: .\apps\account\models\groups.py:24
+#, fuzzy
+#| msgid "Professors"
+msgid "Professor Users"
+msgstr "Профессора"
+
+#: .\apps\account\models\groups.py:43 .\apps\account\models\user.py:289
+#: .\apps\chat\models.py:166 .\apps\course\models\live_session.py:83
+#: .\apps\quiz\models\participant.py:11 .\apps\transaction\models.py:30
+msgid "User"
+msgstr "Пользователь"
+
+#: .\apps\account\models\groups.py:44 .\apps\account\models\user.py:290
+#: .\config\settings\base.py:444
+msgid "Users"
+msgstr "Пользователи"
+
+#: .\apps\account\models\groups.py:61
+#, fuzzy
+#| msgid "Session User"
+msgid "Admin User"
+msgstr "Пользователь сессии"
+
+#: .\apps\account\models\groups.py:62
+#, fuzzy
+#| msgid "All Users"
+msgid "Admin Users"
+msgstr "Все пользователи"
+
+#: .\apps\account\models\groups.py:78
+#, fuzzy
+#| msgid "Session User"
+msgid "Super Admin User"
+msgstr "Пользователь сессии"
+
+#: .\apps\account\models\groups.py:79
+#, fuzzy
+#| msgid "Session Users"
+msgid "Super Admin Users"
+msgstr "Пользователи сессии"
+
+#: .\apps\account\models\groups.py:95
+#, fuzzy
+#| msgid "Students"
+msgid "Student User"
+msgstr "Студенты"
+
+#: .\apps\account\models\groups.py:96
+#, fuzzy
+#| msgid "Students"
+msgid "Student Users"
+msgstr "Студенты"
+
+#: .\apps\account\models\notification.py:7
+#, fuzzy
+#| msgid "Imam Javad Site"
+msgid "Imam Javad"
+msgstr "Сайт Имам Джавад"
+
+#: .\apps\account\models\notification.py:8
+#, fuzzy
+#| msgid "Dovoodi Site"
+msgid "Doboodi"
+msgstr "Сайт Довуди"
+
#: .\apps\account\models\notification.py:10 .\apps\article\models.py:9
#: .\apps\article\models.py:184 .\apps\dobodbi_calendar\models.py:20
#: .\apps\podcast\models.py:9 .\apps\podcast\models.py:128
@@ -180,7 +298,8 @@ msgstr "название"
msgid "message"
msgstr "сообщение"
-#: .\apps\account\models\notification.py:12 .\apps\library\models.py:171
+#: .\apps\account\models\notification.py:12 .\apps\account\models\user.py:298
+#: .\apps\account\models\user.py:315 .\apps\library\models.py:171
#: .\apps\podcast\models.py:255
msgid "user"
msgstr "пользователь"
@@ -240,6 +359,52 @@ msgstr "создано"
msgid "updated at"
msgstr "обновлено"
+#: .\apps\account\models\notification.py:24
+#, fuzzy
+#| msgid "Location"
+msgid "Notification"
+msgstr "Местоположение"
+
+#: .\apps\account\models\notification.py:25
+#, fuzzy
+#| msgid "Location"
+msgid "Notifications"
+msgstr "Местоположение"
+
+#: .\apps\account\models\user.py:17
+msgid "android"
+msgstr ""
+
+#: .\apps\account\models\user.py:18
+msgid "apple"
+msgstr ""
+
+#: .\apps\account\models\user.py:19
+msgid "web"
+msgstr "веб"
+
+#: .\apps\account\models\user.py:23
+#, fuzzy
+#| msgid "client ip"
+msgid "Client"
+msgstr "ip клиента"
+
+#: .\apps\account\models\user.py:25
+msgid "Admin"
+msgstr "Админ"
+
+#: .\apps\account\models\user.py:26
+msgid "Super Admin"
+msgstr "Супер Админ"
+
+#: .\apps\account\models\user.py:29 .\apps\transaction\models.py:66
+msgid "Male"
+msgstr "Мужской"
+
+#: .\apps\account\models\user.py:30 .\apps\transaction\models.py:67
+msgid "Female"
+msgstr "Женский"
+
#: .\apps\account\models\user.py:35
msgid "Username"
msgstr "Имя пользователя"
@@ -273,20 +438,45 @@ msgstr "Введите полное имя пользователя."
msgid "birthdate"
msgstr "дата рождения"
-#: .\apps\account\models\user.py:51
-msgid "Phone Number"
-msgstr "Номер телефона"
+#: .\apps\account\models\user.py:46
+msgid "Avatar"
+msgstr "Аватар пользователя"
+
+#: .\apps\account\models\user.py:52
+msgid "e.g., +49 151 12345678"
+msgstr "Например, +49 151 12345678"
+
+#: .\apps\account\models\user.py:54 .\apps\blog\models.py:199
+#: .\apps\hadis\models\reference.py:65 .\apps\library\models.py:119
+msgid "Language"
+msgstr "Язык"
#: .\apps\account\models\user.py:56 .\apps\transaction\models.py:79
msgid "Gender"
msgstr "Пол"
+#: .\apps\account\models\user.py:56 .\apps\transaction\models.py:79
+msgid "Select the user's gender."
+msgstr "Выберите пол пользователя."
+
+#: .\apps\account\models\user.py:57 .\utils\unfold_translations.py:80
+msgid "User Type"
+msgstr "Тип файла"
+
+#: .\apps\account\models\user.py:57
+msgid "Type of the user."
+msgstr "Введите для поиска..."
+
+#: .\apps\account\models\user.py:58
+msgid "The date and time the user registered."
+msgstr "Дата и время регистрации пользователя."
+
#: .\apps\account\models\user.py:60
msgid "City"
msgstr "Город"
#: .\apps\account\models\user.py:61 .\apps\account\models\user.py:301
-#: .\apps\account\models\user.py:314
+#: .\apps\account\models\user.py:318
msgid "country"
msgstr "страна"
@@ -294,6 +484,12 @@ msgstr "страна"
msgid "device id"
msgstr "id устройства"
+#: .\apps\account\models\user.py:64
+#, fuzzy
+#| msgid "Device os"
+msgid "device os"
+msgstr "id устройства"
+
#: .\apps\account\models\user.py:65 .\apps\account\models\user.py:305
msgid "user agent"
msgstr "user agent"
@@ -302,26 +498,109 @@ msgstr "user agent"
msgid "client ip"
msgstr "ip клиента"
+#: .\apps\account\models\user.py:68
+msgid "fcm"
+msgstr ""
+
+#: .\apps\account\models\user.py:69 .\apps\article\models.py:10
+#: .\apps\hadis\models\hadis.py:14 .\apps\hadis\models\hadis.py:170
+#: .\apps\hadis\models\hadis.py:265 .\apps\hadis\models\hadis.py:490
+#: .\apps\hadis\models\reference.py:70 .\apps\hadis\models\transmitter.py:22
+#: .\apps\hadis\models\transmitter.py:128
+#: .\apps\hadis\models\transmitter.py:237
+#: .\apps\hadis\models\transmitter.py:471
+#: .\apps\hadis\models\transmitter.py:637 .\apps\podcast\models.py:10
+#: .\apps\podcast\models.py:129 .\apps\video\models.py:12
+#: .\apps\video\models.py:145
+msgid "slug"
+msgstr "ярлык (slug)"
+
#: .\apps\account\models\user.py:70
msgid "Experience years"
msgstr "Годы опыта"
+#: .\apps\account\models\user.py:71
+msgid "is staff"
+msgstr "статус хадиса"
+
+#: .\apps\account\models\user.py:72 .\apps\api\models.py:111
+#: .\apps\chat\admin.py:315 .\apps\hadis\models\version.py:10
+#: .\apps\library\admin.py:212 .\apps\quiz\admin\quiz.py:68
+msgid "Active"
+msgstr "Активно"
+
+#: .\apps\account\models\user.py:72
+msgid ""
+"Designates whether this user should be treated as active. Unselect this "
+"instead of deleting accounts."
+msgstr ""
+"Обозначает, должен ли этот пользователь считаться активным. Вместо удаления "
+"учетных записей отключите это."
+
+#: .\apps\account\models\user.py:73
+#, fuzzy
+#| msgid "Deleted At"
+msgid "deleted at"
+msgstr "Удалено в"
+
+#: .\apps\account\models\user.py:74
+msgid "Info"
+msgstr "Инфо"
+
+#: .\apps\account\models\user.py:75
+msgid "skill"
+msgstr "навык"
+
#: .\apps\account\models\user.py:118
msgid "Email is required for all regular users."
msgstr "Email обязателен для всех обычных пользователей."
-#: .\apps\account\models\user.py:299 .\apps\account\models\user.py:312
+#: .\apps\account\models\user.py:299 .\apps\account\models\user.py:316
msgid "lat"
msgstr "широта"
-#: .\apps\account\models\user.py:300 .\apps\account\models\user.py:313
+#: .\apps\account\models\user.py:300 .\apps\account\models\user.py:317
msgid "lon"
msgstr "долгота"
-#: .\apps\account\models\user.py:302 .\apps\account\models\user.py:315
+#: .\apps\account\models\user.py:302 .\apps\account\models\user.py:319
msgid "city"
msgstr "город"
+#: .\apps\account\models\user.py:303 .\apps\account\models\user.py:321
+msgid "ip"
+msgstr "Ай Пи"
+
+#: .\apps\account\models\user.py:304 .\apps\account\models\user.py:322
+msgid "timezone"
+msgstr "часовой пояс"
+
+#: .\apps\account\models\user.py:306
+msgid "Device os"
+msgstr "id устройства"
+
+#: .\apps\account\models\user.py:307 .\apps\account\models\user.py:323
+#, fuzzy
+#| msgid "total time"
+msgid "at time"
+msgstr "общее время"
+
+#: .\apps\account\models\user.py:310
+#, fuzzy
+#| msgid "Location History"
+msgid "Login History"
+msgstr "История местоположений"
+
+#: .\apps\account\models\user.py:311
+#, fuzzy
+#| msgid "Location History"
+msgid "Login Histories"
+msgstr "История местоположений"
+
+#: .\apps\account\models\user.py:320
+msgid "selected manually"
+msgstr "выбрано вручную"
+
#: .\apps\account\templates\account\group_help_text.html:5
msgid "Driver before template"
msgstr "Водитель до шаблона"
@@ -343,18 +622,24 @@ msgid "Total races"
msgstr "Всего гонок"
#: .\apps\account\templates\account\user_list_section.html:8
-msgid "Total Actice Users"
+#: .\utils\unfold_translations.py:83
+#, fuzzy
+#| msgid "Total Actice Users"
+msgid "Total Active Users"
msgstr "Всего активных пользователей"
#: .\apps\account\templates\account\user_list_section.html:16
+#: .\utils\unfold_translations.py:84
msgid "Total Guest Users"
msgstr "Всего гостевых пользователей"
#: .\apps\account\templates\account\user_list_section.html:22
+#: .\utils\unfold_translations.py:85
msgid "Total Students"
msgstr "Всего студентов"
#: .\apps\account\templates\account\user_list_section.html:28
+#: .\utils\unfold_translations.py:86
msgid "Total Professors"
msgstr "Всего преподавателей"
@@ -444,7 +729,7 @@ msgid "Application APK file"
msgstr "APK файл приложения"
#: .\apps\api\models.py:84 .\apps\blog\models.py:195 .\apps\chat\models.py:28
-#: .\apps\course\admin\course.py:397 .\apps\course\models\course.py:172
+#: .\apps\course\admin\course.py:397 .\apps\course\models\course.py:175
#: .\apps\hadis\admin\hadis.py:649 .\apps\hadis\models\category.py:16
#: .\apps\hadis\models\category.py:78 .\apps\hadis\models\hadis.py:173
#: .\apps\hadis\models\hadis.py:268 .\apps\hadis\models\hadis.py:426
@@ -484,21 +769,15 @@ msgstr "Загрузки из Google Play"
msgid "Total number of downloads on Google Play"
msgstr "Общее количество загрузок в Google Play"
-#: .\apps\api\models.py:111 .\apps\chat\admin.py:315
-#: .\apps\hadis\models\version.py:10 .\apps\library\admin.py:212
-#: .\apps\quiz\admin\quiz.py:68
-msgid "Active"
-msgstr "Активно"
-
#: .\apps\api\models.py:112
msgid "Is this version active?"
msgstr "Эта версия активна?"
#: .\apps\api\models.py:122 .\apps\blog\models.py:38 .\apps\blog\models.py:159
#: .\apps\chat\models.py:50 .\apps\chat\models.py:126
-#: .\apps\course\models\course.py:116 .\apps\course\models\course.py:174
-#: .\apps\course\models\course.py:192 .\apps\course\models\course.py:223
-#: .\apps\course\models\course.py:247 .\apps\course\models\lesson.py:36
+#: .\apps\course\models\course.py:119 .\apps\course\models\course.py:177
+#: .\apps\course\models\course.py:195 .\apps\course\models\course.py:226
+#: .\apps\course\models\course.py:250 .\apps\course\models\lesson.py:36
#: .\apps\course\models\lesson.py:62 .\apps\course\models\live_session.py:47
#: .\apps\course\models\live_session.py:109
#: .\apps\course\models\live_session.py:171
@@ -571,6 +850,7 @@ msgstr "Содержимое статей"
#: .\apps\video\admin.py:83 .\utils\keyval_field.py:39
#: .\utils\keyval_field.py:59 .\utils\keyval_field.py:76
#: .\utils\keyval_field.py:139 .\utils\keyval_field.py:167 .\utils\schema.py:51
+#: .\utils\unfold_translations.py:74
msgid "Title"
msgstr "Название"
@@ -600,11 +880,11 @@ msgstr "Файл"
#: .\apps\article\admin.py:210 .\apps\bookmark\admin.py:42
#: .\apps\bookmark\admin.py:112 .\apps\certificate\admin.py:30
-#: .\apps\chat\admin.py:257 .\apps\chat\admin.py:311
-#: .\apps\course\admin\live_session.py:158 .\apps\library\admin.py:68
-#: .\apps\library\admin.py:207 .\apps\podcast\admin.py:160
-#: .\apps\quiz\admin\quiz.py:65 .\apps\quiz\models\quiz.py:13
-#: .\apps\video\admin.py:169
+#: .\apps\certificate\models.py:19 .\apps\chat\admin.py:257
+#: .\apps\chat\admin.py:311 .\apps\course\admin\live_session.py:167
+#: .\apps\library\admin.py:68 .\apps\library\admin.py:207
+#: .\apps\podcast\admin.py:160 .\apps\quiz\admin\quiz.py:65
+#: .\apps\quiz\models\quiz.py:13 .\apps\video\admin.py:169
msgid "Status"
msgstr "Статус"
@@ -623,18 +903,6 @@ msgstr "Содержимое"
msgid "Parts"
msgstr "Части"
-#: .\apps\article\models.py:10 .\apps\hadis\models\hadis.py:14
-#: .\apps\hadis\models\hadis.py:170 .\apps\hadis\models\hadis.py:265
-#: .\apps\hadis\models\hadis.py:490 .\apps\hadis\models\reference.py:70
-#: .\apps\hadis\models\transmitter.py:22 .\apps\hadis\models\transmitter.py:128
-#: .\apps\hadis\models\transmitter.py:237
-#: .\apps\hadis\models\transmitter.py:471
-#: .\apps\hadis\models\transmitter.py:637 .\apps\podcast\models.py:10
-#: .\apps\podcast\models.py:129 .\apps\video\models.py:12
-#: .\apps\video\models.py:145
-msgid "slug"
-msgstr "ярлык (slug)"
-
#: .\apps\article\models.py:12 .\apps\article\models.py:42
#: .\apps\article\models.py:107 .\apps\article\models.py:188
#: .\apps\hadis\models\hadis.py:16 .\apps\hadis\models\hadis.py:142
@@ -804,9 +1072,9 @@ msgstr "Содержимое"
#: .\apps\blog\admin.py:77 .\apps\blog\admin.py:115 .\apps\bookmark\admin.py:45
#: .\apps\bookmark\admin.py:115 .\apps\certificate\admin.py:24
#: .\apps\chat\admin.py:150 .\apps\chat\admin.py:261
-#: .\apps\course\admin\live_session.py:108
-#: .\apps\course\admin\live_session.py:131
-#: .\apps\course\admin\live_session.py:159 .\apps\hadis\admin\hadis.py:611
+#: .\apps\course\admin\live_session.py:117
+#: .\apps\course\admin\live_session.py:140
+#: .\apps\course\admin\live_session.py:168 .\apps\hadis\admin\hadis.py:611
#: .\apps\hadis\admin\hadis.py:687 .\apps\hadis\admin\hadis.py:719
#: .\apps\hadis\admin\hadis.py:762 .\apps\hadis\admin\hadis.py:814
#: .\apps\hadis\admin\hadis.py:943 .\apps\hadis\admin\reference.py:512
@@ -817,7 +1085,7 @@ msgstr "Содержимое"
msgid "Timestamps"
msgstr "Метки времени"
-#: .\apps\blog\models.py:16 .\apps\course\models\course.py:74
+#: .\apps\blog\models.py:16 .\apps\course\models\course.py:76
#: .\apps\course\models\live_session.py:165
msgid "Thumbnail"
msgstr "Миниатюра"
@@ -924,11 +1192,6 @@ msgstr ""
"описывает и резюмирует содержимое страницы для пользователей и поисковых "
"систем"
-#: .\apps\blog\models.py:199 .\apps\hadis\models\reference.py:65
-#: .\apps\library\models.py:119
-msgid "Language"
-msgstr "Язык"
-
#: .\apps\blog\models.py:203
msgid "Blog SEO"
msgstr "SEO блога"
@@ -961,10 +1224,27 @@ msgstr "одобрено"
msgid "canceled"
msgstr "отменено"
+#: .\apps\certificate\models.py:18 .\apps\chat\models.py:32
+#: .\apps\course\admin\course.py:271 .\apps\course\admin\course.py:503
+#: .\apps\course\models\course.py:156 .\apps\course\models\course.py:192
+#: .\apps\course\models\course.py:247 .\apps\course\models\lesson.py:55
+#: .\apps\course\models\live_session.py:13
+#: .\apps\course\models\participant.py:19 .\apps\transaction\models.py:31
+msgid "Course"
+msgstr "Курс"
+
#: .\apps\certificate\models.py:20
msgid "certificate_file"
msgstr "файл_сертификата"
+#: .\apps\certificate\models.py:22 .\apps\course\models\course.py:118
+#: .\apps\course\models\course.py:176 .\apps\course\models\course.py:194
+#: .\apps\course\models\course.py:225 .\apps\course\models\course.py:249
+#: .\apps\course\models\lesson.py:35 .\apps\course\models\lesson.py:61
+#: .\apps\course\models\lesson.py:135 .\apps\transaction\models.py:36
+msgid "Created at"
+msgstr "Дата создания"
+
#: .\apps\chat\admin.py:77
msgid "Recent Message"
msgstr "Последнее сообщение"
@@ -1027,7 +1307,7 @@ msgstr "Статусы прочтения"
msgid "Message Information"
msgstr "Информация о сообщении"
-#: .\apps\chat\admin.py:249 .\apps\course\models\course.py:236
+#: .\apps\chat\admin.py:249 .\apps\course\models\course.py:239
msgid "Attachments"
msgstr "Вложения"
@@ -1044,6 +1324,7 @@ msgid "Content Preview"
msgstr "Предпросмотр контента"
#: .\apps\chat\admin.py:295
+#, python-format
msgid "%(type)s content"
msgstr "Содержимое (%(type)s)"
@@ -1074,8 +1355,8 @@ msgstr "Размер"
msgid "{} bytes"
msgstr "{} байт"
-#: .\apps\chat\admin.py:326 .\apps\course\models\course.py:235
-#: .\apps\course\models\course.py:245
+#: .\apps\chat\admin.py:326 .\apps\course\models\course.py:238
+#: .\apps\course\models\course.py:248
msgid "Attachment"
msgstr "Вложение"
@@ -1146,14 +1427,6 @@ msgstr "Очистка данных чата успешно завершена!"
msgid "Room Name"
msgstr "Название комнаты"
-#: .\apps\chat\models.py:32 .\apps\course\admin\course.py:271
-#: .\apps\course\admin\course.py:503 .\apps\course\models\course.py:153
-#: .\apps\course\models\course.py:189 .\apps\course\models\course.py:244
-#: .\apps\course\models\lesson.py:55 .\apps\course\models\live_session.py:13
-#: .\apps\course\models\participant.py:19 .\apps\transaction\models.py:31
-msgid "Course"
-msgstr "Курс"
-
#: .\apps\chat\models.py:37 .\utils\unfold_translations.py:29
msgid "Initiator"
msgstr "Инициатор"
@@ -1248,11 +1521,6 @@ msgstr "Сообщение чата"
msgid "Chat Messages"
msgstr "Сообщения чата"
-#: .\apps\chat\models.py:166 .\apps\course\models\live_session.py:83
-#: .\apps\quiz\models\participant.py:11 .\apps\transaction\models.py:30
-msgid "User"
-msgstr "Пользователь"
-
#: .\apps\chat\models.py:172
msgid "Message"
msgstr "Сообщение"
@@ -1289,15 +1557,15 @@ msgstr "Это поле обязательно для заполнения и н
msgid "This field is required."
msgstr "Это поле обязательно."
-#: .\apps\course\admin\course.py:125 .\apps\course\admin\live_session.py:43
+#: .\apps\course\admin\course.py:125 .\apps\course\admin\live_session.py:52
msgid "Select a value"
msgstr "Выберите значение"
-#: .\apps\course\admin\course.py:135 .\apps\course\models\course.py:266
+#: .\apps\course\admin\course.py:135 .\apps\course\models\course.py:269
msgid "Course Attachment"
msgstr "Вложение курса"
-#: .\apps\course\admin\course.py:136 .\apps\course\models\course.py:267
+#: .\apps\course\admin\course.py:136 .\apps\course\models\course.py:270
#: .\config\settings\base.py:492
msgid "Course Attachments"
msgstr "Вложения курсов"
@@ -1318,7 +1586,7 @@ msgstr "Выберите студента"
msgid "Settings & Status"
msgstr "Настройки и статус"
-#: .\apps\course\admin\course.py:251 .\apps\course\admin\live_session.py:82
+#: .\apps\course\admin\course.py:251 .\apps\course\admin\live_session.py:91
msgid "Media"
msgstr "Медиа"
@@ -1384,31 +1652,31 @@ msgstr "Продолжительность"
msgid "min"
msgstr "мин"
-#: .\apps\course\admin\live_session.py:56 .\apps\course\models\course.py:113
+#: .\apps\course\admin\live_session.py:65 .\apps\course\models\course.py:116
msgid "Timing"
msgstr "Расписание"
-#: .\apps\course\admin\live_session.py:62
+#: .\apps\course\admin\live_session.py:71
msgid "Session User"
msgstr "Пользователь сессии"
-#: .\apps\course\admin\live_session.py:63 .\config\settings\base.py:521
+#: .\apps\course\admin\live_session.py:72 .\config\settings\base.py:521
msgid "Session Users"
msgstr "Пользователи сессии"
-#: .\apps\course\admin\live_session.py:88
+#: .\apps\course\admin\live_session.py:97
msgid "Session Recording"
msgstr "Запись сессии"
-#: .\apps\course\admin\live_session.py:89 .\config\settings\base.py:527
+#: .\apps\course\admin\live_session.py:98 .\config\settings\base.py:527
msgid "Session Recordings"
msgstr "Записи сессий"
-#: .\apps\course\admin\live_session.py:130
+#: .\apps\course\admin\live_session.py:139
msgid "Session Timing"
msgstr "Время сессии"
-#: .\apps\course\admin\live_session.py:157 .\apps\hadis\admin\category.py:198
+#: .\apps\course\admin\live_session.py:166 .\apps\hadis\admin\category.py:198
msgid "Files"
msgstr "Файлы"
@@ -1438,161 +1706,160 @@ msgstr ", "
msgid "Course data clearing completed"
msgstr "Очистка данных курсов завершена"
-#: .\apps\course\models\course.py:29
+#: .\apps\course\models\course.py:30
msgid "Category Name"
msgstr "Название категории"
-#: .\apps\course\models\course.py:48
+#: .\apps\course\models\course.py:49
msgid "Beginner"
msgstr "Начинающий"
-#: .\apps\course\models\course.py:49
+#: .\apps\course\models\course.py:50
msgid "Mid Level"
msgstr "Средний уровень"
-#: .\apps\course\models\course.py:50
+#: .\apps\course\models\course.py:51
msgid "Advanced"
msgstr "Продвинутый"
-#: .\apps\course\models\course.py:53 .\apps\library\admin.py:216
+#: .\apps\course\models\course.py:54 .\apps\library\admin.py:216
#: .\apps\quiz\admin\quiz.py:69
msgid "Inactive"
msgstr "Неактивно"
-#: .\apps\course\models\course.py:54
+#: .\apps\course\models\course.py:55
msgid "Upcoming"
msgstr "Предстоящий"
-#: .\apps\course\models\course.py:55
+#: .\apps\course\models\course.py:56
msgid "Registering"
msgstr "Идет регистрация"
-#: .\apps\course\models\course.py:56
+#: .\apps\course\models\course.py:57
msgid "Ongoing"
msgstr "Текущий"
-#: .\apps\course\models\course.py:57
+#: .\apps\course\models\course.py:58
msgid "Finished"
msgstr "Завершен"
-#: .\apps\course\models\course.py:60 .\apps\course\models\lesson.py:21
+#: .\apps\course\models\course.py:61 .\apps\course\models\lesson.py:21
msgid "Youtube Link"
msgstr "Ссылка на YouTube"
-#: .\apps\course\models\course.py:61 .\apps\course\models\lesson.py:22
+#: .\apps\course\models\course.py:62 .\apps\course\models\course.py:86
+#: .\apps\course\models\lesson.py:22
msgid "Video File"
msgstr "Видеофайл"
-#: .\apps\course\models\course.py:65
+#: .\apps\course\models\course.py:66
msgid "Course Title"
msgstr "Название курса"
-#: .\apps\course\models\course.py:67 .\apps\library\models.py:92
+#: .\apps\course\models\course.py:68 .\apps\library\models.py:92
msgid "Category"
msgstr "Категория"
-#: .\apps\course\models\course.py:78
+#: .\apps\course\models\course.py:80
msgid "Preview Video Type (YouTube Link or File Upload)"
msgstr "Тип превью-видео (ссылка на YouTube или загрузка файла)"
-#: .\apps\course\models\course.py:87
+#: .\apps\course\models\course.py:88 .\utils\unfold_translations.py:71
+#, fuzzy
+#| msgid "Video File"
+msgid "Video Link"
+msgstr "Видеофайл"
+
+#: .\apps\course\models\course.py:90
msgid "Is Online Course"
msgstr "Это онлайн-курс"
-#: .\apps\course\models\course.py:88
+#: .\apps\course\models\course.py:91
msgid "Online Class Link"
msgstr "Ссылка на онлайн-занятие"
-#: .\apps\course\models\course.py:89
+#: .\apps\course\models\course.py:92
msgid "Course Level"
msgstr "Уровень курса"
-#: .\apps\course\models\course.py:90
+#: .\apps\course\models\course.py:93
msgid "Duration (in hours)"
msgstr "Продолжительность (в часах)"
-#: .\apps\course\models\course.py:91
+#: .\apps\course\models\course.py:94
msgid "Number of Lessons"
msgstr "Количество уроков"
-#: .\apps\course\models\course.py:93
+#: .\apps\course\models\course.py:96
msgid "Course Description"
msgstr "Описание курса"
-#: .\apps\course\models\course.py:94
+#: .\apps\course\models\course.py:97
msgid "Short Description"
msgstr "Краткое описание"
-#: .\apps\course\models\course.py:96
+#: .\apps\course\models\course.py:99
msgid "Is Free"
msgstr "Бесплатный"
-#: .\apps\course\models\course.py:97
+#: .\apps\course\models\course.py:100
msgid "Course Price"
msgstr "Цена курса"
-#: .\apps\course\models\course.py:98
+#: .\apps\course\models\course.py:101
msgid "Discount Percentage"
msgstr "Процент скидки"
-#: .\apps\course\models\course.py:100
+#: .\apps\course\models\course.py:103
msgid "Course Final Price"
msgstr "Итоговая цена курса"
-#: .\apps\course\models\course.py:101
+#: .\apps\course\models\course.py:104
msgid ""
"This field is automatically calculated based on the discount percentage."
msgstr "Это поле рассчитывается автоматически на основе процента скидки."
-#: .\apps\course\models\course.py:106
+#: .\apps\course\models\course.py:109
msgid "Lock Group Chat"
msgstr "Заблокировать групповой чат"
-#: .\apps\course\models\course.py:110
+#: .\apps\course\models\course.py:113
msgid "Lock Private Chats with Professor"
msgstr "Заблокировать личные чаты с профессором"
-#: .\apps\course\models\course.py:114
+#: .\apps\course\models\course.py:117
msgid "Course features"
msgstr "Особенности курса"
-#: .\apps\course\models\course.py:115 .\apps\course\models\course.py:173
-#: .\apps\course\models\course.py:191 .\apps\course\models\course.py:222
-#: .\apps\course\models\course.py:246 .\apps\course\models\lesson.py:35
-#: .\apps\course\models\lesson.py:61 .\apps\course\models\lesson.py:135
-#: .\apps\transaction\models.py:36
-msgid "Created at"
-msgstr "Дата создания"
-
-#: .\apps\course\models\course.py:171
+#: .\apps\course\models\course.py:174
msgid "Glossary Title"
msgstr "Название глоссария"
-#: .\apps\course\models\course.py:180 .\apps\course\models\course.py:190
+#: .\apps\course\models\course.py:183 .\apps\course\models\course.py:193
msgid "Glossary"
msgstr "Глоссарий"
-#: .\apps\course\models\course.py:181
+#: .\apps\course\models\course.py:184
msgid "Glossaries"
msgstr "Глоссарии"
-#: .\apps\course\models\course.py:207 .\config\settings\base.py:498
+#: .\apps\course\models\course.py:210 .\config\settings\base.py:498
msgid "Course Glossary"
msgstr "Глоссарий курса"
-#: .\apps\course\models\course.py:208
+#: .\apps\course\models\course.py:211
msgid "Course Glossaries"
msgstr "Глоссарии курсов"
-#: .\apps\course\models\course.py:216
+#: .\apps\course\models\course.py:219
msgid "Attachment Title"
msgstr "Название вложения"
-#: .\apps\course\models\course.py:219
+#: .\apps\course\models\course.py:222
msgid "Attachment File"
msgstr "Файл вложения"
-#: .\apps\course\models\course.py:221
+#: .\apps\course\models\course.py:224
msgid "File Size (in bytes)"
msgstr "Размер файла (в байтах)"
@@ -1839,6 +2106,7 @@ msgid "Joined Date"
msgstr "Дата присоединения"
#: .\apps\course\models\participant.py:28 .\apps\quiz\models\participant.py:22
+#: .\templates\admin\index.html:89
msgid "Participants"
msgstr "Участники"
@@ -2490,6 +2758,7 @@ msgid "Searching..."
msgstr "Поиск..."
#: .\apps\hadis\templates\admin\category_index.html:931
+#: .\utils\unfold_translations.py:66
msgid "Type to search..."
msgstr "Введите для поиска..."
@@ -2979,6 +3248,7 @@ msgid "Paid"
msgstr "Оплачено"
#: .\apps\transaction\admin.py:62 .\apps\transaction\models.py:23
+#: .\templates\admin\index.html:156 .\utils\unfold_translations.py:56
msgid "Failed"
msgstr "Неуспешно"
@@ -2987,6 +3257,7 @@ msgid "Waiting Approval"
msgstr "Ожидает одобрения"
#: .\apps\transaction\admin.py:65 .\apps\transaction\models.py:20
+#: .\templates\admin\index.html:146 .\utils\unfold_translations.py:54
msgid "Pending"
msgstr "В ожидании"
@@ -3041,7 +3312,8 @@ msgstr ""
msgid "Waiting for Approval"
msgstr "Ожидает одобрения"
-#: .\apps\transaction\models.py:22
+#: .\apps\transaction\models.py:22 .\templates\admin\index.html:133
+#: .\templates\admin\index.html:141 .\utils\unfold_translations.py:53
msgid "Success"
msgstr "Успешно"
@@ -3061,7 +3333,7 @@ msgstr "Метод оплаты транзакции"
msgid "Transaction Price"
msgstr "Цена транзакции"
-#: .\apps\transaction\models.py:35
+#: .\apps\transaction\models.py:35 .\templates\admin\index.html:103
msgid "Transaction Status"
msgstr "Статус транзакции"
@@ -3081,22 +3353,10 @@ msgstr "Участник транзакции"
msgid "Transaction Participants"
msgstr "Участники транзакции"
-#: .\apps\transaction\models.py:66
-msgid "Male"
-msgstr "Мужской"
-
-#: .\apps\transaction\models.py:67
-msgid "Female"
-msgstr "Женский"
-
#: .\apps\transaction\models.py:77
msgid "phone"
msgstr "телефон"
-#: .\apps\transaction\models.py:79
-msgid "Select the user's gender."
-msgstr "Выберите пол пользователя."
-
#: .\apps\transaction\models.py:87
msgid "Participant Info"
msgstr "Информация об участнике"
@@ -3253,10 +3513,6 @@ msgstr "Закрепленные коллекции"
msgid "Regular Collections"
msgstr "Обычные коллекции"
-#: .\config\settings\base.py:444
-msgid "Users"
-msgstr "Пользователи"
-
#: .\config\settings\base.py:452
msgid "Guest Users"
msgstr "Гостевые пользователи"
@@ -3274,7 +3530,7 @@ msgid "Quiz Participants"
msgstr "Участники теста"
#: .\config\settings\base.py:584 .\templates\admin\index.html:7
-#: .\utils\admin.py:462
+#: .\utils\admin.py:469
msgid "Dashboard"
msgstr "Панель управления"
@@ -3290,7 +3546,7 @@ msgstr "Все пользователи"
msgid "Students"
msgstr "Студенты"
-#: .\config\settings\base.py:621
+#: .\config\settings\base.py:621 .\utils\admin.py:555
msgid "Professors"
msgstr "Профессора"
@@ -3502,10 +3758,28 @@ msgstr "Очистить выбор"
msgid "System Overview"
msgstr "Обзор системы"
-#: .\templates\admin\index.html:42
+#: .\templates\admin\index.html:47
msgid "No statistics available for this panel."
msgstr "Статистика для этой панели недоступна."
+#: .\templates\admin\index.html:60 .\utils\unfold_translations.py:52
+msgid "Top 5 Popular Courses"
+msgstr "Топ-5 популярных курсов"
+
+#: .\templates\admin\index.html:93
+msgid "No courses found."
+msgstr "Курсы не найдены."
+
+#: .\templates\admin\index.html:151 .\utils\unfold_translations.py:55
+msgid "Waiting"
+msgstr "В ожидании"
+
+#: .\templates\admin\index.html:164
+#, fuzzy
+#| msgid "Transaction Receipt"
+msgid "No transactions recorded yet."
+msgstr "Квитанция транзакции"
+
#: .\templates\course\course_analytics.html:9
msgid "Course Analytics Dashboard"
msgstr "Панель аналитики курса"
@@ -3637,43 +3911,44 @@ msgstr "Разработка"
msgid "Production"
msgstr "Продакшн"
-#: .\utils\admin.py:139 .\utils\admin.py:242
+#: .\utils\admin.py:139 .\utils\admin.py:251
msgid "Imam Javad Site"
msgstr "Сайт Имам Джавад"
-#: .\utils\admin.py:144 .\utils\admin.py:237
+#: .\utils\admin.py:144 .\utils\admin.py:246
msgid "Dovoodi Site"
msgstr "Сайт Довуди"
-#: .\utils\admin.py:149
-msgid "Dovoodi Admin"
-msgstr "Админ Довуди"
-
-#: .\utils\admin.py:247
-msgid "Imam Javad Admin"
-msgstr "Админ Имам Джавад"
-#: .\utils\admin.py:489
+#: .\utils\admin.py:554
msgid "Active Students"
msgstr "Активные студенты"
-#: .\utils\admin.py:494
-msgid "Published Courses"
-msgstr "Опубликованные курсы"
+#: .\utils\admin.py:556 .\utils\unfold_translations.py:49
+msgid "Active Courses"
+msgstr "Активные водители"
+
+#: .\utils\admin.py:557
+msgid "Total Blogs"
+msgstr "Всего блогов"
-#: .\utils\admin.py:499
+#: .\utils\admin.py:558 .\utils\unfold_translations.py:50
+msgid "30-Day Revenue"
+msgstr "Доход за 30 дней"
+
+#: .\utils\admin.py:559
msgid "Pending Certificates"
msgstr "Сертификаты в ожидании"
-#: .\utils\admin.py:524
+#: .\utils\admin.py:579
msgid "Hadith Database"
msgstr "База данных хадисов"
-#: .\utils\admin.py:529
+#: .\utils\admin.py:580
msgid "Books & Articles"
msgstr "Книги и статьи"
-#: .\utils\admin.py:534
+#: .\utils\admin.py:581
msgid "Multimedia"
msgstr "Мультимедиа"
@@ -3759,7 +4034,7 @@ msgstr "Воскресенье"
msgid "Day"
msgstr "День"
-#: .\utils\schema.py:36
+#: .\utils\schema.py:36 .\utils\unfold_translations.py:72
msgid "Time"
msgstr "Время"
@@ -3863,3 +4138,166 @@ msgstr "Название комнаты"
#: .\utils\unfold_translations.py:39
msgid "System Administration"
msgstr "Системное Администрирование"
+
+#: .\utils\unfold_translations.py:48
+msgid "Active Course"
+msgstr "Активный курс"
+
+#: .\utils\unfold_translations.py:51
+msgid "Popular Courses"
+msgstr "Популярные курсы"
+
+#: .\utils\unfold_translations.py:57
+msgid "Success:"
+msgstr "Успешно:"
+
+#: .\utils\unfold_translations.py:58
+msgid "Pending:"
+msgstr "В ожидании:"
+
+#: .\utils\unfold_translations.py:59
+msgid "Waiting:"
+msgstr "Ожидание"
+
+#: .\utils\unfold_translations.py:60
+msgid "Failed:"
+msgstr "Ошибка:"
+
+#: .\utils\unfold_translations.py:61
+msgid "Choose file to upload"
+msgstr "Выберите файл для загрузки"
+
+#: .\utils\unfold_translations.py:62
+msgid "Date from"
+msgstr "Дата с"
+
+#: .\utils\unfold_translations.py:63
+msgid "Date to"
+msgstr "Дата по"
+
+#: .\utils\unfold_translations.py:64 .\utils\unfold_translations.py:90
+msgid "By Date Joined"
+msgstr "По дате регистрации"
+
+#: .\utils\unfold_translations.py:65
+msgid "Type to search"
+msgstr "Введите для поиска"
+
+#: .\utils\unfold_translations.py:67
+msgid "Apply filters"
+msgstr "Применить фильтры"
+
+#: .\utils\unfold_translations.py:68
+msgid "From"
+msgstr "От"
+
+#: .\utils\unfold_translations.py:69
+msgid "To"
+msgstr "До"
+
+#: .\utils\unfold_translations.py:70
+msgid "video link"
+msgstr "ссылка на видео"
+
+#: .\utils\unfold_translations.py:73
+msgid "Delete"
+msgstr "Удалить"
+
+#: .\utils\unfold_translations.py:75
+msgid "Add Weekly Timing"
+msgstr "Добавить еженедельное расписание"
+
+#: .\utils\unfold_translations.py:76
+msgid "Delete All"
+msgstr "Удалить все"
+
+#: .\utils\unfold_translations.py:77
+msgid "Add Course Features"
+msgstr "Добавить особенности курса"
+
+#: .\utils\unfold_translations.py:78
+msgid "Is Staff"
+msgstr "Статус персонала"
+
+#: .\utils\unfold_translations.py:79
+msgid "Deleted at"
+msgstr "Удалено в"
+
+#: .\utils\unfold_translations.py:81
+msgid "Type of the user"
+msgstr "Тип пользователя"
+
+#: .\utils\unfold_translations.py:82
+#, python-brace-format
+msgid ""
+"Raw passwords are not stored, so there is no way to see this user’s "
+"password, but you can change the password using this form."
+msgstr "Исходные пароли не хранятся, поэтому нет возможности увидеть пароль этого пользователя, но вы можете изменить пароль, используя эту форму."
+
+#: .\utils\unfold_translations.py:87
+msgid "Users:"
+msgstr "Пользователи:"
+
+#: .\utils\unfold_translations.py:88
+msgid "users :"
+msgstr "пользователи :"
+
+#: .\utils\unfold_translations.py:89
+msgid "By"
+msgstr "По"
+
+#: .\utils\unfold_translations.py:91
+msgid "( both fields are showing )"
+msgstr "( показаны оба поля )"
+
+#: .\utils\unfold_translations.py:92
+msgid "(both fields are showing)"
+msgstr "(показаны оба поля)"
+
+#: .\utils\unfold_translations.py:93
+msgid "Imam Javad Admin"
+msgstr "Админ Имам Джавад"
+
+#: .\utils\unfold_translations.py:94
+msgid "Imam Javad School"
+msgstr "Школа Имама Джавада"
+
+#: .\utils\unfold_translations.py:95
+msgid "Dovoodi Admin"
+msgstr "Админ Довуди"
+
+#: .\utils\unfold_translations.py:96
+msgid "Dovodbi Application"
+msgstr "Приложение Довудби"
+
+#: .\utils\unfold_translations.py:97
+msgid "Updated Today"
+msgstr "Обновлено сегодня"
+
+#: .\utils\unfold_translations.py:98
+msgid "Requires Action"
+msgstr "Требуется действие"
+
+#: .\apps\account\admin\user.py:471
+msgid "{count} permission"
+msgid_plural "{count} permissions"
+msgstr[0] "{count} разрешение"
+msgstr[1] "{count} разрешения"
+msgstr[2] "{count} разрешений"
+msgstr[3] "{count} разрешений"
+
+#: .\apps\account\admin\student.py:59
+msgid "{count} course"
+msgid_plural "{count} courses"
+msgstr[0] "{count} курс"
+msgstr[1] "{count} курса"
+msgstr[2] "{count} курсов"
+msgstr[3] "{count} курсов"
+
+#: .\apps\account\admin\user.py:307 .\apps\account\admin\user.py:447
+msgid "{total} course"
+msgid_plural "{total} courses"
+msgstr[0] "{total} курс"
+msgstr[1] "{total} курса"
+msgstr[2] "{total} курсов"
+msgstr[3] "{total} курсов"