Description
In my case, I have custom localization service (like IStringLocalizer
), that retrieve localization from database for user-specific culture. User culture configures in user settings, that may changes in application runtime, i.e. without page reload.
ILocalizationService
{
string this[string key] { get; }
string GetString(string key);
void ChangeLanguage(CultureInfo culture);
}
Service registers as scoped, i.e. each user have own ILocalizationService
with own specific culture settings.
services.AddScoped<ILocalizationService, LocalizationService>();
In components this works great, just inject service.
@page "/some-page"
@inject ILocalizationService T
<h1>@T["SomeText"]</h1>
Of course, this does not work in standard case of using data annotation attributes. For example:
User
{
[Required]
[Display(Name = "Name")]
string Name { get; set; }
[Display(Name = "Email")]
string Email { get; set; }
}
Data annotation attributes can be provided with custom type with localized strings. Something like this:
User
{
[Required(ErrorMessageResourceName = "Validation_Required", ErrorMessageResourceType = typeof(LocalizationResources))]
[Display(Name = "Name", ResourceType = typeof(LocalizationResources))]
string Name { get; set; }
[Display(Name = "Email", ResourceType = typeof(LocalizationResources))]
string Email { get; set; }
}
LocalizationResources
{
public static string Name => GetString();
public static string Email => GetString();
public static string Validation_Required => GetString();
public static Func<ILocalizationService> LocalizationServiceProvider { get; set; }
public static string GetString([CallerMemberName] string key = null)
{
return LocalizationServiceProvider().GetString(key);
}
}
Main problem of this approach is that localized strings in LocalizationResources
must be as static properties. So we cant directly inject user-specific ILocalizationService
. But we can try get user-specific ILocalizationService
via Func<ILocalizationService> LocalizationServiceProvider
that can be configured, for example, in Configure()
method:
public void Configure(IServiceProvider serviceProvider)
{
LocalizationResources.LocalizationServiceProvider = () => serviceProvider.GetRequiredService<ILocalizationService>();
}
Of course, this does not work, because of scope of serviceProvider
in Configure()
method differs from user-specific scopes. In order for this approach to work it is necessary in LocalizationResources.LocalizationServiceProvider
uses some kind of context that will provide user-scoped IServiceProvider
to resolve user-specific ILocalizationService
.
So, at this moment, in server-side Blazor is exists any method to localize the data annotation attributes in non-resx scenarios? Have a plan to implement its in future?