@cosmicdrift/kumiko-bundled-features 0.206.0 → 0.208.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/package.json +9 -8
  2. package/src/admin-shell/__tests__/admin-shell.boot.test.ts +1 -1
  3. package/src/admin-shell/i18n.ts +17 -20
  4. package/src/admin-shell/web/i18n.ts +6 -11
  5. package/src/audit/i18n.ts +25 -25
  6. package/src/audit/web/i18n.ts +5 -9
  7. package/src/auth-email-password/__tests__/email-templates.test.ts +4 -0
  8. package/src/auth-email-password/email-templates.ts +97 -149
  9. package/src/auth-email-password/i18n.ts +6 -136
  10. package/src/auth-email-password/web/__tests__/confirm-account-unlock-screen.test.tsx +7 -7
  11. package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +14 -14
  12. package/src/auth-email-password/web/__tests__/invite-accept-screen.test.tsx +23 -25
  13. package/src/auth-email-password/web/__tests__/login-screen.test.tsx +60 -68
  14. package/src/auth-email-password/web/__tests__/request-account-unlock-screen.test.tsx +24 -24
  15. package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +20 -20
  16. package/src/auth-email-password/web/__tests__/signup-complete-screen.test.tsx +9 -9
  17. package/src/auth-email-password/web/__tests__/signup-screen.test.tsx +11 -11
  18. package/src/auth-email-password/web/__tests__/test-utils.tsx +2 -2
  19. package/src/auth-email-password/web/__tests__/user-menu.test.tsx +3 -3
  20. package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +3 -3
  21. package/src/auth-email-password/web/invite-accept-screen.tsx +3 -1
  22. package/src/auth-mfa/__tests__/errors-i18n-parity.test.ts +2 -4
  23. package/src/auth-mfa/i18n.ts +1 -2
  24. package/src/auth-mfa/web/__tests__/mfa-enable-screen.test.tsx +15 -15
  25. package/src/auth-mfa/web/__tests__/mfa-setup-preauth-screen.test.tsx +45 -49
  26. package/src/auth-mfa/web/__tests__/mfa-verify-screen.test.tsx +10 -10
  27. package/src/auth-mfa/web/i18n.ts +0 -63
  28. package/src/cap-counter/i18n.ts +5 -6
  29. package/src/compliance-profiles/i18n.ts +3 -3
  30. package/src/compliance-profiles/web/i18n.ts +0 -10
  31. package/src/config/i18n.ts +5 -5
  32. package/src/config/web/i18n.ts +1 -10
  33. package/src/custom-fields/web/i18n.ts +1 -9
  34. package/src/delivery/i18n.ts +3 -3
  35. package/src/delivery/web/i18n.ts +0 -10
  36. package/src/feature-toggles/i18n.ts +3 -3
  37. package/src/feature-toggles/web/i18n.ts +0 -12
  38. package/src/folders/web/i18n.ts +1 -26
  39. package/src/jobs/i18n.ts +40 -46
  40. package/src/jobs/web/i18n.ts +5 -9
  41. package/src/managed-pages/i18n.ts +23 -27
  42. package/src/managed-pages/web/i18n.ts +6 -11
  43. package/src/notes-history/i18n.ts +1 -1
  44. package/src/notes-history/web/i18n.ts +1 -9
  45. package/src/personal-access-tokens/i18n.ts +2 -2
  46. package/src/personal-access-tokens/web/i18n.ts +0 -37
  47. package/src/sessions/i18n.ts +17 -17
  48. package/src/tags/i18n.ts +2 -2
  49. package/src/tags/web/i18n.ts +1 -27
  50. package/src/template-resolver/web/__tests__/client-plugin.test.tsx +2 -2
  51. package/src/template-resolver/web/__tests__/editor-read-only.test.tsx +5 -5
  52. package/src/template-resolver/web/i18n.ts +0 -14
  53. package/src/tenant/__tests__/members-screens.boot.test.ts +0 -2
  54. package/src/tenant/i18n.ts +13 -16
  55. package/src/tenant/web/i18n.ts +0 -19
  56. package/src/tier-engine/i18n.ts +3 -19
  57. package/src/user/i18n.ts +14 -15
  58. package/src/user-data-rights/__tests__/default-mailers.test.ts +4 -0
  59. package/src/user-data-rights/__tests__/email-templates.test.ts +4 -0
  60. package/src/user-data-rights/__tests__/mail-default-bridge.integration.test.ts +2 -0
  61. package/src/user-data-rights/__tests__/run-export-jobs-cron-context.integration.test.ts +4 -0
  62. package/src/user-data-rights/email-templates.ts +55 -91
  63. package/src/user-data-rights/i18n.ts +18 -22
  64. package/src/user-data-rights/lib/default-mailers.ts +4 -1
  65. package/src/user-data-rights/web/__tests__/deletion-screens.test.tsx +11 -11
  66. package/src/user-data-rights/web/__tests__/public-deletion-gate.test.tsx +5 -5
  67. package/src/user-data-rights/web/i18n.ts +9 -88
  68. package/src/user-profile/i18n.ts +1 -36
@@ -1,23 +1,23 @@
1
1
  // @runtime client
2
2
  // Server + client i18n for the sessions operator screens.
3
3
 
4
- type LocalizedString = { readonly de: string; readonly en: string };
4
+ type LocalizedString = { readonly en: string };
5
5
 
6
6
  export const SESSIONS_I18N: Readonly<Record<string, LocalizedString>> = {
7
- "screen:session-list.title": { de: "Sitzungen", en: "Sessions" },
8
- "screen:session-detail.title": { de: "Sitzung", en: "Session" },
9
- "sessions:nav.sessionList": { de: "Sitzungen", en: "Sessions" },
10
- "sessions.list.col.id": { de: "ID", en: "ID" },
11
- "sessions.list.col.userId": { de: "User-ID", en: "User ID" },
12
- "sessions.list.col.createdAt": { de: "Erstellt", en: "Created" },
13
- "sessions.list.col.expiresAt": { de: "Läuft ab", en: "Expires" },
14
- "sessions.list.col.revokedAt": { de: "Widerrufen", en: "Revoked" },
15
- "sessions.list.action.open": { de: "Details", en: "Details" },
16
- "sessions.detail.field.id": { de: "ID", en: "ID" },
17
- "sessions.detail.field.userId": { de: "User-ID", en: "User ID" },
18
- "sessions.detail.field.createdAt": { de: "Erstellt", en: "Created" },
19
- "sessions.detail.field.expiresAt": { de: "Läuft ab", en: "Expires" },
20
- "sessions.detail.field.revokedAt": { de: "Widerrufen", en: "Revoked" },
21
- "sessions.detail.field.ip": { de: "IP-Adresse", en: "IP address" },
22
- "sessions.detail.field.userAgent": { de: "User-Agent", en: "User agent" },
7
+ "screen:session-list.title": { en: "Sessions" },
8
+ "screen:session-detail.title": { en: "Session" },
9
+ "sessions:nav.sessionList": { en: "Sessions" },
10
+ "sessions.list.col.id": { en: "ID" },
11
+ "sessions.list.col.userId": { en: "User ID" },
12
+ "sessions.list.col.createdAt": { en: "Created" },
13
+ "sessions.list.col.expiresAt": { en: "Expires" },
14
+ "sessions.list.col.revokedAt": { en: "Revoked" },
15
+ "sessions.list.action.open": { en: "Details" },
16
+ "sessions.detail.field.id": { en: "ID" },
17
+ "sessions.detail.field.userId": { en: "User ID" },
18
+ "sessions.detail.field.createdAt": { en: "Created" },
19
+ "sessions.detail.field.expiresAt": { en: "Expires" },
20
+ "sessions.detail.field.revokedAt": { en: "Revoked" },
21
+ "sessions.detail.field.ip": { en: "IP address" },
22
+ "sessions.detail.field.userAgent": { en: "User agent" },
23
23
  };
package/src/tags/i18n.ts CHANGED
@@ -1,5 +1,5 @@
1
- type LocalizedString = { readonly de: string; readonly en: string };
1
+ type LocalizedString = { readonly en: string };
2
2
 
3
3
  export const TAGS_FEATURE_I18N: Readonly<Record<string, LocalizedString>> = {
4
- "screen:tag-list.title": { de: "Tags", en: "Tags" },
4
+ "screen:tag-list.title": { en: "Tags" },
5
5
  };
@@ -1,37 +1,11 @@
1
1
  // @runtime client
2
2
  // Default translation bundle for the tags UI. tagsClient() hangs it into the
3
3
  // LocaleProvider as a fallback bundle — apps override individual keys via
4
- // tagsClient({ translations: { de: { ... } } }). Keys follow `tags.<area>.<slug>`.
4
+ // tagsClient({ translations }). Keys follow `tags.<area>.<slug>`.
5
5
 
6
6
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
7
7
 
8
8
  export const defaultTranslations: TranslationsByLocale = {
9
- de: {
10
- "tags.section.createMode": "Speichere zuerst den Eintrag, um Tags zu setzen.",
11
- "tags.section.loading": "Lädt…",
12
- "tags.section.empty": "Keine Tags gefunden.",
13
- "tags.section.working": "Speichert…",
14
- "tags.section.none": "Keine Tags",
15
- "tags.section.edit": "Tags bearbeiten",
16
- "tags.manage.newLabel": "Neuer Tag",
17
- "tags.manage.namePlaceholder": "Tag-Name",
18
- "tags.manage.scopeLabel": "Geltungsbereich (Entity-Typ, leer = global)",
19
- "tags.manage.scopePlaceholder": "z. B. note (leer = überall)",
20
- "tags.manage.create": "Tag anlegen",
21
- "tags.manage.edit": "Bearbeiten",
22
- "tags.manage.save": "Speichern",
23
- "tags.manage.cancel": "Abbrechen",
24
- "tags.manage.delete": "Löschen",
25
- "tags.manage.toggle": "Tag umschalten",
26
- "tags.manage.usage": "{count}×",
27
- "tags.manage.deleteConfirmTitle": "Tag „{name}“ löschen?",
28
- "tags.manage.deleteConfirmDesc":
29
- "Entfernt ihn von {count} Objekten. Das lässt sich nicht rückgängig machen.",
30
- "tags.picker.title": "Tags",
31
- "tags.picker.done": "Fertig",
32
- "tags.filter.label": "Nach Tag filtern",
33
- "tags.filter.clear": "Filter zurücksetzen",
34
- },
35
9
  en: {
36
10
  "tags.section.createMode": "Save the entity first to add tags.",
37
11
  "tags.section.loading": "Loading…",
@@ -254,7 +254,7 @@ describe("textBlocksClient — content collections", () => {
254
254
  });
255
255
 
256
256
  describe("textBlocksClient — plain contentFormat editor wiring", () => {
257
- const localeResolver = createStaticLocaleResolver({ locale: "de" });
257
+ const localeResolver = createStaticLocaleResolver({ locale: "en" });
258
258
 
259
259
  function Wrapper({ children }: { readonly children: ReactNode }): ReactNode {
260
260
  return (
@@ -298,7 +298,7 @@ describe("textBlocksClient — plain contentFormat editor wiring", () => {
298
298
  });
299
299
 
300
300
  describe("textBlocksClient — findContentFormat resolves collectionId to the registered editor", () => {
301
- const localeResolver = createStaticLocaleResolver({ locale: "de" });
301
+ const localeResolver = createStaticLocaleResolver({ locale: "en" });
302
302
  const RichStub: ContentEditorComponent = () => <div data-testid="rich-stub-editor" />;
303
303
 
304
304
  function RichStubWrapper({ children }: { readonly children: ReactNode }): ReactNode {
@@ -52,7 +52,7 @@ function getEditor() {
52
52
  return Editor;
53
53
  }
54
54
 
55
- const localeResolver = createStaticLocaleResolver({ locale: "de" });
55
+ const localeResolver = createStaticLocaleResolver({ locale: "en" });
56
56
 
57
57
  function Wrapper({ children }: { readonly children: ReactNode }): ReactNode {
58
58
  return (
@@ -80,7 +80,7 @@ describe("TextContentEditor — role-based write-access", () => {
80
80
  const Editor = getEditor();
81
81
  render(<Editor target={TARGET} onClose={() => {}} />, { wrapper: Wrapper });
82
82
 
83
- const saveButton = screen.getByRole("button", { name: /speichern/i });
83
+ const saveButton = screen.getByRole("button", { name: /save/i });
84
84
  expect(saveButton).toBeTruthy();
85
85
  expect(saveButton.hasAttribute("disabled")).toBe(false);
86
86
 
@@ -93,7 +93,7 @@ describe("TextContentEditor — role-based write-access", () => {
93
93
  const Editor = getEditor();
94
94
  render(<Editor target={TARGET} onClose={() => {}} />, { wrapper: Wrapper });
95
95
 
96
- expect(screen.getByRole("button", { name: /speichern/i })).toBeTruthy();
96
+ expect(screen.getByRole("button", { name: /save/i })).toBeTruthy();
97
97
  expect(screen.queryByText(/Read-only/)).toBeNull();
98
98
  });
99
99
 
@@ -153,7 +153,7 @@ describe("TextContentEditor — handleSave", () => {
153
153
  render(<Editor target={TARGET} onClose={() => {}} />, { wrapper: Wrapper });
154
154
 
155
155
  await act(async () => {
156
- fireEvent.click(screen.getByRole("button", { name: /speichern/i }));
156
+ fireEvent.click(screen.getByRole("button", { name: /save/i }));
157
157
  await Promise.resolve();
158
158
  });
159
159
 
@@ -177,7 +177,7 @@ describe("TextContentEditor — handleSave", () => {
177
177
  render(<Editor target={TARGET} onClose={() => {}} />, { wrapper: Wrapper });
178
178
 
179
179
  await act(async () => {
180
- fireEvent.click(screen.getByRole("button", { name: /speichern/i }));
180
+ fireEvent.click(screen.getByRole("button", { name: /save/i }));
181
181
  await Promise.resolve();
182
182
  });
183
183
 
@@ -8,20 +8,6 @@
8
8
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
9
9
 
10
10
  export const defaultTranslations: TranslationsByLocale = {
11
- de: {
12
- "template-resolver.editor.titleLabel": "Titel",
13
- "template-resolver.editor.contentLabel": "Inhalt",
14
- "template-resolver.editor.save": "Speichern",
15
- "template-resolver.editor.saving": "Speichern…",
16
- "template-resolver.editor.created": "Neu angelegt.",
17
- "template-resolver.editor.saved": "Gespeichert.",
18
- "template-resolver.editor.saveFailed": "Speichern fehlgeschlagen.",
19
- "template-resolver.editor.networkError": "Netzwerkfehler beim Speichern.",
20
- "template-resolver.editor.loading": "Lädt aktuellen Stand…",
21
- "template-resolver.editor.loadFailed": "Konnte Block nicht laden",
22
- "template-resolver.editor.readOnly":
23
- "Read-only — TenantAdmin- oder SystemAdmin-Rolle für Änderungen erforderlich.",
24
- },
25
11
  en: {
26
12
  "template-resolver.editor.titleLabel": "Title",
27
13
  "template-resolver.editor.contentLabel": "Content",
@@ -5,7 +5,6 @@ import { AuthHandlers } from "../../auth-email-password/constants";
5
5
  import { createConfigFeature } from "../../config/feature";
6
6
  import { MEMBERS_SCREEN_ID, TenantHandlers, TenantQueries } from "../constants";
7
7
  import { createTenantFeature } from "../feature";
8
- import { defaultTranslations } from "../web/i18n";
9
8
 
10
9
  describe("tenant members screen + handler access alignment", () => {
11
10
  const features = [createConfigFeature(), createTenantFeature()];
@@ -38,7 +37,6 @@ describe("tenant members screen + handler access alignment", () => {
38
37
  test("members nav label uses tenantClient i18n key (not feature:nav.* alias)", () => {
39
38
  const nav = createTenantFeature().navs["members"];
40
39
  expect(nav?.label).toBe("tenant.nav.members");
41
- expect(defaultTranslations["de"]?.["tenant.nav.members"]).toBe("Team");
42
40
  });
43
41
 
44
42
  test("updateMemberRoles stays SystemAdmin/system-only (not on members screen)", () => {
@@ -1,28 +1,25 @@
1
- type LocalizedString = { readonly de: string; readonly en: string };
1
+ type LocalizedString = { readonly en: string };
2
2
 
3
3
  export const TENANT_I18N: Readonly<Record<string, LocalizedString>> = {
4
- "screen:tenant-list.title": { de: "Mandanten", en: "Tenants" },
5
- "screen:tenant-edit.title": { de: "Mandant bearbeiten", en: "Edit tenant" },
6
- "screen:members.title": { de: "Team", en: "Team" },
7
- "tenant.nav.members": { de: "Team", en: "Team" },
8
- "tenant:entity:tenant:field:key": { de: "Schlüssel", en: "Key" },
9
- "tenant:entity:tenant:field:name": { de: "Name", en: "Name" },
10
- "tenant:entity:tenant:field:isEnabled": { de: "Aktiv", en: "Enabled" },
11
- "tenant:entity:tenant:field:status": { de: "Status", en: "Status" },
12
- "tenant:entity:tenant:field:status:option:active": { de: "Aktiv", en: "Active" },
4
+ "screen:tenant-list.title": { en: "Tenants" },
5
+ "screen:tenant-edit.title": { en: "Edit tenant" },
6
+ "screen:members.title": { en: "Team" },
7
+ "tenant.nav.members": { en: "Team" },
8
+ "tenant:entity:tenant:field:key": { en: "Key" },
9
+ "tenant:entity:tenant:field:name": { en: "Name" },
10
+ "tenant:entity:tenant:field:isEnabled": { en: "Enabled" },
11
+ "tenant:entity:tenant:field:status": { en: "Status" },
12
+ "tenant:entity:tenant:field:status:option:active": { en: "Active" },
13
13
  "tenant:entity:tenant:field:status:option:destroyRequested": {
14
- de: "Löschung angefordert",
15
14
  en: "Destroy requested",
16
15
  },
17
16
  "tenant:entity:tenant:field:status:option:destroying": {
18
- de: "Wird gelöscht",
19
17
  en: "Destroying",
20
18
  },
21
19
  "tenant:entity:tenant:field:status:option:destroyFailed": {
22
- de: "Löschung fehlgeschlagen",
23
20
  en: "Destroy failed",
24
21
  },
25
- "tenant:entity:tenant:field:status:option:destroyed": { de: "Gelöscht", en: "Destroyed" },
26
- "tenant:entity:tenant:field:isEnabled:option:true": { de: "Ja", en: "Yes" },
27
- "tenant:entity:tenant:field:isEnabled:option:false": { de: "Nein", en: "No" },
22
+ "tenant:entity:tenant:field:status:option:destroyed": { en: "Destroyed" },
23
+ "tenant:entity:tenant:field:isEnabled:option:true": { en: "Yes" },
24
+ "tenant:entity:tenant:field:isEnabled:option:false": { en: "No" },
28
25
  };
@@ -2,25 +2,6 @@
2
2
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
3
3
 
4
4
  export const defaultTranslations: TranslationsByLocale = {
5
- de: {
6
- "tenant.members.title": "Mitglieder",
7
- "tenant.members.loading": "Lade Mitglieder…",
8
- "tenant.members.active": "Aktive Mitglieder",
9
- "tenant.members.invite.title": "Neue Einladung",
10
- "tenant.members.invite.email": "E-Mail",
11
- "tenant.members.invite.role": "Rolle",
12
- "tenant.members.invite.submit": "Einladung senden",
13
- "tenant.members.invite.submitting": "Einladung wird gesendet…",
14
- "tenant.members.invite.success": "Einladung an {email} gesendet",
15
- "tenant.members.pending": "Ausstehende Einladungen",
16
- "tenant.members.pending.empty": "Keine ausstehenden Einladungen.",
17
- "tenant.members.cancel": "Zurückziehen",
18
- "tenant.members.col.userId": "User-ID",
19
- "tenant.members.col.roles": "Rollen",
20
- "tenant.members.col.email": "E-Mail",
21
- "tenant.members.col.expires": "Gültig bis",
22
- "tenant.nav.members": "Team",
23
- },
24
5
  en: {
25
6
  "tenant.members.title": "Members",
26
7
  "tenant.members.loading": "Loading members…",
@@ -1,33 +1,17 @@
1
1
  // @runtime client
2
2
  // Default-Bundles für den TierAdminScreen. Werden vom tierEngineClient()
3
3
  // als Fallback-Bundle in den LocaleProvider gehängt — Apps überschreiben
4
- // einzelne Keys via `tierEngineClient({ translations: { de: { … } } })`.
4
+ // einzelne Keys via `tierEngineClient({ translations })`.
5
5
 
6
6
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
7
7
 
8
- type LocalizedString = { readonly de: string; readonly en: string };
8
+ type LocalizedString = { readonly en: string };
9
9
 
10
10
  export const TIER_ENGINE_I18N: Readonly<Record<string, LocalizedString>> = {
11
- "screen:tier-admin.title": { de: "Tier manuell zuweisen", en: "Assign tier manually" },
11
+ "screen:tier-admin.title": { en: "Assign tier manually" },
12
12
  };
13
13
 
14
14
  export const defaultTranslations: TranslationsByLocale = {
15
- de: {
16
- "screen:tier-admin.title": "Tier manuell zuweisen",
17
- "tier-admin.title": "Tier manuell zuweisen",
18
- "tier-admin.explainer":
19
- "Weise einem Tenant ein Tier ohne Kauf zu. Der Grant wird als „manuell“ markiert und von einem späteren Billing-Sync nicht überschrieben.",
20
- "tier-admin.tenant.label": "Tenant",
21
- "tier-admin.current.label": "Aktuelles Tier",
22
- "tier-admin.current.none": "— noch keins —",
23
- "tier-admin.tier.label": "Neues Tier",
24
- "tier-admin.submit": "Tier zuweisen",
25
- "tier-admin.success": "Tier „{tier}“ zugewiesen.",
26
- "tier-admin.error.generic": "Konnte das Tier nicht zuweisen.",
27
- "tier-admin.error.load": "Tenants konnten nicht geladen werden.",
28
- "tier-admin.error.noTiers":
29
- "Diese App hat keine TierMap konfiguriert — es gibt keine zuweisbaren Tiers.",
30
- },
31
15
  en: {
32
16
  "screen:tier-admin.title": "Assign tier manually",
33
17
  "tier-admin.title": "Assign tier manually",
package/src/user/i18n.ts CHANGED
@@ -1,21 +1,20 @@
1
- type LocalizedString = { readonly de: string; readonly en: string };
1
+ type LocalizedString = { readonly en: string };
2
2
 
3
3
  export const USER_I18N: Readonly<Record<string, LocalizedString>> = {
4
- "screen:user-list.title": { de: "Benutzer", en: "Users" },
5
- "screen:user-edit.title": { de: "Benutzer bearbeiten", en: "Edit user" },
6
- "user:entity:user:field:email": { de: "E-Mail", en: "Email" },
7
- "user:entity:user:field:displayName": { de: "Anzeigename", en: "Display name" },
8
- "user:entity:user:field:status": { de: "Status", en: "Status" },
9
- "user:entity:user:field:emailVerified": { de: "E-Mail bestätigt", en: "Email verified" },
10
- "user:entity:user:field:locale": { de: "Sprache", en: "Locale" },
11
- "user:entity:user:field:timezone": { de: "Zeitzone", en: "Timezone" },
12
- "user:entity:user:field:status:option:active": { de: "Aktiv", en: "Active" },
13
- "user:entity:user:field:status:option:restricted": { de: "Eingeschränkt", en: "Restricted" },
4
+ "screen:user-list.title": { en: "Users" },
5
+ "screen:user-edit.title": { en: "Edit user" },
6
+ "user:entity:user:field:email": { en: "Email" },
7
+ "user:entity:user:field:displayName": { en: "Display name" },
8
+ "user:entity:user:field:status": { en: "Status" },
9
+ "user:entity:user:field:emailVerified": { en: "Email verified" },
10
+ "user:entity:user:field:locale": { en: "Locale" },
11
+ "user:entity:user:field:timezone": { en: "Timezone" },
12
+ "user:entity:user:field:status:option:active": { en: "Active" },
13
+ "user:entity:user:field:status:option:restricted": { en: "Restricted" },
14
14
  "user:entity:user:field:status:option:deletionRequested": {
15
- de: "Löschung angefordert",
16
15
  en: "Deletion requested",
17
16
  },
18
- "user:entity:user:field:status:option:deleted": { de: "Gelöscht", en: "Deleted" },
19
- "user:entity:user:field:emailVerified:option:true": { de: "Ja", en: "Yes" },
20
- "user:entity:user:field:emailVerified:option:false": { de: "Nein", en: "No" },
17
+ "user:entity:user:field:status:option:deleted": { en: "Deleted" },
18
+ "user:entity:user:field:emailVerified:option:true": { en: "Yes" },
19
+ "user:entity:user:field:emailVerified:option:false": { en: "No" },
21
20
  };
@@ -10,6 +10,8 @@ import type {
10
10
  EmailTransport,
11
11
  } from "@cosmicdrift/kumiko-bundled-features/channel-email";
12
12
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
13
+ import { registerMailTranslations } from "@cosmicdrift/kumiko-framework/i18n";
14
+ import { localeDeBundle } from "@cosmicdrift/kumiko-locale-de";
13
15
  import {
14
16
  makeDefaultDeletionExecutedEmail,
15
17
  makeDefaultExportReadyEmail,
@@ -27,6 +29,8 @@ function capturingTransport(): { transport: EmailTransport; sent: EmailMessage[]
27
29
 
28
30
  const TENANT_A = "00000000-0000-4000-8000-00000000000a" as TenantId;
29
31
 
32
+ registerMailTranslations("de", localeDeBundle);
33
+
30
34
  describe("default-mailers dispatch", () => {
31
35
  test("export-ready: rendert Template + sendet an userEmail ueber tenant-transport", async () => {
32
36
  const cap = capturingTransport();
@@ -1,4 +1,6 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { registerMailTranslations } from "@cosmicdrift/kumiko-framework/i18n";
3
+ import { localeDeBundle } from "@cosmicdrift/kumiko-locale-de";
2
4
  import {
3
5
  renderDeletionExecutedEmail,
4
6
  renderDeletionRequestedEmail,
@@ -6,6 +8,8 @@ import {
6
8
  renderExportReadyEmail,
7
9
  } from "../email-templates";
8
10
 
11
+ registerMailTranslations("de", localeDeBundle);
12
+
9
13
  describe("gdpr email-templates", () => {
10
14
  test("export-ready: subject + download-button + formatted expiry, de/en differ", () => {
11
15
  const en = renderExportReadyEmail({
@@ -21,6 +21,7 @@ import {
21
21
  } from "@cosmicdrift/kumiko-framework/stack";
22
22
  import { resetTestTables, seedRow } from "@cosmicdrift/kumiko-framework/testing";
23
23
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
24
+ import { localeDe } from "@cosmicdrift/kumiko-locale-de";
24
25
  import { createComplianceProfilesFeature } from "../../compliance-profiles";
25
26
  import { configValuesTable, createConfigFeature, createConfigResolver } from "../../config";
26
27
  import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
@@ -63,6 +64,7 @@ beforeAll(async () => {
63
64
  mailTransportInMemoryFeature,
64
65
  // KEINE send*Email-Opts — die mail-foundation-Defaults muessen greifen.
65
66
  createUserDataRightsFeature(),
67
+ localeDe(),
66
68
  createUserDataRightsDefaultsFeature(),
67
69
  ],
68
70
  });
@@ -14,6 +14,7 @@ import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth
14
14
  import { asRawClient, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
15
15
  import { type JobContext, SYSTEM_USER_ID } from "@cosmicdrift/kumiko-framework/engine";
16
16
  import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
17
+ import { registerMailTranslations } from "@cosmicdrift/kumiko-framework/i18n";
17
18
  import {
18
19
  setupTestStack,
19
20
  type TestStack,
@@ -22,6 +23,7 @@ import {
22
23
  } from "@cosmicdrift/kumiko-framework/stack";
23
24
  import { seedRow } from "@cosmicdrift/kumiko-framework/testing";
24
25
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
26
+ import { localeDeBundle } from "@cosmicdrift/kumiko-locale-de";
25
27
  import {
26
28
  createComplianceProfilesFeature,
27
29
  tenantComplianceProfileEntity,
@@ -134,6 +136,8 @@ async function seedPendingJob(): Promise<string> {
134
136
  return res.jobId;
135
137
  }
136
138
 
139
+ registerMailTranslations("de", localeDeBundle);
140
+
137
141
  describe("run-export-jobs cron-context", () => {
138
142
  test("Cron-Job-Kontext (configResolver, KEIN config) → Export läuft durch, bytesWritten > 0", async () => {
139
143
  const jobId = await seedPendingJob();