ASP.NET MVC 다국어 대응에 대한 메모
업무로 다국어 대응이 필요한 웹 어플리케이션의 기반 개발을 담당했었는데, 그때 작업한 내용을 정리한 것입니다.
전제 조건
- 기본 언어는 일본어지만 해외 유저에겐 영어로 제공하고 싶음.
- 유저의 기본 설정정보에서 사용 언어에 대한 정보를 취득할 수 있다.
개발
1. 리소스 파일을 준비한다
- 기본 언어:Localize.resx
- 일본어:Localize.ja-JP.resx
- 영어:Localize.en-US.resx
※리소스 파일의 Access Modifier는 「Public」으로 설정합니다.
※리소스 파일의 격납 장소는 임의로 변경 가능 합니다(ex)Lang > Localize.resx 등)
2. 유저 인증 직후의 처리에 이하의 처리를 추가한다
AuthorizeAttribute Class 를 상속받아 인증 로직을 만들고, 그 내부에 처리를 추가하는 이미지 입니다.
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. Action 실행시마다 컬쳐 설정을 한다
Thread.CurrentThread.CurrentCulture에 설정한 값은 1번의 리퀘스트에서만 유효하므로 설정후엔 Cookie등에 격납해 두고 Action이 발생 되는 타이밍 마다 재설정 해 줄 필요가 있습니다.
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 → 이용자명
참고
- http://devadjust.exblog.jp/21514252/