ASP.NET Core Globalization and Localization Series 2

In actual work, we often use ASP.NET Core’s Globalization & Localization features and resource files. Resource files (.resx) are used to separate language strings from code. These files contain key/values items. , you can use vs to create this file, for example: Your website supports 3 cultures – French, Spanish, English, so you have to create 2 types of resource files, such as French and Spanish

In this section I will show how to implement localization and globalization from different regions of the website

1 Controller uses IStringLocalizer object

2 Data Annotations error messages

3 Customer-defined validation error messages

4 Views use IViewLocalizer

We implement multilingual job application forms based on English, French and Spanish

1 Configure startup items

The first step is to tell the application the languages and cultures that the website will support, and add the Localization service and other settings to the application. Enter the Program class and add the following namespace:

using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Options;
using System.Globalization;

Next add the following code:

builder.Services.AddControllersWithViews()
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
                .AddDataAnnotationsLocalization();


builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
            new CultureInfo("en-US"),
            new CultureInfo("fr"),
            new CultureInfo("es")
        };
    options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;
});

This code does 2 things:

1. Add localization features to Data Annotations and Views

2. Your website supports 3 cultures – French, Spanish, and English are defined as default

Allow the use of Localization services in the application

var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);

Use resource files to create globalization & localization features in ASP.NET Core

2 Use resource file DataAnnotations for localization

First create a Model to present the application job application form, then create a new class in the Models folder and name it JobApplication.cs. This class contains the following properties: Name, Email Address, DOB, etc. Apply the characteristics to these On fields, like [Required], [RegularExpression], [Range], [Display]

code show as below:

using AspNetCore.GlobalLocalResFiles.Infrastructure;
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;


namespace AspNetCore.GlobalLocalResFiles.Models
{
    public class JobApplication
    {
        [Required(ErrorMessage = "Please provide your name")]
        [Display(Name = "Job applicant name")]
        public string Name { get; set; }


        [RegularExpression("^[a-zA-Z0-9_\.-] + @([a-zA-Z0-9-] + \.) + [a-zA-Z]{2,6}$ ", ErrorMessage = "E-mail is not valid")]
        [Display(Name = "Job applicant email")]
        public string Email { get; set; }
        [CustomDate]
        [Display(Name = "Date of Birth")]
        public DateTime DOB { get; set; }
        [Required(ErrorMessage = "Please select your sex")]
        [Display(Name = "Job applicant sex")]
        public string Sex { get; set; }
        [Range(2, 4, ErrorMessage = "{0} must be a number between {1} and {2}")]
        [Display(Name = "Job applicant experience")]
        public int Experience { get; set; }
        [Range(typeof(bool), "true", "true", ErrorMessage = "You must accept the Terms")]
        [Display(Name = "Terms")]
        public bool TermsAccepted { get; set; }
    }
}

Next, create resource files to store error messages and display names, so create two resource files in the Models folder and in the same directory as the JobApplication class: JobApplication.es.resx, JobApplication.fr.resx

NOTE: For the names of the resource files I used .es for spanish and .fr for french

In these resource files you can add strings (for example: error messages and display names) and their respective French and Spanish strings

As shown in the figure below, two resource files are displayed:

3ac26c2bd8eefc958a4d6b62fb524e42.png

873f5cb3984f8472bffd0f4c87556878.png

3 Customer-defined verification localization characters

We created a customer custom attribute called [CustomDate] for date of birth, specifying customer validation on the DOB field

[CustomDate]
[Display(Name = "Date of Birth")]
public DateTime DOB { get; set; }

Create a new class called CustomDate.cs in the Infrastructure folder. This class is responsible for validation, so you must inherit from the ValidationAttribute class. The code is as follows:

public class CustomDate : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var _localizationService = (IStringLocalizer<CustomDate>)validationContext.GetService(typeof(IStringLocalizer<CustomDate>));
        if ((DateTime)value > DateTime.Now)
            return new ValidationResult(_localizationService["Date of Birth cannot be in the future"]);
        else if ((DateTime)value < new DateTime(1980, 1, 1))
            return new ValidationResult(_localizationService["Date of Birth should not be before 1980"]);
        return ValidationResult.Success;
    }
}

The IStringLocalizer object is used to obtain the resource class at runtime. It is a service used to provide localized strings stored in resource files.

var _localizationService = (IStringLocalizer<CustomDate>)validationContext.GetService(typeof(IStringLocalizer<CustomDate>));

Note that I use the following code to get the language-specified string from the resource file

_localizationService["Date of Birth cannot be in the future"]
_localizationService["Date of Birth should not be before 1980"]

Next, create 2 resource files in the directory of the Custom verification class and name them:

CustomDate.es.resx

CustomDate.fr.resx

Add French and Spanish text strings to the resource file – Date of Birth cannot be in the future & Date of Birth should not be before 1980

4 The controller uses resource files for localization

When the form is submitted, the controller calls the action method. After the submission is successful, the information is displayed in these three languages based on the language and culture selected by the user.

Therefore, first we use the asp.net core dependency injection feature to inject the IStringLocalizer object in the constructor of the controller, and then traverse the language and culture associated with the string from the resource file. This message will be displayed to the form submitted by the user.

code show as below:

public class HomeController : Controller
{
    private readonly IStringLocalizer<HomeController> _localizer;
    public HomeController(IStringLocalizer<HomeController> localizer)
    {
        _localizer = localizer;
    }
    public IActionResult Index()
    {
        return View();
    }
    [HttpPost]
    public IActionResult Index(JobApplication jobApplication)
    {
        if (ModelState.IsValid)
            ViewBag.Message = _localizer["Your application is accepted"];
        return View();
    }
}

_localizer is a variable containing an IStringLocalizer object which basically gives me the culture specific string stored in the resource file

Next, create 2 resource files in the Controllers folder, named: HomeController.es.resx, HomeController.fr.resx

Since I only have a single string “Your application is accepted”, both resource files have only one entry

The following two pictures are my controller resource files:

d1279c33b2e5e84a65761df37a11b012.png

89fb7a2051403c2df2753303be132aaa.png

5 Views use resource files for localization

The IViewLocalizer service provides localization for view files, which can be injected into your view, as shown below:

@inject IViewLocalizer Localizer

The Job application form is in the Index view. First you add the necessary namespace to your view:

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Localization
@using Microsoft.Extensions.Options
@using Microsoft.AspNetCore.Mvc.Localization

Then inject IViewLocalizer & IOptions into the view, the code is as follows:

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

Through the RequestLocalizationOptions object, I will populate the selection control with the language culture supported by the website, the user can select their culture and the form will be presented to the user based on the selected culture

Next add the following code to create and populate the selection control items

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
}
<label>Language:</label>
<select onchange="SetCulture(this.value)" asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
</select>

This short piece of JavaScript code will jump to the job application form where the user selects the culture.

<script>
    function SetCulture(selectedValue) {
        var url = window.location.href.split('?')[0];
        var culture = "?culture=" + selectedValue + " & amp;ui-culture=" + selectedValue;
        window.location.href = url + culture;
    }
</script>

Here a QueryStringRequestCultureProvider is used, where the user selected culture is added to the query string of the url, so the French version of the application form will be given a url like this:

https://localhost:44356/?culture=fr & amp;ui-culture=fr

The Spanish version of the form URL is as follows:

https://localhost:44356/?culture=es & amp;ui-culture=es

For the English version, we don’t need to add language and culture to the url.

https://localhost:44356

Next we will add the form to the view:

<form class="m-1 p-1" asp-action="Index" asp-route-culture="@culture" asp-route-ui-culture="@uiculture" method="post">
    <div class="form-group">
        <label asp-for="Name"></label>
        <input asp-for="Name" class="form-control" />
        <span asp-validation-for="Name" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="DOB"></label>
        <input asp-for="DOB" type="text" asp-format="{0:d}" class="form-control" />
        <span asp-validation-for="DOB" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Sex"></label>
        <div>
            <input asp-for="Sex" type="radio" value="M" />@Localizer["Male"]
            <input asp-for="Sex" type="radio" value="F" />@Localizer["Female"]
        </div>
        <span asp-validation-for="Sex" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Experience"></label>
        <select asp-for="Experience" class="form-control">
            <option value="Select">@Localizer["Select"]</option>
            <option value="0">Fresher</option>
            <option value="1">0-1 years</option>
            <option value="2">1-2 years</option>
            <option value="3">2-3 years</option>
            <option value="4">3-4 years</option>
            <option value="5">4-5 years</option>
        </select>
        <span asp-validation-for="Experience" class="text-danger"></span>
    </div>
    <div class="form-group">
        <input asp-for="TermsAccepted" />
        <label asp-for="TermsAccepted" class="form-check-label">
            @Localizer["I accept the terms & conditions"]
        </label>
        <span asp-validation-for="TermsAccepted" class="text-danger"></span>
    </div>
    <button name="formsubmit" value="Button Control" type="submit" class="btn btn-primary">@Localizer["Submit Application"]</button>
</form>

In the view we use IViewLocalizer to get the culture-related string, using the code -@Localizer[“SomeString”]

The following is the radio control code:

<input asp-for="Sex" type="radio" value="M" />@Localizer["Male"]
<input asp-for="Sex" type="radio" value="F" />@Localizer["Female"]

Likewise, the terms tag does the same thing:

<label asp-for="TermsAccepted" class="form-check-label">
    @Localizer["I accept the terms & conditions"]
</label>

Next, create 2 resource files in the same directory as the view. As follows:

Index.es.resx

Index.fr.resx

Add necessary strings in the file as shown below

ed845922f519df2fa78201321879b36b.png

6d76180d5cd08508644e51ba9d18e3fc.png

6 Test

Next let’s do a test, the first one will display the culture selected by the user, and the associated culture form will be displayed in the browser:

0d3669ac534219c71de0e75337a550e0.png

e5ab85201fae3c98b22c259088efb663.png

Next, the data annotation information will be displayed in Spanish & French versions

b43a52cda5a3b99762aa85b037169a74.png

69a8b9664e0942f27d20603e515a5d90.png

7 Resource file location

You can use the following code in the startup item to change the location of the resource file

services.AddLocalization(options => options.ResourcesPath = "Resources");

In this case, the HomeController’s resource files should be in either of 2 locations:

1. In the Resources/Controllers/ directory:

Resources/Controllers/HomeController.es.resx

Resources/Controllers/HomeController.fr.resx

2. In the Resources directory:

Resources/Controllers.HomeController.es.resx

Resources/Controllers.HomeController.fr.resx

Data Annotations resource files are located in either of the following 2 locations:

Resources/Models.JobApplication.es.resx

Resources/Models.JobApplication.fr.resx

or

Resources/Models/JobApplication.es.resx

Resources/Models/JobApplication.fr.resx

View resource files are located in either of the following 2 locations:

Resources/Views.Home.Index.es.resx

Resources/Views.Home.Index.fr.resx

or

Resources/Views/Home/Index.es.resx

Resources/Views/Home/Index.fr.resx

Source code address:

https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/Fundamentals/AspNetCore.GlobalizationLocalization/AspNetCore.GlobalLocalResFiles

references

https://www.yogihosting.com/globalization-localization-resource-files-aspnet-core/