IT業界のすみっこ暮らし

ふと気がついたときの記録

ASP.NET MVC:ユーザー設定による多言語対応について諸々メモ

前提

デフォルト言語は日本語だけど、海外のユーザーは英語で見せたい。

ユーザーの設定情報から使用言語の情報を取得可能。

実装

1、リソースファイルを用意する

  • デフォルト言語:Localize.resx
  • 日本語:Localize.ja-JP.resx
  • 英語:Localize.en-US.resx

※リソースファイルのAccess Modifierは「Public」に設定する。

※リソースの格納場所は任意でok(ex)Lang > Localize.resx とか)

2、ユーザー認証直後の処理に以下の内容を追加

var key = "cultureInfo";
var value = string.Empty;
//cType = DBからユーザーのカルチャー情報を取得
switch (cType)
{
    case 1:
        value = "ja-JP";
        break;
    case 2:
        value = "en-US";
        break;
    default:
        value = "ja-JP";
        break;
}

Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(value);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(value);

var cookie = new HttpCookie(key);
cookie.Value = value;
Response.Cookies.Add(cookie);

3、アクションの度にカルチャーの設定を行う

Thread.CurrentThread.CurrentCultureで設定できる範囲は1リクエストのみなので、クッキーなどで保持しておいてアクションが発生するタイミングで設定し直す必要がある。

InternationalizationAttribute.cs
using System.Globalization;
using System.Threading;
using System.Web;
using System.Web.Mvc;

public class InternationalizationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var cultureInfo = "ja-JP";
        HttpCookie cookie = filterContext.RequestContext.HttpContext.Request.Cookies["cultureInfo"];
        if (cookie != null && !string.IsNullOrEmpty(cookie.Value))
        {
            cultureInfo = cookie.Value;
        }

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(cultureInfo);
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(cultureInfo);
    }
}

4、多言語化したいところにリソースに設定した値を使う

xx.cshtml
<p>@Localize.GettingStartedTitle</p>

<!--  改行あり -->
<p>@Html.Raw(Localize.AboutAspNetMvcDesc.Replace("\r\n","<br>"))</p>

<!--  string format使用(エラーメッセージなど) [ex)Please enter an amount greater than {0}. ]-->
<p>@string.Format(Localize.ErrorMessage1, "0")</p>

5、リソースのキーから値を取得したい場合

public string GetResourceValueByName(string name)
{
    var value = string.Empty;
    System.Resources.ResourceManager rm = new System.Resources.ResourceManager("base name", this.GetType().Assembly);
    value = rm.GetString(name).ToString();

    if (!string.IsNullOrEmpty(value))
    {
        return value;
    }
    else
    {
        return name;
    }
}

普通に「Localize.ErrorMessage1」みたいに直で設定するのが一番だけど、もしそれが出来ない場合、もしくはリソースから任意のキーで値があるか確認したり取得する必要がある場合はこういう方法もある。

base nameも引数で受け取って、キーから値取得用の汎用的なモジュールにするのもあり

6、用途によってリソースファイルを分けたい場合

分け方によるけど、個人的にはこんな感じで分けてる

[Lang]
 ┗ Localize.resx
 ┗ Localize.ja-JP.resx
 ┗ [Contract] // 契約書の多言語リソース
   ┗ Localize.resx
   ┗ Localize.ja-JP.resx
 ┗ [Invoice] // 請求書の多言語リソース
   ┗ Localize.resx
   ┗ Localize.ja-JP.resx

#例
  • Lang.Localize.Name → 名前
  • Lang.Contract.Localize.Name → 氏名
  • Lang.Invoice.Localize.Name → 利用者名

参考

ASP.NET MVC におけるテキストの多言語対応 再考 : @jsakamoto