web-dev-qa-db-ja.com

ASP.Net MVCアプリでカルチャを設定する

ASP.net MVCアプリでCulture/UI Cultureを設定するのに最適な場所は何ですか

現在、次のようなCultureControllerクラスがあります。

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 。私はMVC初心者なので、これを正しい場所に設定しているとは確信できません。私はweb.configレベルでそれをしたくありません。ユーザーの選択に基づいている必要があります。また、ブラウザの設定からカルチャを取得するために、httpヘッダーを確認したくありません。

編集:

明確にするために、セッションを使用するかどうかを決定しようとはしていません。私はそのビットに満足しています。私が解決しようとしているのは、設定する各カルチャーのアクションメソッドを持つカルチャーコントローラーでこれを行うのが最善であるか、MVCパイプラインにこれ​​を行うためのより良い場所があるかどうかです?

81
ChrisCa

私はこれを使用しています ローカリゼーション方法 とユーザーが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のサンプルプロジェクトを作成しました。このプロジェクトは here で見つけることができます

Http:// {yourhost}:{port}/en-us/home/indexにアクセスして、英語(米国)で現在の日付を確認するか、http:// {yourhost}:{port}/deに変更します。 -de/home/index(ドイツ語など)。

109
jao

これは古い質問ですが、ModelBinderで(DefaultModelBinder.ResourceClassKey = "MyResource";およびviewmodelクラスのデータアノテーションで示されるリソースに関して)本当にこれを機能させたい場合は、コントローラーまたは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);
    }

[〜#〜] edit [〜#〜]

実際には、カスタムルートハンドラーを使用するより良い方法があります。これは Alex Adamyanのブログで

行うべきことは、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);
    }
}
37
marapet

このようにコントローラーの初期化イベントでそれを行います...

    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;
    }
24
Jace Rhea

セッションはユーザーごとに保存される設定なので、セッションは情報を保存するのに適した場所です。

潜在的なカルチャーごとに異なるアクションメソッドを持たせるのではなく、カルチャーストリングをパラメーターとして使用するようにコントローラーを変更します。ページへのリンクを追加するのは簡単で、新しいカルチャが必要なときに同じコードを繰り返し記述する必要はありません。

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>
7
NerdFury

一番いいのはあなたの質問です。最適な場所はController.Initializeメソッド内です。 MSDNは、コンストラクターの後、アクションメソッドの前に呼び出されると書いています。 OnActionExecutingをオーバーライドするのではなく、Initializeメソッドにコードを配置すると、クラスおよびプロパティのすべてのカスタムデータの注釈と属性をローカライズすることができます。

たとえば、私のローカライズロジックは、カスタムコントローラーに挿入されたクラスから取得されます。 Initializeはコンストラクターの後に呼び出されるため、このオブジェクトにアクセスできます。スレッドのカルチャ割り当てを行うことができますが、すべてのエラーメッセージが正しく表示されません。

 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とHttpContextRouteDataがあり、基本的には解析可能。

5

たとえば「pt.mydomain.com」などのサブドメインを使用してポルトガル語を設定する場合、Application_AcquireRequestStateを使用しても機能しません。後続のキャッシュ要求では呼び出されないためです。

これを解決するには、次のような実装をお勧めします。

  1. 次のように、VaryByCustomパラメーターをOutPutCacheに追加します。

    [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. 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;
    }
    
  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
Andy

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();
}
4
Meng Xue
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;
        }
0
user2861593