[MVC]建置多國語言系統之路

分享以ASP.NET MVC 3一步一步建置一個多國語言系統的方式
1.從Resource File開始
2.利用String Extension Method來做多國語言
3.利用HtmlHelper Extension Method來將輸出多國語言
4.利用自定的Attribute來輸入多國語言的驗証訊息
5.Javascript多國語言的處理

前言

分享以ASP.NET MVC 3一步一步建置一個多國語言系統的方式。

1.從Resource File開始

2.利用String Extension Method來做多國語言

3.利用HtmlHelper Extension Method來將輸出多國語言

4.利用自定的Attribute來輸入多國語言的驗証訊息

5.Javascript多國語言的處理

環境

ASP.NET MVC3, VS2010 C#, .NET 4.0

實作

一開始先建立一個「ASP.NET MVC 3 Web 應用程式」 專案,取名Mvci18n,然後選擇空白的ASP.NET MVC專案,檢視引擎選「Razor」。

1NewMvc

1.從Resource File開始

建立一個Resource1.resx、Resource1.en-US.resx及Controller Home、View Index

Res1

Res1-enUS

public ActionResult Index()
{
    ViewBag.TEST = App_GlobalResources.Resource1.TEST;
    return View();
}

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>@ViewBag.TEST</h2>

備註,如果您從Resource1無法選出TEST的話,那是因為Resource檔中自訂工具是設定成「GlobalResourceProxyGenerator」所導致的,所以請將它清空,然後重新開啟Resource檔,並設定「存取修飾詞」成「Public」,之後在Controller中就可以選到了!

NoTest

ResTool

ShowTest

為了要方便測試多國語言,將web.config中設定成由Client決定,在system.web區段中加入globalization設定,如下,

<globalization culture="auto" uiCulture="auto" enableClientBasedCulture="true" />

所以當IE的語言設成了英文,就會顯示英文訊息,設成中文,就會顯示中文。

enUS

zhTW

 

2.利用String Extension Method來做多國語言

App_GlobalResources.Resource1.TEST感覺不是很直覺,可以利用String Extension Method來做多國語言,變成"TEST".Toi18n(),有直覺一點嗎? 所以我們建立一個StringExtensions Class Code如下,

namespace Mvci18n.Extensions
{
    public static class StringExtensions
    {
        //依語系產生i18n
        public static string Toi18n(this string value)
        {
            return App_GlobalResources.Resource1.ResourceManager.GetString(value);
        }

        public static string CultureName(this string value)
        {
            return System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
        }

        public static string Toi18n(this string nameSpace, string value)
        {
            string resKey = (string.IsNullOrEmpty(nameSpace) ? string.Empty : nameSpace + ".") + value;
            return App_GlobalResources.Resource1.ResourceManager.GetString(resKey); 
        }

        
    }
}

那原本Controller的Code就可改成
public ActionResult Index()
{
    //ViewBag.TEST = App_GlobalResources.Resource1.TEST;
    ViewBag.TEST = "TEST".Toi18n();
    return View();
}

3.利用HtmlHelper Extension Method來將輸出多國語言

接下來,建立新增畫面,所以在Model中新增Product Class,HomeController中新增Create Method,並建立View設定Model為Product,如下,

Product.cs,

namespace Mvci18n.Models
{
    public class Product
    {
        [Required(ErrorMessage="Please enter product name")]
        public string Name { get; set; }
        [Required(ErrorMessage = "Please enter price")]
        [Range(0.01, double.MaxValue, ErrorMessage="Please enter a positive price")]
        public decimal Price { get; set; }
    }
}

HomeController.cs,

[HttpGet]
public ViewResult Create()
{
    return View("Create", new Product());
}

Create.cshtml,

@model Mvci18n.Models.Product 
@using Mvci18n.Extensions          
@{
    ViewBag.Title = "Create".Toi18n();
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>@ViewBag.Title</h2>
@using (Html.BeginForm())
{
    <p>Product Name:@Html.TextBoxFor(x=>x.Name)</p>
    <p>Product Price:@Html.TextBoxFor(x => x.Price)</p> 
    <input type="submit" value="SubmitProduct" />
}

CtrlText

執行http://localhost:6754/home/create,畫面上的Product Name、Product Price及SubmitProduct也需要多國語言,所以也可以透過string的Toi18n Method取得。

但是要在View顯示出來,還要透過HtmlHelper Extension Method,如下,

namespace Mvci18n.Extensions
{
    public static class HtmlHelperExtensions
    {
        /// <summary>
        /// 產生一個字串
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        /// <remarks>
        /// Example:@Html.OutputText("Language".Toi18n())
        /// </remarks>
        public static MvcHtmlString OutputText(this HtmlHelper helper, string text)
        {
            return new MvcHtmlString(text);
        }
    }
}

再改View修改( 如@Html.OutputText("ProductName".Toi18n()) )成如下,

@using (Html.BeginForm())
{
    <p>@Html.OutputText("ProductName".Toi18n()):@Html.TextBoxFor(x => x.Name)</p>
    <p>@Html.OutputText("ProductPrice".Toi18n()):@Html.TextBoxFor(x => x.Price)</p>
    <input type="submit" value="@Html.OutputText("Submit".Toi18n())" />
}

CtlTextOK

4.利用自定的Attribute來輸入多國語言的驗証訊息

再來就是為加入欄位驗証機制,所以在Shared\_Layout.cshtml中加入驗証的JS

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

同時也在Create.cshtml中加入@Html.ValidationSummary() 

@using (Html.BeginForm())
{
    @Html.ValidationSummary()
    <p>@Html.OutputText("ProductName".Toi18n()):@Html.TextBoxFor(x => x.Name)</p>
    <p>@Html.OutputText("ProductPrice".Toi18n()):@Html.TextBoxFor(x => x.Price)</p>
    <input type="submit" value="@Html.OutputText("Submit".Toi18n())" />
}

執行http://localhost:6754/home/create,在畫面上如果沒有輸入產品名稱及價格,就會出現驗証錯誤的訊息,

ValidateMsg

所以,驗証訊息也需要處理多國語言,這裡就繼承DisplayNameAttribute、RangeAttribute來處理驗証訊息的多國語言,建立i18nDisplayNameAttr及i18nRegAttr,如下,

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Mvci18n.Extensions;

namespace Mvci18n.CustomAttrs
{
    public class i18nDisplayNameAttr : DisplayNameAttribute
    {
        public i18nDisplayNameAttr(string displayName)
        {
            DisplayNameValue = displayName.Toi18n();
        }
    }
    
    public class i18nRegAttr : RangeAttribute 
    {
        public i18nRegAttr(double min, double max)
            : base(min, max)
        {

        }
        public override string FormatErrorMessage(string name)
        {
            return string.Format(ErrorMessage.Toi18n(), new object[] { name });
        }
    }
}

Model中的Product屬性則使用我們建立的自定屬性,如下,

namespace Mvci18n.Models
{
    public class Product
    {
        [Required, i18nDisplayNameAttr("ProductName")]
        public string Name { get; set; }

        [Required, i18nDisplayNameAttr("ProductPrice")]
        [i18nRegAttr(0.1, double.MaxValue, ErrorMessage = "ProductPriceRangeChk")]
        public decimal Price { get; set; }
    }
}

再執行程式一次,就可以看到驗証訊息也隨語系而改變了!

ValidateMsgOK

RangeMsgOK

5.Javascript多國語言的處理

JS的處理的話,可依不同的語系建立JS檔,然後依不同的語系加入不同的JS檔,這裡我們在Scripts下再建一個locale的目錄,裡面放lang-en-US.js,lang-zh-TW.js等語系Resource檔。

<!-- 加入 JS i18n -->
<script src="@Url.Content("~/Scripts/locale/lang-" + Html.OutputText("".CultureName()) 
+ ".js")" type="text/javascript"></script>

lang-en-US.js內容如下,

var locale = {
    confirmSubmit: "Are you sure submit?"
    ,ShowMsg : "Show a JS Message!"
};

lang-zh-TW.js內容如下,

var locale = {
    confirmSubmit: "請問您確定送出嗎?" 
,ShowMsg : "顯示JS訊息!"
};

所以在View使用時,就可以直接使用locale.ShowMsg,如下,

<input type="button" value="@Html.OutputText("ShowMsg".Toi18n())" onclick="alert(locale.ShowMsg);" />

imageimage

 

結論

多國語言只是個開始,希望對大家有幫助,也希望有大家有其他的方法也能提出來討論,謝謝!

另外畫面的Layout,各時區的處理也是多國語言系統要考量的事! 

範例

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^