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


85

ASP.netMVCアプリでカルチャ/ UIカルチャを設定するのに最適な場所はどこですか

現在、次のような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>

これは問題なく動作しますが、これを行うにはもっと適切な方法があると思います。

次のActionFilterhttp //www.iansuttle.com/blog/post/ASPNET-MVC-Action-Filter-for-Localized-Sites.aspxを使用してCultureを読んでい ます。私は少しMVCの初心者なので、これを正しい場所に設定しているとは確信していません。web.configレベルでは実行したくありません。ユーザーの選択に基づいている必要があります。また、ブラウザの設定からカルチャを取得するためにhttpヘッダーを確認したくありません。

編集:

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


セッション状態を使用してユーザーカルチャを選択することは適切な選択ではありません。最良の方法は、カルチャをURLの一部として含めることです。これにより、現在のページを別のカルチャと簡単に「交換」できます。
nightOwl888 2016年

回答:


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属性をアクティブにするには、それをクラスに追加するだけです。

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

これで、訪問者がhttp://example.com/de-DE/Home/Indexにアクセスするたびに、ドイツ語のサイトが表示されます。

この答えがあなたを正しい方向に向けてくれることを願っています。

また、ここで見つけることができる小さなMVC5サンプルプロジェクトを作成しました

http:// {yourhost}:{port} / en-us / home / indexにアクセスして、現在の日付を英語(US)で表示するか、http:// {yourhost}:{port} / deに変更してください。 -ドイツ語などのde / home / index。


15
また、言語をURLに入れるのも好きです。これは、さまざまな言語の検索エンジンでクロールできるようになり、ユーザーが特定の言語でURLを保存または送信できるようになったためです。
Eduardo Molteni 2009年

50
言語をURLに追加しても、RESTに違反することはありません。Webリソースを非表示のセッション状態に依存しないようにすることで、これに準拠しているのは事実です。
Jace Rhea

4
Webリソースは、非表示の状態に依存せず、レンダリング方法が異なります。あなたは、Webサービスなどのリソースにアクセスしたい場合、あなたはそれを行うには、言語を選択する必要があります。
デイヴ・ヴァン・デンEynde

4
このタイプのソリューションにはいくつか問題がありました。検証エラーメッセージは翻訳されていませんでした。この問題を解決するために、global.asax.csファイルのApplication_AcquireRequestState関数でカルチャを設定しました。
ADH 2015年

4
これをフィルターに入れるのは良い考えではありません。モデルバインディングはCurrentCultureを利用しますが、ActionFilterはモデルバインディングの後に発生します。Global.asax、Application_PreRequestHandlerExecuteでこれを行うことをお勧めします。
ステファン

38

これは古い質問ですが、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);
    }

編集

実際には、URLに従ってカルチャを設定するカスタムルートハンドラーを使用するより良い方法があります。これは、AlexAdamyanがブログで完全に説明しています。

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

残念ながら、RouteDataなどは「Application_AcquireRequestState」メソッドでは使用できませんが、Controller.CreateActionInvoker()では使用できます。だから私は「保護されたオーバーライドIActionInvokerCreateActionInvoker()」を提案し、CultureInfoをそこに設定します。
–SkorunkaFrantišek 2012

そのブログを読んだ。クッキーを進めても問題はありませんか?変更する権限がないので。お知らせください。このアプローチに問題はありますか?
kbvishnu 2012年

@VeeKeyBeeサイトが公開されている場合、Cookieを使用すると、すべての言語が適切にインデックスに登録されません。保護されたサイトの場合は、おそらく問題ありません。
marapet 2012年

公開されていません。「インデックス付き」という言葉についてヒントを教えてください。
kbvishnu 2012年

1
あなたはあなた自身の質問をしてSEOを読むべきです、これはもはや元の質問とは何の関係もありません。webmasters.stackexchange.com/questions/3786/...
marapet

25

私はこのようにコントローラーのInitializeイベントでそれを行います...

    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
ユーザーはサイトで使用するカルチャを指定できる必要があるため、カルチャ文字列をconstにすることはできません。
NerdFury 2009年

2
それは理解できますが、問題は、文化をどのように設定するかではなく、どこに設定するのが最善かということでした。
Jace Rhea

constの代わりに、次のようなものを使用できます。varnewCulture = new CultureInfo(RouteData.Values ["lang"]。ToString());
Nordes 2010年

AuthorizeCoreはOnActionExecutingの前に呼び出されるため、AuthorizeCoreオーバーライドメソッドにカルチャの詳細はありません。特にカスタムAuthorizeAttributeを実装している場合は、AuthorizeCoreの前にInitializeメソッドが呼び出されるため(AuthorizeCore内にカルチャの詳細があります)、コントローラーのinitializeメソッドを使用するとうまくいく可能性があります。
ネイサンR

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>

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

質問により適した編集済みの回答を提供しました。
NerdFury 2009年

はい、それは確かにクリーンですが、私が本当に知りたいのは、これをコントローラーで実行する必要があるかどうかです。または、MVCパイプラインにCultureを設定するためのより良い場所がある場合。または、ActionFilters、Handlers、Modulesなどで優れている場合
ChrisCa 2009年

ユーザーが選択する機会がなかったため、ハンドラーとモジュールは意味がありません。ユーザーが選択を行い、ユーザーの選択を処理する方法が必要です。これはコントローラーで実行されます。
NerdFury 2009年

合意されたように、ハンドラーとモジュールは、ユーザーとの対話を可能にするために早期に行う必要があります。ただし、私はMVCを初めて使用するため、これを設定するパイプラインの最適な場所であるかどうかはわかりません。しばらく経っても連絡がない場合は、お答えいたします。パラメータをActionメソッドに渡すために使用した構文が機能していないようです。コントローラが定義されていないため、デフォルトのコントローラを使用します(この場合は正しくありません)。そして、適切な別の過負荷はないようです
ChrisCa 2009年

6

最高の場所はあなたの質問です。最適な場所はコントローラー内です。初期化メソッドです。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とHttpContext、および基本的に可能なすべての解析を実行できるRouteData取得できます。


これは私のHTML5Telerik ReportLocalization!で機能します。ありがとう@PatrickDesjardins
CoderRoller 2015

4

たとえば「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

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
これが最善の方法であると思われる理由を説明してください。
Max Leske 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.