Quantcast
Channel: ASP.NET Core – Software Engineering
Viewing all articles
Browse latest Browse all 269

ASP.NET Core 1.0 MVC 6 Localization

$
0
0

This article shows some of the ways in which localization can be used in a MVC 6 ASP.NET Core 1.0 application.

Code: https://github.com/damienbod/AspNet5Localization

20.11.2015: ASP.NET Core 1.0 rc1 version

Localization Setup

The localization is configured in the setup class and can be used throughout the application per dependency injection. The AddLocalization method is used in the ConfigureServices to define the resources and localization. This can then be used in the Configure method. Here, the RequestLocalizationOptions can be defined and is added to the stack using the UseRequestLocalization method. You can also define different options as required, for example the Accept-Header provider could be removed or a custom provider could be added.

using System.Collections.Generic;
using System.Globalization;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Localization;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Logging;

namespace AspNet5Localization
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddLocalization(options => options.ResourcesPath = "Resources");

            services.AddMvc()
                .AddViewLocalization()
                .AddDataAnnotationsLocalization();

            services.AddScoped<LanguageActionFilter>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.MinimumLevel = LogLevel.Information;
            loggerFactory.AddConsole();
            loggerFactory.AddDebug();

            var requestLocalizationOptions = new RequestLocalizationOptions
            {
                DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US")),
                SupportedCultures = new List<CultureInfo>
                {
                    new CultureInfo("en-US"), 
                    new CultureInfo("de-CH"), 
                    new CultureInfo("fr-CH"), 
                    new CultureInfo("it-CH")
                },
                SupportedUICultures = new List<CultureInfo>
                {
                    new CultureInfo("en-US"), 
                    new CultureInfo("de-CH"), 
                    new CultureInfo("fr-CH"), 
                    new CultureInfo("it-CH")
                }
            };

            app.UseRequestLocalization(requestLocalizationOptions);

            app.UseIISPlatformHandler();

            app.UseStaticFiles();

            app.UseMvc();
        }
    }
}

The localization can be used for example in a MVC 6 controller. This is done by defining the IHtmlLocalizer with the name of your resx file(s). The resx files are defined in the folder defined in the Startup class AddLocalization method. The IHtmlLocalizer can then be used to return localized properties. A shared resource requires an emtpy class and special resource naming so that the magic string conventions work and the resource can be found. See the code for this.

using System.Globalization;
using System.Threading;
using AspNet5Localization.Resources;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Localization;

namespace AspNet5Localization.Controllers
{
    [Route("api/[controller]")]
    public class AboutController : Controller
    {
        private IHtmlLocalizer<AmazingResource> _htmlLocalizer;

        public AboutController(IHtmlLocalizer<AmazingResource> localizer)
        {
            _htmlLocalizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _htmlLocalizer["Name"];
        }
    }
}

Setting the culture in the Query

The culture required by the client application can be set in the query using the ?culture=de-CH.

To test this, the application needs to be started in the console due to a Visual Studio Tooling bug.

Open the application in the src folder and

dnu restore

dnx web

Now the query localization can be tested or used as follows:

http://localhost:5000/api/About?culture=de-CH

http://localhost:5000/api/About?culture=it-CH 

Setting the culture in the Accept Header

The HTTP Request Accept-Language header can also be used to request from the server the required culture.

This is implemented as follows for the de-CH culture

GET http://localhost:5000/api/About HTTP/1.1

Accept: */*
Accept-Language: de-CH
Host: localhost:5000

Or implemented as follows for the it-CH culture

GET http://localhost:5000/api/About HTTP/1.1

Accept: */*
Accept-Language: it-CH
Host: localhost:5000

Setting the culture in the Request URL

The culture can also be set in the URL. This is not supported out of the box and you must implement this yourself for example using an action filter.

The action filter can be implemented as follows:

using System.Globalization;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.Framework.Logging;

namespace AspNet5Localization
{
    public class LanguageActionFilter : ActionFilterAttribute
    {
        private readonly ILogger _logger;

        public LanguageActionFilter(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger("LanguageActionFilter");
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {         
            string culture = context.RouteData.Values["culture"].ToString();
            _logger.LogInformation($"Setting the culture from the URL: {culture}");

#if DNX451
            System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
            System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
#else
            CultureInfo.CurrentCulture = new CultureInfo(culture);
            CultureInfo.CurrentUICulture = new CultureInfo(culture);
#endif
            base.OnActionExecuting(context);
        }
    }
}

The culture value is defined as route data and this is then used to set the culture.

The action filter is then registered in the Startup ConfigureServices method.

public void ConfigureServices(IServiceCollection services)
{
	services.AddLocalization(options => options.ResourcesPath = "Resources");

	services.AddMvc()
		.AddViewLocalization()
		.AddDataAnnotationsLocalization();

	services.AddScoped<LanguageActionFilter>();
}

This can then be used in a controller using an attribute routing parameter and applying the action filter to the controller class.

using System.Globalization;
using System.Threading;
using AspNet5Localization.Resources;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Localization;

namespace AspNet5Localization.Controllers
{
    [ServiceFilter(typeof(LanguageActionFilter))]
    [Route("api/{culture}/[controller]")]
    public class AboutWithCultureInRouteController : Controller
    {
        // http://localhost:5000/api/it-CH/AboutWithCultureInRoute
        // http://localhost:5000/api/fr-CH/AboutWithCultureInRoute

        private IHtmlLocalizer<AmazingResource> _htmlLocalizer;

        public AboutWithCultureInRouteController(IHtmlLocalizer<AmazingResource> localizer)
        {
            _htmlLocalizer = localizer;
        }

        [HttpGet]
        public string Get()
        {
            return _htmlLocalizer["Name"];
        }
    }
}

This can then be used as follows:

 http://localhost:5000/api/it-CH/AboutWithCultureInRoute
 
 http://localhost:5000/api/fr-CH/AboutWithCultureInRoute

This is very useful if you cannot rely on the browser culture.

Notes

Localization in MVC 6 is not flexible enough for most requirements. At present, the Visual Studio Tooling does not work and some of the implementation is not yet polished. The usage of magic strings is a pain. If you do not want to implement the IStringLocalizerFactory and/or IStringLocalizer, you need to follow this magic string convention.

It is also not possible to add resx files to a MVC 6 application using Visual Studio. This will be supported. It is also possible to use the localization in Razor views if your not implementing a Javascript client. See the links underneath for further reading on this.

Links:

https://github.com/aspnet/Localization

https://github.com/aspnet/Tooling/issues/236

http://www.jerriepelser.com/blog/how-aspnet5-determines-culture-info-for-localization

https://github.com/WeebDo/WeebDo.CMF

https://github.com/joeaudette/cloudscribe

https://github.com/aspnet/Mvc/tree/dev/test/WebSites/LocalizationWebSite

Example of localization middleware for culture in route

http://weblogs.asp.net/jeff/beating-localization-into-submission-on-asp-net-5

https://github.com/joeaudette/experiments

https://github.com/avodovnik/Cancel/tree/master/Source/Demo06.ViewLocationExpanders



Viewing all articles
Browse latest Browse all 269

Trending Articles