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.
94 lines
2.9 KiB
Plaintext
94 lines
2.9 KiB
Plaintext
@using EnvelopeGenerator.Server.Client.Services
|
|
@using EnvelopeGenerator.Application.Resources
|
|
@using Microsoft.Extensions.Localization
|
|
@rendermode InteractiveWebAssembly
|
|
|
|
@inject LocalizationService LocalizationService
|
|
@inject NavigationManager Navigation
|
|
@inject IStringLocalizer<Resource> UiLocalizer
|
|
|
|
<div class="sf-lang-combo">
|
|
<button type="button"
|
|
class="sf-lang-trigger"
|
|
@onclick="ToggleMenu"
|
|
aria-label="@L("Language", "Language")"
|
|
aria-expanded="@_isOpen">
|
|
<span class="fi @_selected.FlagClass"></span>
|
|
</button>
|
|
|
|
@if (_isOpen)
|
|
{
|
|
<button type="button"
|
|
class="sf-lang-backdrop"
|
|
aria-label="@L("CloseLanguageMenu", "Close language menu")"
|
|
@onclick="CloseMenu">
|
|
</button>
|
|
|
|
<div class="sf-lang-menu" role="listbox" aria-label="@L("Languages", "Languages")">
|
|
@foreach (var option in _options)
|
|
{
|
|
<button type="button"
|
|
class="sf-lang-option @(_selected.Code == option.Code ? "sf-lang-option--active" : string.Empty)"
|
|
role="option"
|
|
aria-selected="@(_selected.Code == option.Code)"
|
|
@onmousedown:preventDefault="true"
|
|
@onclick="() => SelectLanguageAsync(option)">
|
|
<span class="fi @option.FlagClass"></span>
|
|
<span>@option.ShortName</span>
|
|
</button>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
@code {
|
|
private readonly IReadOnlyList<LanguageOption> _options =
|
|
[
|
|
new("de-DE", "fi-de", "DE"),
|
|
new("en-US", "fi-us", "EN"),
|
|
new("fr-FR", "fi-fr", "FR")
|
|
];
|
|
|
|
private LanguageOption _selected = new("de-DE", "fi-de", "DE");
|
|
private bool _isOpen;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
var currentLanguage = await LocalizationService.GetLanguageAsync();
|
|
_selected = _options.FirstOrDefault(x => x.Code.Equals(currentLanguage, StringComparison.OrdinalIgnoreCase))
|
|
?? _options[0];
|
|
}
|
|
|
|
private void ToggleMenu()
|
|
{
|
|
_isOpen = !_isOpen;
|
|
}
|
|
|
|
private void CloseMenu()
|
|
{
|
|
_isOpen = false;
|
|
}
|
|
|
|
private async Task SelectLanguageAsync(LanguageOption option)
|
|
{
|
|
if (_selected.Code.Equals(option.Code, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_isOpen = false;
|
|
return;
|
|
}
|
|
|
|
_selected = option;
|
|
_isOpen = false;
|
|
await LocalizationService.SetLanguageAsync(option.Code);
|
|
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
|
|
}
|
|
|
|
private sealed record LanguageOption(string Code, string FlagClass, string ShortName);
|
|
|
|
string L(string key, string fallback)
|
|
{
|
|
var value = UiLocalizer[key];
|
|
return value.ResourceNotFound ? fallback : value.Value;
|
|
}
|
|
}
|