引言
如果你是英语的用户就不必做任何本地化的工作了,这篇教程是为非英语用户所准备的,好像一般的用户,开发主管,业务员等,他们的外语可能稍逊,这样就需要你对如何本地化ext的整个流程了解一番了。
慢慢开始
如果你曾浏览Ext 2.x目录的树状结构,你就会发现source/locale的目录(或SVN目录的src/locale)。 此目录包含了Ext本地化类。 先不长篇大论地讲太多概念的东西,我们应了解如何先使用。
下面的一个例子就是使用了本地化的ext,但是不是在ext同一个目录下的。因此通常的,你需要调整head标签内的路径,以正确指向Ext的安装目录。尤其注意本地化的那个目录路径。
把你服务器的路径Copy and paste到相应文件路径中:
注意: 下里的代码我是动态加载到head头部的,只能在FireFox通过。不过实际情况你不必如此,你只要在服务端指定script的路径而不必动态加载。
2<head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css">
5 <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
6 <script type="text/javascript" src="../ext/ext-all-debug.js"></script>
7 <script type="text/javascript">
8
9 //根据url上指定的语言进行解码
10 var locale = window.location.search
11 ? Ext.urlDecode(window.location.search.substring(1)).locale
12 : '';
13
14 // 将本地化的JS文件加入head元素内
15 var head = Ext.fly(document.getElementsByTagName('head')[0]);
16 if(locale) {
17 Ext.DomHelper.append(head, {
18 tag:'script'
19 ,type:'text/javascript'
20 ,src:'../ext/src/locale/ext-lang-' + locale + '.js'
21 });
22 }
23
24 //预先定义的window继承类
25 Ext.ns('Tutorial');
26 Tutorial.LocalizationWin = Ext.extend(Ext.Window, {
27 initComponent:function() {
28 Ext.apply(this, {
29 width:500
30 ,id:'winid'
31 ,height:300
32 ,layout:'fit'
33 ,border:false
34 ,closable:false
35 ,title:Ext.get('title').dom.innerHTML
36 ,items:[{
37 xtype:'form'
38 ,frame:true
39 ,defaultType:'textfield'
40 ,items:[{
41 xtype:'combo'
42 ,fieldLabel:'Select Language'
43 ,name:'locale'
44 ,store:new Ext.data.SimpleStore({
45 id:0
46 ,fields:['file', 'locale']
47 ,data:[
48 ['cs', 'Czech']
49 ,['', 'English']
50 ,['fr', 'French']
51 ,['de', 'German']
52 ,['gr', 'Greece']
53 ,['hu', 'Hungarian']
54 ,['it', 'Italian']
55 ,['ja', 'Japaneese']
56 ,['pl', 'Polish']
57 ,['pt', 'Portugal']
58 ,['ru', 'Russian']
59 ,['sk', 'Slovak']
60 ,['es', 'Spanish']
61 ,['sv_SE', 'Swedish']
62 ,['tr', 'Turkish']
63 ]
64 })
65 ,listeners:{
66 select:{fn:function(combo){
67 window.location.search = '?'
68 + Ext.urlEncode({locale:combo.getValue()})
69 ;
70 }}
71 }
72 ,mode:'local'
73 ,editable:false
74 ,forceSelection:true
75 ,valueField:'file'
76 ,displayField:'locale'
77 ,triggerAction:'all'
78 ,value:locale
79 },{
80 fieldLabel:'Text Field'
81 ,allowBlank:false
82 },{
83 xtype:'datefield'
84 ,fieldLabel:'Date Field'
85 ,allowBlank:false
86 }]
87 }]
88 }); // eo apply
89 Tutorial.LocalizationWin.superclass.initComponent.apply(this, arguments);
90 } // eo function initComponent
91 }); // eo Tutorial.LocalizationWin
92
93Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';
94Ext.onReady(function() {
95 Ext.QuickTips.init();
96 Ext.form.Field.prototype.msgTarget = 'side';
97
98 // create example window
99 var win = new Tutorial.LocalizationWin();
100 win.show();
101});
102 </script>
103 <title id="title">Localization Example</title>
104</head>
105<body>
106</body>
107</html>
现在完整的本地化工作是限于ComboBox、TextField和DateField这些Ext基础组件。试试在已翻译好的DataPicker组件中输入一些文字。
原理是??
原理是一改变cobmo box里面的"Select Language"就会包含(include)相应的Ext本地化文件(这里我使用了一些技巧性的做法,改变本地化文件的过程是用过客户端脚本完成的)
本地化文件的葫芦里卖的什么药?
首先要打开本地化文件来看看,读懂里面的源码后不但对Ext的理解有帮助而且对整个程序的本地化,也是有帮助的。我们以法语版的DatePicker为例子:
2 Ext.override(Ext.DatePicker, {
3 todayText : "Aujourd'hui",
4 minText : "Cette date est antérieure à la date minimum",
5 maxText : "Cette date est postérieure à la date maximum",
6 disabledDaysText : "",
7 disabledDatesText : "",
8 monthNames : Date.monthNames,
9 dayNames : Date.dayNames,
10 nextText : 'Mois suivant (CTRL+Flèche droite)',
11 prevText : "Mois précédent (CTRL+Flèche gauche)",
12 monthYearText : "Choisissez un mois (CTRL+Flèche haut ou bas pour changer d'année.)",
13 todayTip : "{0} (Barre d'espace)",
14 okText : " OK ",
15 cancelText : "Annuler",
16 format : "d/m/y",
17 startDay : 1
18 });
19}
通过观察,我们得知如果DataPicker对象存在(这是需要检测的,事因有些ext是你自己可制定的)就重写DataPicker的部分属性; 更严格说,我们是把法语的文字替换掉英语的文字而已。Ext.override的作用是在DatePicker建立实例之前改变class的原型。
应用程序的本地化
我们对范例文件略加修改,把所有的静态文本变为类成员,修改过后看起来是这样的:
2<head>
3 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4 <link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css">
5 <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
6 <script type="text/javascript" src="../ext/ext-all-debug.js"></script>
7
8 <!-- Ext localization javascript -->
9 <script type="text/javascript" id="extlocale"></script>
10
11 <!-- Locale and example extension javascript -->
12 <script type="text/javascript">
13
14 // decode language passed in url
15 var locale = window.location.search
16 ? Ext.urlDecode(window.location.search.substring(1)).locale
17 : ''
18 ;
19
20 // append locale script to the head
21 var head = Ext.fly(document.getElementsByTagName('head')[0]);
22 if(locale) {
23 Ext.fly('extlocale').set({src:'../ext/src/locale/ext-lang-' + locale + '.js'});
24 }
25
26 // create pre-configured example window extension class
27 Ext.ns('Tutorial');
28 Tutorial.LocalizationWin = Ext.extend(Ext.Window, {
29 titleText:'Localization Example'
30 ,selectLangText:'Select Language'
31 ,textFieldText:'Text Field'
32 ,dateFieldText:'Date Field'
33 ,initComponent:function() {
34 Ext.apply(this, {
35 width:500
36 ,id:'winid'
37 ,height:300
38 ,layout:'fit'
39 ,border:false
40 ,closable:false
41 ,title:this.titleText
42 ,items:[{
43 xtype:'form'
44 ,frame:true
45 ,defaultType:'textfield'
46 ,items:[{
47 xtype:'combo'
48 ,fieldLabel:this.selectLangText
49 ,name:'locale'
50 ,store:new Ext.data.SimpleStore({
51 id:0
52 ,fields:['file', 'locale']
53 ,data:[
54 ['cs', 'Czech']
55 ,['', 'English']
56 ,['fr', 'French']
57 ,['de', 'German']
58 ,['gr', 'Greece']
59 ,['hu', 'Hungarian']
60 ,['it', 'Italian']
61 ,['ja', 'Japaneese']
62 ,['pl', 'Polish']
63 ,['pt', 'Portugal']
64 ,['ru', 'Russian']
65 ,['sk', 'Slovak']
66 ,['es', 'Spanish']
67 ,['sv_SE', 'Swedish']
68 ,['tr', 'Turkish']
69 ]
70 })
71 ,listeners:{
72 select:{fn:function(combo){
73 window.location.search = '?'
74 + Ext.urlEncode({locale:combo.getValue()})
75 ;
76 }}
77 }
78 ,mode:'local'
79 ,editable:false
80 ,forceSelection:true
81 ,valueField:'file'
82 ,displayField:'locale'
83 ,triggerAction:'all'
84 ,value:locale
85 },{
86 fieldLabel:this.textFieldText
87 ,allowBlank:false
88 },{
89 xtype:'datefield'
90 ,fieldLabel:this.dateFieldText
91 ,allowBlank:false
92 }]
93 }]
94 }); // eo apply
95 Tutorial.LocalizationWin.superclass.initComponent.apply(this, arguments);
96 } // eo function initComponent
97 }); // eo Tutorial.LocalizationWin
98 </script>
99
100 <!-- Application localization javascript -->
101 <script type="text/javascript" id="applocale"></script>
102
103 <!-- Set src for application localization javascript -->
104 <script>
105 if(locale) {
106 Ext.fly('applocale').set({src:'app-lang-' + locale + '.js'});
107 }
108 </script>
109
110 <!-- Main application -->
111 <script type="text/javascript">
112 Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';
113 Ext.onReady(function() {
114 Ext.QuickTips.init();
115 Ext.form.Field.prototype.msgTarget = 'side';
116
117 // create example window
118 var win = new Tutorial.LocalizationWin();
119 win.show();
120 });
121 </script>
122 <title id="title">Localization Example</title>
123</head>
124<body>
125</body>
126</html>
最后一步,我们需要为特定的语种创建程序本地化的文件(翻译,语种)。这里是app-lang-sk.js文件因为我操的是斯洛伐克语的缘故。你可因应你需求的语种去设置(保存html的格式放到同一目录下或修改上面代码的目录):
2 * 斯洛伐克语版的教程之本地化文件
3 */
4if(Tutorial.LocalizationWin) {
5 Ext.override(Tutorial.LocalizationWin, {
6 titleText:'Príklad lokalizácie'
7 ,selectLangText:'Zvoľ jazyk'
8 ,textFieldText:'Textové pole'
9 ,dateFieldText:'Dátumové pole'
10 });
11}
高级提示
请明确,要做Ext程序的本地化需要遵循哪些的原则。关键点在于将所有翻译文本作为公共类的成员出现,重写原先类的prototype的属性
Advanced developers will immediately feel some drawback of having, maintaining and deploying that many localization files especially if they already have a server with some translating infrastructure such as GNU gettext. For these users I would recommend to generate localization files on the fly by the server using gettext as backend.
这种做法最大的好处是可讲翻译文件集中在一块(*.po),客户端和服务端都可以使用。
如果本地化这主题反映还不错的话而读者又非常想进一步了解我会写进阶的Ext本地化。
Enjoy!