应用系统的多语言支持 (二)
看到有不少人关注多语言这方面的问题,感到非常高兴。有人也提议看看CCS的实现方法,其实我之前是看过它的办法的也是不错。但是我总觉得那种实现方法比较时候去做网站和一下简单的内容管理系统,不太适合用于有复杂操作的应用系统。
好了,闲话少说回到主题。考虑到应用程序的特点,需求变化比较快,页面操作复杂,所以我们一般不采用Theme那种方法将页面的内容放在Webcontrol里面一层套一层,这样在设定控件的事件以及控件的控制方面都比较麻烦。我们的主旨是把程序写到最简单,这样非常容易控制也便于变更,所以我们的系统中大部分的页面都是普通的web页面,有前端apsx文件和后代码组成,后代码继承一个基类页面。继承关系如图:
图一
在页面内部也没有太多的控件嵌套关系,由于这个特点。于是我们得到了这样的一个数据结构:
图二
一个系统有多个页面,一个页面有多个控件,一个控件可能有多列要显示的内容(其中,javascript中提示的信息和后台逻辑运算返回的信息也可以作为一个控件形式来考虑,有多条信息)。于是,到数据库表:
图三
数据部分由于客户要求存入数据库,所以这里我们使用数据库来设计了这个表。当然,也可以使用XML或者是Resource文件来保存也没有问题,只是存储方式的不同。
OK,有了数据有了页面文件,下面要考虑的只剩下2个问题了。一个是怎么取数据,一个是如何赋值。
今天我们主要讲如何赋值,取数据的方法我们下次再谈。
1) 页面控件的赋值
由于我们的系统中的页面较多,页面的控件也不少。所以考虑如何让系统自动来赋值而不用手工的一个一个去添加(当然,这样会损失一部分的性能)。 于是我们修改了基类,在基类中对页面的控件进行逐个处理, 实现代码如下:
之前,我们是将控件处理部分放在OnPreRender事件中处理的,但发现DataGrid控件的列头信息总是不能在页面初始化的时及时更新内容,后将这部分放在了Page_Load中实现了这个功能。
LocalizationManager.getMultiResource(Me.curLanguage, Me.GetType.Name, c.ID)
LocalizationManager.GetSingleResource(Me.curLanguage, Me.GetType.Name, c.ID, 0)
两个方法是用来从数据库中文本内容的,在下次的讨论中在讲它的实现。(当然,你可以用自己写的简单方法来实现)
2) 客户端Javascript提示信息
对于哪些Javascript中Alert的信息以及用来显示内容的信息,我们的想法是将这些信息用同一个关键字"jsmsg"作为controlid并按顺序存入数据库。在页面显示的时候,再将所有的信息组成一个字符串数组注册在页面上。这样,在基类中添加下面的代码:
2 Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
3 ClentMessageRegister()
4 End Sub
5
6 Private Sub ClentMessageRegister()
7 Dim dt As DataTable
8 Dim i As Integer
9 Dim jsmsg As String = ""
10
11 'get all client message
12 dt = LocalizationManager.getMultiResource(Me.curLanguage, Me.GetType.Name, "jsmsg")
13
14 'generate client message array
15 If dt.Rows.Count > 0 Then
16 jsmsg = "var msgstr = new Array("
17 For i = 0 To dt.Rows.Count - 1
18 jsmsg += """" + dt.Rows.Find(i.ToString).Item("Text") + ""","
19 Next
20 End If
21
22
23 'remove the last comas
24 If jsmsg.Length > 0 Then
25 jsmsg = jsmsg.Substring(0, jsmsg.Length - 1)
26 jsmsg += ");"
27
28 Page.RegisterStartupScript("PromptJSMsg", "<script language=""javascript"">" + jsmsg + "</script>")
29 End If
30 End Sub
31#End Region
这样,在页面显示时所有的信息都会根据语言注册在页面上。在页面上我们按照下面的例子来使用就可以了:
2 <!--
3 function submitSearch()
4 {
5 if (document.all['txtCreateFrmDate'].value != "")
6 {
7 if (!(checkdate(document.all['txtCreateFrmDate'].value)))
8 {
9 alert(msgstr[0]);
10 return false;
11 }
12 }
13
14 if (document.all['txtCreateToDate'].value != "")
15 {
16 if (!(checkdate(document.all['txtCreateToDate'].value)))
17 {
18 alert(msgstr[1]);
19 return false;
20 }
21 }
22
23 if ((document.all['txtCreateFrmDate'].value != "") && (document.all['txtCreateToDate'].value != ""))
24 {
25 if (!(compDate(document.all['txtCreateFrmDate'].value,document.all['txtCreateToDate'].value)))
26 {
27 alert(msgstr[2]);
28 return false;
29 }
30 }
31 }
32 //-->
33 </script>
3) 后台逻辑提示出的信息
对于后台逻辑运算后要提示的信息,也是同样的道理,只是不用提前注册在客户端罢了。例如:
'msg = "The stock code [{0}] does not exist in system!"
LocalizationManager.GetSingleResource(Me.GetType.Name, "vbmsg", 0, Me.curLanguage)
msg = msg.Format(msg, Me.txtStockCode.Text.Trim)
Me.pageAlert(msg)
我也简单的总结了一下,这样做的好处与坏处。
好处当然是避免了程序员在代码中一个控件一个控件的去赋值了,当客户想改某段文本时,可以随时修改。
缺点是增加了大量的数据录入工作,也损失了一部分的性能。因为很多可以复用的记录没有复用。
这就要靠大家来取舍了。如果你觉得还是在每个页面中手工去赋值好,也不要紧我们下次讨论如何组合和获取数据时你也可以一起讨论一下。
这方法中也许有些笨拙,希望大家多提意见,也好给小弟开拓一下思路。
相关链接:应用系统的多语言支持 (一)