14

I am using blazor 3.1 in latest version of VS 2019.

So far, I am able to localize page labels (title, table fields etc.).

On the ListEmployee.razor page, I am able to localize table heading etc. On the AddEmplyeeValidation.razor page, I am able to localize form labels but I have a problem localizing the validation messages.

For validation message for the Employee.cs file, validation message are defined in the Resources/Data folder in files Data.Employee.resx and Data.Employee.ar.resx but this doesn't seem to work.

    using System.ComponentModel.DataAnnotations;

    namespace BlazorSPA1.Data
    {
        public class Employee
        {
            [MaxLength(50)]
            public string Id { get; set; }

            [Required (ErrorMessage ="Name is RRRequired")]
            [StringLength(20, ErrorMessage = "Name is too long.")]
            public string Name { get; set; }

            [Required]
            [StringLength(20)]
            public string Department { get; set; }
            [MaxLength(100)]
            public string Designation { get; set; }
            [MaxLength(100)]
            public string Company { get; set; }
            [MaxLength(100)]
            public string City { get; set; }
        }
    }

How can I load the validation messages from the resource files based on language for my AddEmployeForm?

    @page "/addemployeeValidation"
    @inject NavigationManager NavigationManager
    @inject IEmployeeService EmployeeService
    @inject IStringLocalizer<AddEmployeeValidation> L

    <h2>Create Employee</h2>
    <hr />
    <EditForm Model="@employee" OnValidSubmit="@CreateEmployee">
        <DataAnnotationsValidator />
        <ValidationSummary />
        <div class="row">
            <div class="col-md-8">
                <div class="form-group">
                    <label for="Name" class="control-label">@L["Name"]</label>
                    <input for="Name" class="form-control" @bind="@employee.Name" />
                    <ValidationMessage For="@(()=> employee.Name)" />
                </div>
                <div class="form-group">
                    <label for="Department" class="control-label">@L["Department"]</label>
                    <input for="Department" class="form-control" @bind="@employee.Department" />
                </div>
                <div class="form-group">
                    <label for="Designation" class="control-label">@L["Designation"]</label>
                    <input for="Designation" class="form-control" @bind="@employee.Designation" />
                </div>
                <div class="form-group">
                    <label for="Company" class="control-label">@L["Company"]</label>
                    <input for="Company" class="form-control" @bind="@employee.Company" />
                </div>
                <div class="form-group">
                    <label for="City" class="control-label">@L["City"]</label>
                    <input for="City" class="form-control" @bind="@employee.City" />
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-md-4">
                <div class="form-group">
                    <input type="submit" class="btn btn-primary" value="Save" />
                    <input type="button" class="btn" @onclick="@Cancel" value="Cancel" />
                </div>
            </div>
        </div>
    </EditForm>

    @code {

        Employee employee = new Employee();

        protected async Task CreateEmployee()
        {
            await EmployeeService.CreateEmployee(employee);
            NavigationManager.NavigateTo("listemployees");
        }


        void Cancel()
        {
            NavigationManager.NavigateTo("listemployees");
        }
    }   

I have read a few articles and tried few thing but nothing seems to be working.

Here is my Startup.cs code:

        services.AddServerSideBlazor(options => options.DetailedErrors = true);
        services.AddLocalization(options => options.ResourcesPath = "Resources");
        var supportedCultures = new List<CultureInfo> { new CultureInfo("en"), new CultureInfo("ar") };
        services.Configure<RequestLocalizationOptions>(options =>
        {
            options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("en");
            options.SupportedUICultures = supportedCultures;
        });

I am using the following example for localization but it doesn't show how to localize error messages: https://www.c-sharpcorner.com/article/localization-in-blazor-server/

Folder structure image for reference:

enter image description here

Resource file example for English version in same way i have Arabic file also:

enter image description here

In the screenshot below, you will see field names are being pulled correctly from the Resource file but validation messages are not working and only display in English.

enter image description here

xDaevax
  • 2,002
  • 2
  • 24
  • 34
Learning
  • 17,618
  • 35
  • 153
  • 314

3 Answers3

16

Here is my solution for localizing data annotation error messages. I create two resource files, one for fields and another one for error messages.

  • DisplayNameResource for localizing fields
  • ErrorMessageResource for localizing error messages

enter image description here enter image description here enter image description here enter image description here

In view model class use Display attribute for localizing field name. To specify resource file use ResourceType property on Display attribute:

[Display(Name = "Address", ResourceType = typeof(DisplayNameResource))]

And on validation attributes use ErrorMessageResourceName and ErrorMessageResourceType to specify resource file:

[Required(ErrorMessageResourceName = "RequiredError", ErrorMessageResourceType = typeof(ErrorMessageResource))]

Here is full example:

public class SomeViewModel
{
    [Display(Name = "Address", ResourceType = typeof(DisplayNameResource))]
    [Required(ErrorMessageResourceName = "RequiredError", ErrorMessageResourceType = typeof(ErrorMessageResource))]
    [StringLength(256, ErrorMessageResourceName = "MaxLengthError", ErrorMessageResourceType = typeof(ErrorMessageResource))]
    public string Address { get; set; }

    [Display(Name = "Phone", ResourceType = typeof(DisplayNameResource))]
    [Required(ErrorMessageResourceName = "RequiredError", ErrorMessageResourceType = typeof(ErrorMessageResource))]
    [RegularExpression("^09([0-9]{9})$", ErrorMessageResourceName = "PhoneLengthError", ErrorMessageResourceType = typeof(ErrorMessageResource))]
    public string Phone { get; set; }

    [Display(Name = "Password", ResourceType = typeof(DisplayNameResource))]
    [Required(ErrorMessageResourceName = "RequiredError", ErrorMessageResourceType = typeof(ErrorMessageResource))]
    [StringLength(50, MinimumLength = 6, ErrorMessageResourceType = typeof(ErrorMessageResource), ErrorMessageResourceName = "MinxMaxLengthError")]
    public string Password { get; set; }

    [Display(Name = "ConfirmPassword", ResourceType = typeof(DisplayNameResource))]
    [Required(ErrorMessageResourceName = "RequiredError", ErrorMessageResourceType = typeof(ErrorMessageResource))]
    [StringLength(50, MinimumLength = 6, ErrorMessageResourceType = typeof(ErrorMessageResource), ErrorMessageResourceName = "MinxMaxLengthError")]
    [Compare("Password", ErrorMessageResourceName = "PasswordConfirmMisMatch", ErrorMessageResourceType = typeof(ErrorMessageResource))]
    public string ConfirmPassword { get; set; }
}

Error message for MaxLengthError is {0} cannot be longer than {1} character, so {0} will be replaced with localized filed name and {1} will be replaced with the 256 you specified on attribute [StringLength(256,...

Mohsen Esmailpour
  • 9,428
  • 1
  • 37
  • 60
  • 1
    I will try this out it seems it should work.. I would appreciate if you could post this on Github as this kind or question will often raised and there are huge number of multilingual options.. – Learning Jan 16 '20 at 03:28
  • 1
    @Learning I'll put complete example on github for sure. – Mohsen Esmailpour Jan 19 '20 at 05:54
  • This will be of great help to lot of programmer like me as Blazor doesnt have much example in my context... – Learning Jan 19 '20 at 06:57
1

This has been asked before:

How to add ViewModel localization to Blazor?

I suggested that using FluentValidation would be a better approach. Here is a link to my Github repo that demonstrates how it could work:

https://github.com/conficient/BlazorValidationLocalization

Quango
  • 9,088
  • 5
  • 38
  • 72
  • I had this kind of solution in mind but this will two modal files for each and if project is large it will become it difficult to manage, Yes this is a work around and make thing work... – Learning Jan 16 '20 at 03:31
  • Not quite sure what you mean by "two modal files". You can still use resx with FluentValidation. see https://fluentvalidation.net/localization – Quango Jan 16 '20 at 09:01
0

I did not tried this out!

In the offical docs of asp.net core there is section how to localize DataAnnotations Maybe you find some clues there.

Zsolt Bendes
  • 1,369
  • 8
  • 13
  • I am new to asp.net core i tried different thing but didnt work for before posting this questions i tried looking for solution on my own looking at example, trying different thing but it doesnt seems to work for my case... it bit difficult i am from asp.net webform background with no experience in asp.net MVC... so my focus is toward asp.net core Razor pages only .. let us see – Learning Jan 16 '20 at 03:24