This is a continuation to my ASP.NET Core Localization Deep Dive.
Something which was asked here today by Dwayne Hawkins was:
Why can't it just use the SharedResources file, which I made for my views. I don't want 5000 seperate resx files for all my viewmodels ...
A very valid concern. If we have a lot of view models, we would not want to copy paste error message translations like "{0} is required" to hundreds of RESX files. Updates would be a nightmare. So I found a solution for the problem. I am not sure if it is the best solution, but it does work.
Configuring the Data Annotation Localizer Provider
First I noticed there is an overload on AddDataAnnotationsLocalization
which takes an Action which can be used to configure options.
The options class is pretty simple:
/// <summary>
/// Provides programmatic configuration for DataAnnotations localization in the MVC framework.
/// </summary>
public class MvcDataAnnotationsLocalizationOptions
{
/// <summary>
/// The delegate to invoke for creating <see cref="IStringLocalizer"/>.
/// </summary>
public Func<Type, IStringLocalizerFactory, IStringLocalizer> DataAnnotationLocalizerProvider;
}
It has only one property. But that is the delegate used to create the localizers! By default, it uses the type of the model to create a localizer with the localizer factory.
Here is what I did:
services.AddMvc().AddDataAnnotationsLocalization(o =>
{
o.DataAnnotationLocalizerProvider = (type, factory) =>
{
return factory.Create(typeof(SharedResource));
};
});
services.AddLocalization(o =>
{
o.ResourcesPath = "Resources";
});
SharedResource
here is an empty class.
I have a corresponding SharedResource.en-US.resx
and SharedResource.fi-FI.resx
file in my Resources folder.
This means any annotation localizations will now come from those files!
The Finnish RESX file contains values like this:
- Name: Nimi
- {0} is required: {0} on pakollinen
Then if we have a model, we can do annotations like this:
public class MyViewModel
{
[Display(Name = "Name")]
[Required(ErrorMessage = "{0} is required")]
public string Name { get; set; }
}
And we get localized error messages :)
Shorter article this time, hope this is useful!