RFC是Request For Comment的意思,學過網路的人應該多半有聽過,但這篇文章跟開創網路歷史的那堆偉大協定文件一點關係都沒有(謎之聲: 憑你也配!),純粹只是提出一個構想,想多蒐集各方意見。

事情要從工作專案增加了多國語系需求說起,ASP.NET雖早有解決方案,但我一直覺得傳統的多國語系搞法不夠人性化,就興起了為搞套簡便做法救自己的念頭。

傳統的ASP.NET多國語系做法要把所有因語系變換的文字改成變數物件或指定Resource Key,然後為不同語系設定資源檔,再針對每個Resource Key指定對應的字串。說具體一點,就是ASPX裡原本是

<asp:Label ID="lblUserName" runat="server" Text="使用者名稱"></asp:Label>
<asp:Label ID="lblUserNameHint" runat="server" 
           Text="請填寫中文或英文姓名"></asp:Label>
<script type="text/javascript">
...
    if (...) alert("使用者名稱中不可包含特殊符號! - " + $("#txtUserName").val());
...
</script>

為了多國語系,要改成:

<asp:Label ID="lblUserName" runat="server" 
           Text="<%$ Resources:UserNameLabel %>"></asp:Label>
<asp:Label ID="lblUserNameHint" runat="server" 
           meta:resourcekey="UserNameHint"></asp:Label>

然後Script部分更麻煩,得將原本一氣喝成的Script改成義大利麵寫法:

if (...) 
    alert("<%=GetLocalResourceObject("DontSymbolMessage").ToString()%> - " 
          + $("#txtUserName").val());

再不然就是搬到Server-Side

string s = "alert('" + 
           GetLocalResourceObject("NoSymbolMessage").ToString() + 
           " - ' + $('#txtUserName').val());";

依我個人看法,傳統做法最大的缺點是原本Visual Studio WYSWYG的直覺化特色不見了! 在開發階段看不出表單到底長什麼樣子,得按下執行鈕從Browser得到結果;若Layout需要調整,就得重覆"改HTML/CSS->跑Browser看結果->改HTML/CSS->跑Brwoser看結果..."的惱人迴圈。再者,為每段文字編一個Resource Key及維護的浩大工程,更是一箭射中粗心又沒耐性暴躁大叔的罩門,光用想像的就足以讓我瀕臨崩潰。

我不知道別人怎麼看待這樣的設計,但在我心目中,應該要用更直覺的方法解決Client-Side的多國語系問題才對,於是我想出了以下做法,還不怎麼成熟,姑且先稱它jQuery Multi-Language Helper Ver 0.5吧! 如果有機會得到大家的回饋,修校得更具體可行,或許會有推出Ver 1.0的機會。

使用它時,程式長這樣:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Multi-Language UI Test</title>
    <script src="jquery-1.4.2.js" type="text/javascript"></script>
    <script src="jquery.multilang.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            jQuery.setupMultiLang("UI.lang.htm");
            $("#dvLangSwitch span").click(function () {
                var t = $(this).text();
                var lang = "DEF";
                switch (t) {
                    case "中文":
                        lang = "DEF";
                        break;
                    case "英文":
                        lang = "ENG";
                        break;
                    case "簡中":
                        lang = "CHS";
                        break;
                }
                jQuery.switchLang(lang);
 
            });
            $("#btnSubmit").click(function () {
                var v = $("#txtEmpName").val();
                if (v.length == 0) {
                    //呼叫ml函數(Multi-Language縮寫),可以自動換訊息
                    alert(ml("員工姓名不可空白!"));
                } else if (v.match("[0-9_!@#$%^&*()<>]"))
                //可以利用{0}, {1}加入變動內容
                    alert(ml("員工姓名有無效字元: {0}", v));
            });
        });
    </script>
    <style type="text/css">
        #dvLangSwitch span  
        {
            color: Blue; text-decoration: underline; 
            margin-left: 5px; cursor: pointer 
        }
        body, table { font-size: 9pt; }
        #tblFillForm { width: 400px; }
        #tblFillForm td { border: 1px solid #dddddd; }
        td.hdr { text-align: right; padding-right: 10px; }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div id="dvLangSwitch"><span>中文</span><span>英文</span><span>簡中</span></div>
    <div>
    <table id="tblFillForm">
    <tr><td class="dtml hdr" style="width: 100px">員工姓名</td>
    <td><input type="text" id="txtEmpName" /></td></tr>
    <tr><td class="hdr"><span class="dtml">通訊選項</span></td><td>
    <select id="txtContChan" class="dtml">
        <option value="MSN">MSN</option>
        <option value="Yahoo">即時通</option>
        <option value="Plurk">噗浪</option>
    </select>
    </td></tr>
    <tr><td></td>
    <td><input type="button" id="btnSubmit" value="送出" class="dtml" /></td></tr>
    </table>
    </div>
    </form>
</body>
</html>

這個網頁跟一般非多語系網頁做法差不多,但我用黃底標出了幾個為了配合多國語系而加的東西。

首先,HTML中還是直接寫死預設語系文字,若針對切換語系時要變化的內容,要多加一個class "dtml"。在本範例中,有td, span, select, input加上了多國語系支援。當jQuery. setupMultiLang時,要指定一個多語系資源檔,雖然XML可能是更好的選擇,但我決定用HTML Table做為儲存對照文字的格式,主要考量在於它可直接用現成網頁編輯工具維護,不需要再生工具。而setupMultiLang時背後有個小機關,它會找出所有標示dtml Class的元素,取出其內容,在UI.lang.htm中比對出它是哪一筆資料,自動定義Resource Key,這種看似沒效率且不怎麼可靠(因為HTML中的文字要跟UI.lang.htm欄位的內容一字不差)的做法,卻可以省下為每個資料定義唯一Resource Key的可觀工程(暴躁大叔表示欣慰)。

在本例中,UI.lang.htm長像如下。第一欄的標記可以用來放#btnSubmit之類的jQuery Selector用以準確鎖定特定元素,會比用文字內容比對決定Resource Key來得可靠,效率也更好;第二欄位則用來標註該內容用於更換SELECT選項清單、INPUT的value或是一般元素的innerHTML;第三欄為預設語系的文字內容,就是HTML使用的語系;第四欄以後則是其他語系資料。

最後,在範例中,順便展示了怎麼讓Javascript也支援多語系文字內容的做法,其中有個ml(...)函數可以查表將預設語系文字轉換成目前語系的內容(一樣用的是比對法,故記得要使其與DEF內容一字不差),而ml("... {0} {1}", v1, v2)的寫法可應用在需穿插動態內容的場合。

經過上述一番惡搞,用了不算太複雜的寫法跟規則,就弄出了一個支援中文、英文跟簡體中文三種語系的介面:

這就是目前我的構想,有興趣的朋友可以下載回去玩(下載解壓如有問題,請用IE以外的瀏覽器試試[原委]),並歡迎將應用時發現的問題反映給我,做為改良參考,感謝!


Comments

# by Wolke

黑大你好: 我有用JQuery做一個語言包的程式, 完全在Client端解決多語系的問題了, 我自已是用的還不錯啦! 歡迎參觀看看! http://wolke-codes.blogspot.com/2010/07/wolke-jquery-language-tools-wolke.html 我的網站,作品集裡也有Demo http://wolke-web-app.appspot.com/

# by Will 保哥

切換語系的地方感覺用 span 怪怪的,用 a 標籤比較符合語意,然後套用 class="DEF" 之類的,少用 switch case 程式碼比較短些。另外,用標準的 zh-TW 似乎比較具有語系的概念。

# by Jeffrey

to 保哥,哈! 切換語系的地方是亂亂寫的(因為實務上大家多半會視Browser語系或使用者Profile決定語系,不會直接用這種方式),不過用class="DEF"是好主意,取zh-TW的建議也很值得考量,十分感謝!

# by 疑惑者

請問您有放在主機上run過嗎? 下載您的範例後,在本機電腦都沒問題 但若是放在主機上,再去開啟UI.htm 都會出現 : multiLangToolbox 未被定義的錯誤

# by Jeffrey

to 疑惑者, 這個做法使用的都是純js加html,理論上對部署主機沒什麼條件限制,只要擺進htm及js後都能正常下載即可。我唯一想到的是編碼問題,若js檔案被當成ANSI編碼,有可能出現一些奇怪狀況: http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/05/04/747.aspx 若是你主機有對Internet開放,提供連結大家可幫忙看。

# by 真相

員工改為教師 其對應employee -> teacher 如何增列呢??? 謝謝您 by 一位菜鳥

# by Jeffrey

to 真相,不是很明白你的問題。員工改為教師是指 員工姓名->教師姓名, Employee Name->Teacher Name 這樣嗎?

# by

請問範例檔的ui.html頁面打開 出現 ---------- Java script通知 ui .lang.htm is missing BEGIN/END mark ---------- 是甚麼狀況 然後暗了確認知後 語言是無法照著按鈕切換

# by Jeffrey

to 宥,請問直接下載範例放在網站執行就出錯嗎?使用的瀏覽器版本為何? 我放了一個Live Demo http://www.darkthread.net/miniajaxlab/multilang/ui.htm 可以比對看看有何差異?

Post a comment