Quel est le meilleur endroit pour définir la culture / culture de l'interface utilisateur dans une application ASP.net MVC
Actuellement, j'ai une classe CultureController qui ressemble à ceci:
public class CultureController : Controller
{
public ActionResult SetSpanishCulture()
{
HttpContext.Session["culture"] = "es-ES";
return RedirectToAction("Index", "Home");
}
public ActionResult SetFrenchCulture()
{
HttpContext.Session["culture"] = "fr-FR";
return RedirectToAction("Index", "Home");
}
}
et un lien hypertexte pour chaque langue sur la page d'accueil avec un lien tel que celui-ci:
<li><%= Html.ActionLink("French", "SetFrenchCulture", "Culture")%></li>
<li><%= Html.ActionLink("Spanish", "SetSpanishCulture", "Culture")%></li>
qui fonctionne bien mais je pense qu'il y a une manière plus appropriée de faire ceci.
Je lis la culture en utilisant le ActionFilter suivant http://www.iansuttle.com/blog/post/ASPNET-MVC-Action-Filter-for-Localized-Sites.aspx . Je suis un peu un MVC noob, donc je ne suis pas sûr que je mets cela au bon endroit. Je ne veux pas le faire au niveau de web.config, cela doit être basé sur le choix d'un utilisateur. Je ne veux pas non plus vérifier leurs en-têtes http pour obtenir la culture à partir des paramètres de leur navigateur.
Éditer:
Juste pour être clair - je n'essaye pas de décider d'utiliser la session ou non. Je suis content de ça. Ce que j'essaie de déterminer, c'est s'il est préférable de le faire dans un contrôleur de culture qui a une méthode d'action pour chaque culture à définir, ou existe-t-il un meilleur endroit dans le pipeline MVC pour le faire?
la source
Réponses:
J'utilise cette méthode de localisation et ajouté un paramètre d'itinéraire qui définit la culture et la langue chaque fois qu'un utilisateur visite example.com/xx-xx/
Exemple:
routes.MapRoute("DefaultLocalized", "{language}-{culture}/{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "", language = "nl", culture = "NL" });
J'ai un filtre qui fait le réglage de la culture / langue réelle:
using System.Globalization; using System.Threading; using System.Web.Mvc; public class InternationalizationAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { string language = (string)filterContext.RouteData.Values["language"] ?? "nl"; string culture = (string)filterContext.RouteData.Values["culture"] ?? "NL"; Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture)); Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture)); } }
Pour activer l'attribut Internationalisation, ajoutez-le simplement à votre classe:
[Internationalization] public class HomeController : Controller { ...
Désormais, chaque fois qu'un visiteur accède à http://example.com/de-DE/Home/Index, le site allemand s'affiche.
J'espère que cette réponse vous oriente dans la bonne direction.
J'ai également fait un petit exemple de projet MVC 5 que vous pouvez trouver ici
Accédez simplement à http: // {yourhost}: {port} / en-us / home / index pour voir la date actuelle en anglais (États-Unis), ou modifiez-la en http: // {yourhost}: {port} / de -de / home / index pour l'allemand, etc.
la source
Je sais que c'est une vieille question, mais si vous souhaitez vraiment que cela fonctionne avec votre ModelBinder (en ce qui concerne
DefaultModelBinder.ResourceClassKey = "MyResource";
ainsi que les ressources indiquées dans les annotations de données des classes viewmodel), le contrôleur ou même unActionFilter
est trop tard pour définir la culture .La culture peut être définie
Application_AcquireRequestState
, par exemple:protected void Application_AcquireRequestState(object sender, EventArgs e) { // For example a cookie, but better extract it from the url string culture = HttpContext.Current.Request.Cookies["culture"].Value; Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture); Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture); }
ÉDITER
En fait, il existe un meilleur moyen d'utiliser un gestionnaire d'itinéraire personnalisé qui définit la culture en fonction de l'url, parfaitement décrite par Alex Adamyan sur son blog .
Tout ce qu'il y a à faire est de remplacer la
GetHttpHandler
méthode et d'y définir la culture.public class MultiCultureMvcRouteHandler : MvcRouteHandler { protected override IHttpHandler GetHttpHandler(RequestContext requestContext) { // get culture from route data 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); } }
la source
Je le ferais dans l'événement Initialize du contrôleur comme ceci ...
protected override void Initialize(System.Web.Routing.RequestContext requestContext) { base.Initialize(requestContext); const string culture = "en-US"; CultureInfo ci = CultureInfo.GetCultureInfo(culture); Thread.CurrentThread.CurrentCulture = ci; Thread.CurrentThread.CurrentUICulture = ci; }
la source
Étant donné qu'il s'agit d'un paramètre stocké par utilisateur, la session est un endroit approprié pour stocker les informations.
Je changerais votre contrôleur pour prendre la chaîne de culture comme paramètre, plutôt que d'avoir une méthode d'action différente pour chaque culture potentielle. L'ajout d'un lien vers la page est facile et vous ne devriez pas avoir besoin d'écrire le même code à plusieurs reprises chaque fois qu'une nouvelle culture est requise.
public class CultureController : Controller { public ActionResult SetCulture(string culture) { HttpContext.Session["culture"] = culture return RedirectToAction("Index", "Home"); } } <li><%= Html.ActionLink("French", "SetCulture", new {controller = "Culture", culture = "fr-FR"})%></li> <li><%= Html.ActionLink("Spanish", "SetCulture", new {controller = "Culture", culture = "es-ES"})%></li>
la source
Quel est le meilleur endroit est votre question. Le meilleur endroit est à l'intérieur du contrôleur. méthode . MSDN écrit qu'il est appelé après le constructeur et avant la méthode d'action. Contrairement à la substitution de OnActionExecuting, placer votre code dans la méthode Initialize vous permet de bénéficier de toutes les annotations et attributs de données personnalisés sur vos classes et sur vos propriétés à localiser.
Par exemple, ma logique de localisation provient d'une classe qui est injectée dans mon contrôleur personnalisé. J'ai accès à cet objet puisque Initialize est appelé après le constructeur. Je peux faire l'attribution de culture du fil et ne pas afficher tous les messages d'erreur correctement.
public BaseController(IRunningContext runningContext){/*...*/} protected override void Initialize(RequestContext requestContext) { base.Initialize(requestContext); var culture = runningContext.GetCulture(); Thread.CurrentThread.CurrentUICulture = culture; Thread.CurrentThread.CurrentCulture = culture; }
Même si votre logique n'est pas à l'intérieur d'une classe comme l'exemple que j'ai fourni, vous avez accès au RequestContext qui vous permet d'avoir l'URL et HttpContext et le RouteData que vous pouvez faire pratiquement n'importe quelle analyse possible.
la source
Si vous utilisez des sous-domaines, par exemple comme "pt.mydomain.com" pour définir le portugais par exemple, utiliser Application_AcquireRequestState ne fonctionnera pas, car il n'est pas appelé lors des requêtes de cache suivantes.
Pour résoudre cela, je suggère une implémentation comme celle-ci:
Ajoutez le paramètre VaryByCustom à OutPutCache comme ceci:
[OutputCache(Duration = 10000, VaryByCustom = "lang")] public ActionResult Contact() { return View("Contact"); }
Dans global.asax.cs, récupérez la culture de l'hôte à l'aide d'un appel de fonction:
protected void Application_AcquireRequestState(object sender, EventArgs e) { System.Threading.Thread.CurrentThread.CurrentUICulture = GetCultureFromHost(); }
Ajoutez la fonction GetCultureFromHost à global.asax.cs:
private CultureInfo GetCultureFromHost() { CultureInfo ci = new CultureInfo("en-US"); // en-US string host = Request.Url.Host.ToLower(); if (host.Equals("mydomain.com")) { ci = new CultureInfo("en-US"); } else if (host.StartsWith("pt.")) { ci = new CultureInfo("pt"); } else if (host.StartsWith("de.")) { ci = new CultureInfo("de"); } else if (host.StartsWith("da.")) { ci = new CultureInfo("da"); } return ci; }
Et enfin, remplacez GetVaryByCustomString (...) pour utiliser également cette fonction:
public override string GetVaryByCustomString(HttpContext context, string value) { if (value.ToLower() == "lang") { CultureInfo ci = GetCultureFromHost(); return ci.Name; } return base.GetVaryByCustomString(context, value); }
La fonction Application_AcquireRequestState est appelée sur les appels non mis en cache, ce qui permet au contenu d'être généré et mis en cache. GetVaryByCustomString est appelé sur les appels mis en cache pour vérifier si le contenu est disponible dans le cache, et dans ce cas, nous examinons la valeur du domaine hôte entrant, encore une fois, au lieu de nous fier uniquement aux informations de culture actuelles, qui auraient pu changer pour la nouvelle demande (car nous utilisons des sous-domaines).
la source
1: Créez un attribut personnalisé et remplacez la méthode comme ceci:
public class CultureAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { // Retreive culture from GET string currentCulture = filterContext.HttpContext.Request.QueryString["culture"]; // Also, you can retreive culture from Cookie like this : //string currentCulture = filterContext.HttpContext.Request.Cookies["cookie"].Value; // Set culture Thread.CurrentThread.CurrentCulture = new CultureInfo(currentCulture); Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(currentCulture); } }
2: Dans App_Start, recherchez FilterConfig.cs, ajoutez cet attribut. (cela fonctionne pour toute l'application)
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // Add custom attribute here filters.Add(new CultureAttribute()); } }
C'est ça !
Si vous souhaitez définir la culture pour chaque contrôleur / action au lieu de l'application entière, vous pouvez utiliser cet attribut comme ceci:
[Culture] public class StudentsController : Controller { }
Ou:
[Culture] public ActionResult Index() { return View(); }
la source
protected void Application_AcquireRequestState(object sender, EventArgs e) { if(Context.Session!= null) Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = (Context.Session["culture"] ?? (Context.Session["culture"] = new CultureInfo("pt-BR"))) as CultureInfo; }
la source