平臺化專案多語言架構實現

孫凱旋發表於2016-07-24

專案為什麼要平臺化

一、易維護

封裝可以大大的減少耦合,當發生變更的時候只需要修改一處地方。平臺化專案和封裝是有區別的,平臺化專案是將專案所有元件、事件等制定一個標準,將這些元件基於標準進行高度封裝,實現配置介面,通過配置大大的減少編碼量。

當需要整體變更的時候只需要更改這個標準便可,維護點更加的明確。

二、可擴充套件

1、首先有一點我要糾正,好多人都說封裝性太強的東西只能做一些定性的專案,不能滿足複雜的需求。這個觀點是錯誤的,只能說你在使用別人高度封裝的框架,而沒有自已的框架 或者 沒有掌握別人的框架 在或者 那個框架太LOW了。優秀的框架都是可以滿足開發需求的,因為他們都留有很多自定義的地方。

2、當專案需求不能滿足的時候,可以按照標準去擴充套件現有元件或者建立新的元件。

3、即使元件程式碼太垃圾也沒關係,只要保證呼叫處是規範的,以後隨時都可以對元件進行重構。

三、成長性

隨著專案越來越多,標準會越來越完善,元件也會越來越多 

 

多語言傳統實現方式

拋開資料庫部分

一、資原始檔

通過Cookie的值來決定到底呼叫哪個資原始檔,我用的是.NET,我就來吐嘈下.NET資原始檔的多麼不方便

1、需要定義N多的Key。

2、為什麼要把中文和英文分成兩個檔案,來回切換有多麻煩,而實際上我們需要的是這樣的資原始檔。

3、效能差笨重

二、XML

1、需要自已設計程式碼

2、無法在靜態檔案中使用,做不到前後分離

3、檢視不方便,沒有EXCEL直觀

 

三、多個頁面

 使用多個頁面來實現多語言有兩個缺點:

1、當一個頁面HTML結構發現變動的時候其它頁面也需要變更

2、沒有現成的檔案給專門的部門去翻譯,要自已整理或者翻譯者就在程式設計師身邊

 

基於平臺化的實現方式

一、設計資原始檔

如下圖我們選擇了EXCEL作為資原始檔,根據功能的不同把EXCEL劃分為多個檔案,和傳統的資原始檔劃分方式是不同的。

 

根據頁面定義了多個Sheet,有幾種語言就定義幾列,而不是有幾種言語就定義多少檔案和傳統方式是質變。

只要找個小弟把CN整理好,就不需要我們開發部門出任何體力了,也許會有人問為什麼沒有key,對!我們就是不需要用到key這個累贅,下面會講到如何實現。

 

二、如何解析EXCEL

.NET可以使用Aspose.cell或者NOPI等元件把將EXCEL轉為物件,可以將這個物件存進Cache減少IO操作

儲存的結構為List<T>

public class T{

目錄

模組

頁面

語言A

語言B

語言C ...

}

這種結構可以很容易的篩選出當前頁面所需要的語言

 

三、實現1:模版解析引擎裡面作手腳實現全域性替換

拿.NET MVC來舉例子:

使用RazorEngine.dll自已實現CSHTML轉HTML

public ActionResult Index(){

string templateObj = GetViewByFilePath("~/Home/index.cshtml");  

var model=new { id = xxx };

string html = Razor.Parse(templateObj ,model ); 

//根據Excel轉成的List<T>,篩選出當前頁面的語言List<T>,對這個html 進行遍歷替換處理 
//程式碼並無封裝可言,我只是為了讓大家看的更明白些
foreach(var it in List<T>){
  html=html.Replace(it.預設語言,it.當前語言);
}

return View((new HtmlString(html),"~/Home/Shared/Language.cshtml");
}

  

 

//所有頁面最後都使用Language.CSHTML檔案  

@model HtmlString


@Model

 

上面的替換程式碼只是最簡單的例子更細節的地方我會在下面講到  

缺點: 

即使使用了快取也會有點點效能影響,至少不會比資原始檔差。

 

四、實現2:生成靜態檔案方式

只需要開發預設語言的所有頁面,然後通過工具的方式去生成其他頁面

如圖: index_en.cshtml是通過工具生成出來的頁面

 

重寫檢視引擎根據Cookie自動呼叫相應的View檔案

{
    /// <summary>
    /// 自定義MVC檢視引擎
    /// </summary>
    public sealed class BestViewEngine : RazorViewEngine
    {
 
        public BestViewEngine()
        {
        }
        /// <summary>
        /// 重寫FindView
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="viewName"></param>
        /// <param name="masterName"></param>
        /// <param name="useCache"></param>
        /// <returns></returns>
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            var key ="languageKey";//COOKIE KEY
            var cm = CookiesManager<string>.GetInstance();
            if (cm.ContainsKey(key))//驗證多語言COOKIE是否有值
            {
                var cacheVal = cm[key]; //獲取多語言字尾 (例如: en)
                if (cacheVal.IsValuable())
                    viewName += "_{0}".ToFormat(cm[key]);//將原檢視名新增字尾   比如 index 新增字尾之後就是 index_en
            }
            return base.FindView(controllerContext, viewName, masterName, useCache);//引數處理後呼叫BASE的FindView方法
        }
 
    }
}

 

工具的邏輯很簡單  讀取檔案index.cshtml HTML =》獲取語言List<T>=>篩選語言List<T>=>遍歷替換成新的HTML 寫入Index_en.cshtml 

 

缺點

 使用的是工具,總感覺少了點什麼。

 

五、實現3:我們平臺的實現方式

1、頁面所有的選單是通過平臺配置生成的

 

通過後臺配置生成出來的導航地圖

 

2、將多語言工具整合到平臺配置介面,點選生成自動建立相應的VIEW檔案

 

生成後的目錄

 

3、資料庫因為有 語言表和選單表,Excel裡面的Sheet就更容易篩選了,只要在列裡面新增一個選單ID便可,演算法也更加精簡,EXCEL的結構也支援更多花樣

 

六、替換的小技巧

1、JS程式碼中文的提取

 

JS使用頁面的定義

 

2、根據上圖整理出來的Sheet,把JS部分和頁面部分的中文都整理進去了,並且把當前選單ID也加進去了方便篩選

 

3、拿EXCEL裡面的第一行和第二行來說吧,如果就這麼單純的替換會出現問題

頁面裡面的【必填數字】,會變成 【Required數字】

 

(1)、我們可以通過先替換長的,在替換短的來解決這個問題

(2)、先替換當前頁面的在替換公共的

(3)、按上面2種替換方式可以保證99%頁面替換是正確定的了,針對特殊情況們可以 【^移動】通過符號新增優先順序  只要以^符號的開頭的最先替換=》然後按長度=》按當前頁和通用頁,這樣就能保證99.9%,以此類推(說白了就是在優先順序上面做手腳)。

 

 

您不給個贊嗎?

相關文章