Skip to content

fix(calendar): blank task titles from invalid translation LanguageId#996

Merged
renemadsen merged 4 commits into
stablefrom
fix/calendar-translation-languageid-remap
Jun 10, 2026
Merged

fix(calendar): blank task titles from invalid translation LanguageId#996
renemadsen merged 4 commits into
stablefrom
fix/calendar-translation-languageid-remap

Conversation

@renemadsen

Copy link
Copy Markdown
Member

Summary

Calendar/task titles were rendering blank (the tile showed only the numeric id, e.g. "113") for tasks whose Danish title translation was stored under an invalid LanguageId. Affected both the Angular calendar and the Flutter mobile app (both read the same GetTasksForWeek title resolution).

Root cause

  • The calendar create/edit modal hardcoded the Danish source title as languageId: 1, and the backend persisted it verbatim into AreaRuleTranslations and PlanningNameTranslation.
  • But the SDK Languages table is customer-specific (e.g. this tenant: da=2, en-US=5, de-DE=8, no id 1). So the Danish title was stored under a language id no reader ever queries → blank title. Confirmed live: AreaRule 113 was created today and still got LanguageId=1. The earlier #985 "remap seed LanguageId" fix only covered seed paths, not the calendar create/update path.
  • Secondary: the compliance title branches had no cross-language fallback, so a mis-keyed translation degraded to blank instead of the available name.

Fix

Write path (stop minting bad rows):

  • Frontend: the modal now resolves Danish's real SDK id by language code from the loaded languages list instead of hardcoding 1.
  • Backend: AreaRuleLanguageHelper.RemapCommonTranslationLanguageIdsAsync defensively remaps any incoming translation LanguageId that is absent from SDK Languages, resolving via language code → SDK Languages.Id. Applied on Create + Update, covering both AreaRuleTranslations and PlanningNameTranslation. Existence-based guard: valid SDK ids are never touched (avoids corrupting multi-language targets on shifted-id tenants).

Read path (graceful degrade):

  • A single ResolveTaskTitle helper replaces 4 inconsistent title-computation sites (recurrence, moved-in, compliance in GetTasksForWeek, compliance in GetTaskTrackerList). Order: user-language non-empty → any non-empty translation → caller fallback (e.g. compliance.ItemName) → "". Uses IsNullOrWhiteSpace so empty-string names also fall through (the old ?? only caught null).

Tests

  • Remap: shifted-id tenant scenario; asserts an absent app-locale id is remapped by code AND that a valid SDK target id is left untouched (anti-corruption regression test).
  • ResolveTaskTitle: user-lang wins, empty-string fall-through, cross-language fallback, null collection, all-empty → "".
  • Backend build green; remap + resolver tests pass; frontend build green.

Note

Existing mis-keyed rows in a database (created before this fix) still carry the bad LanguageId; the read-path fallback makes them display correctly, and they can be repaired by remapping AreaRuleTranslations/PlanningNameTranslation rows whose LanguageId is absent from SDK Languages to the correct id by code (done for the local 420 DB during investigation).

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 10, 2026 16:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes blank calendar/task titles caused by persisting translations under invalid/non-SDK LanguageId values, and makes title resolution resilient when a user-language translation is missing or empty.

Changes:

  • Frontend: resolve Danish source title’s real SDK Languages.Id by languageCode instead of hardcoding languageId: 1.
  • Backend write path: defensively remap incoming CommonTranslationsModel.LanguageId values that don’t exist in SDK Languages before persisting.
  • Backend read path: centralize task title resolution via ResolveTaskTitle with cross-language + whitespace-aware fallback, plus unit/integration coverage.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationTaskWizardService/BackendConfigurationTaskWizardService.cs Remaps incoming translation LanguageIds on create/update to avoid minting bad rows.
eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationCalendarService/BackendConfigurationCalendarService.cs Uses shared ResolveTaskTitle helper for consistent, fallback-capable title resolution.
eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Infrastructure/Helpers/AreaRuleLanguageHelper.cs Adds existence-guarded remap helper for frontend-sourced translation ids.
eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/BackendConfiguration.Pn.csproj Exposes internals to unit test assembly for direct helper testing.
eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn.Test/Services/ResolveTaskTitleTests.cs Unit tests for title resolution fallbacks and whitespace handling.
eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn.Integration.Test/CalendarTranslationLanguageIdRemapTests.cs Integration tests validating remap behavior on shifted-id tenants.
eform-client/src/app/plugins/modules/backend-configuration-pn/modules/calendar/modals/task-create-edit-modal/task-create-edit-modal.component.ts Frontend now looks up Danish SDK language id from loaded languages instead of hardcoding 1.

Comment on lines +4452 to +4461
var list = translations?.ToList() ?? new List<AreaRuleTranslation>();
// 1) user-language, non-empty name
var byLang = list.FirstOrDefault(t => t.LanguageId == userLanguageId
&& !string.IsNullOrWhiteSpace(t.Name))?.Name;
if (!string.IsNullOrWhiteSpace(byLang)) return byLang!;
// 2) any translation with a non-empty name (cross-language fallback)
var any = list.FirstOrDefault(t => !string.IsNullOrWhiteSpace(t.Name))?.Name;
if (!string.IsNullOrWhiteSpace(any)) return any!;
// 3) caller-supplied fallback (e.g. compliance.ItemName), else empty
return string.IsNullOrWhiteSpace(finalFallback) ? "" : finalFallback!;
Comment on lines +386 to +389
// Remap each translate's LanguageId to the real SDK Languages.Id before it is persisted
// into PlanningNameTranslation and AreaRuleTranslations below. The calendar modal
// hardcodes the Danish source title to app-locale id 1, which is not a valid SDK id and
// would otherwise store the title under a language no reader ever queries (blank title).
Comment on lines +97 to +101
/// The calendar create/edit modal hardcodes the Danish source title's LanguageId to the
/// frontend app-locale id 1 (see task-create-edit-modal.component.ts), while target-language
/// translates already carry the real SDK Languages.Id returned by GET /settings/languages.
/// Persisting the verbatim id stores the Danish title under LanguageId=1, which no reader ever
/// queries (readers match against the user's SDK Languages.Id resolved by LanguageCode), so the
@renemadsen renemadsen merged commit 9419fbc into stable Jun 10, 2026
27 checks passed
@renemadsen renemadsen deleted the fix/calendar-translation-languageid-remap branch June 10, 2026 16:32
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.

2 participants