设为首页
加入收藏
站内地图
旧版入口
当前位置:首页 > 站长学院 > 网络编程 > ASP.NET

解析Asp.net中资源本地化的实现 1

作者:佚名 出处:网络转载 时间:11-29 点击:

内容载入中...
     本文将从ASP.net实现资源全球化和本地化的基本概念入手,阐述在ASP.net1.1和ASP.net2.0中实现全球化和本地化的步骤、方法。
  
  一.基本概念
  
  1.为什么要实现资源的本地化?
  
   我们的站点可能为全球各个国家和地区的人所浏览,每个国家和地区的人都有自身的语言文化特点。就拿咱们伟大的祖国为例,中国大陆用简体中文,港澳台则使用繁体中文。另外各个国家对于货币、数字、日历等信息的表达格式各有不同,我们国家多使用年月日的格式,而美国则是月日年。诸如此类的区别林林总总,我也就不多举例了。为了给我们的网站浏览者更好的用户体验,我们应该提供一个全球化的解决方案,只要用户选择了他的语言和区域,站点就按照他的语言文化习惯来展现页面信息,这个过程可以叫做本地化。
  
  2.区域性、固定区域性、非特定区域性、特定区域性
  
   区域性名称遵循 RFC 1766 标准,格式为“<languagecode2>-<country/regioncode2>”,其中 <languagecode2> 是从 ISO 639-1 派生的由两个小写字母构成的代码,<country/regioncode2> 是从 ISO 3166 派生的由两个大写字母构成的代码。例如,美国英语为“en-US”。在双字母语言代码不可用的情况中,将使用从 ISO 639-2 派生的三字母代码;例如,三字母代码“div”用于使用 Dhivehi 语言的区域。某些区域性名称带有指定书写符号的后缀;例如“-Cyrl”指定西里尔语书写符号,“-Latn”指定拉丁语书写符号。举例:
  区域性名称
   区域性标识符
   语言-国家/地区
  
  zh-CN
   0x0804
   中文-中国
  
  zh-TW
   0x0404
   中文-台湾
  
  zh-CHS
   0x0004
   简体中文
  
  zh-CHT
   0x7C04
   繁体中文
  
  en
   0x0009
   英语
  
  en-US
   0x0409
   英语-美国
  
  en-GB
   0x0809
   英语-英国
  
  uz-UZ-Cyrl
   0x0843
   乌兹别克语(西里尔语)- 乌兹别克斯坦
  
  uz-UZ-Latn
   0x0443
   乌兹别克语(拉丁)- 乌兹别克斯坦
  
  
  
   固定区域性不区分区域性。可以使用空字符串 ("") 按名称或者按区域性标识符 0x007F 来指定固定区域性。固定区域性由CultureInfo类的InvariantCulture属性来代表固定区域性的实例。固定区域性仅与英语语言关联,不与任何国家/地区关联。它几乎可用在要求区域性的“全局化”命名空间中的所有方法中。如果你的程序进行字符串比较或大小写更改操作,则应该使用 InvariantCulture 确保无论系统如何设置的区域性,行为都将按照InvariantCulture所代表的英语语言的固定区域性来完成。但是,固定区域性必须仅由需要不依赖区域性的结果的进程(如系统服务)使用;否则,它得到的结果可能在语言上不正确,或者在文化上不合适。举例:CultureInfo Invc = New CultureInfo("");
  CultureInfo Invc = CultureInfo.InvariantCulture;这两行代码的作用相同,目的是获得固定区域性实例。
  
   比如你现在要对一个DateTime的实例dateTime执行dateTime.ToString()方法。这个方法实际是使用你当前线程的CurrentCulture作为默认的区域性,根据这个区域性将日期实例转化为相应的字符串形式。那么如果我们此时不需要它按照线程或系统的区域性进行ToString操作,那么我们应该用这个方法dateTime.ToString(“G”, CultureInfo.InvariantCulture)或者dateTime.ToString(“G”, DateTimeFormatInfo.InvariantInfo)。
  
   非特定区域性是与某种语言关联但不与国家/地区关联的区域性。特定区域性是与某种语言和某个国家/地区关联的区域性。例如,“en”是非特定区域性,而“en-US”是特定区域性。注意,“zh-CHS”(简体中文)和“zh-CHT”(繁体中文)均为非特定区域性。
  
   区域性有层次结构,即特定区域性的父级是非特定区域性,而非特定区域性的父级是 InvariantCulture。CultureInfo类的Parent属性将返回与特定区域性关联的非特定区域性。如果特定区域性的资源在系统中不存在,或因其它原因不可用,则使用非特定区域性的资源;如果非特定区域性的资源也不可用,那么使用主程序集中嵌入的资源。
  
  3.实现本地化常用的类型、属性和方法
  
   CultureInfo类表示有关特定区域性的信息,包括区域性的名称、书写体系和使用的日历,以及有关对常用操作(如格式化日期和排序字符串)提供信息的区域性特定对象的访问。CultureInfo类的实例化一般有两个途径,如下所示:
  CultureInfo culture = CultureInfo. CreateSpecificCulture (name);
  CultureInfo culture = new CultureInfo(name);
  
   二者的区别是,使用第一种方法,只能创建固定区域性或特定区域性的CultureInfo实例。如果name为空字符串,则建立固定区域性的实例,如果name为非特定区域性,那么建立name 关联的默认特定区域性的 CultureInfo实例。第二种方法,则是建立一个name所指定的区域性的CultureInfo实例,它可以是固定的,非特定的或特定区域性的。
  
   Thread类的CurrentCulture属性用来获取或设置当前线程的区域性。它必须被设置为特定区域性。Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");如果Thread.CurrentThread.CurrentCulture = new CultureInfo("en ");就会报错!
  
   Thread类的CurrentUICulture属性用来获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。这里的资源管理器可以关联为ResourceManger类。
  Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
  Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
  
   ResourceManger类可以查找区域性特定的资源,当本地化资源不存在时提供代用资源,并支持资源序列化。常用的ResourceManager的构造函数是public ResourceManager(string,Assembly)。其含义是初始化 ResourceManager类的新实例,它使用指定的根名称从给定的Assembly中查找资源文件。所谓根名称是例如名为“MyResource.en-US.resources”的资源文件的根名称为“MyResource”。在根名称的表达中可以加上命名空间,如“MyWebSite.Resource.UserFolder. MyResource”。而Assembly可以是需要调用资源文件的页面所在的Assembly,如typeof(MyPage).Assembly。ResourceManager类的GetString方法用来获得资源文件中的指定键的值。举例:当已设置了线程的CurrentUICulture属性之后按如下方法。
  ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly());
  String str = rm.GetString("welcome");
  
  如果想按照指定的区域性来获得资源则按照如下写法:
  ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly());
  CultureInfo ci = Thread.CurrentThread.CurrentCulture;
  String str = rm.GetString("welcome",ci);
  
  
  二.在ASP.net1.1中实现资源本地化
  
   首先应在网站项目WebTest中建立一个Resource文件夹,在这个文件夹中存放整个项目公用的资源文件。比如我们建立了以下三个资源文件:MyResource.en.resx,MyResource.en-US.resx,MyResource.zh-CN.res。每个资源文件中都有两个键值对,键值为State和Address。在需要使用资源文件的页面MyPage.ASPx中调用资源文件,如下所示:
  Thread.CurrentThread.CurrentCulture= CultureInfo.CreateSpecificCulture("zh-CN");
  Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
  ResourceManager rm = new ResourceManager("WebTest.Resource.MyResource", typeof (MyPage).Assembly);
  Label1.Text = rm.GetString("State");
  Label2.Text = rm.GetString("Address");
  
  好了,这个时候Label1和Label2就按照MyResource.zh-CN.resx文件中的规定显示“州”和“地址”。以上是一个最基本最简单的本地化方法,这里隐含着一些问题,我们来逐一解决并优化该方法。
  
  1. 如何获得用户的默认区域性
  
   通过用户浏览器“属性”->“语言”选项里的设置,取最上面那条作为用户的默认语言。
  CultureInfo cultureInfo = CultureInfo.CreateSpecificCulture(Request.UserLanguages[0]);
  Thread.CurrentThread.CurrentCulture = cultureInfo;
  Thread.CurrentThread.CurrentUICulture = cultureInfo;
  
   一般情况下,设定CurrentCulture和CurrentUICulture具有相同的区域性,当然也可以不相同,比如你规定CurrentCulture为en-US,而CurrentUICulture为zh-CN。那么这样造成的效果是,页面中货币、日期等信息都按照美国英语的格式显示,而需要从资源文件中取值的内容,资源管理器会从MyResource.zh-CN.resx文件里获得。
  
   如果你的站点页面上并没有提供让用户选择语言的功能,那么也就是默认按照用户浏览器设置的区域性进行显示,因此你就可以把上述代码放在Global.asax.cs文件的Application_BeginRequest方法中。这样每次用户对页面发出请求时,我们的程序都会首先进行区域性设置。
  
  2. 记住用户的区域性设置
  
   通过会话可以记住浏览者的区域性设置或选择。但是这个操作不能在Global.asax.cs文件中Application_BeginRequest方法中进行,因为那时会话还处于不可用状态。如果你的站点并没有提供让用户选择语言的功能,那么你也没什么必要记住用户的区域性设置,只要按照上面介绍的在Global.asax.cs文件中Application_BeginRequest方法里设置一下就可以了,不影响性能。这主要可以避免用户在中途突然改变了浏览器中语言的设置,而网站仍按照会话中存储的区域性为用户显示页面内容的冲突。
  
   如果你提过了让用户选择语言的功能,那显然要在页面程序中使用会话来记录用户的区域性选择。因为从客户端到服务器段的每次请求,服务器段都会开启一个新的线程进行处理和响应。如果你的程序没有记住客户的选择,那么只能按照默认的区域性进行响应。
  
  3. 资源管理器如何查找指定区域性的相应资源文件?
  
   在执行取值操作时,也就是执行ResourceManager类的GetString方法时,资源管理器会按照当前线程的CurrentUICulture属性去寻找相对应的资源文件。有如下几种情况:
  (1). 比如当前CurrentUICulture对应的区域性是en-US,那么首先找MyResource.en-US.resx是否存在,如存在则从中取值;如不存在,则看MyResource.en.resx是否存在。
  (2). 比如当前CurrentUICulture对应的区域性是en,因为en是非特定区域性的,那么首先找其默认关联的特定区域性en-US的资源文件MyResource.en-US.resx是否存在,如存在则从中取值;如不存在,则看MyResource.en.resx是否存在。
  (3). 比如当前CurrentUICulture对应的区域性是en-GB,那么首先找资源文件MyResource.en-GB.resx,如不存在,则看MyResource.en.resx是否存在,如存在则从中取值;如也不存在,则看en关联的默认特定区域性en-US的资源文件MyResource.en-US.resx是否存在,如果此时MyResource.en-US.resx不存在,但是MyResource.en-CA.resx存在,则程序依然会抛出找不到合适资源文件的异常。
  
   因此我们可以总结一下,当前线程CurrentUICulture对应的是特定区域性时,资源管理器优先查找此特定区域性对应的资源文件,如果没找到,则去找其非特定区域性的资源文件,如果还没找到,再去找其非特定区域性关联的默认区域性的资源文件。当前线程CurrentUICulture对应的是非特定区域性时,资源管理器优先查找此非特定区域性对应的默认特定区域性的资源文件是否存在,如果不存在,则去看此非特定区域性对应的资源文件是否存在,如果也不存在则抛出异常。
  
  4.如何处理未提供本地化支持的区域性?
  
   如果站点没有提供相应的资源文件支持用户默认的区域性,那么必须将其当前线程的CurrentUICulture转化为你站点默认的区域性,比如en-US或zh-CN。转化的时机有两个:
  一是当你在获得Request.UserLanguages[0]时,用其与配置文件中预先设定的被支持的区域性进行比较,如果确认其为不被支持的,那么立刻设置CurrentUICulture为默认区域性。
  二是在使用ResourceManager的GetString方法进行取值的时候,使用try catch结构,捕获MissingManifestResourceException异常,在异常处理中,首先将CurrentUICulture设为默认区域性,之后再重新使用GetString取值。
  
  5. 通过Web.config设定站点默认的culture和uiCulture
  
   <globalization requestEncoding="utf-8" responseEncoding="utf-8" uiCulture="zh-CN" culture="en-US"/>
  如上所示:规定站点的默认culture为en-US(此处必须为特定区域性),uiCulture为zh-CN。
  
   当然你也可以在每个页面的Page标签中进行逐页设定:<@Page Culture=“zh-CN” UICulture=“en”>。这里就不管web.config是如何设置的,页面会按照Page标签的设定进行显示。
  
  
    。

收藏本文:
】【打印页面】【推荐给朋友】【关闭窗口

站长学院

推荐信息