ASP.NET 的全球化体系结构(摘自MSDN)

 

ASP.NET 的全球化体系结构

Michele Leroux Bustamante
2003 年 9 月

适用于:
Microsoft® ASP.NET

摘要:在设计体系结构时事先对全球化进行规划可以提高业务的灵活性并显著减少后续工作量。本文提供了有关全球化的背景信息,介绍了 .NET 资源的部署体系结构,并探讨了 ASP.NET 全球化过程中所面临的特定困难,以及如何构建应用程序的体系结构以便最大限度地提高部署效率和简化维护工作。(本文包含一些指向英文站点的链接。)

下载本文中讨论的以下代码示例:

目录

什么是全球化?
.NET 资源
Web 的全球化体系结构
您的文化环境是什么?
格式和规则
用于帮助理解的代码示例

构建任何应用程序而不为将来的全球化进行事先规划是难以想象的,尽管如此,真正进行了必要准备的公司却非常少见。各家公司每天都在通过 Internet 忙于国际业务,他们常常会听到这样的询问,“您的应用程序能够支持我们的全球分支机构吗?”。虽然公司可能并未建立专门面向其他语言和文化环境的业务基础结构,但是仍然有人会质疑:这只是一个站点内容的简单翻译过程,为何如此困难?其实他们并未意识到,这是由于开发第一版时限制了一个很有限的时间,设计小组无法开发可以支持未来全球化的应用程序体系结构。鉴于客户可能在其他国家设立了分支机构,同时大型企业在评估第三方应用程序时经常会考虑是购买还是自行开发,因此满足这些需要就显得非常重要。而准备不足则会影响业务的灵活性。如果在设计体系结构时能够事先考虑到全球化,则可以轻松化解上述问题。

如果您对这种事先规划感兴趣,请继续阅读,本文将为您提供一些有关全球化的背景信息,介绍 .NET 资源的部署体系结构,并探讨 Microsoft® ASP.NET 全球化过程中所面临的特定难题,以及如何构建应用程序以便最大限度地提高部署效率和简化维护工作。

什么是全球化?

全球化是一个简单的概念,但为便于理解,我们还是先概述一下它的基本概念。全球化过程的第一步是将应用程序代码国际化,然后将此应用程序本地化为其他语言,并适应相应的文化环境。国际化过程使我们能够为任何区域设置翻译、存储、检索和呈现应用程序内容,并且在此过程中最好使用相同的应用程序代码库。区域设置是语言和文化环境的组合,包括日期、时间、货币、电话号码等的格式。这意味着我们需要将与区域设置相关的内容和与区域设置无关的内容分开,同时使代码能够根据区域设置对内容进行动态格式化。经过国际化的应用程序便可用于本地化。本地化是指根据文化环境对内容进行翻译和格式化,以使应用程序能够适用于其他区域设置。在此过程中最好不要触及代码。如果在初始开发阶段进行了国际化,则开发小组在进行本地化时应当会相对轻松些。但是,最初进行本地化时通常会发现一些由国际化引起的错误,例如意外翻译的文件或字段名称。

注意:国际化和本地化通常统称为应用程序的全球化,但有时我们也会看到“可用于全球 (world-ready)”和“可本地化 (localizability)”这两个词,用于描述已经国际化的应用程序。此外,“文化环境”和“区域设置”这两个词也可以互换,其中文化环境包括了语言和特定于区域的首选项。

国际化的理想目标是:

  • 删除表示层和代码库中的所有内容。其核心思想是使用一个代码库和一个可用于为任何文化环境呈现内容的表示层(表示布局)。
  • 将内容放在一个易于翻译并且可以通过编程方式进行访问以便填充表示层的位置。
  • 将内容和用户输入存储在某种格式中,以便可以针对相应的文化环境将其作为一个整体呈现出来。

完成上述步骤后,我们便可以针对特定的文化环境进行本地化过程,其中包括:

  • 由第三方对所有内容进行翻译。其难易程度在很大程度上取决于内容的存储位置,以及它与应用程序其他部分集成的紧密程度。
  • 将翻译后的内容与应用程序集成在一起。如果它们与表示层或代码库的联系并不紧密,则这一过程不会对开发人员和用户界面设计人员有什么影响。
  • 针对新文化环境进行部署和校验。

本文余下的内容将介绍一些支持 ASP.NET 全球化的体系结构方案,并解释相关的 .NET 功能。

.NET 资源

在介绍 ASP.NET 的特定体系结构之前,我们先讨论一下 .NET 中的资源。首先,我将介绍如何在 Windows 窗体应用程序中使用 .NET 资源,因为 Visual Studio.NET IDE 为这些资源提供了丰富的支持。然后,我将介绍如何在 ASP.NET 应用程序中利用这些资源。

Windows 窗体的资源

创建 Windows 应用程序时,每个窗体将自动获得一个 XML 资源文件 (*.resx)。

图 1:为 Form1 自动生成 Form1.resx

设计窗体和输入内容时,如果将窗体的 Localizable 属性设置为 True,则表示要对资源进行翻译。因此,IDE 将修改您的代码以便将可本地化的属性从资源加载到窗体的 *.resx 文件中。

图 2:如果设置为 True,则可本地化的属性将自动添加到窗体的 *.resx 文件中

对于窗体上的任何控件,当初始化控件时,将从 *.resx 文件中加载一组预设的可本地化的属性,例如与位置、大小和显示等值相关的属性。IDE 不仅在 *.resx 中放置了值,而且在 InitializeComponent() 方法中生成了代码,以创建 ResourceManager 来访问这些资源。例如,以下代码将创建 Form1 资源的实例并初始化 Label1 的某些可本地化的属性:

System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
this.label1 = new System.Windows.Forms.Label();
this.label1.Location = ((System.Drawing.Point)(resources.GetObject("label1.Location")));
   this.label1.Size = ((System.Drawing.Size)(resources.GetObject("label1.Size")));
         this.label1.TabIndex = ((int)(resources.GetObject("label1.TabIndex")));
         this.label1.Text = resources.GetString("label1.Text");
         this.label1.TextAlign = ((System.Drawing.ContentAlignment)(resources.GetObject("label1.TextAlign")));

当您在属性窗口中添加、删除和编辑控件或窗体属性时,IDE 将修改相应窗体的资源和代码库。您还可以直接使用 Resource Editor(资源编辑器)向任何 *.resx 文件中添加自己的资源。

您不必对以下消息进行硬编码:

DialogResult result = MessageBox.Show("Are you sure you want to exit?",
"Exit Application?", MessageBoxButtons.YesNo);

相反,可以将字符串添加到 XML 资源文件中,然后编写代码以便按名称访问这些资源:

System.Resources.ResourceManager resources = new 
   System.Resources.ResourceManager(typeof(Form1));
DialogResult result = MessageBox.Show(resources.GetString("quitapplication"), 
            resources.GetString("quit"), MessageBoxButtons.YesNo);

实际上,在构建窗体后,可能只需对 ResourceManager 进行一次实例化,将其保存到该窗体的某个实例成员中。

要访问资源编辑器,可以在 Solution Explorer(解决方案资源管理器)中双击 *.resx 文件。您可以在数据视图或 XML 视图中进行编辑,但目前这种方式似乎有些笨拙。您可以轻松地创建新字符串资源而不指定类型,但是,如果要创建具有明确类型的其他资源,则必须手动输入完整的类型名称(区分大小写),包括它的程序集。

marginwidth="0" marginheight="0" src="/china/msdn/Archives/library/dnaspp/images/aspnet-globalarchitect-03.gif" frameborder="0" width="100%" height="788">

图 3:在资源编辑器中创建新字符串资源

至此,根据前面介绍的内容,我们已经可以访问嵌入到主程序集中的资源(包括您添加的新资源条目),下面将介绍文化环境的特定资源和附属程序集。

附属程序集

针对应用程序支持的每个文化环境都将生成一个附属程序集。了解中性文化环境和特定文化环境之间的差别将有助于您确定支持哪些文化环境。每个文化环境都有一个未指定区域的中性文化环境,例如,“en”是表示中性英语文化环境的 ISO 代码,而“es”是表示中性西班牙语环境的代码。提供中性文化环境的翻译时,它将作为该文化环境的默认资源(如果您没有为每个可能的区域提供特定的资源)。特定文化环境同时包含了语言和区域。例如,“en-CA”表示英语(加拿大),“en-US”表示英语(美国),“es-EC”表示西班牙语(厄瓜多尔),“es-SP”表示西班牙语(西班牙)。按区域进行本地化对于您的客户端可能会很重要,因为这样便可以解决不同地区之间的细微差别问题。

虽然客户端会影响对特定文化环境翻译的需要,但您至少应当始终为中性文化环境提供资源,作为默认的语言翻译。

注意:文化环境代码遵循 ISO 3166 命名规则,.NET Framework Class Library 中的 CultureInfo class 对此进行了介绍。

对于 Windows 应用程序,您可以使用 IDE 为不同的文化环境生成窗体资源,即,将窗体的 Language 属性设置为要支持的文化环境。如果将 Language 属性设置为 English(英语)(图 4),则会为中性英语文化环境创建一个新资源(图 5)。

图 4:在 Properties(属性)对话框中设置语言

图 5:生成新窗体资源

每次更改 Language 属性时,都将为该语言及其中性文化环境(如果选择了一个特定文化环境)生成一个新的空资源文件(如果该资源文件尚不存在)。对窗体和控件属性所作的所有更改将保存到选定的语言资源中。您也可以使用资源编辑器编辑自己的资源条目(未绑定到窗体元素)。

我曾提到过,不变的资源嵌入在主程序集中,那么这些特定于文化环境的 XML 资源又将如何呢?它们被 IDE 编译到附属程序集中。附属程序集只包含资源,不包含代码,并且部署在根据其文化环境的 ISO 代码命名的子目录下。

因此,您会看到以下命名模式:

  1. 资源文件的源被命名为 resourcename.culture.resx(即 Form1.en.resx、Form1.en-CA.resx)。
  2. 这些源资源被编译到中间资源文件中,其命名规则为 assemblyname.resourcename.culture.resources(即 ColorPicker.Form1.en.resources)。
  3. 这些中间资源文件随后将嵌入到它们各自的附属程序集中。附属程序集全部被命名为 assemblyname.resources.dll(即 ColorPicker.resources.dll),并且部署到根据此文化环境的 ISO 代码命名的子目录(即 /en、/en-CA)下。
  4. 嵌入的资源在每个程序集清单中被标识为 assemblyname.resourcename.culture.resources,与第 2 条中的格式相同。附属程序集在其程序集清单中也包含一个与它的文化环境的 ISO 代码相匹配的文化环境属性。

主程序集应当始终包含不变的文化环境资源(在清单中标识为 assemblyname.resourcename.resources)。

访问资源

因此,假设您已经获得了翻译的资源并准备进行构建,那么怎样才能针对特定的文化环境运行应用程序呢?也就是说,如何访问特定文化环境的资源呢?

实际上,您可以使用 ResourceManager.GetResourceSet() 来请求特定文化环境的资源。以下代码通过为西班牙语(厄瓜多尔)提供一个 CultureInfo 对象来请求该文化环境(由 ISO 代码“es-EC”标识)的资源:

System.Resources.ResourceManager rm = 
   new System.Resources.ResourceManager(typeof(Form1));

System.Resources.ResourceSet resources = rm.GetResourceSet(new 
   System.Globalization.CultureInfo("es-EC"), true,true);

DialogResult result = MessageBox.Show(resources.GetString("quitapplication"), 
   resources.GetString("quit"), MessageBoxButtons.YesNo);

仅当您的首要目标是访问“es-EC”时,此代码才有效。通常,如果找不到所请求的“es-EC”资源,则会回退到中性文化环境“es”并给出输出结果。这就是 ResourceManager 的功能。它能够从特定资源回退到中性资源,如果未提供中性资源,则会继续回退到不变的资源(请记住,您应当在中性资源中为每个文化环境提供一个完整的翻译)。

ResourceManager 将基于当前线程的 UI 文化环境查找资源。确定当前用户的相应文化环境后,可以设置当前线程的文化环境。否则,它将默认为代码运行所在系统的设置。

System.Threading.Thread.CurrentThread.CurrentUICulture = 
   new System.Globalization.CultureInfo("es-EC");

只要您在通过 ResourceManager 访问资源之前修改 CurrentUICulture 属性,就会看到正确的结果。

注意:有关资源回退的详细信息,请参阅《.NET Framework Developer's Guide》中的 Locating and Using Resources for a Specific Culture

共享资源

大多数应用程序都包含一些在组件和/或其他应用程序之间共享的公用资源。公用资源可能包括错误消息、应用程序消息及动态填充的文本(该文本并不特定于某个窗体,或者可能被重复使用)。即便是对于某个特定的应用程序,也没有必要将所有窗体的公用资源放到某个特定窗体的 *.resx 文件中。相反,可以将这些资源放到某个公用字符串资源中。

您可以向项目中添加资源,即,在 Add New Item(添加新项目)对话框中选择 Assembly Resource File(程序集资源文件)。默认情况下,对此资源进行的生成操作将把此资源嵌入到主程序集中,对于资源的不变版本,这正是我们所希望的。现在,要在 Visual Studio 环境中为此新资源生成附属程序集,您还必须为要本地化的每个文化环境创建一个新资源。虽然这里未进行详细说明,但该操作其实非常简单。只需使用与窗体资源使用的命名规则相同的命名规则将新资源添加到同一项目中即可。在本示例中,我们添加了 strings.es.resx,用于保存字符串资源的西班牙语翻译。IDE 将该资源编译到此项目的附属程序集中,这样,“es”子目录现在包含一个附属程序集,用于保存以下两种类型的资源:ColorPicker.Form1.es.resources 和 ColorPicker.strings.es.resources。图 6 显示了使用 ILDASM.EXE 时的 /es 目录附属程序集的清单。

图 6:使用 ILDASM.EXE 时的 /es 目录附属程序集的清单

要访问这些自定义资源,需要再创建一个用于访问“strings”资源类型的 ResourceManager。不过,这一次我们使用构造函数,以便可以为资源类型指定字符串名称,包括命名空间以及所加载的包含该资源的程序集:

System.Resources.ResourceManager resources = 
   new System.Resources.ResourceManager("ColorPicker.strings",
   System.Reflection.Assembly.GetExecutingAssembly());

现在,如果要在应用程序或组件之间共享资源,可以进一步扩展此代码,创建一个只包含资源的新的类库。例如,我向 CommonRes 项目中添加了两个 XML 资源:errors.resx 和 errors.es.resx。对此项目进行编译后,将创建一个只包含资源的主程序集 (CommonRes.dll),同时在 /es 目录下生成一个西班牙语的附属程序集 (CommonRes.resources.dll)。要使用这些资源,可以将主程序集和附属程序集部署到目标应用程序的目录结构中。在访问程序集的资源项之前,必须先加载该程序集:

System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFrom
(String.Format("{0}//CommonRes.dll", 
   Application.StartupPath));

System.Resources.ResourceManager resources = 
   new System.Resources.ResourceManager("CommonRes.errors",asm);

MessageBox.Show(resources.GetString("InvalidColor"));

如果资源将由部署到某台计算机的多个应用程序共享,您还可以将这些共享资源部署到同一台计算机的全局程序集缓存 (GAC) 中。

ASP.NET 资源

现在您已了解了 ResourceManager 是如何处理附属程序集的,下面我们将这些概念应用到 ASP.NET 程序中的资源上。除以下几个细微差别外,这些概念基本上是相同的:

  • 默认情况下,每个 Web 窗体都将获取自己的 XML 资源,Global.asax 也是如此,但是命名规则略有不同。Web 窗体资源文件的命名规则为 webformname.aspx.resx,而全局资源的命名规则为 Global.asax.resx,嵌入的资源仍遵循前面介绍的命名规则。
  • 您必须手动向项目中添加特定的文化环境资源,因为当前尚没有支持此操作的 IDE。要将这些资源编译到附属程序集中,仍必须遵循前面介绍的命名规则。也就是说,将西班牙语的 XML 资源命名为 webformname.es.resx 和 Global.es.resx,而不是某些人可能认为的 webformname.aspx.es.resx 和 Global.asax.es.resx。*.resx 文件的名称被直接映射到程序集清单中嵌入资源的名称,任何偏差都会使 ResourceManager 找不到此资源。
  • Web 应用程序的默认部署模型将主组件程序集放在应用程序的 /bin 目录下,这意味着附属程序集子目录将放在 /bin 下(/bin/en、/bin/en-CA 和 /bin/es 等)。

开始时,您可能会对没有支持生成 Web 窗体资源的 IDE 而感到失望。不过,您会意识到要为每个 Web 窗体使用单独的资源是不可能的,因为 Web 应用程序会包含很多页面,并且 Web 页面中的大多数内容通常并没有存储在资源中。下面,我们将探讨 Web 应用程序全球化过程中的特定难题,以及资源在 Web 部署中的用途。

Web 的全球化体系结构

对 Windows 应用程序进行本地化时需要使用大量资源,用于用户界面布局和固定的内容。Web 应用程序中的这种复杂性主要是由于开发 Web 应用程序时使用了众多不同的技术。如果再向其中添加翻译内容,事情就变得更复杂了。让我们通过不同的功能角色思考一下所面临的难题:内容提供商、Web 设计人员、应用程序开发人员和翻译人员。

一个应用程序中可能包含多种类型的内容提供商。某些提供商提供菜单和页面部分的术语以及其他营销语言。其他提供商可能提供描述产品和服务的数据库内容、公司和雇员信息、白皮书和文章、订户协议以及注册窗体等。

Web 设计人员负责美化内容的外观。因此他们必须清楚内容的外观以及如何在每个页面中将内容分组。

为便于说明,我将应用程序开发人员定义为负责将 HTML 或 Web 设计的图形转换为 ASP.NET 页面、确定内容存储结构、设计数据库以及处理运行时的内容访问的人员。

翻译人员负责翻译内容,因此他们需要访问多个数据源。他们可能使用资源编辑器和 XML 编辑器,并且还必须找到一种修改数据库内容的方法(可以允许他们对内容服务器进行有限的访问,或者采用传统的平面文件交换方法)。

当然,我们还必须考虑项目经理的角色。他/她负责协调所有这一切,这是一个复杂的过程。除协调问题外,还有一条共同的主线将所有这些角色联系起来,这就是应用程序内容。应用程序内容的存储位置和访问方式将影响所有角色完成各自工作的方式。确定内容的存储位置时,需要权衡以下因素:

  • 便于内容开发人员和翻译人员访问和修改内容
  • 便于 Web 设计人员在内容发生变化及需要进行调整时修改页面布局
  • 能够支持新的文化环境而不必修改 Web 界面、应用程序组件或数据库结构

复制站点

Web 内容通常嵌入在 HTML 或 ASP 中,且某些动态生成的内容可能由数据库提供。翻译 Web 应用程序时始终面临一个由简单的原因导致的难题,即内容总是来自不同的源。将 Web 内容作为静态 HTML 存储时,翻译将直接在 HTML 页面中进行,并且通常会在某个本地化的目录结构下存储该 Web 站点的一个副本。翻译人员使用自己的专用工具将内容与 HTML 标记分开,以便简化工作和减少出错。

此方法的体系结构通常是,在根据其文化环境命名的子目录(使用相应的 ISO 代码)下放置该站点的完整副本。这样,当应用程序确定当前用户的文化环境时,便可以将 ISO 代码映射到重定向 URL 中,以确保用户位于该站点的正确版本中。

图 7 和图 8 显示了一个应用程序根目录,其中包含一个 /articles 子目录,每个翻译的子目录也包含一个 /articles 子目录。

图 7:此应用程序根目录包含一个 /articles 子目录

图 8:每个翻译的子目录也包含一个 /articles 子目录

对于不同的文化环境,可以将用户重定向到按 ISO 命名的相应子目录下的默认页面。在默认页面中可以使用相对链接(如果设计无误)。但在使用相对路径时必须小心。例如,./ 和 / 会将您转至 Web 服务器的根目录,从而将您重新置于应用程序根目录下。

注意:有关 ASP.NET 如何处理相对路径的详细信息,请参阅我的文章 Organization Strategies:Handling Relative Paths in ASP.NET

除了可能出现导航错误外,此体系结构还存在其他一些明显问题。当功能和内容发生变化时,需要修改一组重复的页面(可能还要修改代码库)。翻译人员必须躲开 HTML 标记来修改内容,而 Web 设计人员无法与翻译人员同时工作,因为两者的结合是很困难的。此外,站点的设计通常会因不同的翻译而发生变化,这仅仅是由于布局没有位于中央模板中。同时,每次发生更改时都要进行一轮校验。

但实际情况是,很多公司仍然采用这种方法来翻译页面内容。某些公司称,他们之所以这样做是因为他们的站点很少更改,所以不值得为这种变更花费时间来重新构建其体系结构。其他公司则期待着更好的工具的出现,以便 Web 设计人员和开发人员能够使用同一个代码库。在下面的内容中您将了解到,其实真正的差别在于进行这项工作的时间的选择。您可以迅速发布站点的第一个版本,然后每次进行更改时采取相应措施,也可以事先采取措施,然后轻松完成更新内容的部署。

单个代码库

一种理想的情况是,如果能够为单个代码库的全球化构建站点的体系结构,则从长远角度看,您将省去很多麻烦。所面临的困难之一是 Web 内容具有不同的源。虽然可以将很多内容存储在 Web 页面中,但仍有大量内容是从数据库、XML 或其他可配置的数据源动态加载的。

设计应用程序时必须采取适当的策略,以便将内容源动态添加到 ASPX、ASCX 和其他用户界面表示层中。因此我们在确定不同内容的位置时必须审慎考虑。某些内容,尤其是产品信息以及其他可能发生变化的重要内容,最好存储在可搜索的数据库中。这意味着 Web 设计人员必须执行查询才能看到此页面。其他不是很重要的、不经常修改且容易共享的内容可以存储在 XML 资源中。这些内容可能包括菜单标题、按钮标题、标签、公司标记行和宗旨说明。某些 XML 内容也可能适于存储在文件系统上的 XML 文件中,然后可以通过 XSLT 将这些文件转换到用户表示层中。

当我们将内容划分到外部资源、XML 文件或数据库表中时,便可以获得一致的应用程序代码,即基于用户的文化环境(由前面提到的 ISO 代码标识)来选择相应的资源、文件或表。下面各个小节将向您介绍如何构建站点的体系结构以处理不同的内容源。

资源

既然大多数内容都放在数据库或 XML 文件中,那么资源在 ASP.NET 应用程序中有什么用途呢?实际上,您可以利用附属资源的回退过程来引用正确的数据库表、XML 或其他用于填充界面的文件。对于未翻译的文件和表,您不必在文化环境的特定附属资源中提供资源条目。此外,对于菜单标题、术语项目和错误消息等内容,资源也是很有用的。

这会带来一个很有趣的问题,即,如何分布这些资源条目。您会希望将可翻译的资源与不可翻译的资源分开,以确保翻译人员不会翻译数据库表名称、连接字符串、查询和文件名。

要使用资源内容来填充页面,您可以通过 ResourceManager 访问资源(如上所述),并将控件属性绑定到相应的条目,或者由内含代码填充它们。这里面的技巧是,确保将 HTTP 请求的线程设置为进行该请求的用户的相应文化环境。由于 Web 应用程序是无状态的,因此必须为每个请求执行此操作。下面将介绍如何检测用户的文化环境首选项。

顺便说明一下,对于 ASP.NET 应用程序,所有程序集(包括主程序集和附属程序集)都应原样复制到 GAC 中,以便能够对版本更新进行 XCOPY 部署。这样便可以轻松地添加语言或更新特定资源,而不必重新启动应用程序或 Web 服务器。

XML 和数据库内容

这里是我们要认真进行权衡的地方。假设我们仅将资源用于很小的内容片段、对外部文件的引用和数据源。现在,我们将确定大量动态和静态内容的存储位置。

XML 是一个出色的存储媒介,因为您可以轻松地将 XML 传递给翻译人员,并且可以使用 XSLT 在页面中呈现 XML,从而使 Web 设计人员能够在修改布局时看到页面中的内容。但是,它对于复杂的关系数据用处并不大,而且您还必须监视繁忙的生产性站点上的文件的 IO 活动。此外,使用 XSLT 需要一定技巧,如果没有一个长驻的专家,您会发现它并不是一个简单的过程,即使它确实会给设计过程带来好处。

而数据库内容通常具有很强的关系性,并且可以动态查询,同时任何 IO 活动的监视都是在数据库层上进行的(最好将其部署到可以相应缩放的某个硬件部分)。通常情况下,翻译人员将获得一份要翻译的数据库表的副本,或者使其能够安全地远程访问这些表,甚至可以采用具有优良传统的提取平面文件的方法。这里有一个很大的难题,也是一个不可避免的难题,即如何与 Web 设计人员协作以设计内容的布局。

要解决这一涉及 Web 设计人员的难题,我的建议是先设计 Web 界面的原型,包括高级别的站点图,然后使用 XML 来填充此原型。这样一来就非常简单了,我们只需添加几行代码来加载 XML 文件并填充 DataGrid 即可,我们简直没有理由不采用这种方式。如果 Web 设计人员和 ASP.NET 专家不是同一个人(通常情况下他们不是同一个人),则必须进行大量的通信,一方面 Web 设计人员使用 HTML 和/或图像来提供布局,另一方面 ASP.NET 开发人员为页面工作流的可重复使用的控件、用户控件和一般体系结构构造原型。

采用这些步骤的好处是您可以更清楚地了解应当将哪些内容存储在资源、XML 或数据库中。同时,内容开发人员可以专注于他们的工作,并由组件和数据库开发人员构建后端程序。

您的文化环境是什么?

要选择正确的内容,您需要知道用户的文化环境首选项。可以通过各种方法让用户指出他们首选的 Web 应用程序文化环境。但所有方法都要从首次访问开始。如果您的站点有注册页面,则可以搜集用户在该页面中设置的首选文化环境。如果没有注册页面,可以将文化环境默认设置为英语,并让用户通过用户界面选择一个新的文化环境。还有一种方法是默认为用户在 Internet Explorer 中选择的语言。

图 9 和图 10 显示了在 IE 中选择了“语言”选项卡并在列表顶部放置了一个首选语言。

图 9:在“Internet 选项”对话框中单击“语言”

图 10:将首选语言移到列表顶部

语言设置按照指定的顺序在 Accept-Language HTTP 信息头中随请求一起传递:

GET WebForm1.aspx HTTP/1.1
Connection: Keep-Alive
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-us;q=0.8,es-ec;q=0.6,fr-ca;q=0.4,de;q=0.2; ja
Host: localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)

您可以通过 HttpRequest.Headers 属性访问这些语言设置并按以下方式设置当前线程的文化环境:

   Thread.CurrentThread.CurrentUICulture = 
               new CultureInfo(this.Request.UserLanguages[0]);
    

通常,我们将用户的首选项存储在 Session 对象中,并且最好保存这些首选项以便下次使用(如果您的系统中包含这些用户的帐户)。您还可以为用户提供一种方法,使其能够根据需要更改他们在用户界面中的文化环境首选项。

格式和规则

虽然本文探讨的主要内容是体系结构,但是要注意,对于呈现内容而言,您不仅仅要考虑内容的翻译,还必须考虑日期、时间、日历、数字和货币的格式,以及如何执行排序和字符串的比较。幸运的是,当您设置当前线程的 CurrentCulture 属性时,.NET Framework 的内置格式化程序类将对此进行无缝处理。

CurrentUICulture 和 CurrentCulture 属性的区别是,前者只处理 ResourceManager 选择,而后者处理数据格式。

如果使用 DateTime 或 Calendar 类,它们将自动设定线程的 CurrentCulture 设置。同样,当格式化数字值(包括格式化货币)时,.NET Framework 将使用 NumberFormatInfo 类无缝地设定 CurrentCulture。

对于数据格式和存储,还可能出现一个更基本的问题。例如,我经常遇到这样一些数据库,它们被设计为处理包含 5 个字符的邮政编码和 10 位电话号码。这在处理国际性的邮政编码和电话号码时会带来严重问题。ISO 标准没有涵盖所有情况,但是您可以采用一些建议的存储格式,例如,用 +1-555-555-1212+111 表示电话号码。该格式包含了国家(地区)代码和 PBX 分机,如果您始终以这种格式存储号码,则分析查询结果时会更容易,尤其是如果您的系统需要使用存储的号码来生成传真。

用于帮助理解的代码示例

为帮助说明本文讨论的主题,我提供了一些代码示例(GlobalWebContent.msiGlobalWebDataSample.msiGlobalWinAppSample.msi)。您在 .NET Dashboard Web 站点上也能看到这些代码示例。其中包含一些短小的特定示例,专用于揭示本文介绍的各个概念;还有一个更复杂的示例,用于将这些概念综合在一起。您可以随时向我索取其他代码示例--只要时间允许,我会在相同的位置发布这些代码。请将索取请求发送至:suggest@dotnetdashboard.com。

同时,如果本文只能给您带来一点启示,那么我希望您能记住,即使您现在还无法预见到做好全球化准备的必要,也应当避免为支持全球化而重新构建应用程序所带来的麻烦。如果您希望应用程序具有灵活性并收到立杆见影的效果,那么请尽早进行规划以避免中途更改应用程序体系结构。

要查阅 Michele Leroux Bustamante 撰写的更多文章和代码示例,请访问 .NET Dashboard Web 站点。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值