Monday, May 28, 2012

Multi Language in Ext.NET MVC - Tạo ứng dụng web đa ngôn ngữ trong Ext.NET MVC

Các công cụ cần có:

  1. Visual Studio 2010 SP1 + ASP.NET MVC 4 installed
  2. Ext.Net 2.0 beta lastest  https://docs.google.com/folder/d/0B_CfB63y75oaYWVvWUczZldwX2s/edit
That's all you need!
Tạo new  project ASP.NET MVC 4 chọn template là Emty Project
Chuột phải vào Node Project/Reference và add các DLL của Ext.NET vừa tải về
Như các bạn đã biết thì ASP.NET hỗ trợ xây dựng website đa ngôn ngữ bằng cách tạo ra các file resource và lưu tại App_GlobalResources. Nếu project của bạn chưa có thư mục này thì bạn hãy chuột phải vào Project và chọn Add ASP.NET folder->App_GlobalResources. Sau đó ta thêm 1 file resource, ở đây mình đặt tên là LocalizedText.resx. Ngôn ngữ mặc định của nó sẽ là tiếng Anh. Sau đó mình thêm 1 file LocalizedText.vi-VN.resx để lưu ngôn ngữ tiếng việt. Sau đó các bạn thêm vào 1 số text string
Các bạn nhấn chuột phải vào tệp LocalizedText.resx và chọn Build ActionEmbedded Resource, sau đó lưu lại và Rebuild Project

Cơ chế để thực hiện thay đổi ngôn ngữ là khi người dùng chọn ngôn ngữ của mình, ứng dụng sẽ gọi đến 1 ajax để trả về cho ứng dụng 1 tập hợp các cặp key-value chứa ngôn ngữ của họ được đọc ra từ file resource. Các cặp key value này sẽ đc lưu trong 1 ext store và viết hàm javascript để thay đổi các label tương ứng với cặp key-value của nó. Ưu điểm của phương pháp này là ứng dụng chạy nhanh và người dùng ko cảm thấy được độ trễ cũng như ko cần load lại trang, các tác vụ của người dùng đang làm sẽ vẫn được giữ nguyên.
Tạo 1 controller và đặt tên là HomeController sau đó thêm vào đoạn code sau:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ext.Net.MVC;
using Ext.Net;
using System.Threading;
using System.Globalization;

namespace MultiLangExt.Controllers {
    public class HomeController : System.Web.Mvc.Controller {
        //
        // GET: /Home/

        public ActionResult Index() {
            return View();
        }
        public StoreResult Translate() {
            string lang="";
            if (Request.Cookies["language"] == null) {
                lang = "vi-VN";
            }
            else { lang = Request.Cookies["language"].Value; }
            
            CultureInfo cult = Thread.CurrentThread.CurrentCulture;

            try {
                cult = new CultureInfo(lang);
            }
            catch (Exception ex) { }
            var res = Resources.LocalizedText.ResourceManager.GetResourceSet(cult, true, true);
            var trav = res.GetEnumerator();
            var dict = new Dictionary();

            while (trav.MoveNext()) {
                if (trav.Key.ToString().Length > 2)
                    dict.Add(trav.Key.ToString(), trav.Value.ToString());
            }

            var q = from c in dict
                    select new { key = c.Key, value = c.Value };

            return new StoreResult(q, dict.Count);
        }
    }
}

Trong file Global.asax bạn thêm vào hai route :
routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
routes.MapRoute(
      name: "Transalte",
      url: "{controller}/{action}/{id}",
      defaults: new { controller = "Home", action = "Transalte", id = UrlParameter.Optional }
   );
Cái route thứ nhất là để hiển thị view Index, còn route thứ 2 để gọi đến Action Translate khi người dùng thay đổi ngôn ngữ.
Tiếp đến sẽ là file Index.cshtml. Các bạn thêm vào đoạn code sau.

@using Ext.Net;
@using Ext.Net.MVC;
@{
    Layout = null;
}
@Html.X().ResourceManager()
@(
 Html.X().Store().ID("dsTranslate").AutoLoad(true)
     .Proxy(proxy => proxy.Add(
                    new AjaxProxy {
                        BatchActions = true,
                        API = {
                            Read = "/Home/Translate"
                        },
                        Reader = { new JsonReader{
                                Root="data",
                                TotalProperty="total"
                            }
                        }
                    }
                ))
     .Model(model => model.Add(Html.X().Model().IDProperty("key")
                    .Fields(fields => {
                        fields.Add(Html.X().ModelField().Name("key"));
                        fields.Add(Html.X().ModelField().Name("value"));
                    })
                ))
    .Listeners(listener => {
        listener.Load.Handler = "TranslateLoaded()";
    })
)
@(
 Html.X().Button()
    .Text("Language")
    .Menu(theme =>
        theme.Add(Html.X().Menu()
                .Items(themeMenuItem => {
                    themeMenuItem.Add(Html.X().CheckMenuItem()
                                        .Text("English")
                                        .Group("Language")
                                        .OnClientClick("changeLanguage('en-US');")
                        );
                    themeMenuItem.Add(Html.X().CheckMenuItem()
                                        .Text("Vietnamese")
                                        .Group("Language")
                                        .OnClientClick("changeLanguage('vi-VN');")
                        );
                })))
)
@( 
 Html.X().Window().Icon(Icon.Information).Width(400).Height(400).ID("lbWindowTitle")
 .Buttons(b => {
     b.Add(Html.X().Button().Text("Click").Icon(Icon.Accept));
 })
.Items(items =>
{
    items.Add(Html.X().TextField().ID("lbUsername").AnchorHorizontal("100%").LabelWidth(100));
    items.Add(Html.X().TextField().ID("lbPassword").AnchorHorizontal("100%").LabelWidth(100));
    items.Add(Html.X().Checkbox().ID("lbRememberMe").AnchorHorizontal("100%").LabelWidth(100));

})
)


Đây là hàm javascript để xử lí các tác vụ
 var TranslateLoaded = function () {
        var records = App.dsTranslate.getRecordsValues();
        for (var i = 0; i < records.length; i++) {
            var cmp = Ext.getCmp(records[i].key);
            if (cmp) {
                //Different Ext.NET control might need
                //different treatment.
                if (cmp instanceof Ext.form.ComboBox) {
                    cmp.setFieldLabel(records[i].value);
                }
                else if (cmp instanceof Ext.form.TriggerField) {
                    if (cmp.emptyText != '') {
                        Ext.apply(cmp, {
                            emptyText: records[i].value
                        });
                        cmp.reset();
                    }
                    if (cmp.fieldLabel != '')
                        cmp.setFieldLabel(records[i].value);
                }
                else if (cmp instanceof Ext.menu.Item) {
                    var pnl = tpMain.find('title', cmp.text);
                    if (pnl.length > 0) {
                        pnl[0].setTitle(records[i].value);
                        pnl[0].reload();
                    }
                    cmp.setText(records[i].value);
                }
                else if (cmp instanceof Ext.form.Label
                  || cmp instanceof Ext.data.NodeStore) {
                    cmp.setText(records[i].value);
                }
                else if (cmp instanceof Ext.Panel
                || cmp instanceof Ext.Window)
                    cmp.setTitle(records[i].value);
                else if (cmp instanceof Ext.form.TextField
                || cmp instanceof Ext.form.FieldContainer
                            || cmp instanceof Ext.form.Radio
                            || cmp instanceof Ext.form.Checkbox) {
                    cmp.setFieldLabel(records[i].value);
                }
                else if (cmp instanceof Ext.Button) {
                    if (cmp.getText() != '' && cmp.getText() != undefined)
                        cmp.setText(records[i].value);
                } else if (cmp instanceof Ext.form.DisplayField) {
                    cmp.setValue(records[i].value);
                }
            }
        }
    }
    var changeLanguage = function (language) {
        Ext.util.Cookies.set('language', language);
        App.dsTranslate.reload();
    }
Và đây là kết quả

1 comment: