项目推广到其它国家的时候要做本地化。关于多语言开发,一搜一大堆,但真正适合自己的很少。.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#):
访问接口:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
ResourceManager
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
namespace MultiLanguage
{
2
static UnKnowInforManage m_unKnowMan = null;
3
public string GetItemValueOfUnKnownXml(string xmlFile, string item)
4![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
5
if (!isLastProccessedXml(xmlFile))
6
recordLastProccessdXml(xmlFile);
7![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
if (m_unKnowMan == null)
9
m_unKnowMan = new UnKnowInforManage(xmlFile);
10![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
return m_unKnowMan.GetItem(item);
12
}
13![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
15
/// 纪录上一次处理的信息
16
/// </summary>
17
/// <param name="xmlFile"></param>
18
void recordLastProccessdXml(string xmlFile)
19![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
20
m_lastUnKnowXml = xmlFile;
21
m_unKnowMan = new UnKnowInforManage(xmlFile);
22
}
23![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
24![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
25
/// 本次要处理的文件是不是已经处理过
26
/// </summary>
27
/// <param name="xmlFile"></param>
28
/// <returns></returns>
29
bool isLastProccessedXml(string xmlFile)
30![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
31
return string.Compare(m_lastUnKnowXml, xmlFile, true) == 0;
32
}
33![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
34
string m_unKnowXml;
35
string m_lastUnKnowXml;//上一次使用的未知xml,用于与下一次要访问的xml文件比较,如果相同,不用进行解析
36
public void SetDefaultUnKnowXmlPath(string xmlFile)
37![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
xmlFile=FormatXmlFile( xmlFile);
39
m_unKnowXml =xmlFile;
40
recordLastProccessdXml(xmlFile);
41
}
42![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
43
bool isSetUnKnowXml()
44![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
45
return !string.IsNullOrEmpty(m_unKnowXml);
46
}
47![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
48
public string GetItemValueOfUnKnownXml(string item)
49![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
50
if (!isSetUnKnowXml())
51
throw (new Exception("没有设置要解析的xml文件,先调用SetDefaultUnKnowXmlPath(string xmlFile)设置文件路径"));
52
return GetItemValueOfUnKnownXml(m_unKnowXml, item);
53
}
54![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
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
}
资源操作类,对资源文件进行解析:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
ResourceParse
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
/**//// <summary>
2
/// 未知文件的处理(不知道里面的节点信息),但必需是xml格式
3
/// 暂不能处理同名不同根的节点,同名不同根的节点须传入完整路径的节点
4
/// author:胡艳波
5
/// time:2008/10/15
6
/// </summary>
7
public class UnKnowInforManage
8![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
9
string m_file,m_culture;
10
static Dictionary<string, string> ItemsZh=null,ItemsEn=null;
11![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public UnKnowInforManage(string xmlFile)
{
13
m_file = xmlFile;
14
m_culture = CommonUtil.getCultureNameByFile(xmlFile);
15
}
16![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
18
/// 可传入带父级的节点,即完整路径,或者直接传入节点名称
19
/// 传入节点即可,不传入父级及以上的节点,如root/a/b/c,取c的值只需传入c
20
/// 暂不能处理同名不同根的节点,同名不同根的节点须传入完整路径的节点
21
/// </summary>
22
/// <param name="item"></param>
23
/// <returns></returns>
24![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string GetItem(string item)
{
25
string result=string.Empty;
26
if (string.Compare(m_culture, "zh-CN", true) == 0)
27![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
28
if (ItemsZh == null)
29![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
30
UnKnowInfor infor = new UnKnowInfor(m_file);
31
ItemsZh = infor.GetItems();
32
}
33
result = getValue(ItemsZh, item);
34
}
35![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
36
else
37![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
38
if (string.Compare(m_culture, "en-US", true) == 0)
39![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
40
if (ItemsEn == null)
41![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
42
UnKnowInfor infor = new UnKnowInfor(m_file);
43
ItemsEn = infor.GetItems();
44
}
45
result = getValue(ItemsEn, item);
46
}
47![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
48![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
49
UnKnowInfor infor = new UnKnowInfor(m_file);
50
result = getValue(infor.GetItems(),item);
51
}
52
}
53
return result;
54
}
55![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
56![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
57
/// 使用dictionary处理的原因:为处理不确定层次及节点信息的xml,支持使用完整路径和只提供节点名称的方式
58
/// </summary>
59
/// <param name="dic"></param>
60
/// <param name="key"></param>
61
/// <returns></returns>
62![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
string getValue(Dictionary<string,string> dic,string key)
{
63
string result;
64
//是否是带父级的节点
65
if (key.IndexOf("/") >= 0)
66![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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这方面已经做了不少工作,看看它的处理。后来终于搞定。