ASP.Net本地化/国际化解决方案原理和代码示例

出处:http://blog.csdn.net/snaill/archive/2007/12/06/1920843.aspx

解决方案原理:
ASP.NET本地化支持
通过 CultureInfo 类可以访问区域设置的属性。
此外,ASP.NET 基于每个线程和请求跟踪默认区域性的两个属性:用于区域设置相关函数默认值的 CurrentCulture,
和用于区域设置特定的资源数据查找的 CurrentUICulture。

解决方案主要包含几个部分组成:
1:客户设置语言的控件,一般会包含在每个页面,使得用户可以随时切换区域
控件ascx代码

< asp:DropDownList  ID ="DropDownList1"  runat ="server"  AutoPostBack ="true"  OnSelectedIndexChanged ="DropDownList1_SelectedIndexChanged" >
< asp:ListItem  Text ="English Version"  Value ="en-US" > asp:ListItem >
< asp:ListItem  Text ="中 文 版"  Value ="zh-CN" > asp:ListItem >
asp:DropDownList >

控件CS事件代码
protected   void  Page_Load( object  sender, EventArgs e)
        
{
            
if (!Page.IsPostBack){
                
if (Request.Cookies[Settings.Default.Cookies_Language] == null || Request.Cookies[Settings.Default.Cookies_Language].Value == "")
                
{
                    
foreach (ListItem li in DropDownList1.Items)
                    
{
                        
if (li.Value == "")
                            li.Selected 
= true;
                    }

                }

                
else
                
{
                    
foreach (ListItem li in DropDownList1.Items)
                    
{
                        
if (li.Value.ToLower() == Request.Cookies[Settings.Default.Cookies_Language].Value.ToLower())
                            li.Selected 
= true;
                    }

                }

            }

        }


        
protected   void  DropDownList1_SelectedIndexChanged( object  sender, EventArgs e)
        
{
            Response.Redirect(
"~/ChangeLanguage.aspx?Language=" + DropDownList1.SelectedValue + "&url=" + Server.UrlEncode(Request.Url.PathAndQuery) ,true);
        }
ChangeLanguage中间页面代码:
public  partial  class  ChangeLanguage : System.Web.UI.Page
    
{
        
protected void Page_Load(object sender, EventArgs e)
        
{
            Response.Cookies[
"Language"].Value = Request["Language"];
            Response.Cookies[
"Language"].Expires = DateTime.Now.AddDays(1000);
           

            Response.Redirect(Server.UrlDecode(Request[
"url"]));
        }

    }

2:在每页加载时会判断当前用户选择的区域,一般在页面的基类中实现比如类名:BasePage。
当用户初次进入网站识别客户端浏览器,
当用户曾经选择了区域,加载选择区域
/// 
        
/// 本地化
        
/// 

         protected   override   void  InitializeCulture()
        
{
            
if (Request.Cookies[Settings.Default.Cookies_Language] != null && Request.Cookies[Settings.Default.Cookies_Language].Value != null && Request.Cookies[Settings.Default.Cookies_Language].Value != "")
            
{
                setCulture();
            }

            
else
            
{//设置Cookie
                Response.Cookies[Settings.Default.Cookies_Language].Value =
                    (Request.Headers[
"accept-language"].Split(",".ToCharArray())[0]);
                Response.Cookies[Settings.Default.Cookies_Language].Expires 
= DateTime.Now.AddDays(1000);
                setCulture();
            }

            
base.InitializeCulture();
        }



        
private   void  setCulture()
        
{

            
try
            
{
                String selectedLanguage 
= Request.Cookies[Settings.Default.Cookies_Language].Value;
                UICulture 
= selectedLanguage;
                Culture 
= selectedLanguage;

                System.Threading.Thread.CurrentThread.CurrentCulture 
=
                    System.Globalization.CultureInfo.CreateSpecificCulture(selectedLanguage);
                System.Threading.Thread.CurrentThread.CurrentUICulture 
= new
                    System.Globalization.CultureInfo(selectedLanguage);
            }

            
catch //( Exception ex )
            {
                Response.Cookies.Clear();
// [Settings.Default.Cookies_Language].d
                
//throw;
            }

        }

3:当然是为每个页面准备资源文件。
这个是个体力活,
ASPNET.ascx.en.resx 表示英文的
ASPNET.ascx.zh.resx 这个表示中文的,当然还可以分为更加细的区域,比如zh-CN/zh-HK/zh-TW

4:当然要记得,把你的页面都要继承你的基类
   public partial class Index : PageBase
 

style="MARGIN-TOP: 0px; FLOAT: left" border="0" marginwidth="0" framespacing="0" marginheight="0" src="http://wz.csdn.net/vote.aspx?t=ASP.NET%202.0%20%u672C%u5730%u5316%u6280%u672F%u4E4B%u7814%u7A76%uFF08%u4E8C%uFF09%20-%20%u8717%u725B%u6863%u6848%u5BA4%20-%20CSDNBlog&u=http%3A//blog.csdn.net/snaill/archive/2007/12/06/1920837.aspx" frameborder="0" noresize="noresize" width="54" scrolling="no" height="75">  ASP.NET 2.0 本地化技术之研究(二)     
ASP.NET 2.0 本地化技术之研究的回复中提到了以下两点:

1.这只是单个页面的切换,如何做整个站点的切换呢?( hjh )
2.关于如何将资源直接显示……既然控件能够将嵌入dll的资源直接显示,不知道网站能否也将嵌入资源直接调用WebResource显示呢?( Cat Chen

由于不是一两句可以说清,所以再开一篇仔细讲一下。


内容列表:

1.整站本地化资源的切换
2.使用ProFile保存用户选择的语言
3.关于WebResource的使用
4.代码下载

1.整站本地化资源的切换

在上一篇里我们讲到,可以通过重载页面的InitializeCulture函数,在其中切换当前线程的CurrentUICulture和CurrentCulture来实现本页的资源切换。那么整站呢?总不能在每个页面里都写上这几句吧。。。

首先,我想到的是使用MasterPage,如果在MasterPage里加上资源切换的代码,那么所有使用该母板的页面都具备这种能力了吧,呵呵(想得不错)。但如意算盘打破了,MasterPage是使用@Master来声明的,根本和Page是两个继承路线,所以MasterPage里没有InitializeCulture这个虚函数!

没办法,想到了另一个解决方案,创建一个从System.Web.UI.Page继承下来的基类,在其中实现资源切换,而站内所有页面的实现类都从该类继承。OK,就这么办!

打开上一篇完成的网站,选中网站,右键在弹出菜单中点击[添加ASP.NET文件夹]-[App_Code]。
选中该文件夹,右键点击[添加新项],在弹出式窗口中选择“类”,命名为LocalizedPage.cs,点击[添加]完成,如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第1张图片

编辑LocalizedPage.cs,代码如下:
using  System;
using  System.Data;
using  System.Configuration;
using  System.Web;
using  System.Web.Security;
using  System.Web.UI;
using  System.Web.UI.WebControls;
using  System.Web.UI.WebControls.WebParts;
using  System.Web.UI.HtmlControls;
using  System.Threading;
using  System.Globalization;

///  
///  所有需要本地化资源切换的页面基类
///  

public   class  LocalizedPage : System.Web.UI.Page 
{
    
protected   override   void  InitializeCulture()
    {
        String s 
=  Request.QueryString[ " currentculture " ];
        
if  ( ! String.IsNullOrEmpty(s))
        {
            
// UICulture - 决定了采用哪一种本地化资源,也就是使用哪种语言
            
// Culture - 决定各种数据类型是如何组织,如数字与日期
            Thread.CurrentThread.CurrentUICulture  =   new  CultureInfo(s);
            Thread.CurrentThread.CurrentCulture 
=  CultureInfo.CreateSpecificCulture(s);
        }
    }
}

编辑Image.aspx.cs,去除其重载的InitialzeCulture()函数,将其基类改为LocalizedPage,代码如下:
using  System;
using  System.Data;
using  System.Configuration;
using  System.Collections;
using  System.Web;
using  System.Web.Security;
using  System.Web.UI;
using  System.Web.UI.WebControls;
using  System.Web.UI.WebControls.WebParts;
using  System.Web.UI.HtmlControls;
using  System.Threading;
using  System.Globalization;

public  partial  class  Image : LocalizedPage
{
    
protected   void  Page_Load( object  sender, EventArgs e)
    {
        System.Drawing.Bitmap img 
=  (System.Drawing.Bitmap)GetGlobalResourceObject(
            
" LocalizedText " ,
            CultureInfo.CurrentCulture.Name.ToLower().Replace(
" - " " _ " +   " _flag " );

        System.IO.MemoryStream ms 
=   new  System.IO.MemoryStream();
        img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

        Response.ClearContent();
        Response.ContentType 
=   " image/jpeg " ;
        Response.BinaryWrite(ms.ToArray());

        img.Dispose();
        ms.Dispose();
        ms.Flush();
    }
}

运行网站,可以看到由Image页面负责输出的图片,可以按选中的语言正常切换。

再编辑Default.aspx.cs,调整代码如下:
using  System;
using  System.Data;
using  System.Configuration;
using  System.Web;
using  System.Web.Security;
using  System.Web.UI;
using  System.Web.UI.WebControls;
using  System.Web.UI.WebControls.WebParts;
using  System.Web.UI.HtmlControls;
using  System.Globalization;
using  System.Threading;


public  partial  class  _Default : LocalizedPage 
{
    
protected   void  Page_Load( object  sender, EventArgs e)
    {
        String s 
=  Request.QueryString[ " currentculture " ];
        Image1.ImageUrl 
=   " ~/Image.aspx?currentculture= "   +  s;
    }

    
protected   void  Button1_Click( object  sender, EventArgs e)
    {
        Localize1.Text 
=  (String)GetLocalResourceObject( " Label1Resource1.Text " +   "   "   +
            (String)GetGlobalResourceObject(
" LocalizedText " " Msg1 " );
    }
}

运行程序,一切正常。

总结:利用这种方式,新建页面时只需修改其继承的基类为LocalizedPage即可。对于已经建好的站点,同理,也可以很方便的加入资源切换的支持。

2.使用ProFile保存用户选择的语言

前面我们是通过URL传参的方式将用户选择的语言传递到各个页面,感觉不爽。那么使用Session呢?听上去不错,但是你没听过ProFile吗?这可是ASP.NET 2.0的新特性之一呀!与Session一样ProFile是针对一个特定用户的,但ProFile更好用,因为它有以下特点:
  1)可存储,默认是保存在SQL Server Express中,但通过实现Provider可以将它存储到任何地方
  2)支持匿名使用,在用户认证后还可以迁移到认证用户中(具体实现方法据说是非常的“巧妙”)
  3)支持生成和管理报告
不错吧,那么我们就用ProFile来保存用户选择的语言信息吧。

注意:由于ProFile默认是由SQL Server Express来存储的,所以要保证你的VS2005已经安装该模块。

编辑Web.Config,在system.web节点下增加以下配置
< configuration >
    
< system .web >
        
< anonymousIdentification  enabled ="true" />
        
< profile >
            
< properties >
                
< add  name ="LanguagePreference"  type ="string"  
                    defaultValue
="Auto"  allowAnonymous ="true"   />
            
properties >
        
profile >
    
system.web >
configuration >

同时加入的anonymousIdentification节,是为了让系统自动为匿名用户生成唯一标识。另外的allowAnonymous="true"表明LanguagePreference属性可以被匿名用户访问。

编辑Default.aspx,切换到[设计]视图,删除原来用于切换语言的两个链接“中文(中国)”和“English(USA)”。从工具箱中拖一个DropDownList控件到页面上,设置其AutoPostBack属性为True( 切记!),然后编辑它的Items属性,如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第2张图片

中文(中国)的Value为zh-cn,英文(美国)的Value为en-us。

编辑Default.aspx.cs,为DropDownList编写SelectedIndexChanged事件的实现,代码如下:
     protected   void  DropDownList1_SelectedIndexChanged( object  sender, EventArgs e)
    {
        Profile.LanguagePreference 
=  DropDownList1.SelectedValue;
        Response.Redirect(Request.Url.AbsolutePath);
    }

修改Page_Load的实现,代码如下:
     protected   void  Page_Load( object  sender, EventArgs e)
    {
        String s 
=  Profile.LanguagePreference;
        Image1.ImageUrl 
=   " ~/Image.aspx " ;
    }

然后再编辑LocalizedPage.cs,代码如下:
     protected   override   void  InitializeCulture()
    {
        String s 
=  (String)Context.Profile.GetPropertyValue( " LanguagePreference " );
        
if  ( ! String.IsNullOrEmpty(s)  &&  (s  !=   " Auto " )) 
        {
            
// UICulture - 决定了采用哪一种本地化资源,也就是使用哪种语言
            
// Culture - 决定各种数据类型是如何组织,如数字与日期
            Thread.CurrentThread.CurrentUICulture  =   new  CultureInfo(s);
            Thread.CurrentThread.CurrentCulture 
=  CultureInfo.CreateSpecificCulture(s);
        }
    }

注意:我们在Default.aspx.cs之所以可以直接使用Profile来访问用户个人信息,是因为ASP.NET在页面运行时自动为我们生成了一个继承自System.Web.Profile.ProfileBase的ProfileCommon类。而在App_Code目录的代码开始执行时,ProfileCommon还没有生成,更别提Profile了。所幸的是,我们可以通过上面代码的方式访问到用户个人信息(真的研究了好长时间。。。

运行程序,切换语言,运行效果如图所示:
中文(中国)
ASP.Net本地化/国际化解决方案原理和代码示例_第3张图片

英文(美国)
ASP.Net本地化/国际化解决方案原理和代码示例_第4张图片

注意哟,退出程序后,再次运行,所有页面将按你上次设置的语言显示,Profile真的很不错。

3.关于WebResource的使用


ASP.NET是在运行时将全局资源和本地资源进行编译,象.aspx文件一样,所以我们只需要将.resx文件xcopy到正在运行的WEB服务器上,即可为新语言提供本地化的支持。但如果我们开发了一个WEB控件,其中使用到了一些资源(如图片),那就要求我们必须将DLL和资源文件一起部署到WEB服务器上,比较麻烦。

ASP.NET开发团队考虑到了这一点,现在我们可以在网站里使用资源DLL,这样在发布DLL时资源也同时被分配了。该技术是通过在控件代码里调用GetWebResourceUrl方法,这个方法指向一个名为WebResource.axd的内置HTTP处理程序的URL。通过加载一个名为AssemblyResourceLoader的HttpHandler类,ASP.NET运行时响应WebResource.axd的请求,返回指定资源的URL。

该技术有以下缺点:
  1)只能在面向 ASP.NET 2.0 网站的 DLL 项目内使用该技术,而无法网站内直接使用该技术
  2)该技术实际上并不支持任何形式的本地化(说到这,感觉把这家伙写到本随笔里不太合适。。。管它呢,先写完再说! )

选中网解决方案,右键在弹出式菜单里点击[添加]->[新建项目],在弹出窗口选中Visual C#项目下的类库,并设好保存路径,如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第5张图片

点击确定,删除Class1.cs。选中ClassLibrary1项目,右键在弹出菜单里点击[添加]->[新建项],在弹出窗口选择“WEB 自定义控件”,如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第6张图片

点击[添加],现在解决方案里已经包含两个项目了,如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第7张图片

右键ClassLibrary1项目,选择[添加]->[现有项],随便找一张图片(我使的是园子的logo,嘿嘿),如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第8张图片

点击[添加],右键刚添加的图片点击[属性],将“生成操作”设为“嵌入的资源”,如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第9张图片

编辑WebCustomControl1.cs,代码如下:
using  System;
using  System.Collections.Generic;
using  System.ComponentModel;
using  System.Text;
using  System.Web;
using  System.Web.UI;
using  System.Web.UI.WebControls;

[assembly: WebResource(
" ClassLibrary1.logo.gif " " image/gif " )]

namespace  ClassLibrary1
{
    [ToolboxData(
" <{0}:WebCustomControl1 runat=server> " )]
    
public   class  WebCustomControl1 : WebControl
    {
        
protected   override   void  RenderContents(HtmlTextWriter output)
        {
            output.WriteBeginTag(
" image " );
            String url 
=  Page.ClientScript.GetWebResourceUrl(GetType(),  " ClassLibrary1.logo.gif " );
            output.WriteAttribute(
" src " , url);
            output.WriteEndTag(
" image " );
        }
    }
}

编辑网站的Default.aspx文件,切换到[设计]视图,将工具箱的ClassLibrary1面板里的WebCustomControl1控件拖到页面上,运行程序,效果如图所示:
ASP.Net本地化/国际化解决方案原理和代码示例_第10张图片


4.代码下载

下载地址: http://www.cnblogs.com/Files/reonlyrun/WebLocalizationTaste2.rar
 

你可能感兴趣的:(Asp.Net,2.0,asp.net,object,语言,sql,server,image,class)