@model List<GAP_Compressor.Models.Language>
@if (Model != null && Model.Any())
{
var returnUrl = Context.Request.Url?.PathAndQuery ?? "";
foreach (var lang in Model)
{
<li>
<a href="@Url.Action("SetLanguage", "_Layout", new { languageID = lang.language_id, languageCode = lang.code, returnUrl = returnUrl })">
<img src="@lang.image_path" alt="@lang.code"> @lang.code
</a>
</li>
}
}
public ActionResult SetLanguage(int languageID, string languageCode, string returnUrl = "/")
{
LanguageHelper.SetLanguage(languageID, languageCode);
return Redirect(string.IsNullOrEmpty(returnUrl) ? Url.Action("Index", "Home") : returnUrl);
}
public static class LanguageHelper
{
private const int defaultLanguageID = 1;
private const string defaultLanguageCode = "tr";
public static int GetCurrentLanguageID()
{
return HttpContext.Current.Session["languageID"] as int? ?? defaultLanguageID;
}
public static string GetCurrentLanguageCode()
{
if (HttpContext.Current.Session != null)
{
return HttpContext.Current.Session["languageCode"] as string ?? defaultLanguageCode;
}
return defaultLanguageCode;
}
public static void SetLanguage(int languageID, string languageCode)
{
HttpContext.Current.Session["languageID"] = languageID;
HttpContext.Current.Session["languageCode"] = languageCode;
}
}
routes.MapRoute(
name: "Localized",
url: "{languageCode}/{controller}/{action}/{id}",
defaults: new { languageCode = "tr", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Reposunu verirsen Debug yaparak çözebilirim.
Tam olarak anlayamadım durumu? Session'a Lang'i zaten URL'e göre yazmıyor musunuz?
Anladim, yani normalde Localization icin Core MVC'nin built-in destegi vardi neden onu kullanmadiniz bilemiyorum. Sorununuza soyle yaklasalim, siz her URL'in "/tr/anasayfa" gibi bir dil belirteci ile alinmasini istiyorsunuz. Bunun icin gerekli Route'u da olusturmussunuz.
Siradaki adim olarak bir Middleware ile bu languageCode'u alip servislerinize iletmeniz gerekiyor.
Fakat kilit nokta şu, .NET MVC mi yaziyorsunuz yoksa .NET Core MVC mi? Ona gore yardima devam edeyim.
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if(requestContext.HttpContext.IsPostNotification || requestContext.HttpContext.Request.IsAjaxRequest() || requestContext.HttpContext.Method != "GET")
return base.GetControllerInstance(requestContext, controllerType);
var langId = LanguageHelper.GetCurrentLanguageID();
var langCode = LanguageHelper.GetCurrentLanguageCode();
if(langCode != requestContext.RouteData.Values["lang"].ToString()){
var controller = requestContext.RouteData.Values["controller"];
var action = requestContext.RouteData.Values["action"];
var id = requestContext.RouteData.Values["id"];
requestContext.HttpContext.Response.RedirectToRoute(new { lang = langCode, controller = controller, action = action, id = id });
}
return base.GetControllerInstance(requestContext, controllerType);
}
}
routes.MapRoute(
name: "Localized",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { lang = "tr", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
Çok teşekkür ederim hocam. Yarın bilgisayara geçtiğim gibi deneyeceğim. İlginiz için çok teşekkürler.Ücrete gerek yok, ben size yine yardım ederim. Dediğiniz gibi işler buradan baya karmaşık oluyor.
.NET MVC'de Middleware desteği yoktu, dolayısıyla request pipeline'ında bu lokalizasyonu farklı bir yere koymamız gerek.
Simdi .NET MVC'nin yasam dongusunde her istek icin Controller ornegi yaratilir. Hem de RouteData kullanilarak ki bu da burayi interception icin mantıklı kıldı benim gözümde.
Bahsettiğimiz noktayı intercept etmek için özel bir ControllerFactory'e ihtiyacımız var. Yine de biz bütün methodları kendimiz implemente etmek istemediğimiz için .NET MVC'de built-in gelen DefaultControllerFactory'i dekore ederek ilerleyelim.
Kod:public class CustomControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if(requestContext.HttpContext.IsPostNotification || requestContext.HttpContext.Request.IsAjaxRequest() || requestContext.HttpContext.Method != "GET") return base.GetControllerInstance(requestContext, controllerType); var langId = LanguageHelper.GetCurrentLanguageID(); var langCode = LanguageHelper.GetCurrentLanguageCode(); if(langCode != requestContext.RouteData.Values["lang"].ToString()){ var controller = requestContext.RouteData.Values["controller"]; var action = requestContext.RouteData.Values["action"]; var id = requestContext.RouteData.Values["id"]; requestContext.HttpContext.Response.RedirectToRoute(new { lang = langCode, controller = controller, action = action, id = id }); } return base.GetControllerInstance(requestContext, controllerType); } }
Tabii bunun çalışması için RouteConfig'deki ayarınız şöyle olmalı:
C#:routes.MapRoute( name: "Localized", url: "{lang}/{controller}/{action}/{id}", defaults: new { lang = "tr", controller = "Home", action = "Index", id = UrlParameter.Optional } );
Bu sayede artık seçilen dile göre URL'ye otomatik olarak "/tr" "/en" olarak eklenecektir. Controller adlarını da lokalize etmek istiyorsanız size sağladığım ControllerFactory üzerinde matching yapabilirsiniz ki bu maalesef performans zaafiyetine sebep olur.
Ayrıca kodda elimden geldiğince POST, Ajax isteklerini redirect etmemesi için uğraştım. Fakat gözümden kaçan noktalar olabilir. Burası için kendi kurallarınızı belirleyebilirsiniz, zira HttpContext'e erişip dilediğiniz noktayı kontrol edebilirsiniz.
Ardından yazdığımız bu ControllerFactory'i kullanması için Global.asax.cs üzerinde şu kodu eklememiz gerekiyor:
C#:ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());