Культура по умолчанию в маршрутизации URL при локализации
Недавно я взял на себя огромный проект C# MVC. Он локализован на английский и норвежский, но у меня есть некоторые проблемы с локализацией и с тем, как правильно установить маршрут. Я хочу добиться следующего:
- / controller / action -> должен отображаться на язык по умолчанию (норвежский)
- / no / controller / action -> должен отображаться на странице на норвежском
- / en / controller / action -> должен отображаться на странице на английском языке
Во всех случаях URL должен оставаться прежним. Нужно ли мне устанавливать отдельный нелокализованный маршрут для всех случаев, как я сделал для страницы входа? Вот основная часть кода:
routes.MapRoute(
name: "metaRelated",
url: "related/{type}/{id}",
defaults: new { controller = "Meta", action = "Related" }
).RouteHandler = new MultiCultureMvcRouteHandler();
routes.MapRoute(
name: "login",
url: "Login",
defaults: new { controller = "Login", action = "Login" }
).RouteHandler = new MultiCultureMvcRouteHandler();
routes.MapRoute(
name: "loginNoCulture",
url: "Login",
defaults: new { controller = "Login", action = "Login", culture = UrlParameter.Optional }
).RouteHandler = new MvcRouteHandler();
routes.MapRoute(
name: "actionStatus",
url: "DocumentActions/{ActionStatus}/{DocumentId}",
defaults: new { controller = "Action", action = "Index", DocumentId = UrlParameter.Optional }
).RouteHandler = new MultiCultureMvcRouteHandler();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
).RouteHandler = new MultiCultureMvcRouteHandler();
foreach (Route r in routes)
{
if (r.RouteHandler is MultiCultureMvcRouteHandler)
{
r.RouteHandler = new MultiCultureMvcRouteHandler();
r.Url = "{culture}/" + r.Url;
// Adding default culture
if (r.Defaults == null)
r.Defaults = new RouteValueDictionary();
r.Defaults.Add("culture", Culture.No.ToString().ToLower());
// Adding constraint for culture param
if (r.Constraints == null)
r.Constraints = new RouteValueDictionary();
r.Constraints.Add("culture", new CultureConstraint(Culture.En.ToString().ToLower(), Culture.No.ToString().ToLower(), Culture.Nl.ToString().ToLower()));
}
}
Вот класс MultiCultureMvcRouteHandler:
public class MultiCultureMvcRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var culture = requestContext.RouteData.Values["culture"].ToString();
var ci = new CultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name);
return base.GetHttpHandler(requestContext);
}
}
1 ответ
Я столкнулся с необходимостью сделать это. Мой вариант использования был для веб-API .NET 5.
После изучения вариантов (несколько дней биться головой о клавиатуру) я нашел хорошее решение. Я использовал фильтр действий на глобальном уровне.
Вот класс ActionFilter
/// <summary>
/// This filter sets the Thread.CurrentThread.CurrentCulture To the culture property of the route.
/// </summary>
public class CultureActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
try
{
if (context.RouteData.Values.ContainsKey("culture"))
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(context.RouteData.Values["culture"].ToString());
}
catch { }
await next();
}
}
Как видите, это довольно просто. Он смотрит, есть ли культура в данных маршрута, а затем пытается проанализировать ее и установить текущую культуру потока.
В Настройках служб
services.AddControllers(config => config.Filters.Add(new CultureActionFilter()));
services.Configure<RequestLocalizationOptions>(options =>
{
options.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US-POSIX"), new CultureInfo("en-US"));
options.SupportedCultures = new List<CultureInfo>(_allowedCultures);
options.SupportedUICultures = new List<CultureInfo>(_allowedCultures);
options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
services.AddSingleton(options);
});
services.AddRouting(options =>
{
options.LowercaseUrls = true;
});
Затем в Настройках
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Теперь вы можете проверить это в контроллере, добавив {culture} к маршруту. Пример
[Route("v{version:apiVersion}/{culture}/[controller]/[action]")]
Затем вы можете использовать его так в методе.
[HttpGet]
public IActionResult Test()
{
return Ok(Thread.CurrentThread.CurrentCulture.EnglishName);
}
Вызовите так: http://localhost:41121/v1/fr-CA/maintenance/test
Возвращает французский (Канада)