自从 10 年前出现 Internet 以来,企业团体已不断地开拓国际化的市场。企业不仅通过自己的 Web 站点拥有了全球化的网络呈现方式,而且越来越多的企业也正在发布和/或许可企业级 Web 应用程序以便最终能向全世界的客户提供服务。由于大多数客户喜欢在本国语言和环境下开展业务,因此有必要准备本地化的 Web 站点和应用程序。毫无疑问,不论哪种部署模型(智能客户端、Web 站点和应用程序、Web 服务),具体而言就是体系结构和设计,本地化任务都需要付出时间和精力。有效的开发工具能影响体系结构的好坏,但奇怪的是,对于开发用于 Web 应用程序本地化的工具这一领域而言,仍然进步不足。结果许多企业求助于更传统、更麻烦的本地化方法,而花费了大量时间和金钱。
Microsoft ASP.NET 2.0 版本承诺更好地转变 Web 开发人员实现本地化的方式。通过使用更多 Microsoft Visual Studio .NET 环境内置的工具、新的运行时功能以及一个新的特定于本地化需求的编程 API,开发人员能够更迅速地从 ASP.NET 页面分离可本地化的内容,减少为访问可本地化内容编写的代码,扩展满足额外需求的环境,同时综合利用一个一致的编程模型。本文将带领您体验新改进的准备本地化应用程序的 ASP.NET 开发。
使用 .NET 1.x 进行本地化
.NET Framework 1.x 引入一个新的本地化体系结构,它提供语言支持的非插入渐进式部署,方法是将其拖放到新的附属程序集(或只含资源程序集)中。这种轮辐式部署范例允许开发人员依靠公共语言运行库来管理通过 ResourceManager 类精确选择的可本地化内容。ResourceManager 的一个优点是它与一个封装的资源回调机制进行交互,根据应用程序的运行时语言设置查找最合适语言,因此加载每个 ResourceSet 来检索可本地化内容的过程无需开发人员编写代码进行管理。
Windows 或 Web 应用程序可以使用资源来本地化 Windows 窗体,但是 Visual Studio 2003 使 Windows 开发人员本地化 Windows 窗体的工作变得更加容易。当一个窗体的 Localizable 属性设置为 true 时,则用于可本地化的 form 和 control 属性的资源将自动生成。属性值被压入默认资源以备后来进行翻译,通过这些资源,生成的代码在运行时使用 ResourceManager 类的实例填充控件。ResourceManager 先考虑正在执行线程的 CurrentUICulture 设置,然后尝试在 ResourceSet 中查找匹配语言的资源,最后求助于资源的回调过程。
注 请在此处阅读有关资源回调过程的信息。
.NET Framework 也包含许多与语言有关的类,在生成诸如格式化日期、时间和货币值等输出结果时考虑 CurrentUICulture,从而进一步减少开发人员所需的工作量。
注 请从 MSDN 参考资源中阅读与语言有关的类的更多信息。
尽管附属程序集的部署模型、资源管理器以及与语言有关的类也能应用于 ASP.NET 应用程序,可是缺少供开发人员使用的工具将这个模型集成到 Web 窗体的编程范例中。目前,为 Web 页面生成资源实体、在运行时访问这些资源以及为每个请求设置正确的语言需要人工完成。因此 Web 应用程序本地化没有过多考虑将资源作为一个集成部分。本地化 Web 内容传统上造成了重复整个特定语言的网站,从而就地本地化静态内容以及为任何共享代码编写自定义代码来管理本地化数据源的检索。ASP.NET 2.0 极大地改进了该方法。
注 后面的 MSDN 文章讨论用于 ASP.NET 1.1 本地化的结构化方法。
ASP.NET 2.0 新本地化功能简介
ASP.NET 2.0 在 .NET 1.x 本地化功能的基础上构建,专门改进了工作流和 Web 开发人员可用的功能。下面总结了促进下一代本地化支持的设计目标:
• | 为 Web 应用程序提供支持资源生成的工具。 |
• | 为资源访问提供新的声明性和运行时编程构造。 |
• | 简化对页面请求应用正确语言和自动实例化 ResourceManager 的过程。 |
• | 支持 XCOPY 部署和小型商业网站的编译步骤移除。 |
• | 支持具有使用和管理各方面资源的可扩展性的企业级开发版. |
• | 确保 ASP.NET 控件和其他可应用性运行时组件和适配器集成式地支持新本地化功能。 |
Visual Studio 2005 和 ASP.NET 2.0 集成的新功能确保能简化 Web 应用程序本地化,它提供工具从 Web 页面提取可本地化内容,为补充无状态请求模型的资源使用提供集成的运行时支持,通过先进的声明性构造将资源绑定到页面输出,为往返过程提供自动选择语言的新方法。下面的功能专门用于支持这些目标:
Strongly Typed Resources — 处于 .NET Framework 2.0 版本核心地位的是强类型资源支持,它为开发人员提供智能感知,从而简化运行时访问资源所需的代码。
Managed Resource Editor — Visual Studio .NET 2.0 包含一个新的资源编辑器,用于更好地创建和管理资源实例,例如字符串、图像、外部文件和其他复杂类型等等。
Resource Generationfor Web Forms — Windows 窗体开发人员已经受益于自动的国际化。现在,Visual Studio 2005 将支持快速的国际化,自动生成 Web 窗体、用户控件和主页面的资源。
Improved Runtime Support — ResourceManager 实例由运行时管理,服务器代码可通过更多可访问的编程接口轻松访问它。
Localization Expressions — 用于 Web 页面的先进声明性表达式将资源实体映射到控件属性、HTML 属性或静态的内容区域。这些表达式也可扩展,从而提供了其他方法来控制将本地化内容添加到 HTML 输出的过程。
Automatic Culture Selection — 每次 Web 请求的语言选择能够自动连接到浏览器偏爱来管理。
Resource Provider Model — 一个新的资源提供程序模型允许开发人员发布可选数据源(例如,平面文件和数据库表格)的资源,而访问这些资源的编程模型保持一致。
这些灵活的功能足以为亟需可靠且有效的解决方案的小型企业提供出盒支持,还仍然以附加的可扩展性满足大型组织应用多种部署体系结构的复杂需求。改进的新模型综合利用了 Web 应用程序的资源,联合了 Windows 窗体编程模型,还考虑了开发周期和 Web 的运行时需求。以下各部分内容详细介绍了在 Beta 1 版本中实现的这些新功能,也评论了期望在 Beta 2 版本中实现的改进。
生成本地资源
.NET 资源实现了为特定语言和语言区域选择性地替换内容,因此同一个代码基能够支持多种语言。然而,为 Web 页面生成资源需要大量的人工劳动,因此很难调动开发人员为 Web 应用程序使用这种方法的积极性。ASP.NET 2.0 提供一种简单的方法为 Web 页面自动生成资源,同时支持各种复杂的内容代理,包括 HTML 元素和属性、静态内容和服务器控件。
为特定的 Web 窗体生成资源,需要从 Visual Studio 2005 的“Tools”菜单选择 Generate Local Resource,然后为 Design View 中打开的任何页面(包括 Web 窗体、用户控件和主页面)创建本地资源。这个步骤自动生成一组页面的默认 .NET XML 资源,将其放置在为本地资源建立的名为 /LocalResources 的专用子目录下(在 Beta 2 中此目录名将改变)。
图 1. Web 窗体、用户控件和主页面能在 Visual Studio .NET 2.0 内部国际化。这个特定视图显示为一些页面生成的默认资源。
本地资源存储在 .resx 文件中,文件的命名规则对应本地资源所服务的页面(参见图 1)。例如,为名为 site.master 的主页面生成资源后,新的名为 site.master.resx 的 .resx 文件出现在 /LocalResources 中。对于名为 default.aspx 的 Web 窗体而言,生成的资源存储在名为 default.aspx.resx 的文件中。
Visual Studio 设计器检查页面和它的控件(ASP.NET 服务器控件、自定义控件和设置为 runat="server" 的 HTML 控件)— 查找标记为 LocalizableAttribute 的属性 — 并填充这些资源:
[Localizable(true)] public virtual string Text { get {...} set {...} }
每个控件的可本地化属性自动压入资源,以关键字唯一标识每个属性。关键字包含一个标识页面控件名和属性名的前缀。除非在控件声明中指定属性值,否则每个属性值均设置为控件的默认值。下列 LinkButton 声明为 PostBackUrl 和 Text 属性指定了一个值:
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server">Change Selected Culture</asp:LinkButton>
图 2 显示的是为宿主页面生成本地资源后,为 LinkButton 生成的资源(参见示例项目中的 cultureinfo.ascx)。资源存储在资源文件中(参见 cultureinfo.ascx.resx),默认情况下排除诸如 PostBackUrl 这样的非可本地化属性。
图 2. 为 ASP.NET 服务器控件、自定义服务器控件和服务器端运行 (runat=“server”) 的 HTML 控件的可本地化属性生成本地资源。
生成资源时,控件声明也被修改,以便声明性地使属性与资源实体相关联。一些新的声明性表达式也为页面解析器所识别,它们触发代码生成,在运行时使用资源值填充控件属性。声明性本地化表达式是 ASP.NET 2.0 的一种新构造,类似数据绑定语句,是为访问资源而专门设计的。这些表达式具有两种形式:隐式和显示。隐式表达式在本地资源生成时自动插入,而且支持在单个声明语句中将多个资源实体映射到一组控件属性中。显式表达式是开发人员添加的用于进一步控制页面本地化的声明。
下列由 meta:resourcekey 标识的隐式表达式是为 LinkButton 声明而生成的,现在,它为这个控件设置了资源关键字前缀:
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server" meta:resourcekey="LinkButtonResource1"> Change Selected Culture</asp:LinkButton>
控件属性的资源实体使用这个前缀后,运行时将自动映射到正确的控件属性。控件声明中的每个属性值保持原封不动,其中也包括那些压入资源的值。这些默认值将出现在 Design View 中,为页面内的控件提供上下文。解析页面时,本地化表达式生成的代码将资源应用到控件属性。开发人员无需编写代码将 ResourceManager 实例化,以便在运行时访问这些本地资源。
运行时资源值优先,无资源值时由默认值代替。这对 Web 开发人员而言非常有用,因为在站点部署完成之前,他们就可以查看页面内容。在 Properties Window 中,本地化后的内容由特殊图标进行标记,表示它们的值是从资源中提取的。图 3 显示一个 ASP.NET ImageButton 控件,其中一些属性绑定到共享资源(以蓝色标识),另一些绑定到本地资源(以红色标识)。使用表达式绑定属性的内容将在后面部分深入讨论。
图 3. 在 Properties Window 视图中,很容易定位由特殊图标标识的本地化内容。
到目前为止,讨论的焦点是生成本地资源。默认情况下,它既为可本地化控件属性生成隐式本地化表达式和资源,也将属性绑定到共享应用程序资源。此外,它也可能为非可本地化控件属性、其他 HTML 元素和静态内容自动生成本地资源。将显式本地化表达式应用到这些页面和控件元素就可以实现。换句话说,开发人员能够声明性地标识出需要本地化的内容,以便页面的资源生成中包含这些内容或选择性地从替代源中提取。
共享的应用程序资源
为每个页面自动生成本地资源会造成实体重复和多余的翻译工作。幸运的是,ASP.NET 2.0 内部拥有一个为主页面和用户控件建立的重用模型,它支持标题、菜单、提要栏以及 HTML 其他部分在 Web 窗体间共享。每个主页面、用户控件和 Web 窗体拥有自己的本地资源集合,这样就减少了资源重复。而且,在所有页面之间进行合并和共享时,资源实体,例如词条、错误信息和功能驱动程序(例如,方向属性)将非常有用。
每个页面的本地资源通过设计器自动生成,而共享的应用程序资源则需要手动创建。这就意味着将一个新的应用程序资源添加到解决方案中,将其放置在为共享资源指定的名为 /Resources 的专用目录下(在 Beta 2 中此目录将更改)。这与 1.x 应用程序生成共享资源的方法一致,然而,新的资源编辑器简化了创建和编辑资源实体,共享资源通过智能感知支持进行了强类型化。共享资源也参与新页面的解析和 ASP.NET 2.0 的运行时模型。它们能够通过显式本地化表达式绑定到页面,这时,ResourceManager 自动进行实例化和缓存,开发人员不必管理运行时访问资源的生命周期。
图 2 和 图 4. 显示 Visual Studio 2005 的一个新 Managed Resource Editor。图 2 是资源字符串编辑器,它与 Visual Studio 中的资源编辑器相似。图 4 说明了编辑器支持的预定义资源种类列表,包括字符串、图标、其他图像文件类型、音频文件类型以及含 XML 的其他文件。除了资源编辑器支持的这些预定义类型,以编程方式将其他复杂类型插入资源也是可能实现的。这时,基础资源文件是基于 XML 的。
图 4. 新 Managed Resource Editor 集成支持多种预定义数据类型,提供替换视图,此处显示的是 Images 资源种类的缩略图。
通过编辑器插入的基于文件的资源(例如,图像、声音和 XML 文件),在默认情况下定义为 ResxFileRef 实体。例如,下列代码分别为一个外部图像和一个 XML 文件创建资源实体:
<data name="Spain" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>../Images/Spain.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> <data name="supportedCultures" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>../Xml/supportedCultures.xml;System.String, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;iso-8859-1</value> </data>
资源编译器解析每个文件引用,运行时将引用的文件载入流,并将其转换成正确的数据类型。图像转换后的类型是 System.Drawing.Bitmap,而 XML 默认情况下返回 System.String 类型。对于预编译的 Web 应用程序而言,资源是嵌入到输出程序集中的。这意味着实际文件无需与网站一起部署。资源和相关文件也能够部署为完整运行时编译,这与 ASP.NET 2.0 的新编译模型一致(有关更多信息,请参见本文)。
共享资源最显著的优点是编译后的强类型类使资源关键字能够直接访问实体。例如,名为 Flags.resx 的共享应用程序资源以运行时类型 Resources.Flags 来访问。内部的 Resources 类型都支持智能感知,如果类型转换器可用,则资源项将以本机数据类型返回。图 5 所示图像的数据类型是 System.Drawing.Bitmap。
图 5. 共享资源编译到强类型资源中,通过内部的 Resources 对象访问。
基于图像的资源对 Web 控件开发人员而言很有用,因为它能封装控件使用的嵌入式图形。然而,它对 Windows 窗体开发人员而言更有用,开发人员能够很容易地使用二进制图像格式进行显示。总之,强类型资源和智能感知提高了运行时访问资源的效率。例如,图 5 也阐释了一个强类型 Glossary 资源如何使检索命名的字符串值变得更容易。
本地资源和共享资源都能够以声明方式或编程方式访问,以便生成本地化内容。这些技术将在以下部分讨论。
隐式本地化表达式
正如之前提到的,本地资源生成时将触发页面控件声明修改。默认行为是将隐式本地化表达式添加到服务器控件,由解析时属性 meta:resourcekey 表示。
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server" meta:resourcekey="LinkButtonResource1"> Change Culture Settings</asp:LinkButton>
这个表达式为控件属性相关的所有资源实体设置了预期的前缀 —— 因此使用术语隐式表达式。自动的资源生成只考虑可本地化属性,但是实际上任何资源实体,只要使用此前缀加上一个合法的属性名,都能绑定到编译过的页面代码中的该属性。在上面的示例中,LinkButtonResource1 是资源关键字前缀,图 2 显示的资源为应用到同一个控件实例(即 LinkButtonResource1.Text)的所有属性使用了这个前缀。
这条声明性的语句(meta:resourcekey)通知 ASP.NET 页面解析器生成代码,用于从默认本地资源检索属性值。结果代码最终在 GetPageResourceObject(在 Beta 2 中此方法名可能更改)的帮助下使用运行时方法访问资源。在提供的示例代码中,编译的 cultureinfo.ascx 页面使用以下代码来创建和实例化 LinkButton 和 lnkSelectCulture:
LinkButtonbutton1 = new LinkButton(); this.lnkSelectCulture= button1; button1.ID = "lnkSelectCulture"; button1.PostBackUrl= "selectculture.aspx"; button1.AccessKey = ((string) base.GetPageResourceObject("LinkButtonResource1.AccessKey")); button1.SoftkeyLabel = ((string) . base.GetPageResourceObject("LinkButtonResource1.SoftkeyLabel")); button1.Text = ((string) base.GetPageResourceObject("LinkButtonResource1.Text")); button1.ToolTip = ((string) base.GetPageResourceObject("LinkButtonResource1.ToolTip")); button1.Visible = ((bool) base.GetPageResourceObject("LinkButtonResource1.Visible", typeof(Control), "Visible"));
隐式本地化表达式在生成页面资源时应用到所有服务器控件声明。您能够使用下面的替代语法取消这个行为,它指示出该控件不应该进行本地化:
<asp:LinkButton id=lnkSelectCulture PostBackUrl="selectculture.aspx" runat="server" meta:localize="false">Change Culture Settings</asp:LinkButton>
对本地化策略不重要的个别控件属性可以使用图 2 显示的 Managed Resource Editor 手动将其从本地资源中移除。这将减少页面解析器生成的将本地资源实体应用到控件属性的代码数量,因为代码只反映页面的默认本地资源中存在的那些实体。这也意味着添加到本地化资源的附加关键字值在运行时将不会应用,因为没有生成代码来实现这一点。
这类本地化表达式综合利用了与 .NET Framework 2.0 一起发布的新 Expression Builder。隐式本地化表达式从单个声明语句生成代码来填充所有可本地化的服务器控件属性,为开发人员节省了时间。同时也删除了目前 1.x Web 应用程序所需的一个手动步骤,即通常需要自定义数据绑定语句或自定义代码从本地化资源或数据源提取值。下面将预览如何为静态文本和具体控件属性(包括那些没有 LocalizableAttribute 标记的属性)自动生成附加资源。
显式本地化表达式
尽管为可本地化控件属性自动生成资源非常容易,可是开发人员也需要一个支持本地化特定属性值和其他内容块的解决方案。显式本地化表达式以声明方式将特定资源实体分配到服务器控件属性和其他 HTML 元素。例如,下面的 ImageButton 控件声明使用了一个显式表达式来设置 AlternateText 属性:
<asp:ImageButton id="btnIDesign" Runat="server" ImageUrl="~/Images/idesignlogo.jpg" AlternateText='<%$ Resources: MissionStatement %>' PostBackUrl="http://www.idesign.net" />
显式本地化表达式使用以下语法:
<%$ resources: [applicationkey], resourcekey%>
上例省略了 applicationkey,因为 MissionStatement 值从本地资源提取。resourcekey 值标识提取的资源实体,而 default 值表示设计器默认值。设计器默认值仅在设计时存在,供开发人员或 Web 设计者编辑页面布局。
显式表达式也能够通过图 6 所示的“Properties”窗口中的 Expressions 对话框生成。这个对话框支持创建显式表达式值,从而将控件属性绑定到本地资源或共享资源。
图 6. 使用 Expressions 对话框,开发人员能直观地将资源映射到属性,并生成显式本地化表达式。
通过该对话框,开发人员能使用“Properties”窗口创建显式表达式,就像设置其他控件属性一样。如果 Expression Properties 中省略 ClassName(请参见图 6),下拉列表将显示可用的本地资源关键字(假定已经创建了资源)。否则,本地资源对应的显式表达式将生成关键字与 ResourceKey 匹配的本地资源实体。这又一次减少了开发人员在运行时创建资源实体和生成填充属性的代码所需的工作量。
如果访问共享资源,ClassName 应标识全局资源目录下的一个合法资源文件名。与本地资源不同的是,共享资源对应的显式表达式不自动生成这些资源。
隐式和显式本地化表达式能混合使用,以便特定属性从共享资源提取,而其他属性从本地资源提取。下列代码示例显示的是,ImageButton 控件声明从共享资源 (Glossary.resx) 获取 AlternateText 属性,所有其他属性使用隐式表达式语法从本地资源提取:
<asp:ImageButton ID="btnIDesign" Runat="server" ImageUrl="~/Images/idesignlogo.jpg" AlternateText='<%$ Resources:Glossary, MissionSatatement%>' PostBackUrl="http://www.idesign.net" meta:resourcekey="ImageButtonResource1" /></td>
使用显式本地化表达式后,详细控制哪里、哪些属性被本地化将可能实现。对于包含显式和隐式表达式两者的控件声明,页面资源按以下方式生成:
• | 显式表达式绑定的属性,如果指定了一个共享资源,在本地资源生成中将省略。 |
• | 用于本地资源的显式表达式绑定的属性,生成一个 default 值的 resourcekey 入口点。 |
• | 其余未绑定显式表达式的可本地化属性,用控件声明或控件的默认属性值生成一个 resourcekey.propertyname 的入口点。 |
正如之前提到的,页面解析时,声明中的代码自动生成,以便从共享或本地资源提取属性值。在上面的示例代码中,结果代码创建了一个 ImageButton 控件,从 Glossary 共享资源设置 AlternateText 属性,其余可本地化属性通过本地资源设置:
ImageButtonbutton1 = new ImageButton(); // other initialization code button1.ID = "btnIDesign"; button1.AccessKey = (string) base.GetPageResourceObject("ImageButtonResource1.AccessKey"); button1.AlternateText= (string) base.GetAppResourceObject("Glossary", "MissionStatement"); button1.ImageUrl = (string) base.GetPageResourceObject("ImageButtonResource1.ImageUrl"); button1.ToolTip = (string) base.GetPageResourceObject("ImageButtonResource1.ToolTip"); button1.Visible = (bool) base.GetPageResourceObject("ImageButtonResource1.Visible", typeof(Control), "Visible");
本地化 HTML 元素和静态文本
使用隐式和显式本地化表达式,使得为服务器控件属性生成资源变得容易。但是,准备本地化一个页面,也必须考虑诸如 HTML 页标题、方向属性和静态内容等其他内容。本地化表达式也能应用到 @Page 指令和 HTML 其他部分,先于生成页面资源,声明性地标识其他本地化部分。
HTML 控件:
HTML 控件运行在服务器端 (runat="server") 时,才能体现隐式或显式表达式的优点。一旦标记为服务器端控件,将自动生成应用于控件的可本地化属性的本地资源。HTML 服务器控件与 ASP.NET、自定义服务器控件一样,也能绑定到隐式或显式表达式,后者可使用前面提到的 Expressions 对话框生成。
页标头的 HTML 元素也能声明性地绑定到资源,对于页标题和样式表链接,这是有用的。HTML 页标题元素很特殊,因为它也是一个 Page 属性,能通过 @Page 指令设置。默认情况下,本地资源生成时,隐式表达式分配到每个页面:
<%@ Page Language="C#" CodeFile="Default.aspx.cs" Inherits="_Default" meta:resourcekey
这条表达式也可以修改为显式表达式,用于从共享资源(而非本地资源)提取值:
这些表达式都不能覆盖 HTML 标头的 <title> 元素值,但是没有这些值,表达式也能够直接应用到 <title> 元素,下面使用的是显式表达式:
<head runat="server"> <title> <asp:Literal Text='<% $ Resources: Glossary, DefaultPageTitle %>' runat="server"></asp:Literal> </title> </head>
方向属性
改进的方向设置支持是通过新提供的 Direction 属性添加的,这个属性由诸如 <asp:Panel> 一类的控件支持。因为使用一个根据语言标识应用程序的整体方向的共享资源,所以在默认的共享资源中能标识默认的 “LTR” 方向,并依据能够指定 “LTR” 的语言覆盖这个值。
为了控制浏览器滚动条的方向并设置站点的整体方向,下面的显式表达式通过设计器默认值 “LTR” 从共享资源提取正确的值:
<html runat="server" dir='<% $Resources: Common, Direction %>' > ... </html>
panel 也可以用于设置所包含控件的方向:
<asp:panel runat="server" direction='<% Resources: Common, Direction %>'> ... </asp:panel>
有关 Visual Studio .NET 方向支持的更多信息,请访问此站点。
静态文本
本地化表达式用于设置控件属性和其他 HTML 元素;但是,许多要进行本地化的 Web 页面已经包含大量混有 ASP.NET 控件的静态内容块。新的 ASP.NET Localize 控件用于将静态内容标记为可本地化,以便资源生成包含这部分静态内容。如果控件中 meta:resourcekey 的指定先于生成资源命令的发布,则使用指定的关键字(同样适应于其他控件):
<asp:Localize id="welcomeContent" runat="server" meta:resourcekey="welcome">Welcome!</asp:Localize>
以上示例为 Localize 控件的 Text 属性生成了一个新的本地资源入口点,资源前缀是 "welcome" (welcome.Text)。要从共享资源显式填充静态内容,可以通过一个显式本地化表达式指定 Text 属性:
<asp:Localize id="welcomeContent" runat="server" text='<%$ resources: Glossary, welcomeText%>'>Welcome!</asp:Localize>
与其他情况一样,这些声明性语句解析成代码来请求资源设置控件属性,这里是 Text 属性。任何出现在控件声明语句中的 HTML 标记都将包含在资源生成中,这使翻译过程变得复杂,因此最好不要包含标记。
Localize 控件比它的基类 Literal 控件优越的是,运行时它的处理方式与 Literal 控件很像;然而,设计器会忽略它,并允许开发人员直接在 Design View 中编辑静态内容(不像 Literal 控件,在 Design View 中它绑定到一个容器中)。
资源本地化和部署
新的声明语句、页面资源的自动生成和强类型共享资源都使开发人员准备本地化 Web 应用程序更轻松。存储在 /LocalResources 和 /Resources 目录(分别是本地资源和共享资源)下的默认资源能翻译成支持的语言,翻译后的资源复制到源目录下。翻译资源的命名规则遵循 1.x 使用的规则。翻译后的 .resx 文件名包含语言代码。图 7 显示的是一个示例工程的扩展视图,其中的页面资源翻译成了西班牙语、法语和意大利语。
图 7. 与 1.x 的资源命名规则一致,根据语言代码命名 .resx 文件。
典型的 .NET Framework 1.x 应用程序发布时附带本地化的附属程序集,而 ASP.NET 2.0 还有新的可选部署集:
1. | ASP.NET 2.0 运行时继续支持传统的部署模型 — /bin 目录包含本地程序集依赖项,每个支持语言的子目录包含附属(只含资源)程序集。 |
2. | ASP.NET 2.0 预编译将 Web 页(即页面、用户控件和主页面)、本地资源和代码分隔文件作为一个单独文件进行处理 — 将它们编译到可部署的程序集。共享资源也预编译到用于部署的程序集。任何引用的资源入口点(例如,图像或 XML 文件)编译到程序集单元中。基本上而言,ASP.NET 2.0 Web 应用程序的预编译就是一个二进制容器,通过封装为源文件提供更高级别的保护。 |
3. | ASP.NET 2.0 也支持完整的运行时编译。这意味着所有 Web 页、代码分隔文件、其他源代码、资源(共享和本地)以及其他支持的应用程序文件都能以原始格式进行部署。然后,运行时编译器负责解析页面,随时生成程序集。这个模型提供了最大化的灵活性,但是主要用于轻量型 Web 应用程序,这样的应用程序频繁更改,而且不要求高级别的源代码安全。 |
4. | ASP.NET 2.0 发布时也可能实现混合多项功能。也就是说,将所有代码分隔文件和其他资源编译到用于部署的二进制程序集的同时,还能将页面和资源部署成源。这样可以灵活地为一个或多个页面编辑页面布局和资源内容或部署新的可本地化资源,而不会导致不受影响的应用程序集进行动态地重新编译。 |
对于第二、三、四项,ASP.NET 2.0 编译器自动将 /LocalResources 和 /Resources 目录下的 .resx 源文件编译到程序集。至于第三项和第四项,本地资源的编译先于页面的编译,即第一次访问页面或修改了页面源(或它的 .resx 文件)时进行的编译。由于具有 .resx 的编译提供程序,因此无需编译步骤就能进行部署。
正如第一项提到的,用于 1.x 程序集的向后可编译支持、非特定资源和相关附属程序集仍然存在。这个部署模型不使用 2.0 的本地化表达式,而且访问这些资源也不是通过默认的运行时资源提供程序模型进行的。使用表达式编译程序和资源提供程序的可扩展模型,对综合利用 2.0 提供的高效功能和 1.x 支持的资源部署将很有用处。
运行时资源提供程序
为了在 ASP.NET 1.x 应用程序中使用 ResourceManager,需要在执行数据绑定语句或应用从资源检索值的其他机制之前,在代码中实例化 ResourceManager。访问本地资源和共享资源时,ASP.NET .0 按需要自动实例化资源管理器,无需编写代码来管理此过程。因为使用声明性语句以资源值填充控件属性和 HTML 元素,所以不用编写任何代码来生成完全本地化的页面!
默认的 ResourceProviderFactory 负责在设计时使用相关的设计器工厂实例化资源提供程序,在运行时为页面和共享资源实例化资源提供程序。开发人员能编写代码来访问本地资源的值,方法是使用 Beta 1 中 Page 对象公开的 GetPageResourceObject:
if (this.Context.User.Identity.IsAuthenticated) mnuLogin.Text = GetPageResourceObject("Login"); else mnuLogin.Text = String.Format(GetPageResourceObject("LogoutUser", this.Context.User.Identity.Name);
当依赖资源的 HTML 输出需要运行时决策时,它能够用于覆盖声明性本地化表达式。要访问共享的页面资源,可以使用 Page 对象公开的另一个方法:
string cultures = (string)this.GetAppResourceObject("supportedCultures");
对于共享资源而言,开发人员更倾向于综合利用智能感知和强类型资源访问,下面的示例是检索一个存储为 String 类型的 XML 资源:
string cultures = Resources.Cultures.supportedCultures;
最终,GetPageResourceObject 和 GetAppResourceObject 通过配置好的资源提供程序访问正确的资源。如果创建了一个自定义资源提供程序,这些方法将能够使用 GetAppResourceObject 从那些共享资源中进行检索。
首选的语言选择
ASP.NET 1.x 应用程序传统上使用两种主要的方法选择每次请求的语言。对于在特定语言子目录下复制整个站点的应用程序,由 web.config 中的 <globalization> 元素来标识从这些子目录请求资源的运行时线程所使用的语言和 UI 语言:
<system.web> <globalization culture="es-ES" uiCulture="es"> </system.web>
这些声明性设置对使用单一代码基的应用程序没用。而手动设置每个请求线程的语言需要运行时代码,以便能为每个发出请求的用户动态地选择语言。用户的首选语言能从数据库配置文件、一个 HTTP cookie 或 Web 浏览器的语言设置中收集。无论如何,设置请求线程的 UI 语言决定了在运行时 ResourceManager 从哪一个本地化资源提取资源,而且正如之前提到的,语言设置影响与语言有关的格式。
ASP.NET 2.0 引入一个新功能,能根据 Web 浏览器的偏爱自动选择运行时的语言。@Page 指令用于标识是否应该根据浏览器的偏爱执行特定页面,它也支持语言和 UI 语言的设置:
<%@ Page uiCulture="auto" culture="auto">
应用程序的 web.config 文件也能将这项设置应用到整个应用程序中:
<system.web> <globalization culture="auto:en-US" uiCulture="auto:en"> </system.web>
如果 HTTP 页眉不可用,auto 后的冒号允许您指定一个默认的语言。因为必须设置一个特定的语言,因此上面的示例将 en-US 作为显示的语言。
最终结果是运行时自动检测浏览器发送的 ACCEPT_LANG 页眉,在页面周期的早期,将线程设置为用户语言首选列表中的第一个语言。如果为应用程序的用户存储了一个配置文件,或用户能够通过站点选择特定的语言,那么开发人员必须编写代码来覆盖运行时处理的 auto 设置。示例代码说明了这种情况的一个使用技巧。
小结
为了更迅速地适应未来遍及全球市场的产品发布的要求,在开发周期早期就定义一个全球化策略势在必行。使用 ASP.NET .0 这些新的本地化功能,开发人员能够更轻松地贯彻执行本地化应用程序的策略,与此同时,减少开发周期的系统开销。页面资源的自动生成和新的 Managed Resource Editor 使创建 Web 应用程序资源变得更自然。使用声明性本地化表达式,可能确保本地化所有必要的页面元素,并有助于自动生成适当的页面资源。一个新的运行时模型意味着开发人员能选择不再编译附属程序集,不再实例化资源管理器,并且不用根据语言来设置请求线程。最终将有利于发布强健的具有单一代码集的 Web 应用程序,从而降低发布应用于全球化市场的解决方案的成本和付出。