fix(i18n): sweep activity-type translations + smart notification fallback
The admin notification bell and dashboard "Recent Activities" panel were
showing raw snake_case keys ("event_published") or the generic
"Systemaktivität: <type>" fallback for ~65 activity types — most of them
from the CRM and Accounting modules added since #555. Users with German
locale saw the gap most visibly because the English placeholder leaked
through.
Three pieces:
1. notifications.service.ts — smart `default:` branch. Instead of falling
straight to the systemActivity template, derive the camelCase i18n key
from the snake_case type, try resolving `admin.notificationMessages.<camelCase>`
directly with the full metadata spread as params, and only drop to the
legacy template when no specific translation exists. This means every
future activity type just needs an i18n entry — no per-type switch
case to add.
2. en.json + de.json — added 65 missing `admin.notificationMessages.*`
bell entries and 58 missing `admin.activities.*` dashboard entries
across both locales. Covers Contracts (13), Quotes (7), Invoices /
Storno (12), Monthly billing (5), Expenses (4), Hours (5), Incoming
invoices (6), Customers (1), Admin user mgmt (3), and 9 misc /
legacy types (bulk_archive_completed, email_resent, email_queue_flushed,
email_template_created, event_duplicated, feedback_deleted,
feedback_moderated, feedback_settings_updated, word_filter_added).
Both locales finish symmetrical (149 activities / 136 notifications
each, vs. 91 / 71 before).
3. admin.service.ts `formatActivityMessage` messages dict — added the
same 58 English-only entries as a last-resort fallback for the
dashboard when i18n itself fails to load. Keeps the surface
resilient against bundle-load issues.
Metadata field names in the new translations match what the backend
writes via `logActivity()` — `{{contractNumber}}`, `{{quoteNumber}}`,
`{{invoiceNumber}}`, `{{username}}`, `{{template_key}}`,
`{{source_event_name}}`, `{{word}}` — verified against the call sites
in contractService, quoteService, invoiceService, userManagementService,
expenseService, adminEvents, adminEmail, adminFeedback.
DE wording authored natively; tone matches the existing terse,
maintainer-voice style of the rest of the file.
This commit is contained in:
@@ -2169,7 +2169,72 @@
|
||||
"categoryHeroUpdated": "Kategorie-Titelbild aktualisiert",
|
||||
"publicSiteResetToDefault": "Öffentliche Seite auf Standard zurückgesetzt",
|
||||
"cmsPageLogoUploaded": "CMS-Seiten-Logo hochgeladen: {{slug}}",
|
||||
"adminPasswordResetByAdmin": "Admin-Passwort durch anderen Admin zurückgesetzt: {{username}}"
|
||||
"adminPasswordResetByAdmin": "Admin-Passwort durch anderen Admin zurückgesetzt: {{username}}",
|
||||
"contractCreated": "Vertrag erstellt: {{contractNumber}}",
|
||||
"contractCreatedFromQuote": "Vertrag aus Angebot erstellt: {{contractNumber}}",
|
||||
"contractUpdated": "Vertrag aktualisiert: {{contractNumber}}",
|
||||
"contractSent": "Vertrag gesendet: {{contractNumber}}",
|
||||
"contractResentSigned": "Unterschriebener Vertrag erneut gesendet: {{contractNumber}}",
|
||||
"contractSignedByCustomer": "Vertrag vom Kunden unterschrieben: {{contractNumber}}",
|
||||
"contractSignedPdfUploaded": "Unterschriebenes Vertrag-PDF hochgeladen: {{contractNumber}}",
|
||||
"contractSignaturesRestamped": "Vertragsunterschriften neu gestempelt: {{contractNumber}}",
|
||||
"contractCancelled": "Vertrag storniert: {{contractNumber}}",
|
||||
"contractConvertedToEvent": "Vertrag in Event umgewandelt: {{contractNumber}}",
|
||||
"contractConvertedToEmptyEvent": "Vertrag in leeres Event umgewandelt: {{contractNumber}}",
|
||||
"contractConvertedToInvoices": "Vertrag in Rechnungen umgewandelt: {{contractNumber}}",
|
||||
"contractConvertedToEmptyInvoice": "Vertrag in leere Rechnung umgewandelt: {{contractNumber}}",
|
||||
"quoteCreated": "Angebot erstellt: {{quoteNumber}}",
|
||||
"quoteSent": "Angebot gesendet: {{quoteNumber}}",
|
||||
"quoteUpdated": "Angebot aktualisiert: {{quoteNumber}}",
|
||||
"quoteAcceptedByAdmin": "Angebot angenommen: {{quoteNumber}}",
|
||||
"quoteDeclinedByAdmin": "Angebot abgelehnt: {{quoteNumber}}",
|
||||
"quoteConverted": "Angebot umgewandelt: {{quoteNumber}}",
|
||||
"quoteConvertedInvoicesOnly": "Angebot in Rechnungen umgewandelt: {{quoteNumber}}",
|
||||
"invoiceCreated": "Rechnung erstellt: {{invoiceNumber}}",
|
||||
"invoiceSent": "Rechnung gesendet: {{invoiceNumber}}",
|
||||
"invoiceScheduled": "Rechnung geplant: {{invoiceNumber}}",
|
||||
"invoiceCancelled": "Rechnung storniert: {{invoiceNumber}}",
|
||||
"invoiceCancelledViaStorno": "Rechnung per Storno storniert: {{invoiceNumber}}",
|
||||
"invoiceReissued": "Rechnung neu ausgestellt: {{invoiceNumber}}",
|
||||
"invoicePaidAdminNotified": "Rechnung als bezahlt markiert: {{invoiceNumber}}",
|
||||
"invoicePaymentCheckRecorded": "Zahlungsprüfung erfasst für Rechnung: {{invoiceNumber}}",
|
||||
"invoicePaymentCheckSent": "Zahlungsprüfung gesendet für Rechnung: {{invoiceNumber}}",
|
||||
"invoiceReleasedForDelivery": "Rechnung zur Lieferung freigegeben: {{invoiceNumber}}",
|
||||
"invoiceReminderSent": "Rechnungserinnerung gesendet: {{invoiceNumber}}",
|
||||
"stornoSent": "Storno gesendet: {{invoiceNumber}}",
|
||||
"monthlyBillIssued": "Monatsrechnung für Kunden ausgestellt",
|
||||
"monthlyBillSkippedEmpty": "Monatsrechnung übersprungen (keine Einträge)",
|
||||
"monthlyBillTriggeredManually": "Monatsrechnung manuell ausgelöst",
|
||||
"monthlyBillingItemsQueued": "Monatsabrechnungsposten in Warteschlange",
|
||||
"installmentPlanUpdated": "Ratenplan aktualisiert",
|
||||
"expenseCreated": "Ausgabe erstellt",
|
||||
"expenseUpdated": "Ausgabe aktualisiert",
|
||||
"expensePaid": "Ausgabe als bezahlt markiert",
|
||||
"expenseInvoiced": "Ausgabe in Rechnung gestellt",
|
||||
"hourEntryLogged": "Stundeneintrag erfasst",
|
||||
"hourEntryUpdated": "Stundeneintrag aktualisiert",
|
||||
"hourEntryDeleted": "Stundeneintrag gelöscht",
|
||||
"hourEntryLoggedToMonthlyDraft": "Stundeneintrag in Monatsentwurf erfasst",
|
||||
"hourEntriesBilled": "Stundeneinträge an Kunden abgerechnet",
|
||||
"incomingInvoiceCaptured": "Eingangsrechnung erfasst",
|
||||
"incomingInvoiceCategorized": "Eingangsrechnung kategorisiert",
|
||||
"incomingInvoiceUpdated": "Eingangsrechnung aktualisiert",
|
||||
"incomingInvoiceRebilled": "Eingangsrechnung an Kunden weiterverrechnet",
|
||||
"incomingInvoiceSupplierPayment": "Lieferantenzahlung erfasst",
|
||||
"incomingMailConfigUpdated": "Eingangs-Mail-Konfiguration aktualisiert",
|
||||
"customerCreatedPassive": "Passiver Kunde erstellt: {{email}}",
|
||||
"adminUserActivated": "Admin-Konto aktiviert: {{username}}",
|
||||
"adminUserDeleted": "Admin-Konto gelöscht: {{username}}",
|
||||
"adminPasswordReset": "Admin-Passwort zurückgesetzt: {{username}}",
|
||||
"bulkArchiveCompleted": "Massen-Archivierung abgeschlossen: {{count}} Events archiviert",
|
||||
"emailQueueFlushed": "E-Mail-Warteschlange geleert",
|
||||
"emailResent": "Erstellungs-E-Mail erneut gesendet für {{eventName}}",
|
||||
"emailTemplateCreated": "E-Mail-Vorlage erstellt: {{template_key}}",
|
||||
"eventDuplicated": "Event dupliziert aus {{source_event_name}}",
|
||||
"feedbackDeleted": "Feedback gelöscht",
|
||||
"feedbackModerated": "Feedback moderiert",
|
||||
"feedbackSettingsUpdated": "Feedback-Einstellungen aktualisiert für {{eventName}}",
|
||||
"wordFilterAdded": "Wortfilter hinzugefügt: {{word}}"
|
||||
},
|
||||
"notificationToasts": {
|
||||
"markedAllRead": "Alle Benachrichtigungen als gelesen markiert",
|
||||
@@ -2364,7 +2429,65 @@
|
||||
"photo_uploaded": "Foto hochgeladen in {{eventName}}",
|
||||
"category_hero_updated": "Kategorie-Titelbild aktualisiert",
|
||||
"public_site_reset_to_default": "Öffentliche Seite auf Standard zurückgesetzt",
|
||||
"cms_page_logo_uploaded": "CMS-Seiten-Logo hochgeladen: {{slug}}"
|
||||
"cms_page_logo_uploaded": "CMS-Seiten-Logo hochgeladen: {{slug}}",
|
||||
"contract_created": "Vertrag erstellt: {{contractNumber}}",
|
||||
"contract_created_from_quote": "Vertrag aus Angebot erstellt: {{contractNumber}}",
|
||||
"contract_updated": "Vertrag aktualisiert: {{contractNumber}}",
|
||||
"contract_sent": "Vertrag gesendet: {{contractNumber}}",
|
||||
"contract_resent_signed": "Unterschriebener Vertrag erneut gesendet: {{contractNumber}}",
|
||||
"contract_signed_by_customer": "Vertrag vom Kunden unterschrieben: {{contractNumber}}",
|
||||
"contract_signed_pdf_uploaded": "Unterschriebenes Vertrag-PDF hochgeladen: {{contractNumber}}",
|
||||
"contract_signatures_restamped": "Vertragsunterschriften neu gestempelt: {{contractNumber}}",
|
||||
"contract_cancelled": "Vertrag storniert: {{contractNumber}}",
|
||||
"contract_converted_to_event": "Vertrag in Event umgewandelt: {{contractNumber}}",
|
||||
"contract_converted_to_empty_event": "Vertrag in leeres Event umgewandelt: {{contractNumber}}",
|
||||
"contract_converted_to_invoices": "Vertrag in Rechnungen umgewandelt: {{contractNumber}}",
|
||||
"contract_converted_to_empty_invoice": "Vertrag in leere Rechnung umgewandelt: {{contractNumber}}",
|
||||
"quote_created": "Angebot erstellt: {{quoteNumber}}",
|
||||
"quote_sent": "Angebot gesendet: {{quoteNumber}}",
|
||||
"quote_updated": "Angebot aktualisiert: {{quoteNumber}}",
|
||||
"quote_accepted_by_admin": "Angebot angenommen: {{quoteNumber}}",
|
||||
"quote_declined_by_admin": "Angebot abgelehnt: {{quoteNumber}}",
|
||||
"quote_converted": "Angebot umgewandelt: {{quoteNumber}}",
|
||||
"quote_converted_invoices_only": "Angebot in Rechnungen umgewandelt: {{quoteNumber}}",
|
||||
"invoice_created": "Rechnung erstellt: {{invoiceNumber}}",
|
||||
"invoice_sent": "Rechnung gesendet: {{invoiceNumber}}",
|
||||
"invoice_scheduled": "Rechnung geplant: {{invoiceNumber}}",
|
||||
"invoice_cancelled": "Rechnung storniert: {{invoiceNumber}}",
|
||||
"invoice_cancelled_via_storno": "Rechnung per Storno storniert: {{invoiceNumber}}",
|
||||
"invoice_reissued": "Rechnung neu ausgestellt: {{invoiceNumber}}",
|
||||
"invoice_paid_admin_notified": "Rechnung als bezahlt markiert: {{invoiceNumber}}",
|
||||
"invoice_payment_check_recorded": "Zahlungsprüfung erfasst für Rechnung: {{invoiceNumber}}",
|
||||
"invoice_payment_check_sent": "Zahlungsprüfung gesendet für Rechnung: {{invoiceNumber}}",
|
||||
"invoice_released_for_delivery": "Rechnung zur Lieferung freigegeben: {{invoiceNumber}}",
|
||||
"invoice_reminder_sent": "Rechnungserinnerung gesendet: {{invoiceNumber}}",
|
||||
"storno_sent": "Storno gesendet: {{invoiceNumber}}",
|
||||
"monthly_bill_issued": "Monatsrechnung für Kunden ausgestellt",
|
||||
"monthly_bill_skipped_empty": "Monatsrechnung übersprungen (keine Einträge)",
|
||||
"monthly_bill_triggered_manually": "Monatsrechnung manuell ausgelöst",
|
||||
"monthly_billing_items_queued": "Monatsabrechnungsposten in Warteschlange",
|
||||
"installment_plan_updated": "Ratenplan aktualisiert",
|
||||
"expense_created": "Ausgabe erstellt",
|
||||
"expense_updated": "Ausgabe aktualisiert",
|
||||
"expense_paid": "Ausgabe als bezahlt markiert",
|
||||
"expense_invoiced": "Ausgabe in Rechnung gestellt",
|
||||
"hour_entry_logged": "Stundeneintrag erfasst",
|
||||
"hour_entry_updated": "Stundeneintrag aktualisiert",
|
||||
"hour_entry_deleted": "Stundeneintrag gelöscht",
|
||||
"hour_entry_logged_to_monthly_draft": "Stundeneintrag in Monatsentwurf erfasst",
|
||||
"hour_entries_billed": "Stundeneinträge an Kunden abgerechnet",
|
||||
"incoming_invoice_captured": "Eingangsrechnung erfasst",
|
||||
"incoming_invoice_categorized": "Eingangsrechnung kategorisiert",
|
||||
"incoming_invoice_updated": "Eingangsrechnung aktualisiert",
|
||||
"incoming_invoice_rebilled": "Eingangsrechnung an Kunden weiterverrechnet",
|
||||
"incoming_invoice_supplier_payment": "Lieferantenzahlung erfasst",
|
||||
"incoming_mail_config_updated": "Eingangs-Mail-Konfiguration aktualisiert",
|
||||
"customer_created_passive": "Passiver Kunde erstellt: {{email}}",
|
||||
"admin_user_activated": "Admin-Konto aktiviert: {{username}}",
|
||||
"admin_user_deleted": "Admin-Konto gelöscht: {{username}}",
|
||||
"email_queue_flushed": "E-Mail-Warteschlange geleert",
|
||||
"email_template_created": "E-Mail-Vorlage erstellt: {{template_key}}",
|
||||
"event_duplicated": "Event dupliziert aus {{source_event_name}}"
|
||||
}
|
||||
},
|
||||
"acceptInvitation": {
|
||||
@@ -3922,10 +4045,15 @@
|
||||
"settingsSaved": "Zuordnungen gespeichert.",
|
||||
"saveDefaults": "Zuordnungen speichern",
|
||||
"accountType": {
|
||||
"asset": "Aktiven", "liability": "Passiven", "equity": "Eigenkapital", "revenue": "Ertrag", "expense": "Aufwand"
|
||||
"asset": "Aktiven",
|
||||
"liability": "Passiven",
|
||||
"equity": "Eigenkapital",
|
||||
"revenue": "Ertrag",
|
||||
"expense": "Aufwand"
|
||||
},
|
||||
"vatDirection": {
|
||||
"input": "Vorsteuer", "output": "Umsatzsteuer"
|
||||
"input": "Vorsteuer",
|
||||
"output": "Umsatzsteuer"
|
||||
},
|
||||
"defaults": {
|
||||
"title": "Standard- & Systemkonten",
|
||||
@@ -3940,20 +4068,40 @@
|
||||
"ledger_account_per_diem": "Spesenpauschalen-Konto",
|
||||
"ledger_account_rebilled_revenue": "Weiterverrechnete Spesen (Ertrag)"
|
||||
},
|
||||
"vatMap": { "title": "MWST-Code nach steuerlicher Behandlung (Kosten)" },
|
||||
"outputVatMap": { "title": "MWST-Code nach Umsatzsatz", "empty": "Fügen Sie oben Ausgangs-MWST-Codes hinzu, um pro Umsatzsatz einen Code festzulegen." },
|
||||
"categoryMap": { "title": "Aufwandkategorie → Konto" },
|
||||
"accounts": { "title": "Kontenplan" },
|
||||
"vatCodes": { "title": "MWST-Codes" },
|
||||
"vatMap": {
|
||||
"title": "MWST-Code nach steuerlicher Behandlung (Kosten)"
|
||||
},
|
||||
"outputVatMap": {
|
||||
"title": "MWST-Code nach Umsatzsatz",
|
||||
"empty": "Fügen Sie oben Ausgangs-MWST-Codes hinzu, um pro Umsatzsatz einen Code festzulegen."
|
||||
},
|
||||
"categoryMap": {
|
||||
"title": "Aufwandkategorie → Konto"
|
||||
},
|
||||
"accounts": {
|
||||
"title": "Kontenplan"
|
||||
},
|
||||
"vatCodes": {
|
||||
"title": "MWST-Codes"
|
||||
},
|
||||
"account": {
|
||||
"addTitle": "Konto hinzufügen", "editTitle": "Konto bearbeiten",
|
||||
"number": "Kontonummer", "name": "Name", "type": "Art",
|
||||
"addTitle": "Konto hinzufügen",
|
||||
"editTitle": "Konto bearbeiten",
|
||||
"number": "Kontonummer",
|
||||
"name": "Name",
|
||||
"type": "Art",
|
||||
"confirmDelete": "Dieses Konto löschen?"
|
||||
},
|
||||
"vat": {
|
||||
"addTitle": "MWST-Code hinzufügen", "editTitle": "MWST-Code bearbeiten",
|
||||
"code": "Code", "name": "Name", "rate": "Satz %", "direction": "Richtung",
|
||||
"account": "MWST-Konto", "noAccount": "— keines —", "confirmDelete": "Diesen MWST-Code löschen?"
|
||||
"addTitle": "MWST-Code hinzufügen",
|
||||
"editTitle": "MWST-Code bearbeiten",
|
||||
"code": "Code",
|
||||
"name": "Name",
|
||||
"rate": "Satz %",
|
||||
"direction": "Richtung",
|
||||
"account": "MWST-Konto",
|
||||
"noAccount": "— keines —",
|
||||
"confirmDelete": "Diesen MWST-Code löschen?"
|
||||
},
|
||||
"export": {
|
||||
"title": "Treuhänder-Export",
|
||||
|
||||
@@ -1756,7 +1756,72 @@
|
||||
"categoryHeroUpdated": "Category hero photo updated",
|
||||
"publicSiteResetToDefault": "Public site reset to default",
|
||||
"cmsPageLogoUploaded": "CMS page logo uploaded: {{slug}}",
|
||||
"adminPasswordResetByAdmin": "Admin password reset by another admin: {{username}}"
|
||||
"adminPasswordResetByAdmin": "Admin password reset by another admin: {{username}}",
|
||||
"contractCreated": "Contract created: {{contractNumber}}",
|
||||
"contractCreatedFromQuote": "Contract created from quote: {{contractNumber}}",
|
||||
"contractUpdated": "Contract updated: {{contractNumber}}",
|
||||
"contractSent": "Contract sent: {{contractNumber}}",
|
||||
"contractResentSigned": "Signed contract resent: {{contractNumber}}",
|
||||
"contractSignedByCustomer": "Contract signed by customer: {{contractNumber}}",
|
||||
"contractSignedPdfUploaded": "Signed contract PDF uploaded: {{contractNumber}}",
|
||||
"contractSignaturesRestamped": "Contract signatures re-stamped: {{contractNumber}}",
|
||||
"contractCancelled": "Contract cancelled: {{contractNumber}}",
|
||||
"contractConvertedToEvent": "Contract converted to event: {{contractNumber}}",
|
||||
"contractConvertedToEmptyEvent": "Contract converted to empty event: {{contractNumber}}",
|
||||
"contractConvertedToInvoices": "Contract converted to invoices: {{contractNumber}}",
|
||||
"contractConvertedToEmptyInvoice": "Contract converted to empty invoice: {{contractNumber}}",
|
||||
"quoteCreated": "Quote created: {{quoteNumber}}",
|
||||
"quoteSent": "Quote sent: {{quoteNumber}}",
|
||||
"quoteUpdated": "Quote updated: {{quoteNumber}}",
|
||||
"quoteAcceptedByAdmin": "Quote accepted: {{quoteNumber}}",
|
||||
"quoteDeclinedByAdmin": "Quote declined: {{quoteNumber}}",
|
||||
"quoteConverted": "Quote converted: {{quoteNumber}}",
|
||||
"quoteConvertedInvoicesOnly": "Quote converted to invoices: {{quoteNumber}}",
|
||||
"invoiceCreated": "Invoice created: {{invoiceNumber}}",
|
||||
"invoiceSent": "Invoice sent: {{invoiceNumber}}",
|
||||
"invoiceScheduled": "Invoice scheduled: {{invoiceNumber}}",
|
||||
"invoiceCancelled": "Invoice cancelled: {{invoiceNumber}}",
|
||||
"invoiceCancelledViaStorno": "Invoice cancelled via Storno: {{invoiceNumber}}",
|
||||
"invoiceReissued": "Invoice reissued: {{invoiceNumber}}",
|
||||
"invoicePaidAdminNotified": "Invoice marked paid: {{invoiceNumber}}",
|
||||
"invoicePaymentCheckRecorded": "Payment-check recorded for invoice: {{invoiceNumber}}",
|
||||
"invoicePaymentCheckSent": "Payment-check sent for invoice: {{invoiceNumber}}",
|
||||
"invoiceReleasedForDelivery": "Invoice released for delivery: {{invoiceNumber}}",
|
||||
"invoiceReminderSent": "Invoice reminder sent: {{invoiceNumber}}",
|
||||
"stornoSent": "Storno sent: {{invoiceNumber}}",
|
||||
"monthlyBillIssued": "Monthly bill issued for customer",
|
||||
"monthlyBillSkippedEmpty": "Monthly bill skipped (no entries)",
|
||||
"monthlyBillTriggeredManually": "Monthly bill triggered manually",
|
||||
"monthlyBillingItemsQueued": "Monthly billing items queued",
|
||||
"installmentPlanUpdated": "Installment plan updated",
|
||||
"expenseCreated": "Expense created",
|
||||
"expenseUpdated": "Expense updated",
|
||||
"expensePaid": "Expense marked paid",
|
||||
"expenseInvoiced": "Expense invoiced",
|
||||
"hourEntryLogged": "Hour entry logged",
|
||||
"hourEntryUpdated": "Hour entry updated",
|
||||
"hourEntryDeleted": "Hour entry deleted",
|
||||
"hourEntryLoggedToMonthlyDraft": "Hour entry logged to monthly draft",
|
||||
"hourEntriesBilled": "Hour entries billed to customer",
|
||||
"incomingInvoiceCaptured": "Incoming invoice captured",
|
||||
"incomingInvoiceCategorized": "Incoming invoice categorised",
|
||||
"incomingInvoiceUpdated": "Incoming invoice updated",
|
||||
"incomingInvoiceRebilled": "Incoming invoice re-billed to customer",
|
||||
"incomingInvoiceSupplierPayment": "Supplier payment recorded",
|
||||
"incomingMailConfigUpdated": "Incoming mail configuration updated",
|
||||
"customerCreatedPassive": "Passive customer created: {{email}}",
|
||||
"adminUserActivated": "Admin user activated: {{username}}",
|
||||
"adminUserDeleted": "Admin user deleted: {{username}}",
|
||||
"adminPasswordReset": "Admin password reset: {{username}}",
|
||||
"bulkArchiveCompleted": "Bulk archive completed: {{count}} events archived",
|
||||
"emailQueueFlushed": "Email queue flushed",
|
||||
"emailResent": "Creation email resent for {{eventName}}",
|
||||
"emailTemplateCreated": "Email template created: {{template_key}}",
|
||||
"eventDuplicated": "Event duplicated from {{source_event_name}}",
|
||||
"feedbackDeleted": "Feedback deleted",
|
||||
"feedbackModerated": "Feedback moderated",
|
||||
"feedbackSettingsUpdated": "Feedback settings updated for {{eventName}}",
|
||||
"wordFilterAdded": "Word filter added: {{word}}"
|
||||
},
|
||||
"notificationToasts": {
|
||||
"markedAllRead": "All notifications marked as read",
|
||||
@@ -1953,7 +2018,65 @@
|
||||
"photo_uploaded": "Photo uploaded to {{eventName}}",
|
||||
"category_hero_updated": "Category hero photo updated",
|
||||
"public_site_reset_to_default": "Public site reset to default",
|
||||
"cms_page_logo_uploaded": "CMS page logo uploaded: {{slug}}"
|
||||
"cms_page_logo_uploaded": "CMS page logo uploaded: {{slug}}",
|
||||
"contract_created": "Contract created: {{contractNumber}}",
|
||||
"contract_created_from_quote": "Contract created from quote: {{contractNumber}}",
|
||||
"contract_updated": "Contract updated: {{contractNumber}}",
|
||||
"contract_sent": "Contract sent: {{contractNumber}}",
|
||||
"contract_resent_signed": "Signed contract resent: {{contractNumber}}",
|
||||
"contract_signed_by_customer": "Contract signed by customer: {{contractNumber}}",
|
||||
"contract_signed_pdf_uploaded": "Signed contract PDF uploaded: {{contractNumber}}",
|
||||
"contract_signatures_restamped": "Contract signatures re-stamped: {{contractNumber}}",
|
||||
"contract_cancelled": "Contract cancelled: {{contractNumber}}",
|
||||
"contract_converted_to_event": "Contract converted to event: {{contractNumber}}",
|
||||
"contract_converted_to_empty_event": "Contract converted to empty event: {{contractNumber}}",
|
||||
"contract_converted_to_invoices": "Contract converted to invoices: {{contractNumber}}",
|
||||
"contract_converted_to_empty_invoice": "Contract converted to empty invoice: {{contractNumber}}",
|
||||
"quote_created": "Quote created: {{quoteNumber}}",
|
||||
"quote_sent": "Quote sent: {{quoteNumber}}",
|
||||
"quote_updated": "Quote updated: {{quoteNumber}}",
|
||||
"quote_accepted_by_admin": "Quote accepted: {{quoteNumber}}",
|
||||
"quote_declined_by_admin": "Quote declined: {{quoteNumber}}",
|
||||
"quote_converted": "Quote converted: {{quoteNumber}}",
|
||||
"quote_converted_invoices_only": "Quote converted to invoices: {{quoteNumber}}",
|
||||
"invoice_created": "Invoice created: {{invoiceNumber}}",
|
||||
"invoice_sent": "Invoice sent: {{invoiceNumber}}",
|
||||
"invoice_scheduled": "Invoice scheduled: {{invoiceNumber}}",
|
||||
"invoice_cancelled": "Invoice cancelled: {{invoiceNumber}}",
|
||||
"invoice_cancelled_via_storno": "Invoice cancelled via Storno: {{invoiceNumber}}",
|
||||
"invoice_reissued": "Invoice reissued: {{invoiceNumber}}",
|
||||
"invoice_paid_admin_notified": "Invoice marked paid: {{invoiceNumber}}",
|
||||
"invoice_payment_check_recorded": "Payment-check recorded for invoice: {{invoiceNumber}}",
|
||||
"invoice_payment_check_sent": "Payment-check sent for invoice: {{invoiceNumber}}",
|
||||
"invoice_released_for_delivery": "Invoice released for delivery: {{invoiceNumber}}",
|
||||
"invoice_reminder_sent": "Invoice reminder sent: {{invoiceNumber}}",
|
||||
"storno_sent": "Storno sent: {{invoiceNumber}}",
|
||||
"monthly_bill_issued": "Monthly bill issued for customer",
|
||||
"monthly_bill_skipped_empty": "Monthly bill skipped (no entries)",
|
||||
"monthly_bill_triggered_manually": "Monthly bill triggered manually",
|
||||
"monthly_billing_items_queued": "Monthly billing items queued",
|
||||
"installment_plan_updated": "Installment plan updated",
|
||||
"expense_created": "Expense created",
|
||||
"expense_updated": "Expense updated",
|
||||
"expense_paid": "Expense marked paid",
|
||||
"expense_invoiced": "Expense invoiced",
|
||||
"hour_entry_logged": "Hour entry logged",
|
||||
"hour_entry_updated": "Hour entry updated",
|
||||
"hour_entry_deleted": "Hour entry deleted",
|
||||
"hour_entry_logged_to_monthly_draft": "Hour entry logged to monthly draft",
|
||||
"hour_entries_billed": "Hour entries billed to customer",
|
||||
"incoming_invoice_captured": "Incoming invoice captured",
|
||||
"incoming_invoice_categorized": "Incoming invoice categorised",
|
||||
"incoming_invoice_updated": "Incoming invoice updated",
|
||||
"incoming_invoice_rebilled": "Incoming invoice re-billed to customer",
|
||||
"incoming_invoice_supplier_payment": "Supplier payment recorded",
|
||||
"incoming_mail_config_updated": "Incoming mail configuration updated",
|
||||
"customer_created_passive": "Passive customer created: {{email}}",
|
||||
"admin_user_activated": "Admin user activated: {{username}}",
|
||||
"admin_user_deleted": "Admin user deleted: {{username}}",
|
||||
"email_queue_flushed": "Email queue flushed",
|
||||
"email_template_created": "Email template created: {{template_key}}",
|
||||
"event_duplicated": "Event duplicated from {{source_event_name}}"
|
||||
}
|
||||
},
|
||||
"acceptInvitation": {
|
||||
@@ -3922,10 +4045,15 @@
|
||||
"settingsSaved": "Mappings saved.",
|
||||
"saveDefaults": "Save mappings",
|
||||
"accountType": {
|
||||
"asset": "Asset", "liability": "Liability", "equity": "Equity", "revenue": "Revenue", "expense": "Expense"
|
||||
"asset": "Asset",
|
||||
"liability": "Liability",
|
||||
"equity": "Equity",
|
||||
"revenue": "Revenue",
|
||||
"expense": "Expense"
|
||||
},
|
||||
"vatDirection": {
|
||||
"input": "Input (Vorsteuer)", "output": "Output (Umsatzsteuer)"
|
||||
"input": "Input (Vorsteuer)",
|
||||
"output": "Output (Umsatzsteuer)"
|
||||
},
|
||||
"defaults": {
|
||||
"title": "Default & system accounts",
|
||||
@@ -3940,20 +4068,40 @@
|
||||
"ledger_account_per_diem": "Per-diem account",
|
||||
"ledger_account_rebilled_revenue": "Re-billed expenses (revenue)"
|
||||
},
|
||||
"vatMap": { "title": "VAT code by tax treatment (costs)" },
|
||||
"outputVatMap": { "title": "VAT code by revenue rate", "empty": "Add output VAT codes above to configure a code per revenue rate." },
|
||||
"categoryMap": { "title": "Expense category → account" },
|
||||
"accounts": { "title": "Chart of accounts" },
|
||||
"vatCodes": { "title": "VAT codes" },
|
||||
"vatMap": {
|
||||
"title": "VAT code by tax treatment (costs)"
|
||||
},
|
||||
"outputVatMap": {
|
||||
"title": "VAT code by revenue rate",
|
||||
"empty": "Add output VAT codes above to configure a code per revenue rate."
|
||||
},
|
||||
"categoryMap": {
|
||||
"title": "Expense category → account"
|
||||
},
|
||||
"accounts": {
|
||||
"title": "Chart of accounts"
|
||||
},
|
||||
"vatCodes": {
|
||||
"title": "VAT codes"
|
||||
},
|
||||
"account": {
|
||||
"addTitle": "Add account", "editTitle": "Edit account",
|
||||
"number": "Account number", "name": "Name", "type": "Type",
|
||||
"addTitle": "Add account",
|
||||
"editTitle": "Edit account",
|
||||
"number": "Account number",
|
||||
"name": "Name",
|
||||
"type": "Type",
|
||||
"confirmDelete": "Delete this account?"
|
||||
},
|
||||
"vat": {
|
||||
"addTitle": "Add VAT code", "editTitle": "Edit VAT code",
|
||||
"code": "Code", "name": "Name", "rate": "Rate %", "direction": "Direction",
|
||||
"account": "VAT account", "noAccount": "— none —", "confirmDelete": "Delete this VAT code?"
|
||||
"addTitle": "Add VAT code",
|
||||
"editTitle": "Edit VAT code",
|
||||
"code": "Code",
|
||||
"name": "Name",
|
||||
"rate": "Rate %",
|
||||
"direction": "Direction",
|
||||
"account": "VAT account",
|
||||
"noAccount": "— none —",
|
||||
"confirmDelete": "Delete this VAT code?"
|
||||
},
|
||||
"export": {
|
||||
"title": "Treuhänder export",
|
||||
|
||||
@@ -445,6 +445,78 @@ export const adminService = {
|
||||
'event_type_updated': `Event type updated: ${md.name || ''}`,
|
||||
'event_type_deleted': `Event type deleted: ${md.name || ''}`,
|
||||
'event_types_reordered': 'Event types reordered',
|
||||
// CRM — Contracts.
|
||||
'contract_created': `Contract created: ${md.contractNumber || ''}`,
|
||||
'contract_created_from_quote': `Contract created from quote: ${md.contractNumber || ''}`,
|
||||
'contract_updated': `Contract updated: ${md.contractNumber || ''}`,
|
||||
'contract_sent': `Contract sent: ${md.contractNumber || ''}`,
|
||||
'contract_resent_signed': `Signed contract resent: ${md.contractNumber || ''}`,
|
||||
'contract_signed_by_customer': `Contract signed by customer: ${md.contractNumber || ''}`,
|
||||
'contract_signed_pdf_uploaded': `Signed contract PDF uploaded: ${md.contractNumber || ''}`,
|
||||
'contract_signatures_restamped': `Contract signatures re-stamped: ${md.contractNumber || ''}`,
|
||||
'contract_cancelled': `Contract cancelled: ${md.contractNumber || ''}`,
|
||||
'contract_converted_to_event': `Contract converted to event: ${md.contractNumber || ''}`,
|
||||
'contract_converted_to_empty_event': `Contract converted to empty event: ${md.contractNumber || ''}`,
|
||||
'contract_converted_to_invoices': `Contract converted to invoices: ${md.contractNumber || ''}`,
|
||||
'contract_converted_to_empty_invoice': `Contract converted to empty invoice: ${md.contractNumber || ''}`,
|
||||
// CRM — Quotes.
|
||||
'quote_created': `Quote created: ${md.quoteNumber || ''}`,
|
||||
'quote_sent': `Quote sent: ${md.quoteNumber || ''}`,
|
||||
'quote_updated': `Quote updated: ${md.quoteNumber || ''}`,
|
||||
'quote_accepted_by_admin': `Quote accepted: ${md.quoteNumber || ''}`,
|
||||
'quote_declined_by_admin': `Quote declined: ${md.quoteNumber || ''}`,
|
||||
'quote_converted': `Quote converted: ${md.quoteNumber || ''}`,
|
||||
'quote_converted_invoices_only': `Quote converted to invoices: ${md.quoteNumber || ''}`,
|
||||
// CRM — Invoices / Storno.
|
||||
'invoice_created': `Invoice created: ${md.invoiceNumber || ''}`,
|
||||
'invoice_sent': `Invoice sent: ${md.invoiceNumber || ''}`,
|
||||
'invoice_scheduled': `Invoice scheduled: ${md.invoiceNumber || ''}`,
|
||||
'invoice_cancelled': `Invoice cancelled: ${md.invoiceNumber || ''}`,
|
||||
'invoice_cancelled_via_storno': `Invoice cancelled via Storno: ${md.invoiceNumber || ''}`,
|
||||
'invoice_reissued': `Invoice reissued: ${md.invoiceNumber || ''}`,
|
||||
'invoice_paid_admin_notified': `Invoice marked paid: ${md.invoiceNumber || ''}`,
|
||||
'invoice_payment_check_recorded': `Payment-check recorded for invoice: ${md.invoiceNumber || ''}`,
|
||||
'invoice_payment_check_sent': `Payment-check sent for invoice: ${md.invoiceNumber || ''}`,
|
||||
'invoice_released_for_delivery': `Invoice released for delivery: ${md.invoiceNumber || ''}`,
|
||||
'invoice_reminder_sent': `Invoice reminder sent: ${md.invoiceNumber || ''}`,
|
||||
'storno_sent': `Storno sent: ${md.invoiceNumber || ''}`,
|
||||
// CRM — Monthly billing.
|
||||
'monthly_bill_issued': 'Monthly bill issued for customer',
|
||||
'monthly_bill_skipped_empty': 'Monthly bill skipped (no entries)',
|
||||
'monthly_bill_triggered_manually': 'Monthly bill triggered manually',
|
||||
'monthly_billing_items_queued': 'Monthly billing items queued',
|
||||
'installment_plan_updated': 'Installment plan updated',
|
||||
// Accounting — Expenses + Hours + Incoming invoices.
|
||||
'expense_created': 'Expense created',
|
||||
'expense_updated': 'Expense updated',
|
||||
'expense_paid': 'Expense marked paid',
|
||||
'expense_invoiced': 'Expense invoiced',
|
||||
'hour_entry_logged': 'Hour entry logged',
|
||||
'hour_entry_updated': 'Hour entry updated',
|
||||
'hour_entry_deleted': 'Hour entry deleted',
|
||||
'hour_entry_logged_to_monthly_draft': 'Hour entry logged to monthly draft',
|
||||
'hour_entries_billed': 'Hour entries billed to customer',
|
||||
'incoming_invoice_captured': 'Incoming invoice captured',
|
||||
'incoming_invoice_categorized': 'Incoming invoice categorised',
|
||||
'incoming_invoice_updated': 'Incoming invoice updated',
|
||||
'incoming_invoice_rebilled': 'Incoming invoice re-billed to customer',
|
||||
'incoming_invoice_supplier_payment': 'Supplier payment recorded',
|
||||
'incoming_mail_config_updated': 'Incoming mail configuration updated',
|
||||
// Customers + Admin user mgmt.
|
||||
'customer_created_passive': `Passive customer created: ${md.email || ''}`,
|
||||
'admin_user_activated': `Admin user activated: ${md.username || ''}`,
|
||||
'admin_user_deleted': `Admin user deleted: ${md.username || ''}`,
|
||||
'admin_password_reset': `Admin password reset: ${md.username || ''}`,
|
||||
// Misc / legacy.
|
||||
'bulk_archive_completed': `Bulk archive completed: ${md.count || 0} events archived`,
|
||||
'email_queue_flushed': 'Email queue flushed',
|
||||
'email_resent': `Creation email resent for ${activity.eventName || ''}`,
|
||||
'email_template_created': `Email template created: ${md.template_key || ''}`,
|
||||
'event_duplicated': `Event duplicated from ${md.source_event_name || ''}`,
|
||||
'feedback_deleted': 'Feedback deleted',
|
||||
'feedback_moderated': 'Feedback moderated',
|
||||
'feedback_settings_updated': `Feedback settings updated for ${activity.eventName || ''}`,
|
||||
'word_filter_added': `Word filter added: ${md.word || ''}`,
|
||||
};
|
||||
|
||||
return messages[activity.type] || activity.type;
|
||||
|
||||
@@ -288,12 +288,27 @@ export const notificationsService = {
|
||||
slug: notification.metadata.slug,
|
||||
});
|
||||
|
||||
default:
|
||||
// Log unknown notification types for debugging
|
||||
default: {
|
||||
// Smart fallback: try to resolve admin.notificationMessages.<camelCase>
|
||||
// directly before giving up to the systemActivity template. Most CRM
|
||||
// and accounting activity types follow a stable shape (a doc number /
|
||||
// customer email / count interpolated into a short sentence), so we
|
||||
// add their translation entries to the locale files and rely on this
|
||||
// default to pick them up — no per-type switch case needed.
|
||||
const camelCase = notification.type.replace(/_(\w)/g, (_match, c) => c.toUpperCase());
|
||||
const key = `admin.notificationMessages.${camelCase}`;
|
||||
const translated = t(key, {
|
||||
eventName: notification.eventName,
|
||||
actorName: notification.actorName,
|
||||
...notification.metadata,
|
||||
});
|
||||
if (translated && translated !== key) return translated as string;
|
||||
// Truly unknown — log and render the legacy systemActivity template.
|
||||
console.warn('Unknown notification type:', notification.type, notification);
|
||||
return notification.metadata.message || t('admin.notificationMessages.systemActivity', {
|
||||
type: notification.type.replace(/_/g, ' ')
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user