एक ASP.Net MVC ऐप में संस्कृति सेट करें


85

ASP.net MVC ऐप में संस्कृति / UI संस्कृति को सेट करने के लिए सबसे अच्छी जगह कौन सी है

वर्तमान में मेरे पास एक संस्कृतिसंसाधक वर्ग है जो इस तरह दिखता है:

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

और इस तरह के लिंक के साथ होमपेज पर प्रत्येक भाषा के लिए एक हाइपरलिंक:

<li><%= Html.ActionLink("French", "SetFrenchCulture", "Culture")%></li>
<li><%= Html.ActionLink("Spanish", "SetSpanishCulture", "Culture")%></li>

जो ठीक काम करता है लेकिन मैं सोच रहा हूं कि ऐसा करने का एक और उपयुक्त तरीका है।

मैं निम्नलिखित ActionFilter http://www.iansuttle.com/blog/post/ASPNET-MVC-Action-Filter-for-Localized-Sites.aspx का उपयोग करके संस्कृति पढ़ रहा हूं । मैं एमवीसी दोपहर का एक सा हूं, इसलिए मुझे विश्वास नहीं है कि मैं इसे सही जगह स्थापित कर रहा हूं। मैं इसे web.config स्तर पर नहीं करना चाहता, इसे उपयोगकर्ता की पसंद पर आधारित होना चाहिए। मैं अपने ब्राउज़र सेटिंग्स से संस्कृति प्राप्त करने के लिए उनके http-headers की जांच करना भी नहीं चाहता।

संपादित करें:

बस स्पष्ट होने के लिए - मैं यह तय करने की कोशिश नहीं कर रहा हूं कि सत्र का उपयोग करना है या नहीं। मैं उस बिट से खुश हूं। क्या मैं बाहर काम करने की कोशिश कर रहा हूं, अगर संस्कृति नियंत्रक में ऐसा करना सबसे अच्छा है, जिसमें प्रत्येक संस्कृति को सेट करने के लिए एक क्रिया पद्धति है, या ऐसा करने के लिए एमवीसी पाइपलाइन में बेहतर जगह है?


उपयोगकर्ता संस्कृति का चयन करने के लिए सत्र राज्य का उपयोग करना एक अच्छा विकल्प नहीं है। सबसे अच्छा तरीका है कि URL के हिस्से के रूप में संस्कृति को शामिल किया जाए , जो वर्तमान पृष्ठ को किसी अन्य संस्कृति के साथ "स्वैप" करना आसान बनाता है।
NightOwl888

जवाबों:


114

मैं इस स्थानीयकरण विधि का उपयोग कर रहा हूँ और जब भी कोई उपयोगकर्ता example.com/xx-xx/ पर जाता है तो संस्कृति और भाषा सेट करने वाला मार्ग पैरामीटर जोड़ा जाता है

उदाहरण:

routes.MapRoute("DefaultLocalized",
            "{language}-{culture}/{controller}/{action}/{id}",
            new
            {
                controller = "Home",
                action = "Index",
                id = "",
                language = "nl",
                culture = "NL"
            });

मेरे पास एक फ़िल्टर है जो वास्तविक संस्कृति / भाषा सेटिंग करता है:

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

    }
}

अंतर्राष्ट्रीयकरण विशेषता को सक्रिय करने के लिए, बस इसे अपनी कक्षा में जोड़ें:

[Internationalization]
public class HomeController : Controller {
...

अब जब भी कोई आगंतुक http://example.com/de-DE/Home/Index पर जाता है तो जर्मन साइट प्रदर्शित होती है।

मुझे उम्मीद है कि यह उत्तर आपको सही दिशा में इंगित करता है।

मैंने एक छोटा MVC 5 उदाहरण परियोजना भी बनाई जिसे आप यहां पा सकते हैं

बस http: // {yourhost}: {port} / en-us / home / index पर जाएं अंग्रेजी में वर्तमान दिनांक (यूएस) देखें, या इसे http: // {yourhost}: {port} / de में बदलें जर्मन वगैरह के लिए -d / home / index।


15
मुझे यूआरएल में लैंग डालना भी पसंद है, क्योंकि यह अलग-अलग भाषाओं में सर्च इंजन द्वारा क्रॉल करने योग्य हो गया और उपयोगकर्ता को एक विशिष्ट लैंग के साथ एक यूआरएल को बचाने या भेजने की अनुमति देता है।
एडुआर्डो मोल्टनी

50
Url में भाषा जोड़ने से REST का उल्लंघन नहीं होता है। यह तथ्य यह है कि यह वेब संसाधन को एक छिपे हुए सत्र की स्थिति पर निर्भर न करके इसका पालन करता है।
Jace Rhea

4
वेब संसाधन एक छिपी हुई स्थिति पर निर्भर नहीं है, जिस तरह से इसका प्रतिपादन किया गया है। यदि आप संसाधन को एक वेब सेवा के रूप में एक्सेस करना चाहते हैं, तो आपको इसे करने के लिए एक भाषा चुनने की आवश्यकता होगी।
डेव वान डेन आईन्दे

4
इस प्रकार के समाधान के साथ मेरे कुछ मुद्दे थे। सत्यापन त्रुटि संदेश का अनुवाद नहीं किया जा रहा था। समस्या को हल करने के लिए मैंने Global.asax.cs फ़ाइल में Application_AcquireRequestState फ़ंक्शन में संस्कृति सेट की।
ADH

4
इसे फ़िल्टर में रखना एक अच्छा विचार नहीं है। मॉडल बाइंडिंग करंटकल्चर का उपयोग करता है, लेकिन ActionFilter मॉडल बाइंडिंग के बाद होता है। Global.asax, Application_PreRequestHandlerExecute में ऐसा करना बेहतर है।
स्टेफान

38

मुझे पता है कि यह एक पुराना सवाल है, लेकिन अगर आप वास्तव में अपने मॉडलबाइंडर के साथ काम करना चाहते हैं ( DefaultModelBinder.ResourceClassKey = "MyResource";साथ ही साथ दृश्यमॉडल कक्षाओं के डेटा एनोटेशन में संकेतित संसाधन), नियंत्रक या यहां तक ActionFilterकि बहुत देर हो चुकी है संस्कृति सेट करें

संस्कृति को Application_AcquireRequestStateउदाहरण के लिए सेट किया जा सकता है :

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

संपादित करें

वास्तव में एक कस्टम मार्गहैंडलर का उपयोग करने का एक बेहतर तरीका है जो संस्कृति को url के अनुसार सेट करता है, जिसे एलेक्स एडमैन ने अपने ब्लॉग पर पूरी तरह से वर्णित किया है ।

वहाँ सब करना है कि GetHttpHandlerविधि को ओवरराइड करना है और वहां की संस्कृति को सेट करना है।

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

Unfortunatelly RouteData आदि "Application_AcquireRequestState" विधि में उपलब्ध नहीं हैं, लेकिन वे कंट्रोलर .CreateActionInvoker () में हैं। इसलिए मैं "संरक्षित IActionInvoker CreateActionInvoker ()" का सुझाव देता हूं और संस्कृतिInfo को वहीं सेट करता हूं।
स्कोरुनका फ्रांटिसेक

मैंने वह ब्लॉग पढ़ा। अगर मैं कुकी के साथ आगे बढ़ूं तो क्या कोई समस्या है? चूंकि मुझे इसे बदलने की अनुमति नहीं है। कृपया मुझे सूचित करें। इस दृष्टिकोण के साथ कोई समस्या है?
केबिष्णु

@VeeKeyBee यदि आपकी साइट सार्वजनिक है, तो सुरक्षित साइटों के लिए कुकीज़ का उपयोग करते समय सभी भाषाओं को ठीक से अनुक्रमित नहीं किया जाएगा, आप शायद ठीक हैं।
मैरपेट

सार्वजनिक नहीं है। क्या आप कृपया "अनुक्रमित" शब्द के बारे में संकेत दे सकते हैं?
केविष्णु

1
आपको अपना प्रश्न पूछना चाहिए और एसईओ पर पढ़ना चाहिए, इसका मूल प्रश्न से कोई लेना-देना नहीं है। webmasters.stackexchange.com/questions/3786/…
marapet

25

मैं इसे इस तरह नियंत्रक की प्रारंभिक घटना में करूँगा ...

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

1
कल्चर स्ट्रिंग एक कास्ट नहीं हो सकता है, क्योंकि उपयोगकर्ता को उस संस्कृति को निर्दिष्ट करने में सक्षम होना चाहिए जो वे साइट पर उपयोग करना चाहते हैं।
NerdFury

2
मैं समझता हूं कि, लेकिन सवाल यह था कि संस्कृति को स्थापित करने के लिए सबसे अच्छा नहीं था कि इसे कैसे स्थापित किया जाए।
जैस रिया

एक कास्ट के बजाय, आप कुछ का उपयोग कर सकते हैं जैसे: var newCulture = new CultureInfo (RouteData.Values ​​["lang"]। ToString ());
नोर्ड्स

ऑथराइज़कोर को ऑनएशन एक्ज़ीक्यूटिंग से पहले कहा जाता है, इसलिए आपके ऑथराइज़कोर ओवरराइड विधि में आपके पास कोई संस्कृति विवरण नहीं होगा। कंट्रोलर की इनिशियलाइज़ मेथड का उपयोग करना बेहतर काम कर सकता है, खासकर यदि आप एक कस्टम ऑथराइज एट्रिब्यूट को लागू कर रहे हैं, क्योंकि इनिशियलाइज़ मेथड को ऑथराइजकोर से पहले कहा जाता है (आपके पास ऑथराइज डिटेल होंगे।
नाथन आर।

7

जैसा कि यह एक सेटिंग है जिसे प्रति उपयोगकर्ता संग्रहीत किया जाता है, सत्र सूचना को संग्रहीत करने के लिए एक उपयुक्त स्थान है।

मैं संस्कृति नियंत्रक को एक पैरामीटर के रूप में लेने के लिए आपके नियंत्रक को बदल दूंगा, बजाय प्रत्येक संभावित संस्कृति के लिए एक अलग एक्शन विधि होने के कारण। पृष्ठ पर एक लिंक जोड़ना आसान है, और किसी भी नई संस्कृति की आवश्यकता होने पर आपको बार-बार एक ही कोड लिखने की आवश्यकता नहीं है।

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>

उत्तर के लिए धन्यवाद, मैं सत्र का उपयोग करने या नहीं करने का निर्णय लेने की कोशिश नहीं कर रहा हूं। मैं उस बिट से खुश हूं। क्या मैं बाहर काम करने की कोशिश कर रहा हूं, अगर संस्कृति नियंत्रक में ऐसा करना सबसे अच्छा है, जिसमें प्रत्येक संस्कृति को सेट करने के लिए एक क्रिया पद्धति है या ऐसा करने के लिए एमवीसी पाइपलाइन में बेहतर जगह है
क्रिसका

मैंने एक संपादित उत्तर प्रदान किया है जो प्रश्न को बेहतर ढंग से प्रस्तुत करता है।
NerdFury

हां, यह निश्चित रूप से क्लीनर है, लेकिन मैं वास्तव में जानना चाहता हूं कि क्या यह एक नियंत्रक में किया जाना चाहिए। या फिर संस्कृति को स्थापित करने के लिए एमवीसी पाइपलाइन में बेहतर जगह है। या अगर यह एक ActionFilters, हैंडलर, मॉड्यूल आदि में बेहतर है
क्रिसक

एक हैंडलर और मॉड्यूल का कोई मतलब नहीं है क्योंकि उपयोगकर्ता को चयन करने का मौका नहीं मिला है। उपयोगकर्ता को चयन करने के लिए आपके पास एक तरीका है, और फिर उपयोगकर्ताओं के चयन की प्रक्रिया करें, जो एक नियंत्रक में किया जाएगा।
NerdFury

सहमत, हैंडलर और मॉड्यूल उपयोगकर्ता बातचीत की अनुमति देने के लिए जल्दी हैं। हालांकि, मैं एमवीसी के लिए काफी नया हूं, इसलिए अनिश्चित हूं कि इसे स्थापित करने के लिए पाइपलाइन में सबसे अच्छी जगह है। अगर मैं नहीं सुनता तो कुछ समय बाद मैं आपका जवाब स्वीकार करता हूँ। पीएस जो सिंटैक्स आपने एक पैरामीटर को पास करने के लिए उपयोग किया है वह एक्शन विधि से काम नहीं करता है। यह एक नियंत्रक परिभाषित नहीं है, इसलिए बस डिफ़ॉल्ट एक का उपयोग करता है (जो इस मामले में सही नहीं है)। और वहाँ एक और अधिभार उपयुक्त प्रतीत नहीं होता है
क्रिसका

6

सबसे अच्छी जगह कौन सा है आपका सवाल। सबसे अच्छी जगह कंट्रोलर के अंदर है। इंसुलेटिड मेथड। एमएसडीएन लिखता है कि यह कंस्ट्रक्टर के बाद और एक्शन विधि से पहले कहा जाता है। OnActionExecuting को ओवरराइड करने के विपरीत, अपने कोड को इनिशियलाइज़ विधि में रखने से आपको सभी कस्टम डेटा एनोटेशन और विशेषता का लाभ आपकी कक्षाओं में और आपके गुणों पर स्थानीयकृत होने की अनुमति मिलती है।

उदाहरण के लिए, मेरा स्थानीयकरण तर्क एक वर्ग से आता है जिसे मेरे कस्टम नियंत्रक को इंजेक्ट किया जाता है। मेरे पास इस ऑब्जेक्ट तक पहुंच है, क्योंकि निर्माण के बाद इनिशियलाइज़ को कॉल किया जाता है। मैं थ्रेड कल्चर असाइनमेंट कर सकता हूं और हर त्रुटि संदेश को सही ढंग से प्रदर्शित नहीं कर रहा है।

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

यहां तक ​​कि अगर आपका तर्क मेरे द्वारा दिए गए उदाहरण की तरह एक वर्ग के अंदर नहीं है, तो आपके पास RequestContext तक पहुंच है, जो आपको URL और HttpContext और रूटडेटा की अनुमति देता है जो आप मूल रूप से किसी भी पार्सिंग को संभव कर सकते हैं।


यह मेरे HTML5 Telerik ReportLocalization के लिए काम करता है! धन्यवाद @Patrick Desjardins
कोडरोलर

4

यदि उप उदाहरणों के लिए, उदाहरण के लिए, "pt.mydomain.com" जैसे उदाहरण के लिए पुर्तगाली को सेट करने के लिए, Application_AcquireRequestState का उपयोग करने से काम नहीं चलेगा, क्योंकि यह बाद के कैश अनुरोधों पर नहीं कहा जाता है।

इसे हल करने के लिए, मैं इस तरह से एक कार्यान्वयन का सुझाव देता हूं:

  1. इस तरह OutPutCache के लिए VaryByCustom पैरामीटर जोड़ें:

    [OutputCache(Duration = 10000, VaryByCustom = "lang")]
    public ActionResult Contact()
    {
        return View("Contact");
    }
    
  2. Global.asax.cs में, फ़ंक्शन कॉल का उपयोग करके होस्ट से संस्कृति प्राप्त करें:

    protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        System.Threading.Thread.CurrentThread.CurrentUICulture = GetCultureFromHost();
    }
    
  3. Global.asax.cs पर GetCultureFromHost फ़ंक्शन जोड़ें:

    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;
    }
    
  4. और अंततः इस फ़ंक्शन का उपयोग करने के लिए GetVaryByCustomString (...) को ओवरराइड करें:

    public override string GetVaryByCustomString(HttpContext context, string value)
    {
        if (value.ToLower() == "lang")
        {
            CultureInfo ci = GetCultureFromHost();
            return ci.Name;
        }
        return base.GetVaryByCustomString(context, value);
    }
    

फ़ंक्शन Application_AcquireRequestState को गैर-कैश्ड कॉल पर कहा जाता है, जो सामग्री को उत्पन्न और कैश करने की अनुमति देता है। GetVaryByCustomString को कैश में सामग्री उपलब्ध होने की जाँच करने के लिए कैश्ड कॉल पर कॉल किया जाता है, और इस मामले में हम आने वाले होस्ट डोमेन मूल्य की जांच करते हैं, फिर से, केवल वर्तमान संस्कृति जानकारी पर भरोसा करने के बजाय, जो नए अनुरोध के लिए बदल सकता है (क्योंकि हम उप डोमेन का उपयोग कर रहे हैं)।


4

1: एक कस्टम विशेषता बनाएँ और इस तरह से ओवरराइड विधि:

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: App_Start में, FilterConfig.cs ढूंढें, इस विशेषता को जोड़ें। (यह व्होल एप्लीकेशन के लिए काम करता है)

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
    // Add custom attribute here
    filters.Add(new CultureAttribute());
    }
}    

बस !

यदि आप पूरे एप्लिकेशन के अनुसार प्रत्येक नियंत्रक / कार्रवाई के लिए संस्कृति को परिभाषित करना चाहते हैं, तो आप इस विशेषता का उपयोग कर सकते हैं:

[Culture]
public class StudentsController : Controller
{
}

या:

[Culture]
public ActionResult Index()
{
    return View();
}

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

3
कृपया समझाएं कि यह सबसे अच्छा तरीका क्यों माना जाता है।
मैक्स लेसके
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.