本地化与Atlas对于本地化的支持

简介:


一、什么是本地化

   本地化,英文是Localization,缩写为L10n(与之类似的还有Globalization - G11n和Internationalization - I17n),其工作是将一个市场的产品进行某种方式的修改,目的在于向另一个市场的推广。一般来说,这两种市场的语言环境是不同的,因此“翻译”似乎就是 本地化工作的重中之重,其重要程度已经达到了让某些人误以为本地化工作完全就是一个翻译工作。其实不然。正像刚才所说的,本地化是为了让一个产品在另一个 市场得到推广,因此它需要做的事情还不少:

  首先当然最重要的就是 文字的翻译 。一个产品会有大量的 文字信息,在不同的市场中,对于这些文字自然应该翻译成符合该市场语言。翻译后语言应该要保持语句流畅和意义明确。需要注意的是,这里的“文字信息”不单 指产品中的“文本”,图片中的文字和以图片方式显示的文字也一样需要被翻译。在ASP.NET中,对于这方面的本地化工作有着很好的支持。

  其次是 环境的转换 。打个比方,在产品中很可能会有关于人的图片,则在美国市场应该显示为美国人,而在中国大陆市场则必须换作中国人——当然,如果用香港台湾韩国日本人可以吗?这……

  还要注意的是 语言习惯和环境属性 。 不同的市场往往会有不同的语言习惯和环境属性,比如时间格式、数字格式、货币单位、距离单位、时区、距离单位与标准长度单位的比等等。同样的信息在不同市 场的显示出来时会有很大的不同。这里大部分的属性在.NET Framework的System.Globalization.CultureInfo类有描述。而本文也着重于Atlas对于这一点的支持。

  不同的市场往往还需要运用不同的 样式 。 姑且不说市场不同语言之间文字的阅读方向会不同,就拿同样是从左往右的两种不同语言,在样式上就会有所不同。比如拿英语与中文来说,首先他们如果用相同的 字号,则中文会显得偏小。如果放大一些文字那么文字与边框,边框与边框,文字与图片之间的距离就会显得偏小,也需要一并改变。英文字母所组成的文章会有参 差的感觉,而中文汉字基本上都是方块字,同样是文章汉字给人的感觉会比较密。单个英语单词中间不能换行,而中文任意两个汉字之间都能换行,其限制主要在在 标点符号上。诸如此类等等。如果是大规模的产品,会涉及到许多产品的本地化工作,会专门成立一个小组用来研究各种语言文字下的样式,并提供开发人员全面的 参考。这样保证了同一个,或者同一系列的产品,在不同市场会应用不同样式,却又保持了风格的美观和统一。

  本地化工作还包括开发 市场特定功能 。不同的市场在很多地方会不相同,比如当地的法律限制了有些功能无法发布,有些功能必须修改和标注等等。为了更好地迎合用户,也有可能会为本地用户开发出新的功能。

  其他例如还有广告商,赞助商等等,这里就不多说了。


二、Atlas对于本地化的支持

  Atlas对于本地化工作的支持主要体现在客户端的Sys.CultureInfo对象。打开Atlas.js文件,可以发现如下的代码:
Sys.CultureInfo  =
{
    
" Name "  :  " en-US "
    
" NumberFormat "  : { ... }, 
    
" DateTimeFormat "  : { ... }
};

  代码比较长也比较无聊,因此就不完整贴出了。Sys.CultureInfo对象对于日期和时间的格式有着良好的支持,Atlas的客户端代 码对于Date和Number的扩展都是基于Sys.CultureInfo对象的定义,具体代码也可以在Atlas.js文件中看到。那么Atlas是 如何支持别的Culture的呢?我们新建一个aspx页面,加入一个ScriptManager,代码如下:
< atlas:ScriptManager  ID ="ScriptManager1"  runat ="server"   />

  然后在浏览器中打开这张页面。查看网页的源文件,可以发现这么一段代码:
< script  src ="atlasglob.axd"  type ="text/javascript" ></ script >

  在浏览器里访问这个atlasglob.axd文件就可以查看这个“文件”的内容。它也是一段和上面相似的Sys.CultureInfo代 码,只是内容会有所不同(如果相同的话那么访问atlasglob.axd?c=zh-cn就可以看到zh-cn的Sys.CultureInfo内 容)。它后与Atlas.js文件加载,因此它的内容会覆盖Atlas.js文件中的定义。这就是Atlas对于本地化的支持。

  在 ScriptManager中有一个属性EnableScriptGlobalization,默认值为True。如果不需要这个功能,则可以把它设为 False,那么页面就不会产生前面的<script />元素,加快加载速度。事实上,ScriptManager判断是否加载atlasglob.axd的逻辑会先判断 EnabledScriptGlobalization的值,如果是True,并且Request.UserLanguages[0]不是“en-us” (en-us的Sys.CultureInfo已经被包含在Atlas.js文件中),则会在页面中引用atlasglob.axd文件。

  那么atlasglob.axd文件是什么呢?它是如何工作的呢?首先,如果使用在web.config中可以看到下面这样定义:
< httpHandlers >
    
< add  verb ="*"  path ="atlasglob.axd"  type ="Microsoft.Web.Globalization.GlobalizationHandler"  validate ="false" />
</ httpHandlers >

  这个定义表示将atlasglob.axd文件交由Microsoft.Web.Globalization.GlobalizationHandler处理,我们要它如何运行的,就必须看一下那个类的代码了。它的ProcessRequest方法代码:
 1 None.gif public   void  ProcessRequest(HttpContext context)
 2 ExpandedBlockStart.gif {
 3InBlock.gif      string culture = context.Request.QueryString["c"];
 4InBlock.gif
 5InBlock.gif      if ((culture == null&& (context.Request.UserLanguages != null))
 6ExpandedSubBlockStart.gif      {
 7InBlock.gif            culture = context.Request.UserLanguages[0];
 8ExpandedSubBlockEnd.gif      }

 9InBlock.gif
10InBlock.gif      if (culture == null)
11ExpandedSubBlockStart.gif      {
12InBlock.gif            culture = "en-us";
13ExpandedSubBlockEnd.gif      }

14InBlock.gif
15InBlock.gif      AtlasCultureInfo info = AtlasCultureInfo.Create(culture);
16InBlock.gif      string script = JavaScriptObjectSerializer.Serialize(info);
17InBlock.gif      context.Response.Write("Sys.CultureInfo = ");
18InBlock.gif      context.Response.Write(script);
19InBlock.gif      context.Response.Write(";");
20ExpandedBlockEnd.gif}

  首先先查看Query String里“c”的值(因此前面通过atlasglob.axd?c=zh-cn可以访问到zh-cn的信息),如果没有提供c的值,那么则会查看 Request对象里UserLanguages数组的第一个值。那么什么是UserLanguage?它反映了客户端的设定,我们打开IE,点击菜单 “工具——Internet选项”,再点击“语言”按钮,会弹出语言首选项窗口,如图:
UserLanguagesSetting.jpg

   在这里可以添加删除UserLanguage,比如现在UserLanguage[0]是“zh-cn”。在上面的ProcessRequest的方法 中,如果没有Query String和UserLanguage的设定,则默认使用en-us。接着将culture值传入AtlasCultureInfo的静态方法 Create得到一个AtlasCultureInfo对象。然后将对象序列化输出,就得到了我们看到的结果:一个Sys.CultureInfo的定 义。

  AtlasCultureInfo的静态方法Create会使用用户传入的cultureName字符串,根据 System.Globalization.CultureInfo类的静态方法CreateSpecificCulture得到一个 CultureInfo对象。可以看出,这个cultureName必须代表了一个specific culture(例如zh-CN和en-GB),否则就会抛出异常(关于invariant culture,neutral culture和specific culture的区别和联系可以参考MSDN相关内容)。然后根据得到的CultureInfo对象使用AtlasCultureInfo的私有构造函数 得到一个AtlasCultureInfo对象,这个对象会把传入的CultureInfo对象的Name,NumberFormat和 DateTimeFormat复制给自己的相关属性。因此,序列化后的信息就是我们前面从atlasglob.axd访问得到的数据了。


三、为Atlas的本地化的支持自定义Culture Detection规则

   分析了Atlas对于本地化的支持,是不是发现还缺了点什么?默认Handler会使用用户UserLanguage设定,那么如果用户没有 UserLanguage设定该怎么办呢?如果我们要根据访问页面的Query String,用户当前的Cookie设定,或者用户帐户设定又该怎么办呢?如果我们只是想把默认的Culture设为zh-cn而不是en-us又该怎 么办呢?其实我们需要的只是将自己的Culture Detection规则告诉Atlas。

  还好我们能从 atlasglob.axd的Query String下手。首先,我们先将ScriptManager的EnableScriptGlobalization属性设成False,以避免 ScriptManager自动生成对于atlasglob.axd文件的script加载。代码如下:
< atlas:ScriptManager  ID ="ScriptManager1"  runat ="server"  EnableScriptGlobalization ="false"   />

  接着,我们可以用自己的方式在网页里添加对于atlasglob.axd的script引用了。注意,引用必须在Atlas.js的 script引用(在网页源文件可以看到是一个对WebResource.axd的script引用)之后才能生效。当然最简单的办法就是通过 ScriptManager使用RegisterScriptReference方法添加引用了。比如我们需要在Form_Load里注册,代码如下:
protected   void  Page_Load( object  sender, EventArgs e)
{
    
string  cultureName  =  GetUserCulture();
    
this .ScriptManager1.RegisterScriptReference( " atlasglob.axd?c= "   +  cultureName);
}

  打开网页后查看页面的源代码,就能发现下面的xml-script:
< script  type ="text/xml-script" >
    
< page  xmlns:script ="http://schemas.microsoft.com/xml-script/2005" >
        
< references >
            
< add  src ="atlasglob.axd?c=en-GB"   />
        
</ references >
        
< components  />
    
</ page >
</ script >

  那么我们就来检验了它有没有生效,在浏览器地址栏里输入“javascript:alert(Sys.CultureInfo.Name)”并回车,弹出的MessageBox就显示了目前Sys.CultureInfo对象的名称。如图:


  如果当前页面无法访问到ScriptManager对象,那么使用下面的代码也能完成相同的功能:
protected   void  Page_Load( object  sender, EventArgs e)
{
    
string  cultureName  =  GetUserCulture();
    ScriptManager.GetCurrent(
this .Page).RegisterScriptReference( " atlasglob.axd?c= "   +  cultureName);
}

  ScriptManager类的静态方法GetCurrent是取出作为参数的System.Web.UI.Page对象里的 ScriptManager实例。当然,它的前提是当前Page对象里有ScriptManager对象。在Atlas类库里大量使用了这个方法,各个控 件(比如UpdatePanel)都是通过这个方法获得当前页面的ScriptManager对象,然后通过各种逻辑改变页面的行为。


四、更好地控制Atlas本地化支持

   我们已经做到了自定义的Culture Detection,足够了吗?事实上,这样的做法还有比较明显的缺陷。首先它将Culture Detection的逻辑放在了页面中,很可能会在多个地方出现类似的代码,不利于维护,我们应该集中的处理这段逻辑。再者,如果我们还想更进一步地操作 Atlas的本地化支持,该怎么做呢?比如,我们希望修改部分的CultureInfo信息,甚至完全自定义,又该怎么办呢?

  我们自 然可以完全放弃atlasglob.axd而使用自己生成的Scripts,但是我更倾向于在Atlas的基础上作。毕竟,atlasglob.axd的 使用是ScriptManager的built-in功能,我们不妨就在这个基础上扩展。我们知道,atlasglob.axd自身没有任何功能,因为它 不是一个文件,根本不存在。唯一起作用的是Microsoft.Web.Globalization.GlobalizationHandler类,它生 成了我们需要的所有CultureInfo代码。因此,我们为什么不使用自定义的Handler?

  写这样一个Handler非常简 单,唯一要关注的只有ProcessRequest方法。这样,我们就可以将所需culture在Handler里得到,然后和上面贴出的 GlobalizationHandler.ProcessRequest代码完全一样地输出即可。

  唔?AtlasCultureInfo是internal类,外界无法访问?没有关系,那么我们自己写一个:
None.gif public   class  JeffzAtlasCultureInfo
ExpandedBlockStart.gif
{
InBlock.gif    
public DateTimeFormatInfo DateTimeFormat;
InBlock.gif    
public string Name;
InBlock.gif    
public NumberFormatInfo NumberFormat;
InBlock.gif
InBlock.gif    
public JeffzAtlasCultureInfo(CultureInfo culture)
ExpandedSubBlockStart.gif    
{
InBlock.gif        
this.Name = cultureInfo.Name;
InBlock.gif        
this.NumberFormat = cultureInfo.NumberFormat;
InBlock.gif        
this.DateTimeFormat = cultureInfo.DateTimeFormat;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

  然后在ProcessRequest方法里使用即可。

  如果我们有特殊的要求,想修改部分Sys.CultureInfo 信息又该怎么办呢?当然我们可以自己定义一个类并序列化输出,但是CultureInfo还是有不少信息,编写起来有着不小的工作量,而我们往往只需要做 一点点修改。因此我推荐在输出代码的最后输出额外的修改代码即可。例如:
public   void  ProcessRequest(HttpContext context)
{
    
//  the original output
    context.Response.Write( " Sys.CultureInfo.NumberFormat.CurrencySymbol = '@'; " );
}

  这样,Sys.CultureInfo对象的内容就会被修改了,非常地方便。

  当我们写好了自己的Handler,只需再web.config文件中把Handler注册给atlasglob.axd文件即可。剩下的工作,就交给ScriptManager去处理吧。



本文转自 jeffz 51CTO博客,原文链接:http://blog.51cto.com/jeffz/60953,如需转载请自行联系原作者

相关文章
|
4月前
|
UED
在进行应用的本地化时,需要注意哪些问题?
在进行应用的本地化时,需要注意哪些问题?
26 2
|
11天前
|
存储 自然语言处理 API
Flutter应用的国际化支持:实现多语言环境的优雅策略
【4月更文挑战第26天】Flutter提供强大的国际化(i18n)和本地化(l10n)支持,使开发者能轻松实现应用多语言特性。通过定义`.arb`文件来管理字符串资源,使用`LocalizationsDelegate`加载资源,设置应用语言环境,以及在UI中使用`S.of(context).someString`访问字符串。进阶技巧包括字符串格式化、复数形式、双向文本和Unicode支持。充分测试确保所有语言正确显示。随着全球化需求增长,Flutter的国际化支持成为应用开发关键。
|
22天前
|
自然语言处理 中间件 开发者
Django的国际化与本地化支持:打造多语言应用
【4月更文挑战第15天】Django,一款强大的Web框架,内置出色的支持国际化和本地化功能,使得创建多语言应用变得简单。本文介绍了国际化(i18n)与本地化(l10n)的概念,阐述了Django的相应机制,包括标记可翻译字符串、提取与翻译、设置语言和地区、本地化格式处理。遵循文中步骤,开发者能有效构建适应不同语言和地区需求的Web应用,提升用户体验。
|
5月前
|
存储 自然语言处理 监控
【Unity 实用工具篇】| 游戏多语言解决方案,官方插件Localization 实现本地化及多种语言切换
Unity的多语言本地化是一个很实用的功能,它可以帮助游戏支持多种语言,让不同语言的玩家都能够更好地体验游戏。 而实现本地化的方案也有很多种,各个方案之间也各有优劣,后面也会对多个方案进行介绍学习。 本文就来介绍一个专门作用于多语言本地化的Unity官方插件:Localization 。 这个插件方便进行游戏的多语言本地化,让游戏支持多种语言,下面就来看看该插件的使用方法吧!
|
9月前
|
XML 存储 JSON
前端国际化和本地化的实现方法
前端国际化和本地化的实现方法
354 0
|
10月前
UE4插件的本地化/国际化工作
UE4插件的本地化/国际化工作
174 0
Yii2的国际化和本地化支持是什么?底层原理是什么?
Yii2的国际化和本地化支持是什么?底层原理是什么?
119 0
|
XML 自然语言处理 JavaScript
第四十三章 在CSP应用程序中本地化文本 - 本地化的基础
第四十三章 在CSP应用程序中本地化文本 - 本地化的基础
|
自然语言处理 iOS开发
iOS 开发之 国际化/本地化 配置
iOS 开发之 国际化/本地化 配置
589 0
iOS 开发之 国际化/本地化 配置