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