Adds localization support across application views

Implements localization for dashboard, cash register, account, and profile sections

Adds localization keys for various UI elements, improving internationalization support
Refactors view components to use ILocalizationService for dynamic text rendering
Prepares ground for multi-language support with translation-ready markup
This commit is contained in:
Janus C. H. Knudsen 2026-01-12 15:42:18 +01:00
parent 1f400dcc6e
commit ef174af0e1
36 changed files with 821 additions and 263 deletions

View file

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using PlanTempus.Application.Features.Localization.Services;
namespace PlanTempus.Application.Features.Dashboard.Components;
@ -7,9 +8,16 @@ namespace PlanTempus.Application.Features.Dashboard.Components;
/// </summary>
public class StatCardViewComponent : ViewComponent
{
private readonly ILocalizationService _localization;
public StatCardViewComponent(ILocalizationService localization)
{
_localization = localization;
}
public IViewComponentResult Invoke(string key)
{
var model = StatCardCatalog.Get(key);
var model = StatCardCatalog.Get(key, _localization);
return View(model);
}
}
@ -29,61 +37,84 @@ public class StatCardViewModel
public bool HasTrend => !string.IsNullOrEmpty(TrendText);
}
/// <summary>
/// Internal data for stat cards (uses localization keys).
/// </summary>
internal class StatCardData
{
public required string Key { get; init; }
public required string Value { get; init; }
public required string LabelKey { get; init; }
public string? TrendTextKey { get; init; }
public string? TrendIcon { get; init; }
public string? TrendDirection { get; init; }
public string? Variant { get; init; }
}
/// <summary>
/// Catalog of available stat cards with their data.
/// </summary>
public static class StatCardCatalog
{
private static readonly Dictionary<string, StatCardViewModel> Cards = new()
private static readonly Dictionary<string, StatCardData> Cards = new()
{
["bookings-today"] = new StatCardViewModel
["bookings-today"] = new StatCardData
{
Key = "bookings-today",
Value = "12",
Label = "Bookinger i dag",
TrendText = "4 gennemført, 2 i gang",
LabelKey = "dashboard.stats.bookingsToday",
TrendTextKey = "dashboard.stats.bookingsTrend",
TrendIcon = "ph-check-circle",
TrendDirection = "up",
Variant = "highlight"
},
["expected-revenue"] = new StatCardViewModel
["expected-revenue"] = new StatCardData
{
Key = "expected-revenue",
Value = "8.450 kr",
Label = "Forventet omsætning",
TrendText = "+12% vs. gennemsnit",
LabelKey = "dashboard.stats.expectedRevenue",
TrendTextKey = "dashboard.stats.revenueTrend",
TrendIcon = "ph-trend-up",
TrendDirection = "up",
Variant = "success"
},
["occupancy-rate"] = new StatCardViewModel
["occupancy-rate"] = new StatCardData
{
Key = "occupancy-rate",
Value = "78%",
Label = "Belægningsgrad",
TrendText = "God kapacitet",
LabelKey = "dashboard.stats.occupancyRate",
TrendTextKey = "dashboard.stats.occupancyTrend",
TrendIcon = "ph-trend-up",
TrendDirection = "up",
Variant = null
},
["needs-attention"] = new StatCardViewModel
["needs-attention"] = new StatCardData
{
Key = "needs-attention",
Value = "4",
Label = "Kræver opmærksomhed",
TrendText = null,
LabelKey = "dashboard.stats.needsAttention",
TrendTextKey = null,
TrendIcon = null,
TrendDirection = null,
Variant = "warning"
}
};
public static StatCardViewModel Get(string key)
public static StatCardViewModel Get(string key, ILocalizationService localization)
{
if (Cards.TryGetValue(key, out var card))
return card;
if (!Cards.TryGetValue(key, out var card))
throw new KeyNotFoundException($"StatCard with key '{key}' not found");
throw new KeyNotFoundException($"StatCard with key '{key}' not found");
return new StatCardViewModel
{
Key = card.Key,
Value = card.Value,
Label = localization.Get(card.LabelKey),
TrendText = card.TrendTextKey != null ? localization.Get(card.TrendTextKey) : null,
TrendIcon = card.TrendIcon,
TrendDirection = card.TrendDirection,
Variant = card.Variant
};
}
public static IEnumerable<string> AllKeys => Cards.Keys;