- Excluded rows are intentionally omitted from delivery. Their SMTP and IMAP states are shown as Skipped because no transport effect is attempted; use the separate status filters to isolate them.
+ i18n:govoplan-campaign.excluded_rows_are_intentionally_omitted_from_del.421a1f00
- Queue for workers commits durable jobs and returns immediately; progress remains visible here after you leave. Send now keeps this request open and is limited to {synchronousSendLimit || "the configured maximum"} eligible recipient jobs.
+ {i18nMessage("i18n:govoplan-campaign.queue_for_workers_commits_durable_jobs_and_retur.d0dbe81a", {
+ value0: synchronousSendLimit || "i18n:govoplan-campaign.the_configured_maximum.eb10006b"
+ })}
Worker queue committed {String(queueResult.queued_count ?? 0)} message(s) and published {String(queueResult.enqueued_count ?? 0)} task(s). Refreshing progress does not requeue them.
- This version last entered {humanize(persistedDeliveryMode)} mode{persistedDeliveryModeSelectedAt ? ` at ${formatDateTime(persistedDeliveryModeSelectedAt)}` : ""}. This record remains available after leaving and returning.
+ {persistedDeliveryModeSelectedAt
+ ? i18nMessage("i18n:govoplan-campaign.this_version_last_entered_value0_mode_at_value1_.c087d2f3", {
+ value0: deliveryModeLabel(persistedDeliveryMode),
+ value1: formatDateTime(persistedDeliveryModeSelectedAt)
+ })
+ : i18nMessage("i18n:govoplan-campaign.this_version_last_entered_value0_mode_this_recor.ea2f201f", {
+ value0: deliveryModeLabel(persistedDeliveryMode)
+ })}
- Small-cell threshold: {threshold}. Suppressed values cannot be opened, filtered, exported, or inspected from this view.
+ {i18nMessage("i18n:govoplan-campaign.small_cell_threshold_value0_suppressed_values_ca.d73f87a6", { value0: threshold })}
>
@@ -229,5 +230,18 @@ export default function AggregateReportsPage({ settings }: {settings: ApiSetting
}
function countValue(count: AggregateReportCount): string | number {
- return count.suppressed ? "Suppressed" : count.value ?? "—";
+ return count.suppressed ? "i18n:govoplan-campaign.suppressed.fce88db5" : count.value ?? "—";
+}
+
+function aggregateCompletionLabel(state: AggregateCampaignReport["completion_state"]): string {
+ const labels: Record = {
+ not_started: "i18n:govoplan-campaign.not_started.db2c45d5",
+ in_progress: "i18n:govoplan-campaign.in_progress.b6bd42e4",
+ completed: "i18n:govoplan-campaign.completed.1798b3ba",
+ partially_completed: "i18n:govoplan-campaign.partially_completed.760bc5e6",
+ incomplete: "i18n:govoplan-campaign.incomplete.387fd1bb",
+ outcome_unknown: "i18n:govoplan-campaign.outcome_unknown.6e929fca",
+ suppressed: "i18n:govoplan-campaign.suppressed.fce88db5"
+ };
+ return labels[state];
}
diff --git a/webui/src/i18n/generatedTranslations.ts b/webui/src/i18n/generatedTranslations.ts
index a79f085..76e74dc 100644
--- a/webui/src/i18n/generatedTranslations.ts
+++ b/webui/src/i18n/generatedTranslations.ts
@@ -21,6 +21,82 @@ export const generatedTranslations: PlatformTranslations = {
"i18n:govoplan-campaign.reconcile_outcomes.bd81d8a7": "Reconcile outcomes",
"i18n:govoplan-campaign.resume_queue.1f22f964": "Resume queue",
"i18n:govoplan-campaign.you_do_not_have_permission_for_this_action.dfcfbad6": "You do not have permission for this action.",
+ "i18n:govoplan-campaign.campaign_reports_available_to_you.f14fa403": "Campaign reports available to you",
+ "i18n:govoplan-campaign.cancelled_value0_unsent_message_s_value1_protect.d24c5e24": "Cancelled {value0} unsent message(s); {value1} protected outcome(s) and {value2} excluded/skipped message(s) were retained.",
+ "i18n:govoplan-campaign.completion.2ff25568": "Completion",
+ "i18n:govoplan-campaign.database_queue.8bf98437": "Database queue",
+ "i18n:govoplan-campaign.delivery_activity_range.0d1b62ec": "Delivery activity range",
+ "i18n:govoplan-campaign.delivery_mode.109ed9d1": "Delivery mode",
+ "i18n:govoplan-campaign.excluded_or_blocked_jobs.e2190d47": "Excluded or blocked jobs",
+ "i18n:govoplan-campaign.excluded_rows_are_intentionally_omitted_from_del.421a1f00": "Excluded rows are intentionally omitted from delivery. Their SMTP and IMAP states are shown as Skipped because no transport effect is attempted; use the separate status filters to isolate them.",
+ "i18n:govoplan-campaign.first_activity.3fe36ef4": "First activity",
+ "i18n:govoplan-campaign.in_progress.b6bd42e4": "In progress",
+ "i18n:govoplan-campaign.inactive_source_entries.88fa0cf8": "Inactive source entries",
+ "i18n:govoplan-campaign.incomplete.387fd1bb": "Incomplete",
+ "i18n:govoplan-campaign.last_activity.1c73b806": "Last activity",
+ "i18n:govoplan-campaign.loading_aggregate_campaign_report_.72f2f091": "Loading aggregate Campaign report…",
+ "i18n:govoplan-campaign.loading_campaign_reports_.61ec1ee8": "Loading Campaign reports…",
+ "i18n:govoplan-campaign.no_aggregate_campaign_reports_are_available_to_y.dafb2781": "No aggregate Campaign reports are available to you.",
+ "i18n:govoplan-campaign.not_started.db2c45d5": "Not started",
+ "i18n:govoplan-campaign.partially_completed.760bc5e6": "Partially completed",
+ "i18n:govoplan-campaign.population_and_exclusions.cdff62ad": "Population and exclusions",
+ "i18n:govoplan-campaign.privacy_boundary.d37e12bc": "Privacy boundary",
+ "i18n:govoplan-campaign.privacy_protected_campaign_outcomes_without_reci.5b8a100d": "Privacy-protected Campaign outcomes without recipient or delivery diagnostics.",
+ "i18n:govoplan-campaign.queued_or_active.afdcd7da": "Queued or active",
+ "i18n:govoplan-campaign.report_denominator.d089074a": "Report denominator",
+ "i18n:govoplan-campaign.small_cell_threshold_value0_suppressed_values_ca.d73f87a6": "Small-cell threshold: {value0}. Suppressed values cannot be opened, filtered, exported, or inspected from this view.",
+ "i18n:govoplan-campaign.smtp_skipped_excluded_.df6eca19": "SMTP skipped (excluded)",
+ "i18n:govoplan-campaign.suppressed.fce88db5": "Suppressed",
+ "i18n:govoplan-campaign.synchronous.77c61919": "Synchronous",
+ "i18n:govoplan-campaign.this_report_is_already_selected_.983c5be4": "This report is already selected.",
+ "i18n:govoplan-campaign.this_version_last_entered_value0_mode_at_value1_.c087d2f3": "This version last entered {value0} mode at {value1}. This record remains available after leaving and returning.",
+ "i18n:govoplan-campaign.this_version_last_entered_value0_mode_this_recor.ea2f201f": "This version last entered {value0} mode. This record remains available after leaving and returning.",
+ "i18n:govoplan-campaign.view_aggregate_report.94b42124": "View aggregate report",
+ "i18n:govoplan-campaign.worker_queue.c911e32c": "Worker queue",
+ "i18n:govoplan-campaign.all_persisted_recipient_delivery_jobs_for_the_se.208e90cc": "All persisted recipient delivery jobs for the selected campaign version, including excluded or blocked jobs. Inactive source entries without a job record are excluded and reported separately.",
+ "i18n:govoplan-campaign.background_workers_are_not_configured_.efa72396": "Background workers are not configured.",
+ "i18n:govoplan-campaign.cancel_all_unsent_delivery_work_.a2f56cda": "Cancel all unsent delivery work?",
+ "i18n:govoplan-campaign.cancel_unsent_work.66df9f0d": "Cancel unsent work",
+ "i18n:govoplan-campaign.cancelling_eligible_delivery_jobs_.4090fa47": "Cancelling eligible delivery jobs…",
+ "i18n:govoplan-campaign.committing_the_reviewed_execution_to_the_backgro.6ae349e2": "Committing the reviewed execution to the background-worker queue…",
+ "i18n:govoplan-campaign.delivery_options_are_still_being_evaluated.8395096e": "delivery options are still being evaluated",
+ "i18n:govoplan-campaign.deployment.327a55f8": "Deployment",
+ "i18n:govoplan-campaign.deployment_ceiling.abbec75b": "Deployment ceiling",
+ "i18n:govoplan-campaign.deployment_default.aa39f7b4": "Deployment default",
+ "i18n:govoplan-campaign.keep_delivery_work.10dbcb13": "Keep delivery work",
+ "i18n:govoplan-campaign.limit_source.bd933adb": "Limit source",
+ "i18n:govoplan-campaign.loading_the_effective_delivery_policy_.d6893011": "Loading the effective delivery policy…",
+ "i18n:govoplan-campaign.no_real_delivery_mode_is_currently_available_val.618cce1f": "No real delivery mode is currently available ({value0}).",
+ "i18n:govoplan-campaign.not_available.d1a17af1": "Not available",
+ "i18n:govoplan-campaign.pause_queued_work.35ab4a5b": "Pause queued work",
+ "i18n:govoplan-campaign.paused_value0_queued_message_s_.c7d568d2": "Paused {value0} queued message(s).",
+ "i18n:govoplan-campaign.pausing_eligible_delivery_jobs_.eb6b9d58": "Pausing eligible delivery jobs…",
+ "i18n:govoplan-campaign.positive_counts_below_the_threshold_are_hidden_a.1dc97093": "Positive counts below the threshold are hidden. At least one additional count or the denominator is hidden when needed to prevent subtraction.",
+ "i18n:govoplan-campaign.queued_value0_message_s_value1_worker_task_s_pub.18d67ec8": "Queued {value0} message(s); {value1} worker task(s) published.",
+ "i18n:govoplan-campaign.queued_value0_retryable_message_s_value1_worker_.f4795bdb": "Queued {value0} retryable message(s); {value1} worker task(s) published.",
+ "i18n:govoplan-campaign.queue_for_workers.dae9a3e4": "Queue for workers",
+ "i18n:govoplan-campaign.queue_for_workers_commits_durable_jobs_and_retur.d0dbe81a": "Queue for workers commits durable jobs and returns immediately; progress remains visible here after you leave. Send now keeps this request open and is limited to {value0} eligible recipient jobs.",
+ "i18n:govoplan-campaign.queue_this_version_for_background_workers_.943d032c": "Queue this version for background workers?",
+ "i18n:govoplan-campaign.queueing_for_workers_.d24584fe": "Queueing for workers…",
+ "i18n:govoplan-campaign.queueing_retryable_failed_messages_for_backgroun.4bc80cd9": "Queueing retryable failed messages for background workers…",
+ "i18n:govoplan-campaign.resume_with_workers.510a2a9a": "Resume with workers",
+ "i18n:govoplan-campaign.resumed_value0_message_s_value1_worker_task_s_pu.0f59afb4": "Resumed {value0} message(s); {value1} worker task(s) published.",
+ "i18n:govoplan-campaign.resuming_eligible_delivery_jobs_.dd12c5a2": "Resuming eligible delivery jobs…",
+ "i18n:govoplan-campaign.retry_failed_with_workers.a4b7dcc5": "Retry failed with workers",
+ "i18n:govoplan-campaign.send_now_is_available_for_value0_eligible_messag.6ec0ed6c": "Send now is available for {value0} eligible message(s), within the effective limit of {value1}. {value2}",
+ "i18n:govoplan-campaign.send_now_is_unavailable_value0_.d93c0b29": "Send now is unavailable: {value0}.",
+ "i18n:govoplan-campaign.send_now_is_unavailable_value0_queue_for_workers.59bfc873": "Send now is unavailable ({value0}). Queue for workers remains available.",
+ "i18n:govoplan-campaign.synchronous_limit.f88c0bcd": "Synchronous limit",
+ "i18n:govoplan-campaign.the_built_run_has_no_eligible_message.48e5410c": "the built run has no eligible message",
+ "i18n:govoplan-campaign.the_configured_maximum.eb10006b": "the configured maximum",
+ "i18n:govoplan-campaign.the_delivery_policy_configuration_is_invalid.a804a8f8": "the delivery policy configuration is invalid",
+ "i18n:govoplan-campaign.the_exact_built_run_exceeds_the_effective_limit_.d7812d6a": "the exact built run exceeds the effective limit for recipient jobs",
+ "i18n:govoplan-campaign.the_worker_queue_is_also_available_.7b77144e": "The worker queue is also available.",
+ "i18n:govoplan-campaign.this_cancels_queued_or_paused_messages_that_have.add583bc": "This cancels queued or paused messages that have not crossed the SMTP boundary. Accepted, active, or outcome-unknown messages remain protected for audit and reconciliation.",
+ "i18n:govoplan-campaign.this_commits_value0_eligible_message_s_from_vers.f53e7222": "This commits {value0} eligible message(s) from version {value1} to durable worker jobs. You may leave this page and return to the same progress and recovery state.",
+ "i18n:govoplan-campaign.validate_lock_build_and_review_the_current_versi.d0567dcc": "validate, lock, build, and review the current version first",
+ "i18n:govoplan-campaign.value0_this_is_a_synchronous_request_for_value1_.0267bc6b": "{value0} This is a synchronous request for {value1} eligible message(s), within the effective limit of {value2}. All messages are preflighted before SMTP is contacted.",
+ "i18n:govoplan-campaign.worker_queue_committed_value0_message_s_and_publ.24400d3c": "Worker queue committed {value0} message(s) and published {value1} task(s). Refreshing progress does not requeue them.",
"i18n:govoplan-campaign.campaign_scoped_mail_profile.9cbf3505": "Campaign-scoped Mail profile",
"i18n:govoplan-campaign.campaign_stores_only_this_stable_profile_referen.de554809": "Campaign stores only this stable profile reference. The Mail module owns, encrypts, authorizes, tests, and resolves all SMTP/IMAP settings and credentials.",
"i18n:govoplan-campaign.configured.668c5fff": "Configured",
@@ -1210,6 +1286,82 @@ export const generatedTranslations: PlatformTranslations = {
"i18n:govoplan-campaign.reconcile_outcomes.bd81d8a7": "Ergebnisse abstimmen",
"i18n:govoplan-campaign.resume_queue.1f22f964": "Warteschlange fortsetzen",
"i18n:govoplan-campaign.you_do_not_have_permission_for_this_action.dfcfbad6": "Sie haben keine Berechtigung für diese Aktion.",
+ "i18n:govoplan-campaign.campaign_reports_available_to_you.f14fa403": "Für Sie verfügbare Kampagnenberichte",
+ "i18n:govoplan-campaign.cancelled_value0_unsent_message_s_value1_protect.d24c5e24": "{value0} ungesendete Nachricht(en) wurden abgebrochen; {value1} geschützte Ergebnisse und {value2} ausgeschlossene/übersprungene Nachricht(en) wurden beibehalten.",
+ "i18n:govoplan-campaign.completion.2ff25568": "Abschluss",
+ "i18n:govoplan-campaign.database_queue.8bf98437": "Datenbank-Warteschlange",
+ "i18n:govoplan-campaign.delivery_activity_range.0d1b62ec": "Zeitraum der Versandaktivität",
+ "i18n:govoplan-campaign.delivery_mode.109ed9d1": "Versandmodus",
+ "i18n:govoplan-campaign.excluded_or_blocked_jobs.e2190d47": "Ausgeschlossene oder blockierte Aufträge",
+ "i18n:govoplan-campaign.excluded_rows_are_intentionally_omitted_from_del.421a1f00": "Ausgeschlossene Zeilen werden absichtlich nicht versendet. Ihr SMTP- und IMAP-Status wird als „Übersprungen“ angezeigt, da kein Transport versucht wird; über die separaten Statusfilter können Sie diese Zeilen gezielt anzeigen.",
+ "i18n:govoplan-campaign.first_activity.3fe36ef4": "Erste Aktivität",
+ "i18n:govoplan-campaign.in_progress.b6bd42e4": "In Bearbeitung",
+ "i18n:govoplan-campaign.inactive_source_entries.88fa0cf8": "Inaktive Quelleinträge",
+ "i18n:govoplan-campaign.incomplete.387fd1bb": "Unvollständig",
+ "i18n:govoplan-campaign.last_activity.1c73b806": "Letzte Aktivität",
+ "i18n:govoplan-campaign.loading_aggregate_campaign_report_.72f2f091": "Aggregierter Kampagnenbericht wird geladen…",
+ "i18n:govoplan-campaign.loading_campaign_reports_.61ec1ee8": "Kampagnenberichte werden geladen…",
+ "i18n:govoplan-campaign.no_aggregate_campaign_reports_are_available_to_y.dafb2781": "Für Sie sind keine aggregierten Kampagnenberichte verfügbar.",
+ "i18n:govoplan-campaign.not_started.db2c45d5": "Nicht begonnen",
+ "i18n:govoplan-campaign.partially_completed.760bc5e6": "Teilweise abgeschlossen",
+ "i18n:govoplan-campaign.population_and_exclusions.cdff62ad": "Grundgesamtheit und Ausschlüsse",
+ "i18n:govoplan-campaign.privacy_boundary.d37e12bc": "Datenschutzgrenze",
+ "i18n:govoplan-campaign.privacy_protected_campaign_outcomes_without_reci.5b8a100d": "Datenschutzgeschützte Kampagnenergebnisse ohne Empfänger- oder Versanddiagnosen.",
+ "i18n:govoplan-campaign.queued_or_active.afdcd7da": "In Warteschlange oder aktiv",
+ "i18n:govoplan-campaign.report_denominator.d089074a": "Bezugsgröße des Berichts",
+ "i18n:govoplan-campaign.small_cell_threshold_value0_suppressed_values_ca.d73f87a6": "Schwellenwert für kleine Fallzahlen: {value0}. Unterdrückte Werte können in dieser Ansicht nicht geöffnet, gefiltert, exportiert oder geprüft werden.",
+ "i18n:govoplan-campaign.smtp_skipped_excluded_.df6eca19": "SMTP übersprungen (ausgeschlossen)",
+ "i18n:govoplan-campaign.suppressed.fce88db5": "Unterdrückt",
+ "i18n:govoplan-campaign.synchronous.77c61919": "Synchron",
+ "i18n:govoplan-campaign.this_report_is_already_selected_.983c5be4": "Dieser Bericht ist bereits ausgewählt.",
+ "i18n:govoplan-campaign.this_version_last_entered_value0_mode_at_value1_.c087d2f3": "Diese Version wechselte zuletzt am {value1} in den Modus „{value0}“. Der Eintrag bleibt auch nach dem Verlassen und erneuten Öffnen verfügbar.",
+ "i18n:govoplan-campaign.this_version_last_entered_value0_mode_this_recor.ea2f201f": "Diese Version wechselte zuletzt in den Modus „{value0}“. Der Eintrag bleibt auch nach dem Verlassen und erneuten Öffnen verfügbar.",
+ "i18n:govoplan-campaign.view_aggregate_report.94b42124": "Aggregierten Bericht anzeigen",
+ "i18n:govoplan-campaign.worker_queue.c911e32c": "Worker-Warteschlange",
+ "i18n:govoplan-campaign.all_persisted_recipient_delivery_jobs_for_the_se.208e90cc": "Alle dauerhaft gespeicherten Empfänger-Versandaufträge der ausgewählten Kampagnenversion werden berücksichtigt, einschließlich ausgeschlossener oder blockierter Aufträge. Inaktive Quelleinträge ohne Auftragsdatensatz sind ausgeschlossen und werden separat ausgewiesen.",
+ "i18n:govoplan-campaign.background_workers_are_not_configured_.efa72396": "Hintergrund-Worker sind nicht konfiguriert.",
+ "i18n:govoplan-campaign.cancel_all_unsent_delivery_work_.a2f56cda": "Alle ungesendeten Versandaufträge abbrechen?",
+ "i18n:govoplan-campaign.cancel_unsent_work.66df9f0d": "Ungesendete Aufträge abbrechen",
+ "i18n:govoplan-campaign.cancelling_eligible_delivery_jobs_.4090fa47": "Geeignete Versandaufträge werden abgebrochen…",
+ "i18n:govoplan-campaign.committing_the_reviewed_execution_to_the_backgro.6ae349e2": "Die geprüfte Ausführung wird an die Hintergrund-Worker-Warteschlange übergeben…",
+ "i18n:govoplan-campaign.delivery_options_are_still_being_evaluated.8395096e": "die Versandoptionen werden noch ausgewertet",
+ "i18n:govoplan-campaign.deployment.327a55f8": "Bereitstellung",
+ "i18n:govoplan-campaign.deployment_ceiling.abbec75b": "Bereitstellungsobergrenze",
+ "i18n:govoplan-campaign.deployment_default.aa39f7b4": "Bereitstellungsstandard",
+ "i18n:govoplan-campaign.keep_delivery_work.10dbcb13": "Versandaufträge beibehalten",
+ "i18n:govoplan-campaign.limit_source.bd933adb": "Quelle des Grenzwerts",
+ "i18n:govoplan-campaign.loading_the_effective_delivery_policy_.d6893011": "Wirksame Versandrichtlinie wird geladen…",
+ "i18n:govoplan-campaign.no_real_delivery_mode_is_currently_available_val.618cce1f": "Derzeit ist kein echter Versandmodus verfügbar ({value0}).",
+ "i18n:govoplan-campaign.not_available.d1a17af1": "Nicht verfügbar",
+ "i18n:govoplan-campaign.pause_queued_work.35ab4a5b": "Wartende Aufträge pausieren",
+ "i18n:govoplan-campaign.paused_value0_queued_message_s_.c7d568d2": "{value0} wartende Nachricht(en) pausiert.",
+ "i18n:govoplan-campaign.pausing_eligible_delivery_jobs_.eb6b9d58": "Geeignete Versandaufträge werden pausiert…",
+ "i18n:govoplan-campaign.positive_counts_below_the_threshold_are_hidden_a.1dc97093": "Positive Anzahlen unterhalb des Schwellenwerts werden ausgeblendet. Falls erforderlich, wird mindestens eine weitere Anzahl oder die Bezugsgröße ausgeblendet, damit keine Rückrechnung möglich ist.",
+ "i18n:govoplan-campaign.queued_value0_message_s_value1_worker_task_s_pub.18d67ec8": "{value0} Nachricht(en) wurden eingereiht; {value1} Worker-Aufgabe(n) wurden veröffentlicht.",
+ "i18n:govoplan-campaign.queued_value0_retryable_message_s_value1_worker_.f4795bdb": "{value0} wiederholbare Nachricht(en) wurden eingereiht; {value1} Worker-Aufgabe(n) wurden veröffentlicht.",
+ "i18n:govoplan-campaign.queue_for_workers.dae9a3e4": "Für Worker einreihen",
+ "i18n:govoplan-campaign.queue_for_workers_commits_durable_jobs_and_retur.d0dbe81a": "Durch das Einreihen für Worker werden dauerhafte Aufträge erstellt und die Aktion kehrt sofort zurück; der Fortschritt bleibt nach dem Verlassen sichtbar. „Jetzt senden“ hält diese Anfrage offen und ist auf {value0} geeignete Empfängeraufträge begrenzt.",
+ "i18n:govoplan-campaign.queue_this_version_for_background_workers_.943d032c": "Diese Version für Hintergrund-Worker einreihen?",
+ "i18n:govoplan-campaign.queueing_for_workers_.d24584fe": "Wird für Worker eingereiht…",
+ "i18n:govoplan-campaign.queueing_retryable_failed_messages_for_backgroun.4bc80cd9": "Wiederholbare fehlgeschlagene Nachrichten werden für Hintergrund-Worker eingereiht…",
+ "i18n:govoplan-campaign.resume_with_workers.510a2a9a": "Mit Workern fortsetzen",
+ "i18n:govoplan-campaign.resumed_value0_message_s_value1_worker_task_s_pu.0f59afb4": "{value0} Nachricht(en) wurden fortgesetzt; {value1} Worker-Aufgabe(n) wurden veröffentlicht.",
+ "i18n:govoplan-campaign.resuming_eligible_delivery_jobs_.dd12c5a2": "Geeignete Versandaufträge werden fortgesetzt…",
+ "i18n:govoplan-campaign.retry_failed_with_workers.a4b7dcc5": "Fehlgeschlagene Aufträge mit Workern wiederholen",
+ "i18n:govoplan-campaign.send_now_is_available_for_value0_eligible_messag.6ec0ed6c": "„Jetzt senden“ ist für {value0} geeignete Nachricht(en) innerhalb des wirksamen Grenzwerts von {value1} verfügbar. {value2}",
+ "i18n:govoplan-campaign.send_now_is_unavailable_value0_.d93c0b29": "„Jetzt senden“ ist nicht verfügbar: {value0}.",
+ "i18n:govoplan-campaign.send_now_is_unavailable_value0_queue_for_workers.59bfc873": "„Jetzt senden“ ist nicht verfügbar ({value0}). Die Worker-Warteschlange bleibt verfügbar.",
+ "i18n:govoplan-campaign.synchronous_limit.f88c0bcd": "Grenzwert für synchronen Versand",
+ "i18n:govoplan-campaign.the_built_run_has_no_eligible_message.48e5410c": "der erstellte Lauf enthält keine geeignete Nachricht",
+ "i18n:govoplan-campaign.the_configured_maximum.eb10006b": "das konfigurierte Maximum",
+ "i18n:govoplan-campaign.the_delivery_policy_configuration_is_invalid.a804a8f8": "die Konfiguration der Versandrichtlinie ist ungültig",
+ "i18n:govoplan-campaign.the_exact_built_run_exceeds_the_effective_limit_.d7812d6a": "der exakt erstellte Lauf überschreitet den wirksamen Grenzwert für Empfängeraufträge",
+ "i18n:govoplan-campaign.the_worker_queue_is_also_available_.7b77144e": "Die Worker-Warteschlange ist ebenfalls verfügbar.",
+ "i18n:govoplan-campaign.this_cancels_queued_or_paused_messages_that_have.add583bc": "Dadurch werden wartende oder pausierte Nachrichten abgebrochen, die die SMTP-Grenze noch nicht überschritten haben. Angenommene, aktive oder ungeklärte Nachrichten bleiben für Audit und Abstimmung geschützt.",
+ "i18n:govoplan-campaign.this_commits_value0_eligible_message_s_from_vers.f53e7222": "Dadurch werden {value0} geeignete Nachricht(en) aus Version {value1} als dauerhafte Worker-Aufträge eingereiht. Sie können diese Seite verlassen und später zum selben Fortschritts- und Wiederherstellungszustand zurückkehren.",
+ "i18n:govoplan-campaign.validate_lock_build_and_review_the_current_versi.d0567dcc": "validieren, sperren, erstellen und prüfen Sie zuerst die aktuelle Version",
+ "i18n:govoplan-campaign.value0_this_is_a_synchronous_request_for_value1_.0267bc6b": "{value0} Dies ist eine synchrone Anfrage für {value1} geeignete Nachricht(en) innerhalb des wirksamen Grenzwerts von {value2}. Alle Nachrichten werden vor dem SMTP-Kontakt vollständig vorgeprüft.",
+ "i18n:govoplan-campaign.worker_queue_committed_value0_message_s_and_publ.24400d3c": "Die Worker-Warteschlange hat {value0} Nachricht(en) übernommen und {value1} Aufgabe(n) veröffentlicht. Eine Fortschrittsaktualisierung reiht sie nicht erneut ein.",
"i18n:govoplan-campaign.campaign_scoped_mail_profile.9cbf3505": "Kampagnenspezifisches Mail-Profil",
"i18n:govoplan-campaign.campaign_stores_only_this_stable_profile_referen.de554809": "Campaign speichert nur diese stabile Profilreferenz. Das Mail-Modul verwaltet, verschlüsselt, autorisiert, testet und löst alle SMTP-/IMAP-Einstellungen und Zugangsdaten auf.",
"i18n:govoplan-campaign.configured.668c5fff": "Konfiguriert",
diff --git a/webui/tests/aggregate-report-ui-structure.test.mjs b/webui/tests/aggregate-report-ui-structure.test.mjs
index ec7e313..ce2194a 100644
--- a/webui/tests/aggregate-report-ui-structure.test.mjs
+++ b/webui/tests/aggregate-report-ui-structure.test.mjs
@@ -1,8 +1,14 @@
import assert from "node:assert/strict";
+import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
const api = readFileSync("src/api/campaigns.ts", "utf8");
const page = readFileSync("src/features/reports/AggregateReportsPage.tsx", "utf8");
+const reportPage = readFileSync("src/features/campaigns/CampaignReportPage.tsx", "utf8");
+const reviewPage = readFileSync("src/features/campaigns/ReviewSendPage.tsx", "utf8");
+const operatorPage = readFileSync("src/features/operator/OperatorQueuePage.tsx", "utf8");
+const deliveryMode = readFileSync("src/features/campaigns/utils/deliveryMode.ts", "utf8");
+const translationCatalog = readFileSync("src/i18n/generatedTranslations.ts", "utf8");
assert(api.includes('"/api/v1/campaigns/aggregate-reports"'), "the report list uses the safe aggregate collection");
assert(api.includes("/api/v1/campaigns/aggregate-reports/${encodeURIComponent(campaignId)}"), "the selected report uses the safe aggregate projection");
@@ -17,5 +23,32 @@ assert(!page.includes("localStorage"), "the aggregate page does not persist repo
assert(!page.includes("sessionStorage"), "the aggregate page does not persist report data in session storage");
assert(page.includes("TableActionGroup"), "campaign selection uses the central icon-only table action group");
assert(page.includes("disabled: campaign.id === selectedFromUrl"), "the selected row action stays visible and disabled");
+assert(!page.includes("{report.population.denominator_definition}"), "the known denominator contract uses a localized UI explanation");
+assert(!page.includes("{report.privacy.rule}"), "the known privacy contract uses a localized UI explanation");
+assert(page.includes("all_persisted_recipient_delivery_jobs_for_the_se.208e90cc"), "the denominator explanation is bilingual");
+assert(page.includes("positive_counts_below_the_threshold_are_hidden_a.1dc97093"), "the suppression rule is bilingual");
+
+const touchedSources = [page, reportPage, reviewPage, operatorPage, deliveryMode].join("\n");
+const touchedKeys = new Set(touchedSources.match(/i18n:govoplan-campaign\.[a-z0-9_]+\.[a-f0-9]{8}/g) ?? []);
+for (const key of touchedKeys) {
+ const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+ const catalogEntries = [...translationCatalog.matchAll(new RegExp(`"${escapedKey}":\\s*("(?:[^"\\\\]|\\\\.)*")`, "g"))];
+ assert.equal(catalogEntries.length, 2, `${key} is present exactly once in both language catalogs`);
+ const english = JSON.parse(catalogEntries[0][1]);
+ const german = JSON.parse(catalogEntries[1][1]);
+ assert.notEqual(english.trim(), "", `${key} has a non-empty English translation`);
+ assert.notEqual(german.trim(), "", `${key} has a non-empty German translation`);
+}
+
+const sliceSections = [...translationCatalog.matchAll(/ "i18n:govoplan-campaign\.campaign_reports_available_to_you\.f14fa403":[\s\S]*? "i18n:govoplan-campaign\.worker_queue_committed_value0_message_s_and_publ\.24400d3c":.*\n/g)];
+assert.equal(sliceSections.length, 2, "the current slice has one contiguous English and German catalog section");
+const newEnglishEntries = [...sliceSections[0][0].matchAll(/"(i18n:govoplan-campaign\.[a-z0-9_]+\.[a-f0-9]{8})":\s*("(?:[^"\\]|\\.)*")/g)];
+for (const [, key, encodedEnglish] of newEnglishEntries) {
+ const english = JSON.parse(encodedEnglish);
+ const digest = createHash("sha1").update(english).digest("hex").slice(0, 8);
+ const slug = english.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+/, "").slice(0, 48);
+ assert.equal(key, `i18n:govoplan-campaign.${slug}.${digest}`, `${key} uses the normalized source slug and exact SHA-1 suffix`);
+ assert(touchedKeys.has(key), `${key} is referenced by the current Campaign UI slices`);
+}
console.log("aggregate report UI structure checks passed");
diff --git a/webui/tests/delivery-mode-ui-structure.test.mjs b/webui/tests/delivery-mode-ui-structure.test.mjs
index 972879a..dda3faf 100644
--- a/webui/tests/delivery-mode-ui-structure.test.mjs
+++ b/webui/tests/delivery-mode-ui-structure.test.mjs
@@ -5,12 +5,22 @@ import { dirname, resolve } from "node:path";
const here = dirname(fileURLToPath(import.meta.url));
const source = readFileSync(resolve(here, "../src/features/campaigns/ReviewSendPage.tsx"), "utf8");
+const modeSource = readFileSync(resolve(here, "../src/features/campaigns/utils/deliveryMode.ts"), "utf8");
assert.match(source, /getCampaignDeliveryOptions/);
-assert.match(source, /Queue for workers/);
-assert.match(source, /Send now keeps this request open/);
+assert.match(source, /queue_for_workers\.dae9a3e4/);
+assert.match(source, /queue_for_workers_commits_durable_jobs_and_retur\.d0dbe81a/);
+assert.match(source, /loading_the_effective_delivery_policy_\.d6893011/);
+assert.match(source, /deliveryControlProgressMessage/);
assert.match(source, /synchronousSendAllowed/);
assert.match(source, /commandInProgress[\s\S]*refreshQueueStatus/);
assert.match(source, / {
const blocks = operatorQueueActionBlocks(everything, noPermissions);
assert.deepEqual(
Object.values(blocks),
- Array.from({ length: 7 }, () => OPERATOR_QUEUE_REASON.permission)
+ Array.from({ length: 7 }, () => OPERATOR_QUEUE_REASON.permissionDenied)
);
});
diff --git a/webui/tests/report-grid-query.test.ts b/webui/tests/report-grid-query.test.ts
index fa08408..abdec48 100644
--- a/webui/tests/report-grid-query.test.ts
+++ b/webui/tests/report-grid-query.test.ts
@@ -41,7 +41,8 @@ assert(reportSource.includes("onQueryChange={handleJobGridQuery}"), "header sort
assert(reportSource.includes("initialReportGridFilters()"), "status deep links initialize the DataGrid filters");
assert(reportSource.includes("initialReportQuery()"), "q deep links initialize the report search");
assert(reportSource.includes('"skipped",\n"queued"'), "SMTP skipped is a first-class report filter option");
-assert(reportSource.includes("Excluded rows are intentionally omitted from delivery"), "the report explains excluded transport semantics");
+assert(reportSource.includes("i18n:govoplan-campaign.excluded_rows_are_intentionally_omitted_from_del.421a1f00"), "the report explains excluded transport semantics through the bilingual catalog");
+assert(reportSource.includes('return status === "skipped" ? "i18n:govoplan-campaign.skipped.5a000ad7"'), "the new skipped filter and status badges use the localized label");
assert(reportSource.includes("cards?.skipped ?? jobs.counts.send?.skipped"), "SMTP skipped has a separate report count");
assert(reportSource.includes("cards?.imap_skipped ?? jobs.counts.imap?.skipped"), "IMAP skipped has a separate report count");
assert(!reportSource.includes("setPage((value) => Math.max(1, value - 1))"), "the one-off report pager is removed in favor of the central DataGrid pager");