feat(i18n): #16 Phase 3 — localize emails + in-app notifications (recipient language)#92
Merged
Merged
Conversation
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>
Owner
Author
|
✅ CI is green now. The earlier |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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):
bb270c2— 11 new catalog keys (email.*/notification.*) in en (messages.properties) + de (messages_de.properties,\uXXXX-escaped, 0 non-ASCII bytes) +EmailNotificationMessagesTest.54e1ed8—EmailServicerenders mention/assigned subject + body vialocaleOf(recipient); new/mergedEmailServiceTest.30b5aca—NotificationService: localize the 2 listener titles; convertcreateDirectto a keyed signature that looks upuser.languageand renders internally (injectsLocalizedMessages+UserRepository, EN fallback). Migrates all 3 callers + their tests in one atomic (compile-breaking) commit.IncidentServicenow uses the humanissue.key(not the raw UUID) in title/body/link, via a single guardedIssueRepositorylookup.Design decisions (from the approved spec)
LocalizedMessages.get(key, locale, args)withlocale = localeOf(recipientUser); neverLocaleContextHolder(the triggering request may be a different language than the recipient).message) stay untranslated..toString()(avoids MessageFormat digit-grouping:1440, not1.440). Keys append-only;LocalizedMessagesunchanged; no DB migration.CI fix bundled in (commit
98a4c55)The first
backend-dockerrun failed the Trivy HIGH/CRITICAL image gate on CVE-2026-54291 (org.postgresql:postgresql42.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 anextra["postgresql.version"]override of the Spring Boot 3.5.16 BOM (same idiom as the existingcommons-lang3/logbackoverrides) and regenerating the Gradle lockfile pin. Re-run CI is fully green.Verification
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.backend-docker/ Trivy gate).Frontend / behavior note
IncidentServiceincident 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 usedissue.key.Owed after merge (Wolfgang)
Manual DE/EN smoke (trigger a mention/assignment email + an incident/SLA/automation notification for a
deuser and anenuser; confirm recipient-language subject/title + localized incident/SLA bodies; confirm user-content bodies stay untranslated), then thev1.0.xrelease — which ships all of #16 (Phases 1–3).🤖 Generated with Claude Code