Skip to content

davidikin45/AspNetCore.Mvc.UrlLocalization

Repository files navigation

ASP.NET Core Url Localization

nuget Downloads

By default ASP.NET comes with support for Globalization and Localization

  • Formatting - (Dates, Currencies, Numbers) - CultureInfo.CurrentCulture
  • Resource Localization via Resx files - CultureInfo.CurrentUICulture

The aim of this package is to build on top of Resource Localization to provide Url Localization (Link Generation) and Unlocalization (Request Processing) via files named Url.{culture}.resx. Unlocalized routes will continue to work for any culture until a localization is provided. For example /privacy would initially also work for /es/privacy also. Once a url route was included in Url.es.resx for 'Privacy' > 'Intimidad' the middleware (by default) would redirect /es/privacy > /es/intimidad. This functionality can be changed so a 404 is returned or the request is still processed. Inject IUrlLocalizer into views to localize link text, often the link text is the same as the url route so in that case only one replacement would need to be added.

Url Resource Files

Resx

Installation

NuGet

PM> Install-Package AspNetCore.Mvc.UrlLocalization

.Net CLI

> dotnet add package AspNetCore.Mvc.UrlLocalization

Examples

  • See Examples\AspNetCore3
  • See Examples\AspNetCore2.2
  • See Examples\AspNetCore2.2FullFramework

Quick Start ASP.NET Core 3.0

public class Startup
{
	public Startup(IConfiguration configuration)
	{
		Configuration = configuration;
	}

	public IConfiguration Configuration { get; }

	public bool RedirectCulturelessToDefaultCulture = false;

	// This method gets called by the runtime. Use this method to add services to the container.
	public void ConfigureServices(IServiceCollection services)
	{
		services.AddLocalization(options => options.ResourcesPath = "Resources");
		services.AddUrlLocalization();

		services.AddCultureRouteConstraint("cultureCheck");

		services.AddControllersWithViews(options =>
		{
			//Adds {culture:cultureCheck} to ALL routes
			if (RedirectCulturelessToDefaultCulture)
				options.AddCultureAttributeRouteConvention("culture", "cultureCheck");
			else
				options.AddOptionalCultureAttributeRouteConvention("culture", "cultureCheck");

			//options.Filters.Add(new MvcUrlLocalizationFilterAttribute());
		})
		.AddRazorPagesOptions(options => {
			if (RedirectCulturelessToDefaultCulture)
				options.AddCultureAttributeRouteConvention();
			else
				options.AddOptionalCultureAttributeRouteConvention();
		})
		.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
		.AddDataAnnotationsLocalization()
		.AddActionLinkLocalization()
		.AddAmbientRouteDataUrlHelperFactory(options =>
		{
			options.AmbientRouteDataKeys.Add(new AmbientRouteDataKey("area", false));
			options.AmbientRouteDataKeys.Add(new AmbientRouteDataKey("culture", true));
			options.AmbientRouteDataKeys.Add(new AmbientRouteDataKey("ui-culture", true));
		});

		var supportedCultures = new[]
		 {
			new CultureInfo("en-US"),
			new CultureInfo("es"),
			new CultureInfo("fr"),
			new CultureInfo("de")
		};

		services.Configure<RequestLocalizationOptions>(options =>
		{
			options.DefaultRequestCulture = new RequestCulture("en-US");
			// Formatting numbers, dates, etc.
			options.SupportedCultures = supportedCultures;
			// UI strings that we have localized.
			options.SupportedUICultures = supportedCultures;
			options.RequestCultureProviders = new List<IRequestCultureProvider>()
			{
				 new RouteDataRequestCultureProvider() { Options = options, RouteDataStringKey = "culture", UIRouteDataStringKey = "ui-culture" },
				 new UrlRequestCultureProvider(),
				 new QueryStringRequestCultureProvider() { QueryStringKey = "culture", UIQueryStringKey = "ui-culture" },
				 new CookieRequestCultureProvider(),
				 new AcceptLanguageHeaderRequestCultureProvider(),
			};
		});

		services.AddSingleton(sp => sp.GetService<IOptions<RequestLocalizationOptions>>().Value);

		services.Configure<RedirectUnsupportedUrlCulturesOptions>(options =>
		{
			options.RedirectUnspportedCulturesToDefaultCulture = true;
			options.RedirectCulturelessToDefaultCulture = RedirectCulturelessToDefaultCulture;
		});

		services.AddSingleton(sp => sp.GetService<IOptions<RedirectUnsupportedUrlCulturesOptions>>().Value);

		services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
	}

	// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
	public void Configure(IApplicationBuilder app, IWebHostEnvironment env, RequestLocalizationOptions localizationOptions, RedirectUnsupportedUrlCulturesOptions redirectUnsupportedUrlCulturesOptions)
	{
		if (env.IsDevelopment())
		{
			app.UseDeveloperExceptionPage();
		}
		else
		{
			app.UseExceptionHandler("/Home/Error");
			// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
			app.UseHsts();
		}
		app.UseHttpsRedirection();        

		app.UseStaticFiles();

		app.UseRequestLocalization(localizationOptions);
		app.UseRedirectUnsupportedUrlCultures(redirectUnsupportedUrlCulturesOptions);
		app.UseUrlUnlocalization();

		app.UseRouting();

		app.UseAuthorization();

		app.UseEndpoints(endpoints =>
		{
			if (redirectUnsupportedUrlCulturesOptions.RedirectCulturelessToDefaultCulture)
			{
				endpoints.MapControllerRoute(
				 name: "defaultWithCulture",
				 pattern: "{culture:cultureCheck}/{controller=Home}/{action=Index}/{id?}");

				//Other Routes

				endpoints.RedirectCulturelessToDefaultCulture();
			}
			else
			{
				endpoints.MapControllerRoute(
				name: "default",
				pattern: "{controller=Home}/{action=Index}/{id?}");

				endpoints.MapControllerRoute(
				 name: "defaultWithCulture",
				 pattern: "{culture:cultureCheck}/{controller=Home}/{action=Index}/{id?}");

				//Other Routes
			}
		});
	}
}

Authors

License

This project is licensed under the MIT License

Acknowledgments

About

ASP.NET Core Library for implementing Url Localization using resource files

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages