Add localization support for multi-language UI
This commit introduces comprehensive localization support for the application, enabling dynamic language switching and localized UI elements. Key changes include: - Added `.resx` files for German (de-DE), English (en-US), and French (fr-FR). - Updated Razor components to use `IStringLocalizer` for dynamic string localization. - Introduced the `L(string key, string fallback)` helper method for consistent localized string retrieval with fallback support. - Implemented dynamic culture initialization in `Program.cs` via an API call to `/api/Localization/lang`. - Localized error pages, grid columns, tabs, popups, validation messages, and tooltips. - Dynamically generated privacy policy links based on the current culture. - Improved user experience with fully localized loading states, error handling, and UI labels. These changes enhance accessibility and usability, making the application more user-friendly for a global audience.
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
@using EnvelopeGenerator.Server.Client.Services
|
||||
@using EnvelopeGenerator.Application.Resources
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.Extensions.Localization
|
||||
@using System.Globalization
|
||||
@inherits LayoutComponentBase
|
||||
@implements IDisposable
|
||||
|
||||
@inject ThemeService ThemeService
|
||||
@inject IStringLocalizer<Resource> UiLocalizer
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<HeadContent>
|
||||
<link href="@ThemeService.ThemeCssHref" rel="stylesheet" />
|
||||
@@ -18,7 +24,7 @@
|
||||
<div class="receiver-footer__left">
|
||||
<span>© SignFlow 2023-2024 <a href="https://digitaldata.works" target="_blank" rel="noopener">Digital Data GmbH</a></span>
|
||||
<span class="receiver-footer__sep">|</span>
|
||||
<a href="docs/privacy-policy.de-DE.html" target="_blank" rel="noopener">Datenschutz</a>
|
||||
<a href="@GetPrivacyPolicyPath()" target="_blank" rel="noopener">@L("PrivacyPolicy", "Datenschutz")</a>
|
||||
</div>
|
||||
|
||||
<div class="receiver-footer__right">
|
||||
@@ -35,6 +41,7 @@
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
Navigation.LocationChanged += OnLocationChanged;
|
||||
await FontLoader.LoadFonts(HttpClientFactory, ["opensans.ttf"]);
|
||||
_themeChangeHandler = () => InvokeAsync(StateHasChanged);
|
||||
ThemeService.OnChange += _themeChangeHandler;
|
||||
@@ -42,5 +49,31 @@
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> ThemeService.OnChange -= _themeChangeHandler;
|
||||
{
|
||||
ThemeService.OnChange -= _themeChangeHandler;
|
||||
Navigation.LocationChanged -= OnLocationChanged;
|
||||
}
|
||||
|
||||
private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
=> _ = InvokeAsync(StateHasChanged);
|
||||
|
||||
private string GetPrivacyPolicyPath()
|
||||
{
|
||||
var current = CultureInfo.CurrentUICulture.Name;
|
||||
var code = current switch
|
||||
{
|
||||
"de-DE" => "de-DE",
|
||||
"en-US" => "en-US",
|
||||
"fr-FR" => "fr-FR",
|
||||
_ => "de-DE"
|
||||
};
|
||||
|
||||
return $"docs/privacy-policy.{code}.html";
|
||||
}
|
||||
|
||||
string L(string key, string fallback)
|
||||
{
|
||||
var value = UiLocalizer[key];
|
||||
return value.ResourceNotFound ? fallback : value.Value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user