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.
PM> Install-Package AspNetCore.Mvc.UrlLocalization
> dotnet add package AspNetCore.Mvc.UrlLocalization
- See Examples\AspNetCore3
- See Examples\AspNetCore2.2
- See Examples\AspNetCore2.2FullFramework
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
}
});
}
}
- Dave Ikin - davidikin45
This project is licensed under the MIT License
- Url culture provider using middleware as filters in ASP.NET Core 1.1.0
- Applying the RouteDataRequest CultureProvider globally with middleware as filters
- Using a culture constraint and catching 404s with the url culture provider
- Redirecting unknown cultures to the default culture when using the url culture provider
- Localized routes with ASP.NET 5 and MVC 6
- ASP.NET Core 2.1 MVC localized routing
- Dynamic controller routing in ASP.NET Core 3.0