项目推广到其它国家的时候要做本地化。关于多语言开发,一搜一大堆,但真正适合自己的很少。.net提供了本地化和国际化的操作,但有些不便利。最近在做项目的时候,遇到了资源国际化的问题。网上有不少的介绍,但很多都是介绍.net是怎么处理的或者如何用.net来处理。后来根据.net里面的设计思想进行了改进,很好的解决了问题。大致介绍一下。
项目推广到其它国家的时候要做本地化。.net提供了本地化和国际化的操作,但有些不便利。最近在做项目的时候,遇到了资源国际化的问题。网上有不少的介绍,但很多都是介绍.net是怎么处理的或者如何用.net来处理。后来根据.net里面的设计思想进行了改进,很好的解决了问题。大致介绍一下。
在.net中,提供了对资源文件供操作(较早的是resouce格式,现都是resx格式)。resx格式的资源简化了开发,但实际是与操作resource一样的(有兴趣可看下.net对resx操作的大致情况,就会知道两者间的联系)。多语言的资源根据不同的语言进行了命名,resourcefile.language.resx。根据不同的语言加载对应的资源文件进行解析(它提供了culture类)。
借鉴这一思想,增加xml作为资源存储文件,最终发布的时候可将xml做处理,如加密等。文件的命名同上filename.language.xml,设置culture,根据不同的culture加载不同的xml资源文件,然后进行解析。
在项目中已经使用了,这里贴一下代码(C#):
访问接口:
ResourceManager
1namespace MultiLanguage{
2 static UnKnowInforManage m_unKnowMan = null;
3 public string GetItemValueOfUnKnownXml(string xmlFile, string item)
4 {
5 if (!isLastProccessedXml(xmlFile))
6 recordLastProccessdXml(xmlFile);
7
8 if (m_unKnowMan == null)
9 m_unKnowMan = new UnKnowInforManage(xmlFile);
10
11 return m_unKnowMan.GetItem(item);
12 }
13
14 /**//// <summary>
15 /// 纪录上一次处理的信息
16 /// </summary>
17 /// <param name="xmlFile"></param>
18 void recordLastProccessdXml(string xmlFile)
19 {
20 m_lastUnKnowXml = xmlFile;
21 m_unKnowMan = new UnKnowInforManage(xmlFile);
22 }
23
24 /**//// <summary>
25 /// 本次要处理的文件是不是已经处理过
26 /// </summary>
27 /// <param name="xmlFile"></param>
28 /// <returns></returns>
29 bool isLastProccessedXml(string xmlFile)
30 {
31 return string.Compare(m_lastUnKnowXml, xmlFile, true) == 0;
32 }
33
34 string m_unKnowXml;
35 string m_lastUnKnowXml;//上一次使用的未知xml,用于与下一次要访问的xml文件比较,如果相同,不用进行解析
36 public void SetDefaultUnKnowXmlPath(string xmlFile)
37 {
38 xmlFile=FormatXmlFile( xmlFile);
39 m_unKnowXml =xmlFile;
40 recordLastProccessdXml(xmlFile);
41 }
42
43 bool isSetUnKnowXml()
44 {
45 return !string.IsNullOrEmpty(m_unKnowXml);
46 }
47
48 public string GetItemValueOfUnKnownXml(string item)
49 {
50 if (!isSetUnKnowXml())
51 throw (new Exception("没有设置要解析的xml文件,先调用SetDefaultUnKnowXmlPath(string xmlFile)设置文件路径"));
52 return GetItemValueOfUnKnownXml(m_unKnowXml, item);
53 }
54
55 string FormatXmlFile(string xmlFileName) {
56 System.Text.RegularExpressions.Regex regx = new System.Text.RegularExpressions.Regex(@".*(\.xml)$");
57 if (regx.IsMatch(xmlFileName))
58 return xmlFileName;
59
60 return string.Format("{0}Resources\\{2}.{1}.xml", System.AppDomain.CurrentDomain.BaseDirectory, _culture.Name,xmlFileName);
61 }
62}
资源操作类,对资源文件进行解析:
ResourceParse
1 /**//// <summary>
2 /// 未知文件的处理(不知道里面的节点信息),但必需是xml格式
3 /// 暂不能处理同名不同根的节点,同名不同根的节点须传入完整路径的节点
4 /// author:胡艳波
5 /// time:2008/10/15
6 /// </summary>
7 public class UnKnowInforManage
8 {
9 string m_file,m_culture;
10 static Dictionary<string, string> ItemsZh=null,ItemsEn=null;
11
12 public UnKnowInforManage(string xmlFile) {
13 m_file = xmlFile;
14 m_culture = CommonUtil.getCultureNameByFile(xmlFile);
15 }
16
17 /**//// <summary>
18 /// 可传入带父级的节点,即完整路径,或者直接传入节点名称
19 /// 传入节点即可,不传入父级及以上的节点,如root/a/b/c,取c的值只需传入c
20 /// 暂不能处理同名不同根的节点,同名不同根的节点须传入完整路径的节点
21 /// </summary>
22 /// <param name="item"></param>
23 /// <returns></returns>
24 public string GetItem(string item) {
25 string result=string.Empty;
26 if (string.Compare(m_culture, "zh-CN", true) == 0)
27 {
28 if (ItemsZh == null)
29 {
30 UnKnowInfor infor = new UnKnowInfor(m_file);
31 ItemsZh = infor.GetItems();
32 }
33 result = getValue(ItemsZh, item);
34 }
35
36 else
37 {
38 if (string.Compare(m_culture, "en-US", true) == 0)
39 {
40 if (ItemsEn == null)
41 {
42 UnKnowInfor infor = new UnKnowInfor(m_file);
43 ItemsEn = infor.GetItems();
44 }
45 result = getValue(ItemsEn, item);
46 }
47
48 else {
49 UnKnowInfor infor = new UnKnowInfor(m_file);
50 result = getValue(infor.GetItems(),item);
51 }
52 }
53 return result;
54 }
55
56 /**//// <summary>
57 /// 使用dictionary处理的原因:为处理不确定层次及节点信息的xml,支持使用完整路径和只提供节点名称的方式
58 /// </summary>
59 /// <param name="dic"></param>
60 /// <param name="key"></param>
61 /// <returns></returns>
62 string getValue(Dictionary<string,string> dic,string key) {
63 string result;
64 //是否是带父级的节点
65 if (key.IndexOf("/") >= 0)
66 {
67 UnKnowInfor infor = new UnKnowInfor(m_file);
68 result = infor.GetItemValue(key);
69 }
70 else
71 dic.TryGetValue(key, out result);
72 return result;
73 }
74 }
通过ResouceManger对象进行访问,先设置文件路径。为简化操作,在访问的时候,提供文件的filename,由程序根据当前的语言文化形成完整的文件路径。如传入filename,假设当前是en-us,最终形成的解析文件就是appdomain/Resources/filename.en-us.xml,如果是简体中文,要解析的就是appdomain/Resources/filename.zh-CN.xml。
利用这一思想,可很方便进行修改。但缺点就是不能对图片等文件隐藏,只能纪录文本信息,这也是由xml特性决定的。利用resx则可以对图片、声音等处理,在编译的时候设置embed。resx+xml很好的解决了这一问题。其它语言开发,也可以采用这一思想。
ps:当时做多语言开发的时候,很自然的想到已经有不少方案了,于是上网一搜,太多太多,但都不适合。后来索性好好的看看.net是怎么处理的,毕竟ms这方面已经做了不少工作,看看它的处理。后来终于搞定。