2012-06-01 3 views
1

J'ai cherché et essayé de nombreuses approches de localisation mais tout n'est pas exactement ce que je veux. Au fond, je veux avoir mon URL comme celui-ciASP.NET MVC 3 Localisation en utilisant route et vue

  • www.myweb.com < == langue par défaut (ce qui est l'anglais)
  • de www.myweb.com/promotion
  • www.myweb.com/ e/promotion < == langue locale (Thai)
  • www.myweb.com/cn/promotion < == langue locale (chinois)

Je veux que ces URL pour la carte avec une structure différente de Voir ci-dessous

/Views 
    /_Localization 
     /cn 
      /Home 
       /About.cshtml 
       /Index.cshtml 
      /Shared 
       /_Layout.cshtml 
       /Error.cshtml 
     /th 
      /Home 
       /About.cshtml 
      /Shared 
    /Home 
     /About.cshtml 
     /Index.cshtml 
    /Shared 
     /_Layout.cshtml 
     /_LogOnPartial.cshtml 
     /Error.cshtml 
    _ViewStart.cshtml 
    Web.config 

Comme vous pouvez le voir, Thai ne pas posséder Index.cshtml, _Layout.cshtml et Error.cshtml. Donc, je voudrais que cela se replie pour utiliser la valeur par défaut à la place. Mais les Chinois vont l'utiliser.

J'ai essayé de MapRoute comme ce

routes.MapRoute(
    "DefaultLocal", 
    "{lang}/{controller}/{action}/{id}", 
    new { lang = "th", controller = "Home", action = "Index", id = UrlParameter.Optional } 
); 

routes.MapRoute(
    "Default", 
    "{controller}/{action}/{id}", 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
); 

mais je ne sais pas comment pointer vers une structure différente de vue. Et dans cet exemple, Brian Reiter, il utilise Cookie pas url.

Alors, comment puis-je y parvenir. Notez que j'utilise RazorViewEngine. Merci pour toute aide et réflexion.

+0

vous avez vu ce couple de liens: http://afana.me/post/aspnet-mvc-internationalization.aspx http://www.hanselman.com/blog/GlobalizationInternationalizationAndLocalizationInASPNETMVC3JavaScriptAndJQueryPart1.aspx? – ILya

+0

Oui, j'ai essayé les deux avec succès mais les deux gardent la trace de la langue sélectionnée dans le paramètre Session. Pour moi, je voudrais avoir url route à vue différente à la place. quelque chose comme ça, [link] (http://www.codeproject.com/Articles/207602/Creating-a-Bilingual-ASP-NET-MVC3-Application-Part), perhap. mais pointez sur des vues différentes et non sur des ressources. – Siripongz

Répondre

3

En raison de la grande quantité de code nécessaire, je vais seulement illustrer une idée de la façon dont cela pourrait être fait.

Vous pouvez sous-classe de RazorViewEngine comme ceci:

public class I18NRazorViewEngine : RazorViewEngine 
{ 
    public I18NRazorViewEngine() : this(null) 
    { } 

    protected string[] I18NAreaViewLocationFormats; 
    protected string[] I18NAreaMasterLocationFormats; 
    protected string[] I18NAreaPartialViewLocationFormats; 
    protected string[] I18NViewLocationFormats; 
    protected string[] I18NMasterLocationFormats; 
    protected string[] I18NPartialViewLocationFormats; 

    public I18NRazorViewEngine(IViewPageActivator viewPageActivator) 
     : base(viewPageActivator) 
    { 
     this.I18NAreaViewLocationFormats = new string[] 
     { 
      "~/Areas/{3}/{2}/Views/{1}/{0}.cshtml", 
      "~/Areas/{3}/{2}/Views/{1}/{0}.vbhtml", 
      "~/Areas/{3}/{2}/Views/Shared/{0}.cshtml", 
      "~/Areas/{3}/{2}/Views/Shared/{0}.vbhtml" 
     }; 

     this.I18NAreaMasterLocationFormats = new string[] 
     { 
      "~/Areas/{3}/{2}/Views/{1}/{0}.cshtml", 
      "~/Areas/{3}/{2}/Views/{1}/{0}.vbhtml", 
      "~/Areas/{3}/{2}/Views/Shared/{0}.cshtml", 
      "~/Areas/{3}/{2}/Views/Shared/{0}.vbhtml" 
     }; 

     this.I18NAreaPartialViewLocationFormats = new string[] 
     { 
      "~/Areas/{3}/{2}/Views/{1}/{0}.cshtml", 
      "~/Areas/{3}/{2}/Views/{1}/{0}.vbhtml", 
      "~/Areas/{3}/{2}/Views/Shared/{0}.cshtml", 
      "~/Areas/{3}/{2}/Views/Shared/{0}.vbhtml" 
     }; 

     this.I18NViewLocationFormats = new string[] 
     { 
      "~/Views/{2}/{1}/{0}.cshtml", 
      "~/Views/{2}/{1}/{0}.vbhtml", 
      "~/Views/{2}/Shared/{0}.cshtml", 
      "~/Views/{2}/Shared/{0}.vbhtml" 
     }; 

     this.I18NMasterLocationFormats = new string[] 
     { 
      "~/Views/{2}/{1}/{0}.cshtml", 
      "~/Views/{2}/{1}/{0}.vbhtml", 
      "~/Views/{2}/Shared/{0}.cshtml", 
      "~/Views/{2}/Shared/{0}.vbhtml" 
     }; 

     this.I18NPartialViewLocationFormats = new string[] 
     { 
      "~/Views/{2}/{1}/{0}.cshtml", 
      "~/Views/{2}/{1}/{0}.vbhtml", 
      "~/Views/{2}/Shared/{0}.cshtml", 
      "~/Views/{2}/Shared/{0}.vbhtml" 
     }; 
    } 

    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 
    { 
     var langValue = controllerContext.Controller.ValueProvider.GetValue("lang"); 
     if (langValue == null || String.IsNullOrEmpty(langValue.AttemptedValue)) 
      return base.FindView(controllerContext, viewName, masterName, useCache); 

     //Code here 
    } 

    public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) 
    { 
     var langValue = controllerContext.Controller.ValueProvider.GetValue("lang"); 
     if (langValue == null || String.IsNullOrEmpty(langValue.AttemptedValue)) 
      return base.FindPartialView(controllerContext, partialViewName, useCache); 

     //Code here 
    }   
} 

La prochaine ce que vous devez faire est de regarder à l'intérieur VirtualPathProviderViewEngine sur FindView et FindPartialView inplementations. Le code réfléchi est comme ceci:

public virtual ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) 
{ 
    if (controllerContext == null) 
    { 
     throw new ArgumentNullException("controllerContext"); 
    } 
    if (string.IsNullOrEmpty(partialViewName)) 
    { 
     throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName"); 
    } 
    string requiredString = controllerContext.RouteData.GetRequiredString("controller"); 
    string[] searchedLocations; 
    string path = this.GetPath(controllerContext, this.PartialViewLocationFormats, this.AreaPartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, requiredString, "Partial", useCache, out searchedLocations); 
    if (string.IsNullOrEmpty(path)) 
    { 
     return new ViewEngineResult(searchedLocations); 
    } 
    return new ViewEngineResult(this.CreatePartialView(controllerContext, path), this); 
} 

et

public virtual ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 
{ 
    if (controllerContext == null) 
    { 
     throw new ArgumentNullException("controllerContext"); 
    } 
    if (string.IsNullOrEmpty(viewName)) 
    { 
     throw new ArgumentException(MvcResources.Common_NullOrEmpty, "viewName"); 
    } 
    string requiredString = controllerContext.RouteData.GetRequiredString("controller"); 
    string[] first; 
    string path = this.GetPath(controllerContext, this.ViewLocationFormats, this.AreaViewLocationFormats, "ViewLocationFormats", viewName, requiredString, "View", useCache, out first); 
    string[] second; 
    string path2 = this.GetPath(controllerContext, this.MasterLocationFormats, this.AreaMasterLocationFormats, "MasterLocationFormats", masterName, requiredString, "Master", useCache, out second); 
    if (string.IsNullOrEmpty(path) || (string.IsNullOrEmpty(path2) && !string.IsNullOrEmpty(masterName))) 
    { 
     return new ViewEngineResult(first.Union(second)); 
    } 
    return new ViewEngineResult(this.CreateView(controllerContext, path, path2), this); 
} 

les deux méthodes reposent sur la méthode GetPath privée:

private string GetPath(ControllerContext controllerContext, string[] locations, string[] areaLocations, string locationsPropertyName, string name, string controllerName, string cacheKeyPrefix, bool useCache, out string[] searchedLocations) 
{ 
    searchedLocations = VirtualPathProviderViewEngine._emptyLocations; 
    if (string.IsNullOrEmpty(name)) 
    { 
     return string.Empty; 
    } 
    string areaName = AreaHelpers.GetAreaName(controllerContext.RouteData); 
    List<VirtualPathProviderViewEngine.ViewLocation> viewLocations = VirtualPathProviderViewEngine.GetViewLocations(locations, (!string.IsNullOrEmpty(areaName)) ? areaLocations : null); 
    if (viewLocations.Count == 0) 
    { 
     throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.Common_PropertyCannotBeNullOrEmpty, new object[] 
     { 
      locationsPropertyName 
     })); 
    } 
    bool flag = VirtualPathProviderViewEngine.IsSpecificPath(name); 
    string text = this.CreateCacheKey(cacheKeyPrefix, name, flag ? string.Empty : controllerName, areaName); 
    if (useCache) 
    { 
     return this.ViewLocationCache.GetViewLocation(controllerContext.HttpContext, text); 
    } 
    if (!flag) 
    { 
     return this.GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, text, ref searchedLocations); 
    } 
    return this.GetPathFromSpecificName(controllerContext, name, text, ref searchedLocations); 
} 

Ce que vous devez faire est de réimplémenter. La plupart du code que vous pouvez réutiliser, mais vous devez créer votre propre méthode au lieu de VirtualPathProviderViewEngine.GetViewLocations. Voici son code reflète:

private static List<VirtualPathProviderViewEngine.ViewLocation> GetViewLocations(string[] viewLocationFormats, string[] areaViewLocationFormats) 
{ 
    List<VirtualPathProviderViewEngine.ViewLocation> list = new List<VirtualPathProviderViewEngine.ViewLocation>(); 
    if (areaViewLocationFormats != null) 
    { 
     for (int i = 0; i < areaViewLocationFormats.Length; i++) 
     { 
      string virtualPathFormatString = areaViewLocationFormats[i]; 
      list.Add(new VirtualPathProviderViewEngine.AreaAwareViewLocation(virtualPathFormatString)); 
     } 
    } 
    if (viewLocationFormats != null) 
    { 
     for (int j = 0; j < viewLocationFormats.Length; j++) 
     { 
      string virtualPathFormatString2 = viewLocationFormats[j]; 
      list.Add(new VirtualPathProviderViewEngine.ViewLocation(virtualPathFormatString2)); 
     } 
    } 
    return list; 
} 

Vous pouvez également réutiliser la plupart du code, mais au lieu de VirtualPathProviderViewEngine.ViewLocation et VirtualPathProviderViewEngine.AreaAwareViewLocation vous devez utiliser vos propres classes.Ils pourraient ressembler à ceci:

class ViewLocation 
{ 
    protected string _virtualPathFormatString; 
    public ViewLocation(string virtualPathFormatString) 
    { 
     this._virtualPathFormatString = virtualPathFormatString; 
    } 
    public virtual string Format(string viewName, string controllerName, string areaName, string lang) 
    { 
     return string.Format(CultureInfo.InvariantCulture, this._virtualPathFormatString, new object[] 
     { 
      viewName, 
      controllerName, 
        lang 
     }); 
    } 
} 

et:

class AreaAwareViewLocation : VirtualPathProviderViewEngine.ViewLocation 
{ 
    public AreaAwareViewLocation(string virtualPathFormatString) : base(virtualPathFormatString) 
    { 
    } 
    public override string Format(string viewName, string controllerName, string areaName, string lang) 
    { 
     return string.Format(CultureInfo.InvariantCulture, this._virtualPathFormatString, new object[] 
     { 
      viewName, 
      controllerName, 
      areaName, 
        lang 
     }); 
    } 
} 

et puis quand vous appellerez Format méthodes que vous devriez passer langValue.AttemptedValue (il est de la portée de FindView et FindPartialView dans le premier bloc de code) à paramètre lang. Normalement, il s'appelle VirtualPathProviderViewEngine.GetPathFromGeneralName.

Le conseil principal est d'utiliser ILSpy ou un autre désassembleur pour explorer le code de System.Web.Mvc (ou mieux encore - télécharger ses sources). L'objectif est de réimplémenter FindView et FindPartialView. Le code de repos fourni est pour illustrer comment cela a déjà été fait dans le framework mvc.

Il est également important de chercher à travers les tableaux déclarés dans notre nouveau moteur de vue au lieu de ceux sans préfixe I18N qui sont déjà là et utilisé par les classes par défaut

espère que cela aidera malgré réponse est indirecte. Vous pouvez poser des questions supplémentaires si vous rencontrez des difficultés.

P.S. Ne pas oublier de vous enregistrer moteur de vue dans global.asax.cs après qu'il sera développé.

protected virtual void Application_Start() 
{ 
    ViewEngines.Engines.Clear(); 
    ViewEngines.Engines.Add(new I18NRazorViewEngine()); 
} 
+0

Merci de m'avoir guidé. – Siripongz

+0

Vous êtes les bienvenus) – ILya