eray aydoğdu

jQuery and ASP.NET MVC fanatic.

Asp.Net MVC Çoklu Dil Desteği

İki dil site yapımı ya da çoklu dil desteği olan bir site yapımı için session veya cache yöntemi de kullanılabilir fakat profesyonel bir uygulamada bu en iyi çözüm yolu değil. Bunun en güçlü ve pratik yolu dil değişkenini asp.net mvc nin url routing mekanizmasını kullanarak saklamaktır.

Amaç url nin şu şekilde gözükmesini sağlamak : /{culture}/{Controller}/{Action} yani /tr/Home/About

Öncelikle MvcRouteHandler class ını extend etmemiz gerekiyor. Culture parametresi için MultiCultureMvcRouteHandler ve culture parametresi kullanmayacağımız SingleCultureMvcRouteHandler class larımızı oluşturalım.

Custom Route Handlers oluşturalım

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);
    }
}

Base implementation ını çağırmadan önce GetHttpHandler override ederken RouteData collection ından culture parametresini alıyoruz, CultureInfo objesi yaratıp current culture ve current thread özelliklerini ayarladık.

public class SingleCultureMvcRouteHandler : MvcRouteHandler {}

Bu class ı culture yani dil ayarı yapmamızı gerektirmeyen sayfaları için kullanacağız.

Registering Routes (Route larımızı tanımlayalım)

Global.asax dosyasındaki RegisterRoute() methodumuzu açalım. Default route tanımlamasının altına aşağıda ki foreach blogunu ekleyelim.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
         "Default", // Route name
         "{controller}/{action}/{id}", // URL with parameters
         new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );

    foreach (Route r in routes)
    {
        if (!(r.RouteHandler is SingleCultureMvcRouteHandler))
        {
            r.RouteHandler = new MultiCultureMvcRouteHandler();
            r.Url = "{culture}/" + r.Url;

           if (r.Defaults == null)
           {
               r.Defaults = new RouteValueDictionary();
           }
           r.Defaults.Add("culture", Culture.tr.ToString());

           if (r.Constraints == null)
           {
               r.Constraints = new RouteValueDictionary();
           }
           r.Constraints.Add("culture", new CultureConstraint(Culture.en.ToString(),
Culture.tr.ToString()));
        }
   }

}

Culture enum ve CultureConstraint class larımızıda oluşturalım.

public class CultureConstraint : IRouteConstraint
{
    private string[] _values;
    public CultureConstraint(params string[] values)
    {
        this._values = values;
    }

    public bool Match(HttpContextBase httpContext,Route route,string parameterName,
                        RouteValueDictionary values, RouteDirection routeDirection)
    {

        string value = values[parameterName].ToString();
        return _values.Contains(value);

    }

}
    public enum Culture
    {
        tr = 1,
        en = 2
    }

Dil değiştirme İşlemi

Dil değişikliği yapmak için aşağıdaki gibi basit bir Action ımız var. AccountController mıza koyabiliriz. İstersiniz HomeController a da koyabilirsiniz.

public ActionResult ChangeCulture(Culture lang, string returnUrl)
{
     if (returnUrl.Length >= 3)
     {
         returnUrl = returnUrl.Substring(3);
     }
     return Redirect("/" + lang.ToString() + returnUrl);
}

İkinci dil e geçmek için CultureSwitchControl.ascx adında bir partial view oluşturdum. Bununda kodu aşağıda ki gibi:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<%= Html.ActionLink("eng", "ChangeCulture", "Account",
    new { lang = (int)MvcLocalization.Helpers.Culture.en, returnUrl =
    this.Request.RawUrl }, new { @class = "culture-link" })%>

<%= Html.ActionLink("tr", "ChangeCulture", "Account",
    new { lang = (int)MvcLocalization.Helpers.Culture.tr, returnUrl =
    this.Request.RawUrl }, new { @class = "culture-link" })%>

Tek Dil

Eğer tek dile ihtiyaç duyacağımız sayfalar olursa onuda RouteHandler ını SingleCultureMvcRouteHandler olarak Global.asax ta tanımlamamız gerekecek.

routes.MapRoute(
          "AboutRoute",
          "About",
          new { controller = "Home", action = "About"}
   ).RouteHandler = new SingleCultureMvcRouteHandler();

Localization işlemi bu kadar.

Çok dilli web uygulaması yaparken karşınıza iki sorun daha çıkacak. Telaşlanmayın işin zor kısmını zaten hallettiniz. Geriye sayfa içinde ki sabit yazılar (örn. “Son Yazılar”,”Son Yorumlar”) ve dile göre değişecek resimler bannerler. Bu sorunu Resources Files kullanarak çok basit atlatabilirsiniz. Ancak resimler için tavsiyem 2 ayrı klasör oluşturup (tr ve en) adında dillere ait dosyalarınızı bu klasörlere atmanız ve sayfa içinde kullanacağınız zaman url deki parametreyle aynı olan dosya adınıza yol vermenizdir örneğin;

../../Content/tr/logo.jpg ve ../../Content/en/logo.jpg şeklinde url deki parametreyi sayfa içine taşırsanız(ister class yapın ister ViewData[“dil”] ile taşıyın farketmez) bu sorunu halledebilirsiniz.

Sabit yazılar içinse yine aynı yöntemi kullabilirsiniz fakat çok uzun sürebilir o yüzden tavsiyem Resources Files kullanmanızdır. bu konuda ufak bir araştırma ile çok sayıda dökümana ulaşabilirsiniz, üstelik kullanımı çok kolay