diff --git a/.github/workflows/crowdin_upload.yml b/.github/workflows/crowdin_upload.yml
index eaebd18e..af471811 100644
--- a/.github/workflows/crowdin_upload.yml
+++ b/.github/workflows/crowdin_upload.yml
@@ -16,11 +16,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v6
# Backend i18n
- - name: Create env files
- run: make create-env-files
- - name: Generate source translations
+ - name: Install frontend dependencies
run: make install-frozen-front
- - name: Generate source translations
+ - name: Generate frontend source translations
run: make i18n-generate
- name: crowdin action
uses: crowdin/github-action@v2
diff --git a/.github/workflows/messages.yml b/.github/workflows/messages.yml
index 933037e1..46ee46d9 100644
--- a/.github/workflows/messages.yml
+++ b/.github/workflows/messages.yml
@@ -81,7 +81,7 @@ jobs:
- name: Run frontend linting
run: make lint-front
- name: Run frontend check
- run: make ts-check-front
+ run: make typecheck-front
build-front:
runs-on: ubuntu-latest
diff --git a/Makefile b/Makefile
index e0a50c1a..6a51dcc0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,3 @@
-# /!\ /!\ /!\ /!\ /!\ /!\ /!\ DISCLAIMER /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
-#
-# This Makefile is only meant to be used for DEVELOPMENT purpose as we are
-# changing the user id that will run in the container.
-#
-# PLEASE DO NOT USE IT FOR YOUR CI/PRODUCTION/WHATEVER...
-#
-# /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\
-#
# Note to developers:
#
# While editing this file, please respect the following statements:
@@ -115,7 +106,6 @@ update: ## Update the project with latest changes
@$(MAKE) collectstatic
@$(MAKE) migrate
@$(MAKE) install-frozen-front
- @$(MAKE) i18n-compile
.PHONY: update
# -- Docker/compose
@@ -173,53 +163,58 @@ lint: ## run all linters
lint: \
lint-back \
lint-front \
- ts-check-front \
+ typecheck-front \
lint-mta-in \
lint-mta-out
.PHONY: lint
-lint-check: ## run all linters in check mode
+lint-check: ## run all linters in check mode (no auto-fix)
lint-check: \
- ruff-check-back \
- pylint-back \
- ts-check-front \
+ lint-check-back \
+ typecheck-front \
lint-front
.PHONY: lint-check
-lint-back: ## run back-end linters
+lint-back: ## run back-end linters (with auto-fix)
lint-back: \
- ruff-format-back \
- ruff-check-back \
- pylint-back
+ format-back \
+ check-back \
+ analyze-back
.PHONY: lint-back
-ruff-format-back: ## format back-end python sources with ruff
- @$(COMPOSE_RUN_APP_TOOLS) ruff format .
-.PHONY: ruff-format-back
-
-ruff-check-back: ## lint back-end python sources with ruff
- @$(COMPOSE_RUN_APP_TOOLS) ruff check . --fix
-.PHONY: ruff-check-back
-
-pylint-back: ## lint back-end python sources with pylint
+lint-check-back: ## run back-end linters in check mode (no auto-fix)
+ @$(COMPOSE_RUN_APP_TOOLS) ruff format --check .
+ @$(COMPOSE_RUN_APP_TOOLS) ruff check .
@$(COMPOSE_RUN_APP_TOOLS) sh -c "pylint ."
-.PHONY: pylint-back
+.PHONY: lint-check-back
-ts-check-front: ## run the frontend type checker
+format-back: ## format back-end python sources
+ @$(COMPOSE_RUN_APP_TOOLS) ruff format .
+.PHONY: format-back
+
+check-back: ## check back-end python sources
+ @$(COMPOSE_RUN_APP_TOOLS) ruff check . --fix
+.PHONY: check-back
+
+analyze-back: ## analyze back-end python sources
+ @$(COMPOSE_RUN_APP_TOOLS) sh -c "pylint ."
+.PHONY: analyze-back
+
+typecheck-front: ## run the frontend type checker
@$(COMPOSE) run --rm frontend-tools npm run ts:check
-.PHONY: ts-check-front
+.PHONY: typecheck-front
lint-front: ## run the frontend linter
@$(COMPOSE) run --rm frontend-tools npm run lint
.PHONY: lint-front
-lint-mta-in: ## lint mta-in python sources with pylint
+lint-mta-in: ## lint mta-in python sources
$(COMPOSE_RUN) --rm -e EXEC_CMD_ONLY=true mta-in-test ruff format .
#$(COMPOSE_RUN) --rm -e EXEC_CMD_ONLY=true mta-in-test ruff check . --fix
#$(COMPOSE_RUN) --rm -e EXEC_CMD_ONLY=true mta-in-test pylint .
.PHONY: lint-mta-in
-lint-mta-out: ## lint mta-out python sources with pylint
+lint-mta-out: ## lint mta-out python sources
$(COMPOSE_RUN) --rm -e EXEC_CMD_ONLY=true mta-out-test ruff format .
.PHONY: lint-mta-out
@@ -283,27 +278,27 @@ test-socks-proxy: ## run the socks-proxy tests
# -- E2E Tests
test-e2e: ## Setup, run and teardown e2e tests in headless mode
- @$(MAKE) setup-e2e
+ @$(MAKE) start-e2e
@args="$(filter-out $@,$(MAKECMDGOALS))" && \
- $(MAKE) run-test-e2e args="$${args:-${1}}" || echo "$(BOLD)Tests failed$(RESET)"
- @$(MAKE) teardown-e2e
+ $(MAKE) test-e2e-bare args="$${args:-${1}}" || echo "$(BOLD)Tests failed$(RESET)"
+ @$(MAKE) stop-e2e
.PHONY: test-e2e
test-e2e-ui: ## Setup, run and teardown e2e tests in UI mode
- @$(MAKE) setup-e2e
- @$(MAKE) run-test-e2e-ui
- @$(MAKE) teardown-e2e
+ @$(MAKE) start-e2e
+ @$(MAKE) test-e2e-ui-bare
+ @$(MAKE) stop-e2e
.PHONY: test-e2e-ui
test-e2e-dev: ## Setup, run and teardown e2e tests in UI mode with dev frontend
- @$(MAKE) setup-e2e
- @$(MAKE) run-test-e2e-dev
- @$(MAKE) teardown-e2e
+ @$(MAKE) start-e2e
+ @$(MAKE) test-e2e-dev-bare
+ @$(MAKE) stop-e2e
.PHONY: test-e2e-dev
test-e2e-ci: ## Setup and run e2e tests in CI mode
- @$(MAKE) setup-e2e
- @$(MAKE) run-test-e2e args="$(args)"
+ @$(MAKE) start-e2e
+ @$(MAKE) test-e2e-bare args="$(args)"
.PHONY: test-e2e-ci
build-e2e: ## Build the e2e services
@@ -311,7 +306,7 @@ build-e2e: ## Build the e2e services
$(COMPOSE_E2E) build --no-cache $${args:-${1}}
.PHONY: build-e2e
-log-e2e:
+log-e2e: ## alias for logs-e2e
@args="$(filter-out $@,$(MAKECMDGOALS))" && \
$(MAKE) logs-e2e -- $${args:-${1}}
.PHONY: log-e2e
@@ -321,30 +316,27 @@ logs-e2e: ## Show logs from e2e services
$(COMPOSE_E2E) --profile dev logs $${args:-${1}}
.PHONY: logs-e2e
-run-test-e2e: ## Run e2e tests in headless mode
+test-e2e-bare: ## Run e2e tests in headless mode
@echo "$(BLUE)\n\n| ๐ญ Running E2E tests... \n$(RESET)"
$(COMPOSE_E2E) run --rm --service-ports runner npm run test -- $(args)
@echo "$(GREEN)> ๐ญ E2E tests completed!$(RESET)\n"
-.PHONY: run-test-e2e
+.PHONY: test-e2e-bare
-run-test-e2e-ui: ## Run e2e tests in UI mode
+test-e2e-ui-bare: ## Run e2e tests in UI mode
@echo "$(BLUE)\n\n| ๐ญ Running E2E tests in UI mode... \n$(RESET)"
# Note: || true allows graceful exit when user closes the UI
@$(COMPOSE_E2E) run --rm --service-ports runner npm run test:ui || true
@echo "$(GREEN)> ๐ญ You killed the UI!$(RESET)\n"
-.PHONY: run-test-e2e-ui
+.PHONY: test-e2e-ui-bare
-run-test-e2e-dev: ## Run e2e tests in UI mode with dev frontend
+test-e2e-dev-bare: ## Run e2e tests in UI mode with dev frontend
@echo "$(BLUE)\n\n| ๐ญ Running E2E tests in dev mode... \n$(RESET)"
# Note: || true allows graceful exit when user closes the UI
E2E_PROFILE=dev $(COMPOSE_E2E) --profile dev run --rm --service-ports runner npm run test:ui || true
@echo "$(GREEN)> ๐ญ You killed the UI!$(RESET)\n"
-.PHONY: run-test-e2e-dev
+.PHONY: test-e2e-dev-bare
-down-e2e: ## Stop and remove all e2e services
- @echo "$(BOLD)Stopping E2E services...$(RESET)"
- @$(COMPOSE_E2E) --profile dev down -v
- @echo "$(GREEN)โ E2E services stopped$(RESET)"
+down-e2e: stop-e2e ## alias for stop-e2e
.PHONY: down-e2e
demo-e2e: ## Populate the e2e database with demo data
@@ -352,18 +344,18 @@ demo-e2e: ## Populate the e2e database with demo data
@$(COMPOSE_E2E) run --rm backend python manage.py e2e_demo
.PHONY: demo-e2e
-setup-e2e: ## Setup e2e services
+start-e2e: ## Start e2e services (migrate, seed, etc.)
@echo "$(BLUE)\n\n| ๐ง Setting up E2E services... \n$(RESET)"
@$(COMPOSE_E2E) run --rm objectstorage-createbucket
@$(COMPOSE_E2E) run --rm backend python manage.py migrate --noinput
@$(COMPOSE_E2E) run --rm backend python manage.py search_index_create || true
@$(MAKE) demo-e2e
-.PHONY: setup-e2e
+.PHONY: start-e2e
-teardown-e2e: ## Teardown e2e services
+stop-e2e: ## Stop and remove e2e services
@echo "$(BLUE)\n\n| ๐งน Cleaning up E2E services... \n$(RESET)"
@$(COMPOSE_E2E) --profile dev down -v
-.PHONY: teardown-e2e
+.PHONY: stop-e2e
# -- Backend
@@ -386,14 +378,6 @@ superuser: ## Create an admin superuser with password "admin"
@$(MANAGE_DB) createsuperuser --email admin@admin.local --password admin
.PHONY: superuser
-i18n-compile-back: ## compile the gettext files
- @$(MANAGE) compilemessages --ignore="venv/**/*"
-.PHONY: i18n-compile-back
-
-i18n-generate-back: ## create the .pot files used for i18n
- @$(MANAGE) makemessages -a --keep-pot --all --no-location
-.PHONY: i18n-generate-back
-
shell-back: ## open a shell in the backend container
@$(COMPOSE) run --rm --build backend-dev /bin/bash
.PHONY: shell-back
@@ -406,39 +390,42 @@ exec-back: ## open a shell in the running backend-dev container
@$(COMPOSE) exec backend-dev /bin/bash
.PHONY: exec-back
-uv-lock-back: ## lock the dependencies
+deps-lock-back: ## lock the dependencies
@$(COMPOSE) run --rm --build backend-uv uv lock
- make pip-audit
-.PHONY: uv-lock-back
+ make deps-audit
+.PHONY: deps-lock-back
-uv-update-indirect-back: ## update indirect dependencies
+deps-update-indirect-back: ## update indirect dependencies
rm src/backend/uv.lock
- make uv-lock-back
-.PHONY: uv-update-indirect-back
+ make deps-lock-back
+.PHONY: deps-update-indirect-back
-uv-outdated-back: ## show outdated dependencies
+deps-outdated-back: ## show outdated dependencies
@$(COMPOSE) run --rm --build backend-uv uv tree --outdated
-.PHONY: uv-outdated-back
+.PHONY: deps-outdated-back
-uv-tree-back: ## show dependencies as a tree
+deps-tree-back: ## show dependencies as a tree
@$(COMPOSE) run --rm --build backend-uv uv tree
-.PHONY: uv-tree-back
+.PHONY: deps-tree-back
-pip-audit: ## check the dependencies
+deps-audit-back: ## audit back-end dependencies for vulnerabilities
@$(COMPOSE) run --rm --no-deps -e HOME=/tmp --build backend-dev pip-audit
-.PHONY: pip-audit
+.PHONY: deps-audit-back
+
+deps-audit: deps-audit-back ## alias for deps-audit-back
+.PHONY: deps-audit
collectstatic: ## collect static files
@$(MANAGE_DB) collectstatic --noinput
.PHONY: collectstatic
-shell: ## connect to django shell
+shell-back-django: ## connect to django shell
@$(MANAGE) shell #_plus
-.PHONY: shell
+.PHONY: shell-back-django
-export-keycloak: ## export all keycloak data to a JSON file
+export-identity: ## export all identity provider data to a JSON file
@$(COMPOSE) run -v `pwd`/src/keycloak:/tmp/keycloak-export --rm keycloak export --realm messages --file /tmp/keycloak-export/realm.json
-.PHONY: export-keycloak
+.PHONY: export-identity
# -- Database
@@ -467,39 +454,32 @@ env.d/development/%.local:
# -- Internationalization
-download-crowdin: ## Download translated message from crowdin
+i18n-download: ## Download translated messages
@$(COMPOSE_RUN_CROWDIN) download -c crowdin/config.yml
-.PHONY: download-crowdin
+.PHONY: i18n-download
-download-crowdin-sources: ## Download sources from Crowdin
+i18n-download-sources: ## Download translation sources
@$(COMPOSE_RUN_CROWDIN) download sources -c crowdin/config.yml
-.PHONY: download-crowdin-sources
+.PHONY: i18n-download-sources
-upload-crowdin: ## Upload source translations to crowdin
+i18n-upload: ## Upload source translations
@$(COMPOSE_RUN_CROWDIN) upload sources -c crowdin/config.yml
-.PHONY: upload-crowdin
+.PHONY: i18n-upload
-i18n-compile: ## compile all translations
-i18n-compile: \
- i18n-compile-back
-.PHONY: i18n-compile
-
-i18n-generate: ## create the .pot files and extract frontend messages
+i18n-generate: ## extract frontend messages for translation
i18n-generate: \
- i18n-generate-back \
i18n-generate-front
.PHONY: i18n-generate
-i18n-download-and-compile: ## download all translated messages and compile them to be used by all applications
+i18n-download-and-compile: ## download all translated messages to be used by all applications
i18n-download-and-compile: \
- download-crowdin \
- i18n-compile
+ i18n-download
.PHONY: i18n-download-and-compile
i18n-generate-and-upload: ## generate source translations for all applications and upload them to Crowdin
i18n-generate-and-upload: \
i18n-generate \
- upload-crowdin
+ i18n-upload
.PHONY: i18n-generate-and-upload
# -- Release
@@ -516,9 +496,9 @@ clean-media: ## remove all media files
rm -rf data/media/*
.PHONY: clean-media
-pyclean: ## remove all python cache files
+clean-cache: ## remove all python cache files
find . | grep -E "\(/__pycache__$|\.pyc$|\.pyo$\)" | xargs rm -rf
-.PHONY: pyclean
+.PHONY: clean-cache
help:
@echo "$(BOLD)messages Makefile"
@@ -572,10 +552,10 @@ search-index: ## Create and/or reindex opensearch data
@$(MANAGE) search_reindex --all
.PHONY: search-index
-uv-lock-mta-in: ## lock the dependencies
+deps-lock-mta-in: ## lock the dependencies
@$(COMPOSE) run --rm --build mta-in-uv uv lock
-.PHONY: uv-lock-mta-in
+.PHONY: deps-lock-mta-in
-uv-lock-mta-out: ## lock the dependencies
+deps-lock-mta-out: ## lock the dependencies
@$(COMPOSE) run --rm --build mta-out-uv uv lock
-.PHONY: uv-lock-mta-out
+.PHONY: deps-lock-mta-out
diff --git a/crowdin/config.yml b/crowdin/config.yml
index 8bb1e4da..f4e8328b 100644
--- a/crowdin/config.yml
+++ b/crowdin/config.yml
@@ -15,11 +15,6 @@ preserve_hierarchy: true
# Files configuration
#
files: [
- {
- source : "/backend/locale/django.pot",
- dest: "/backend.pot",
- translation : "/backend/locale/%locale_with_underscore%/LC_MESSAGES/django.po"
- },
{
source: "/frontend/public/locales/common/en-US.json",
dest: "/frontend-common.json",
diff --git a/src/backend/.pylintrc b/src/backend/.pylintrc
index a737f6b9..ebe0ea71 100644
--- a/src/backend/.pylintrc
+++ b/src/backend/.pylintrc
@@ -3,7 +3,7 @@
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
-extension-pkg-whitelist=
+extension-pkg-whitelist=pypff
# Add files or directories to the blacklist. They should be base names, not
# paths.
@@ -23,7 +23,7 @@ jobs=0
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
-load-plugins=pylint_django,pylint.extensions.no_self_use
+load-plugins=pylint_django
# Pickle collected data for later comparisons.
persistent=yes
@@ -33,8 +33,6 @@ persistent=yes
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages
-suggestion-mode=yes
-
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
@@ -60,11 +58,11 @@ disable=bad-inline-option,
django-not-configured,
file-ignored,
locally-disabled,
- no-self-use,
raw-checker-failed,
suppressed-message,
useless-suppression,
- fixme
+ fixme,
+ cyclic-import
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
diff --git a/src/backend/__init__.py b/src/backend/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/backend/core/admin.py b/src/backend/core/admin.py
index 2d00cbad..f204cd00 100644
--- a/src/backend/core/admin.py
+++ b/src/backend/core/admin.py
@@ -13,7 +13,6 @@ from django.template.response import TemplateResponse
from django.urls import path
from django.utils.html import escape, format_html
from django.utils.text import slugify
-from django.utils.translation import gettext_lazy as _
from sentry_sdk import capture_exception
@@ -33,7 +32,7 @@ from .forms import IMAPImportForm, MessageImportForm
class RecipientDeliveryStatusFilter(admin.SimpleListFilter):
"""Filter messages by their recipients' delivery status."""
- title = _("delivery status")
+ title = "delivery status"
parameter_name = "recipient_delivery_status"
def lookups(self, request, model_admin):
@@ -95,18 +94,12 @@ def retry_send_messages_action(__, request, queryset):
messages.info(
request,
- _(
- "%(message_count)d messages - "
- "Retry send message task queued (id: %(task_id)s)."
- )
- % {
- "message_count": len(message_ids),
- "task_id": task.id,
- },
+ f"{len(message_ids)} messages - "
+ f"Retry send message task queued (id: {task.id}).",
)
-retry_send_messages_action.short_description = _(
+retry_send_messages_action.short_description = (
"Retry to send selected messages to pending recipients"
)
@@ -127,7 +120,7 @@ class UserAdmin(auth_admin.UserAdmin):
},
),
(
- _("Personal info"),
+ "Personal info",
{
"fields": (
"sub",
@@ -140,7 +133,7 @@ class UserAdmin(auth_admin.UserAdmin):
},
),
(
- _("Permissions"),
+ "Permissions",
{
"fields": (
"is_active",
@@ -151,7 +144,7 @@ class UserAdmin(auth_admin.UserAdmin):
),
},
),
- (_("Important dates"), {"fields": ("created_at", "updated_at")}),
+ ("Important dates", {"fields": ("created_at", "updated_at")}),
)
add_fieldsets = (
(
@@ -216,12 +209,12 @@ class MailDomainAdmin(admin.ModelAdmin):
readonly_fields = ("throttle_status_display",)
change_form_template = "admin/core/maildomain/change_form.html"
- @admin.display(description=_("Throttle Status (External Recipients)"))
+ @admin.display(description="Throttle Status (External Recipients)")
def throttle_status_display(self, obj):
"""Display current throttle usage for this maildomain."""
status = get_throttle_status(maildomain=obj)
if "maildomain" not in status:
- return _("No throttle configured")
+ return "No throttle configured"
info = status["maildomain"]
return format_html(
@@ -251,7 +244,7 @@ class MailDomainAdmin(admin.ModelAdmin):
maildomain = self.get_object(request, object_id)
if maildomain is None:
- messages.error(request, _("Mail domain not found."))
+ messages.error(request, "Mail domain not found.")
return redirect("..")
# Run DNS provisioning
@@ -264,22 +257,18 @@ class MailDomainAdmin(admin.ModelAdmin):
changes_text = ", ".join(changes)
messages.success(
request,
- _("DNS provisioning successful via %(provider)s: %(changes)s")
- % {"provider": provider_used, "changes": changes_text},
+ f"DNS provisioning successful via {provider_used}: {changes_text}",
)
else:
messages.success(
request,
- _(
- "DNS provisioning successful via %(provider)s (no changes needed)."
- )
- % {"provider": provider_used},
+ f"DNS provisioning successful via {provider_used} (no changes needed).",
)
else:
error_msg = results.get("error", "Unknown error")
messages.error(
request,
- _("DNS provisioning failed: %(error)s") % {"error": error_msg},
+ f"DNS provisioning failed: {error_msg}",
)
return redirect("..")
@@ -332,7 +321,7 @@ class MailboxAdmin(admin.ModelAdmin):
mailbox_obj = self.get_object(request, object_id)
if mailbox_obj is None:
- messages.error(request, _("Mailbox not found."))
+ messages.error(request, "Mailbox not found.")
return redirect("..")
# Start the export task
@@ -345,23 +334,20 @@ class MailboxAdmin(admin.ModelAdmin):
)
capture_exception()
messages.error(
- request, _("Failed to queue export task. Please try again later.")
+ request, "Failed to queue export task. Please try again later."
)
return redirect("..")
messages.success(
request,
- _(
- "Export task has been queued for mailbox %(mailbox)s. "
- "You will receive a message with the download link when the export "
- "is complete (task id: %(task_id)s)."
- )
- % {"mailbox": mailbox_obj, "task_id": task.id},
+ f"Export task has been queued for mailbox {mailbox_obj}. "
+ f"You will receive a message with the download link when the export "
+ f"is complete (task id: {task.id}).",
)
return redirect("..")
- @admin.display(description=_("Throttle Status (External Recipients)"))
+ @admin.display(description="Throttle Status (External Recipients)")
def throttle_status_display(self, obj):
"""Display current throttle usage for this mailbox and its domain."""
status = get_throttle_status(mailbox=obj, maildomain=obj.domain)
@@ -390,7 +376,7 @@ class MailboxAdmin(admin.ModelAdmin):
)
)
- return format_html("
".join(parts)) if parts else _("No throttle configured")
+ return format_html("
".join(parts)) if parts else "No throttle configured"
@admin.register(models.Channel)
@@ -466,7 +452,7 @@ class ThreadAdmin(admin.ModelAdmin):
fieldsets = (
(None, {"fields": ("subject", "snippet", "display_labels", "summary")}),
(
- _("Statistics"),
+ "Statistics",
{
"fields": (
"has_unread",
@@ -486,7 +472,7 @@ class ThreadAdmin(admin.ModelAdmin):
},
),
(
- _("Metadata"),
+ "Metadata",
{
"fields": ("sender_names", "created_at", "updated_at", "messaged_at"),
"classes": ("collapse",),
@@ -517,13 +503,13 @@ class ThreadAdmin(admin.ModelAdmin):
"""Return a comma-separated list of labels for the thread."""
return ", ".join(label.name for label in obj.labels.all())
- get_labels.short_description = _("Labels")
+ get_labels.short_description = "Labels"
get_labels.admin_order_field = "labels__name"
def display_labels(self, obj):
"""Display labels with their colors in the detail view."""
if not obj.labels.exists():
- return _("No labels")
+ return "No labels"
# Create a list of formatted label spans
label_spans = []
@@ -540,7 +526,7 @@ class ThreadAdmin(admin.ModelAdmin):
# Join all spans with a space using format_html
return format_html(" ".join(label_spans))
- display_labels.short_description = _("Labels")
+ display_labels.short_description = "Labels"
class MessageRecipientInline(admin.TabularInline):
@@ -674,7 +660,7 @@ class MessageAdmin(admin.ModelAdmin):
context = dict(
self.admin_site.each_context(request),
- title=_("Import Messages"),
+ title="Import Messages",
form=form,
opts=self.model._meta, # noqa: SLF001
)
@@ -704,7 +690,7 @@ class MessageAdmin(admin.ModelAdmin):
context = dict(
self.admin_site.each_context(request),
- title=_("Import Messages from IMAP"),
+ title="Import Messages from IMAP",
form=form,
opts=self.model._meta, # noqa: SLF001
)
@@ -751,7 +737,7 @@ class MessageAdmin(admin.ModelAdmin):
message = self.get_object(request, object_id)
if message is None:
- messages.error(request, _("Message not found."))
+ messages.error(request, "Message not found.")
return redirect("..")
# Check if message has recipients with retry status
@@ -763,7 +749,7 @@ class MessageAdmin(admin.ModelAdmin):
if retryable_recipients_count == 0:
messages.warning(
request,
- _("No pending recipients found for this message."),
+ "No pending recipients found for this message.",
)
return redirect("..")
@@ -772,14 +758,8 @@ class MessageAdmin(admin.ModelAdmin):
messages.success(
request,
- _(
- "Retry task has been queued for "
- "%(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
- )
- % {
- "retryable_recipients_count": retryable_recipients_count,
- "task_id": task.id,
- },
+ f"Retry task has been queued for "
+ f"{retryable_recipients_count} pending recipient(s) (id: {task.id}).",
)
return redirect("..")
@@ -931,7 +911,7 @@ class DKIMKeyAdmin(admin.ModelAdmin):
},
),
(
- _("Keys"),
+ "Keys",
{
"fields": ("public_key",),
"classes": ("collapse",),
@@ -966,7 +946,7 @@ class InboundMessageAdmin(admin.ModelAdmin):
return bool(obj.error_message)
has_error.boolean = True
- has_error.short_description = _("Error")
+ has_error.short_description = "Error"
def get_queryset(self, request):
"""Optimize queryset with select_related for better performance."""
diff --git a/src/backend/core/ai/call_label.py b/src/backend/core/ai/call_label.py
index 023e7cf8..74d0d1c9 100644
--- a/src/backend/core/ai/call_label.py
+++ b/src/backend/core/ai/call_label.py
@@ -1,3 +1,5 @@
+"""AI-powered label assignment for threads."""
+
from core.ai.thread_classifier import get_most_relevant_labels
from core.models import Label, Thread
diff --git a/src/backend/core/ai/thread_classifier.py b/src/backend/core/ai/thread_classifier.py
index 4358fa3d..0194614b 100644
--- a/src/backend/core/ai/thread_classifier.py
+++ b/src/backend/core/ai/thread_classifier.py
@@ -4,7 +4,7 @@ import json
from pathlib import Path
from django.conf import settings
-from django.utils import timezone, translation
+from django.utils import timezone
from core.ai.utils import get_messages_from_thread
from core.models import Thread
@@ -23,8 +23,7 @@ def get_most_relevant_labels(thread: Thread, labels: list) -> list[str]:
current_datetime = timezone.now().isoformat()
- # Determine the active or fallback language
- active_language = translation.get_language() or settings.LANGUAGE_CODE
+ active_language = settings.LANGUAGE_CODE
# Extract messages from the thread
messages = get_messages_from_thread(thread)
@@ -45,8 +44,7 @@ def get_most_relevant_labels(thread: Thread, labels: list) -> list[str]:
language=active_language,
)
- with translation.override(active_language):
- best_labels = AIService().call_ai_api(prompt)
+ best_labels = AIService().call_ai_api(prompt)
# Get rid of surrounding text if present
if best_labels.startswith('["') and best_labels.endswith('"]'):
diff --git a/src/backend/core/ai/thread_summarizer.py b/src/backend/core/ai/thread_summarizer.py
index ccccc611..85ead6c7 100644
--- a/src/backend/core/ai/thread_summarizer.py
+++ b/src/backend/core/ai/thread_summarizer.py
@@ -1,8 +1,9 @@
+"""AI-powered thread summarization."""
+
import json
from pathlib import Path
from django.conf import settings
-from django.utils import translation
from core.ai.utils import get_messages_from_thread
from core.models import Thread
@@ -10,10 +11,9 @@ from core.services.ai_service import AIService
def summarize_thread(thread: Thread) -> str:
- """Summarizes a thread using the OpenAI client based on the active Django language."""
+ """Summarizes a thread using the OpenAI client based on the configured language."""
- # Determine the active or fallback language
- active_language = translation.get_language() or settings.LANGUAGE_CODE
+ active_language = settings.LANGUAGE_CODE
# Extract messages from the thread
messages = get_messages_from_thread(thread)
@@ -29,7 +29,6 @@ def summarize_thread(thread: Thread) -> str:
prompt_query = prompt_template["summary_query"]
prompt = prompt_query.format(messages=messages_as_text, language=active_language)
- with translation.override(active_language):
- summary = AIService().call_ai_api(prompt)
+ summary = AIService().call_ai_api(prompt)
return summary
diff --git a/src/backend/core/ai/utils.py b/src/backend/core/ai/utils.py
index 1660f85a..131143ac 100644
--- a/src/backend/core/ai/utils.py
+++ b/src/backend/core/ai/utils.py
@@ -1,3 +1,5 @@
+"""Utility functions for AI features."""
+
from typing import List
from django.conf import settings
@@ -20,7 +22,7 @@ def get_messages_from_thread(thread: Thread) -> List[Message]:
def is_ai_enabled() -> bool:
- """Check if AI features are enabled based on the presence of required settings in the environment (API_KEY, BASE_URL, MODEL)"""
+ """Check if AI features are enabled based on required settings."""
return all(
[
settings.AI_API_KEY,
diff --git a/src/backend/core/api/__init__.py b/src/backend/core/api/__init__.py
index 5e9bf834..8f933d27 100644
--- a/src/backend/core/api/__init__.py
+++ b/src/backend/core/api/__init__.py
@@ -4,7 +4,6 @@ import logging
from django.conf import settings
from django.core.exceptions import ValidationError
-from django.utils.translation import gettext_lazy as _
from rest_framework import exceptions as drf_exceptions
from rest_framework import views as drf_views
@@ -32,7 +31,7 @@ def exception_handler(exc, context):
exc.retry_after,
)
response = Response(
- {"detail": _("Sending limit reached. Please wait before trying again.")},
+ {"detail": "Sending limit reached. Please wait before trying again."},
status=429,
)
response["Retry-After"] = exc.retry_after
diff --git a/src/backend/core/api/serializers.py b/src/backend/core/api/serializers.py
index 3a9c7bd9..ed59a2d4 100644
--- a/src/backend/core/api/serializers.py
+++ b/src/backend/core/api/serializers.py
@@ -8,7 +8,6 @@ import uuid
from django.conf import settings
from django.db import transaction
from django.db.models import Count, Exists, OuterRef, Q
-from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
@@ -1124,7 +1123,7 @@ class MailboxAdminSerializer(serializers.ModelSerializer):
if metadata.get("type") == "personal" and not domain.identity_sync:
raise serializers.ValidationError(
{
- "identity_sync": _(
+ "identity_sync": (
"Personal mailboxes cannot be created when "
"identity synchronization is disabled."
)
@@ -1140,7 +1139,7 @@ class MailboxAdminSerializer(serializers.ModelSerializer):
if any(lower_value == prefix.lower() for prefix in denylist):
raise serializers.ValidationError(
{
- "local_part_denied": _(
+ "local_part_denied": (
"This prefix is not allowed for personal mailboxes."
)
}
@@ -1154,7 +1153,7 @@ class MailboxAdminSerializer(serializers.ModelSerializer):
domain=self.context.get("domain"), local_part=value
).exists():
raise serializers.ValidationError(
- _("A mailbox with this local part already exists in this domain.")
+ "A mailbox with this local part already exists in this domain."
)
return value
@@ -1626,7 +1625,7 @@ class MessageTemplateSerializer(serializers.ModelSerializer):
image_mb = image["size"] / (1024 * 1024)
raise serializers.ValidationError(
{
- "html_body": _(
+ "html_body": (
'Image "%(name)s" (%(size)s MB) exceeds'
" the %(max)s MB limit."
)
@@ -1642,7 +1641,7 @@ class MessageTemplateSerializer(serializers.ModelSerializer):
total_mb = total_image_size / (1024 * 1024)
raise serializers.ValidationError(
{
- "html_body": _(
+ "html_body": (
"Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. "
"Please remove or reduce attachments."
)
diff --git a/src/backend/core/api/viewsets/placeholder.py b/src/backend/core/api/viewsets/placeholder.py
index 9a35be14..8efbb447 100644
--- a/src/backend/core/api/viewsets/placeholder.py
+++ b/src/backend/core/api/viewsets/placeholder.py
@@ -2,7 +2,6 @@
from django.conf import settings
from django.db.models import F
-from django.utils import translation
from drf_spectacular.utils import extend_schema
from rest_framework import permissions
@@ -48,10 +47,10 @@ class PlaceholderView(APIView):
)
def get(self, request):
"""Get the structure of available fields."""
- current_language = translation.get_language().split("-")[0]
+ current_language = settings.LANGUAGE_CODE.split("-")[0]
fields = {
- "name": translation.gettext_lazy("Name"),
- "recipient_name": translation.gettext_lazy("Recipient name"),
+ "name": "Name",
+ "recipient_name": "Recipient name",
}
# Add user custom attributes fields from schema
schema = settings.SCHEMA_CUSTOM_ATTRIBUTES_USER
diff --git a/src/backend/core/apps.py b/src/backend/core/apps.py
index b92ecf1d..79b3b360 100644
--- a/src/backend/core/apps.py
+++ b/src/backend/core/apps.py
@@ -1,7 +1,6 @@
"""Messages Core application"""
from django.apps import AppConfig
-from django.utils.translation import gettext_lazy as _
class CoreConfig(AppConfig):
@@ -9,7 +8,7 @@ class CoreConfig(AppConfig):
name = "core"
app_label = "core"
- verbose_name = _("messages core application")
+ verbose_name = "messages core application"
def ready(self):
"""Register signal handlers and prometheus collector when the app is ready."""
diff --git a/src/backend/core/authentication/backends.py b/src/backend/core/authentication/backends.py
index 451cadb8..795f8874 100644
--- a/src/backend/core/authentication/backends.py
+++ b/src/backend/core/authentication/backends.py
@@ -5,7 +5,6 @@ import re
from django.conf import settings
from django.core.exceptions import SuspiciousOperation
-from django.utils.translation import gettext_lazy as _
from lasuite.oidc_login.backends import (
OIDCAuthenticationBackend as LaSuiteOIDCAuthenticationBackend,
@@ -74,7 +73,7 @@ class OIDCAuthenticationBackend(LaSuiteOIDCAuthenticationBackend):
if user:
if not user.is_active:
- raise SuspiciousOperation(_("User account is disabled"))
+ raise SuspiciousOperation("User account is disabled")
self.update_user_if_needed(user, claims)
elif self.should_create_user(email):
diff --git a/src/backend/core/factories.py b/src/backend/core/factories.py
index a9571d0f..a9c6ea6c 100644
--- a/src/backend/core/factories.py
+++ b/src/backend/core/factories.py
@@ -1,4 +1,3 @@
-# ruff: noqa: S311
"""
Core application factories
"""
diff --git a/src/backend/core/management/commands/dns_check.py b/src/backend/core/management/commands/dns_check.py
index 0207df66..7dfbf6da 100644
--- a/src/backend/core/management/commands/dns_check.py
+++ b/src/backend/core/management/commands/dns_check.py
@@ -9,6 +9,8 @@ from core.services.dns.check import check_dns_records
class Command(BaseCommand):
+ """Check DNS records for mail domains."""
+
help = "Check DNS records for mail domains"
def add_arguments(self, parser):
diff --git a/src/backend/core/management/commands/dns_provision.py b/src/backend/core/management/commands/dns_provision.py
index ac053bd8..340f29f8 100644
--- a/src/backend/core/management/commands/dns_provision.py
+++ b/src/backend/core/management/commands/dns_provision.py
@@ -13,6 +13,8 @@ from core.services.dns.provisioning import (
class Command(BaseCommand):
+ """Provision DNS records for mail domains."""
+
help = "Provision DNS records for mail domains"
def add_arguments(self, parser):
@@ -49,8 +51,7 @@ class Command(BaseCommand):
except MailDomain.DoesNotExist:
if domain_name:
raise CommandError(f"Domain '{domain_name}' not found") from None
- else:
- raise CommandError(f"Domain with ID {domain_id} not found") from None
+ raise CommandError(f"Domain with ID {domain_id} not found") from None
if pretend:
self.stdout.write(
diff --git a/src/backend/core/management/commands/identity.py b/src/backend/core/management/commands/identity.py
index 45a16acf..5c9cf1bf 100644
--- a/src/backend/core/management/commands/identity.py
+++ b/src/backend/core/management/commands/identity.py
@@ -1,3 +1,5 @@
+"""Management command for Keycloak identity management."""
+
import logging
from django.core.management.base import BaseCommand, CommandError
@@ -14,6 +16,8 @@ logger = logging.getLogger(__name__)
class Command(BaseCommand):
+ """Identity management commands for Keycloak integration."""
+
help = "Identity management commands for Keycloak integration"
def add_arguments(self, parser):
@@ -126,7 +130,7 @@ class Command(BaseCommand):
except ValueError as e:
raise CommandError(str(e)) from e
- def resync_all(self, options):
+ def resync_all(self, options): # pylint: disable=unused-argument
"""Resync all mailboxes with identity_sync enabled to Keycloak."""
self.stdout.write(
self.style.SUCCESS("Starting resync of all mailboxes to Keycloak...")
diff --git a/src/backend/core/management/commands/print_sessions.py b/src/backend/core/management/commands/print_sessions.py
index 6e005a5f..46b0e7ee 100644
--- a/src/backend/core/management/commands/print_sessions.py
+++ b/src/backend/core/management/commands/print_sessions.py
@@ -1,3 +1,5 @@
+"""Management command to print active user sessions."""
+
import logging
from importlib import import_module
@@ -13,6 +15,8 @@ User = get_user_model()
class Command(BaseCommand):
+ """Print active user sessions with optional filters."""
+
help = "Print active user sessions with optional filters"
def add_arguments(self, parser):
@@ -31,7 +35,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
redis = get_redis_connection(settings.SESSION_CACHE_ALIAS)
engine = import_module(settings.SESSION_ENGINE)
- SessionStore = engine.SessionStore
+ session_store = engine.SessionStore
user_email_filter = options.get("email")
session_id_filter = options.get("session_id")
@@ -42,7 +46,7 @@ class Command(BaseCommand):
# If session ID filter is provided, check that specific session
if session_id_filter:
self._print_specific_session(
- redis, SessionStore, prefix, session_id_filter, verbose
+ redis, session_store, prefix, session_id_filter, verbose
)
return
@@ -55,7 +59,7 @@ class Command(BaseCommand):
for redis_key in redis_keys:
session_count += 1
- session_data = self._get_session_data(redis_key, SessionStore, prefix)
+ session_data = self._get_session_data(redis_key, session_store, prefix)
if not session_data:
continue
@@ -77,7 +81,7 @@ class Command(BaseCommand):
)
)
- def _get_session_data(self, redis_key, SessionStore, prefix):
+ def _get_session_data(self, redis_key, session_store, prefix):
"""Extract and validate session data."""
try:
# Extract actual session key
@@ -85,7 +89,7 @@ class Command(BaseCommand):
session_key = raw_key.replace(prefix, "")
# Load and decode session
- session = SessionStore(session_key=session_key)
+ session = session_store(session_key=session_key)
data = session.load()
user_id = data.get("_auth_user_id")
@@ -96,18 +100,19 @@ class Command(BaseCommand):
user = User.objects.get(id=user_id)
except User.DoesNotExist:
logger.warning(
- f"User with ID {user_id} not found for session {session_key}"
+ "User with ID %s not found for session %s", user_id, session_key
)
return None
return user, session_key, data
- # pylint: disable=broad-except
- except Exception as e:
- logger.error(f"Failed to process session {redis_key}: {e}")
+ except Exception as e: # pylint: disable=broad-exception-caught
+ logger.error("Failed to process session %s: %s", redis_key, e)
return None
- def _print_specific_session(self, redis, SessionStore, prefix, session_id, verbose):
+ def _print_specific_session(
+ self, redis, session_store, prefix, session_id, verbose
+ ):
"""Print information for a specific session ID."""
redis_key = f"{prefix}{session_id}".encode()
@@ -117,7 +122,7 @@ class Command(BaseCommand):
)
return
- session_data = self._get_session_data(redis_key, SessionStore, prefix)
+ session_data = self._get_session_data(redis_key, session_store, prefix)
if not session_data:
self.stdout.write(
self.style.ERROR(f"Could not load session data for ID '{session_id}'")
diff --git a/src/backend/core/management/commands/search_reindex.py b/src/backend/core/management/commands/search_reindex.py
index a6a9d51e..d7b77094 100644
--- a/src/backend/core/management/commands/search_reindex.py
+++ b/src/backend/core/management/commands/search_reindex.py
@@ -95,6 +95,7 @@ class Command(BaseCommand):
)
if result.get("failure_count", 0) > 0:
return 1
+ return None
def _reindex_thread(self, thread_id, async_mode):
"""Reindex a specific thread and its messages."""
@@ -115,7 +116,7 @@ class Command(BaseCommand):
self.style.SUCCESS(f"Reindexing task scheduled (ID: {task.id})")
)
else:
- result = reindex_thread_task(thread_id)
+ result = reindex_thread_task(thread_id) # pylint: disable=no-value-for-parameter
if result.get("success", False):
self.stdout.write(
self.style.SUCCESS(f"Thread {thread_id} indexed successfully")
@@ -127,6 +128,7 @@ class Command(BaseCommand):
)
)
return 1
+ return None
def _reindex_mailbox(self, mailbox_id, async_mode):
"""Reindex all threads and messages in a specific mailbox."""
@@ -146,7 +148,7 @@ class Command(BaseCommand):
self.style.SUCCESS(f"Reindexing task scheduled (ID: {task.id})")
)
else:
- result = reindex_mailbox_task(mailbox_id)
+ result = reindex_mailbox_task(mailbox_id) # pylint: disable=no-value-for-parameter
self.stdout.write(
self.style.SUCCESS(
f"Reindexing completed: {result.get('success_count', 0)} succeeded, "
@@ -155,3 +157,4 @@ class Command(BaseCommand):
)
if result.get("failure_count", 0) > 0:
return 1
+ return None
diff --git a/src/backend/core/management/commands/selfcheck.py b/src/backend/core/management/commands/selfcheck.py
index bd914ab1..e4523919 100644
--- a/src/backend/core/management/commands/selfcheck.py
+++ b/src/backend/core/management/commands/selfcheck.py
@@ -15,7 +15,6 @@ class Command(BaseCommand):
def add_arguments(self, parser):
"""Add command arguments."""
- pass
def handle(self, *args, **options):
"""Execute the command."""
diff --git a/src/backend/core/management/commands/send_mail.py b/src/backend/core/management/commands/send_mail.py
index 0818608e..d06e8340 100644
--- a/src/backend/core/management/commands/send_mail.py
+++ b/src/backend/core/management/commands/send_mail.py
@@ -31,6 +31,8 @@ logger = logging.getLogger(__name__)
class Command(BaseCommand):
+ """Send an email using send_outbound_email."""
+
help = "Send an email using send_outbound_email (works without mailboxes, no DB writes)"
def add_arguments(self, parser):
@@ -97,7 +99,8 @@ class Command(BaseCommand):
except models.Mailbox.DoesNotExist:
# Use minimal setup without mailbox
logger.warning(
- f"Mailbox with email '{from_email}' not found, sending without DKIM"
+ "Mailbox with email '%s' not found, sending without DKIM",
+ from_email,
)
else:
# Use minimal setup without mailbox
@@ -108,8 +111,8 @@ class Command(BaseCommand):
sender_mailbox.contact.name if sender_mailbox else None
) or from_email.split("@")[0]
- logger.info(f"Sending email from {from_email} to {to_email}")
- logger.info(f"Subject: {subject}")
+ logger.info("Sending email from %s to %s", from_email, to_email)
+ logger.info("Subject: %s", subject)
# Generate MIME ID
mime_id = (
diff --git a/src/backend/core/mda/draft.py b/src/backend/core/mda/draft.py
index 1ff9f6de..7303f5d4 100644
--- a/src/backend/core/mda/draft.py
+++ b/src/backend/core/mda/draft.py
@@ -6,7 +6,6 @@ from typing import Optional
from django.conf import settings
from django.utils import timezone
-from django.utils.translation import gettext_lazy as _
import rest_framework as drf
@@ -25,7 +24,7 @@ def validate_body_size(body_bytes: bytes) -> None:
raise drf.exceptions.ValidationError(
{
- "draftBody": _(
+ "draftBody": (
"Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. "
"Please reduce message content."
)
@@ -51,7 +50,7 @@ def validate_attachment_size(current_total_size: int, new_total_size: int) -> No
raise drf.exceptions.ValidationError(
{
- "attachments": _(
+ "attachments": (
"Cannot add attachment(s) (%(new_size)s MB). "
"Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. "
"Current attachments: %(current_size)s MB."
diff --git a/src/backend/core/mda/outbound.py b/src/backend/core/mda/outbound.py
index 3d5484dc..c2249b8a 100644
--- a/src/backend/core/mda/outbound.py
+++ b/src/backend/core/mda/outbound.py
@@ -7,7 +7,6 @@ from typing import Any, Optional
from django.conf import settings
from django.core.cache import cache
from django.utils import timezone
-from django.utils.translation import gettext_lazy as _
import rest_framework as drf
@@ -65,7 +64,7 @@ def prepare_outbound_message(
if recipient_count > max_recipients:
raise drf.exceptions.ValidationError(
{
- "message": _(
+ "message": (
"Too many recipients: %(count)s (maximum is %(max)s). "
"Please reduce the number of recipients before sending."
)
@@ -217,7 +216,7 @@ def prepare_outbound_message(
raise drf.exceptions.ValidationError(
{
- "message": _(
+ "message": (
"Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. "
"Please remove or reduce attachments."
)
@@ -303,7 +302,7 @@ def prepare_outbound_message(
raise drf.exceptions.ValidationError(
{
- "message": _(
+ "message": (
"The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. "
"Please reduce message content or attachments."
)
diff --git a/src/backend/core/models.py b/src/backend/core/models.py
index 93471ff6..c269846c 100644
--- a/src/backend/core/models.py
+++ b/src/backend/core/models.py
@@ -22,7 +22,6 @@ from django.db.models import Case, Q, When
from django.utils import timezone
from django.utils.html import escape
from django.utils.text import slugify
-from django.utils.translation import gettext_lazy as _
import jsonschema
import pyzstd
@@ -68,21 +67,21 @@ class BaseModel(models.Model):
"""
id = models.UUIDField(
- verbose_name=_("id"),
- help_text=_("primary key for the record as UUID"),
+ verbose_name="id",
+ help_text="primary key for the record as UUID",
primary_key=True,
default=uuid.uuid4,
editable=False,
)
created_at = models.DateTimeField(
- verbose_name=_("created on"),
- help_text=_("date and time at which a record was created"),
+ verbose_name="created on",
+ help_text="date and time at which a record was created",
auto_now_add=True,
editable=False,
)
updated_at = models.DateTimeField(
- verbose_name=_("updated on"),
- help_text=_("date and time at which a record was last updated"),
+ verbose_name="updated on",
+ help_text="date and time at which a record was last updated",
auto_now=True,
editable=False,
)
@@ -117,10 +116,8 @@ class UserManager(auth_models.UserManager):
and not settings.OIDC_ALLOW_DUPLICATE_EMAILS
):
raise DuplicateEmailError(
- _(
- "We couldn't find a user with this sub but the email is already "
- "associated with a registered user."
- )
+ "We couldn't find a user with this sub but the email is already "
+ "associated with a registered user."
) from err
return None
@@ -130,15 +127,15 @@ class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin):
sub_validator = validators.RegexValidator(
regex=r"^[\w.@+-:]+\Z",
- message=_(
+ message=(
"Enter a valid sub. This value may contain only letters, "
"numbers, and @/./+/-/_/: characters."
),
)
sub = models.CharField(
- _("sub"),
- help_text=_(
+ "sub",
+ help_text=(
"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
),
max_length=255,
@@ -148,48 +145,48 @@ class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin):
null=True,
)
- full_name = models.CharField(_("full name"), max_length=255, null=True, blank=True)
+ full_name = models.CharField("full name", max_length=255, null=True, blank=True)
- email = models.EmailField(_("identity email address"), blank=True, null=True)
+ email = models.EmailField("identity email address", blank=True, null=True)
# Unlike the "email" field which stores the email coming from the OIDC token, this field
# stores the email used by staff users to login to the admin site
admin_email = models.EmailField(
- _("admin email address"), unique=True, blank=True, null=True
+ "admin email address", unique=True, blank=True, null=True
)
language = models.CharField(
max_length=10,
choices=settings.LANGUAGES,
default=settings.LANGUAGE_CODE,
- verbose_name=_("language"),
- help_text=_("The language in which the user wants to see the interface."),
+ verbose_name="language",
+ help_text="The language in which the user wants to see the interface.",
)
timezone = TimeZoneField(
choices_display="WITH_GMT_OFFSET",
use_pytz=False,
default=settings.TIME_ZONE,
- help_text=_("The timezone in which the user wants to see times."),
+ help_text="The timezone in which the user wants to see times.",
)
is_staff = models.BooleanField(
- _("staff status"),
+ "staff status",
default=False,
- help_text=_("Whether the user can log into this admin site."),
+ help_text="Whether the user can log into this admin site.",
)
is_active = models.BooleanField(
- _("active"),
+ "active",
default=True,
- help_text=_(
+ help_text=(
"Whether this user should be treated as active. "
"Unselect this instead of deleting accounts."
),
)
custom_attributes = models.JSONField(
- _("Custom attributes"),
+ "Custom attributes",
default=dict,
blank=True,
- help_text=_("Metadata to sync to the user in the identity provider."),
+ help_text="Metadata to sync to the user in the identity provider.",
)
objects = UserManager()
@@ -199,8 +196,8 @@ class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin):
class Meta:
db_table = "messages_user"
- verbose_name = _("user")
- verbose_name_plural = _("users")
+ verbose_name = "user"
+ verbose_name_plural = "users"
def __str__(self):
return self.email or self.admin_email or str(self.id)
@@ -246,14 +243,14 @@ class MailDomain(BaseModel):
name_validator = validators.RegexValidator(
regex=r"^[a-z0-9][a-z0-9.-]*[a-z0-9]$",
- message=_(
+ message=(
"Enter a valid domain name. This value may contain only lowercase "
"letters, numbers, dots and - characters."
),
)
name = models.CharField(
- _("name"), max_length=253, unique=True, validators=[name_validator]
+ "name", max_length=253, unique=True, validators=[name_validator]
)
alias_of = models.ForeignKey(
@@ -261,37 +258,37 @@ class MailDomain(BaseModel):
)
oidc_autojoin = models.BooleanField(
- _("oidc autojoin"),
+ "oidc autojoin",
default=False,
- help_text=_("Create mailboxes automatically based on OIDC emails."),
+ help_text="Create mailboxes automatically based on OIDC emails.",
)
identity_sync = models.BooleanField(
- _("Identity sync"),
+ "Identity sync",
default=False,
- help_text=_("Sync mailboxes to an identity provider."),
+ help_text="Sync mailboxes to an identity provider.",
)
custom_settings = models.JSONField(
- _("Custom settings"),
+ "Custom settings",
default=dict,
blank=True,
- help_text=_("Custom settings for the mail domain."),
+ help_text="Custom settings for the mail domain.",
)
custom_attributes = models.JSONField(
- _("Custom attributes"),
+ "Custom attributes",
default=dict,
blank=True,
- help_text=_(
+ help_text=(
"Metadata to sync to the maildomain group in the identity provider."
),
)
class Meta:
db_table = "messages_maildomain"
- verbose_name = _("mail domain")
- verbose_name_plural = _("mail domains")
+ verbose_name = "mail domain"
+ verbose_name_plural = "mail domains"
def __str__(self):
return self.name
@@ -433,18 +430,18 @@ class Channel(BaseModel):
"""Channel model to store channel information for receiving messages from various sources."""
name = models.CharField(
- _("name"), max_length=255, help_text=_("Human-readable name for this channel")
+ "name", max_length=255, help_text="Human-readable name for this channel"
)
type = models.CharField(
- _("type"), max_length=255, help_text=_("Type of channel"), default="mta"
+ "type", max_length=255, help_text="Type of channel", default="mta"
)
settings = models.JSONField(
- _("settings"),
+ "settings",
default=dict,
blank=True,
- help_text=_("Channel-specific configuration settings"),
+ help_text="Channel-specific configuration settings",
)
mailbox = models.ForeignKey(
@@ -453,7 +450,7 @@ class Channel(BaseModel):
null=True,
blank=True,
related_name="channels",
- help_text=_("Mailbox that receives messages from this channel"),
+ help_text="Mailbox that receives messages from this channel",
)
maildomain = models.ForeignKey(
@@ -462,13 +459,13 @@ class Channel(BaseModel):
null=True,
blank=True,
related_name="channels",
- help_text=_("Mail domain that owns this channel"),
+ help_text="Mail domain that owns this channel",
)
class Meta:
db_table = "messages_channel"
- verbose_name = _("channel")
- verbose_name_plural = _("channels")
+ verbose_name = "channel"
+ verbose_name_plural = "channels"
ordering = ["-created_at"]
constraints = [
models.CheckConstraint(
@@ -487,7 +484,7 @@ class Mailbox(BaseModel):
"""Mailbox model to store mailbox information."""
local_part = models.CharField(
- _("local part"),
+ "local part",
max_length=64,
validators=[validators.RegexValidator(regex=r"^[a-zA-Z0-9_.-]+$")],
)
@@ -501,9 +498,9 @@ class Mailbox(BaseModel):
)
is_identity = models.BooleanField(
- _("is identity"),
+ "is identity",
default=True,
- help_text=_(
+ help_text=(
"Whether this mailbox identifies a person (i.e. is not an alias or a group)"
),
)
@@ -514,8 +511,8 @@ class Mailbox(BaseModel):
class Meta:
db_table = "messages_mailbox"
- verbose_name = _("mailbox")
- verbose_name_plural = _("mailboxes")
+ verbose_name = "mailbox"
+ verbose_name_plural = "mailboxes"
unique_together = ("local_part", "domain")
ordering = ["-created_at"]
@@ -720,19 +717,19 @@ class MailboxAccess(BaseModel):
"User", on_delete=models.CASCADE, related_name="mailbox_accesses"
)
role = models.SmallIntegerField(
- _("role"),
+ "role",
choices=MailboxRoleChoices.choices,
default=MailboxRoleChoices.VIEWER,
)
accessed_at = models.DateTimeField(
- _("accessed at"), null=True, blank=True, db_index=True
+ "accessed at", null=True, blank=True, db_index=True
)
class Meta:
db_table = "messages_mailboxaccess"
- verbose_name = _("mailbox access")
- verbose_name_plural = _("mailbox accesses")
+ verbose_name = "mailbox access"
+ verbose_name_plural = "mailbox accesses"
unique_together = ("mailbox", "user")
def __str__(self):
@@ -756,44 +753,44 @@ class MailboxAccess(BaseModel):
class Thread(BaseModel):
"""Thread model to group messages."""
- subject = models.CharField(_("subject"), max_length=255, null=True, blank=True)
- snippet = models.TextField(_("snippet"), blank=True)
- has_unread = models.BooleanField(_("has unread"), default=False)
- has_trashed = models.BooleanField(_("has trashed"), default=False)
+ subject = models.CharField("subject", max_length=255, null=True, blank=True)
+ snippet = models.TextField("snippet", blank=True)
+ has_unread = models.BooleanField("has unread", default=False)
+ has_trashed = models.BooleanField("has trashed", default=False)
is_trashed = models.BooleanField(
- _("is trashed"),
+ "is trashed",
default=False,
- help_text=_("Whether all messages in the thread are trashed"),
+ help_text="Whether all messages in the thread are trashed",
)
- has_archived = models.BooleanField(_("has archived"), default=False)
- has_draft = models.BooleanField(_("has draft"), default=False)
- has_starred = models.BooleanField(_("has starred"), default=False)
- has_sender = models.BooleanField(_("has sender"), default=False)
- has_messages = models.BooleanField(_("has messages"), default=True)
- has_attachments = models.BooleanField(_("has attachments"), default=False)
- is_spam = models.BooleanField(_("is spam"), default=False)
- has_active = models.BooleanField(_("has active"), default=False)
+ has_archived = models.BooleanField("has archived", default=False)
+ has_draft = models.BooleanField("has draft", default=False)
+ has_starred = models.BooleanField("has starred", default=False)
+ has_sender = models.BooleanField("has sender", default=False)
+ has_messages = models.BooleanField("has messages", default=True)
+ has_attachments = models.BooleanField("has attachments", default=False)
+ is_spam = models.BooleanField("is spam", default=False)
+ has_active = models.BooleanField("has active", default=False)
has_delivery_pending = models.BooleanField(
- _("has delivery pending"),
+ "has delivery pending",
default=False,
- help_text=_(
+ help_text=(
"True if thread has messages awaiting successful delivery "
"(sending, retrying, or failed)."
),
)
has_delivery_failed = models.BooleanField(
- _("has delivery failed"),
+ "has delivery failed",
default=False,
- help_text=_("True if thread has messages with permanent delivery failure."),
+ help_text="True if thread has messages with permanent delivery failure.",
)
- messaged_at = models.DateTimeField(_("messaged at"), null=True, blank=True)
- sender_names = models.JSONField(_("sender names"), null=True, blank=True)
- summary = models.TextField(_("summary"), null=True, blank=True, default=None)
+ messaged_at = models.DateTimeField("messaged at", null=True, blank=True)
+ sender_names = models.JSONField("sender names", null=True, blank=True)
+ summary = models.TextField("summary", null=True, blank=True, default=None)
class Meta:
db_table = "messages_thread"
- verbose_name = _("thread")
- verbose_name_plural = _("threads")
+ verbose_name = "thread"
+ verbose_name_plural = "threads"
def __str__(self):
return str(self.subject) if self.subject else "(no subject)"
@@ -962,52 +959,52 @@ class Label(BaseModel):
"""Label model to organize threads into folders using slash-based naming."""
name = models.CharField(
- _("name"),
+ "name",
max_length=255,
- help_text=_(
+ help_text=(
"Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
),
)
slug = models.SlugField(
- _("slug"),
+ "slug",
max_length=255,
- help_text=_("URL-friendly version of the name"),
+ help_text="URL-friendly version of the name",
)
color = models.CharField(
- _("color"),
+ "color",
max_length=7,
default="#E3E3FD",
- help_text=_("Color of the label in hex format (e.g. #FF0000)"),
+ help_text="Color of the label in hex format (e.g. #FF0000)",
)
mailbox = models.ForeignKey(
"Mailbox",
on_delete=models.CASCADE,
related_name="labels",
- help_text=_("Mailbox that owns this label"),
+ help_text="Mailbox that owns this label",
)
threads = models.ManyToManyField(
"Thread",
related_name="labels",
- help_text=_("Threads that have this label"),
+ help_text="Threads that have this label",
blank=True,
)
description = models.CharField(
- _("description"),
+ "description",
max_length=255,
blank=True,
default="",
- help_text=_("Description of the label, used by AI to understand its purpose"),
+ help_text="Description of the label, used by AI to understand its purpose",
)
is_auto = models.BooleanField(
- _("auto labeling"),
+ "auto labeling",
default=False,
- help_text=_("Whether this label should be automatically applied by AI"),
+ help_text="Whether this label should be automatically applied by AI",
)
class Meta:
db_table = "messages_label"
- verbose_name = _("label")
- verbose_name_plural = _("labels")
+ verbose_name = "label"
+ verbose_name_plural = "labels"
unique_together = ("slug", "mailbox")
ordering = ["slug"]
@@ -1171,15 +1168,15 @@ class ThreadAccess(BaseModel):
"Mailbox", on_delete=models.CASCADE, related_name="thread_accesses"
)
role = models.SmallIntegerField(
- _("role"),
+ "role",
choices=ThreadAccessRoleChoices.choices,
default=ThreadAccessRoleChoices.VIEWER,
)
class Meta:
db_table = "messages_threadaccess"
- verbose_name = _("thread access")
- verbose_name_plural = _("thread accesses")
+ verbose_name = "thread access"
+ verbose_name_plural = "thread accesses"
unique_together = ("thread", "mailbox")
def __str__(self):
@@ -1189,8 +1186,8 @@ class ThreadAccess(BaseModel):
class Contact(BaseModel):
"""Contact model to store contact information."""
- name = models.CharField(_("name"), max_length=255, null=True, blank=True)
- email = models.EmailField(_("email"))
+ name = models.CharField("name", max_length=255, null=True, blank=True)
+ email = models.EmailField("email")
mailbox = models.ForeignKey(
"Mailbox",
on_delete=models.CASCADE,
@@ -1199,8 +1196,8 @@ class Contact(BaseModel):
class Meta:
db_table = "messages_contact"
- verbose_name = _("contact")
- verbose_name_plural = _("contacts")
+ verbose_name = "contact"
+ verbose_name_plural = "contacts"
unique_together = ("email", "mailbox")
def __str__(self):
@@ -1222,26 +1219,26 @@ class MessageRecipient(BaseModel):
"Contact", on_delete=models.CASCADE, related_name="messages"
)
type = models.SmallIntegerField(
- _("type"),
+ "type",
choices=MessageRecipientTypeChoices.choices,
default=MessageRecipientTypeChoices.TO,
)
- delivered_at = models.DateTimeField(_("delivered at"), null=True, blank=True)
+ delivered_at = models.DateTimeField("delivered at", null=True, blank=True)
delivery_status = models.SmallIntegerField(
- _("delivery status"),
+ "delivery status",
null=True,
blank=True,
choices=MessageDeliveryStatusChoices.choices,
)
- delivery_message = models.TextField(_("delivery message"), null=True, blank=True)
- retry_count = models.IntegerField(_("retry count"), default=0)
- retry_at = models.DateTimeField(_("retry at"), null=True, blank=True)
+ delivery_message = models.TextField("delivery message", null=True, blank=True)
+ retry_count = models.IntegerField("retry count", default=0)
+ retry_at = models.DateTimeField("retry at", null=True, blank=True)
class Meta:
db_table = "messages_messagerecipient"
- verbose_name = _("message recipient")
- verbose_name_plural = _("message recipients")
+ verbose_name = "message recipient"
+ verbose_name_plural = "message recipients"
unique_together = ("message", "contact", "type")
def __str__(self):
@@ -1254,28 +1251,28 @@ class Message(BaseModel):
thread = models.ForeignKey(
Thread, on_delete=models.CASCADE, related_name="messages"
)
- subject = models.CharField(_("subject"), max_length=255, null=True, blank=True)
+ subject = models.CharField("subject", max_length=255, null=True, blank=True)
sender = models.ForeignKey("Contact", on_delete=models.CASCADE)
parent = models.ForeignKey(
"Message", on_delete=models.SET_NULL, null=True, blank=True
)
# Flags
- is_draft = models.BooleanField(_("is draft"), default=False)
- is_sender = models.BooleanField(_("is sender"), default=False)
- is_starred = models.BooleanField(_("is starred"), default=False)
- is_trashed = models.BooleanField(_("is trashed"), default=False)
- is_unread = models.BooleanField(_("is unread"), default=False)
- is_spam = models.BooleanField(_("is spam"), default=False)
- is_archived = models.BooleanField(_("is archived"), default=False)
- has_attachments = models.BooleanField(_("has attachments"), default=False)
+ is_draft = models.BooleanField("is draft", default=False)
+ is_sender = models.BooleanField("is sender", default=False)
+ is_starred = models.BooleanField("is starred", default=False)
+ is_trashed = models.BooleanField("is trashed", default=False)
+ is_unread = models.BooleanField("is unread", default=False)
+ is_spam = models.BooleanField("is spam", default=False)
+ is_archived = models.BooleanField("is archived", default=False)
+ has_attachments = models.BooleanField("has attachments", default=False)
- trashed_at = models.DateTimeField(_("trashed at"), null=True, blank=True)
- sent_at = models.DateTimeField(_("sent at"), null=True, blank=True)
- read_at = models.DateTimeField(_("read at"), null=True, blank=True)
- archived_at = models.DateTimeField(_("archived at"), null=True, blank=True)
+ trashed_at = models.DateTimeField("trashed at", null=True, blank=True)
+ sent_at = models.DateTimeField("sent at", null=True, blank=True)
+ read_at = models.DateTimeField("read at", null=True, blank=True)
+ archived_at = models.DateTimeField("archived at", null=True, blank=True)
- mime_id = models.CharField(_("mime id"), max_length=998, null=True, blank=True)
+ mime_id = models.CharField("mime id", max_length=998, null=True, blank=True)
channel = models.ForeignKey(
"Channel",
@@ -1303,7 +1300,7 @@ class Message(BaseModel):
)
signature = models.ForeignKey(
"MessageTemplate",
- help_text=_("Signature template for the message"),
+ help_text="Signature template for the message",
on_delete=models.SET_NULL,
null=True,
blank=True,
@@ -1315,8 +1312,8 @@ class Message(BaseModel):
class Meta:
db_table = "messages_message"
- verbose_name = _("message")
- verbose_name_plural = _("messages")
+ verbose_name = "message"
+ verbose_name_plural = "messages"
ordering = ["-created_at"]
def __str__(self):
@@ -1387,7 +1384,7 @@ class Message(BaseModel):
).select_related("contact")
cc = [str(mr.contact) for mr in cc_contacts]
# Subject
- subject = self.subject or _("No subject")
+ subject = self.subject or "No subject"
# Body: try to get text/plain from parsed data
body = ""
parsed_data = self.get_parsed_data()
@@ -1398,19 +1395,19 @@ class Message(BaseModel):
# Message ID
msg_id = str(self.id)
return (
- f"{_('Message ID')}: {msg_id}\n"
- f"{_('From')}: {sender}\n"
- f"{_('To')}: {', '.join(recipients)}\n"
- f"{_('CC')}: {', '.join(cc)}\n"
- f"{_('Date')}: {date_str}\n"
- f"{_('Subject')}: {subject}\n\n"
- f"{_('Body')}: {body}"
+ f"Message ID: {msg_id}\n"
+ f"From: {sender}\n"
+ f"To: {', '.join(recipients)}\n"
+ f"CC: {', '.join(cc)}\n"
+ f"Date: {date_str}\n"
+ f"Subject: {subject}\n\n"
+ f"Body: {body}"
)
def get_tokens_count(self) -> int:
"""Get the number of tokens in the message (subject + body)."""
# Subject
- subject = self.subject or _("No subject")
+ subject = self.subject or "No subject"
# Body: try to get text/plain from parsed data
body = ""
parsed_data = self.get_parsed_data()
@@ -1430,7 +1427,7 @@ class InboundMessage(BaseModel):
on_delete=models.CASCADE,
related_name="inbound_messages",
)
- raw_data = models.BinaryField(_("raw data"), help_text=_("Raw email message bytes"))
+ raw_data = models.BinaryField("raw data", help_text="Raw email message bytes")
channel = models.ForeignKey(
"Channel",
on_delete=models.SET_NULL,
@@ -1439,15 +1436,15 @@ class InboundMessage(BaseModel):
related_name="inbound_messages",
)
error_message = models.TextField(
- _("error message"),
+ "error message",
blank=True,
- help_text=_("Error message if processing failed"),
+ help_text="Error message if processing failed",
)
class Meta:
db_table = "messages_inboundmessage"
- verbose_name = _("inbound message")
- verbose_name_plural = _("inbound messages")
+ verbose_name = "inbound message"
+ verbose_name_plural = "inbound messages"
ordering = ["-created_at"]
indexes = [
models.Index(fields=["created_at"]),
@@ -1538,33 +1535,33 @@ class Blob(BaseModel):
"""
sha256 = models.BinaryField(
- _("sha256 hash"),
+ "sha256 hash",
max_length=32,
db_index=True,
- help_text=_("SHA-256 hash of the uncompressed blob content"),
+ help_text="SHA-256 hash of the uncompressed blob content",
)
size = models.PositiveIntegerField(
- _("file size"), help_text=_("Size of the blob in bytes")
+ "file size", help_text="Size of the blob in bytes"
)
size_compressed = models.PositiveIntegerField(
- _("compressed size"), help_text=_("Size of the compressed blob in bytes")
+ "compressed size", help_text="Size of the compressed blob in bytes"
)
content_type = models.CharField(
- _("content type"), max_length=127, help_text=_("MIME type of the blob")
+ "content type", max_length=127, help_text="MIME type of the blob"
)
compression = models.SmallIntegerField(
- _("compression"),
+ "compression",
choices=CompressionTypeChoices.choices,
default=CompressionTypeChoices.NONE,
)
raw_content = models.BinaryField(
- _("raw content"),
- help_text=_("Compressed binary content of the blob"),
+ "raw content",
+ help_text="Compressed binary content of the blob",
)
mailbox = models.ForeignKey(
@@ -1573,7 +1570,7 @@ class Blob(BaseModel):
blank=True,
on_delete=models.CASCADE,
related_name="blobs",
- help_text=_("Mailbox that owns this blob"),
+ help_text="Mailbox that owns this blob",
)
maildomain = models.ForeignKey(
"MailDomain",
@@ -1581,15 +1578,15 @@ class Blob(BaseModel):
blank=True,
on_delete=models.CASCADE,
related_name="blobs",
- help_text=_("Mail domain that owns this blob"),
+ help_text="Mail domain that owns this blob",
)
objects = BlobManager()
class Meta:
db_table = "messages_blob"
- verbose_name = _("blob")
- verbose_name_plural = _("blobs")
+ verbose_name = "blob"
+ verbose_name_plural = "blobs"
ordering = ["-created_at"]
constraints = [
models.CheckConstraint(
@@ -1629,43 +1626,43 @@ class Attachment(BaseModel):
"""Attachment model to link messages with blobs."""
name = models.CharField(
- _("file name"),
+ "file name",
max_length=255,
- help_text=_("Original filename of the attachment"),
+ help_text="Original filename of the attachment",
)
blob = models.ForeignKey(
"Blob",
on_delete=models.CASCADE,
related_name="attachments",
- help_text=_("Reference to the blob containing the attachment data"),
+ help_text="Reference to the blob containing the attachment data",
)
mailbox = models.ForeignKey(
"Mailbox",
on_delete=models.CASCADE,
related_name="attachments",
- help_text=_("Mailbox that owns this attachment"),
+ help_text="Mailbox that owns this attachment",
)
messages = models.ManyToManyField(
"Message",
related_name="attachments",
- help_text=_("Messages that use this attachment"),
+ help_text="Messages that use this attachment",
)
cid = models.CharField(
- _("content ID"),
+ "content ID",
max_length=255,
blank=True,
null=True,
- help_text=_("Content-ID for inline images"),
+ help_text="Content-ID for inline images",
)
class Meta:
db_table = "messages_attachment"
- verbose_name = _("attachment")
- verbose_name_plural = _("attachments")
+ verbose_name = "attachment"
+ verbose_name_plural = "attachments"
ordering = ["-created_at"]
def __str__(self):
@@ -1697,15 +1694,15 @@ class MailDomainAccess(BaseModel):
"User", on_delete=models.CASCADE, related_name="maildomain_accesses"
)
role = models.SmallIntegerField(
- _("role"),
+ "role",
choices=MailDomainAccessRoleChoices.choices,
default=MailDomainAccessRoleChoices.ADMIN,
)
class Meta:
db_table = "messages_maildomainaccess"
- verbose_name = _("mail domain access")
- verbose_name_plural = _("mail domain accesses")
+ verbose_name = "mail domain access"
+ verbose_name_plural = "mail domain accesses"
unique_together = ("maildomain", "user")
def __str__(self):
@@ -1716,50 +1713,50 @@ class DKIMKey(BaseModel):
"""DKIM Key model to store DKIM signing keys with encrypted private key storage."""
selector = models.CharField(
- _("selector"),
+ "selector",
max_length=255,
- help_text=_("DKIM selector (e.g., 'default', 'mail')"),
+ help_text="DKIM selector (e.g., 'default', 'mail')",
)
private_key = EncryptedTextField(
- _("private key"),
- help_text=_("DKIM private key in PEM format (encrypted)"),
+ "private key",
+ help_text="DKIM private key in PEM format (encrypted)",
)
public_key = models.TextField(
- _("public key"),
- help_text=_("DKIM public key for DNS record generation"),
+ "public key",
+ help_text="DKIM public key for DNS record generation",
)
algorithm = models.SmallIntegerField(
- _("algorithm"),
+ "algorithm",
choices=DKIMAlgorithmChoices.choices,
default=DKIMAlgorithmChoices.RSA,
- help_text=_("DKIM signing algorithm"),
+ help_text="DKIM signing algorithm",
)
key_size = models.PositiveIntegerField(
- _("key size"),
- help_text=_("Key size in bits (e.g., 2048, 4096 for RSA)"),
+ "key size",
+ help_text="Key size in bits (e.g., 2048, 4096 for RSA)",
)
is_active = models.BooleanField(
- _("is active"),
+ "is active",
default=True,
- help_text=_("Whether this DKIM key is active and should be used for signing"),
+ help_text="Whether this DKIM key is active and should be used for signing",
)
domain = models.ForeignKey(
"MailDomain",
on_delete=models.CASCADE,
related_name="dkim_keys",
- help_text=_("Domain that owns this DKIM key"),
+ help_text="Domain that owns this DKIM key",
)
class Meta:
db_table = "messages_dkimkey"
- verbose_name = _("DKIM key")
- verbose_name_plural = _("DKIM keys")
+ verbose_name = "DKIM key"
+ verbose_name_plural = "DKIM keys"
ordering = ["-created_at"] # Most recent first for picking latest active key
def __str__(self):
@@ -1779,9 +1776,9 @@ class MessageTemplate(BaseModel):
"""Message template model to store reusable message templates and signatures."""
name = models.CharField(
- _("name"),
+ "name",
max_length=255,
- help_text=_(
+ help_text=(
"Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
),
)
@@ -1792,22 +1789,22 @@ class MessageTemplate(BaseModel):
null=True,
blank=True,
related_name="message_templates",
- help_text=_(
+ help_text=(
"Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
),
)
type = models.SmallIntegerField(
- _("type"),
+ "type",
choices=MessageTemplateTypeChoices.choices,
default=MessageTemplateTypeChoices.MESSAGE,
- help_text=_("Type of template (message, signature)"),
+ help_text="Type of template (message, signature)",
)
is_active = models.BooleanField(
- _("is active"),
+ "is active",
default=True,
- help_text=_("Whether this template is available for use"),
+ help_text="Whether this template is available for use",
)
maildomain = models.ForeignKey(
@@ -1816,7 +1813,7 @@ class MessageTemplate(BaseModel):
blank=True,
on_delete=models.CASCADE,
related_name="message_templates",
- help_text=_("Mail domain that can use this template"),
+ help_text="Mail domain that can use this template",
)
mailbox = models.ForeignKey(
@@ -1825,29 +1822,29 @@ class MessageTemplate(BaseModel):
blank=True,
on_delete=models.CASCADE,
related_name="message_templates",
- help_text=_("Mailbox that can use this template"),
+ help_text="Mailbox that can use this template",
)
is_forced = models.BooleanField(
- _("is forced"),
+ "is forced",
default=False,
- help_text=_(
+ help_text=(
"Whether this template is forced; no other template of the same type can be used in the same scope"
),
)
is_default = models.BooleanField(
- _("is default"),
+ "is default",
default=False,
- help_text=_(
+ help_text=(
"Whether this template is the default; it will be automatically loaded when composing a new message"
),
)
class Meta:
db_table = "messages_messagetemplate"
- verbose_name = _("message template")
- verbose_name_plural = _("message templates")
+ verbose_name = "message template"
+ verbose_name_plural = "message templates"
ordering = ["-created_at"]
constraints = [
models.CheckConstraint(
diff --git a/src/backend/core/services/ai_service.py b/src/backend/core/services/ai_service.py
index b7398d45..0e78c5b4 100644
--- a/src/backend/core/services/ai_service.py
+++ b/src/backend/core/services/ai_service.py
@@ -1,3 +1,5 @@
+"""Service for AI-powered features using OpenAI-compatible API."""
+
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
diff --git a/src/backend/core/services/dns/check.py b/src/backend/core/services/dns/check.py
index 1cbb7fc6..02cda035 100644
--- a/src/backend/core/services/dns/check.py
+++ b/src/backend/core/services/dns/check.py
@@ -5,10 +5,10 @@ DNS checking functionality for mail domains.
import re
from typing import Dict, List
-from core.models import MailDomain
-
import dns.resolver
+from core.models import MailDomain
+
def normalize_txt_value(value: str) -> str:
"""
diff --git a/src/backend/core/services/dns/provisioning.py b/src/backend/core/services/dns/provisioning.py
index 47940877..68c98ddc 100644
--- a/src/backend/core/services/dns/provisioning.py
+++ b/src/backend/core/services/dns/provisioning.py
@@ -7,11 +7,11 @@ from typing import Any, Dict, Optional
from django.conf import settings
+import dns.resolver
+
from core.models import MailDomain
from core.services.dns.providers.scaleway import ScalewayDNSProvider
-import dns.resolver
-
logger = logging.getLogger(__name__)
diff --git a/src/backend/core/services/exporter/tasks.py b/src/backend/core/services/exporter/tasks.py
index 5bd8acbb..47f593f4 100644
--- a/src/backend/core/services/exporter/tasks.py
+++ b/src/backend/core/services/exporter/tasks.py
@@ -34,7 +34,7 @@ CHUNK_SIZE = 100 * 1024 * 1024
MIN_PART_SIZE = 5 * 1024 * 1024
-class S3MultipartGzipUploader:
+class S3MultipartGzipUploader: # pylint: disable=too-many-instance-attributes
"""
A file-like object that streams gzip-compressed data to S3 using multipart upload.
@@ -399,7 +399,7 @@ def _create_mbox_entry(
@celery_app.task(bind=True) # pylint: disable=too-many-locals
-def export_mailbox_task(self, mailbox_id: str, user_id: str) -> Dict[str, Any]:
+def export_mailbox_task(self, mailbox_id: str, user_id: str) -> Dict[str, Any]: # pylint: disable=unused-argument
"""
Export all messages from a mailbox to an MBOX file and upload to S3.
diff --git a/src/backend/core/services/identity/keycloak.py b/src/backend/core/services/identity/keycloak.py
index 2b6b6b3d..3e7862b0 100644
--- a/src/backend/core/services/identity/keycloak.py
+++ b/src/backend/core/services/identity/keycloak.py
@@ -212,8 +212,7 @@ def sync_mailbox_to_keycloak_user(mailbox):
for group in groups:
yield group
- for sub_group in group.get("subGroups") or []:
- yield sub_group
+ yield from group.get("subGroups") or []
for group in list_groups_and_subgroups():
if group.get("name") == group_name:
diff --git a/src/backend/core/services/importer/imap.py b/src/backend/core/services/importer/imap.py
index cbbdc9e8..622939b9 100644
--- a/src/backend/core/services/importer/imap.py
+++ b/src/backend/core/services/importer/imap.py
@@ -1,4 +1,11 @@
-"""IMAP utilities for message import."""
+"""IMAP utilities for message import.
+
+Broad exception handling (W0718) is intentional: IMAP servers can raise many
+different exception types (socket errors, encoding errors, protocol errors)
+and the import must continue processing remaining messages on failure.
+"""
+
+# pylint: disable=broad-exception-caught
import base64
import codecs
@@ -183,13 +190,13 @@ def _parse_imap_folder_info(folder_info: str) -> Optional[str]:
return None
-def get_selectable_folders(
+def get_selectable_folders( # pylint: disable=unused-argument
imap_connection, username: str, imap_server: str
) -> List[str]:
"""Get list of selectable folders from IMAP server."""
status, folder_list = imap_connection.list()
if status != "OK":
- raise Exception(f"Failed to list folders: {folder_list}")
+ raise RuntimeError(f"Failed to list folders: {folder_list}")
selectable_folders = []
for folder_info in folder_list:
@@ -281,7 +288,7 @@ def select_imap_folder(imap_connection, folder: str) -> bool:
return False
-def get_message_numbers(
+def get_message_numbers( # pylint: disable=unused-argument
imap_connection, folder: str, username: str, imap_server: str
) -> List[bytes]:
"""Get message numbers from the selected folder."""
@@ -409,7 +416,7 @@ def _fetch_message_with_flags(
# Fetch message with flags
status, msg_data = imap_connection.fetch(msg_num, "(FLAGS BODY.PEEK[])")
if status != "OK":
- raise Exception(f"Failed to fetch message {msg_num}: {msg_data}")
+ raise RuntimeError(f"Failed to fetch message {msg_num}: {msg_data}")
flags, raw_email = _extract_imap_flags_and_content(msg_data)
@@ -418,12 +425,12 @@ def _fetch_message_with_flags(
flags = _fetch_separate_flags(imap_connection, msg_num)
if raw_email is None:
- raise Exception(f"No raw email found for message {msg_num}")
+ raise RuntimeError(f"No raw email found for message {msg_num}")
return flags, raw_email
-def _fetch_message_with_flags_retry(
+def _fetch_message_with_flags_retry( # pylint: disable=inconsistent-return-statements
imap_connection, msg_num: bytes
) -> Tuple[List[str], Optional[bytes]]:
"""Fetch a message with retry logic for timeout errors."""
@@ -442,13 +449,12 @@ def _fetch_message_with_flags_retry(
# Exponential backoff
time.sleep(2**attempt)
continue
- else:
- logger.error(
- "Failed to fetch message %s after %d attempts",
- msg_num,
- max_retries,
- )
- raise
+ logger.error(
+ "Failed to fetch message %s after %d attempts",
+ msg_num,
+ max_retries,
+ )
+ raise
except Exception as e:
logger.error("Unexpected error fetching message %s: %s", msg_num, e)
raise
diff --git a/src/backend/core/services/importer/labels.py b/src/backend/core/services/importer/labels.py
index bfe513f5..e5e7642f 100644
--- a/src/backend/core/services/importer/labels.py
+++ b/src/backend/core/services/importer/labels.py
@@ -140,6 +140,6 @@ def handle_duplicate_message(
)
existing_message.thread.labels.add(label_obj)
- except Exception as e:
+ except Exception as e: # pylint: disable=broad-exception-caught
logger.exception("Error creating label %s: %s", label, e)
continue
diff --git a/src/backend/core/services/importer/pst.py b/src/backend/core/services/importer/pst.py
index 4642c0ce..580b9ba4 100644
--- a/src/backend/core/services/importer/pst.py
+++ b/src/backend/core/services/importer/pst.py
@@ -1,4 +1,11 @@
-"""PST file parsing utilities for message import."""
+"""PST file parsing utilities for message import.
+
+Broad exception handling (W0718/C0302) is intentional: PST parsing relies on
+the pypff C library which can raise arbitrary exceptions on malformed data.
+Each field extraction must be individually guarded to maximise data recovery.
+"""
+
+# pylint: disable=broad-exception-caught,too-many-lines
import base64
import logging
@@ -565,9 +572,9 @@ def _extract_recipients_from_mapi(message) -> dict:
result = {"to": [], "cc": [], "bcc": []}
# MAPI recipient types
- MAPI_TO = 1
- MAPI_CC = 2
- MAPI_BCC = 3
+ MAPI_TO = 1 # pylint: disable=invalid-name
+ MAPI_CC = 2 # pylint: disable=invalid-name
+ MAPI_BCC = 3 # pylint: disable=invalid-name
try:
num_recipients = int(message.number_of_recipients)
@@ -651,7 +658,7 @@ def _decode_html_bytes(raw_html: bytes) -> str:
return raw_html.decode("utf-8", errors="replace")
-def reconstruct_eml(message, store_email: Optional[str] = None) -> bytes:
+def reconstruct_eml(message, store_email: Optional[str] = None) -> bytes: # pylint: disable=too-many-branches
"""Convert a pypff message to RFC5322 bytes.
If transport_headers is available, uses those for threading headers.
diff --git a/src/backend/core/services/importer/s3_seekable.py b/src/backend/core/services/importer/s3_seekable.py
index 7776ea51..d1077613 100644
--- a/src/backend/core/services/importer/s3_seekable.py
+++ b/src/backend/core/services/importer/s3_seekable.py
@@ -11,7 +11,7 @@ BUFFER_CENTERED = "centered"
BUFFER_NONE = "none"
-class S3SeekableReader:
+class S3SeekableReader: # pylint: disable=too-many-instance-attributes
"""Seekable file-like object that reads from S3 using range requests.
Maintains a read-ahead buffer (default 100MB) and makes HTTP Range
diff --git a/src/backend/core/services/importer/service.py b/src/backend/core/services/importer/service.py
index cbbb70d6..d1c7f725 100644
--- a/src/backend/core/services/importer/service.py
+++ b/src/backend/core/services/importer/service.py
@@ -76,16 +76,15 @@ class ImportService:
"mbox": "application/mbox",
"pst": "application/vnd.ms-outlook",
}
- if ext in extension_map:
- content_type = extension_map[ext]
+ content_type = extension_map.get(ext, content_type)
if content_type not in enums.ARCHIVE_SUPPORTED_MIME_TYPES:
return False, {
"detail": (
- "Invalid file format. Only EML, MBOX, "
- "and PST files are supported. "
- "Detected content type: {content_type}"
- ).format(content_type=content_type)
+ f"Invalid file format. Only EML, MBOX, "
+ f"and PST files are supported. "
+ f"Detected content type: {content_type}"
+ )
}
try:
@@ -102,7 +101,7 @@ class ImportService:
)
return True, response_data
# Check MIME type for MBOX
- elif content_type in enums.MBOX_SUPPORTED_MIME_TYPES:
+ if content_type in enums.MBOX_SUPPORTED_MIME_TYPES:
# Process MBOX file asynchronously
task = process_mbox_file_task.delay(file_key, str(recipient.id))
register_task_owner(task.id, user.id)
@@ -115,7 +114,7 @@ class ImportService:
)
return True, response_data
# Check MIME type for EML
- elif content_type in enums.EML_SUPPORTED_MIME_TYPES:
+ if content_type in enums.EML_SUPPORTED_MIME_TYPES:
# Process EML file asynchronously
task = process_eml_file_task.delay(file_key, str(recipient.id))
register_task_owner(task.id, user.id)
@@ -127,9 +126,8 @@ class ImportService:
"This may take a while. You can check the status in the Celery task monitor.",
)
return True, response_data
- else:
- return False, {"detail": f"Unsupported file format: {content_type}"}
- except Exception as e:
+ return False, {"detail": f"Unsupported file format: {content_type}"}
+ except Exception as e: # pylint: disable=broad-exception-caught
capture_exception(e)
logger.exception("Error processing file: %s", e)
if request:
@@ -192,7 +190,7 @@ class ImportService:
)
return True, response_data
- except Exception as e:
+ except Exception as e: # pylint: disable=broad-exception-caught
capture_exception(e)
logger.exception("Error starting IMAP import: %s", e)
if request:
diff --git a/src/backend/core/services/search/search.py b/src/backend/core/services/search/search.py
index a28c1b6b..0826b6d4 100644
--- a/src/backend/core/services/search/search.py
+++ b/src/backend/core/services/search/search.py
@@ -14,7 +14,7 @@ from core.services.search.parse import parse_search_query
logger = logging.getLogger(__name__)
-def search_threads(
+def search_threads( # pylint: disable=too-many-branches
query: str,
mailbox_ids: Optional[list] = None,
filters: Optional[Dict[str, Any]] = None,
@@ -41,7 +41,7 @@ def search_threads(
logger.debug("OpenSearch search is disabled, returning empty results")
return {"threads": [], "total": 0, "from": from_offset, "size": size}
- try:
+ try: # pylint: disable=too-many-nested-blocks
es = get_opensearch_client()
# Parse the query for modifiers
@@ -167,7 +167,7 @@ def search_threads(
{"term": {"is_trashed": True}}
)
else:
- # Fully trashed threads should be excluded from search results until the user explicitly searches for trashed threads
+ # Exclude fully trashed threads unless the user explicitly searches for them
search_body["query"]["bool"]["filter"].append(
{"term": {"is_trashed": False}}
)
diff --git a/src/backend/core/services/throttle.py b/src/backend/core/services/throttle.py
index b9f7cc69..b96f8585 100644
--- a/src/backend/core/services/throttle.py
+++ b/src/backend/core/services/throttle.py
@@ -64,12 +64,11 @@ def get_period_key(period_name: str) -> str:
now = timezone.now()
if period_name == "day":
return now.strftime("%Y-%m-%d")
- elif period_name == "hour":
+ if period_name == "hour":
return now.strftime("%Y-%m-%d-%H")
- elif period_name == "minute":
+ if period_name == "minute":
return now.strftime("%Y-%m-%d-%H-%M")
- else:
- return now.strftime("%Y-%m-%d")
+ return now.strftime("%Y-%m-%d")
def get_period_expiry(period_name: str) -> int:
@@ -81,16 +80,15 @@ def get_period_expiry(period_name: str) -> int:
hour=0, minute=0, second=0, microsecond=0
)
return int((tomorrow - now).total_seconds())
- elif period_name == "hour":
+ if period_name == "hour":
next_hour = (now + timedelta(hours=1)).replace(
minute=0, second=0, microsecond=0
)
return int((next_hour - now).total_seconds())
- elif period_name == "minute":
+ if period_name == "minute":
next_minute = (now + timedelta(minutes=1)).replace(second=0, microsecond=0)
return int((next_minute - now).total_seconds())
- else:
- return 86400
+ return 86400
def get_throttle_cache_key(entity_type: str, entity_id: str, period_key: str) -> str:
@@ -119,7 +117,7 @@ def increment_counter(cache_key: str, amount: int, expiry_seconds: int) -> int:
return amount
-def decrement_counter(cache_key: str, amount: int, expiry_seconds: int) -> int:
+def decrement_counter(cache_key: str, amount: int, expiry_seconds: int) -> int: # pylint: disable=unused-argument
"""
Decrement a counter in cache and return the new value.
@@ -255,7 +253,7 @@ def check_and_increment_throttle(mailbox, maildomain, message) -> None:
decrement_counter(
inc_check["cache_key"], external_count, inc_check["expiry"]
)
- except Exception as rollback_error:
+ except Exception as rollback_error: # pylint: disable=broad-exception-caught
logger.error("Failed to rollback throttle counter: %s", rollback_error)
raise
@@ -313,9 +311,8 @@ def format_duration(seconds: int) -> str:
"""Format seconds into a human-readable duration."""
if seconds < 60:
return f"{seconds}s"
- elif seconds < 3600:
+ if seconds < 3600:
minutes = math.ceil(seconds / 60)
return f"{minutes}m"
- else:
- hours = math.ceil(seconds / 3600)
- return f"{hours}h"
+ hours = math.ceil(seconds / 3600)
+ return f"{hours}h"
diff --git a/src/backend/core/tests/api/test_placeholder.py b/src/backend/core/tests/api/test_placeholder.py
index 26af00bf..1015b7bd 100644
--- a/src/backend/core/tests/api/test_placeholder.py
+++ b/src/backend/core/tests/api/test_placeholder.py
@@ -113,20 +113,13 @@ class TestPlaceholderView:
"required": [],
}
)
- def test_internationalization_support(self, api_client):
- """Test that internationalization is properly handled."""
+ def test_i18n_schema_uses_default_language(self, api_client):
+ """Test that x-i18n schema labels always use the default language."""
url = reverse("placeholders")
+ # Accept-Language header is ignored; backend always uses LANGUAGE_CODE
response = api_client.get(url, HTTP_ACCEPT_LANGUAGE="fr-fr")
assert response.status_code == status.HTTP_200_OK
data = response.json()
- assert data["job_title"] == "Fonction"
- assert data["is_elected"] == "Est รฉlu"
- assert data["name"] == "Nom"
-
- # Test that fallback language handling works correctly.
- response = api_client.get(url, HTTP_ACCEPT_LANGUAGE="de-de")
- assert response.status_code == status.HTTP_200_OK
- data = response.json()
assert data["job_title"] == "Job title"
assert data["is_elected"] == "Is elected"
assert data["name"] == "Name"
diff --git a/src/backend/core/tests/dns/test_check.py b/src/backend/core/tests/dns/test_check.py
index 05e8490c..08e7a8ba 100644
--- a/src/backend/core/tests/dns/test_check.py
+++ b/src/backend/core/tests/dns/test_check.py
@@ -773,7 +773,6 @@ class TestDNSChecking: # pylint: disable=too-many-public-methods
@pytest.fixture(name="maildomain_factory")
-@pytest.mark.django_db
def fixture_maildomain_factory():
"""Factory for creating test mail domains."""
diff --git a/src/backend/core/tests/dns/test_provisioning.py b/src/backend/core/tests/dns/test_provisioning.py
index 98232918..56ecdb0d 100644
--- a/src/backend/core/tests/dns/test_provisioning.py
+++ b/src/backend/core/tests/dns/test_provisioning.py
@@ -276,7 +276,6 @@ class TestDNSProvisioning:
@pytest.fixture(name="maildomain_factory")
-@pytest.mark.django_db
def fixture_maildomain_factory():
"""Create a maildomain factory for testing."""
diff --git a/src/backend/core/tests/models/test_maildomain.py b/src/backend/core/tests/models/test_maildomain.py
index 6016d3be..8aebfaf5 100644
--- a/src/backend/core/tests/models/test_maildomain.py
+++ b/src/backend/core/tests/models/test_maildomain.py
@@ -118,10 +118,11 @@ class TestMailDomainModel:
}
with pytest.raises(ValidationError) as exception_info:
MailDomainFactory(custom_attributes=custom_attributes)
- assert (
- str(exception_info.value)
- == "{'custom_attributes': [\"Additional properties are not allowed ('additional_property' was unexpected)\"]}"
+ expected = (
+ """{'custom_attributes': ["Additional properties are not allowed"""
+ """ ('additional_property' was unexpected)"]}"""
)
+ assert str(exception_info.value) == expected
class TestMailDomainModelAbilities:
diff --git a/src/backend/core/tests/models/test_maildomainaccess.py b/src/backend/core/tests/models/test_maildomainaccess.py
index 6ef8164f..c5e9158e 100644
--- a/src/backend/core/tests/models/test_maildomainaccess.py
+++ b/src/backend/core/tests/models/test_maildomainaccess.py
@@ -1,3 +1,5 @@
+"""Tests for the MailDomainAccess model."""
+
from django.core.exceptions import ValidationError
import pytest
@@ -9,7 +11,10 @@ pytestmark = pytest.mark.django_db
class TestMailDomainAccessModel:
+ """Tests for MailDomainAccess model CRUD and constraints."""
+
def test_create_mail_domain_access(self):
+ """Test creating a MailDomainAccess instance."""
user = factories.UserFactory()
maildomain = factories.MailDomainFactory()
@@ -26,6 +31,7 @@ class TestMailDomainAccessModel:
)
def test_unique_together_constraint(self):
+ """Test that duplicate user+maildomain access is rejected."""
user = factories.UserFactory()
maildomain = factories.MailDomainFactory()
@@ -41,6 +47,7 @@ class TestMailDomainAccessModel:
)
def test_related_names(self):
+ """Test reverse relation names on User and MailDomain."""
user = factories.UserFactory()
maildomain = factories.MailDomainFactory()
access = factories.MailDomainAccessFactory(user=user, maildomain=maildomain)
diff --git a/src/backend/core/tests/models/test_users.py b/src/backend/core/tests/models/test_users.py
index dc42eb13..9df567fe 100644
--- a/src/backend/core/tests/models/test_users.py
+++ b/src/backend/core/tests/models/test_users.py
@@ -63,7 +63,8 @@ class TestUserModel:
custom_attributes = {"job_title": "test", "additional_property": "should fail"}
with pytest.raises(ValidationError) as exception_info:
factories.UserFactory(custom_attributes=custom_attributes)
- assert (
- str(exception_info.value)
- == "{'custom_attributes': [\"Additional properties are not allowed ('additional_property' was unexpected)\"]}"
+ expected = (
+ """{'custom_attributes': ["Additional properties are not allowed"""
+ """ ('additional_property' was unexpected)"]}"""
)
+ assert str(exception_info.value) == expected
diff --git a/src/backend/core/tests/search/test_search.py b/src/backend/core/tests/search/test_search.py
index 25371df0..d49bb45a 100644
--- a/src/backend/core/tests/search/test_search.py
+++ b/src/backend/core/tests/search/test_search.py
@@ -148,7 +148,7 @@ def test_reindex_all(mock_es_client_index):
@pytest.mark.django_db
-def test_reindex_mailbox(mock_es_client_index, test_mailbox, test_thread):
+def test_reindex_mailbox(mock_es_client_index, test_mailbox, test_thread): # pylint: disable=unused-argument
"""Test reindexing a specific mailbox."""
# Call the function
diff --git a/src/backend/core/tests/tasks/test_task_importer.py b/src/backend/core/tests/tasks/test_task_importer.py
index bb5f1dfd..7aae1f59 100644
--- a/src/backend/core/tests/tasks/test_task_importer.py
+++ b/src/backend/core/tests/tasks/test_task_importer.py
@@ -324,7 +324,7 @@ class TestProcessMboxFileTask:
finally:
s3_client.delete_object(Bucket=storage.bucket_name, Key=file_key)
- def test_task_process_mbox_file_mailbox_not_found(self, sample_mbox_content):
+ def test_task_process_mbox_file_mailbox_not_found(self, sample_mbox_content): # pylint: disable=unused-argument
"""Test MBOX processing with non-existent mailbox."""
mock_task = MagicMock()
mock_task.update_state = MagicMock()
diff --git a/src/backend/core/tests/tasks/test_task_send_message.py b/src/backend/core/tests/tasks/test_task_send_message.py
index 3cf46519..ce3ef44d 100644
--- a/src/backend/core/tests/tasks/test_task_send_message.py
+++ b/src/backend/core/tests/tasks/test_task_send_message.py
@@ -40,7 +40,7 @@ class TestSendMessageTask:
self, draft_message, mailbox_with_thread
):
"""Test send_message_task with must_archive=True archives all thread messages."""
- mailbox, thread = mailbox_with_thread
+ _, thread = mailbox_with_thread
# Create additional messages in the same thread
other_message1 = factories.MessageFactory(
@@ -68,7 +68,9 @@ class TestSendMessageTask:
with patch("core.mda.outbound_tasks.send_message") as mock_mda_send:
# Call the task with must_archive=True
with patch.object(send_message_task, "update_state"):
- result = send_message_task(str(draft_message.id), must_archive=True)
+ result = send_message_task( # pylint: disable=no-value-for-parameter
+ str(draft_message.id), must_archive=True
+ )
# Verify send_message was called
mock_mda_send.assert_called_once_with(draft_message, False)
@@ -94,7 +96,7 @@ class TestSendMessageTask:
self, draft_message, mailbox_with_thread
):
"""Test send_message_task with must_archive=False does not archive messages."""
- mailbox, thread = mailbox_with_thread
+ _, thread = mailbox_with_thread
# Create additional messages in the same thread
other_message = factories.MessageFactory(
@@ -114,7 +116,9 @@ class TestSendMessageTask:
with patch("core.mda.outbound_tasks.send_message") as mock_mda_send:
# Call the task with must_archive=False
with patch.object(send_message_task, "update_state"):
- result = send_message_task(str(draft_message.id), must_archive=False)
+ result = send_message_task( # pylint: disable=no-value-for-parameter
+ str(draft_message.id), must_archive=False
+ )
# Verify the result
assert result["success"] is True
@@ -134,7 +138,9 @@ class TestSendMessageTask:
assert other_message.archived_at is None
def test_task_send_message_archive_error_does_not_fail_task(
- self, draft_message, mailbox_with_thread
+ self,
+ draft_message,
+ mailbox_with_thread, # pylint: disable=unused-argument
):
"""Test that archiving error does not cause the task to fail."""
assert draft_message.is_draft is True
@@ -150,7 +156,9 @@ class TestSendMessageTask:
# Call the task with must_archive=True
# The task should succeed even if archiving fails
with patch.object(send_message_task, "update_state"):
- result = send_message_task(str(draft_message.id), must_archive=True)
+ result = send_message_task( # pylint: disable=no-value-for-parameter
+ str(draft_message.id), must_archive=True
+ )
# Verify send_message was called
mock_mda_send.assert_called_once_with(draft_message, False)
@@ -160,7 +168,9 @@ class TestSendMessageTask:
assert result["message_id"] == str(draft_message.id)
def test_task_send_message_updates_thread_stats_after_archive(
- self, draft_message, mailbox_with_thread
+ self,
+ draft_message,
+ mailbox_with_thread, # pylint: disable=unused-argument
):
"""Test that thread stats are updated after archiving."""
# Mock the send_message function
@@ -169,7 +179,9 @@ class TestSendMessageTask:
with patch("core.models.Thread.update_stats") as mock_update_stats:
# Call the task with must_archive=True
with patch.object(send_message_task, "update_state"):
- result = send_message_task(str(draft_message.id), must_archive=True)
+ result = send_message_task( # pylint: disable=no-value-for-parameter
+ str(draft_message.id), must_archive=True
+ )
# Verify the result
assert result["success"] is True
diff --git a/src/backend/locale/br_FR/LC_MESSAGES/django.mo b/src/backend/locale/br_FR/LC_MESSAGES/django.mo
deleted file mode 100644
index b05712f8..00000000
Binary files a/src/backend/locale/br_FR/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/br_FR/LC_MESSAGES/django.po b/src/backend/locale/br_FR/LC_MESSAGES/django.po
deleted file mode 100644
index 309bf8b5..00000000
--- a/src/backend/locale/br_FR/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: Breton\n"
-"Language: br_FR\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=5; plural=(n%10==1 && (n%100!=11 || n%100!=71 || n%100!=91) ? 0 : n%10==2 && (n%100!=12 || n%100!=72 || n%100!=92) ? 1 : ((n%10>=3 && n%10<=4) || n%10==9) && ((n%100 < 10 || n%100 > 19) || (n%100 < 70 || n%100 > 79) || (n%100 < 90 || n%100 > 99)) ? 2 : (n!=0 && n%1;\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: br-FR\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr ""
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr ""
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr ""
-
-msgid "Personal info"
-msgstr ""
-
-msgid "Permissions"
-msgstr ""
-
-msgid "Important dates"
-msgstr ""
-
-msgid "Mail domain not found."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr ""
-
-msgid "Metadata"
-msgstr ""
-
-msgid "Labels"
-msgstr ""
-
-msgid "No labels"
-msgstr ""
-
-msgid "Import Messages"
-msgstr ""
-
-msgid "Import Messages from IMAP"
-msgstr ""
-
-msgid "Message not found."
-msgstr ""
-
-msgid "No pending recipients found for this message."
-msgstr ""
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr ""
-
-msgid "Keys"
-msgstr ""
-
-msgid "Error"
-msgstr ""
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr ""
-
-msgid "Name"
-msgstr ""
-
-msgid "Recipient name"
-msgstr ""
-
-msgid "messages core application"
-msgstr ""
-
-msgid "User account is disabled"
-msgstr ""
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr ""
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr ""
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr ""
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr ""
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr ""
-
-msgid "id"
-msgstr ""
-
-msgid "primary key for the record as UUID"
-msgstr ""
-
-msgid "created on"
-msgstr ""
-
-msgid "date and time at which a record was created"
-msgstr ""
-
-msgid "updated on"
-msgstr ""
-
-msgid "date and time at which a record was last updated"
-msgstr ""
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr ""
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr ""
-
-msgid "sub"
-msgstr ""
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr ""
-
-msgid "full name"
-msgstr ""
-
-msgid "identity email address"
-msgstr ""
-
-msgid "admin email address"
-msgstr ""
-
-msgid "language"
-msgstr ""
-
-msgid "The language in which the user wants to see the interface."
-msgstr ""
-
-msgid "The timezone in which the user wants to see times."
-msgstr ""
-
-msgid "staff status"
-msgstr ""
-
-msgid "Whether the user can log into this admin site."
-msgstr ""
-
-msgid "active"
-msgstr ""
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr ""
-
-msgid "Custom attributes"
-msgstr ""
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr ""
-
-msgid "user"
-msgstr ""
-
-msgid "users"
-msgstr ""
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr ""
-
-msgid "name"
-msgstr ""
-
-msgid "oidc autojoin"
-msgstr ""
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr ""
-
-msgid "Identity sync"
-msgstr ""
-
-msgid "Sync mailboxes to an identity provider."
-msgstr ""
-
-msgid "Custom settings"
-msgstr ""
-
-msgid "Custom settings for the mail domain."
-msgstr ""
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr ""
-
-msgid "mail domain"
-msgstr ""
-
-msgid "mail domains"
-msgstr ""
-
-msgid "Human-readable name for this channel"
-msgstr ""
-
-msgid "type"
-msgstr ""
-
-msgid "Type of channel"
-msgstr ""
-
-msgid "settings"
-msgstr ""
-
-msgid "Channel-specific configuration settings"
-msgstr ""
-
-msgid "Mailbox that receives messages from this channel"
-msgstr ""
-
-msgid "Mail domain that owns this channel"
-msgstr ""
-
-msgid "channel"
-msgstr ""
-
-msgid "channels"
-msgstr ""
-
-msgid "local part"
-msgstr ""
-
-msgid "is identity"
-msgstr ""
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr ""
-
-msgid "mailbox"
-msgstr ""
-
-msgid "mailboxes"
-msgstr ""
-
-msgid "role"
-msgstr ""
-
-msgid "accessed at"
-msgstr ""
-
-msgid "mailbox access"
-msgstr ""
-
-msgid "mailbox accesses"
-msgstr ""
-
-msgid "subject"
-msgstr ""
-
-msgid "snippet"
-msgstr ""
-
-msgid "has unread"
-msgstr ""
-
-msgid "has trashed"
-msgstr ""
-
-msgid "is trashed"
-msgstr ""
-
-msgid "Whether all messages in the thread are trashed"
-msgstr ""
-
-msgid "has archived"
-msgstr ""
-
-msgid "has draft"
-msgstr ""
-
-msgid "has starred"
-msgstr ""
-
-msgid "has sender"
-msgstr ""
-
-msgid "has messages"
-msgstr ""
-
-msgid "has attachments"
-msgstr ""
-
-msgid "is spam"
-msgstr ""
-
-msgid "has active"
-msgstr ""
-
-msgid "messaged at"
-msgstr ""
-
-msgid "sender names"
-msgstr ""
-
-msgid "summary"
-msgstr ""
-
-msgid "thread"
-msgstr ""
-
-msgid "threads"
-msgstr ""
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr ""
-
-msgid "slug"
-msgstr ""
-
-msgid "URL-friendly version of the name"
-msgstr ""
-
-msgid "color"
-msgstr ""
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr ""
-
-msgid "Mailbox that owns this label"
-msgstr ""
-
-msgid "Threads that have this label"
-msgstr ""
-
-msgid "description"
-msgstr ""
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr ""
-
-msgid "auto labeling"
-msgstr ""
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr ""
-
-msgid "label"
-msgstr ""
-
-msgid "labels"
-msgstr ""
-
-msgid "thread access"
-msgstr ""
-
-msgid "thread accesses"
-msgstr ""
-
-msgid "email"
-msgstr ""
-
-msgid "contact"
-msgstr ""
-
-msgid "contacts"
-msgstr ""
-
-msgid "delivered at"
-msgstr ""
-
-msgid "delivery message"
-msgstr ""
-
-msgid "retry count"
-msgstr ""
-
-msgid "retry at"
-msgstr ""
-
-msgid "message recipient"
-msgstr ""
-
-msgid "message recipients"
-msgstr ""
-
-msgid "is draft"
-msgstr ""
-
-msgid "is sender"
-msgstr ""
-
-msgid "is starred"
-msgstr ""
-
-msgid "is unread"
-msgstr ""
-
-msgid "is archived"
-msgstr ""
-
-msgid "trashed at"
-msgstr ""
-
-msgid "sent at"
-msgstr ""
-
-msgid "read at"
-msgstr ""
-
-msgid "archived at"
-msgstr ""
-
-msgid "mime id"
-msgstr ""
-
-msgid "Signature template for the message"
-msgstr ""
-
-msgid "message"
-msgstr ""
-
-msgid "messages"
-msgstr ""
-
-msgid "No subject"
-msgstr ""
-
-msgid "Message ID"
-msgstr ""
-
-msgid "From"
-msgstr ""
-
-msgid "To"
-msgstr ""
-
-msgid "CC"
-msgstr ""
-
-msgid "Date"
-msgstr ""
-
-msgid "Subject"
-msgstr ""
-
-msgid "Body"
-msgstr ""
-
-msgid "raw data"
-msgstr ""
-
-msgid "Raw email message bytes"
-msgstr ""
-
-msgid "error message"
-msgstr ""
-
-msgid "Error message if processing failed"
-msgstr ""
-
-msgid "inbound message"
-msgstr ""
-
-msgid "inbound messages"
-msgstr ""
-
-msgid "sha256 hash"
-msgstr ""
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr ""
-
-msgid "file size"
-msgstr ""
-
-msgid "Size of the blob in bytes"
-msgstr ""
-
-msgid "compressed size"
-msgstr ""
-
-msgid "Size of the compressed blob in bytes"
-msgstr ""
-
-msgid "content type"
-msgstr ""
-
-msgid "MIME type of the blob"
-msgstr ""
-
-msgid "compression"
-msgstr ""
-
-msgid "raw content"
-msgstr ""
-
-msgid "Compressed binary content of the blob"
-msgstr ""
-
-msgid "Mailbox that owns this blob"
-msgstr ""
-
-msgid "Mail domain that owns this blob"
-msgstr ""
-
-msgid "blob"
-msgstr ""
-
-msgid "blobs"
-msgstr ""
-
-msgid "file name"
-msgstr ""
-
-msgid "Original filename of the attachment"
-msgstr ""
-
-msgid "Reference to the blob containing the attachment data"
-msgstr ""
-
-msgid "Mailbox that owns this attachment"
-msgstr ""
-
-msgid "Messages that use this attachment"
-msgstr ""
-
-msgid "content ID"
-msgstr ""
-
-msgid "Content-ID for inline images"
-msgstr ""
-
-msgid "attachment"
-msgstr ""
-
-msgid "attachments"
-msgstr ""
-
-msgid "mail domain access"
-msgstr ""
-
-msgid "mail domain accesses"
-msgstr ""
-
-msgid "selector"
-msgstr ""
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr ""
-
-msgid "private key"
-msgstr ""
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr ""
-
-msgid "public key"
-msgstr ""
-
-msgid "DKIM public key for DNS record generation"
-msgstr ""
-
-msgid "algorithm"
-msgstr ""
-
-msgid "DKIM signing algorithm"
-msgstr ""
-
-msgid "key size"
-msgstr ""
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr ""
-
-msgid "is active"
-msgstr ""
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr ""
-
-msgid "Domain that owns this DKIM key"
-msgstr ""
-
-msgid "DKIM key"
-msgstr ""
-
-msgid "DKIM keys"
-msgstr ""
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr ""
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr ""
-
-msgid "Type of template (message, signature)"
-msgstr ""
-
-msgid "Whether this template is available for use"
-msgstr ""
-
-msgid "Mail domain that can use this template"
-msgstr ""
-
-msgid "Mailbox that can use this template"
-msgstr ""
-
-msgid "is forced"
-msgstr ""
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr ""
-
-msgid "is default"
-msgstr ""
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr ""
-
-msgid "message template"
-msgstr ""
-
-msgid "message templates"
-msgstr ""
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr ""
-
-msgid "Import from IMAP"
-msgstr ""
-
-msgid "Home"
-msgstr ""
-
-msgid "Please correct the error below."
-msgstr ""
-
-msgid "Please correct the errors below."
-msgstr ""
-
-msgid "Start Import"
-msgstr ""
-
-msgid "English"
-msgstr ""
-
-msgid "French"
-msgstr ""
-
-msgid "Dutch"
-msgstr ""
-
diff --git a/src/backend/locale/de_DE/LC_MESSAGES/django.mo b/src/backend/locale/de_DE/LC_MESSAGES/django.mo
deleted file mode 100644
index 33a8dec9..00000000
Binary files a/src/backend/locale/de_DE/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/de_DE/LC_MESSAGES/django.po b/src/backend/locale/de_DE/LC_MESSAGES/django.po
deleted file mode 100644
index 99bb1245..00000000
--- a/src/backend/locale/de_DE/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: German\n"
-"Language: de_DE\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: de\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr ""
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr ""
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr ""
-
-msgid "Personal info"
-msgstr "Persรถnliche Daten"
-
-msgid "Permissions"
-msgstr "Berechtigungen"
-
-msgid "Important dates"
-msgstr "Wichtige Daten"
-
-msgid "Mail domain not found."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr ""
-
-msgid "Metadata"
-msgstr ""
-
-msgid "Labels"
-msgstr ""
-
-msgid "No labels"
-msgstr ""
-
-msgid "Import Messages"
-msgstr ""
-
-msgid "Import Messages from IMAP"
-msgstr ""
-
-msgid "Message not found."
-msgstr ""
-
-msgid "No pending recipients found for this message."
-msgstr ""
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr ""
-
-msgid "Keys"
-msgstr ""
-
-msgid "Error"
-msgstr ""
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr ""
-
-msgid "Name"
-msgstr ""
-
-msgid "Recipient name"
-msgstr ""
-
-msgid "messages core application"
-msgstr ""
-
-msgid "User account is disabled"
-msgstr ""
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr ""
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr ""
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr ""
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr ""
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr ""
-
-msgid "id"
-msgstr ""
-
-msgid "primary key for the record as UUID"
-msgstr ""
-
-msgid "created on"
-msgstr "Erstellt"
-
-msgid "date and time at which a record was created"
-msgstr ""
-
-msgid "updated on"
-msgstr "Aktualisiert"
-
-msgid "date and time at which a record was last updated"
-msgstr ""
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr ""
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr ""
-
-msgid "sub"
-msgstr ""
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr ""
-
-msgid "full name"
-msgstr ""
-
-msgid "identity email address"
-msgstr ""
-
-msgid "admin email address"
-msgstr ""
-
-msgid "language"
-msgstr "Sprache"
-
-msgid "The language in which the user wants to see the interface."
-msgstr ""
-
-msgid "The timezone in which the user wants to see times."
-msgstr ""
-
-msgid "staff status"
-msgstr ""
-
-msgid "Whether the user can log into this admin site."
-msgstr ""
-
-msgid "active"
-msgstr ""
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr ""
-
-msgid "Custom attributes"
-msgstr ""
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr ""
-
-msgid "user"
-msgstr "Benutzer"
-
-msgid "users"
-msgstr "Benutzer"
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr ""
-
-msgid "name"
-msgstr ""
-
-msgid "oidc autojoin"
-msgstr ""
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr ""
-
-msgid "Identity sync"
-msgstr ""
-
-msgid "Sync mailboxes to an identity provider."
-msgstr ""
-
-msgid "Custom settings"
-msgstr ""
-
-msgid "Custom settings for the mail domain."
-msgstr ""
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr ""
-
-msgid "mail domain"
-msgstr ""
-
-msgid "mail domains"
-msgstr ""
-
-msgid "Human-readable name for this channel"
-msgstr ""
-
-msgid "type"
-msgstr ""
-
-msgid "Type of channel"
-msgstr ""
-
-msgid "settings"
-msgstr ""
-
-msgid "Channel-specific configuration settings"
-msgstr ""
-
-msgid "Mailbox that receives messages from this channel"
-msgstr ""
-
-msgid "Mail domain that owns this channel"
-msgstr ""
-
-msgid "channel"
-msgstr ""
-
-msgid "channels"
-msgstr ""
-
-msgid "local part"
-msgstr ""
-
-msgid "is identity"
-msgstr ""
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr ""
-
-msgid "mailbox"
-msgstr "Briefkasten"
-
-msgid "mailboxes"
-msgstr ""
-
-msgid "role"
-msgstr ""
-
-msgid "accessed at"
-msgstr ""
-
-msgid "mailbox access"
-msgstr ""
-
-msgid "mailbox accesses"
-msgstr ""
-
-msgid "subject"
-msgstr ""
-
-msgid "snippet"
-msgstr ""
-
-msgid "has unread"
-msgstr ""
-
-msgid "has trashed"
-msgstr ""
-
-msgid "is trashed"
-msgstr ""
-
-msgid "Whether all messages in the thread are trashed"
-msgstr ""
-
-msgid "has archived"
-msgstr ""
-
-msgid "has draft"
-msgstr ""
-
-msgid "has starred"
-msgstr ""
-
-msgid "has sender"
-msgstr ""
-
-msgid "has messages"
-msgstr ""
-
-msgid "has attachments"
-msgstr ""
-
-msgid "is spam"
-msgstr ""
-
-msgid "has active"
-msgstr ""
-
-msgid "messaged at"
-msgstr ""
-
-msgid "sender names"
-msgstr ""
-
-msgid "summary"
-msgstr ""
-
-msgid "thread"
-msgstr ""
-
-msgid "threads"
-msgstr ""
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr ""
-
-msgid "slug"
-msgstr ""
-
-msgid "URL-friendly version of the name"
-msgstr ""
-
-msgid "color"
-msgstr "Farbe"
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr ""
-
-msgid "Mailbox that owns this label"
-msgstr ""
-
-msgid "Threads that have this label"
-msgstr ""
-
-msgid "description"
-msgstr "Beschreibung"
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr ""
-
-msgid "auto labeling"
-msgstr ""
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr ""
-
-msgid "label"
-msgstr ""
-
-msgid "labels"
-msgstr ""
-
-msgid "thread access"
-msgstr ""
-
-msgid "thread accesses"
-msgstr ""
-
-msgid "email"
-msgstr "E-Mail"
-
-msgid "contact"
-msgstr ""
-
-msgid "contacts"
-msgstr ""
-
-msgid "delivered at"
-msgstr ""
-
-msgid "delivery message"
-msgstr ""
-
-msgid "retry count"
-msgstr ""
-
-msgid "retry at"
-msgstr ""
-
-msgid "message recipient"
-msgstr ""
-
-msgid "message recipients"
-msgstr ""
-
-msgid "is draft"
-msgstr ""
-
-msgid "is sender"
-msgstr ""
-
-msgid "is starred"
-msgstr ""
-
-msgid "is unread"
-msgstr ""
-
-msgid "is archived"
-msgstr ""
-
-msgid "trashed at"
-msgstr ""
-
-msgid "sent at"
-msgstr ""
-
-msgid "read at"
-msgstr ""
-
-msgid "archived at"
-msgstr ""
-
-msgid "mime id"
-msgstr ""
-
-msgid "Signature template for the message"
-msgstr ""
-
-msgid "message"
-msgstr "Nachricht"
-
-msgid "messages"
-msgstr "Nachrichten"
-
-msgid "No subject"
-msgstr ""
-
-msgid "Message ID"
-msgstr ""
-
-msgid "From"
-msgstr ""
-
-msgid "To"
-msgstr ""
-
-msgid "CC"
-msgstr ""
-
-msgid "Date"
-msgstr ""
-
-msgid "Subject"
-msgstr ""
-
-msgid "Body"
-msgstr ""
-
-msgid "raw data"
-msgstr ""
-
-msgid "Raw email message bytes"
-msgstr ""
-
-msgid "error message"
-msgstr ""
-
-msgid "Error message if processing failed"
-msgstr ""
-
-msgid "inbound message"
-msgstr ""
-
-msgid "inbound messages"
-msgstr ""
-
-msgid "sha256 hash"
-msgstr ""
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr ""
-
-msgid "file size"
-msgstr ""
-
-msgid "Size of the blob in bytes"
-msgstr ""
-
-msgid "compressed size"
-msgstr ""
-
-msgid "Size of the compressed blob in bytes"
-msgstr ""
-
-msgid "content type"
-msgstr ""
-
-msgid "MIME type of the blob"
-msgstr ""
-
-msgid "compression"
-msgstr ""
-
-msgid "raw content"
-msgstr ""
-
-msgid "Compressed binary content of the blob"
-msgstr ""
-
-msgid "Mailbox that owns this blob"
-msgstr ""
-
-msgid "Mail domain that owns this blob"
-msgstr ""
-
-msgid "blob"
-msgstr ""
-
-msgid "blobs"
-msgstr ""
-
-msgid "file name"
-msgstr ""
-
-msgid "Original filename of the attachment"
-msgstr ""
-
-msgid "Reference to the blob containing the attachment data"
-msgstr ""
-
-msgid "Mailbox that owns this attachment"
-msgstr ""
-
-msgid "Messages that use this attachment"
-msgstr ""
-
-msgid "content ID"
-msgstr ""
-
-msgid "Content-ID for inline images"
-msgstr ""
-
-msgid "attachment"
-msgstr "Anhang"
-
-msgid "attachments"
-msgstr ""
-
-msgid "mail domain access"
-msgstr ""
-
-msgid "mail domain accesses"
-msgstr ""
-
-msgid "selector"
-msgstr ""
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr ""
-
-msgid "private key"
-msgstr ""
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr ""
-
-msgid "public key"
-msgstr "รffentlicher Schlรผssel"
-
-msgid "DKIM public key for DNS record generation"
-msgstr ""
-
-msgid "algorithm"
-msgstr ""
-
-msgid "DKIM signing algorithm"
-msgstr ""
-
-msgid "key size"
-msgstr ""
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr ""
-
-msgid "is active"
-msgstr ""
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr ""
-
-msgid "Domain that owns this DKIM key"
-msgstr ""
-
-msgid "DKIM key"
-msgstr ""
-
-msgid "DKIM keys"
-msgstr ""
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr ""
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr ""
-
-msgid "Type of template (message, signature)"
-msgstr ""
-
-msgid "Whether this template is available for use"
-msgstr ""
-
-msgid "Mail domain that can use this template"
-msgstr ""
-
-msgid "Mailbox that can use this template"
-msgstr ""
-
-msgid "is forced"
-msgstr ""
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr ""
-
-msgid "is default"
-msgstr ""
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr ""
-
-msgid "message template"
-msgstr ""
-
-msgid "message templates"
-msgstr ""
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr ""
-
-msgid "Import from IMAP"
-msgstr ""
-
-msgid "Home"
-msgstr "Start"
-
-msgid "Please correct the error below."
-msgstr ""
-
-msgid "Please correct the errors below."
-msgstr ""
-
-msgid "Start Import"
-msgstr ""
-
-msgid "English"
-msgstr ""
-
-msgid "French"
-msgstr "Franzรถsisch"
-
-msgid "Dutch"
-msgstr "Niederlรคndisch"
-
diff --git a/src/backend/locale/en_US/LC_MESSAGES/django.mo b/src/backend/locale/en_US/LC_MESSAGES/django.mo
deleted file mode 100644
index 45bc38fc..00000000
Binary files a/src/backend/locale/en_US/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/en_US/LC_MESSAGES/django.po b/src/backend/locale/en_US/LC_MESSAGES/django.po
deleted file mode 100644
index e3de3de1..00000000
--- a/src/backend/locale/en_US/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,736 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-docs\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-02-11 17:50+0000\n"
-"PO-Revision-Date: 2025-01-27 09:27\n"
-"Last-Translator: \n"
-"Language-Team: English\n"
-"Language: en_US\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Crowdin-Project: lasuite-docs\n"
-"X-Crowdin-Project-ID: 754523\n"
-"X-Crowdin-Language: en\n"
-"X-Crowdin-File: backend-drive.pot\n"
-"X-Crowdin-File-ID: 18\n"
-
-msgid "delivery status"
-msgstr ""
-
-#, python-format
-msgid ""
-"%(message_count)d messages - Retry send message task queued (id: "
-"%(task_id)s)."
-msgstr ""
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr ""
-
-msgid "Personal info"
-msgstr ""
-
-msgid "Permissions"
-msgstr ""
-
-msgid "Important dates"
-msgstr ""
-
-msgid "Mail domain not found."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr ""
-
-msgid "Metadata"
-msgstr ""
-
-msgid "Labels"
-msgstr ""
-
-msgid "No labels"
-msgstr ""
-
-msgid "Import Messages"
-msgstr ""
-
-msgid "Import Messages from IMAP"
-msgstr ""
-
-msgid "Message not found."
-msgstr ""
-
-msgid "No pending recipients found for this message."
-msgstr ""
-
-#, python-format
-msgid ""
-"Retry task has been queued for %(retryable_recipients_count)d pending "
-"recipient(s) (id: %(task_id)s)."
-msgstr ""
-
-msgid "Keys"
-msgstr ""
-
-msgid "Error"
-msgstr ""
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr ""
-
-#, python-format
-msgid "Image \"%(name)s\" (%(size)s MB) exceeds the %(max)s MB limit."
-msgstr ""
-
-msgid "Name"
-msgstr ""
-
-msgid "Recipient name"
-msgstr ""
-
-msgid "messages core application"
-msgstr ""
-
-msgid "User account is disabled"
-msgstr ""
-
-#, python-format
-msgid ""
-"Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. "
-"Please reduce message content."
-msgstr ""
-
-#, python-format
-msgid ""
-"Cannot add attachment(s) (%(new_size)s MB). Total attachments would be "
-"%(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: "
-"%(current_size)s MB."
-msgstr ""
-
-#, python-format
-msgid ""
-"Too many recipients: %(count)s (maximum is %(max)s). Please reduce the "
-"number of recipients before sending."
-msgstr ""
-
-#, python-format
-msgid ""
-"Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. "
-"Please remove or reduce attachments."
-msgstr ""
-
-#, python-format
-msgid ""
-"The composed email (%(mime_size)s MB) exceeds the maximum allowed size of "
-"%(max_size)s MB. Please reduce message content or attachments."
-msgstr ""
-
-msgid "id"
-msgstr ""
-
-msgid "primary key for the record as UUID"
-msgstr ""
-
-msgid "created on"
-msgstr ""
-
-msgid "date and time at which a record was created"
-msgstr ""
-
-msgid "updated on"
-msgstr ""
-
-msgid "date and time at which a record was last updated"
-msgstr ""
-
-msgid ""
-"We couldn't find a user with this sub but the email is already associated "
-"with a registered user."
-msgstr ""
-
-msgid ""
-"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
-"_/: characters."
-msgstr ""
-
-msgid "sub"
-msgstr ""
-
-msgid ""
-"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: "
-"characters only."
-msgstr ""
-
-msgid "full name"
-msgstr ""
-
-msgid "identity email address"
-msgstr ""
-
-msgid "admin email address"
-msgstr ""
-
-msgid "language"
-msgstr ""
-
-msgid "The language in which the user wants to see the interface."
-msgstr ""
-
-msgid "The timezone in which the user wants to see times."
-msgstr ""
-
-msgid "staff status"
-msgstr ""
-
-msgid "Whether the user can log into this admin site."
-msgstr ""
-
-msgid "active"
-msgstr ""
-
-msgid ""
-"Whether this user should be treated as active. Unselect this instead of "
-"deleting accounts."
-msgstr ""
-
-msgid "Custom attributes"
-msgstr ""
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr ""
-
-msgid "user"
-msgstr ""
-
-msgid "users"
-msgstr ""
-
-msgid ""
-"Enter a valid domain name. This value may contain only lowercase letters, "
-"numbers, dots and - characters."
-msgstr ""
-
-msgid "name"
-msgstr ""
-
-msgid "oidc autojoin"
-msgstr ""
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr ""
-
-msgid "Identity sync"
-msgstr ""
-
-msgid "Sync mailboxes to an identity provider."
-msgstr ""
-
-msgid "Custom settings"
-msgstr ""
-
-msgid "Custom settings for the mail domain."
-msgstr ""
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr ""
-
-msgid "mail domain"
-msgstr ""
-
-msgid "mail domains"
-msgstr ""
-
-msgid "Human-readable name for this channel"
-msgstr ""
-
-msgid "type"
-msgstr ""
-
-msgid "Type of channel"
-msgstr ""
-
-msgid "settings"
-msgstr ""
-
-msgid "Channel-specific configuration settings"
-msgstr ""
-
-msgid "Mailbox that receives messages from this channel"
-msgstr ""
-
-msgid "Mail domain that owns this channel"
-msgstr ""
-
-msgid "channel"
-msgstr ""
-
-msgid "channels"
-msgstr ""
-
-msgid "local part"
-msgstr ""
-
-msgid "is identity"
-msgstr ""
-
-msgid ""
-"Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr ""
-
-msgid "mailbox"
-msgstr ""
-
-msgid "mailboxes"
-msgstr ""
-
-msgid "role"
-msgstr ""
-
-msgid "accessed at"
-msgstr ""
-
-msgid "mailbox access"
-msgstr ""
-
-msgid "mailbox accesses"
-msgstr ""
-
-msgid "subject"
-msgstr ""
-
-msgid "snippet"
-msgstr ""
-
-msgid "has unread"
-msgstr ""
-
-msgid "has trashed"
-msgstr ""
-
-msgid "is trashed"
-msgstr ""
-
-msgid "Whether all messages in the thread are trashed"
-msgstr ""
-
-msgid "has archived"
-msgstr ""
-
-msgid "has draft"
-msgstr ""
-
-msgid "has starred"
-msgstr ""
-
-msgid "has sender"
-msgstr ""
-
-msgid "has messages"
-msgstr ""
-
-msgid "has attachments"
-msgstr ""
-
-msgid "is spam"
-msgstr ""
-
-msgid "has active"
-msgstr ""
-
-msgid "has delivery pending"
-msgstr ""
-
-msgid ""
-"True if thread has messages awaiting successful delivery (sending, retrying, "
-"or failed)."
-msgstr ""
-
-msgid "has delivery failed"
-msgstr ""
-
-msgid "True if thread has messages with permanent delivery failure."
-msgstr ""
-
-msgid "messaged at"
-msgstr ""
-
-msgid "sender names"
-msgstr ""
-
-msgid "summary"
-msgstr ""
-
-msgid "thread"
-msgstr ""
-
-msgid "threads"
-msgstr ""
-
-msgid ""
-"Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/"
-"Projects')"
-msgstr ""
-
-msgid "slug"
-msgstr ""
-
-msgid "URL-friendly version of the name"
-msgstr ""
-
-msgid "color"
-msgstr ""
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr ""
-
-msgid "Mailbox that owns this label"
-msgstr ""
-
-msgid "Threads that have this label"
-msgstr ""
-
-msgid "description"
-msgstr ""
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr ""
-
-msgid "auto labeling"
-msgstr ""
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr ""
-
-msgid "label"
-msgstr ""
-
-msgid "labels"
-msgstr ""
-
-msgid "thread access"
-msgstr ""
-
-msgid "thread accesses"
-msgstr ""
-
-msgid "email"
-msgstr ""
-
-msgid "contact"
-msgstr ""
-
-msgid "contacts"
-msgstr ""
-
-msgid "delivered at"
-msgstr ""
-
-msgid "delivery message"
-msgstr ""
-
-msgid "retry count"
-msgstr ""
-
-msgid "retry at"
-msgstr ""
-
-msgid "message recipient"
-msgstr ""
-
-msgid "message recipients"
-msgstr ""
-
-msgid "is draft"
-msgstr ""
-
-msgid "is sender"
-msgstr ""
-
-msgid "is starred"
-msgstr ""
-
-msgid "is unread"
-msgstr ""
-
-msgid "is archived"
-msgstr ""
-
-msgid "trashed at"
-msgstr ""
-
-msgid "sent at"
-msgstr ""
-
-msgid "read at"
-msgstr ""
-
-msgid "archived at"
-msgstr ""
-
-msgid "mime id"
-msgstr ""
-
-msgid "Signature template for the message"
-msgstr ""
-
-msgid "message"
-msgstr ""
-
-msgid "messages"
-msgstr ""
-
-msgid "No subject"
-msgstr ""
-
-msgid "Message ID"
-msgstr ""
-
-msgid "From"
-msgstr ""
-
-msgid "To"
-msgstr ""
-
-msgid "CC"
-msgstr ""
-
-msgid "Date"
-msgstr ""
-
-msgid "Subject"
-msgstr ""
-
-msgid "Body"
-msgstr ""
-
-msgid "raw data"
-msgstr ""
-
-msgid "Raw email message bytes"
-msgstr ""
-
-msgid "error message"
-msgstr ""
-
-msgid "Error message if processing failed"
-msgstr ""
-
-msgid "inbound message"
-msgstr ""
-
-msgid "inbound messages"
-msgstr ""
-
-msgid "sha256 hash"
-msgstr ""
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr ""
-
-msgid "file size"
-msgstr ""
-
-msgid "Size of the blob in bytes"
-msgstr ""
-
-msgid "compressed size"
-msgstr ""
-
-msgid "Size of the compressed blob in bytes"
-msgstr ""
-
-msgid "content type"
-msgstr ""
-
-msgid "MIME type of the blob"
-msgstr ""
-
-msgid "compression"
-msgstr ""
-
-msgid "raw content"
-msgstr ""
-
-msgid "Compressed binary content of the blob"
-msgstr ""
-
-msgid "Mailbox that owns this blob"
-msgstr ""
-
-msgid "Mail domain that owns this blob"
-msgstr ""
-
-msgid "blob"
-msgstr ""
-
-msgid "blobs"
-msgstr ""
-
-msgid "file name"
-msgstr ""
-
-msgid "Original filename of the attachment"
-msgstr ""
-
-msgid "Reference to the blob containing the attachment data"
-msgstr ""
-
-msgid "Mailbox that owns this attachment"
-msgstr ""
-
-msgid "Messages that use this attachment"
-msgstr ""
-
-msgid "content ID"
-msgstr ""
-
-msgid "Content-ID for inline images"
-msgstr ""
-
-msgid "attachment"
-msgstr ""
-
-msgid "attachments"
-msgstr ""
-
-msgid "mail domain access"
-msgstr ""
-
-msgid "mail domain accesses"
-msgstr ""
-
-msgid "selector"
-msgstr ""
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr ""
-
-msgid "private key"
-msgstr ""
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr ""
-
-msgid "public key"
-msgstr ""
-
-msgid "DKIM public key for DNS record generation"
-msgstr ""
-
-msgid "algorithm"
-msgstr ""
-
-msgid "DKIM signing algorithm"
-msgstr ""
-
-msgid "key size"
-msgstr ""
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr ""
-
-msgid "is active"
-msgstr ""
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr ""
-
-msgid "Domain that owns this DKIM key"
-msgstr ""
-
-msgid "DKIM key"
-msgstr ""
-
-msgid "DKIM keys"
-msgstr ""
-
-msgid ""
-"Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work "
-"Signature')"
-msgstr ""
-
-msgid ""
-"Reference to the blob containing template content as JSON: {html: str, text: "
-"str, raw: any}"
-msgstr ""
-
-msgid "Type of template (message, signature)"
-msgstr ""
-
-msgid "Whether this template is available for use"
-msgstr ""
-
-msgid "Mail domain that can use this template"
-msgstr ""
-
-msgid "Mailbox that can use this template"
-msgstr ""
-
-msgid "is forced"
-msgstr ""
-
-msgid ""
-"Whether this template is forced; no other template of the same type can be "
-"used in the same scope"
-msgstr ""
-
-msgid "is default"
-msgstr ""
-
-msgid ""
-"Whether this template is the default; it will be automatically loaded when "
-"composing a new message"
-msgstr ""
-
-msgid "message template"
-msgstr ""
-
-msgid "message templates"
-msgstr ""
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr ""
-
-msgid "Import from IMAP"
-msgstr ""
-
-msgid "Home"
-msgstr ""
-
-msgid "Please correct the error below."
-msgstr ""
-
-msgid "Please correct the errors below."
-msgstr ""
-
-msgid "Start Import"
-msgstr ""
-
-msgid "English"
-msgstr ""
-
-msgid "French"
-msgstr ""
-
-msgid "Dutch"
-msgstr ""
-
-#~ msgid "Full name"
-#~ msgstr "Full name"
diff --git a/src/backend/locale/es_ES/LC_MESSAGES/django.mo b/src/backend/locale/es_ES/LC_MESSAGES/django.mo
deleted file mode 100644
index a6804cb8..00000000
Binary files a/src/backend/locale/es_ES/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/es_ES/LC_MESSAGES/django.po b/src/backend/locale/es_ES/LC_MESSAGES/django.po
deleted file mode 100644
index 9effa25b..00000000
--- a/src/backend/locale/es_ES/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: Spanish\n"
-"Language: es_ES\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: es-ES\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr ""
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr ""
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr ""
-
-msgid "Personal info"
-msgstr ""
-
-msgid "Permissions"
-msgstr ""
-
-msgid "Important dates"
-msgstr ""
-
-msgid "Mail domain not found."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr ""
-
-msgid "Metadata"
-msgstr ""
-
-msgid "Labels"
-msgstr ""
-
-msgid "No labels"
-msgstr ""
-
-msgid "Import Messages"
-msgstr ""
-
-msgid "Import Messages from IMAP"
-msgstr ""
-
-msgid "Message not found."
-msgstr ""
-
-msgid "No pending recipients found for this message."
-msgstr ""
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr ""
-
-msgid "Keys"
-msgstr ""
-
-msgid "Error"
-msgstr ""
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr ""
-
-msgid "Name"
-msgstr ""
-
-msgid "Recipient name"
-msgstr ""
-
-msgid "messages core application"
-msgstr ""
-
-msgid "User account is disabled"
-msgstr ""
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr ""
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr ""
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr ""
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr ""
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr ""
-
-msgid "id"
-msgstr ""
-
-msgid "primary key for the record as UUID"
-msgstr ""
-
-msgid "created on"
-msgstr ""
-
-msgid "date and time at which a record was created"
-msgstr ""
-
-msgid "updated on"
-msgstr ""
-
-msgid "date and time at which a record was last updated"
-msgstr ""
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr ""
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr ""
-
-msgid "sub"
-msgstr ""
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr ""
-
-msgid "full name"
-msgstr ""
-
-msgid "identity email address"
-msgstr ""
-
-msgid "admin email address"
-msgstr ""
-
-msgid "language"
-msgstr ""
-
-msgid "The language in which the user wants to see the interface."
-msgstr ""
-
-msgid "The timezone in which the user wants to see times."
-msgstr ""
-
-msgid "staff status"
-msgstr ""
-
-msgid "Whether the user can log into this admin site."
-msgstr ""
-
-msgid "active"
-msgstr ""
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr ""
-
-msgid "Custom attributes"
-msgstr ""
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr ""
-
-msgid "user"
-msgstr ""
-
-msgid "users"
-msgstr ""
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr ""
-
-msgid "name"
-msgstr ""
-
-msgid "oidc autojoin"
-msgstr ""
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr ""
-
-msgid "Identity sync"
-msgstr ""
-
-msgid "Sync mailboxes to an identity provider."
-msgstr ""
-
-msgid "Custom settings"
-msgstr ""
-
-msgid "Custom settings for the mail domain."
-msgstr ""
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr ""
-
-msgid "mail domain"
-msgstr ""
-
-msgid "mail domains"
-msgstr ""
-
-msgid "Human-readable name for this channel"
-msgstr ""
-
-msgid "type"
-msgstr ""
-
-msgid "Type of channel"
-msgstr ""
-
-msgid "settings"
-msgstr ""
-
-msgid "Channel-specific configuration settings"
-msgstr ""
-
-msgid "Mailbox that receives messages from this channel"
-msgstr ""
-
-msgid "Mail domain that owns this channel"
-msgstr ""
-
-msgid "channel"
-msgstr ""
-
-msgid "channels"
-msgstr ""
-
-msgid "local part"
-msgstr ""
-
-msgid "is identity"
-msgstr ""
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr ""
-
-msgid "mailbox"
-msgstr ""
-
-msgid "mailboxes"
-msgstr ""
-
-msgid "role"
-msgstr ""
-
-msgid "accessed at"
-msgstr ""
-
-msgid "mailbox access"
-msgstr ""
-
-msgid "mailbox accesses"
-msgstr ""
-
-msgid "subject"
-msgstr ""
-
-msgid "snippet"
-msgstr ""
-
-msgid "has unread"
-msgstr ""
-
-msgid "has trashed"
-msgstr ""
-
-msgid "is trashed"
-msgstr ""
-
-msgid "Whether all messages in the thread are trashed"
-msgstr ""
-
-msgid "has archived"
-msgstr ""
-
-msgid "has draft"
-msgstr ""
-
-msgid "has starred"
-msgstr ""
-
-msgid "has sender"
-msgstr ""
-
-msgid "has messages"
-msgstr ""
-
-msgid "has attachments"
-msgstr ""
-
-msgid "is spam"
-msgstr ""
-
-msgid "has active"
-msgstr ""
-
-msgid "messaged at"
-msgstr ""
-
-msgid "sender names"
-msgstr ""
-
-msgid "summary"
-msgstr ""
-
-msgid "thread"
-msgstr ""
-
-msgid "threads"
-msgstr ""
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr ""
-
-msgid "slug"
-msgstr ""
-
-msgid "URL-friendly version of the name"
-msgstr ""
-
-msgid "color"
-msgstr ""
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr ""
-
-msgid "Mailbox that owns this label"
-msgstr ""
-
-msgid "Threads that have this label"
-msgstr ""
-
-msgid "description"
-msgstr ""
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr ""
-
-msgid "auto labeling"
-msgstr ""
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr ""
-
-msgid "label"
-msgstr ""
-
-msgid "labels"
-msgstr ""
-
-msgid "thread access"
-msgstr ""
-
-msgid "thread accesses"
-msgstr ""
-
-msgid "email"
-msgstr ""
-
-msgid "contact"
-msgstr ""
-
-msgid "contacts"
-msgstr ""
-
-msgid "delivered at"
-msgstr ""
-
-msgid "delivery message"
-msgstr ""
-
-msgid "retry count"
-msgstr ""
-
-msgid "retry at"
-msgstr ""
-
-msgid "message recipient"
-msgstr ""
-
-msgid "message recipients"
-msgstr ""
-
-msgid "is draft"
-msgstr ""
-
-msgid "is sender"
-msgstr ""
-
-msgid "is starred"
-msgstr ""
-
-msgid "is unread"
-msgstr ""
-
-msgid "is archived"
-msgstr ""
-
-msgid "trashed at"
-msgstr ""
-
-msgid "sent at"
-msgstr ""
-
-msgid "read at"
-msgstr ""
-
-msgid "archived at"
-msgstr ""
-
-msgid "mime id"
-msgstr ""
-
-msgid "Signature template for the message"
-msgstr ""
-
-msgid "message"
-msgstr ""
-
-msgid "messages"
-msgstr ""
-
-msgid "No subject"
-msgstr ""
-
-msgid "Message ID"
-msgstr ""
-
-msgid "From"
-msgstr ""
-
-msgid "To"
-msgstr ""
-
-msgid "CC"
-msgstr ""
-
-msgid "Date"
-msgstr ""
-
-msgid "Subject"
-msgstr ""
-
-msgid "Body"
-msgstr ""
-
-msgid "raw data"
-msgstr ""
-
-msgid "Raw email message bytes"
-msgstr ""
-
-msgid "error message"
-msgstr ""
-
-msgid "Error message if processing failed"
-msgstr ""
-
-msgid "inbound message"
-msgstr ""
-
-msgid "inbound messages"
-msgstr ""
-
-msgid "sha256 hash"
-msgstr ""
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr ""
-
-msgid "file size"
-msgstr ""
-
-msgid "Size of the blob in bytes"
-msgstr ""
-
-msgid "compressed size"
-msgstr ""
-
-msgid "Size of the compressed blob in bytes"
-msgstr ""
-
-msgid "content type"
-msgstr ""
-
-msgid "MIME type of the blob"
-msgstr ""
-
-msgid "compression"
-msgstr ""
-
-msgid "raw content"
-msgstr ""
-
-msgid "Compressed binary content of the blob"
-msgstr ""
-
-msgid "Mailbox that owns this blob"
-msgstr ""
-
-msgid "Mail domain that owns this blob"
-msgstr ""
-
-msgid "blob"
-msgstr ""
-
-msgid "blobs"
-msgstr ""
-
-msgid "file name"
-msgstr ""
-
-msgid "Original filename of the attachment"
-msgstr ""
-
-msgid "Reference to the blob containing the attachment data"
-msgstr ""
-
-msgid "Mailbox that owns this attachment"
-msgstr ""
-
-msgid "Messages that use this attachment"
-msgstr ""
-
-msgid "content ID"
-msgstr ""
-
-msgid "Content-ID for inline images"
-msgstr ""
-
-msgid "attachment"
-msgstr ""
-
-msgid "attachments"
-msgstr ""
-
-msgid "mail domain access"
-msgstr ""
-
-msgid "mail domain accesses"
-msgstr ""
-
-msgid "selector"
-msgstr ""
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr ""
-
-msgid "private key"
-msgstr ""
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr ""
-
-msgid "public key"
-msgstr ""
-
-msgid "DKIM public key for DNS record generation"
-msgstr ""
-
-msgid "algorithm"
-msgstr ""
-
-msgid "DKIM signing algorithm"
-msgstr ""
-
-msgid "key size"
-msgstr ""
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr ""
-
-msgid "is active"
-msgstr ""
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr ""
-
-msgid "Domain that owns this DKIM key"
-msgstr ""
-
-msgid "DKIM key"
-msgstr ""
-
-msgid "DKIM keys"
-msgstr ""
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr ""
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr ""
-
-msgid "Type of template (message, signature)"
-msgstr ""
-
-msgid "Whether this template is available for use"
-msgstr ""
-
-msgid "Mail domain that can use this template"
-msgstr ""
-
-msgid "Mailbox that can use this template"
-msgstr ""
-
-msgid "is forced"
-msgstr ""
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr ""
-
-msgid "is default"
-msgstr ""
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr ""
-
-msgid "message template"
-msgstr ""
-
-msgid "message templates"
-msgstr ""
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr ""
-
-msgid "Import from IMAP"
-msgstr ""
-
-msgid "Home"
-msgstr ""
-
-msgid "Please correct the error below."
-msgstr ""
-
-msgid "Please correct the errors below."
-msgstr ""
-
-msgid "Start Import"
-msgstr ""
-
-msgid "English"
-msgstr ""
-
-msgid "French"
-msgstr ""
-
-msgid "Dutch"
-msgstr ""
-
diff --git a/src/backend/locale/fr_FR/LC_MESSAGES/django.mo b/src/backend/locale/fr_FR/LC_MESSAGES/django.mo
deleted file mode 100644
index 66160e2c..00000000
Binary files a/src/backend/locale/fr_FR/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/fr_FR/LC_MESSAGES/django.po b/src/backend/locale/fr_FR/LC_MESSAGES/django.po
deleted file mode 100644
index bbb43fac..00000000
--- a/src/backend/locale/fr_FR/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,776 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-02-11 17:50+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: French\n"
-"Language: fr_FR\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: fr\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr "statut de livraison"
-
-#, python-format
-msgid ""
-"%(message_count)d messages - Retry send message task queued (id: "
-"%(task_id)s)."
-msgstr ""
-"%(message_count)d messages - Rรฉexpรฉdition mise en file d'attente (id: "
-"%(task_id)s)."
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr "Rรฉexpรฉdier les messages sรฉlectionnรฉs aux destinataires en attente"
-
-msgid "Personal info"
-msgstr "Informations personnelles"
-
-msgid "Permissions"
-msgstr "Permissions"
-
-msgid "Important dates"
-msgstr "Dates importantes"
-
-msgid "Mail domain not found."
-msgstr "Domaine de messagerie introuvable."
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr "Statistiques"
-
-msgid "Metadata"
-msgstr "Mรฉtadonnรฉes"
-
-msgid "Labels"
-msgstr "Libellรฉs"
-
-msgid "No labels"
-msgstr "Aucun libellรฉ"
-
-msgid "Import Messages"
-msgstr "Importer des messages"
-
-msgid "Import Messages from IMAP"
-msgstr "Importer des messages via IMAP"
-
-msgid "Message not found."
-msgstr "Aucun message trouvรฉ."
-
-msgid "No pending recipients found for this message."
-msgstr "Aucun destinataire en attente d'envoie trouvรฉ pour ce message."
-
-#, python-format
-msgid ""
-"Retry task has been queued for %(retryable_recipients_count)d pending "
-"recipient(s) (id: %(task_id)s)."
-msgstr ""
-"Rรฉexpรฉdition mise en file d'attente pour %(retryable_recipients_count)d "
-"destinataire(s) en attente (id: %(task_id)s)."
-
-msgid "Keys"
-msgstr "Clรฉs"
-
-msgid "Error"
-msgstr "Erreur"
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr "Une boรฎte avec ce prรฉfixe existe dรฉjร dans ce domaine."
-
-#, python-format
-msgid "Image \"%(name)s\" (%(size)s MB) exceeds the %(max)s MB limit."
-msgstr ""
-"L'image ยซ %(name)s ยป (%(size)s Mo) dรฉpasse la limite de %(max)s Mo."
-
-msgid "Name"
-msgstr "Nom"
-
-msgid "Recipient name"
-msgstr "Nom du destinataire"
-
-msgid "messages core application"
-msgstr "Messages : Application \"Core\""
-
-msgid "User account is disabled"
-msgstr "Le compte de l'utilisateur est dรฉsactivรฉ"
-
-#, python-format
-msgid ""
-"Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. "
-"Please reduce message content."
-msgstr ""
-"La taille du corps du message (%(body_size)s Mo) dรฉpasse la limite "
-"%(max_size)s Mo. Veuillez rรฉduire le contenu du message."
-
-#, python-format
-msgid ""
-"Cannot add attachment(s) (%(new_size)s MB). Total attachments would be "
-"%(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: "
-"%(current_size)s MB."
-msgstr ""
-"Impossible d'ajouter des piรจces jointes (%(new_size)s Mo). Le total des "
-"piรจces jointes serait %(total_size)s Mo, dรฉpassant la limite %(max_size)s "
-"Mo. Piรจces jointes actuelles : %(current_size)s Mo."
-
-#, python-format
-msgid ""
-"Too many recipients: %(count)s (maximum is %(max)s). Please reduce the "
-"number of recipients before sending."
-msgstr ""
-"Trop de destinataires : %(count)s (le maximum est %(max)s). Veuillez rรฉduire "
-"le nombre de destinataires avant l'envoi."
-
-#, python-format
-msgid ""
-"Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. "
-"Please remove or reduce attachments."
-msgstr ""
-"La taille totale des piรจces jointes (%(total_size)s Mo) dรฉpasse la limite "
-"%(max_size)s Mo. Veuillez supprimer ou rรฉduire les piรจces jointes."
-
-#, python-format
-msgid ""
-"The composed email (%(mime_size)s MB) exceeds the maximum allowed size of "
-"%(max_size)s MB. Please reduce message content or attachments."
-msgstr ""
-"L'e-mail composรฉ (%(mime_size)s Mo) dรฉpasse la taille maximale autorisรฉe de "
-"%(max_size)s Mo. Veuillez rรฉduire le contenu du message ou les piรจces "
-"jointes."
-
-msgid "id"
-msgstr "id"
-
-msgid "primary key for the record as UUID"
-msgstr "clรฉ primaire de la ressource en tant que UUID"
-
-msgid "created on"
-msgstr "crรฉรฉ le"
-
-msgid "date and time at which a record was created"
-msgstr "date et heure de crรฉation de la ressource"
-
-msgid "updated on"
-msgstr "modifiรฉ le"
-
-msgid "date and time at which a record was last updated"
-msgstr "date et heure de la derniรจre mise ร jour de la ressource"
-
-msgid ""
-"We couldn't find a user with this sub but the email is already associated "
-"with a registered user."
-msgstr ""
-"Nous n'avons pas pu trouver un utilisateur avec ce sub mais l'e-mail est "
-"dรฉjร associรฉ ร un utilisateur enregistrรฉ."
-
-msgid ""
-"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/"
-"_/: characters."
-msgstr ""
-"Saisissez un sub valide. Cette valeur ne peut contenir que des lettres, des "
-"chiffres et les caractรจres @/./+/-/_/: uniquement."
-
-msgid "sub"
-msgstr "sub"
-
-msgid ""
-"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: "
-"characters only."
-msgstr ""
-"Obligatoire. 255 caractรจres ou moins. Lettres, chiffres et caractรจres @/./"
-"+/-/_/: uniquement."
-
-msgid "full name"
-msgstr "nom complet"
-
-msgid "identity email address"
-msgstr "adresse e-mail d'identitรฉ"
-
-msgid "admin email address"
-msgstr "adresse e-mail d'administrateur"
-
-msgid "language"
-msgstr "langue"
-
-msgid "The language in which the user wants to see the interface."
-msgstr "La langue dans laquelle l'utilisateur veut voir l'interface."
-
-msgid "The timezone in which the user wants to see times."
-msgstr "Le fuseau horaire dans lequel l'utilisateur souhaite voir les heures."
-
-msgid "staff status"
-msgstr "statut d'รฉquipe"
-
-msgid "Whether the user can log into this admin site."
-msgstr "Si l'utilisateur peut se connecter ร ce site d'administration."
-
-msgid "active"
-msgstr "actif"
-
-msgid ""
-"Whether this user should be treated as active. Unselect this instead of "
-"deleting accounts."
-msgstr ""
-"Si cet utilisateur doit รชtre traitรฉ comme actif. Dรฉsรฉlectionnez ceci au lieu "
-"de supprimer des comptes."
-
-msgid "Custom attributes"
-msgstr "Attributs personnalisรฉs"
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr ""
-"Mรฉtadonnรฉes de l'utilisateur ร synchroniser avec le fournisseur d'identitรฉ."
-
-msgid "user"
-msgstr "utilisateur"
-
-msgid "users"
-msgstr "utilisateurs"
-
-msgid ""
-"Enter a valid domain name. This value may contain only lowercase letters, "
-"numbers, dots and - characters."
-msgstr ""
-"Entrez un nom de domaine valide. Cette valeur ne peut contenir que des "
-"minuscules, des chiffres, des points et des caractรจres -."
-
-msgid "name"
-msgstr "nom"
-
-msgid "oidc autojoin"
-msgstr "auto-jonction OIDC"
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr ""
-"Crรฉez automatiquement les boรฎtes aux lettres ร partir des courriels OIDC."
-
-msgid "Identity sync"
-msgstr "Synchronisation de l'identitรฉ"
-
-msgid "Sync mailboxes to an identity provider."
-msgstr "Synchroniser les boรฎtes aux lettres avec un fournisseur d'identitรฉ."
-
-msgid "Custom settings"
-msgstr "Paramรจtres personnalisรฉs"
-
-msgid "Custom settings for the mail domain."
-msgstr "Paramรจtres personnalisรฉs pour le domaine de messagerie."
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr ""
-"Mรฉtadonnรฉes ร synchroniser avec le groupe de domaine de messagerie du "
-"fournisseur d'identitรฉ."
-
-msgid "mail domain"
-msgstr "domaine de messagerie"
-
-msgid "mail domains"
-msgstr "domaines de messagerie"
-
-msgid "Human-readable name for this channel"
-msgstr "Nom intelligible pour ce canal"
-
-msgid "type"
-msgstr "type"
-
-msgid "Type of channel"
-msgstr "Type de canal"
-
-msgid "settings"
-msgstr "paramรจtres"
-
-msgid "Channel-specific configuration settings"
-msgstr "Configuration spรฉcifique aux canaux"
-
-msgid "Mailbox that receives messages from this channel"
-msgstr "Boรฎte aux lettres qui reรงoit les messages provenant de ce canal"
-
-msgid "Mail domain that owns this channel"
-msgstr "Domaine de messagerie qui possรจde ce canal"
-
-msgid "channel"
-msgstr "canal"
-
-msgid "channels"
-msgstr "canaux"
-
-msgid "local part"
-msgstr "partie locale"
-
-msgid "is identity"
-msgstr "est une identitรฉ"
-
-msgid ""
-"Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr ""
-"Si cette boรฎte aux lettres identifie une personne (c'est-ร -dire n'est pas un "
-"alias ou un groupe)"
-
-msgid "mailbox"
-msgstr "boรฎte aux lettres"
-
-msgid "mailboxes"
-msgstr "boรฎtes aux lettres"
-
-msgid "role"
-msgstr "rรดle"
-
-msgid "accessed at"
-msgstr "accรฉdรฉ le"
-
-msgid "mailbox access"
-msgstr "accรจs de la boรฎte aux lettres"
-
-msgid "mailbox accesses"
-msgstr "accรจs de la boรฎte aux lettres"
-
-msgid "subject"
-msgstr "objet"
-
-msgid "snippet"
-msgstr "extrait"
-
-msgid "has unread"
-msgstr "a des non lus"
-
-msgid "has trashed"
-msgstr "a des mis ร la corbeille"
-
-msgid "is trashed"
-msgstr "est mis ร la corbeille"
-
-msgid "Whether all messages in the thread are trashed"
-msgstr "Si tous les messages de la conversation sont supprimรฉs"
-
-msgid "has archived"
-msgstr "a des archives"
-
-msgid "has draft"
-msgstr "a un brouillon"
-
-msgid "has starred"
-msgstr "a des favoris"
-
-msgid "has sender"
-msgstr "a envoyรฉ"
-
-msgid "has messages"
-msgstr "a des messages"
-
-msgid "has attachments"
-msgstr "a des piรจces jointes"
-
-msgid "is spam"
-msgstr "est un spam"
-
-msgid "has active"
-msgstr "a des actifs"
-
-msgid "has delivery pending"
-msgstr "a des messages en cours d'envoi"
-
-msgid ""
-"True if thread has messages awaiting successful delivery (sending, retrying, "
-"or failed)."
-msgstr "Vrai si la conversation a des messages en attente de livraison (envoi, rรฉexpรฉdition, รฉchec)."
-
-msgid "has delivery failed"
-msgstr "a des messages en รฉchec de livraison"
-
-msgid "True if thread has messages with permanent delivery failure."
-msgstr "Vrai si la conversation a des messages avec un รฉchec de livraison permanent."
-
-msgid "messaged at"
-msgstr "dernier message ร "
-
-msgid "sender names"
-msgstr "noms des expรฉditeurs"
-
-msgid "summary"
-msgstr "rรฉsumรฉ"
-
-msgid "thread"
-msgstr "conversation"
-
-msgid "threads"
-msgstr "conversations"
-
-msgid ""
-"Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/"
-"Projects')"
-msgstr ""
-"Nom du libellรฉ/du dossier (vous pouvez utiliser des barres obliques pour la "
-"hiรฉrarchie, par exemple ยซ Travail/Projets ยป)"
-
-msgid "slug"
-msgstr "slug"
-
-msgid "URL-friendly version of the name"
-msgstr "Version du nom optimisรฉe pour les URL"
-
-msgid "color"
-msgstr "couleur"
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr "Couleur du libellรฉ au format hexadรฉcimal (par exemple #FF0000)"
-
-msgid "Mailbox that owns this label"
-msgstr "Boรฎte propriรฉtaire du libellรฉ"
-
-msgid "Threads that have this label"
-msgstr "Conversations qui ont ce libellรฉ"
-
-msgid "description"
-msgstr "description"
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr "Description du libellรฉ, utilisรฉe par l'IA pour comprendre son but"
-
-msgid "auto labeling"
-msgstr "labellisation automatique"
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr "Si ce libellรฉ doit รชtre automatiquement appliquรฉe par l'IA"
-
-msgid "label"
-msgstr "libellรฉ"
-
-msgid "labels"
-msgstr "libellรฉs"
-
-msgid "thread access"
-msgstr "accรจs de conversation"
-
-msgid "thread accesses"
-msgstr "accรจs des conversations"
-
-msgid "email"
-msgstr "courriel"
-
-msgid "contact"
-msgstr "contact"
-
-msgid "contacts"
-msgstr "contacts"
-
-msgid "delivered at"
-msgstr "dรฉlivrรฉ ร "
-
-msgid "delivery message"
-msgstr "message de livraison"
-
-msgid "retry count"
-msgstr "nombre de tentatives"
-
-msgid "retry at"
-msgstr "rรฉessayer ร "
-
-msgid "message recipient"
-msgstr "destinataire du message"
-
-msgid "message recipients"
-msgstr "destinataires du message"
-
-msgid "is draft"
-msgstr "est un brouillon"
-
-msgid "is sender"
-msgstr "est expรฉditeur"
-
-msgid "is starred"
-msgstr "est favori"
-
-msgid "is unread"
-msgstr "est non lu"
-
-msgid "is archived"
-msgstr "est archivรฉ"
-
-msgid "trashed at"
-msgstr "mis ร la corbeille le"
-
-msgid "sent at"
-msgstr "envoyรฉ le"
-
-msgid "read at"
-msgstr "lu ร "
-
-msgid "archived at"
-msgstr "archivรฉ ร "
-
-msgid "mime id"
-msgstr "id mime"
-
-msgid "Signature template for the message"
-msgstr "Modรจle de signature pour le message"
-
-msgid "message"
-msgstr "message"
-
-msgid "messages"
-msgstr "messages"
-
-msgid "No subject"
-msgstr "Aucun objet"
-
-msgid "Message ID"
-msgstr "ID du message"
-
-msgid "From"
-msgstr "Deย "
-
-msgid "To"
-msgstr "ร"
-
-msgid "CC"
-msgstr "CC"
-
-msgid "Date"
-msgstr "Date"
-
-msgid "Subject"
-msgstr "Objet"
-
-msgid "Body"
-msgstr "Corps"
-
-msgid "raw data"
-msgstr "donnรฉes brutes"
-
-msgid "Raw email message bytes"
-msgstr "Octets des messages bruts"
-
-msgid "error message"
-msgstr "message d'erreur"
-
-msgid "Error message if processing failed"
-msgstr "Message d'erreur si le traitement a รฉchouรฉ"
-
-msgid "inbound message"
-msgstr "message entrant"
-
-msgid "inbound messages"
-msgstr "messages entrants"
-
-msgid "sha256 hash"
-msgstr "hash sha256"
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr "Hash SHA-256 du contenu du blob non compressรฉ"
-
-msgid "file size"
-msgstr "taille du fichier"
-
-msgid "Size of the blob in bytes"
-msgstr "Taille du blob en octets"
-
-msgid "compressed size"
-msgstr "taille compressรฉe"
-
-msgid "Size of the compressed blob in bytes"
-msgstr "Taille du blob compressรฉ en octets"
-
-msgid "content type"
-msgstr "type de contenu"
-
-msgid "MIME type of the blob"
-msgstr "Type MIME du blob"
-
-msgid "compression"
-msgstr "compression"
-
-msgid "raw content"
-msgstr "contenu brut"
-
-msgid "Compressed binary content of the blob"
-msgstr "Contenu binaire compressรฉ du blob"
-
-msgid "Mailbox that owns this blob"
-msgstr "Boรฎte aux lettres propriรฉtaire de ce blob"
-
-msgid "Mail domain that owns this blob"
-msgstr "Domaine de courrier qui possรจde ce blob"
-
-msgid "blob"
-msgstr "blob"
-
-msgid "blobs"
-msgstr "blobs"
-
-msgid "file name"
-msgstr "nom du fichier"
-
-msgid "Original filename of the attachment"
-msgstr "Nom du fichier original de la piรจce jointe"
-
-msgid "Reference to the blob containing the attachment data"
-msgstr "Rรฉfรฉrence vers le blob contenant les donnรฉes de la piรจce jointe"
-
-msgid "Mailbox that owns this attachment"
-msgstr "Boรฎte aux lettres propriรฉtaire de cette piรจce jointe"
-
-msgid "Messages that use this attachment"
-msgstr "Messages qui utilisent cette piรจce jointe"
-
-msgid "content ID"
-msgstr "content ID"
-
-msgid "Content-ID for inline images"
-msgstr "ID du contenu pour les images en ligne"
-
-msgid "attachment"
-msgstr "piรจce jointe"
-
-msgid "attachments"
-msgstr "piรจces jointes"
-
-msgid "mail domain access"
-msgstr "accรจs au domaine de messagerie"
-
-msgid "mail domain accesses"
-msgstr "accรจs au domaine de messagerie"
-
-msgid "selector"
-msgstr "sรฉlecteur"
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr "Sรฉlecteur DKIM (i.e., 'default', 'mail')"
-
-msgid "private key"
-msgstr "clรฉ privรฉe"
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr "Clรฉ privรฉe DKIM au format PEM (chiffrรฉe)"
-
-msgid "public key"
-msgstr "clรฉ publique"
-
-msgid "DKIM public key for DNS record generation"
-msgstr "Clรฉ publique de DKIM pour la gรฉnรฉration d'enregistrements DNS"
-
-msgid "algorithm"
-msgstr "algorithme"
-
-msgid "DKIM signing algorithm"
-msgstr "Algorithme de signature DKIM"
-
-msgid "key size"
-msgstr "taille de la clรฉ"
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr "Taille de la clรฉ en octets (par exemple, 2048, 4096 pour RSA)"
-
-msgid "is active"
-msgstr "est active"
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr "Si cette clรฉ DKIM est active et doit รชtre utilisรฉe pour signer"
-
-msgid "Domain that owns this DKIM key"
-msgstr "Domaine propriรฉtaire de cette clรฉ DKIM"
-
-msgid "DKIM key"
-msgstr "Clรฉ DKIM"
-
-msgid "DKIM keys"
-msgstr "Clรฉs DKIM"
-
-msgid ""
-"Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work "
-"Signature')"
-msgstr ""
-"Nom du modรจle (ex., 'Rรฉponse standard', 'Absence de bureau', 'Signature "
-"professionnelle')"
-
-msgid ""
-"Reference to the blob containing template content as JSON: {html: str, text: "
-"str, raw: any}"
-msgstr ""
-"Rรฉfรฉrence vers le blob contenant le contenu du modรจle au format JSON : "
-"{html: str, text: str, raw: any}"
-
-msgid "Type of template (message, signature)"
-msgstr "Type de modรจle (message, signature)"
-
-msgid "Whether this template is available for use"
-msgstr "Si ce modรจle est utilisable"
-
-msgid "Mail domain that can use this template"
-msgstr "Domaine de messagerie qui peut utiliser ce modรจle"
-
-msgid "Mailbox that can use this template"
-msgstr "Boรฎte aux lettres qui peut utiliser ce modรจle"
-
-msgid "is forced"
-msgstr "est forcรฉ"
-
-msgid ""
-"Whether this template is forced; no other template of the same type can be "
-"used in the same scope"
-msgstr ""
-"Si ce modรจle est forcรฉ ; aucun autre modรจle du mรชme type ne peut รชtre "
-"utilisรฉ dans le mรชme pรฉrimรจtre"
-
-msgid "is default"
-msgstr "est par dรฉfaut"
-
-msgid ""
-"Whether this template is the default; it will be automatically loaded when "
-"composing a new message"
-msgstr ""
-"Si ce modรจle est celui par dรฉfaut ; il sera automatiquement chargรฉ lors de "
-"la composition d'un nouveau message"
-
-msgid "message template"
-msgstr "modรจle de message"
-
-msgid "message templates"
-msgstr "modรจles de message"
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr "Rรฉessayer d'envoyer aux destinataires en attente"
-
-msgid "Import from IMAP"
-msgstr "Importer via IMAP"
-
-msgid "Home"
-msgstr "Accueil"
-
-msgid "Please correct the error below."
-msgstr "Veuillez corriger l'erreur ci-dessous."
-
-msgid "Please correct the errors below."
-msgstr "Veuillez corriger les erreurs ci-dessous."
-
-msgid "Start Import"
-msgstr "Dรฉmarrer l'importation"
-
-msgid "English"
-msgstr "Anglais"
-
-msgid "French"
-msgstr "Franรงais"
-
-msgid "Dutch"
-msgstr "Nรฉerlandais"
diff --git a/src/backend/locale/it_IT/LC_MESSAGES/django.mo b/src/backend/locale/it_IT/LC_MESSAGES/django.mo
deleted file mode 100644
index 998dfeda..00000000
Binary files a/src/backend/locale/it_IT/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/it_IT/LC_MESSAGES/django.po b/src/backend/locale/it_IT/LC_MESSAGES/django.po
deleted file mode 100644
index 7ccdacc8..00000000
--- a/src/backend/locale/it_IT/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: Italian\n"
-"Language: it_IT\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: it\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr ""
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr ""
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr ""
-
-msgid "Personal info"
-msgstr ""
-
-msgid "Permissions"
-msgstr ""
-
-msgid "Important dates"
-msgstr ""
-
-msgid "Mail domain not found."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr ""
-
-msgid "Metadata"
-msgstr ""
-
-msgid "Labels"
-msgstr ""
-
-msgid "No labels"
-msgstr ""
-
-msgid "Import Messages"
-msgstr ""
-
-msgid "Import Messages from IMAP"
-msgstr ""
-
-msgid "Message not found."
-msgstr ""
-
-msgid "No pending recipients found for this message."
-msgstr ""
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr ""
-
-msgid "Keys"
-msgstr ""
-
-msgid "Error"
-msgstr ""
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr ""
-
-msgid "Name"
-msgstr ""
-
-msgid "Recipient name"
-msgstr ""
-
-msgid "messages core application"
-msgstr ""
-
-msgid "User account is disabled"
-msgstr ""
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr ""
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr ""
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr ""
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr ""
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr ""
-
-msgid "id"
-msgstr ""
-
-msgid "primary key for the record as UUID"
-msgstr ""
-
-msgid "created on"
-msgstr ""
-
-msgid "date and time at which a record was created"
-msgstr ""
-
-msgid "updated on"
-msgstr ""
-
-msgid "date and time at which a record was last updated"
-msgstr ""
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr ""
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr ""
-
-msgid "sub"
-msgstr ""
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr ""
-
-msgid "full name"
-msgstr ""
-
-msgid "identity email address"
-msgstr ""
-
-msgid "admin email address"
-msgstr ""
-
-msgid "language"
-msgstr ""
-
-msgid "The language in which the user wants to see the interface."
-msgstr ""
-
-msgid "The timezone in which the user wants to see times."
-msgstr ""
-
-msgid "staff status"
-msgstr ""
-
-msgid "Whether the user can log into this admin site."
-msgstr ""
-
-msgid "active"
-msgstr ""
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr ""
-
-msgid "Custom attributes"
-msgstr ""
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr ""
-
-msgid "user"
-msgstr ""
-
-msgid "users"
-msgstr ""
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr ""
-
-msgid "name"
-msgstr ""
-
-msgid "oidc autojoin"
-msgstr ""
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr ""
-
-msgid "Identity sync"
-msgstr ""
-
-msgid "Sync mailboxes to an identity provider."
-msgstr ""
-
-msgid "Custom settings"
-msgstr ""
-
-msgid "Custom settings for the mail domain."
-msgstr ""
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr ""
-
-msgid "mail domain"
-msgstr ""
-
-msgid "mail domains"
-msgstr ""
-
-msgid "Human-readable name for this channel"
-msgstr ""
-
-msgid "type"
-msgstr ""
-
-msgid "Type of channel"
-msgstr ""
-
-msgid "settings"
-msgstr ""
-
-msgid "Channel-specific configuration settings"
-msgstr ""
-
-msgid "Mailbox that receives messages from this channel"
-msgstr ""
-
-msgid "Mail domain that owns this channel"
-msgstr ""
-
-msgid "channel"
-msgstr ""
-
-msgid "channels"
-msgstr ""
-
-msgid "local part"
-msgstr ""
-
-msgid "is identity"
-msgstr ""
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr ""
-
-msgid "mailbox"
-msgstr ""
-
-msgid "mailboxes"
-msgstr ""
-
-msgid "role"
-msgstr ""
-
-msgid "accessed at"
-msgstr ""
-
-msgid "mailbox access"
-msgstr ""
-
-msgid "mailbox accesses"
-msgstr ""
-
-msgid "subject"
-msgstr ""
-
-msgid "snippet"
-msgstr ""
-
-msgid "has unread"
-msgstr ""
-
-msgid "has trashed"
-msgstr ""
-
-msgid "is trashed"
-msgstr ""
-
-msgid "Whether all messages in the thread are trashed"
-msgstr ""
-
-msgid "has archived"
-msgstr ""
-
-msgid "has draft"
-msgstr ""
-
-msgid "has starred"
-msgstr ""
-
-msgid "has sender"
-msgstr ""
-
-msgid "has messages"
-msgstr ""
-
-msgid "has attachments"
-msgstr ""
-
-msgid "is spam"
-msgstr ""
-
-msgid "has active"
-msgstr ""
-
-msgid "messaged at"
-msgstr ""
-
-msgid "sender names"
-msgstr ""
-
-msgid "summary"
-msgstr ""
-
-msgid "thread"
-msgstr ""
-
-msgid "threads"
-msgstr ""
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr ""
-
-msgid "slug"
-msgstr ""
-
-msgid "URL-friendly version of the name"
-msgstr ""
-
-msgid "color"
-msgstr ""
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr ""
-
-msgid "Mailbox that owns this label"
-msgstr ""
-
-msgid "Threads that have this label"
-msgstr ""
-
-msgid "description"
-msgstr ""
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr ""
-
-msgid "auto labeling"
-msgstr ""
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr ""
-
-msgid "label"
-msgstr ""
-
-msgid "labels"
-msgstr ""
-
-msgid "thread access"
-msgstr ""
-
-msgid "thread accesses"
-msgstr ""
-
-msgid "email"
-msgstr ""
-
-msgid "contact"
-msgstr ""
-
-msgid "contacts"
-msgstr ""
-
-msgid "delivered at"
-msgstr ""
-
-msgid "delivery message"
-msgstr ""
-
-msgid "retry count"
-msgstr ""
-
-msgid "retry at"
-msgstr ""
-
-msgid "message recipient"
-msgstr ""
-
-msgid "message recipients"
-msgstr ""
-
-msgid "is draft"
-msgstr ""
-
-msgid "is sender"
-msgstr ""
-
-msgid "is starred"
-msgstr ""
-
-msgid "is unread"
-msgstr ""
-
-msgid "is archived"
-msgstr ""
-
-msgid "trashed at"
-msgstr ""
-
-msgid "sent at"
-msgstr ""
-
-msgid "read at"
-msgstr ""
-
-msgid "archived at"
-msgstr ""
-
-msgid "mime id"
-msgstr ""
-
-msgid "Signature template for the message"
-msgstr ""
-
-msgid "message"
-msgstr ""
-
-msgid "messages"
-msgstr ""
-
-msgid "No subject"
-msgstr ""
-
-msgid "Message ID"
-msgstr ""
-
-msgid "From"
-msgstr ""
-
-msgid "To"
-msgstr ""
-
-msgid "CC"
-msgstr ""
-
-msgid "Date"
-msgstr ""
-
-msgid "Subject"
-msgstr ""
-
-msgid "Body"
-msgstr ""
-
-msgid "raw data"
-msgstr ""
-
-msgid "Raw email message bytes"
-msgstr ""
-
-msgid "error message"
-msgstr ""
-
-msgid "Error message if processing failed"
-msgstr ""
-
-msgid "inbound message"
-msgstr ""
-
-msgid "inbound messages"
-msgstr ""
-
-msgid "sha256 hash"
-msgstr ""
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr ""
-
-msgid "file size"
-msgstr ""
-
-msgid "Size of the blob in bytes"
-msgstr ""
-
-msgid "compressed size"
-msgstr ""
-
-msgid "Size of the compressed blob in bytes"
-msgstr ""
-
-msgid "content type"
-msgstr ""
-
-msgid "MIME type of the blob"
-msgstr ""
-
-msgid "compression"
-msgstr ""
-
-msgid "raw content"
-msgstr ""
-
-msgid "Compressed binary content of the blob"
-msgstr ""
-
-msgid "Mailbox that owns this blob"
-msgstr ""
-
-msgid "Mail domain that owns this blob"
-msgstr ""
-
-msgid "blob"
-msgstr ""
-
-msgid "blobs"
-msgstr ""
-
-msgid "file name"
-msgstr ""
-
-msgid "Original filename of the attachment"
-msgstr ""
-
-msgid "Reference to the blob containing the attachment data"
-msgstr ""
-
-msgid "Mailbox that owns this attachment"
-msgstr ""
-
-msgid "Messages that use this attachment"
-msgstr ""
-
-msgid "content ID"
-msgstr ""
-
-msgid "Content-ID for inline images"
-msgstr ""
-
-msgid "attachment"
-msgstr ""
-
-msgid "attachments"
-msgstr ""
-
-msgid "mail domain access"
-msgstr ""
-
-msgid "mail domain accesses"
-msgstr ""
-
-msgid "selector"
-msgstr ""
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr ""
-
-msgid "private key"
-msgstr ""
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr ""
-
-msgid "public key"
-msgstr ""
-
-msgid "DKIM public key for DNS record generation"
-msgstr ""
-
-msgid "algorithm"
-msgstr ""
-
-msgid "DKIM signing algorithm"
-msgstr ""
-
-msgid "key size"
-msgstr ""
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr ""
-
-msgid "is active"
-msgstr ""
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr ""
-
-msgid "Domain that owns this DKIM key"
-msgstr ""
-
-msgid "DKIM key"
-msgstr ""
-
-msgid "DKIM keys"
-msgstr ""
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr ""
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr ""
-
-msgid "Type of template (message, signature)"
-msgstr ""
-
-msgid "Whether this template is available for use"
-msgstr ""
-
-msgid "Mail domain that can use this template"
-msgstr ""
-
-msgid "Mailbox that can use this template"
-msgstr ""
-
-msgid "is forced"
-msgstr ""
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr ""
-
-msgid "is default"
-msgstr ""
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr ""
-
-msgid "message template"
-msgstr ""
-
-msgid "message templates"
-msgstr ""
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr ""
-
-msgid "Import from IMAP"
-msgstr ""
-
-msgid "Home"
-msgstr ""
-
-msgid "Please correct the error below."
-msgstr ""
-
-msgid "Please correct the errors below."
-msgstr ""
-
-msgid "Start Import"
-msgstr ""
-
-msgid "English"
-msgstr ""
-
-msgid "French"
-msgstr ""
-
-msgid "Dutch"
-msgstr ""
-
diff --git a/src/backend/locale/nl_NL/LC_MESSAGES/django.mo b/src/backend/locale/nl_NL/LC_MESSAGES/django.mo
deleted file mode 100644
index dbb7b590..00000000
Binary files a/src/backend/locale/nl_NL/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/nl_NL/LC_MESSAGES/django.po b/src/backend/locale/nl_NL/LC_MESSAGES/django.po
deleted file mode 100644
index 3b97f598..00000000
--- a/src/backend/locale/nl_NL/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: Dutch\n"
-"Language: nl_NL\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: nl\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr "afleverstatus"
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr ""
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr ""
-
-msgid "Personal info"
-msgstr "Persoonlijke gegevens"
-
-msgid "Permissions"
-msgstr "Machtigingen"
-
-msgid "Important dates"
-msgstr "Belangrijke data"
-
-msgid "Mail domain not found."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr "Statistieken"
-
-msgid "Metadata"
-msgstr "Metadata"
-
-msgid "Labels"
-msgstr "Labels"
-
-msgid "No labels"
-msgstr "Geen labels"
-
-msgid "Import Messages"
-msgstr "Berichten importeren"
-
-msgid "Import Messages from IMAP"
-msgstr "Berichten importeren van IMAP"
-
-msgid "Message not found."
-msgstr ""
-
-msgid "No pending recipients found for this message."
-msgstr ""
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr ""
-
-msgid "Keys"
-msgstr "Keys"
-
-msgid "Error"
-msgstr ""
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr "Er bestaat al een mailbox met dit lokale deel in dit domein."
-
-msgid "Name"
-msgstr "Naam"
-
-msgid "Recipient name"
-msgstr "Naam van ontvanger"
-
-msgid "messages core application"
-msgstr "messages kern applicatie"
-
-msgid "User account is disabled"
-msgstr "Gebruikersaccount is uitgeschakeld"
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr "Berichtinhoud (%(body_size)s MB) overschrijdt de MB-limiet %(max_size)s . Verminder berichteninhoud."
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr "Kan bijlagen niet toevoegen (%(new_size)s MB). Totale bijlagen zouden %(total_size)s MB zijn, die de limiet van de %(max_size)s MB overschrijden. Huidige bijlagen: %(current_size)s MB."
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr "Te veel ontvangers: %(count)s (maximum is %(max)s). Beperk het aantal ontvangers voordat u verzendt."
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr "Totale grootte van bijlagen (%(total_size)s MB) overschrijdt de MB-limiet %(max_size)s. Verwijder of reduceer bijlagen."
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr "De e-mail (%(mime_size)s MB) overschrijdt de maximaal toegestane grootte van %(max_size)s MB. Beperk de inhoud van berichten of bijlagen."
-
-msgid "id"
-msgstr "id"
-
-msgid "primary key for the record as UUID"
-msgstr "primaire sleutel voor het record als UUID"
-
-msgid "created on"
-msgstr "gecreรซerd op"
-
-msgid "date and time at which a record was created"
-msgstr "datum en tijd waarop een record is aangemaakt"
-
-msgid "updated on"
-msgstr "bijgewerkt op"
-
-msgid "date and time at which a record was last updated"
-msgstr "datum en tijd waarop een record voor het laatst is bijgewerkt"
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr "Wij konden geen gebruiker vinden met dit id, maar de email is al geassocieerd met een geregistreerde gebruiker."
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr "Voer een geldig id in. De waarde mag alleen letters, nummers en @/./.+/-/_: karakters bevatten."
-
-msgid "sub"
-msgstr "id"
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr "Verplicht. 255 karakters of minder. Alleen letters, nummers en @/./+/-/_/: karakters zijn toegestaan."
-
-msgid "full name"
-msgstr "volledige naam"
-
-msgid "identity email address"
-msgstr "identiteit emailadres"
-
-msgid "admin email address"
-msgstr "beheerders e-mailadres"
-
-msgid "language"
-msgstr "taal"
-
-msgid "The language in which the user wants to see the interface."
-msgstr "De taal waarin de gebruiker de interface wil zien."
-
-msgid "The timezone in which the user wants to see times."
-msgstr "De tijdzone waarin de gebruiker de tijden wil zien."
-
-msgid "staff status"
-msgstr "beheerder status"
-
-msgid "Whether the user can log into this admin site."
-msgstr "Of de gebruiker kan inloggen in het beheer gedeelte."
-
-msgid "active"
-msgstr "actief"
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr "Of een gebruiker als actief moet worden beschouwd. Deselecteer dit in plaats van het account te deleten."
-
-msgid "Custom attributes"
-msgstr "Aanpasbare attributen"
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr "Metagegevens om te synchroniseren met de gebruiker in de identiteitsprovider."
-
-msgid "user"
-msgstr "gebruiker"
-
-msgid "users"
-msgstr "gebruikers"
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr "Voer een geldige domeinnaam in. Deze waarde mag alleen kleine letters, cijfers, punten en - tekens bevatten."
-
-msgid "name"
-msgstr "naam"
-
-msgid "oidc autojoin"
-msgstr "oidc automatisch deelnemen"
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr "Automatisch mailboxen aanmaken op basis van OIDC e-mails."
-
-msgid "Identity sync"
-msgstr "Identiteit synchronisatie"
-
-msgid "Sync mailboxes to an identity provider."
-msgstr "Synchroniseer mailboxen met een identity provider."
-
-msgid "Custom settings"
-msgstr "Aangepaste instellingen"
-
-msgid "Custom settings for the mail domain."
-msgstr "Aangepaste instellingen voor het e-maildomein."
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr "Metagegevens om te synchroniseren met de gebruiker in de identiteitsprovider."
-
-msgid "mail domain"
-msgstr "e-mail domein"
-
-msgid "mail domains"
-msgstr "e-mail domeinen"
-
-msgid "Human-readable name for this channel"
-msgstr "Leesbare naam voor dit kanaal"
-
-msgid "type"
-msgstr "type"
-
-msgid "Type of channel"
-msgstr "Type kanaal"
-
-msgid "settings"
-msgstr "instellingen"
-
-msgid "Channel-specific configuration settings"
-msgstr "Kanaalspecifieke configuratie-instellingen"
-
-msgid "Mailbox that receives messages from this channel"
-msgstr "Mailbox die berichten van dit kanaal ontvangt"
-
-msgid "Mail domain that owns this channel"
-msgstr "Mail domein die eigenaar is van dit kanaal"
-
-msgid "channel"
-msgstr "kanaal"
-
-msgid "channels"
-msgstr "kanalen"
-
-msgid "local part"
-msgstr "lokaal deel"
-
-msgid "is identity"
-msgstr "is identiteit"
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr "Of dit mailbox een persoon identificeert (bijv. is geen alias of groep)"
-
-msgid "mailbox"
-msgstr "mailbox"
-
-msgid "mailboxes"
-msgstr "mailboxen"
-
-msgid "role"
-msgstr "rol"
-
-msgid "accessed at"
-msgstr "geopend op"
-
-msgid "mailbox access"
-msgstr "mailbox toegang"
-
-msgid "mailbox accesses"
-msgstr "mailbox toegang"
-
-msgid "subject"
-msgstr "onderwerp"
-
-msgid "snippet"
-msgstr "snippet"
-
-msgid "has unread"
-msgstr "bevat ongelezen"
-
-msgid "has trashed"
-msgstr "bevat verwijderd"
-
-msgid "is trashed"
-msgstr "is verwijderd"
-
-msgid "Whether all messages in the thread are trashed"
-msgstr "Of alle berichten in de thread naar de prullenbak zijn verplaatst"
-
-msgid "has archived"
-msgstr "bevat gearchiveerd"
-
-msgid "has draft"
-msgstr "bevat concept"
-
-msgid "has starred"
-msgstr "bevat ster"
-
-msgid "has sender"
-msgstr "bevat afzender"
-
-msgid "has messages"
-msgstr "bevat berichten"
-
-msgid "has attachments"
-msgstr "bevat bijlage"
-
-msgid "is spam"
-msgstr "is spam"
-
-msgid "has active"
-msgstr "heeft actieve"
-
-msgid "messaged at"
-msgstr "bericht op"
-
-msgid "sender names"
-msgstr "naam afzender"
-
-msgid "summary"
-msgstr "samenvatting"
-
-msgid "thread"
-msgstr "kanaal"
-
-msgid "threads"
-msgstr "kanalen"
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr "Naam van de label/map (kan slashes voor de hiรซrarchie gebruiken, bijvoorbeeld 'Werk/Projecten')"
-
-msgid "slug"
-msgstr "slug"
-
-msgid "URL-friendly version of the name"
-msgstr "URL-vriendelijke versie van de naam"
-
-msgid "color"
-msgstr "kleur"
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr "Kleur van het label in hex formaat (bijv. #FF0000)"
-
-msgid "Mailbox that owns this label"
-msgstr "Mailbox die eigenaar is van deze blob"
-
-msgid "Threads that have this label"
-msgstr "Kanalen met dit label"
-
-msgid "description"
-msgstr "beschrijving"
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr "Beschrijving van het label, gebruikt door AI om het doel ervan te begrijpen"
-
-msgid "auto labeling"
-msgstr "automatisch labelen"
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr "Of dit label automatisch moet worden toegepast door AI"
-
-msgid "label"
-msgstr "label"
-
-msgid "labels"
-msgstr "labels"
-
-msgid "thread access"
-msgstr "kanaal toegang"
-
-msgid "thread accesses"
-msgstr "kanaal toegang"
-
-msgid "email"
-msgstr "e-mail"
-
-msgid "contact"
-msgstr "contact"
-
-msgid "contacts"
-msgstr "contacten"
-
-msgid "delivered at"
-msgstr "afgeleverd op"
-
-msgid "delivery message"
-msgstr "verzend bericht"
-
-msgid "retry count"
-msgstr "aantal pogingen"
-
-msgid "retry at"
-msgstr "probeer op"
-
-msgid "message recipient"
-msgstr "ontvanger"
-
-msgid "message recipients"
-msgstr "ontvangers"
-
-msgid "is draft"
-msgstr "is concept"
-
-msgid "is sender"
-msgstr "is afzender"
-
-msgid "is starred"
-msgstr "met ster"
-
-msgid "is unread"
-msgstr "is ongelezen"
-
-msgid "is archived"
-msgstr "is gearchiveerd"
-
-msgid "trashed at"
-msgstr "verwijderd op"
-
-msgid "sent at"
-msgstr "verzonden op"
-
-msgid "read at"
-msgstr "gelezen op"
-
-msgid "archived at"
-msgstr "gearchiveerd op"
-
-msgid "mime id"
-msgstr "mime id"
-
-msgid "Signature template for the message"
-msgstr "Handtekening template voor het bericht"
-
-msgid "message"
-msgstr "bericht"
-
-msgid "messages"
-msgstr "berichten"
-
-msgid "No subject"
-msgstr "Geen onderwerp"
-
-msgid "Message ID"
-msgstr "Bericht ID"
-
-msgid "From"
-msgstr "Van"
-
-msgid "To"
-msgstr "Naar"
-
-msgid "CC"
-msgstr "CC"
-
-msgid "Date"
-msgstr "Datum"
-
-msgid "Subject"
-msgstr "Onderwerp"
-
-msgid "Body"
-msgstr "Bericht"
-
-msgid "raw data"
-msgstr "ruwe gegevens"
-
-msgid "Raw email message bytes"
-msgstr "Ruwe e-mail bericht bytes"
-
-msgid "error message"
-msgstr "Foutmelding"
-
-msgid "Error message if processing failed"
-msgstr "Foutmelding bij verwerking mislukt"
-
-msgid "inbound message"
-msgstr "inkomende bericht"
-
-msgid "inbound messages"
-msgstr "inkomende berichten"
-
-msgid "sha256 hash"
-msgstr "sha256 hash"
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr "SHA-256 hash van de ongecomprimeerde blob inhoud"
-
-msgid "file size"
-msgstr "bestandsgrootte"
-
-msgid "Size of the blob in bytes"
-msgstr "Grootte van de blob in bytes"
-
-msgid "compressed size"
-msgstr "gecomprimeerde grootte"
-
-msgid "Size of the compressed blob in bytes"
-msgstr "Grootte van de gecomprimeerde blob in bytes"
-
-msgid "content type"
-msgstr "inhoudstype"
-
-msgid "MIME type of the blob"
-msgstr "MIME type van de blob"
-
-msgid "compression"
-msgstr "compressie"
-
-msgid "raw content"
-msgstr "ruwe inhoud"
-
-msgid "Compressed binary content of the blob"
-msgstr "Gecomprimeerde binaire inhoud van de blob"
-
-msgid "Mailbox that owns this blob"
-msgstr "Mailbox die eigenaar is van deze blob"
-
-msgid "Mail domain that owns this blob"
-msgstr "Mail domein die eigenaar is van deze blob"
-
-msgid "blob"
-msgstr "blob"
-
-msgid "blobs"
-msgstr "blobs"
-
-msgid "file name"
-msgstr "bestandsnaam"
-
-msgid "Original filename of the attachment"
-msgstr "Oorspronkelijke bestandsnaam van de bijlage"
-
-msgid "Reference to the blob containing the attachment data"
-msgstr "Verwijzing naar de blob die de bijlagegegevens bevat"
-
-msgid "Mailbox that owns this attachment"
-msgstr "Mailbox die eigenaar is van deze bijlage"
-
-msgid "Messages that use this attachment"
-msgstr "Berichten die deze bijlage gebruiken"
-
-msgid "content ID"
-msgstr ""
-
-msgid "Content-ID for inline images"
-msgstr ""
-
-msgid "attachment"
-msgstr "bijlage"
-
-msgid "attachments"
-msgstr "bijlagen"
-
-msgid "mail domain access"
-msgstr "mail domein toegang"
-
-msgid "mail domain accesses"
-msgstr "mail domein toegang"
-
-msgid "selector"
-msgstr "selectiemenu"
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr "DKIM-selector (bijv. 'standaard', 'mail')"
-
-msgid "private key"
-msgstr "privรฉsleutel"
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr "DKIM private key in PEM-formaat (gecodeerd)"
-
-msgid "public key"
-msgstr "publieke sleutel"
-
-msgid "DKIM public key for DNS record generation"
-msgstr "Openbare DKIM sleutel voor DNS record generatie"
-
-msgid "algorithm"
-msgstr "algoritme"
-
-msgid "DKIM signing algorithm"
-msgstr "DKIM ondertekeningsalgoritme"
-
-msgid "key size"
-msgstr "sleutel grootte"
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr "Sleutelgrootte in bits (bijv. 2048, 4096 voor RSA)"
-
-msgid "is active"
-msgstr "is actief"
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr "Of deze DKIM-sleutel actief is en moet worden gebruikt voor het ondertekenen"
-
-msgid "Domain that owns this DKIM key"
-msgstr "Domein dat eigenaar is van deze DKIM-sleutel"
-
-msgid "DKIM key"
-msgstr "DKIM sleutel"
-
-msgid "DKIM keys"
-msgstr "DKIM sleutels"
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr "Naam van de template (bijv. 'Standaard antwoord', 'Niet op kantoor', 'Ondertekening')"
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr "Referentie naar de blob met sjablooninhoud als JSON: {html: str, text: str, raw: any}"
-
-msgid "Type of template (message, signature)"
-msgstr "Type template (bericht, handtekening)"
-
-msgid "Whether this template is available for use"
-msgstr "Of deze template beschikbaar is voor gebruik"
-
-msgid "Mail domain that can use this template"
-msgstr "E-mail domein die deze template kan gebruiken"
-
-msgid "Mailbox that can use this template"
-msgstr "Mailbox die dit sjabloon kan gebruiken"
-
-msgid "is forced"
-msgstr "is afgedwongen"
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr "Of deze template wordt geforceerd; geen andere sjabloon van hetzelfde type kan worden gebruikt in dezelfde scope"
-
-msgid "is default"
-msgstr "is standaard"
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr "Of deze sjabloon standaard is; het zal automatisch worden geladen bij het opstellen van een nieuw bericht"
-
-msgid "message template"
-msgstr "bericht template"
-
-msgid "message templates"
-msgstr "bericht sjablonen"
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr ""
-
-msgid "Import from IMAP"
-msgstr "Importeren van IMAP"
-
-msgid "Home"
-msgstr "Home"
-
-msgid "Please correct the error below."
-msgstr "Herstel onderstaande foutmelding."
-
-msgid "Please correct the errors below."
-msgstr "Herstel onderstaande foutmeldingen."
-
-msgid "Start Import"
-msgstr "Start import"
-
-msgid "English"
-msgstr "Engels"
-
-msgid "French"
-msgstr "Frans"
-
-msgid "Dutch"
-msgstr "Nederlands"
-
diff --git a/src/backend/locale/pt_PT/LC_MESSAGES/django.mo b/src/backend/locale/pt_PT/LC_MESSAGES/django.mo
deleted file mode 100644
index 700981ed..00000000
Binary files a/src/backend/locale/pt_PT/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/pt_PT/LC_MESSAGES/django.po b/src/backend/locale/pt_PT/LC_MESSAGES/django.po
deleted file mode 100644
index d6553134..00000000
--- a/src/backend/locale/pt_PT/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: Portuguese\n"
-"Language: pt_PT\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: pt-PT\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr ""
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr ""
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr ""
-
-msgid "Personal info"
-msgstr ""
-
-msgid "Permissions"
-msgstr ""
-
-msgid "Important dates"
-msgstr ""
-
-msgid "Mail domain not found."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr ""
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr ""
-
-msgid "Statistics"
-msgstr ""
-
-msgid "Metadata"
-msgstr ""
-
-msgid "Labels"
-msgstr ""
-
-msgid "No labels"
-msgstr ""
-
-msgid "Import Messages"
-msgstr ""
-
-msgid "Import Messages from IMAP"
-msgstr ""
-
-msgid "Message not found."
-msgstr ""
-
-msgid "No pending recipients found for this message."
-msgstr ""
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr ""
-
-msgid "Keys"
-msgstr ""
-
-msgid "Error"
-msgstr ""
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr ""
-
-msgid "Name"
-msgstr ""
-
-msgid "Recipient name"
-msgstr ""
-
-msgid "messages core application"
-msgstr ""
-
-msgid "User account is disabled"
-msgstr ""
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr ""
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr ""
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr ""
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr ""
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr ""
-
-msgid "id"
-msgstr ""
-
-msgid "primary key for the record as UUID"
-msgstr ""
-
-msgid "created on"
-msgstr ""
-
-msgid "date and time at which a record was created"
-msgstr ""
-
-msgid "updated on"
-msgstr ""
-
-msgid "date and time at which a record was last updated"
-msgstr ""
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr ""
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr ""
-
-msgid "sub"
-msgstr ""
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr ""
-
-msgid "full name"
-msgstr ""
-
-msgid "identity email address"
-msgstr ""
-
-msgid "admin email address"
-msgstr ""
-
-msgid "language"
-msgstr ""
-
-msgid "The language in which the user wants to see the interface."
-msgstr ""
-
-msgid "The timezone in which the user wants to see times."
-msgstr ""
-
-msgid "staff status"
-msgstr ""
-
-msgid "Whether the user can log into this admin site."
-msgstr ""
-
-msgid "active"
-msgstr ""
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr ""
-
-msgid "Custom attributes"
-msgstr ""
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr ""
-
-msgid "user"
-msgstr ""
-
-msgid "users"
-msgstr ""
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr ""
-
-msgid "name"
-msgstr ""
-
-msgid "oidc autojoin"
-msgstr ""
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr ""
-
-msgid "Identity sync"
-msgstr ""
-
-msgid "Sync mailboxes to an identity provider."
-msgstr ""
-
-msgid "Custom settings"
-msgstr ""
-
-msgid "Custom settings for the mail domain."
-msgstr ""
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr ""
-
-msgid "mail domain"
-msgstr ""
-
-msgid "mail domains"
-msgstr ""
-
-msgid "Human-readable name for this channel"
-msgstr ""
-
-msgid "type"
-msgstr ""
-
-msgid "Type of channel"
-msgstr ""
-
-msgid "settings"
-msgstr ""
-
-msgid "Channel-specific configuration settings"
-msgstr ""
-
-msgid "Mailbox that receives messages from this channel"
-msgstr ""
-
-msgid "Mail domain that owns this channel"
-msgstr ""
-
-msgid "channel"
-msgstr ""
-
-msgid "channels"
-msgstr ""
-
-msgid "local part"
-msgstr ""
-
-msgid "is identity"
-msgstr ""
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr ""
-
-msgid "mailbox"
-msgstr ""
-
-msgid "mailboxes"
-msgstr ""
-
-msgid "role"
-msgstr ""
-
-msgid "accessed at"
-msgstr ""
-
-msgid "mailbox access"
-msgstr ""
-
-msgid "mailbox accesses"
-msgstr ""
-
-msgid "subject"
-msgstr ""
-
-msgid "snippet"
-msgstr ""
-
-msgid "has unread"
-msgstr ""
-
-msgid "has trashed"
-msgstr ""
-
-msgid "is trashed"
-msgstr ""
-
-msgid "Whether all messages in the thread are trashed"
-msgstr ""
-
-msgid "has archived"
-msgstr ""
-
-msgid "has draft"
-msgstr ""
-
-msgid "has starred"
-msgstr ""
-
-msgid "has sender"
-msgstr ""
-
-msgid "has messages"
-msgstr ""
-
-msgid "has attachments"
-msgstr ""
-
-msgid "is spam"
-msgstr ""
-
-msgid "has active"
-msgstr ""
-
-msgid "messaged at"
-msgstr ""
-
-msgid "sender names"
-msgstr ""
-
-msgid "summary"
-msgstr ""
-
-msgid "thread"
-msgstr ""
-
-msgid "threads"
-msgstr ""
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr ""
-
-msgid "slug"
-msgstr ""
-
-msgid "URL-friendly version of the name"
-msgstr ""
-
-msgid "color"
-msgstr ""
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr ""
-
-msgid "Mailbox that owns this label"
-msgstr ""
-
-msgid "Threads that have this label"
-msgstr ""
-
-msgid "description"
-msgstr ""
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr ""
-
-msgid "auto labeling"
-msgstr ""
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr ""
-
-msgid "label"
-msgstr ""
-
-msgid "labels"
-msgstr ""
-
-msgid "thread access"
-msgstr ""
-
-msgid "thread accesses"
-msgstr ""
-
-msgid "email"
-msgstr ""
-
-msgid "contact"
-msgstr ""
-
-msgid "contacts"
-msgstr ""
-
-msgid "delivered at"
-msgstr ""
-
-msgid "delivery message"
-msgstr ""
-
-msgid "retry count"
-msgstr ""
-
-msgid "retry at"
-msgstr ""
-
-msgid "message recipient"
-msgstr ""
-
-msgid "message recipients"
-msgstr ""
-
-msgid "is draft"
-msgstr ""
-
-msgid "is sender"
-msgstr ""
-
-msgid "is starred"
-msgstr ""
-
-msgid "is unread"
-msgstr ""
-
-msgid "is archived"
-msgstr ""
-
-msgid "trashed at"
-msgstr ""
-
-msgid "sent at"
-msgstr ""
-
-msgid "read at"
-msgstr ""
-
-msgid "archived at"
-msgstr ""
-
-msgid "mime id"
-msgstr ""
-
-msgid "Signature template for the message"
-msgstr ""
-
-msgid "message"
-msgstr ""
-
-msgid "messages"
-msgstr ""
-
-msgid "No subject"
-msgstr ""
-
-msgid "Message ID"
-msgstr ""
-
-msgid "From"
-msgstr ""
-
-msgid "To"
-msgstr ""
-
-msgid "CC"
-msgstr ""
-
-msgid "Date"
-msgstr ""
-
-msgid "Subject"
-msgstr ""
-
-msgid "Body"
-msgstr ""
-
-msgid "raw data"
-msgstr ""
-
-msgid "Raw email message bytes"
-msgstr ""
-
-msgid "error message"
-msgstr ""
-
-msgid "Error message if processing failed"
-msgstr ""
-
-msgid "inbound message"
-msgstr ""
-
-msgid "inbound messages"
-msgstr ""
-
-msgid "sha256 hash"
-msgstr ""
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr ""
-
-msgid "file size"
-msgstr ""
-
-msgid "Size of the blob in bytes"
-msgstr ""
-
-msgid "compressed size"
-msgstr ""
-
-msgid "Size of the compressed blob in bytes"
-msgstr ""
-
-msgid "content type"
-msgstr ""
-
-msgid "MIME type of the blob"
-msgstr ""
-
-msgid "compression"
-msgstr ""
-
-msgid "raw content"
-msgstr ""
-
-msgid "Compressed binary content of the blob"
-msgstr ""
-
-msgid "Mailbox that owns this blob"
-msgstr ""
-
-msgid "Mail domain that owns this blob"
-msgstr ""
-
-msgid "blob"
-msgstr ""
-
-msgid "blobs"
-msgstr ""
-
-msgid "file name"
-msgstr ""
-
-msgid "Original filename of the attachment"
-msgstr ""
-
-msgid "Reference to the blob containing the attachment data"
-msgstr ""
-
-msgid "Mailbox that owns this attachment"
-msgstr ""
-
-msgid "Messages that use this attachment"
-msgstr ""
-
-msgid "content ID"
-msgstr ""
-
-msgid "Content-ID for inline images"
-msgstr ""
-
-msgid "attachment"
-msgstr ""
-
-msgid "attachments"
-msgstr ""
-
-msgid "mail domain access"
-msgstr ""
-
-msgid "mail domain accesses"
-msgstr ""
-
-msgid "selector"
-msgstr ""
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr ""
-
-msgid "private key"
-msgstr ""
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr ""
-
-msgid "public key"
-msgstr ""
-
-msgid "DKIM public key for DNS record generation"
-msgstr ""
-
-msgid "algorithm"
-msgstr ""
-
-msgid "DKIM signing algorithm"
-msgstr ""
-
-msgid "key size"
-msgstr ""
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr ""
-
-msgid "is active"
-msgstr ""
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr ""
-
-msgid "Domain that owns this DKIM key"
-msgstr ""
-
-msgid "DKIM key"
-msgstr ""
-
-msgid "DKIM keys"
-msgstr ""
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr ""
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr ""
-
-msgid "Type of template (message, signature)"
-msgstr ""
-
-msgid "Whether this template is available for use"
-msgstr ""
-
-msgid "Mail domain that can use this template"
-msgstr ""
-
-msgid "Mailbox that can use this template"
-msgstr ""
-
-msgid "is forced"
-msgstr ""
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr ""
-
-msgid "is default"
-msgstr ""
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr ""
-
-msgid "message template"
-msgstr ""
-
-msgid "message templates"
-msgstr ""
-
-msgid "Provision DNS records"
-msgstr ""
-
-msgid "Retry to send to pending recipients"
-msgstr ""
-
-msgid "Import from IMAP"
-msgstr ""
-
-msgid "Home"
-msgstr ""
-
-msgid "Please correct the error below."
-msgstr ""
-
-msgid "Please correct the errors below."
-msgstr ""
-
-msgid "Start Import"
-msgstr ""
-
-msgid "English"
-msgstr ""
-
-msgid "French"
-msgstr ""
-
-msgid "Dutch"
-msgstr ""
-
diff --git a/src/backend/locale/ru_RU/LC_MESSAGES/django.mo b/src/backend/locale/ru_RU/LC_MESSAGES/django.mo
deleted file mode 100644
index 29eec838..00000000
Binary files a/src/backend/locale/ru_RU/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/ru_RU/LC_MESSAGES/django.po b/src/backend/locale/ru_RU/LC_MESSAGES/django.po
deleted file mode 100644
index 4aea6d23..00000000
--- a/src/backend/locale/ru_RU/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: Russian\n"
-"Language: ru_RU\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: ru\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr "ัะพััะพัะฝะธะต ะดะพััะฐะฒะบะธ"
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr "%(message_count)d ัะพะพะฑัะตะฝะธะน - ะะพะฒัะพัะธัั ะทะฐะดะฐัั ะพัะฟัะฐะฒะบะธ ะฒ ะพัะตัะตะดะธ (id: %(task_id)s)."
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr "ะะพะฒัะพัะธัั ะพัะฟัะฐะฒะบั ะฒัะฑัะฐะฝะฝัั
ัะพะพะฑัะตะฝะธะน ะพะถะธะดะฐััะธะผ ะฟะพะปััะฐัะตะปัะผ"
-
-msgid "Personal info"
-msgstr "ะะธัะฝัะต ะดะฐะฝะฝัะต"
-
-msgid "Permissions"
-msgstr "ะ ะฐะทัะตัะตะฝะธั"
-
-msgid "Important dates"
-msgstr "ะะฐะถะฝัะต ะดะฐัั"
-
-msgid "Mail domain not found."
-msgstr "ะะพััะพะฒัะน ะดะพะผะตะฝ ะฝะต ะฝะฐะนะดะตะฝ."
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr "ะฃัะฟะตัะฝะฐั ะฝะฐัััะพะนะบะฐ DNS ัะตัะตะท %(provider)s: %(changes)s"
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr "ะฃัะฟะตัะฝะฐั ะฝะฐัััะพะนะบะฐ DNS ัะตัะตะท %(provider)s (ะธะทะผะตะฝะตะฝะธั ะฝะต ััะตะฑััััั)."
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr "ะะต ัะดะฐะปะพัั ะฝะฐัััะพะธัั DNS: %(error)s"
-
-msgid "Statistics"
-msgstr "ะกัะฐัะธััะธะบะฐ"
-
-msgid "Metadata"
-msgstr "ะะตัะฐะดะฐะฝะฝัะต"
-
-msgid "Labels"
-msgstr "ะฏัะปัะบะธ"
-
-msgid "No labels"
-msgstr "ะะตะท ััะปัะบะพะฒ"
-
-msgid "Import Messages"
-msgstr "ะะผะฟะพัั ัะพะพะฑัะตะฝะธะน"
-
-msgid "Import Messages from IMAP"
-msgstr "ะะผะฟะพัั ัะพะพะฑัะตะฝะธะน IMAP"
-
-msgid "Message not found."
-msgstr "ะกะพะพะฑัะตะฝะธะต ะฝะต ะฝะฐะนะดะตะฝะพ."
-
-msgid "No pending recipients found for this message."
-msgstr "ะะปั ััะพะณะพ ัะพะพะฑัะตะฝะธั ะฝะต ะฝะฐะนะดะตะฝะพ ะฝะธ ะพะดะฝะพะณะพ ะฟะพะปััะฐัะตะปั."
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr "ะะพะฒัะพัะฝะฐั ะทะฐะดะฐัะฐ ะฑัะปะฐ ะฟะพััะฐะฒะปะตะฝะฐ ะฒ ะพัะตัะตะดั ะดะปั %(retryable_recipients_count)d ะพะถะธะดะฐััะธั
ะฟะพะปััะฐัะตะปะตะน (id: %(task_id)s)."
-
-msgid "Keys"
-msgstr "ะะปััะธ"
-
-msgid "Error"
-msgstr "ะัะธะฑะบะฐ"
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr "ะะพััะพะฒัะน ััะธะบ ั ััะพะน ะปะพะบะฐะปัะฝะพะน ัะฐัััั ัะถะต ัััะตััะฒัะตั ะฒ ััะพะผ ะดะพะผะตะฝะต."
-
-msgid "Name"
-msgstr "ะะผั"
-
-msgid "Recipient name"
-msgstr "ะะผั ะฟะพะปััะฐัะตะปั"
-
-msgid "messages core application"
-msgstr "ะฟัะธะปะพะถะตะฝะธะต ะดะปั ัะพะพะฑัะตะฝะธะน"
-
-msgid "User account is disabled"
-msgstr "ะฃัััะฝะฐั ะทะฐะฟะธัั ะฟะพะปัะทะพะฒะฐัะตะปั ะพัะบะปััะตะฝะฐ"
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr "ะ ะฐะทะผะตั ัะตะปะฐ ัะพะพะฑัะตะฝะธั (%(body_size)s ะะ) ะฟัะตะฒััะฐะตั ะฟัะตะดะตะป ะฒ %(max_size)s ะะ. ะะพะถะฐะปัะนััะฐ, ัะผะตะฝััะธัะต ัะพะดะตัะถะธะผะพะต ัะพะพะฑัะตะฝะธั."
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr "ะะตะฒะพะทะผะพะถะฝะพ ะดะพะฑะฐะฒะธัั ะฒะปะพะถะตะฝะธะต(ั) (%(new_size)s ะะ). ะกัะผะผะฐัะฝัะน ัะฐะทะผะตั ะฒะปะพะถะตะฝะธะน ัะพััะฐะฒะธั %(total_size)s ะะ, ััะพ ะฟัะตะฒััะธั ะพะณัะฐะฝะธัะตะฝะธะต ะฒ %(max_size)s ะะ. ะ ะฐะทะผะตั ัะตะบััะธั
ะฒะปะพะถะตะฝะธะน: %(current_size)s ะะ."
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr "ะกะปะธัะบะพะผ ะผะฝะพะณะพ ะฟะพะปััะฐัะตะปะตะน: %(count)s (ะผะฐะบัะธะผัะผ %(max)s). ะฃะผะตะฝััะธัะต ะบะพะปะธัะตััะฒะพ ะฟะพะปััะฐัะตะปะตะน ะดะพ ะพัะฟัะฐะฒะบะธ."
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr "ะะฑัะธะน ัะฐะทะผะตั ะฒะปะพะถะตะฝะธะน (%(total_size)s ะะ) ะฟัะตะฒััะฐะตั ะฟัะตะดะตะป ะฒ %(max_size)s ะะ. ะะพะถะฐะปัะนััะฐ, ัะดะฐะปะธัะต ะธะปะธ ัะผะตะฝััะธัะต ะฒะปะพะถะตะฝะธั."
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr "ะ ะฐะทะผะตั ัะพะทะดะฐะฝะฝะพะณะพ ะฟะธััะผะฐ (%(mime_size)s ะะ) ะฟัะตะฒััะฐะตั ะผะฐะบัะธะผะฐะปัะฝะพ ะดะพะฟัััะธะผัะน ัะฐะทะผะตั ะฒ %(max_size)s ะะ. ะฃะผะตะฝััะธัะต ัะฐะทะผะตั ัะพะดะตัะถะธะผะพะณะพ ะธะปะธ ะฒะปะพะถะตะฝะธะน."
-
-msgid "id"
-msgstr "id"
-
-msgid "primary key for the record as UUID"
-msgstr "ะฟะตัะฒะธัะฝัะน ะบะปัั ะดะปั ะทะฐะฟะธัะธ ะบะฐะบ UUID"
-
-msgid "created on"
-msgstr "ัะพะทะดะฐะฝะพ"
-
-msgid "date and time at which a record was created"
-msgstr "ะดะฐัะฐ ะธ ะฒัะตะผั ัะพะทะดะฐะฝะธั ะทะฐะฟะธัะธ"
-
-msgid "updated on"
-msgstr "ะพะฑะฝะพะฒะปะตะฝะพ"
-
-msgid "date and time at which a record was last updated"
-msgstr "ะดะฐัะฐ ะธ ะฒัะตะผั ะฟะพัะปะตะดะฝะตะณะพ ะพะฑะฝะพะฒะปะตะฝะธั ะทะฐะฟะธัะธ"
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr "ะั ะฝะต ัะผะพะณะปะธ ะฝะฐะนัะธ ะฟะพะปัะทะพะฒะฐัะตะปั ั ััะธะผะธ ะดะฐะฝะฝัะผะธ, ะฝะพ ััะพั ะฐะดัะตั ัะถะต ัะฒัะทะฐะฝ ั ะทะฐัะตะณะธัััะธัะพะฒะฐะฝะฝัะผ ะฟะพะปัะทะพะฒะฐัะตะปะตะผ."
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr "ะะฒะตะดะธัะต ะฟัะฐะฒะธะปัะฝัะน ะฟัะตัะธะบั. ะะฝ ะผะพะถะตั ัะพะดะตัะถะฐัั ัะพะปัะบะพ ะฑัะบะฒั, ัะธััั ะธ ัะธะผะฒะพะปั @/./+/-/_/."
-
-msgid "sub"
-msgstr "ะฟัะตัะธะบั"
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr "ะะฑัะทะฐัะตะปัะฝะพ. 255 ัะธะผะฒะพะปะพะฒ ะธะปะธ ะผะตะฝััะต. ะขะพะปัะบะพ ะฑัะบะฒั, ัะธััั ะธ @/./+/-/_/: /."
-
-msgid "full name"
-msgstr "ะฟะพะปะฝะพะต ะธะผั"
-
-msgid "identity email address"
-msgstr "ะปะธัะฝัะน ะฐะดัะตั ัะปะตะบััะพะฝะฝะพะน ะฟะพััั"
-
-msgid "admin email address"
-msgstr "e-mail ะฐะดะผะธะฝะธัััะฐัะพัะฐ"
-
-msgid "language"
-msgstr "ัะทัะบ"
-
-msgid "The language in which the user wants to see the interface."
-msgstr "ะฏะทัะบ, ะฝะฐ ะบะพัะพัะพะผ ะฟะพะปัะทะพะฒะฐัะตะปั ั
ะพัะตั ะฒะธะดะตัั ะธะฝัะตััะตะนั."
-
-msgid "The timezone in which the user wants to see times."
-msgstr "ะงะฐัะพะฒะพะน ะฟะพัั, ะฒ ะบะพัะพัะพะผ ะฟะพะปัะทะพะฒะฐัะตะปั ั
ะพัะตั ะฒะธะดะตัั ะฒัะตะผั."
-
-msgid "staff status"
-msgstr "ััะฐััั ัะพัััะดะฝะธะบะฐ"
-
-msgid "Whether the user can log into this admin site."
-msgstr "ะะพะถะตั ะปะธ ะฟะพะปัะทะพะฒะฐัะตะปั ะฒะพะนัะธ ะฝะฐ ััะพั ะฐะดะผะธะฝะธัััะฐัะธะฒะฝัะน ัะฐะนั."
-
-msgid "active"
-msgstr "ะฐะบัะธะฒะฝัะน"
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr "ะะพะปะถะตะฝ ะปะธ ะฟะพะปัะทะพะฒะฐัะตะปั ัะฐััะผะฐััะธะฒะฐัััั ะบะฐะบ ะฐะบัะธะฒะฝัะน. ะะปััะตัะฝะฐัะธะฒะฐ ัะดะฐะปะตะฝะธั ััััะฝัั
ะทะฐะฟะธัะตะน."
-
-msgid "Custom attributes"
-msgstr "ะะฐัััะฐะธะฒะฐะตะผัะต ะฐััะธะฑััั"
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr "ะะตัะฐะดะฐะฝะฝัะต ะดะปั ัะธะฝั
ัะพะฝะธะทะฐัะธะธ ั ะฟะพะปัะทะพะฒะฐัะตะปะตะผ ะฒ ะฟะพััะฐะฒัะธะบะต ะธะดะตะฝัะธัะธะบะฐัะธะพะฝะฝัั
ะดะฐะฝะฝัั
."
-
-msgid "user"
-msgstr "ะฟะพะปัะทะพะฒะฐัะตะปั"
-
-msgid "users"
-msgstr "ะฟะพะปัะทะพะฒะฐัะตะปะธ"
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr "ะะฒะตะดะธัะต ะฟัะฐะฒะธะปัะฝะพะต ะธะผั ะดะพะผะตะฝะฐ. ะญัะพ ะทะฝะฐัะตะฝะธะต ะผะพะถะตั ัะพะดะตัะถะฐัั ัะพะปัะบะพ ัััะพัะฝัะต ะฑัะบะฒั, ัะธััั, ัะพัะบะธ ะธ ัะธะผะฒะพะปั ะดะตัะธัะฐ."
-
-msgid "name"
-msgstr "ะธะผั"
-
-msgid "oidc autojoin"
-msgstr "oidc autojoin"
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr "ะกะพะทะดะฐะฝะธะต ะฟะพััะพะฒัั
ััะธะบะพะฒ ะฐะฒัะพะผะฐัะธัะตัะบะธ ะฝะฐ ะพัะฝะพะฒะต ัะพะพะฑัะตะฝะธะน OIDC."
-
-msgid "Identity sync"
-msgstr "ะกะธะฝั
ัะพะฝะธะทะฐัะธั ะปะธัะฝัั
ะดะฐะฝะฝัั
"
-
-msgid "Sync mailboxes to an identity provider."
-msgstr "ะกะธะฝั
ัะพะฝะธะทะธัะพะฒะฐัั ะฟะพััะพะฒัะต ััะธะบะธ ั ะฟะพััะฐะฒัะธะบะพะผ ะธะดะตะฝัะธัะธะบะฐัะธะพะฝะฝัั
ะดะฐะฝะฝัั
."
-
-msgid "Custom settings"
-msgstr "ะะพะปัะทะพะฒะฐัะตะปััะบะธะต ะฝะฐัััะพะนะบะธ"
-
-msgid "Custom settings for the mail domain."
-msgstr "ะะพะปัะทะพะฒะฐัะตะปััะบะธะต ะฝะฐัััะพะนะบะธ ะดะปั ะฟะพััะพะฒะพะณะพ ะดะพะผะตะฝะฐ."
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr "ะะตัะฐะดะฐะฝะฝัะต ะดะปั ัะธะฝั
ัะพะฝะธะทะฐัะธะธ ั ะฟะพะปัะทะพะฒะฐัะตะปะตะผ ะฒ ะฟะพััะฐะฒัะธะบะต ะธะดะตะฝัะธัะธะบะฐัะธะพะฝะฝัั
ะดะฐะฝะฝัั
."
-
-msgid "mail domain"
-msgstr "ะฟะพััะพะฒัะน ะดะพะผะตะฝ"
-
-msgid "mail domains"
-msgstr "ะฟะพััะพะฒัะต ะดะพะผะตะฝั"
-
-msgid "Human-readable name for this channel"
-msgstr "ะงะตะปะพะฒะตะบะพัะธัะฐะตะผะพะต ะฝะฐะทะฒะฐะฝะธะต ะดะปั ััะพะณะพ ะบะฐะฝะฐะปะฐ"
-
-msgid "type"
-msgstr "ัะธะฟ"
-
-msgid "Type of channel"
-msgstr "ะขะธะฟ ะบะฐะฝะฐะปะฐ"
-
-msgid "settings"
-msgstr "ะฝะฐัััะพะนะบะธ"
-
-msgid "Channel-specific configuration settings"
-msgstr "ะกะฟะตัะธัะธัะฝัะต ะฝะฐัััะพะนะบะธ ะบะพะฝัะธะณััะฐัะธะธ ะบะฐะฝะฐะปะฐ"
-
-msgid "Mailbox that receives messages from this channel"
-msgstr "ะะพััะพะฒัะน ััะธะบ, ะบะพัะพััะน ะฟะพะปััะฐะตั ัะพะพะฑัะตะฝะธั ะพั ััะพะณะพ ะบะฐะฝะฐะปะฐ"
-
-msgid "Mail domain that owns this channel"
-msgstr "ะะพะผะตะฝ ะฟะพััั, ั ะบะพัะพัะพะณะพ ะตััั ััะพั ะบะฐะฝะฐะป"
-
-msgid "channel"
-msgstr "ะบะฐะฝะฐะป"
-
-msgid "channels"
-msgstr "ะบะฐะฝะฐะปั"
-
-msgid "local part"
-msgstr "ะปะพะบะฐะปัะฝะฐั ัะฐััั"
-
-msgid "is identity"
-msgstr "ัะฒะปัะตััั ะปะธัะฝะพัััั"
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr "ะะฟัะตะดะตะปัะตั ะปะธ ััะพั ะฟะพััะพะฒัะน ััะธะบ ัะตะปะพะฒะตะบะฐ (ั.ะต. ะฝะต ัะฒะปัะตััั ะฟัะตะฒะดะพะฝะธะผะพะผ ะธะปะธ ะณััะฟะฟะพะน)"
-
-msgid "mailbox"
-msgstr "ะฟะพััะพะฒัะน ััะธะบ"
-
-msgid "mailboxes"
-msgstr "ะฟะพััะพะฒัะต ััะธะบะธ"
-
-msgid "role"
-msgstr "ัะพะปั"
-
-msgid "accessed at"
-msgstr "ะดะพัััะฟ ะฒ"
-
-msgid "mailbox access"
-msgstr "ะดะพัััะฟ ะบ ะฟะพััะพะฒะพะผั ััะธะบั"
-
-msgid "mailbox accesses"
-msgstr "ะดะพัััะฟ ะบ ะฟะพััะพะฒะพะผั ััะธะบั"
-
-msgid "subject"
-msgstr "ัะตะผะฐ"
-
-msgid "snippet"
-msgstr "ััะฐะณะผะตะฝั"
-
-msgid "has unread"
-msgstr "ัะพะดะตัะถะธั ะฝะตะฟัะพัะธัะฐะฝะฝัะต"
-
-msgid "has trashed"
-msgstr "ัะพะดะตัะถะธั ัะดะฐะปัะฝะฝัะต"
-
-msgid "is trashed"
-msgstr "ะฒ ะบะพัะทะธะฝะต"
-
-msgid "Whether all messages in the thread are trashed"
-msgstr "ะัะต ะปะธ ัะพะพะฑัะตะฝะธั ะฒ ะพะฑััะถะดะตะฝะธะธ ัะดะฐะปััััั"
-
-msgid "has archived"
-msgstr "ะทะฐะฐัั
ะธะฒะธัะพะฒะฐะฝะพ"
-
-msgid "has draft"
-msgstr "ัะพะดะตัะถะธั ัะตัะฝะพะฒะธะบะธ"
-
-msgid "has starred"
-msgstr "ัะพะดะตัะถะธั ะธะทะฑัะฐะฝะฝะพะต"
-
-msgid "has sender"
-msgstr "ัะพะดะตัะถะธั ะพัะฟัะฐะฒะปะตะฝะฝัะต"
-
-msgid "has messages"
-msgstr "ัะพะดะตัะถะธั ัะพะพะฑัะตะฝะธั"
-
-msgid "has attachments"
-msgstr "ัะพะดะตัะถะธั ะฒะปะพะถะตะฝะธั"
-
-msgid "is spam"
-msgstr "ัะฒะปัะตััั ัะฟะฐะผะพะผ"
-
-msgid "has active"
-msgstr "ัะพะดะตัะถะธั ะฐะบัะธะฒะฝัะต"
-
-msgid "messaged at"
-msgstr "ัะพะพะฑัะตะฝะธะต ะฒ"
-
-msgid "sender names"
-msgstr "ะธะผะตะฝะฐ ะพัะฟัะฐะฒะธัะตะปั"
-
-msgid "summary"
-msgstr "ัะฒะพะดะบะฐ"
-
-msgid "thread"
-msgstr "ะพะฑััะถะดะตะฝะธะต"
-
-msgid "threads"
-msgstr "ะพะฑััะถะดะตะฝะธั"
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr "ะะผั ััะปัะบะฐ/ะฟะฐะฟะบะธ (ะผะพะถะตั ะธัะฟะพะปัะทะพะฒะฐัั ะบะพััั ัะตััั ะดะปั ะทะฐะดะฐะฝะธั ะธะตัะฐัั
ะธะธ, ะฝะฐะฟัะธะผะตั 'ะ ะฐะฑะพัะฐ/ะัะพะตะบัั')"
-
-msgid "slug"
-msgstr "ะฟัะตะฒะดะพะฝะธะผ"
-
-msgid "URL-friendly version of the name"
-msgstr "ะะตััะธั ะธะผะตะฝะธ, ัะพะฒะผะตััะธะผะฐั ั ัะพัะผะฐัะพะผ ะฐะดัะตัะพะฒ URL"
-
-msgid "color"
-msgstr "ัะฒะตั"
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr "ะฆะฒะตั ััะปัะบะฐ ะฒ ัะตััะฝะฐะดัะฐัะตัะธัะฝะพะผ ัะพัะผะฐัะต (ะฝะฐะฟัะธะผะตั, #FF0000)"
-
-msgid "Mailbox that owns this label"
-msgstr "ะะพััะพะฒัะน ััะธะบ ั ััะธะผ ััะปัะบะพะผ"
-
-msgid "Threads that have this label"
-msgstr "ะะฑััะถะดะตะฝะธั ั ััะธะผ ััะปัะบะพะผ"
-
-msgid "description"
-msgstr "ะพะฟะธัะฐะฝะธะต"
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr "ะะฟะธัะฐะฝะธะต ััะปัะบะฐ, ะธัะฟะพะปัะทัะตะผะพะต ะะ ะดะปั ะฟะพะฝะธะผะฐะฝะธั ะตะณะพ ะฝะฐะทะฝะฐัะตะฝะธั"
-
-msgid "auto labeling"
-msgstr "ะฐะฒัะพะผะฐัะบะธัะพะฒะบะฐ ััะปัะบะฐะผะธ"
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr "ะะพะปะถะตะฝ ะปะธ ััะพั ััะปัะบ ะฐะฒัะพะผะฐัะธัะตัะบะธ ะฟัะธะผะตะฝััััั ะะ"
-
-msgid "label"
-msgstr "ััะปัะบ"
-
-msgid "labels"
-msgstr "ััะปัะบะธ"
-
-msgid "thread access"
-msgstr "ะดะพัััะฟ ะบ ะพะฑััะถะดะตะฝะธั"
-
-msgid "thread accesses"
-msgstr "ะดะพัััะฟั ะบ ะพะฑััะถะดะตะฝะธั"
-
-msgid "email"
-msgstr "ัะป. ะฟะพััะฐ"
-
-msgid "contact"
-msgstr "ะบะพะฝัะฐะบั"
-
-msgid "contacts"
-msgstr "ะบะพะฝัะฐะบัั"
-
-msgid "delivered at"
-msgstr "ะดะพััะฐะฒะปะตะฝะพ"
-
-msgid "delivery message"
-msgstr "ัะพะพะฑัะตะฝะธะต ะดะปั ะดะพััะฐะฒะบะธ"
-
-msgid "retry count"
-msgstr "ะบะพะปะธัะตััะฒะพ ะฟะพะฒัะพัะพะฒ"
-
-msgid "retry at"
-msgstr "ะฟะพะฒัะพัะธัั"
-
-msgid "message recipient"
-msgstr "ะฟะพะปััะฐัะตะปั ัะพะพะฑัะตะฝะธั"
-
-msgid "message recipients"
-msgstr "ะฟะพะปััะฐัะตะปะธ ัะพะพะฑัะตะฝะธั"
-
-msgid "is draft"
-msgstr "ัะฒะปัะตััั ัะตัะฝะพะฒะธะบะพะผ"
-
-msgid "is sender"
-msgstr "ะพัะฟัะฐะฒะธัะตะปั"
-
-msgid "is starred"
-msgstr "ะฟะพะผะตัะตะฝะพ"
-
-msgid "is unread"
-msgstr "ะฝะตะฟัะพัะธัะฐะฝะพ"
-
-msgid "is archived"
-msgstr "ะทะฐะฐัั
ะธะฒะธัะพะฒะฐะฝะพ"
-
-msgid "trashed at"
-msgstr "ะฒ ะบะพัะทะธะฝะต"
-
-msgid "sent at"
-msgstr "ะพัะฟัะฐะฒะปะตะฝะพ"
-
-msgid "read at"
-msgstr "ะฟัะพัะธัะฐะฝะพ"
-
-msgid "archived at"
-msgstr "ะฐัั
ะธะฒะธัะพะฒะฐะฝะพ"
-
-msgid "mime id"
-msgstr "mime id"
-
-msgid "Signature template for the message"
-msgstr "ะจะฐะฑะปะพะฝ ะฟะพะดะฟะธัะธ ะดะปั ัะพะพะฑัะตะฝะธั"
-
-msgid "message"
-msgstr "ัะพะพะฑัะตะฝะธะต"
-
-msgid "messages"
-msgstr "ัะพะพะฑัะตะฝะธั"
-
-msgid "No subject"
-msgstr "ะะตะท ัะตะผั"
-
-msgid "Message ID"
-msgstr "ID ัะพะพะฑัะตะฝะธั"
-
-msgid "From"
-msgstr "ะั"
-
-msgid "To"
-msgstr "ะะพะผั"
-
-msgid "CC"
-msgstr "ะะพะฟะธั"
-
-msgid "Date"
-msgstr "ะะฐัะฐ"
-
-msgid "Subject"
-msgstr "ะขะตะผะฐ"
-
-msgid "Body"
-msgstr "ะขะตะบัั ัะพะพะฑัะตะฝะธั"
-
-msgid "raw data"
-msgstr "ะฝะตะพะฑัะฐะฑะพัะฐะฝะฝัะต ะดะฐะฝะฝัะต"
-
-msgid "Raw email message bytes"
-msgstr "ะกััะพะน ัะตะบัั ะฑะฐะนัะพะฒ ัะพะพะฑัะตะฝะธั"
-
-msgid "error message"
-msgstr "ัะพะพะฑัะตะฝะธะต ะพะฑ ะพัะธะฑะบะต"
-
-msgid "Error message if processing failed"
-msgstr "ะกะพะพะฑัะตะฝะธะต ะพะฑ ะพัะธะฑะบะต, ะตัะปะธ ะฝะต ัะดะฐะปะพัั ะพะฑัะฐะฑะพัะฐัั"
-
-msgid "inbound message"
-msgstr "ะฒั
ะพะดััะตะต ัะพะพะฑัะตะฝะธะต"
-
-msgid "inbound messages"
-msgstr "ะฒั
ะพะดััะธะต ัะพะพะฑัะตะฝะธั"
-
-msgid "sha256 hash"
-msgstr "sha256 hash"
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr "ะฅัั SHA-256 ะฑะตะท ัะถะฐัะพะณะพ ัะพะดะตัะถะธะผะพะณะพ"
-
-msgid "file size"
-msgstr "ัะฐะทะผะตั ัะฐะนะปะฐ"
-
-msgid "Size of the blob in bytes"
-msgstr "ะ ะฐะทะผะตั ะฑะปะพะบะฐ ะฒ ะฑะฐะนัะฐั
"
-
-msgid "compressed size"
-msgstr "ัะถะฐััะน ัะฐะทะผะตั"
-
-msgid "Size of the compressed blob in bytes"
-msgstr "ะ ะฐะทะผะตั ัะถะฐัะพะณะพ ะฑะปะพะบะฐ ะฒ ะฑะฐะนัะฐั
"
-
-msgid "content type"
-msgstr "ัะธะฟ ัะพะดะตัะถะธะผะพะณะพ"
-
-msgid "MIME type of the blob"
-msgstr "MIME ัะธะฟ ะฑะปะพะบะฐ"
-
-msgid "compression"
-msgstr "ัะถะฐัะธะต"
-
-msgid "raw content"
-msgstr "ะฝะตะพะฑัะฐะฑะพัะฐะฝะฝะพะต ัะพะดะตัะถะธะผะพะต"
-
-msgid "Compressed binary content of the blob"
-msgstr "ะกะถะฐัะพะต ะดะฒะพะธัะฝะพะต ัะพะดะตัะถะธะผะพะต ะฑะปะพะบะฐ"
-
-msgid "Mailbox that owns this blob"
-msgstr "ะะพััะพะฒัะน ััะธะบ, ั ะบะพัะพัะพะณะพ ะตััั ััะพั ะฑะปะพะบ"
-
-msgid "Mail domain that owns this blob"
-msgstr "ะะพะผะตะฝ ะฟะพััั, ั ะบะพัะพัะพะณะพ ะตััั ััะพั ะฑะปะพะบ"
-
-msgid "blob"
-msgstr "ะฑะปะพะบ"
-
-msgid "blobs"
-msgstr "ะฑะปะพะบะธ"
-
-msgid "file name"
-msgstr "ะธะผั ัะฐะนะปะฐ"
-
-msgid "Original filename of the attachment"
-msgstr "ะัั
ะพะดะฝะพะต ะธะผั ัะฐะนะปะฐ ะฒะปะพะถะตะฝะธั"
-
-msgid "Reference to the blob containing the attachment data"
-msgstr "ะกััะปะบะฐ ะฝะฐ ะฑะปะพะบ, ัะพะดะตัะถะฐัะธะน ะดะฐะฝะฝัะต ัะฐะฑะปะพะฝะฐ ะฒ ัะพัะผะฐัะต Json"
-
-msgid "Mailbox that owns this attachment"
-msgstr "ะะพััะพะฒัะน ััะธะบ, ั ะบะพัะพัะพะณะพ ะตััั ััะพ ะฒะปะพะถะตะฝะธะต"
-
-msgid "Messages that use this attachment"
-msgstr "ะกะพะพะฑัะตะฝะธั, ะบะพัะพััะต ะธัะฟะพะปัะทััั ััะพ ะฒะปะพะถะตะฝะธะต"
-
-msgid "content ID"
-msgstr "content ID"
-
-msgid "Content-ID for inline images"
-msgstr "Content-ID ะดะปั ะฒัััะพะตะฝะฝัั
ะธะทะพะฑัะฐะถะตะฝะธะน"
-
-msgid "attachment"
-msgstr "ะฒะปะพะถะตะฝะธะต"
-
-msgid "attachments"
-msgstr "ะฒะปะพะถะตะฝะธั"
-
-msgid "mail domain access"
-msgstr "ะดะพัััะฟ ะบ ะฟะพััะพะฒะพะผั ะดะพะผะตะฝั"
-
-msgid "mail domain accesses"
-msgstr "ะดะพัััะฟ ะบ ะฟะพััะพะฒะพะผั ะดะพะผะตะฝั"
-
-msgid "selector"
-msgstr "ัะตะปะตะบัะพั"
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr "ะกะตะปะตะบัะพั DKIM (ะฝะฐะฟัะธะผะตั, 'default', 'mail')"
-
-msgid "private key"
-msgstr "ะทะฐะบััััะน ะบะปัั"
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr "ะะฐะบััััะน ะบะปัั DKIM ะฒ ัะพัะผะฐัะต PEM (ะทะฐัะธััะพะฒะฐะฝะฝัะน)"
-
-msgid "public key"
-msgstr "ะพัะบััััะน ะบะปัั"
-
-msgid "DKIM public key for DNS record generation"
-msgstr "ะัะบััััะน ะบะปัั DKIM ะดะปั ะณะตะฝะตัะฐัะธะธ DNS ะทะฐะฟะธัะตะน"
-
-msgid "algorithm"
-msgstr "ะฐะปะณะพัะธัะผ"
-
-msgid "DKIM signing algorithm"
-msgstr "ะะปะณะพัะธัะผ ะฟะพะดะฟะธัะธ DKIM"
-
-msgid "key size"
-msgstr "ัะฐะทะผะตั ะบะปััะฐ"
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr "ะ ะฐะทะผะตั ะบะปััะฐ ะฒ ะฑะธัะฐั
(ะฝะฐะฟัะธะผะตั, 2048, 4096 ะดะปั RSA)"
-
-msgid "is active"
-msgstr "ะฐะบัะธะฒะฝัะน"
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr "ะฏะฒะปัะตััั ะปะธ ััะพั ะบะปัั DKIM ะฐะบัะธะฒะฝัะผ ะธ ะดะพะปะถะตะฝ ะธัะฟะพะปัะทะพะฒะฐัััั ะดะปั ะฟะพะดะฟะธัะฐะฝะธั"
-
-msgid "Domain that owns this DKIM key"
-msgstr "ะะพะผะตะฝ, ะฒะปะฐะดะตััะธะน ััะธะผ ะบะปััะพะผ DKIM"
-
-msgid "DKIM key"
-msgstr "ะะปัั DKIM"
-
-msgid "DKIM keys"
-msgstr "ะะปััะธ DKIM"
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr "ะะฐะทะฒะฐะฝะธะต ัะฐะฑะปะพะฝะฐ (ะฝะฐะฟัะธะผะตั, 'ะกัะฐะฝะดะฐััะฝัะน ะพัะฒะตั', 'ะะต ะฒ ะพัะธัะต', 'ะ ะฐะฑะพัะฐั ะฟะพะดะฟะธัั')"
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr "ะกััะปะบะฐ ะฝะฐ ะฑะปะพะบ, ัะพะดะตัะถะฐัะธะน ะดะฐะฝะฝัะต ัะฐะฑะปะพะฝะฐ ะฒ ัะพัะผะฐัะต JSON: {html: str, text: str, raw: any}"
-
-msgid "Type of template (message, signature)"
-msgstr "ะขะธะฟ ัะฐะฑะปะพะฝะฐ (ัะพะพะฑัะตะฝะธะต, ะฟะพะดะฟะธัั)"
-
-msgid "Whether this template is available for use"
-msgstr "ะะพัััะฟะตะฝ ะปะธ ััะพั ัะฐะฑะปะพะฝ ะดะปั ะธัะฟะพะปัะทะพะฒะฐะฝะธั"
-
-msgid "Mail domain that can use this template"
-msgstr "ะะพะผะตะฝ ะฟะพััั, ะบะพัะพััะน ะผะพะถะตั ะธัะฟะพะปัะทะพะฒะฐัั ััะพั ัะฐะฑะปะพะฝ"
-
-msgid "Mailbox that can use this template"
-msgstr "ะะพััะพะฒัะน ััะธะบ, ะบะพัะพััะน ะผะพะถะตั ะธัะฟะพะปัะทะพะฒะฐัั ััะพั ัะฐะฑะปะพะฝ"
-
-msgid "is forced"
-msgstr "ะพะฑัะทะฐัะตะปัะฝะพ"
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr "ะะพะถะตั ะปะธ ััะพั ัะฐะฑะปะพะฝ ะฟัะธะผะตะฝััััั ะฒ ะพะฑัะทะฐัะตะปัะฝะพะผ ะฟะพััะดะบะต; ะฑัะดะตั ะฝะตะฒะพะทะผะพะถะฝะพ ะธัะฟะพะปัะทะพะฒะฐัั ะดััะณะพะน ัะฐะฑะปะพะฝ ัะพะณะพ ะถะต ัะธะฟะฐ ะฒ ัะพะน ะถะต ะพะฑะปะฐััะธ"
-
-msgid "is default"
-msgstr "ะฟะพ-ัะผะพะปัะฐะฝะธั"
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr "ะจะฐะฑะปะพะฝ ะฟะพ ัะผะพะปัะฐะฝะธั; ะพะฝ ะฑัะดะตั ะฐะฒัะพะผะฐัะธัะตัะบะธ ะทะฐะณััะถะตะฝ ะฟัะธ ะฝะฐะฟะธัะฐะฝะธะธ ะฝะพะฒะพะณะพ ัะพะพะฑัะตะฝะธั"
-
-msgid "message template"
-msgstr "ัะฐะฑะปะพะฝ ัะพะพะฑัะตะฝะธั"
-
-msgid "message templates"
-msgstr "ัะฐะฑะปะพะฝั ัะพะพะฑัะตะฝะธะน"
-
-msgid "Provision DNS records"
-msgstr "ะะฐัััะพะนะบะฐ ะทะฐะฟะธัะตะน DNS"
-
-msgid "Retry to send to pending recipients"
-msgstr "ะะพะฒัะพัะธัั ะพัะฟัะฐะฒะบั ะพะถะธะดะฐััะธะผ ะฟะพะปััะฐัะตะปัะผ"
-
-msgid "Import from IMAP"
-msgstr "ะะผะฟะพัั ะธะท IMAP"
-
-msgid "Home"
-msgstr "ะะปะฐะฒะฝะฐั"
-
-msgid "Please correct the error below."
-msgstr "ะะพะถะฐะปัะนััะฐ, ะธัะฟัะฐะฒััะต ัะปะตะดััััั ะพัะธะฑะบั."
-
-msgid "Please correct the errors below."
-msgstr "ะะพะถะฐะปัะนััะฐ, ะธัะฟัะฐะฒััะต ัะปะตะดัััะธะต ะพัะธะฑะบะธ."
-
-msgid "Start Import"
-msgstr "ะะฐัะฐัั ะธะผะฟะพัั"
-
-msgid "English"
-msgstr "ะะฝะณะปะธะนัะบะธะน"
-
-msgid "French"
-msgstr "ะคัะฐะฝััะทัะบะธะน"
-
-msgid "Dutch"
-msgstr "ะะธะดะตัะปะฐะฝัะบะธะน"
-
diff --git a/src/backend/locale/uk_UA/LC_MESSAGES/django.mo b/src/backend/locale/uk_UA/LC_MESSAGES/django.mo
deleted file mode 100644
index 01a9643d..00000000
Binary files a/src/backend/locale/uk_UA/LC_MESSAGES/django.mo and /dev/null differ
diff --git a/src/backend/locale/uk_UA/LC_MESSAGES/django.po b/src/backend/locale/uk_UA/LC_MESSAGES/django.po
deleted file mode 100644
index 337552b2..00000000
--- a/src/backend/locale/uk_UA/LC_MESSAGES/django.po
+++ /dev/null
@@ -1,680 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: lasuite-messages\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-01-25 11:10+0000\n"
-"PO-Revision-Date: 2026-02-03 17:00\n"
-"Last-Translator: \n"
-"Language-Team: Ukrainian\n"
-"Language: uk_UA\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
-"X-Crowdin-Project: lasuite-messages\n"
-"X-Crowdin-Project-ID: 831182\n"
-"X-Crowdin-Language: uk\n"
-"X-Crowdin-File: backend.pot\n"
-"X-Crowdin-File-ID: 40\n"
-
-msgid "delivery status"
-msgstr "ััะฐะฝ ะดะพััะฐะฒะบะธ"
-
-#, python-format
-msgid "%(message_count)d messages - Retry send message task queued (id: %(task_id)s)."
-msgstr "%(message_count)d ะฟะพะฒัะดะพะผะปะตะฝั - ะะพะฒัะพัะธัะธ ะทะฐะฒะดะฐะฝะฝั ะฒัะดะฟัะฐะฒะปะตะฝะฝั ะฟะพะฒัะดะพะผะปะตะฝะฝั ะฒ ัะตัะทั (id: %(task_id)s)."
-
-msgid "Retry to send selected messages to pending recipients"
-msgstr "ะะพะฒัะพัะธัะธ ัะฟัะพะฑั ะฝะฐะดัะธะปะฐะฝะฝั ะฒะธะฑัะฐะฝะธั
ะฟะพะฒัะดะพะผะปะตะฝั ะดะพ ะพััะบัััะธั
ะพััะธะผัะฒะฐััะฒ"
-
-msgid "Personal info"
-msgstr "ะัะพะฑะธััั ะดะฐะฝั"
-
-msgid "Permissions"
-msgstr "ะะพะทะฒะพะปะธ"
-
-msgid "Important dates"
-msgstr "ะะฐะถะปะธะฒั ะดะฐัะธ"
-
-msgid "Mail domain not found."
-msgstr "ะะพััะพะฒะธะน ะดะพะผะตะฝ ะฝะต ะทะฝะฐะนะดะตะฝะพ."
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s: %(changes)s"
-msgstr "ะฃัะฟััะฝะต ะฝะฐะปะฐัััะฒะฐะฝะฝั DNS ัะตัะตะท %(provider)s: %(changes)s"
-
-#, python-format
-msgid "DNS provisioning successful via %(provider)s (no changes needed)."
-msgstr "ะฃัะฟััะฝะต ะฝะฐะปะฐัััะฒะฐะฝะฝั DNS ัะตัะตะท %(provider)s (ะทะผัะฝะธ ะฝะต ะฟะพัััะฑะฝั)."
-
-#, python-format
-msgid "DNS provisioning failed: %(error)s"
-msgstr "ะะพะผะธะปะบะฐ ะฟัะด ัะฐั ะฝะฐะปะฐัััะฒะฐะฝะฝั DNS: %(error)s"
-
-msgid "Statistics"
-msgstr "ะกัะฐัะธััะธะบะฐ"
-
-msgid "Metadata"
-msgstr "ะะตัะฐะดะฐะฝั"
-
-msgid "Labels"
-msgstr "ะััะบะธ"
-
-msgid "No labels"
-msgstr "ะะตะท ะผััะพะบ"
-
-msgid "Import Messages"
-msgstr "ะะผะฟะพัั ะฟะพะฒัะดะพะผะปะตะฝั"
-
-msgid "Import Messages from IMAP"
-msgstr "ะะผะฟะพัั ะฟะพะฒัะดะพะผะปะตะฝั ะท IMAP"
-
-msgid "Message not found."
-msgstr "ะะพะฒัะดะพะผะปะตะฝะฝั ะฝะต ะทะฝะฐะนะดะตะฝะต."
-
-msgid "No pending recipients found for this message."
-msgstr "ะะปั ััะพะณะพ ะฟะพะฒัะดะพะผะปะตะฝะฝั ะฝะต ะทะฝะฐะนะดะตะฝะพ ะถะพะดะฝะพะณะพ ะพััะธะผัะฒะฐัะฐ."
-
-#, python-format
-msgid "Retry task has been queued for %(retryable_recipients_count)d pending recipient(s) (id: %(task_id)s)."
-msgstr "ะะฐะฒะดะฐะฝะฝั ะฟะพะฒัะพัั ะฑัะปะพ ะฟะพััะฐะฒะปะตะฝะพ ะฒ ัะตัะณั ะฝะฐ %(retryable_recipients_count)d ะพะดะตัะถัะฒะฐััะฒ (id: %(task_id)s)."
-
-msgid "Keys"
-msgstr "ะะปััั"
-
-msgid "Error"
-msgstr "ะะพะผะธะปะบะฐ"
-
-msgid "A mailbox with this local part already exists in this domain."
-msgstr "ะะพััะพะฒะฐ ัะบัะธะฝัะบะฐ ะท ัััั ะปะพะบะฐะปัะฝะพั ัะฐััะธะฝะพั ะฒะถะต ััะฝัั ะฒ ััะพะผั ะดะพะผะตะฝั."
-
-msgid "Name"
-msgstr "ะะผโั"
-
-msgid "Recipient name"
-msgstr "ะะผ`ั ะพััะธะผัะฒะฐัะฐ"
-
-msgid "messages core application"
-msgstr "ะฟะพะฒัะดะพะผะปะตะฝะฝั ะพัะฝะพะฒะฝะพั ะฟัะพะณัะฐะผะธ"
-
-msgid "User account is disabled"
-msgstr "ะะฑะปัะบะพะฒะธะน ะทะฐะฟะธั ะบะพัะธัััะฒะฐัะฐ ะฒะธะผะบะฝะตะฝะพ"
-
-#, python-format
-msgid "Message body size (%(body_size)s MB) exceeds the %(max_size)s MB limit. Please reduce message content."
-msgstr "ะ ะพะทะผัั ััะปะฐ ะฟะพะฒัะดะพะผะปะตะฝะฝั (%(body_size)s ะะ) ะฟะตัะตะฒะธััั ะปัะผัั ั %(max_size)s ะะ. ะัะดั ะปะฐัะบะฐ, ะทะผะตะฝััะต ะฒะผััั ะฟะพะฒัะดะพะผะปะตะฝะฝั."
-
-#, python-format
-msgid "Cannot add attachment(s) (%(new_size)s MB). Total attachments would be %(total_size)s MB, exceeding the %(max_size)s MB limit. Current attachments: %(current_size)s MB."
-msgstr "ะะตะผะพะถะปะธะฒะพ ะดะพะดะฐัะธ ะฒะบะปะฐะดะตะฝะฝั (ะพะดะฝะต ัะธ ะดะตะบัะปัะบะฐ) (%(new_size)s ะะ). ะะฐะณะฐะปัะฝะธะน ัะพะทะผัั ะฒะบะปะฐะดะตะฝั - %(total_size)s ะะ, ัะพ ะฟะตัะตะฒะธััั ะปัะผัั %(max_size)s ะะ. ะะพัะพัะฝะธั
ะฒะบะปะฐะดะตะฝั: %(current_size)s ะะ."
-
-#, python-format
-msgid "Too many recipients: %(count)s (maximum is %(max)s). Please reduce the number of recipients before sending."
-msgstr "ะะฐะฝะฐะดัะพ ะฑะฐะณะฐัะพ ะพััะธะผัะฒะฐััะฒ: %(count)s (ะผะฐะบัะธะผัะผ %(max)s). ะะผะตะฝััะต ะบัะปัะบัััั ะพะดะตัะถัะฒะฐััะฒ, ะฟะตัั ะฝัะถ ะฝะฐะดัะธะปะฐัะธ."
-
-#, python-format
-msgid "Total attachment size (%(total_size)s MB) exceeds the %(max_size)s MB limit. Please remove or reduce attachments."
-msgstr "ะะฐะณะฐะปัะฝะธะน ัะพะทะผัั ะฒะบะปะฐะดะตะฝะฝั (%(total_size)s ะะ) ะฟะตัะตะฒะธััั ะปัะผัั %(max_size)s MB. ะัะดั ะปะฐัะบะฐ, ะฒะธะดะฐะปััั ะฐะฑะพ ะทะผะตะฝััะต ะฒะบะปะฐะดะตะฝะฝั."
-
-#, python-format
-msgid "The composed email (%(mime_size)s MB) exceeds the maximum allowed size of %(max_size)s MB. Please reduce message content or attachments."
-msgstr "ะ ะพะทะผัั ััะพัะผะพะฒะฐะฝะพะณะพ ะตะปะตะบััะพะฝะฝะพะณะพ ะปะธััะฐ (%(mime_size)s ะะ) ะฟะตัะตะฒะธััั ะผะฐะบัะธะผะฐะปัะฝะพ ะดะพะทะฒะพะปะตะฝะธะน ัะพะทะผัั ั %(max_size)s ะะ. ะัะดั ะปะฐัะบะฐ, ะทะผะตะฝััะต ะฒะผััั ะฟะพะฒัะดะพะผะปะตะฝะฝั ะฐะฑะพ ะฒะบะปะฐะดะตะฝะฝั."
-
-msgid "id"
-msgstr "id"
-
-msgid "primary key for the record as UUID"
-msgstr "ะฟะตัะฒะธะฝะฝะธะน ะบะปัั ะดะปั ะทะฐะฟะธัั ัะบ UUID"
-
-msgid "created on"
-msgstr "ััะฒะพัะตะฝะพ"
-
-msgid "date and time at which a record was created"
-msgstr "ะดะฐัะฐ ั ัะฐั, ะบะพะปะธ ะทะฐะฟะธั ะฑัะปะพ ััะฒะพัะตะฝะพ"
-
-msgid "updated on"
-msgstr "ะพะฝะพะฒะปะตะฝะพ"
-
-msgid "date and time at which a record was last updated"
-msgstr "ะดะฐัะฐ ั ัะฐั, ะบะพะปะธ ะทะฐะฟะธั ะฑัะฒ ะฒะพััะฐะฝะฝั ะพะฝะพะฒะปะตะฝะธะน"
-
-msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
-msgstr "ะะธ ะฝะต ะทะผะพะณะปะธ ะทะฝะฐะนัะธ ะบะพัะธัััะฒะฐัะฐ ะท ัะธะผะธ ะดะฐะฝะธะผะธ, ะฐะปะต ะฐะดัะตัะฐ ะฒะถะต ะฟะพะฒ'ัะทะฐะฝะฐ ะท ะทะฐัะตััััะพะฒะฐะฝะธะผ ะบะพัะธัััะฒะฐัะตะผ."
-
-msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
-msgstr "ะะฒะตะดััั ะฟัะฐะฒะธะปัะฝะธะน ะฟัะตััะบั. ะฆะต ะทะฝะฐัะตะฝะฝั ะผะพะถะต ะผัััะธัะธ ะปะธัะต ะปััะตัะธ, ัะธััะธ ัะฐ ัะธะผะฒะพะปะธ @/./+/-/_/:."
-
-msgid "sub"
-msgstr "ะฟัะตััะบั"
-
-msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
-msgstr "ะะฑะพะฒ'ัะทะบะพะฒะพ. 255 ัะธะผะฒะพะปัะฒ ะฐะฑะพ ะผะตะฝัะต. ะะธัะต ะปััะตัะธ, ัะธััะธ ัะฐ ัะธะผะฒะพะปะธ @/./+/-/_/:."
-
-msgid "full name"
-msgstr "ะฟะพะฒะฝะต ัะผ'ั"
-
-msgid "identity email address"
-msgstr "ะฐะดัะตัะฐ ะตะปะตะบััะพะฝะฝะพั ะฟะพััะธ ะพัะพะฑะธ"
-
-msgid "admin email address"
-msgstr "ะตะปะตะบััะพะฝะฝะฐ ะฐะดัะตัะฐ ะฐะดะผัะฝััััะฐัะพัะฐ"
-
-msgid "language"
-msgstr "ะผะพะฒะฐ"
-
-msgid "The language in which the user wants to see the interface."
-msgstr "ะะพะฒะฐ, ัะบะพั ะบะพัะธัััะฒะฐั ั
ะพัะต ะฑะฐัะธัะธ ัะฝัะตััะตะนั."
-
-msgid "The timezone in which the user wants to see times."
-msgstr "ะงะฐัะพะฒะธะน ะฟะพัั, ะฒ ัะบะพะผั ะบะพัะธัััะฒะฐั ั
ะพัะต ะฑะฐัะธัะธ ัะฐั."
-
-msgid "staff status"
-msgstr "ััะฐััั ัะฟัะฒัะพะฑััะฝะธะบะฐ"
-
-msgid "Whether the user can log into this admin site."
-msgstr "ะงะธ ะผะพะถะต ะบะพัะธัััะฒะฐั ัะฒัะนัะธ ะฝะฐ ัะตะน ัะฐะนั ะฐะดะผัะฝััััะฐัะพัะฐ."
-
-msgid "active"
-msgstr "ะฐะบัะธะฒะฝะธะน"
-
-msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
-msgstr "ะงะธ ัะปัะด ััะฐะฒะธัะธัั ะดะพ ััะพะณะพ ะบะพัะธัััะฒะฐัะฐ ัะบ ะดะพ ะฐะบัะธะฒะฝะพะณะพ. ะะฝัะผััั ะฒะธะฑัั ะทะฐะผัััั ะฒะธะดะฐะปะตะฝะฝั ะพะฑะปัะบะพะฒะพะณะพ ะทะฐะฟะธัั."
-
-msgid "Custom attributes"
-msgstr "ะะพัะธัััะฒะฐััะบั ะฐััะธะฑััะธ"
-
-msgid "Metadata to sync to the user in the identity provider."
-msgstr "ะะตัะฐะดะฐะฝั ะดะปั ัะธะฝั
ัะพะฝัะทะฐััั ะบะพัะธัััะฒะฐัะฐ ะฒ ะฟัะพะฒะฐะนะดะตัั ัะดะตะฝัะธััะบะฐััั."
-
-msgid "user"
-msgstr "ะบะพัะธัััะฒะฐั"
-
-msgid "users"
-msgstr "ะบะพัะธัััะฒะฐัั"
-
-msgid "Enter a valid domain name. This value may contain only lowercase letters, numbers, dots and - characters."
-msgstr "ะะฒะตะดััั ะดะพะฟัััะธะผะต ัะผ'ั ะดะพะผะตะฝั. ะฆะต ะทะฝะฐัะตะฝะฝั ะผะพะถะต ะผัััะธัะธ ะปะธัะต ะผะฐะปั ะปััะตัะธ, ัะธััะธ, ะบัะฐะฟะบะธ ัะฐ ัะธะผะฒะพะปะธ ะดะตัััั."
-
-msgid "name"
-msgstr "ัะผโั"
-
-msgid "oidc autojoin"
-msgstr "oidc autojoin"
-
-msgid "Create mailboxes automatically based on OIDC emails."
-msgstr "ะะฒัะพะผะฐัะธัะฝะต ััะฒะพัะตะฝะฝั ะฟะพััะพะฒะธั
ัะบัะธะฝัะพะบ ะฝะฐ ะพัะฝะพะฒั ะตะปะตะบััะพะฝะฝะธั
ะปะธัััะฒ OIDC."
-
-msgid "Identity sync"
-msgstr "ะกะธะฝั
ัะพะฝัะทะฐััั ัะดะตะฝัะธััะบะฐััั"
-
-msgid "Sync mailboxes to an identity provider."
-msgstr "ะกะธะฝั
ัะพะฝัะทะฐััั ะฟะพััะพะฒะธั
ัะบัะธะฝัะพะบ ะดะปั ะฟะพััะฐัะฐะปัะฝะธะบะฐ ัะดะตะฝัะธััะบะฐััั."
-
-msgid "Custom settings"
-msgstr "ะะพัะธัััะฒะฐััะบั ะฝะฐะปะฐัััะฒะฐะฝะฝั"
-
-msgid "Custom settings for the mail domain."
-msgstr "ะะพัะธัััะฒะฐััะบั ะฝะฐะปะฐัััะฒะฐะฝะฝั ะดะปั ะฟะพััะพะฒะพะณะพ ะดะพะผะตะฝั."
-
-msgid "Metadata to sync to the maildomain group in the identity provider."
-msgstr "ะะตัะฐะดะฐะฝั ะดะปั ัะธะฝั
ัะพะฝัะทะฐััั ะบะพัะธัััะฒะฐัะฐ ะฒ ะฟัะพะฒะฐะนะดะตัั ัะดะตะฝัะธััะบะฐััั."
-
-msgid "mail domain"
-msgstr "ะฟะพััะพะฒะธะน ะดะพะผะตะฝ"
-
-msgid "mail domains"
-msgstr "ะฟะพััะพะฒั ะดะพะผะตะฝะธ"
-
-msgid "Human-readable name for this channel"
-msgstr "ะัะดะธะฝะพ-ัะธััะฒะฐะฝะต ัะผ'ั ะดะปั ััะพะณะพ ะบะฐะฝะฐะปั"
-
-msgid "type"
-msgstr "ัะธะฟ"
-
-msgid "Type of channel"
-msgstr "ะขะธะฟ ะบะฐะฝะฐะปั"
-
-msgid "settings"
-msgstr "ะฟะฐัะฐะผะตััะธ"
-
-msgid "Channel-specific configuration settings"
-msgstr "ะะฐัะฐะผะตััะธ, ัะพ ะทะฐะปะตะถะฐัั ะฒัะด ะบะฐะฝะฐะปั"
-
-msgid "Mailbox that receives messages from this channel"
-msgstr "ะะพััะพะฒะฐ ัะบัะธะฝัะบะฐ, ัะบะฐ ะพััะธะผัั ะฟะพะฒัะดะพะผะปะตะฝะฝั ะฒัะด ััะพะณะพ ะบะฐะฝะฐะปั"
-
-msgid "Mail domain that owns this channel"
-msgstr "ะะพััะพะฒะธะน ะดะพะผะตะฝ, ัะพ ะฒะพะปะพะดัั ัะธะผ ะบะฐะฝะฐะปะพะผ"
-
-msgid "channel"
-msgstr "ะบะฐะฝะฐะป"
-
-msgid "channels"
-msgstr "ะบะฐะฝะฐะปะธ"
-
-msgid "local part"
-msgstr "ะปะพะบะฐะปัะฝะฐ ัะฐััะธะฝะฐ"
-
-msgid "is identity"
-msgstr "ั ะพัะพะฑะธัััััั"
-
-msgid "Whether this mailbox identifies a person (i.e. is not an alias or a group)"
-msgstr "ะงะธ ะฑัะดะต ัั ะฟะพััะพะฒะฐ ัะบัะธะฝัะบะฐ ัะดะตะฝัะธััะบัะฒะฐัะธ ะปัะดะธะฝั (ัะพะฑัะพ ะฝะต ะฟัะตะฒะดะพะฝัะผ ัะธ ะณััะฟั)"
-
-msgid "mailbox"
-msgstr "ะฟะพััะพะฒะฐ ัะบัะธะฝัะบะฐ"
-
-msgid "mailboxes"
-msgstr "ะฟะพััะพะฒั ัะบัะธะฝัะบะธ"
-
-msgid "role"
-msgstr "ัะพะปั"
-
-msgid "accessed at"
-msgstr "ะดะพัััะฟ ะดะพ"
-
-msgid "mailbox access"
-msgstr "ะดะพัััะฟ ะดะพ ะฟะพััะพะฒะพั ัะบัะธะฝัะบะธ"
-
-msgid "mailbox accesses"
-msgstr "ะดะพัััะฟ ะดะพ ะฟะพััะพะฒะพั ัะบัะธะฝัะบะธ"
-
-msgid "subject"
-msgstr "ัะตะผะฐ"
-
-msgid "snippet"
-msgstr "ััะฐะณะผะตะฝั"
-
-msgid "has unread"
-msgstr "ะผะฐั ะฝะตะฟัะพัะธัะฐะฝั"
-
-msgid "has trashed"
-msgstr "ั ะบะพัะธะบั"
-
-msgid "is trashed"
-msgstr "ั ะบะพัะธะบั"
-
-msgid "Whether all messages in the thread are trashed"
-msgstr "ะงะธ ะฒัั ะฟะพะฒัะดะพะผะปะตะฝะฝั ะฒ ะพะฑะณะพะฒะพัะตะฝะฝั ะฒะธะดะฐะปะตะฝั"
-
-msgid "has archived"
-msgstr "ะทะฐะฐัั
ัะฒะพะฒะฐะฝะพ"
-
-msgid "has draft"
-msgstr "ะผะฐั ัะตัะฝะตัะบั"
-
-msgid "has starred"
-msgstr "ะดะพะดะฐะฝะพ ะฒ ะพะฑัะฐะฝะต"
-
-msgid "has sender"
-msgstr "ะผะฐั ะฒัะดะฟัะฐะฒะฝะธะบะฐ"
-
-msgid "has messages"
-msgstr "ะผะฐั ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "has attachments"
-msgstr "ะผะฐั ะฒะบะปะฐะดะตะฝะฝั"
-
-msgid "is spam"
-msgstr "ั ัะฟะฐะผะพะผ"
-
-msgid "has active"
-msgstr "ะผะฐั ะฐะบัะธะฒะฝั"
-
-msgid "messaged at"
-msgstr "ะฒัะดะฟัะฐะฒะปะตะฝะต"
-
-msgid "sender names"
-msgstr "ัะผะตะฝะฐ ะฒัะดะฟัะฐะฒะฝะธะบะฐ"
-
-msgid "summary"
-msgstr "ะบะพัะพัะบะธะน ะทะผััั"
-
-msgid "thread"
-msgstr "ะพะฑะณะพะฒะพัะตะฝะฝั"
-
-msgid "threads"
-msgstr "ะพะฑะณะพะฒะพัะตะฝะฝั"
-
-msgid "Name of the label/folder (can use slashes for hierarchy, e.g. 'Work/Projects')"
-msgstr "ะะฐะทะฒะฐ ะผััะบะธ/ะฟะฐะฟะบะธ (ะผะพะถะต ะฒะธะบะพัะธััะพะฒัะฒะฐัะธ ะบะพัั ัะธัะบะธ ะดะปั ัััะฐัั
ัั, ะฝะฐะฟัะธะบะปะฐะด, 'ะ ะพะฑะพัะฐ/ะัะพะตะบัะธ')"
-
-msgid "slug"
-msgstr "ะฟัะตะฒะดะพะฝัะผ"
-
-msgid "URL-friendly version of the name"
-msgstr "URL-ะดััะถะฝั ะฒะตัััั ัะผะตะฝั ะปะฐัะธะฝะธัะตั"
-
-msgid "color"
-msgstr "ะบะพะปัั"
-
-msgid "Color of the label in hex format (e.g. #FF0000)"
-msgstr "ะะพะปัั ะผััะบะธ ั hex-ัะพัะผะฐัั (ะฝะฐะฟัะธะบะปะฐะด, #FF0000)"
-
-msgid "Mailbox that owns this label"
-msgstr "ะะพััะพะฒะฐ ัะบัะธะฝัะบะฐ, ัะพ ะผะฐั ัั ะผััะบั"
-
-msgid "Threads that have this label"
-msgstr "ะะฑะณะพะฒะพัะตะฝะฝั ะท ัััั ะผััะบะพั"
-
-msgid "description"
-msgstr "ะพะฟะธั"
-
-msgid "Description of the label, used by AI to understand its purpose"
-msgstr "ะะฟะธั ะผััะบะธ, ัะพ ะฒะธะบะพัะธััะพะฒัััััั ะจะ ะดะปั ัะพะทัะผัะฝะฝั ัั ะผะตัะธ"
-
-msgid "auto labeling"
-msgstr "ะฐะฒัะพะผะฐัะธัะฝะต ะฟะพะทะฝะฐัะตะฝะฝั"
-
-msgid "Whether this label should be automatically applied by AI"
-msgstr "ะงะธ ะฑัะดะต ัั ะผััะบะฐ ะฐะฒัะพะผะฐัะธัะฝะพ ะทะฐััะพัะพะฒะฐะฝะฐ ะจะ"
-
-msgid "label"
-msgstr "ะผััะบะฐ"
-
-msgid "labels"
-msgstr "ะผััะบะธ"
-
-msgid "thread access"
-msgstr "ะดะพัััะฟ ะดะพ ะพะฑะณะพะฒะพัะตะฝะฝั"
-
-msgid "thread accesses"
-msgstr "ะดะพัััะฟ ะดะพ ะพะฑะณะพะฒะพัะตะฝั"
-
-msgid "email"
-msgstr "ะตะป. ะฟะพััะฐ"
-
-msgid "contact"
-msgstr "ะบะพะฝัะฐะบั"
-
-msgid "contacts"
-msgstr "ะบะพะฝัะฐะบัะธ"
-
-msgid "delivered at"
-msgstr "ะดะพััะฐะฒะปะตะฝะพ"
-
-msgid "delivery message"
-msgstr "ะฟะพะฒัะดะพะผะปะตะฝะฝั ะฟัะพ ะดะพััะฐะฒะบั"
-
-msgid "retry count"
-msgstr "ัะธัะปะพ ะฟะพะฒัะพัะฝะธั
ัะฟัะพะฑ"
-
-msgid "retry at"
-msgstr "ะฟะพะฒัะพัะธัะธ"
-
-msgid "message recipient"
-msgstr "ะพะดะตัะถัะฒะฐั ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "message recipients"
-msgstr "ะพะดะตัะถัะฒะฐัั ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "is draft"
-msgstr "ัะตัะฝะตัะบะฐ"
-
-msgid "is sender"
-msgstr "ะฒัะดะฟัะฐะฒะฝะธะบ"
-
-msgid "is starred"
-msgstr "ะฟะพะทะฝะฐัะตะฝะพ ะทััะพัะบะพั"
-
-msgid "is unread"
-msgstr "ะฝะตะฟัะพัะธัะฐะฝะต"
-
-msgid "is archived"
-msgstr "ะฐัั
ัะฒะพะฒะฐะฝะพ"
-
-msgid "trashed at"
-msgstr "ั ะบะพัะธะบั"
-
-msgid "sent at"
-msgstr "ะฝะฐะดััะปะฐะฝะพ"
-
-msgid "read at"
-msgstr "ัะธัะฐัะธ"
-
-msgid "archived at"
-msgstr "ะฐัั
ัะฒะพะฒะฐะฝะพ"
-
-msgid "mime id"
-msgstr "mime id"
-
-msgid "Signature template for the message"
-msgstr "ะจะฐะฑะปะพะฝ ะฟัะดะฟะธัั ะดะปั ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "message"
-msgstr "ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "messages"
-msgstr "ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "No subject"
-msgstr "ะะตะท ัะตะผะธ"
-
-msgid "Message ID"
-msgstr "ID ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "From"
-msgstr "ะัะด"
-
-msgid "To"
-msgstr "ะะพะผั"
-
-msgid "CC"
-msgstr "ะัะธั
ะพะฒะฐะฝะฐ ะบะพะฟัั"
-
-msgid "Date"
-msgstr "ะะฐัะฐ"
-
-msgid "Subject"
-msgstr "ะขะตะผะฐ"
-
-msgid "Body"
-msgstr "ะะผััั"
-
-msgid "raw data"
-msgstr "ะฝะตะพะฑัะพะฑะปะตะฝั ะดะฐะฝั"
-
-msgid "Raw email message bytes"
-msgstr "ะะตะพะฑัะพะฑะปะตะฝั ะฑะฐะนัะธ ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "error message"
-msgstr "ะฟะพะฒัะดะพะผะปะตะฝะฝั ะฟัะพ ะฟะพะผะธะปะบั"
-
-msgid "Error message if processing failed"
-msgstr "ะะพะฒัะดะพะผะปะตะฝะฝั ะฟัะพ ะฟะพะผะธะปะบั, ัะบัะพ ะฝะต ะฒะดะฐะปะพัั ะพะฑัะพะฑะธัะธ"
-
-msgid "inbound message"
-msgstr "ะฒั
ัะดะฝะต ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "inbound messages"
-msgstr "ะฒั
ัะดะฝั ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "sha256 hash"
-msgstr "sha256 hash"
-
-msgid "SHA-256 hash of the uncompressed blob content"
-msgstr "ะะพะฝััะพะปัะฝั ััะผะธ SHA-256 ะฝะตััะธัะฝััะพะณะพ ะฒะผัััั"
-
-msgid "file size"
-msgstr "ัะพะทะผัั ัะฐะนะปั"
-
-msgid "Size of the blob in bytes"
-msgstr "ะ ะพะทะผัั ะฑะปะพะบั ะฒ ะฑะฐะนัะฐั
"
-
-msgid "compressed size"
-msgstr "ััะธัะฝััะธะน ัะพะทะผัั"
-
-msgid "Size of the compressed blob in bytes"
-msgstr "ะ ะพะทะผัั ััะธัะฝััะพะณะพ ะฑะปะพะบั ะฒ ะฑะฐะนัะฐั
"
-
-msgid "content type"
-msgstr "ัะธะฟ ะฒะผัััั"
-
-msgid "MIME type of the blob"
-msgstr "MIME-ัะธะฟ ะฑะปะพะบั"
-
-msgid "compression"
-msgstr "ััะธัะฝะตะฝะฝั"
-
-msgid "raw content"
-msgstr "ัะธัะธะน ะฒะผััั"
-
-msgid "Compressed binary content of the blob"
-msgstr "ะกัะธัะฝััะธะน ะฑัะฝะฐัะฝะธะน ะฒะผััั ะฑะปะพะบั"
-
-msgid "Mailbox that owns this blob"
-msgstr "ะะพััะพะฒะฐ ัะบัะธะฝัะบะฐ, ัะพ ะผะฐั ัะตะน ะฑะปะพะบ"
-
-msgid "Mail domain that owns this blob"
-msgstr "ะะพััะพะฒะธะน ะดะพะผะตะฝ, ัะพ ะผะฐั ัะตะน ะฑะปะพะบ"
-
-msgid "blob"
-msgstr "ะฑะปะพะบ"
-
-msgid "blobs"
-msgstr "ะฑะปะพะบะธ"
-
-msgid "file name"
-msgstr "ะฝะฐะทะฒะฐ ัะฐะนะปั"
-
-msgid "Original filename of the attachment"
-msgstr "ะัะธะณัะฝะฐะปัะฝะฐ ะฝะฐะทะฒะฐ ะฒะบะปะฐะดะตะฝะพะณะพ ัะฐะนะปั"
-
-msgid "Reference to the blob containing the attachment data"
-msgstr "ะะพัะธะปะฐะฝะฝั ะฝะฐ ะฑะปะพะบ, ัะพ ะผัััะธัั ะดะฐะฝั ะฒะบะปะฐะดะตะฝะฝั"
-
-msgid "Mailbox that owns this attachment"
-msgstr "ะะพััะพะฒะฐ ัะบัะธะฝัะบะฐ, ัะพ ะผะฐั ัะต ะฒะบะปะฐะดะตะฝะฝั"
-
-msgid "Messages that use this attachment"
-msgstr "ะะพะฒัะดะพะผะปะตะฝะฝั, ัะบั ะฒะธะบะพัะธััะพะฒัััั ัะต ะฒะบะปะฐะดะตะฝะฝั"
-
-msgid "content ID"
-msgstr "content ID"
-
-msgid "Content-ID for inline images"
-msgstr "Content-ID ะดะปั ะฒะฑัะดะพะฒะฐะฝะธั
ะทะพะฑัะฐะถะตะฝั"
-
-msgid "attachment"
-msgstr "ะฒะบะปะฐะดะตะฝะฝั"
-
-msgid "attachments"
-msgstr "ะฒะบะปะฐะดะตะฝะฝั"
-
-msgid "mail domain access"
-msgstr "ะดะพัััะฟ ะดะพ ะฟะพััะพะฒะพะณะพ ะดะพะผะตะฝั"
-
-msgid "mail domain accesses"
-msgstr "ะดะพัััะฟะธ ะดะพ ะฟะพััะพะฒะพะณะพ ะดะพะผะตะฝั"
-
-msgid "selector"
-msgstr "ัะตะปะตะบัะพั"
-
-msgid "DKIM selector (e.g., 'default', 'mail')"
-msgstr "DKIM ัะตะปะตะบัะพั (ะฝะฐะฟัะธะบะปะฐะด, 'default', 'mail')"
-
-msgid "private key"
-msgstr "ะฟัะธะฒะฐัะฝะธะน ะบะปัั"
-
-msgid "DKIM private key in PEM format (encrypted)"
-msgstr "ะัะธะฒะฐัะฝะธะน ะบะปัั DKIM ั ัะพัะผะฐัั PEM (ะทะฐัะธััะพะฒะฐะฝะธะน)"
-
-msgid "public key"
-msgstr "ะฒัะดะบัะธัะธะน ะบะปัั"
-
-msgid "DKIM public key for DNS record generation"
-msgstr "ะัะฑะปััะฝะธะน ะบะปัั DKIM ะดะปั ะณะตะฝะตัะฐััั ะทะฐะฟะธััะฒ DNS"
-
-msgid "algorithm"
-msgstr "ะฐะปะณะพัะธัะผ"
-
-msgid "DKIM signing algorithm"
-msgstr "ะะปะณะพัะธัะผ ะฟัะดะฟะธัั DKIM"
-
-msgid "key size"
-msgstr "ัะพะทะผัั ะบะปััะฐ"
-
-msgid "Key size in bits (e.g., 2048, 4096 for RSA)"
-msgstr "ะ ะพะทะผัั ะบะปััะฐ ั ะฑััะฐั
(ะฝะฐะฟัะธะบะปะฐะด, 2048, 4096 ะดะปั RSA)"
-
-msgid "is active"
-msgstr "ะฐะบัะธะฒะฝะธะน"
-
-msgid "Whether this DKIM key is active and should be used for signing"
-msgstr "ะงะธ ั ัะตะน ะบะปัั DKIM ะฐะบัะธะฒะฝะธะผ ั ะฟะพะฒะธะฝะตะฝ ะฒะธะบะพัะธััะพะฒัะฒะฐัะธัั ะดะปั ะฟัะดะฟะธัั"
-
-msgid "Domain that owns this DKIM key"
-msgstr "ะะพะผะตะฝ, ัะบะธะน ะฒะพะปะพะดัั ัะธะผ ะบะปััะตะผ DKIM"
-
-msgid "DKIM key"
-msgstr "ะะปัั DKIM"
-
-msgid "DKIM keys"
-msgstr "ะะปััั DKIM"
-
-msgid "Name of the template (e.g., 'Standard Reply', 'Out of Office', 'Work Signature')"
-msgstr "ะะฐะทะฒะฐ ัะฐะฑะปะพะฝั (ะฝะฐะฟัะธะบะปะฐะด, 'ะกัะฐะฝะดะฐััะฝะฐ ะฒัะดะฟะพะฒัะดั', 'ะะต ะฒ ะพัััั', 'ะัะดะฟะธั ัะพะฑะพัะธ')"
-
-msgid "Reference to the blob containing template content as JSON: {html: str, text: str, raw: any}"
-msgstr "ะะพัะธะปะฐะฝะฝั ะฝะฐ ะฑะปะพะบ, ัะพ ะผัััะธัั ะฒะผััั ัะฐะฑะปะพะฝั ะฒ ัะพัะผะฐัั JSON: {html: str, text: str, raw: any}"
-
-msgid "Type of template (message, signature)"
-msgstr "ะขะธะฟ ัะฐะฑะปะพะฝั (ะฟะพะฒัะดะพะผะปะตะฝะฝั, ะฟัะดะฟะธั)"
-
-msgid "Whether this template is available for use"
-msgstr "ะงะธ ะดะพัััะฟะฝะธะน ัะตะน ัะฐะฑะปะพะฝ ะดะปั ะฒะธะบะพัะธััะฐะฝะฝั"
-
-msgid "Mail domain that can use this template"
-msgstr "ะะพััะพะฒะธะน ะดะพะผะตะฝ, ัะบะธะน ะผะพะถะต ะฒะธะบะพัะธััะพะฒัะฒะฐัะธ ัะตะน ัะฐะฑะปะพะฝ"
-
-msgid "Mailbox that can use this template"
-msgstr "ะะพััะพะฒะฐ ัะบัะธะฝัะบะฐ, ัะพ ะผะพะถะต ะฒะธะบะพัะธััะพะฒัะฒะฐัะธ ัะตะน ัะฐะฑะปะพะฝ"
-
-msgid "is forced"
-msgstr "ะพะฑะพะฒ'ัะทะบะพะฒะธะน"
-
-msgid "Whether this template is forced; no other template of the same type can be used in the same scope"
-msgstr "ะงะธ ั ัะตะน ัะฐะฑะปะพะฝ ะพะฑะพะฒ'ัะทะบะพะฒะธะผ; ะถะพะดะตะฝ ัะฝัะธะน ัะฐะฑะปะพะฝ ัะพะณะพ ะถ ัะธะฟั ะฝะต ะผะพะถะต ะฒะธะบะพัะธััะพะฒัะฒะฐัะธัั ะฒ ััะน ะถะต ะพะฑะปะฐััั"
-
-msgid "is default"
-msgstr "ะทะฐ ะทะฐะผะพะฒััะฒะฐะฝะฝัะผ"
-
-msgid "Whether this template is the default; it will be automatically loaded when composing a new message"
-msgstr "ะงะธ ั ัะตะน ัะฐะฑะปะพะฝ ะทะฐ ะทะฐะผะพะฒััะฒะฐะฝะฝัะผ; ะฒัะฝ ะฑัะดะต ะฐะฒัะพะผะฐัะธัะฝะพ ะทะฐะฒะฐะฝัะฐะถะตะฝะธะน ะฟัะด ัะฐั ะดะพะดะฐะฝะฝั ะฝะพะฒะพะณะพ ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "message template"
-msgstr "ัะฐะฑะปะพะฝ ะฟะพะฒัะดะพะผะปะตะฝะฝั"
-
-msgid "message templates"
-msgstr "ัะฐะฑะปะพะฝะธ ะฟะพะฒัะดะพะผะปะตะฝั"
-
-msgid "Provision DNS records"
-msgstr "ะะฐะปะฐัััะฒะฐะฝะฝั ะทะฐะฟะธััะฒ DNS"
-
-msgid "Retry to send to pending recipients"
-msgstr "ะะพะฒัะพัะธัะธ ัะฟัะพะฑั ะฝะฐะดัะธะปะฐะฝะฝั ะดะพ ะพััะบัััะธั
ะพััะธะผัะฒะฐััะฒ"
-
-msgid "Import from IMAP"
-msgstr "ะะผะฟะพัั ะท IMAP"
-
-msgid "Home"
-msgstr "ะะพะปะพะฒะฝะฐ"
-
-msgid "Please correct the error below."
-msgstr "ะัะดั ะปะฐัะบะฐ, ะฒะธะฟัะฐะฒัะต ะฟะพะผะธะปะบั, ัะพ ะฒะบะฐะทะฐะฝะฐ ะฝะธะถัะต."
-
-msgid "Please correct the errors below."
-msgstr "ะัะดั ะปะฐัะบะฐ, ะฒะธะฟัะฐะฒัะต ะฟะพะผะธะปะบะธ, ัะพ ะฒะบะฐะทะฐะฝั ะฝะธะถัะต."
-
-msgid "Start Import"
-msgstr "ะะพัะฐัะธ ัะผะฟะพัั"
-
-msgid "English"
-msgstr "ะะฝะณะปัะนััะบะฐ"
-
-msgid "French"
-msgstr "ะคัะฐะฝััะทัะบะฐ"
-
-msgid "Dutch"
-msgstr "ะัะดะตัะปะฐะฝะดััะบะฐ"
-
diff --git a/src/backend/messages/settings.py b/src/backend/messages/settings.py
index 57740944..2730edfa 100755
--- a/src/backend/messages/settings.py
+++ b/src/backend/messages/settings.py
@@ -16,8 +16,6 @@ import os
import tomllib
from socket import gethostbyname, gethostname
-from django.utils.translation import gettext_lazy as _
-
import dj_database_url
import sentry_sdk
from configurations import Configuration, values
@@ -459,8 +457,6 @@ class Base(Configuration):
# Languages
LANGUAGE_CODE = values.Value("en-us")
- LANGUAGE_COOKIE_NAME = "messages_language" # cookie & language is set from frontend
-
DRF_NESTED_MULTIPART_PARSER = {
# output of parser is converted to querydict
# if is set to False, dict python is returned
@@ -471,16 +467,14 @@ class Base(Configuration):
# fallback/default languages throughout the app.
LANGUAGES = values.SingleNestedTupleValue(
(
- ("en-us", _("English")),
- ("fr-fr", _("French")),
- ("nl-nl", _("Dutch")),
+ ("en-us", "English"),
+ ("fr-fr", "French"),
+ ("nl-nl", "Dutch"),
)
)
- LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),)
-
TIME_ZONE = "UTC"
- USE_I18N = True
+ USE_I18N = False
USE_TZ = True
# Templates
@@ -494,7 +488,6 @@ class Base(Configuration):
"django.contrib.messages.context_processors.messages",
"django.template.context_processors.csrf",
"django.template.context_processors.debug",
- "django.template.context_processors.i18n",
"django.template.context_processors.media",
"django.template.context_processors.request",
"django.template.context_processors.tz",
@@ -511,7 +504,6 @@ class Base(Configuration):
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
- "django.middleware.locale.LocaleMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"core.middlewares.CustomCorsMiddleware",
"django.middleware.common.CommonMiddleware",
@@ -1004,20 +996,6 @@ class Base(Configuration):
"""
return get_release()
- # pylint: disable=invalid-name
- @property
- def PARLER_LANGUAGES(self):
- """
- Return languages for Parler computed from the LANGUAGES and LANGUAGE_CODE settings.
- """
- return {
- self.SITE_ID: tuple({"code": code} for code, _name in self.LANGUAGES),
- "default": {
- "fallbacks": [self.LANGUAGE_CODE],
- "hide_untranslated": False,
- },
- }
-
@classmethod
def post_setup(cls):
"""Post setup configuration.
diff --git a/src/backend/pyproject.toml b/src/backend/pyproject.toml
index 47f92d92..15381c93 100644
--- a/src/backend/pyproject.toml
+++ b/src/backend/pyproject.toml
@@ -22,50 +22,50 @@ license = "MIT"
readme = "README.md"
requires-python = ">=3.13,<4.0"
-# Note: after changing this list you must re-run `make uv-lock-back`
+# Note: after changing this list you must re-run `make deps-lock-back`
dependencies = [
- "boto3==1.40.43",
- "botocore==1.40.43",
- "celery[redis]==5.5.2",
+ "boto3==1.42.53",
+ "botocore==1.42.53",
+ "celery[redis]==5.6.2",
"cryptography==46.0.5",
- "dj-database-url==2.3.0",
- "django==5.1.15",
- "django-celery-beat==2.8.0",
+ "dj-database-url==3.1.2",
+ "django==5.2.11",
+ "django-celery-beat==2.8.1",
"django-celery-results==2.6.0",
"django-configurations==2.5.1",
- "django-cors-headers==4.6.0",
- "django-countries==7.6.1",
- "django-fernet-encrypted-fields==0.3.0",
- "django-filter==24.3",
+ "django-cors-headers==4.9.0",
+ "django-countries==8.2.0",
+ "django-fernet-encrypted-fields==0.3.1",
+ "django-filter==25.2",
"django-lasuite[all]==0.0.24",
"django-prometheus==2.4.1",
- "django-redis==5.4.0",
+ "django-redis==6.0.0",
"django-storages==1.14.6",
- "django-timezone-field==7.1",
- "djangorestframework==3.15.2",
+ "django-timezone-field==7.2.1",
+ "djangorestframework==3.16.1",
"dkimpy==1.1.8",
- "dnspython==2.7.0",
- "drf_spectacular==0.28.0",
+ "dnspython==2.8.0",
+ "drf_spectacular==0.29.0",
"opensearch-py==2.8.0",
- "factory_boy==3.3.1",
+ "factory_boy==3.3.3",
"flanker@git+https://github.com/sylvinus/flanker@f94ba2c15ab310e333610a78828d09be4e11a6b6",
- "gunicorn==23.0.0",
- "jsonschema==4.25.0",
- "nested-multipart-parser==1.5.0",
- "openai==1.93.0",
+ "gunicorn==25.1.0",
+ "jsonschema==4.26.0",
+ "nested-multipart-parser==1.6.0",
+ "openai==2.21.0",
"psycopg[binary]==3.3.3",
- "PyJWT==2.10.1",
+ "PyJWT==2.11.0",
"PySocks==1.7.1",
"python-keycloak==5.5.1",
"python-magic==0.4.27",
- "pyzstd==0.17.0",
- "redis==5.2.1",
+ "pyzstd==0.19.1",
+ "redis==6.4.0",
"requests==2.32.5",
- "sentry-sdk[django]==2.27.0",
+ "sentry-sdk[django]==2.53.0",
"libpff-python==20231205",
- "url-normalize==1.4.3",
- "whitenoise==6.8.2",
- "prometheus-client==0.22.1",
+ "url-normalize==2.2.1",
+ "whitenoise==6.11.0",
+ "prometheus-client==0.24.1",
]
[project.urls]
@@ -76,22 +76,22 @@ dependencies = [
[project.optional-dependencies]
dev = [
- "django-extensions==3.2.3",
- "drf-spectacular-sidecar==2024.12.1",
+ "django-extensions==4.1",
+ "drf-spectacular-sidecar==2026.1.1",
"flower==2.0.1",
- "hypothesis==6.131.1",
- "pip-audit==2.9.0",
- "pipdeptree==2.28.0",
- "pylint-django==2.6.1",
- "pylint==3.3.4",
- "pytest-cov==6.0.0",
- "pytest-django==4.9.0",
- "pytest==8.3.4",
+ "hypothesis==6.151.9",
+ "pip-audit==2.10.0",
+ "pipdeptree==2.31.0",
+ "pylint-django==2.7.0",
+ "pylint==4.0.4",
+ "pytest-cov==7.0.0",
+ "pytest-django==4.12.0",
+ "pytest==9.0.2",
"pytest-icdiff==0.9",
"pytest-repeat==0.9.4",
- "pytest-xdist==3.6.1",
- "responses==0.25.6",
- "ruff==0.9.3"
+ "pytest-xdist==3.8.0",
+ "responses==0.26.0",
+ "ruff==0.15.2"
]
[build-system]
@@ -115,7 +115,7 @@ exclude = [
line-length = 88
[tool.ruff.lint]
-ignore = ["DJ001", "PLR2004", "PLR0915", "PLR0912", "PLR0913", "PLR0911", "BLE001"]
+ignore = ["DJ001", "PLC0415", "PLR2004", "PLR0915", "PLR0912", "PLR0913", "PLR0911", "BLE001"]
select = [
"B", # flake8-bugbear
"BLE", # flake8-blind-except
@@ -137,6 +137,7 @@ select = [
[tool.ruff.lint.isort]
section-order = ["future","standard-library","django","third-party","messages","first-party","local-folder"]
sections = { messages=["core"], django=["django"] }
+known-third-party = ["dns"]
extra-standard-library = ["tomllib"]
[tool.ruff.lint.per-file-ignores]
diff --git a/src/backend/uv.lock b/src/backend/uv.lock
index 713d0601..d1705834 100644
--- a/src/backend/uv.lock
+++ b/src/backend/uv.lock
@@ -55,11 +55,11 @@ wheels = [
[[package]]
name = "astroid"
-version = "3.3.11"
+version = "4.0.4"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/18/74/dfb75f9ccd592bbedb175d4a32fc643cf569d7c218508bfbd6ea7ef9c091/astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce", size = 400439, upload-time = "2025-07-13T18:04:23.177Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/07/63/0adf26577da5eff6eb7a177876c1cfa213856be9926a000f65c4add9692b/astroid-4.0.4.tar.gz", hash = "sha256:986fed8bcf79fb82c78b18a53352a0b287a73817d6dbcfba3162da36667c49a0", size = 406358, upload-time = "2026-02-07T23:35:07.509Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/af/0f/3b8fdc946b4d9cc8cc1e8af42c4e409468c84441b933d037e101b3d72d86/astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec", size = 275612, upload-time = "2025-07-13T18:04:21.07Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/cf/1c5f42b110e57bc5502eb80dbc3b03d256926062519224835ef08134f1f9/astroid-4.0.4-py3-none-any.whl", hash = "sha256:52f39653876c7dec3e3afd4c2696920e05c83832b9737afc21928f2d2eb7a753", size = 276445, upload-time = "2026-02-07T23:35:05.344Z" },
]
[[package]]
@@ -80,6 +80,48 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
]
+[[package]]
+name = "backports-zstd"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/36a5182ce1d8ef9ef32bff69037bd28b389bbdb66338f8069e61da7028cb/backports_zstd-1.3.0.tar.gz", hash = "sha256:e8b2d68e2812f5c9970cabc5e21da8b409b5ed04e79b4585dbffa33e9b45ebe2", size = 997138, upload-time = "2025-12-29T17:28:06.143Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/0c/7d/53e8da5950cdfc5e8fe23efd5165ce2f4fed5222f9a3292e0cdb03dd8c0d/backports_zstd-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e86e03e3661900955f01afed6c59cae9baa63574e3b66896d99b7de97eaffce9", size = 435463, upload-time = "2025-12-29T17:26:42.152Z" },
+ { url = "https://files.pythonhosted.org/packages/da/78/f98e53870f7404071a41e3d04f2ff514302eeeb3279d931d02b220f437aa/backports_zstd-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41974dcacc9824c1effe1c8d2f9d762bcf47d265ca4581a3c63321c7b06c61f0", size = 361740, upload-time = "2025-12-29T17:26:43.377Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/ed/2c64706205a944c9c346d95c17f632d4e3468db3ce60efb6f5caa7c0dcae/backports_zstd-1.3.0-cp313-cp313-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:3090a97738d6ce9545d3ca5446df43370928092a962cbc0153e5445a947e98ed", size = 505651, upload-time = "2025-12-29T17:26:44.495Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/7b/22998f691dc6e0c7e6fa81d611eb4b1f6a72fb27327f322366d4a7ca8fb3/backports_zstd-1.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ddc874638abf03ea1ff3b0525b4a26a8d0adf7cb46a448c3449f08e4abc276b3", size = 475859, upload-time = "2025-12-29T17:26:45.722Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/78/0cde898339a339530e5f932634872d2d64549969535447a48d3b98959e11/backports_zstd-1.3.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:db609e57b8ed88b3472930c87e93c08a4bbd5ffeb94608cd9c7c6f0ac0e166c6", size = 581339, upload-time = "2025-12-29T17:26:46.93Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/1d/e0973e0eebe678c12c146473af2c54cda8a3e63b179785ca1a20727ad69c/backports_zstd-1.3.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5f13033a3dd95f323c067199f2e61b4589a7880188ef4ef356c7ffbdb78a9f11", size = 642182, upload-time = "2025-12-29T17:26:48.545Z" },
+ { url = "https://files.pythonhosted.org/packages/82/a2/ac67e79e137eb98aead66c7162bafe3cffcb82ef9cdeb6367ec18d88fbce/backports_zstd-1.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c4c7bcda5619a754726e7f5b391827f5efbe4bed8e62e9ec7490d42bff18aa6", size = 490807, upload-time = "2025-12-29T17:26:49.789Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/e9/3514b1d065801ae7dce05246e9389003ed8fb1d7c3d71f85aa07a80f41e6/backports_zstd-1.3.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:884a94c40f27affe986f394f219a4fd3cbbd08e1cff2e028d29d467574cd266e", size = 566103, upload-time = "2025-12-29T17:26:51.062Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/03/10ddb54cbf032e5fe390c0776d3392611b1fc772d6c3cb5a9bcdff4f915f/backports_zstd-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497f5765126f11a5b3fd8fedfdae0166d1dd867e7179b8148370a3313d047197", size = 481614, upload-time = "2025-12-29T17:26:52.255Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/13/21efa7f94c41447f43aee1563b05fc540a235e61bce4597754f6c11c2e97/backports_zstd-1.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a6ff6769948bb29bba07e1c2e8582d5a9765192a366108e42d6581a458475881", size = 509207, upload-time = "2025-12-29T17:26:53.496Z" },
+ { url = "https://files.pythonhosted.org/packages/de/e7/12da9256d9e49e71030f0ff75e9f7c258e76091a4eaf5b5f414409be6a57/backports_zstd-1.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1623e5bff1acd9c8ef90d24fc548110f20df2d14432bfe5de59e76fc036824ef", size = 585765, upload-time = "2025-12-29T17:26:54.99Z" },
+ { url = "https://files.pythonhosted.org/packages/24/bf/59ca9cb4e7be1e59331bb792e8ef1331828efe596b1a2f8cbbc4e3f70d75/backports_zstd-1.3.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:622c28306dcc429c8f2057fc4421d5722b1f22968d299025b35d71b50cfd4e03", size = 563852, upload-time = "2025-12-29T17:26:56.371Z" },
+ { url = "https://files.pythonhosted.org/packages/7c/ee/5a3eaed9a73bdf2c35dc0c7adc0616a99588e0de28f5ab52f3e0caaaa96f/backports_zstd-1.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09a2785e410ed2e812cb39b684ef5eb55083a5897bfd0e6f5de3bbd2c6345f70", size = 632549, upload-time = "2025-12-29T17:26:57.598Z" },
+ { url = "https://files.pythonhosted.org/packages/75/b9/c823633afc48a1ac56d6ad34289c8f51b0234685142531bfa8197ca91777/backports_zstd-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ade1f4127fdbe36a02f8067d75aa79c1ea1c8a306bf63c7b818bb7b530e1beaa", size = 495104, upload-time = "2025-12-29T17:26:58.826Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/8f/6f7030f18fa7307f87b0f57108a50a3a540b6350e2486d1739c0567629a3/backports_zstd-1.3.0-cp313-cp313-win32.whl", hash = "sha256:668e6fb1805b825cb7504c71436f7b28d4d792bb2663ee901ec9a2bb15804437", size = 288447, upload-time = "2025-12-29T17:27:00.036Z" },
+ { url = "https://files.pythonhosted.org/packages/a2/82/b1df1bbbe4e6d3ffd364d0bcffdeb6c4361115c1eccd91238dbdd0c07fec/backports_zstd-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:385bdadf0ea8fe6ba780a95e4c7d7f018db7bafdd630932f0f9f0fad05d608ff", size = 313664, upload-time = "2025-12-29T17:27:01.267Z" },
+ { url = "https://files.pythonhosted.org/packages/45/0f/60918fe4d3f2881de8f4088d73be4837df9e4c6567594109d355a2d548b6/backports_zstd-1.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:4321a8a367537224b3559fe7aeb8012b98aea2a60a737e59e51d86e2e856fe0a", size = 288678, upload-time = "2025-12-29T17:27:02.506Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/b9/35f423c0bcd85020d5e7be6ab8d7517843e3e4441071beb5c3bd8c5216cb/backports_zstd-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:10057d66fa4f0a7d3f6419ffb84b4fe61088da572e3ac4446134a1c8089e4166", size = 436155, upload-time = "2025-12-29T17:27:03.859Z" },
+ { url = "https://files.pythonhosted.org/packages/f6/14/e504daea24e8916f14ecbc223c354b558d8410cfc846606668ab91d96b38/backports_zstd-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4abf29d706ba05f658ca0247eb55675bcc00e10f12bca15736e45b05f1f2d2dc", size = 362436, upload-time = "2025-12-29T17:27:05.076Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/f7/06e178dbab7edb88c2872aebd68b54137e07a169eba1aeedf614014f7036/backports_zstd-1.3.0-cp313-cp313t-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:127b0d73c745b0684da3d95c31c0939570810dad8967dfe8231eea8f0e047b2f", size = 507600, upload-time = "2025-12-29T17:27:06.254Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/f1/2ce499b81c4389d6fa1eeea7e76f6e0bad48effdbb239da7cbcdaaf24b76/backports_zstd-1.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0205ef809fb38bb5ca7f59fa03993596f918768b9378fb7fbd8a68889a6ce028", size = 475496, upload-time = "2025-12-29T17:27:07.939Z" },
+ { url = "https://files.pythonhosted.org/packages/18/1e/c82a586f2866aabf3a601a521af3c58756d83d98b724fda200016ac5e7e2/backports_zstd-1.3.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1c389b667b0b07915781aa28beabf2481f11a6062a1a081873c4c443b98601a7", size = 580919, upload-time = "2025-12-29T17:27:09.1Z" },
+ { url = "https://files.pythonhosted.org/packages/1b/a3/eb5d9b7c4cb69d1b8ccd011abe244ba6815693b70bed07ed4b77ddda4535/backports_zstd-1.3.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8e7ac5ef693d49d6fb35cd7bbb98c4762cfea94a8bd2bf2ab112027004f70b11", size = 639913, upload-time = "2025-12-29T17:27:10.433Z" },
+ { url = "https://files.pythonhosted.org/packages/11/2c/7296b99df79d9f31174a99c81c1964a32de8996ce2b3068f5bc66b413615/backports_zstd-1.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d5543945aae2a76a850b23f283249424f535de6a622d6002957b7d971e6a36d", size = 494800, upload-time = "2025-12-29T17:27:11.59Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/fc/b8ae6e104ba72d20cd5f9dfd9baee36675e89c81d432434927967114f30f/backports_zstd-1.3.0-cp313-cp313t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e38be15ebce82737deda2c9410c1f942f1df9da74121049243a009810432db75", size = 570396, upload-time = "2025-12-29T17:27:13.063Z" },
+ { url = "https://files.pythonhosted.org/packages/30/56/60a7a9de7a5bc951ea1106358b413c95183c93480394f3abc541313c8679/backports_zstd-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3e3f58c76f4730607a4e0130d629173aa114ae72a5c8d3d5ad94e1bf51f18d8", size = 481980, upload-time = "2025-12-29T17:27:14.317Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/bb/93fc1e8e81b8ecba58b0e53a14f7b44375cf837db6354410998f0c4cb6ff/backports_zstd-1.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:b808bf889722d889b792f7894e19c1f904bb0e9092d8c0eb0787b939b08bad9a", size = 511358, upload-time = "2025-12-29T17:27:15.669Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/0f/b165c2a6080d22306975cd86ce97270208493f31a298867e343110570370/backports_zstd-1.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f7be27d56f2f715bcd252d0c65c232146d8e1e039c7e2835b8a3ad3dc88bc508", size = 585492, upload-time = "2025-12-29T17:27:16.986Z" },
+ { url = "https://files.pythonhosted.org/packages/26/76/85b4bde76e982b24a7eb57a2fb9868807887bef4d2114a3654a6530a67ef/backports_zstd-1.3.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:cbe341c7fcc723893663a37175ba859328b907a4e6d2d40a4c26629cc55efb67", size = 568309, upload-time = "2025-12-29T17:27:18.28Z" },
+ { url = "https://files.pythonhosted.org/packages/83/64/9490667827a320766fb883f358a7c19171fdc04f19ade156a8c341c36967/backports_zstd-1.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:b4116a9e12dfcd834dd9132cf6a94657bf0d328cba5b295f26de26ea0ae1adc8", size = 630518, upload-time = "2025-12-29T17:27:19.525Z" },
+ { url = "https://files.pythonhosted.org/packages/ea/43/258587233b728bbff457bdb0c52b3e08504c485a8642b3daeb0bdd5a76bc/backports_zstd-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1049e804cc8754290b24dab383d4d6ed0b7f794ad8338813ddcb3907d15a89d0", size = 499429, upload-time = "2025-12-29T17:27:21.063Z" },
+ { url = "https://files.pythonhosted.org/packages/32/04/cfab76878f360f124dbb533779e1e4603c801a0f5ada72ae5c742b7c4d7d/backports_zstd-1.3.0-cp313-cp313t-win32.whl", hash = "sha256:7d3f0f2499d2049ec53d2674c605a4b3052c217cc7ee49c05258046411685adc", size = 289389, upload-time = "2025-12-29T17:27:22.287Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/ff/dbcfb6c9c922ab6d98f3d321e7d0c7b34ecfa26f3ca71d930fe1ef639737/backports_zstd-1.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:eb2f8fab0b1ea05148394cb34a9e543a43477178765f2d6e7c84ed332e34935e", size = 314776, upload-time = "2025-12-29T17:27:23.458Z" },
+ { url = "https://files.pythonhosted.org/packages/01/4b/82e4baae3117806639fe1c693b1f2f7e6133a7cefd1fa2e38018c8edcd68/backports_zstd-1.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c66ad9eb5bfbe28c2387b7fc58ddcdecfb336d6e4e60bcba1694a906c1f21a6c", size = 289315, upload-time = "2025-12-29T17:27:24.601Z" },
+]
+
[[package]]
name = "billiard"
version = "4.2.4"
@@ -100,30 +142,30 @@ wheels = [
[[package]]
name = "boto3"
-version = "1.40.43"
+version = "1.42.53"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
{ name = "jmespath" },
{ name = "s3transfer" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/1e/43/0ef93cd27a8e753e66d93d7b94f686315384ab6cd63f065a14a4a6c9ee20/boto3-1.40.43.tar.gz", hash = "sha256:9ad9190672ce8736898bec2d94875aea6ae1ead2ac6d158e01d820f3ff9c23e0", size = 111552, upload-time = "2025-10-01T19:38:26.089Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/62/ef/03460914019db52301a6084460f0dd738f3f9e89d2ddf5bd33cef8168e63/boto3-1.42.53.tar.gz", hash = "sha256:56bc79388763995852b6d3fe48023e661e63fc2e60a921273c422d0171b9fbfb", size = 112812, upload-time = "2026-02-19T20:33:58.422Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f5/86/377e2b9aeddfdb7468223c7b48e29a1697b86c200c44916ddfb8dae05a68/boto3-1.40.43-py3-none-any.whl", hash = "sha256:c5d64ba2fb2d90c33c3969f3751869c45746d5efb5136e4cc619e3630ece89a3", size = 139344, upload-time = "2025-10-01T19:38:25Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/ea/08dfba25a5822a7254b20aa905a9937177ca1532dd7f47c926875dd87299/boto3-1.42.53-py3-none-any.whl", hash = "sha256:3bd32f3508a6e9851671d0ef3b1f9e8ee7e8c095aa0488bcd9e86074aef5b7eb", size = 140555, upload-time = "2026-02-19T20:33:55.691Z" },
]
[[package]]
name = "botocore"
-version = "1.40.43"
+version = "1.42.53"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jmespath" },
{ name = "python-dateutil" },
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/49/d0/3888673417202262ddd7e6361cab8e01ee2705e39643af8445e2eb276eab/botocore-1.40.43.tar.gz", hash = "sha256:d87412dc1ea785df156f412627d3417c9f9eb45601fd0846d8fe96fe3c78b630", size = 14389164, upload-time = "2025-10-01T19:38:16.06Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/7a/b6/0b2ab38e422e93f28b7a394a29881a9d767b79831fa1957a3ccab996a70e/botocore-1.42.53.tar.gz", hash = "sha256:0bc1a2e1b6ae4c8397c9bede3bb9007b4f16e159ef2ca7f24837e31d5860caac", size = 14918644, upload-time = "2026-02-19T20:33:44.814Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/79/46/2eb4802e15e38befbea6cab7dafa1ab796722ab6f0833991c2a05e9f8ef0/botocore-1.40.43-py3-none-any.whl", hash = "sha256:1639f38999fc0cf42c92c5c83c5fbe189a4857a86f55b842be868e3283c6d3bb", size = 14057986, upload-time = "2025-10-01T19:38:13.714Z" },
+ { url = "https://files.pythonhosted.org/packages/25/dc/cf3b2ec4a419b20d2cd6ba8e1961bc59b7ec9801339628e31551dac23801/botocore-1.42.53-py3-none-any.whl", hash = "sha256:1255db56bc0a284a8caa182c20966277e6c8871b6881cf816d40e993fa5da503", size = 14589472, upload-time = "2026-02-19T20:33:40.377Z" },
]
[[package]]
@@ -146,7 +188,7 @@ filecache = [
[[package]]
name = "celery"
-version = "5.5.2"
+version = "5.6.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "billiard" },
@@ -156,16 +198,17 @@ dependencies = [
{ name = "click-repl" },
{ name = "kombu" },
{ name = "python-dateutil" },
+ { name = "tzlocal" },
{ name = "vine" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/bf/03/5d9c6c449248958f1a5870e633a29d7419ff3724c452a98ffd22688a1a6a/celery-5.5.2.tar.gz", hash = "sha256:4d6930f354f9d29295425d7a37261245c74a32807c45d764bedc286afd0e724e", size = 1666892, upload-time = "2025-04-25T20:10:04.695Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/8f/9d/3d13596519cfa7207a6f9834f4b082554845eb3cd2684b5f8535d50c7c44/celery-5.6.2.tar.gz", hash = "sha256:4a8921c3fcf2ad76317d3b29020772103581ed2454c4c042cc55dcc43585009b", size = 1718802, upload-time = "2026-01-04T12:35:58.012Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/04/94/8e825ac1cf59d45d20c4345d4461e6b5263ae475f708d047c3dad0ac6401/celery-5.5.2-py3-none-any.whl", hash = "sha256:54425a067afdc88b57cd8d94ed4af2ffaf13ab8c7680041ac2c4ac44357bdf4c", size = 438626, upload-time = "2025-04-25T20:10:01.383Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/bd/9ecd619e456ae4ba73b6583cc313f26152afae13e9a82ac4fe7f8856bfd1/celery-5.6.2-py3-none-any.whl", hash = "sha256:3ffafacbe056951b629c7abcf9064c4a2366de0bdfc9fdba421b97ebb68619a5", size = 445502, upload-time = "2026-01-04T12:35:55.894Z" },
]
[package.optional-dependencies]
redis = [
- { name = "redis" },
+ { name = "kombu", extra = ["redis"] },
]
[[package]]
@@ -520,34 +563,33 @@ wheels = [
[[package]]
name = "dj-database-url"
-version = "2.3.0"
+version = "3.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
- { name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/98/9f/fc9905758256af4f68a55da94ab78a13e7775074edfdcaddd757d4921686/dj_database_url-2.3.0.tar.gz", hash = "sha256:ae52e8e634186b57e5a45e445da5dc407a819c2ceed8a53d1fac004cc5288787", size = 10980, upload-time = "2024-10-23T10:05:19.953Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/03/f6/00b625e9d371b980aa261011d0dc906a16444cb688f94215e0dc86996eb5/dj_database_url-3.1.2.tar.gz", hash = "sha256:63c20e4bbaa51690dfd4c8d189521f6bf6bc9da9fcdb23d95d2ee8ee87f9ec62", size = 11490, upload-time = "2026-02-19T15:30:23.638Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e5/91/641a4e5c8903ed59f6cbcce571003bba9c5d2f731759c31db0ba83bb0bdb/dj_database_url-2.3.0-py3-none-any.whl", hash = "sha256:bb0d414ba0ac5cd62773ec7f86f8cc378a9dbb00a80884c2fc08cc570452521e", size = 7793, upload-time = "2024-10-23T10:05:41.254Z" },
+ { url = "https://files.pythonhosted.org/packages/cf/a9/57c66006373381f1d3e5bd94216f1d371228a89f443d3030e010f73dd198/dj_database_url-3.1.2-py3-none-any.whl", hash = "sha256:544e015fee3efa5127a1eb1cca465f4ace578265b3671fe61d0ed7dbafb5ec8a", size = 8953, upload-time = "2026-02-19T15:30:39.37Z" },
]
[[package]]
name = "django"
-version = "5.1.15"
+version = "5.2.11"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "sqlparse" },
{ name = "tzdata", marker = "sys_platform == 'win32'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/10/45/1ac68964193cfcc0b0912a0f68025d5bdb54f71ba7b8716e85b959874bd0/django-5.1.15.tar.gz", hash = "sha256:46a356b5ff867bece73fc6365e081f21c569973403ee7e9b9a0316f27d0eb947", size = 10719662, upload-time = "2025-12-02T14:01:31.931Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/17/f2/3e57ef696b95067e05ae206171e47a8e53b9c84eec56198671ef9eaa51a6/django-5.2.11.tar.gz", hash = "sha256:7f2d292ad8b9ee35e405d965fbbad293758b858c34bbf7f3df551aeeac6f02d3", size = 10885017, upload-time = "2026-02-03T13:52:50.554Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/27/79/372e091f0eba4ddb8228245ccd1baaa140e9658711f5e3a0056e540b4c1e/django-5.1.15-py3-none-any.whl", hash = "sha256:117871e58d6eda37f09870b7d73a3d66567b03aecd515b386b1751177c413432", size = 8260901, upload-time = "2025-12-02T14:01:27.352Z" },
+ { url = "https://files.pythonhosted.org/packages/91/a7/2b112ab430575bf3135b8304ac372248500d99c352f777485f53fdb9537e/django-5.2.11-py3-none-any.whl", hash = "sha256:e7130df33ada9ab5e5e929bc19346a20fe383f5454acb2cc004508f242ee92c0", size = 8291375, upload-time = "2026-02-03T13:52:42.47Z" },
]
[[package]]
name = "django-celery-beat"
-version = "2.8.0"
+version = "2.8.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "celery" },
@@ -557,9 +599,9 @@ dependencies = [
{ name = "python-crontab" },
{ name = "tzdata" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/d5/c8/f29ec081372fb1d800933a3effebbd19b97a93be27a88a5ab100f01babc2/django_celery_beat-2.8.0.tar.gz", hash = "sha256:955bfb3c4b8f1026a8d20144d0da39c941e1eb23acbaee9e12a7e7cc1f74959a", size = 172052, upload-time = "2025-04-16T07:15:40.122Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/aa/11/0c8b412869b4fda72828572068312b10aafe7ccef7b41af3633af31f9d4b/django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a", size = 175802, upload-time = "2025-05-13T06:58:29.246Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/2e/d6/d83c9664b03f41281a0ae975756ce23fb8da7c6844f400f2d13c840ea941/django_celery_beat-2.8.0-py3-none-any.whl", hash = "sha256:f8fd2e1ffbfa8e570ab9439383b2cd15a6642b347662d0de79c62ba6f68d4b38", size = 103583, upload-time = "2025-04-16T07:15:38.196Z" },
+ { url = "https://files.pythonhosted.org/packages/61/e5/3a0167044773dee989b498e9a851fc1663bea9ab879f1179f7b8a827ac10/django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171", size = 104833, upload-time = "2025-05-13T06:58:27.309Z" },
]
[[package]]
@@ -589,65 +631,65 @@ wheels = [
[[package]]
name = "django-cors-headers"
-version = "4.6.0"
+version = "4.9.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "django" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/c6/e5/3b67fc05b9c02b926411436dfc553829bc00843706ce7f99752433017f47/django_cors_headers-4.6.0.tar.gz", hash = "sha256:14d76b4b4c8d39375baeddd89e4f08899051eeaf177cb02a29bd6eae8cf63aa8", size = 20961, upload-time = "2024-10-29T10:38:15.281Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/21/39/55822b15b7ec87410f34cd16ce04065ff390e50f9e29f31d6d116fc80456/django_cors_headers-4.9.0.tar.gz", hash = "sha256:fe5d7cb59fdc2c8c646ce84b727ac2bca8912a247e6e68e1fb507372178e59e8", size = 21458, upload-time = "2025-09-18T10:40:52.326Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/52/73/689532cf164ab10ed1521d825ea156656520cec98886c8d2ac1ce8829220/django_cors_headers-4.6.0-py3-none-any.whl", hash = "sha256:8edbc0497e611c24d5150e0055d3b178c6534b8ed826fb6f53b21c63f5d48ba3", size = 12791, upload-time = "2024-10-29T10:38:13.784Z" },
+ { url = "https://files.pythonhosted.org/packages/30/d8/19ed1e47badf477d17fb177c1c19b5a21da0fd2d9f093f23be3fb86c5fab/django_cors_headers-4.9.0-py3-none-any.whl", hash = "sha256:15c7f20727f90044dcee2216a9fd7303741a864865f0c3657e28b7056f61b449", size = 12809, upload-time = "2025-09-18T10:40:50.843Z" },
]
[[package]]
name = "django-countries"
-version = "7.6.1"
+version = "8.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0b/c3/ddb94bb50455ae80ff90ddb5affcc28f7e7a48f9c9852cf8bb8fe712fec0/django-countries-7.6.1.tar.gz", hash = "sha256:c772d4e3e54afcc5f97a018544e96f246c6d9f1db51898ab0c15cd57e19437cf", size = 675623, upload-time = "2024-04-01T21:01:09.414Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/67/2e/ed67f8f460d1de25ee64fca5d7f219680f944fc8ac5a29fbede3574dc3db/django_countries-8.2.0.tar.gz", hash = "sha256:6df3883180599052c7dfa9a8be0601792441cfb248935dc229ad1ac92e9e39e3", size = 2455542, upload-time = "2025-11-24T19:57:08.071Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/46/b6931858e5161e5d9166bfcfde3af0b7d60ba89e4f7dd8f033e591c68794/django_countries-7.6.1-py3-none-any.whl", hash = "sha256:1ed20842fe0f6194f91faca21076649513846a8787c9eb5aeec3cbe1656b8acc", size = 864507, upload-time = "2024-04-01T21:01:05.702Z" },
+ { url = "https://files.pythonhosted.org/packages/20/3c/9ebd7ed021b7c519bac954bc88146bc870e7d3c8db2580fa67268464fd2e/django_countries-8.2.0-py3-none-any.whl", hash = "sha256:2b2617bec7c15dc735bdec38ae89f0058e38fddfffdb19a7f6b75ef1e3d5380f", size = 3776079, upload-time = "2025-11-24T19:57:05.576Z" },
]
[[package]]
name = "django-extensions"
-version = "3.2.3"
+version = "4.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/8a/f1/318684c9466968bf9a9c221663128206e460c1a67f595055be4b284cde8a/django-extensions-3.2.3.tar.gz", hash = "sha256:44d27919d04e23b3f40231c4ab7af4e61ce832ef46d610cc650d53e68328410a", size = 277216, upload-time = "2023-06-05T17:09:01.447Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/6d/b3/ed0f54ed706ec0b54fd251cc0364a249c6cd6c6ec97f04dc34be5e929eac/django_extensions-4.1.tar.gz", hash = "sha256:7b70a4d28e9b840f44694e3f7feb54f55d495f8b3fa6c5c0e5e12bcb2aa3cdeb", size = 283078, upload-time = "2025-04-11T01:15:39.617Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/a7/7e/ba12b9660642663f5273141018d2bec0a1cae1711f4f6d1093920e157946/django_extensions-3.2.3-py3-none-any.whl", hash = "sha256:9600b7562f79a92cbf1fde6403c04fee314608fefbb595502e34383ae8203401", size = 229868, upload-time = "2023-06-05T17:08:58.197Z" },
+ { url = "https://files.pythonhosted.org/packages/64/96/d967ca440d6a8e3861120f51985d8e5aec79b9a8bdda16041206adfe7adc/django_extensions-4.1-py3-none-any.whl", hash = "sha256:0699a7af28f2523bf8db309a80278519362cd4b6e1fd0a8cd4bf063e1e023336", size = 232980, upload-time = "2025-04-11T01:15:37.701Z" },
]
[[package]]
name = "django-fernet-encrypted-fields"
-version = "0.3.0"
+version = "0.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cryptography" },
{ name = "django" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/70/b8/b6725f1207693ba9e76223abf87eb9e8de5114cccad8ddd1bce29a195273/django-fernet-encrypted-fields-0.3.0.tar.gz", hash = "sha256:38031bdaf1724a6e885ee137cc66a2bd7dc3726c438e189ea7e44799ec0ba9b3", size = 4021, upload-time = "2025-02-21T02:58:42.049Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/1a/aa/529af3888215b8a660fc3897d6d63eaf1de9aa0699c633ca0ec483d4361c/django_fernet_encrypted_fields-0.3.1.tar.gz", hash = "sha256:5ed328c7f9cc7f2d452bb2e125f3ea2bea3563a259fa943e5a1c626175889a71", size = 5265, upload-time = "2025-11-10T08:39:57.398Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/75/8a/2c5d88cd540d83ceaa1cb3191ed35dfed0caacc6fe2ff5fe74c9ecc7776f/django_fernet_encrypted_fields-0.3.0-py3-none-any.whl", hash = "sha256:a17cca5bf3638ee44674e64f30792d5960b1d4d4b291ec478c27515fc4860612", size = 5400, upload-time = "2025-02-21T02:58:40.832Z" },
+ { url = "https://files.pythonhosted.org/packages/52/7f/4e0b7ed8413fa58e7a77017342e8ab0e977d41cfc376ab9180ae75f216ec/django_fernet_encrypted_fields-0.3.1-py3-none-any.whl", hash = "sha256:3bd2abab02556dc6e15a58a61161ee6c5cdf45a50a8a52d9e035009eb54c6442", size = 5484, upload-time = "2025-11-10T08:39:55.866Z" },
]
[[package]]
name = "django-filter"
-version = "24.3"
+version = "25.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/50/bc/dc19ae39c235332926dd0efe0951f663fa1a9fc6be8430737ff7fd566b20/django_filter-24.3.tar.gz", hash = "sha256:d8ccaf6732afd21ca0542f6733b11591030fa98669f8d15599b358e24a2cd9c3", size = 144444, upload-time = "2024-08-02T13:27:58.132Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/2c/e4/465d2699cd388c0005fb8d6ae6709f239917c6d8790ac35719676fffdcf3/django_filter-25.2.tar.gz", hash = "sha256:760e984a931f4468d096f5541787efb8998c61217b73006163bf2f9523fe8f23", size = 143818, upload-time = "2025-10-05T09:51:31.521Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/09/b1/92f1c30b47c1ebf510c35a2ccad9448f73437e5891bbd2b4febe357cc3de/django_filter-24.3-py3-none-any.whl", hash = "sha256:c4852822928ce17fb699bcfccd644b3574f1a2d80aeb2b4ff4f16b02dd49dc64", size = 95011, upload-time = "2024-08-02T13:27:55.616Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/40/6a02495c5658beb1f31eb09952d8aa12ef3c2a66342331ce3a35f7132439/django_filter-25.2-py3-none-any.whl", hash = "sha256:9c0f8609057309bba611062fe1b720b4a873652541192d232dd28970383633e3", size = 94145, upload-time = "2025-10-05T09:51:29.728Z" },
]
[[package]]
@@ -689,15 +731,15 @@ wheels = [
[[package]]
name = "django-redis"
-version = "5.4.0"
+version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
{ name = "redis" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/83/9d/2272742fdd9d0a9f0b28cd995b0539430c9467a2192e4de2cea9ea6ad38c/django-redis-5.4.0.tar.gz", hash = "sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42", size = 52567, upload-time = "2023-10-01T20:22:01.221Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/08/53/dbcfa1e528e0d6c39947092625b2c89274b5d88f14d357cee53c4d6dbbd4/django_redis-6.0.0.tar.gz", hash = "sha256:2d9cb12a20424a4c4dde082c6122f486628bae2d9c2bee4c0126a4de7fda00dd", size = 56904, upload-time = "2025-06-17T18:15:46.376Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/b7/f1/63caad7c9222c26a62082f4f777de26389233b7574629996098bf6d25a4d/django_redis-5.4.0-py3-none-any.whl", hash = "sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b", size = 31119, upload-time = "2023-10-01T20:21:33.009Z" },
+ { url = "https://files.pythonhosted.org/packages/7e/79/055dfcc508cfe9f439d9f453741188d633efa9eab90fc78a67b0ab50b137/django_redis-6.0.0-py3-none-any.whl", hash = "sha256:20bf0063a8abee567eb5f77f375143c32810c8700c0674ced34737f8de4e36c0", size = 33687, upload-time = "2025-06-17T18:15:34.165Z" },
]
[[package]]
@@ -714,26 +756,26 @@ wheels = [
[[package]]
name = "django-timezone-field"
-version = "7.1"
+version = "7.2.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ba/5b/0dbe271fef3c2274b83dbcb1b19fa3dacf1f7e542382819294644e78ea8b/django_timezone_field-7.1.tar.gz", hash = "sha256:b3ef409d88a2718b566fabe10ea996f2838bc72b22d3a2900c0aa905c761380c", size = 13727, upload-time = "2025-01-11T17:49:54.486Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/da/05/9b93a66452cdb8a08ab26f08d5766d2332673e659a8b2aeb73f2a904d421/django_timezone_field-7.2.1.tar.gz", hash = "sha256:def846f9e7200b7b8f2a28fcce2b78fb2d470f6a9f272b07c4e014f6ba4c6d2e", size = 13096, upload-time = "2025-12-06T23:50:44.591Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ec/09/7a808392a751a24ffa62bec00e3085a9c1a151d728c323a5bab229ea0e58/django_timezone_field-7.1-py3-none-any.whl", hash = "sha256:93914713ed882f5bccda080eda388f7006349f25930b6122e9b07bf8db49c4b4", size = 13177, upload-time = "2025-01-11T17:49:52.142Z" },
+ { url = "https://files.pythonhosted.org/packages/41/7f/d885667401515b467f84569c56075bc9add72c9fd425fca51a25f4c997e1/django_timezone_field-7.2.1-py3-none-any.whl", hash = "sha256:276915b72c5816f57c3baf9e43f816c695ef940d1b21f91ebf6203c09bf4ad44", size = 13284, upload-time = "2025-12-06T23:50:43.302Z" },
]
[[package]]
name = "djangorestframework"
-version = "3.15.2"
+version = "3.16.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/2c/ce/31482eb688bdb4e271027076199e1aa8d02507e530b6d272ab8b4481557c/djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad", size = 1067420, upload-time = "2024-06-19T07:59:32.891Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/8a/95/5376fe618646fde6899b3cdc85fd959716bb67542e273a76a80d9f326f27/djangorestframework-3.16.1.tar.gz", hash = "sha256:166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7", size = 1089735, upload-time = "2025-08-06T17:50:53.251Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7c/b6/fa99d8f05eff3a9310286ae84c4059b08c301ae4ab33ae32e46e8ef76491/djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20", size = 1071235, upload-time = "2024-06-19T07:59:26.106Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/ce/bf8b9d3f415be4ac5588545b5fcdbbb841977db1c1d923f7568eeabe1689/djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec", size = 1080442, upload-time = "2025-08-06T17:50:50.667Z" },
]
[[package]]
@@ -747,16 +789,16 @@ sdist = { url = "https://files.pythonhosted.org/packages/f0/6f/84e91828186bbfced
[[package]]
name = "dnspython"
-version = "2.7.0"
+version = "2.8.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
]
[[package]]
name = "drf-spectacular"
-version = "0.28.0"
+version = "0.29.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
@@ -766,21 +808,21 @@ dependencies = [
{ name = "pyyaml" },
{ name = "uritemplate" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/da/b9/741056455aed00fa51a1df41fad5ad27c8e0d433b6bf490d4e60e2808bc6/drf_spectacular-0.28.0.tar.gz", hash = "sha256:2c778a47a40ab2f5078a7c42e82baba07397bb35b074ae4680721b2805943061", size = 237849, upload-time = "2024-11-30T08:49:02.355Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/5e/0e/a4f50d83e76cbe797eda88fc0083c8ca970cfa362b5586359ef06ec6f70a/drf_spectacular-0.29.0.tar.gz", hash = "sha256:0a069339ea390ce7f14a75e8b5af4a0860a46e833fd4af027411a3e94fc1a0cc", size = 241722, upload-time = "2025-11-02T03:40:26.348Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fb/66/c2929871393b1515c3767a670ff7d980a6882964a31a4ca2680b30d7212a/drf_spectacular-0.28.0-py3-none-any.whl", hash = "sha256:856e7edf1056e49a4245e87a61e8da4baff46c83dbc25be1da2df77f354c7cb4", size = 103928, upload-time = "2024-11-30T08:48:57.288Z" },
+ { url = "https://files.pythonhosted.org/packages/32/d9/502c56fc3ca960075d00956283f1c44e8cafe433dada03f9ed2821f3073b/drf_spectacular-0.29.0-py3-none-any.whl", hash = "sha256:d1ee7c9535d89848affb4427347f7c4a22c5d22530b8842ef133d7b72e19b41a", size = 105433, upload-time = "2025-11-02T03:40:24.823Z" },
]
[[package]]
name = "drf-spectacular-sidecar"
-version = "2024.12.1"
+version = "2026.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "django" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/7c/42/d4fb1284412e51c991fc1da051d7799063a9070a09750def92ae9fb255eb/drf_spectacular_sidecar-2024.12.1.tar.gz", hash = "sha256:6be31df38bcf95681224b6550faa9344ee6dd5360dcf2b44afcc3f7460385613", size = 2385777, upload-time = "2024-12-01T11:22:55.594Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/1e/81/c7b0e3ccbd5a039c4f4fcfecf88391a666ca1406a953886e2f39295b1c90/drf_spectacular_sidecar-2026.1.1.tar.gz", hash = "sha256:6f7c173a8ddbbbdafc7a27e028614b65f07a89ca90f996a432d57460463b56be", size = 2468060, upload-time = "2026-01-01T11:27:12.682Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/2c/b4/250f5c3073835f04997c2ff489cbba51de5e29b4e1deb96d949859c0bd72/drf_spectacular_sidecar-2024.12.1-py3-none-any.whl", hash = "sha256:e30821d150d29294f3be2018aab31b55cd724158e9e690b51a215264751aa8c7", size = 2405338, upload-time = "2024-12-01T11:22:48.875Z" },
+ { url = "https://files.pythonhosted.org/packages/db/96/38725edda526f3e9e597f531beeec94b0ef433d9494f06a13b7636eecb6e/drf_spectacular_sidecar-2026.1.1-py3-none-any.whl", hash = "sha256:af8df62f1b594ec280351336d837eaf2402ab25a6bc2a1fad7aee9935821070f", size = 2489520, upload-time = "2026-01-01T11:27:11.056Z" },
]
[[package]]
@@ -802,14 +844,14 @@ wheels = [
[[package]]
name = "factory-boy"
-version = "3.3.1"
+version = "3.3.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "faker" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/99/3d/8070dde623341401b1c80156583d4c793058fe250450178218bb6e45526c/factory_boy-3.3.1.tar.gz", hash = "sha256:8317aa5289cdfc45f9cae570feb07a6177316c82e34d14df3c2e1f22f26abef0", size = 163924, upload-time = "2024-08-18T19:41:00.212Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/98/75cacae9945f67cfe323829fc2ac451f64517a8a330b572a06a323997065/factory_boy-3.3.3.tar.gz", hash = "sha256:866862d226128dfac7f2b4160287e899daf54f2612778327dd03d0e2cb1e3d03", size = 164146, upload-time = "2025-02-03T09:49:04.433Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/33/cf/44ec67152f3129d0114c1499dd34f0a0a0faf43d9c2af05bc535746ca482/factory_boy-3.3.1-py2.py3-none-any.whl", hash = "sha256:7b1113c49736e1e9995bc2a18f4dbf2c52cf0f841103517010b1d825712ce3ca", size = 36878, upload-time = "2024-08-18T19:40:58.067Z" },
+ { url = "https://files.pythonhosted.org/packages/27/8d/2bc5f5546ff2ccb3f7de06742853483ab75bf74f36a92254702f8baecc79/factory_boy-3.3.3-py2.py3-none-any.whl", hash = "sha256:1c39e3289f7e667c4285433f305f8d506efc2fe9c73aaea4151ebd5cdea394fc", size = 37036, upload-time = "2025-02-03T09:49:01.659Z" },
]
[[package]]
@@ -867,14 +909,14 @@ wheels = [
[[package]]
name = "gunicorn"
-version = "23.0.0"
+version = "25.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031, upload-time = "2024-08-10T20:25:27.378Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/66/13/ef67f59f6a7896fdc2c1d62b5665c5219d6b0a9a1784938eb9a28e55e128/gunicorn-25.1.0.tar.gz", hash = "sha256:1426611d959fa77e7de89f8c0f32eed6aa03ee735f98c01efba3e281b1c47616", size = 594377, upload-time = "2026-02-13T11:09:58.989Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" },
+ { url = "https://files.pythonhosted.org/packages/da/73/4ad5b1f6a2e21cf1e85afdaad2b7b1a933985e2f5d679147a1953aaa192c/gunicorn-25.1.0-py3-none-any.whl", hash = "sha256:d0b1236ccf27f72cfe14bce7caadf467186f19e865094ca84221424e839b8b8b", size = 197067, upload-time = "2026-02-13T11:09:57.146Z" },
]
[[package]]
@@ -925,15 +967,14 @@ wheels = [
[[package]]
name = "hypothesis"
-version = "6.131.1"
+version = "6.151.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "attrs" },
{ name = "sortedcontainers" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/97/e5/6b9b62c0842438c88542ab0b4d9c952b1de48fd359451d4bbdd586f3ebec/hypothesis-6.131.1.tar.gz", hash = "sha256:36e0a14dc4ee0f99ea18f9542e987920e7bf67ff39b37e14d53055249c85b41d", size = 431147, upload-time = "2025-04-17T12:06:25.408Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/e1/ef365ff480903b929d28e057f57b76cae51a30375943e33374ec9a165d9c/hypothesis-6.151.9.tar.gz", hash = "sha256:2f284428dda6c3c48c580de0e18470ff9c7f5ef628a647ee8002f38c3f9097ca", size = 463534, upload-time = "2026-02-16T22:59:23.09Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/d5/7d/6ec8640c8bd4e1817ffd01db74f80d42ea29098865b0610b18b7f5475e85/hypothesis-6.131.1-py3-none-any.whl", hash = "sha256:a8be5428c8c09d51e759f4ac72b7a7ef5352d46b1643527995e93efdccb8ba2e", size = 496270, upload-time = "2025-04-17T12:06:21.364Z" },
+ { url = "https://files.pythonhosted.org/packages/c4/f7/5cc291d701094754a1d327b44d80a44971e13962881d9a400235726171da/hypothesis-6.151.9-py3-none-any.whl", hash = "sha256:7b7220585c67759b1b1ef839b1e6e9e3d82ed468cfc1ece43c67184848d7edd9", size = 529307, upload-time = "2026-02-16T22:59:20.443Z" },
]
[[package]]
@@ -1055,7 +1096,7 @@ wheels = [
[[package]]
name = "jsonschema"
-version = "4.25.0"
+version = "4.26.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
@@ -1063,9 +1104,9 @@ dependencies = [
{ name = "referencing" },
{ name = "rpds-py" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/d5/00/a297a868e9d0784450faa7365c2172a7d6110c763e30ba861867c32ae6a9/jsonschema-4.25.0.tar.gz", hash = "sha256:e63acf5c11762c0e6672ffb61482bdf57f0876684d8d249c0fe2d730d48bc55f", size = 356830, upload-time = "2025-07-18T15:39:45.11Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fe/54/c86cd8e011fe98803d7e382fd67c0df5ceab8d2b7ad8c5a81524f791551c/jsonschema-4.25.0-py3-none-any.whl", hash = "sha256:24c2e8da302de79c8b9382fee3e76b355e44d2a4364bb207159ce10b517bd716", size = 89184, upload-time = "2025-07-18T15:39:42.956Z" },
+ { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" },
]
[[package]]
@@ -1095,7 +1136,7 @@ wheels = [
[[package]]
name = "kombu"
-version = "5.5.4"
+version = "5.6.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "amqp" },
@@ -1103,9 +1144,14 @@ dependencies = [
{ name = "tzdata" },
{ name = "vine" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/0f/d3/5ff936d8319ac86b9c409f1501b07c426e6ad41966fedace9ef1b966e23f/kombu-5.5.4.tar.gz", hash = "sha256:886600168275ebeada93b888e831352fe578168342f0d1d5833d88ba0d847363", size = 461992, upload-time = "2025-06-01T10:19:22.281Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/b6/a5/607e533ed6c83ae1a696969b8e1c137dfebd5759a2e9682e26ff1b97740b/kombu-5.6.2.tar.gz", hash = "sha256:8060497058066c6f5aed7c26d7cd0d3b574990b09de842a8c5aaed0b92cc5a55", size = 472594, upload-time = "2025-12-29T20:30:07.779Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ef/70/a07dcf4f62598c8ad579df241af55ced65bed76e42e45d3c368a6d82dbc1/kombu-5.5.4-py3-none-any.whl", hash = "sha256:a12ed0557c238897d8e518f1d1fdf84bd1516c5e305af2dacd85c2015115feb8", size = 210034, upload-time = "2025-06-01T10:19:20.436Z" },
+ { url = "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl", hash = "sha256:efcfc559da324d41d61ca311b0c64965ea35b4c55cc04ee36e55386145dace93", size = 214219, upload-time = "2025-12-29T20:30:05.74Z" },
+]
+
+[package.optional-dependencies]
+redis = [
+ { name = "redis" },
]
[[package]]
@@ -1236,64 +1282,64 @@ dev = [
[package.metadata]
requires-dist = [
- { name = "boto3", specifier = "==1.40.43" },
- { name = "botocore", specifier = "==1.40.43" },
- { name = "celery", extras = ["redis"], specifier = "==5.5.2" },
+ { name = "boto3", specifier = "==1.42.53" },
+ { name = "botocore", specifier = "==1.42.53" },
+ { name = "celery", extras = ["redis"], specifier = "==5.6.2" },
{ name = "cryptography", specifier = "==46.0.5" },
- { name = "dj-database-url", specifier = "==2.3.0" },
- { name = "django", specifier = "==5.1.15" },
- { name = "django-celery-beat", specifier = "==2.8.0" },
+ { name = "dj-database-url", specifier = "==3.1.2" },
+ { name = "django", specifier = "==5.2.11" },
+ { name = "django-celery-beat", specifier = "==2.8.1" },
{ name = "django-celery-results", specifier = "==2.6.0" },
{ name = "django-configurations", specifier = "==2.5.1" },
- { name = "django-cors-headers", specifier = "==4.6.0" },
- { name = "django-countries", specifier = "==7.6.1" },
- { name = "django-extensions", marker = "extra == 'dev'", specifier = "==3.2.3" },
- { name = "django-fernet-encrypted-fields", specifier = "==0.3.0" },
- { name = "django-filter", specifier = "==24.3" },
+ { name = "django-cors-headers", specifier = "==4.9.0" },
+ { name = "django-countries", specifier = "==8.2.0" },
+ { name = "django-extensions", marker = "extra == 'dev'", specifier = "==4.1" },
+ { name = "django-fernet-encrypted-fields", specifier = "==0.3.1" },
+ { name = "django-filter", specifier = "==25.2" },
{ name = "django-lasuite", extras = ["all"], specifier = "==0.0.24" },
{ name = "django-prometheus", specifier = "==2.4.1" },
- { name = "django-redis", specifier = "==5.4.0" },
+ { name = "django-redis", specifier = "==6.0.0" },
{ name = "django-storages", specifier = "==1.14.6" },
- { name = "django-timezone-field", specifier = "==7.1" },
- { name = "djangorestframework", specifier = "==3.15.2" },
+ { name = "django-timezone-field", specifier = "==7.2.1" },
+ { name = "djangorestframework", specifier = "==3.16.1" },
{ name = "dkimpy", specifier = "==1.1.8" },
- { name = "dnspython", specifier = "==2.7.0" },
- { name = "drf-spectacular", specifier = "==0.28.0" },
- { name = "drf-spectacular-sidecar", marker = "extra == 'dev'", specifier = "==2024.12.1" },
- { name = "factory-boy", specifier = "==3.3.1" },
+ { name = "dnspython", specifier = "==2.8.0" },
+ { name = "drf-spectacular", specifier = "==0.29.0" },
+ { name = "drf-spectacular-sidecar", marker = "extra == 'dev'", specifier = "==2026.1.1" },
+ { name = "factory-boy", specifier = "==3.3.3" },
{ name = "flanker", git = "https://github.com/sylvinus/flanker?rev=f94ba2c15ab310e333610a78828d09be4e11a6b6" },
{ name = "flower", marker = "extra == 'dev'", specifier = "==2.0.1" },
- { name = "gunicorn", specifier = "==23.0.0" },
- { name = "hypothesis", marker = "extra == 'dev'", specifier = "==6.131.1" },
- { name = "jsonschema", specifier = "==4.25.0" },
+ { name = "gunicorn", specifier = "==25.1.0" },
+ { name = "hypothesis", marker = "extra == 'dev'", specifier = "==6.151.9" },
+ { name = "jsonschema", specifier = "==4.26.0" },
{ name = "libpff-python", specifier = "==20231205" },
- { name = "nested-multipart-parser", specifier = "==1.5.0" },
- { name = "openai", specifier = "==1.93.0" },
+ { name = "nested-multipart-parser", specifier = "==1.6.0" },
+ { name = "openai", specifier = "==2.21.0" },
{ name = "opensearch-py", specifier = "==2.8.0" },
- { name = "pip-audit", marker = "extra == 'dev'", specifier = "==2.9.0" },
- { name = "pipdeptree", marker = "extra == 'dev'", specifier = "==2.28.0" },
- { name = "prometheus-client", specifier = "==0.22.1" },
+ { name = "pip-audit", marker = "extra == 'dev'", specifier = "==2.10.0" },
+ { name = "pipdeptree", marker = "extra == 'dev'", specifier = "==2.31.0" },
+ { name = "prometheus-client", specifier = "==0.24.1" },
{ name = "psycopg", extras = ["binary"], specifier = "==3.3.3" },
- { name = "pyjwt", specifier = "==2.10.1" },
- { name = "pylint", marker = "extra == 'dev'", specifier = "==3.3.4" },
- { name = "pylint-django", marker = "extra == 'dev'", specifier = "==2.6.1" },
+ { name = "pyjwt", specifier = "==2.11.0" },
+ { name = "pylint", marker = "extra == 'dev'", specifier = "==4.0.4" },
+ { name = "pylint-django", marker = "extra == 'dev'", specifier = "==2.7.0" },
{ name = "pysocks", specifier = "==1.7.1" },
- { name = "pytest", marker = "extra == 'dev'", specifier = "==8.3.4" },
- { name = "pytest-cov", marker = "extra == 'dev'", specifier = "==6.0.0" },
- { name = "pytest-django", marker = "extra == 'dev'", specifier = "==4.9.0" },
+ { name = "pytest", marker = "extra == 'dev'", specifier = "==9.0.2" },
+ { name = "pytest-cov", marker = "extra == 'dev'", specifier = "==7.0.0" },
+ { name = "pytest-django", marker = "extra == 'dev'", specifier = "==4.12.0" },
{ name = "pytest-icdiff", marker = "extra == 'dev'", specifier = "==0.9" },
{ name = "pytest-repeat", marker = "extra == 'dev'", specifier = "==0.9.4" },
- { name = "pytest-xdist", marker = "extra == 'dev'", specifier = "==3.6.1" },
+ { name = "pytest-xdist", marker = "extra == 'dev'", specifier = "==3.8.0" },
{ name = "python-keycloak", specifier = "==5.5.1" },
{ name = "python-magic", specifier = "==0.4.27" },
- { name = "pyzstd", specifier = "==0.17.0" },
- { name = "redis", specifier = "==5.2.1" },
+ { name = "pyzstd", specifier = "==0.19.1" },
+ { name = "redis", specifier = "==6.4.0" },
{ name = "requests", specifier = "==2.32.5" },
- { name = "responses", marker = "extra == 'dev'", specifier = "==0.25.6" },
- { name = "ruff", marker = "extra == 'dev'", specifier = "==0.9.3" },
- { name = "sentry-sdk", extras = ["django"], specifier = "==2.27.0" },
- { name = "url-normalize", specifier = "==1.4.3" },
- { name = "whitenoise", specifier = "==6.8.2" },
+ { name = "responses", marker = "extra == 'dev'", specifier = "==0.26.0" },
+ { name = "ruff", marker = "extra == 'dev'", specifier = "==0.15.2" },
+ { name = "sentry-sdk", extras = ["django"], specifier = "==2.53.0" },
+ { name = "url-normalize", specifier = "==2.2.1" },
+ { name = "whitenoise", specifier = "==6.11.0" },
]
provides-extras = ["dev"]
@@ -1349,13 +1395,13 @@ wheels = [
[[package]]
name = "nested-multipart-parser"
-version = "1.5.0"
+version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/7e/37/f7bdf0fc439fb2ed11a0ac9f303f94abab36e48e6d90c109fb4c51b39092/nested-multipart-parser-1.5.0.tar.gz", hash = "sha256:28039b6c8acd3d3aa17791f50773f23b7e28604503eec628e8e08932768f73a9", size = 7562, upload-time = "2023-02-07T16:22:39.706Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/b8/48/b91a6f924a2abd9e86b501347ca56989e2c2b4bf3eac86bff57f80b99b75/nested_multipart_parser-1.6.0.tar.gz", hash = "sha256:8c7a07952a4a3c2cb2b99ca16158961af215c6f8c9e04337bc13da016500c69c", size = 13159, upload-time = "2025-09-17T20:47:25.627Z" }
[[package]]
name = "openai"
-version = "1.93.0"
+version = "2.21.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio" },
@@ -1367,9 +1413,9 @@ dependencies = [
{ name = "tqdm" },
{ name = "typing-extensions" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e4/d7/e91c6a9cf71726420cddf539852ee4c29176ebb716a702d9118d0409fd8e/openai-1.93.0.tar.gz", hash = "sha256:988f31ade95e1ff0585af11cc5a64510225e4f5cd392698c675d0a9265b8e337", size = 486573, upload-time = "2025-06-27T21:21:39.421Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/92/e5/3d197a0947a166649f566706d7a4c8f7fe38f1fa7b24c9bcffe4c7591d44/openai-2.21.0.tar.gz", hash = "sha256:81b48ce4b8bbb2cc3af02047ceb19561f7b1dc0d4e52d1de7f02abfd15aa59b7", size = 644374, upload-time = "2026-02-14T00:12:01.577Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/64/46/a10d9df4673df56f71201d129ba1cb19eaff3366d08c8664d61a7df52e65/openai-1.93.0-py3-none-any.whl", hash = "sha256:3d746fe5498f0dd72e0d9ab706f26c91c0f646bf7459e5629af8ba7c9dbdf090", size = 755038, upload-time = "2025-06-27T21:21:37.532Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/56/0a89092a453bb2c676d66abee44f863e742b2110d4dbb1dbcca3f7e5fc33/openai-2.21.0-py3-none-any.whl", hash = "sha256:0bc1c775e5b1536c294eded39ee08f8407656537ccc71b1004104fe1602e267c", size = 1103065, upload-time = "2026-02-14T00:11:59.603Z" },
]
[[package]]
@@ -1429,7 +1475,7 @@ wheels = [
[[package]]
name = "pip-audit"
-version = "2.9.0"
+version = "2.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cachecontrol", extra = ["filecache"] },
@@ -1440,11 +1486,12 @@ dependencies = [
{ name = "platformdirs" },
{ name = "requests" },
{ name = "rich" },
- { name = "toml" },
+ { name = "tomli" },
+ { name = "tomli-w" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/cc/7f/28fad19a9806f796f13192ab6974c07c4a04d9cbb8e30dd895c3c11ce7ee/pip_audit-2.9.0.tar.gz", hash = "sha256:0b998410b58339d7a231e5aa004326a294e4c7c6295289cdc9d5e1ef07b1f44d", size = 52089, upload-time = "2025-04-07T16:45:23.679Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/bd/89/0e999b413facab81c33d118f3ac3739fd02c0622ccf7c4e82e37cebd8447/pip_audit-2.10.0.tar.gz", hash = "sha256:427ea5bf61d1d06b98b1ae29b7feacc00288a2eced52c9c58ceed5253ef6c2a4", size = 53776, upload-time = "2025-12-01T23:42:40.612Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/43/9e/f4dfd9d3dadb6d6dc9406f1111062f871e2e248ed7b584cca6020baf2ac1/pip_audit-2.9.0-py3-none-any.whl", hash = "sha256:348b16e60895749a0839875d7cc27ebd692e1584ebe5d5cb145941c8e25a80bd", size = 58634, upload-time = "2025-04-07T16:45:22.056Z" },
+ { url = "https://files.pythonhosted.org/packages/be/f3/4888f895c02afa085630a3a3329d1b18b998874642ad4c530e9a4d7851fe/pip_audit-2.10.0-py3-none-any.whl", hash = "sha256:16e02093872fac97580303f0848fa3ad64f7ecf600736ea7835a2b24de49613f", size = 61518, upload-time = "2025-12-01T23:42:39.193Z" },
]
[[package]]
@@ -1462,15 +1509,15 @@ wheels = [
[[package]]
name = "pipdeptree"
-version = "2.28.0"
+version = "2.31.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
{ name = "pip" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/25/61/0e855474eee22f06d8508aad787c1bb3f9fff28759e758c0da44f8549998/pipdeptree-2.28.0.tar.gz", hash = "sha256:bae533e30249b1aa6d9cb315ef6f1c039e9adaa55d5b25438395cace5716eaa6", size = 42583, upload-time = "2025-07-20T19:47:26.737Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/67/0d/84e80cb63ef95aac70f279a4fb98e1f29301613b709385f0bc00b5ef33e2/pipdeptree-2.31.0.tar.gz", hash = "sha256:b3863e889761be597cc68cc38b3845f670ceab8d690f7b6728aa396d1e1be458", size = 43790, upload-time = "2026-02-20T02:57:00.51Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/0a/84/d5e9403c11f6440dcb127afbb15b34dda7408dcbcefcaf6e0aa9e9a4730f/pipdeptree-2.28.0-py3-none-any.whl", hash = "sha256:a4ce80e7fdf93dfc6d99809d9bbe0115a13902b1f0498775abeafe56c77bdd3d", size = 33840, upload-time = "2025-07-20T19:47:25.282Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/01/a769099fcb2cc69480201b44f09a197c7f8f2403d486c9788a43868fa875/pipdeptree-2.31.0-py3-none-any.whl", hash = "sha256:8a85583ef755959bda23ff40f39b1f393d73e25d182cf9e9b21c818f3e3ece7d", size = 34626, upload-time = "2026-02-20T02:56:58.932Z" },
]
[[package]]
@@ -1511,11 +1558,11 @@ wheels = [
[[package]]
name = "prometheus-client"
-version = "0.22.1"
+version = "0.24.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/5e/cf/40dde0a2be27cc1eb41e333d1a674a74ce8b8b0457269cc640fd42b07cf7/prometheus_client-0.22.1.tar.gz", hash = "sha256:190f1331e783cf21eb60bca559354e0a4d4378facecf78f5428c39b675d20d28", size = 69746, upload-time = "2025-06-02T14:29:01.152Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616, upload-time = "2026-01-14T15:26:26.965Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/32/ae/ec06af4fe3ee72d16973474f122541746196aaa16cea6f66d18b963c6177/prometheus_client-0.22.1-py3-none-any.whl", hash = "sha256:cca895342e308174341b2cbf99a56bef291fbc0ef7b9e5412a0f26d653ba7094", size = 58694, upload-time = "2025-06-02T14:29:00.068Z" },
+ { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057, upload-time = "2026-01-14T15:26:24.42Z" },
]
[[package]]
@@ -1676,16 +1723,16 @@ wheels = [
[[package]]
name = "pyjwt"
-version = "2.10.1"
+version = "2.11.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
]
[[package]]
name = "pylint"
-version = "3.3.4"
+version = "4.0.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "astroid" },
@@ -1696,22 +1743,21 @@ dependencies = [
{ name = "platformdirs" },
{ name = "tomlkit" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ab/b9/50be49afc91469f832c4bf12318ab4abe56ee9aa3700a89aad5359ad195f/pylint-3.3.4.tar.gz", hash = "sha256:74ae7a38b177e69a9b525d0794bd8183820bfa7eb68cc1bee6e8ed22a42be4ce", size = 1518905, upload-time = "2025-01-28T13:28:21.649Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/5a/d2/b081da1a8930d00e3fc06352a1d449aaf815d4982319fab5d8cdb2e9ab35/pylint-4.0.4.tar.gz", hash = "sha256:d9b71674e19b1c36d79265b5887bf8e55278cbe236c9e95d22dc82cf044fdbd2", size = 1571735, upload-time = "2025-11-30T13:29:04.315Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/0d/8b/eef15df5f4e7aa393de31feb96ca9a3d6639669bd59d589d0685d5ef4e62/pylint-3.3.4-py3-none-any.whl", hash = "sha256:289e6a1eb27b453b08436478391a48cd53bb0efb824873f949e709350f3de018", size = 522280, upload-time = "2025-01-28T13:28:18.044Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/92/d40f5d937517cc489ad848fc4414ecccc7592e4686b9071e09e64f5e378e/pylint-4.0.4-py3-none-any.whl", hash = "sha256:63e06a37d5922555ee2c20963eb42559918c20bd2b21244e4ef426e7c43b92e0", size = 536425, upload-time = "2025-11-30T13:29:02.53Z" },
]
[[package]]
name = "pylint-django"
-version = "2.6.1"
+version = "2.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pylint" },
{ name = "pylint-plugin-utils" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/40/d3/42f88e7549c6d69d9642e7f2de7a1a4a3d45fd352a8ca049c554a3feaba0/pylint-django-2.6.1.tar.gz", hash = "sha256:19e8c85a8573a04e3de7be2ba91e9a7c818ebf05e1b617be2bbae67a906b725f", size = 31970, upload-time = "2024-10-10T14:46:37.931Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/1b/82/88b58feecce482e76e4ec4a45e44ed28075fddd82530d071d89466e83529/pylint_django-2.6.1-py3-none-any.whl", hash = "sha256:359f68fe8c810ee6bc8e1ab4c83c19b15a43b234a24b08978f47a23462b5ce28", size = 42858, upload-time = "2024-10-10T14:46:36.236Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/0d/d775fec0dde8ca5d20e9170a2ca332dfa21b77f7e7e47fc3ab9b2261773c/pylint_django-2.7.0-py3-none-any.whl", hash = "sha256:76ef7e7bbbcf7ee86adbb2beac0ffaa7232509a17bf4a488d81467a1bbaa215b", size = 42892, upload-time = "2026-01-01T11:17:04.292Z" },
]
[[package]]
@@ -1746,42 +1792,44 @@ wheels = [
[[package]]
name = "pytest"
-version = "8.3.4"
+version = "9.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
+ { name = "pygments" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919, upload-time = "2024-12-01T12:54:25.98Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083, upload-time = "2024-12-01T12:54:19.735Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
]
[[package]]
name = "pytest-cov"
-version = "6.0.0"
+version = "7.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage" },
+ { name = "pluggy" },
{ name = "pytest" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945, upload-time = "2024-10-29T20:13:35.363Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949, upload-time = "2024-10-29T20:13:33.215Z" },
+ { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
]
[[package]]
name = "pytest-django"
-version = "4.9.0"
+version = "4.12.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytest" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/02/c0/43c8b2528c24d7f1a48a47e3f7381f5ab2ae8c64634b0c3f4bd843063955/pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314", size = 84067, upload-time = "2024-09-02T15:49:18.407Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/13/2b/db9a193df89e5660137f5428063bcc2ced7ad790003b26974adf5c5ceb3b/pytest_django-4.12.0.tar.gz", hash = "sha256:df94ec819a83c8979c8f6de13d9cdfbe76e8c21d39473cfe2b40c9fc9be3c758", size = 91156, upload-time = "2026-02-14T18:40:49.235Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/47/fe/54f387ee1b41c9ad59e48fb8368a361fad0600fe404315e31a12bacaea7d/pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99", size = 23723, upload-time = "2024-09-02T15:49:17.127Z" },
+ { url = "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl", hash = "sha256:3ff300c49f8350ba2953b90297d23bf5f589db69545f56f1ec5f8cff5da83e85", size = 26123, upload-time = "2026-02-14T18:40:47.381Z" },
]
[[package]]
@@ -1812,15 +1860,15 @@ wheels = [
[[package]]
name = "pytest-xdist"
-version = "3.6.1"
+version = "3.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "execnet" },
{ name = "pytest" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060, upload-time = "2024-04-28T19:29:54.414Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", size = 46108, upload-time = "2024-04-28T19:29:52.813Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" },
]
[[package]]
@@ -1918,34 +1966,23 @@ wheels = [
[[package]]
name = "pyzstd"
-version = "0.17.0"
+version = "0.19.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/8f/a2/54d860ccbd07e3c67e4d0321d1c29fc7963ac82cf801a078debfc4ef7c15/pyzstd-0.17.0.tar.gz", hash = "sha256:d84271f8baa66c419204c1dd115a4dec8b266f8a2921da21b81764fa208c1db6", size = 1212160, upload-time = "2025-05-10T14:14:49.764Z" }
+dependencies = [
+ { name = "backports-zstd", marker = "python_full_version < '3.14'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4c/66/59fed71d0d2065e02974b40296f836a237c364c8bbe07295f2d0dc33c278/pyzstd-0.19.1.tar.gz", hash = "sha256:36723d3c915b3981de9198d0a2c82b2f5fe3eaa36e4d8d586937830a8afc7d72", size = 69531, upload-time = "2025-12-13T08:15:33.455Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/7e/51/171f5aad999e3f99e664e8ef572bbf97cbd684c46891a99fe8767eb9b7f6/pyzstd-0.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6cd1a1d37a7abe9c01d180dad699e3ac3889e4f48ac5dcca145cc46b04e9abd2", size = 379051, upload-time = "2025-05-10T14:13:40.36Z" },
- { url = "https://files.pythonhosted.org/packages/83/1e/bdae9d1331a7fb60cdd9d3c75794ea4c0271d5e8408fbbe877353b730f99/pyzstd-0.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a44fd596eda06b6265dc0358d5b309715a93f8e96e8a4b5292c2fe0e14575b3", size = 298384, upload-time = "2025-05-10T14:13:41.728Z" },
- { url = "https://files.pythonhosted.org/packages/80/3d/c0b61fc7994254b369aa5e96fcd02dbb3f8964482d51e098640802dd35e8/pyzstd-0.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a99b37453f92f0691b2454d0905bbf2f430522612f6f12bbc81133ad947eb97", size = 445950, upload-time = "2025-05-10T14:13:43.034Z" },
- { url = "https://files.pythonhosted.org/packages/78/62/318de78124d49fe3f7ae2b44726bdb85eef63c3f3338ec3673665326df25/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63d864e9f9e624a466070a121ace9d9cbf579eac4ed575dee3b203ab1b3cbeee", size = 392923, upload-time = "2025-05-10T14:13:44.443Z" },
- { url = "https://files.pythonhosted.org/packages/7a/24/21541ee45cae4fd7e3d15d67f67ad3e96e41e0ee0a95653006f8a0df2349/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e58bc02b055f96d1f83c791dd197d8c80253275a56cd84f917a006e9f528420d", size = 480524, upload-time = "2025-05-10T14:13:45.798Z" },
- { url = "https://files.pythonhosted.org/packages/ed/fd/6659504588f4cb53ac5f347bd75206072c4969eacf3ae6925f46ddb6dadb/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e62df7c0ba74618481149c849bc3ed7d551b9147e1274b4b3170bbcc0bfcc0a", size = 423568, upload-time = "2025-05-10T14:13:47.624Z" },
- { url = "https://files.pythonhosted.org/packages/2a/50/1eefc03eb21745321893fbd52702245f85e9e1f7ad35411dff2606792100/pyzstd-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42ecdd7136294f1becb8e57441df00eaa6dfd7444a8b0c96a1dfba5c81b066e7", size = 415473, upload-time = "2025-05-10T14:13:48.994Z" },
- { url = "https://files.pythonhosted.org/packages/8a/27/f3da112795f9b9dc4db819f9f6e1b231a7adc03c609db1f2b33a4185be1d/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:be07a57af75f99fc39b8e2d35f8fb823ecd7ef099cd1f6203829a5094a991ae2", size = 418276, upload-time = "2025-05-10T14:13:50.316Z" },
- { url = "https://files.pythonhosted.org/packages/95/56/02b601d7198dc5138ceea6f2b978b3205b9fab05740957d1ef1c4ca59621/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0d41e6f7ec2a70dab4982157a099562de35a6735c890945b4cebb12fb7eb0be0", size = 449285, upload-time = "2025-05-10T14:13:51.759Z" },
- { url = "https://files.pythonhosted.org/packages/f4/79/8a4c352f9dd5728402318f324930250ad40df8fd27fea33818cf0c9ac171/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f482d906426756e7cc9a43f500fee907e1b3b4e9c04d42d58fb1918c6758759b", size = 522190, upload-time = "2025-05-10T14:13:53.075Z" },
- { url = "https://files.pythonhosted.org/packages/55/4a/51385325e7b816365292078449a8007bc3ab3e05b7b29ab91d9d519edb01/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:827327b35605265e1d05a2f6100244415e8f2728bb75c951736c9288415908d7", size = 566488, upload-time = "2025-05-10T14:13:54.484Z" },
- { url = "https://files.pythonhosted.org/packages/26/68/da37fb4e6a79a3cff7de4a3ee006fb5f981230c59de79f6c8c426392a265/pyzstd-0.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a55008f80e3390e4f37bd9353830f1675f271d13d6368d2f1dc413b7c6022b3", size = 432870, upload-time = "2025-05-10T14:13:55.86Z" },
- { url = "https://files.pythonhosted.org/packages/30/05/769d82f9708c4907512111a1de44bb77e5b08ad3862287c2e5fc5ead2df2/pyzstd-0.17.0-cp313-cp313-win32.whl", hash = "sha256:a4be186c0df86d4d95091c759a06582654f2b93690503b1c24d77f537d0cf5d0", size = 220290, upload-time = "2025-05-10T14:13:57.227Z" },
- { url = "https://files.pythonhosted.org/packages/62/92/f69eb8623f041c2656e27337ac08e69cd18a9eacb1557ab498d391f191bd/pyzstd-0.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:251a0b599bd224ec66f39165ddb2f959d0a523938e3bbfa82d8188dc03a271a2", size = 246450, upload-time = "2025-05-10T14:13:58.596Z" },
- { url = "https://files.pythonhosted.org/packages/ad/ef/5ae5445d5f675e9e8c868b2326597c5b396e41c5c9645daa45e8c1cd3d5c/pyzstd-0.17.0-cp313-cp313-win_arm64.whl", hash = "sha256:ce6d5fd908fd3ddec32d1c1a5a7a15b9d7737d0ef2ab20fe1e8261da61395017", size = 222966, upload-time = "2025-05-10T14:13:59.881Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/62/f55d1363512d1b1cc122af6ca5951008e42605b63675c7d6781affc7c475/pyzstd-0.19.1-py3-none-any.whl", hash = "sha256:267e2eb0de0291dfcb7ccfebc4ffe75b2f9d84e7007ac38844f6ccafc6dce081", size = 23779, upload-time = "2025-12-13T08:15:31.979Z" },
]
[[package]]
name = "redis"
-version = "5.2.1"
+version = "6.4.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/47/da/d283a37303a995cd36f8b92db85135153dc4f7a8e4441aa827721b442cfb/redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f", size = 4608355, upload-time = "2024-12-06T09:50:41.956Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/e8b92798a5bd67d659d51a18170e91c16ac3b59738d91894651ee255ed49/redis-6.4.0.tar.gz", hash = "sha256:b01bc7282b8444e28ec36b261df5375183bb47a07eb9c603f284e89cbc5ef010", size = 4647399, upload-time = "2025-08-07T08:10:11.441Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3c/5f/fa26b9b2672cbe30e07d9a5bdf39cf16e3b80b42916757c5f92bca88e4ba/redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4", size = 261502, upload-time = "2024-12-06T09:50:39.656Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl", hash = "sha256:f0544fa9604264e9464cdf4814e7d4830f74b165d52f2a330a760a88dd248b7f", size = 279847, upload-time = "2025-08-07T08:10:09.84Z" },
]
[[package]]
@@ -2062,16 +2099,16 @@ wheels = [
[[package]]
name = "responses"
-version = "0.25.6"
+version = "0.26.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyyaml" },
{ name = "requests" },
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/97/63/759996eea0f17e8dc4c9ea9c60765292d28a7750bdbee073ad55d83caa57/responses-0.25.6.tar.gz", hash = "sha256:eae7ce61a9603004e76c05691e7c389e59652d91e94b419623c12bbfb8e331d8", size = 79145, upload-time = "2025-01-13T21:04:27.895Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/9f/b4/b7e040379838cc71bf5aabdb26998dfbe5ee73904c92c1c161faf5de8866/responses-0.26.0.tar.gz", hash = "sha256:c7f6923e6343ef3682816ba421c006626777893cb0d5e1434f674b649bac9eb4", size = 81303, upload-time = "2026-02-19T14:38:05.574Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/92/c4/8d23584b3a3471ea6f5a18cfb035e11eeb9fa9b3112d901477c6ad10cc4e/responses-0.25.6-py3-none-any.whl", hash = "sha256:9cac8f21e1193bb150ec557875377e41ed56248aed94e4567ed644db564bacf1", size = 34730, upload-time = "2025-01-13T21:04:24.895Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/04/7f73d05b556da048923e31a0cc878f03be7c5425ed1f268082255c75d872/responses-0.26.0-py3-none-any.whl", hash = "sha256:03ec4409088cd5c66b71ecbbbd27fe2c58ddfad801c66203457b3e6a04868c37", size = 35099, upload-time = "2026-02-19T14:38:03.847Z" },
]
[[package]]
@@ -2155,52 +2192,52 @@ wheels = [
[[package]]
name = "ruff"
-version = "0.9.3"
+version = "0.15.2"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/1e/7f/60fda2eec81f23f8aa7cbbfdf6ec2ca11eb11c273827933fb2541c2ce9d8/ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a", size = 3586740, upload-time = "2025-01-23T19:29:02.538Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f9/77/4fb790596d5d52c87fd55b7160c557c400e90f6116a56d82d76e95d9374a/ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624", size = 11656815, upload-time = "2025-01-23T19:27:49.457Z" },
- { url = "https://files.pythonhosted.org/packages/a2/a8/3338ecb97573eafe74505f28431df3842c1933c5f8eae615427c1de32858/ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c", size = 11594821, upload-time = "2025-01-23T19:27:53.913Z" },
- { url = "https://files.pythonhosted.org/packages/8e/89/320223c3421962762531a6b2dd58579b858ca9916fb2674874df5e97d628/ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4", size = 11040475, upload-time = "2025-01-23T19:27:58.059Z" },
- { url = "https://files.pythonhosted.org/packages/b2/bd/1d775eac5e51409535804a3a888a9623e87a8f4b53e2491580858a083692/ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439", size = 11856207, upload-time = "2025-01-23T19:28:02.26Z" },
- { url = "https://files.pythonhosted.org/packages/7f/c6/3e14e09be29587393d188454064a4aa85174910d16644051a80444e4fd88/ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5", size = 11420460, upload-time = "2025-01-23T19:28:05.706Z" },
- { url = "https://files.pythonhosted.org/packages/ef/42/b7ca38ffd568ae9b128a2fa76353e9a9a3c80ef19746408d4ce99217ecc1/ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4", size = 12605472, upload-time = "2025-01-23T19:28:10.319Z" },
- { url = "https://files.pythonhosted.org/packages/a6/a1/3167023f23e3530fde899497ccfe239e4523854cb874458ac082992d206c/ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1", size = 13243123, upload-time = "2025-01-23T19:28:14.181Z" },
- { url = "https://files.pythonhosted.org/packages/d0/b4/3c600758e320f5bf7de16858502e849f4216cb0151f819fa0d1154874802/ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5", size = 12744650, upload-time = "2025-01-23T19:28:19.738Z" },
- { url = "https://files.pythonhosted.org/packages/be/38/266fbcbb3d0088862c9bafa8b1b99486691d2945a90b9a7316336a0d9a1b/ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4", size = 14458585, upload-time = "2025-01-23T19:28:24.255Z" },
- { url = "https://files.pythonhosted.org/packages/63/a6/47fd0e96990ee9b7a4abda62de26d291bd3f7647218d05b7d6d38af47c30/ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6", size = 12419624, upload-time = "2025-01-23T19:28:29.894Z" },
- { url = "https://files.pythonhosted.org/packages/84/5d/de0b7652e09f7dda49e1a3825a164a65f4998175b6486603c7601279baad/ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730", size = 11843238, upload-time = "2025-01-23T19:28:36.111Z" },
- { url = "https://files.pythonhosted.org/packages/9e/be/3f341ceb1c62b565ec1fb6fd2139cc40b60ae6eff4b6fb8f94b1bb37c7a9/ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2", size = 11484012, upload-time = "2025-01-23T19:28:40.919Z" },
- { url = "https://files.pythonhosted.org/packages/a3/c8/ff8acbd33addc7e797e702cf00bfde352ab469723720c5607b964491d5cf/ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519", size = 12038494, upload-time = "2025-01-23T19:28:44.314Z" },
- { url = "https://files.pythonhosted.org/packages/73/b1/8d9a2c0efbbabe848b55f877bc10c5001a37ab10aca13c711431673414e5/ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b", size = 12473639, upload-time = "2025-01-23T19:28:47.686Z" },
- { url = "https://files.pythonhosted.org/packages/cb/44/a673647105b1ba6da9824a928634fe23186ab19f9d526d7bdf278cd27bc3/ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c", size = 9834353, upload-time = "2025-01-23T19:28:51.755Z" },
- { url = "https://files.pythonhosted.org/packages/c3/01/65cadb59bf8d4fbe33d1a750103e6883d9ef302f60c28b73b773092fbde5/ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4", size = 10821444, upload-time = "2025-01-23T19:28:56.509Z" },
- { url = "https://files.pythonhosted.org/packages/69/cb/b3fe58a136a27d981911cba2f18e4b29f15010623b79f0f2510fd0d31fd3/ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b", size = 10038168, upload-time = "2025-01-23T19:28:59.81Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" },
+ { url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" },
+ { url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" },
+ { url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" },
+ { url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" },
+ { url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" },
+ { url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" },
+ { url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" },
+ { url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" },
+ { url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" },
+ { url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" },
]
[[package]]
name = "s3transfer"
-version = "0.14.0"
+version = "0.16.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/62/74/8d69dcb7a9efe8baa2046891735e5dfe433ad558ae23d9e3c14c633d1d58/s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125", size = 151547, upload-time = "2025-09-09T19:23:31.089Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/48/f0/ae7ca09223a81a1d890b2557186ea015f6e0502e9b8cb8e1813f1d8cfa4e/s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456", size = 85712, upload-time = "2025-09-09T19:23:30.041Z" },
+ { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" },
]
[[package]]
name = "sentry-sdk"
-version = "2.27.0"
+version = "2.53.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "urllib3" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/cf/b6/a92ae6fa6d7e6e536bc586776b1669b84fb724dfe21b8ff08297f2d7c969/sentry_sdk-2.27.0.tar.gz", hash = "sha256:90f4f883f9eff294aff59af3d58c2d1b64e3927b28d5ada2b9b41f5aeda47daf", size = 323556, upload-time = "2025-04-24T10:09:37.927Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/d3/06/66c8b705179bc54087845f28fd1b72f83751b6e9a195628e2e9af9926505/sentry_sdk-2.53.0.tar.gz", hash = "sha256:6520ef2c4acd823f28efc55e43eb6ce2e6d9f954a95a3aa96b6fd14871e92b77", size = 412369, upload-time = "2026-02-16T11:11:14.743Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/dd/8b/fb496a45854e37930b57564a20fb8e90dd0f8b6add0491527c00f2163b00/sentry_sdk-2.27.0-py2.py3-none-any.whl", hash = "sha256:c58935bfff8af6a0856d37e8adebdbc7b3281c2b632ec823ef03cd108d216ff0", size = 340786, upload-time = "2025-04-24T10:09:35.897Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d4/2fdf854bc3b9c7f55219678f812600a20a138af2dd847d99004994eada8f/sentry_sdk-2.53.0-py2.py3-none-any.whl", hash = "sha256:46e1ed8d84355ae54406c924f6b290c3d61f4048625989a723fd622aab838899", size = 437908, upload-time = "2026-02-16T11:11:13.227Z" },
]
[package.optional-dependencies]
@@ -2254,12 +2291,48 @@ wheels = [
]
[[package]]
-name = "toml"
-version = "0.10.2"
+name = "tomli"
+version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
+ { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" },
+ { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" },
+ { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" },
+ { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" },
+ { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" },
+ { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" },
+ { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" },
+ { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" },
+ { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" },
+ { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" },
+ { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" },
+ { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" },
+ { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" },
+ { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
+]
+
+[[package]]
+name = "tomli-w"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184, upload-time = "2025-01-15T12:07:24.262Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675, upload-time = "2025-01-15T12:07:22.074Z" },
]
[[package]]
@@ -2332,6 +2405,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
]
+[[package]]
+name = "tzlocal"
+version = "5.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "tzdata", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" },
+]
+
[[package]]
name = "uritemplate"
version = "4.2.0"
@@ -2343,14 +2428,14 @@ wheels = [
[[package]]
name = "url-normalize"
-version = "1.4.3"
+version = "2.2.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "six" },
+ { name = "idna" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ec/ea/780a38c99fef750897158c0afb83b979def3b379aaac28b31538d24c4e8f/url-normalize-1.4.3.tar.gz", hash = "sha256:d23d3a070ac52a67b83a1c59a0e68f8608d1cd538783b401bc9de2c0fac999b2", size = 6024, upload-time = "2020-10-26T02:07:11.438Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/80/31/febb777441e5fcdaacb4522316bf2a527c44551430a4873b052d545e3279/url_normalize-2.2.1.tar.gz", hash = "sha256:74a540a3b6eba1d95bdc610c24f2c0141639f3ba903501e61a52a8730247ff37", size = 18846, upload-time = "2025-04-26T20:37:58.553Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/65/1c/6c6f408be78692fc850006a2b6dea37c2b8592892534e09996e401efc74b/url_normalize-1.4.3-py2.py3-none-any.whl", hash = "sha256:ec3c301f04e5bb676d333a7fa162fa977ad2ca04b7e652bfc9fac4e405728eed", size = 6804, upload-time = "2020-10-26T02:07:13.218Z" },
+ { url = "https://files.pythonhosted.org/packages/bc/d9/5ec15501b675f7bc07c5d16aa70d8d778b12375686b6efd47656efdc67cd/url_normalize-2.2.1-py3-none-any.whl", hash = "sha256:3deb687587dc91f7b25c9ae5162ffc0f057ae85d22b1e15cf5698311247f567b", size = 14728, upload-time = "2025-04-26T20:37:57.217Z" },
]
[[package]]
@@ -2394,9 +2479,9 @@ wheels = [
[[package]]
name = "whitenoise"
-version = "6.8.2"
+version = "6.11.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/68/49/c21ebb5b911888c349a849ec7d1ead2dffbbcc4e2be0f6af2a7dbac03393/whitenoise-6.8.2.tar.gz", hash = "sha256:486bd7267a375fa9650b136daaec156ac572971acc8bf99add90817a530dd1d4", size = 25892, upload-time = "2024-10-29T23:04:39.888Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/15/95/8c81ec6b6ebcbf8aca2de7603070ccf37dbb873b03f20708e0f7c1664bc6/whitenoise-6.11.0.tar.gz", hash = "sha256:0f5bfce6061ae6611cd9396a8231e088722e4fc67bc13a111be74c738d99375f", size = 26432, upload-time = "2025-09-18T09:16:10.995Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/8c/3a/8d22513e1942899270dcdbd47f9886309836442cd7ede4b0d00be79715f5/whitenoise-6.8.2-py3-none-any.whl", hash = "sha256:df12dce147a043d1956d81d288c6f0044147c6d2ab9726e5772ac50fb45d2280", size = 20158, upload-time = "2024-10-29T23:04:38.415Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/e9/4366332f9295fe0647d7d3251ce18f5615fbcb12d02c79a26f8dba9221b3/whitenoise-6.11.0-py3-none-any.whl", hash = "sha256:b2aeb45950597236f53b5342b3121c5de69c8da0109362aee506ce88e022d258", size = 20197, upload-time = "2025-09-18T09:16:09.754Z" },
]
diff --git a/src/mta-in/pyproject.toml b/src/mta-in/pyproject.toml
index 9d8d65d6..4a92d512 100644
--- a/src/mta-in/pyproject.toml
+++ b/src/mta-in/pyproject.toml
@@ -25,7 +25,7 @@ license = "MIT"
readme = "README.md"
requires-python = ">=3.13,<4.0"
-# Note: after changing this list you must re-run `make uv-lock-mta-in`
+# Note: after changing this list you must re-run `make deps-lock-mta-in`
dependencies = [
"requests==2.32.3",
"PyJWT==2.10.1",