Skip to content

feat(i18n): #16 Phase 3 — localize emails + in-app notifications (recipient language)#92

Merged
WolfTasks merged 4 commits into
mainfrom
worktree-backend-i18n-phase3
Jul 22, 2026
Merged

feat(i18n): #16 Phase 3 — localize emails + in-app notifications (recipient language)#92
WolfTasks merged 4 commits into
mainfrom
worktree-backend-i18n-phase3

Conversation

@WolfTasks

@WolfTasks WolfTasks commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Final phase of backend-i18n #16: async/clientless backend text — emails and in-app notification titles (plus the 2 templated notification bodies) — now render in the recipient's stored language (user.language), with English fallback. Completes the #16 rollout (Phases 1–2 already on main).

3 TDD commits, one per task (+ 1 CI fix, see below):

  1. bb270c2 — 11 new catalog keys (email.* / notification.*) in en (messages.properties) + de (messages_de.properties, \uXXXX-escaped, 0 non-ASCII bytes) + EmailNotificationMessagesTest.
  2. 54e1ed8EmailService renders mention/assigned subject + body via localeOf(recipient); new/merged EmailServiceTest.
  3. 30b5acaNotificationService: localize the 2 listener titles; convert createDirect to a keyed signature that looks up user.language and renders internally (injects LocalizedMessages + UserRepository, EN fallback). Migrates all 3 callers + their tests in one atomic (compile-breaking) commit. IncidentService now uses the human issue.key (not the raw UUID) in title/body/link, via a single guarded IssueRepository lookup.

Design decisions (from the approved spec)

  • Recipient locale, not request locale — rendered via LocalizedMessages.get(key, locale, args) with locale = localeOf(recipientUser); never LocaleContextHolder (the triggering request may be a different language than the recipient).
  • 2 hard-coded template bodies localized too (Incident, SLA) — otherwise a German title would pair with an English body. Genuine user-content bodies (comment excerpt, issue title, automation message) stay untranslated.
  • Numeric SLA arg passed as .toString() (avoids MessageFormat digit-grouping: 1440, not 1.440). Keys append-only; LocalizedMessages unchanged; no DB migration.

CI fix bundled in (commit 98a4c55)

The first backend-docker run failed the Trivy HIGH/CRITICAL image gate on CVE-2026-54291 (org.postgresql:postgresql 42.7.11), a HIGH-severity CVE disclosed after main last passed CI — unrelated to the i18n changes (main would hit the same failure on its next run). Fixed by bumping the JDBC driver to the patched 42.7.12 via an extra["postgresql.version"] override of the Spring Boot 3.5.16 BOM (same idiom as the existing commons-lang3 / logback overrides) and regenerating the Gradle lockfile pin. Re-run CI is fully green.

Verification

  • Full backend suite 382/382 green, including the 3 CI gates: MessagesParityTest, KeyedReferenceIntegrityTest, NoUnkeyedUserFacingThrowTest (forced rerun of gates + all 6 new/changed test classes = BUILD SUCCESSFUL).
  • messages_de.properties: 0 non-ASCII bytes (all German \uXXXX-escaped); en/de key-set parity holds.
  • Per-task reviews + final whole-branch review (opus): 0 Critical, 0 Important. Three Minor items are optional test-coverage niceties over paths already exercised elsewhere (deferred, non-blocking).
  • All CI checks green after the postgresql fix (incl. backend-docker / Trivy gate).

Frontend / behavior note

IncidentService incident notifications now link to /issues/{issueKey} (e.g. /issues/WOLF-1) and show the issue key instead of a raw UUID — aligns with every other notification, which already used issue.key.

Owed after merge (Wolfgang)

Manual DE/EN smoke (trigger a mention/assignment email + an incident/SLA/automation notification for a de user and an en user; confirm recipient-language subject/title + localized incident/SLA bodies; confirm user-content bodies stay untranslated), then the v1.0.x release — which ships all of #16 (Phases 1–3).

🤖 Generated with Claude Code

Wolfgang Kozian and others added 4 commits July 22, 2026 18:05
Phase 3 of #16: 11 new keys for email subject/body and notification
titles + the 2 templated notification bodies (incident, SLA). German
\uXXXX-escaped. Resolution test asserts en/de rendering incl. issue-key
and numeric-as-string args.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 3 of #16: EmailService resolves localeOf(recipient) and renders
subject + body via email.mention.* / email.assigned.* keys. New unit
test asserts de/en/null->en rendering with a real ResourceBundleMessageSource.

Note: EmailServiceTest.kt pre-existed this task (from the original
EmailService feature); the pre-existing guard-condition tests (blank
SMTP host, non-assignee field, disabled preference) were retained
alongside the brief's new locale-rendering tests rather than being
dropped by a verbatim file replacement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 3 of #16: NotificationService localizes mention/assigned titles via
localeOf(recipient); createDirect converted to a keyed signature that renders
title (+ optional templated body) after looking up user.language, with EN
fallback. IncidentService injects IssueRepository and uses issue.key (not the
raw UUID) in title/body/link. SlaMonitorJob + ActionExecutor migrated to keyed
args; user-content bodies (comment excerpt, issue title, automation message)
stay untranslated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Unblocks the backend-docker Trivy gate on this PR: CVE-2026-54291 (HIGH)
was disclosed against the org.postgresql:postgresql 42.7.11 JDBC driver
after main last passed, flipping the previously-green image scan red
(unrelated to the Phase 3 i18n changes; main will hit the same failure on
its next run). Fixed version is 42.7.12. Overrides the Spring Boot 3.5.16
BOM-managed postgresql.version property (same idiom as commons-lang3 /
logback overrides) and regenerates the lockfile pin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@WolfTasks

Copy link
Copy Markdown
Owner Author

✅ CI is green now. The earlier backend-docker failure was the Trivy HIGH/CRITICAL image gate tripping on CVE-2026-54291 (org.postgresql:postgresql 42.7.11) — a HIGH-severity CVE disclosed after main last passed CI, unrelated to the i18n changes. Fixed in 98a4c55 by bumping the JDBC driver to the patched 42.7.12 (BOM property override + lockfile regen). On the re-run all gating checks pass, including backend-docker / Trivy and backend-test.

@WolfTasks
WolfTasks merged commit 00665f5 into main Jul 22, 2026
11 checks passed
@WolfTasks
WolfTasks deleted the worktree-backend-i18n-phase3 branch July 22, 2026 16:50
WolfTasks pushed a commit that referenced this pull request Jul 22, 2026
…lease pending

Phase 3 (emails + in-app notifications, PR #92 squash 00665f5) completes
the #16 backend-i18n rollout on main. Updates the backlog-overview status
from Backlog to GEMERGT — Release ausstehend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant