一 前言

界面支持多种语言,在使用ASP.NET自带的多语言方案时遇到下列问题:

  • 在做管理类的功能时,有添加、修改和查看页面,需要支持多语言的控件基本相同,但要维护多处,产生冗余(ASP.NET有共享的资源,但它是全局的,不能分 模 块,我们不能所模块的信息入在全局资源中);
  • 在页面中必须要指定资源文件中的KEY;
  • 当页面慢来慢多时,页面与资源的匹配实在难以维护;

所以我认为一个理想的支持多语言框架,需要有以下特性:

  • 分模块解决数据冗余问题;
  • 自动匹配页面与资源文件之间的联系;
  • 易于维护,能通过页面快速定位到资源文件中;
  • 支持后台消息的多语言实现
  • 支持前台JS消息的多语言实现

二 后台消息多语言的实现

在实现后台消息多言的实现时,主要利用ASP.NET的特性,通过修改当前线程的区域语言,来获取对应版本的资源。因为ASP.NET在处理请求时,会使用一个单独的线程来执行一次请求的所有代码,所以我们只需要在一个地方重写当前线程的语言信息,在其它任何地方都可以获取当前语言版本的资源文件。重写当前线程的区域语言的代码如下:

        protected override void InitializeCulture()
{
string language = "en";//默认为英文
if (Session["Language"] != null) language = Session["Language"].ToString();
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language);
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(language);
}

在命名资源文件名时,规则如下:

  • 默认语言的版本直接当正常命名,如命名OrderResource.resx
  • 其它版本的资源文件名,应加上区域名称, 如OrderResource.zh-cn.resx, OrderResource.en-us.resx.

将后台消息放在资源文件后,程序中只引用主的资源文件,这样在线程的区域信息更改后,会自动的引用其它语言版本的资源。比如在程序中使用如下代码:

Response.Write(OrderResource.FiledRequired);//当区域信息为英文时,输出"The Filed is required!";当区域信息为中文时,输出"字段必填!"

三 前台JS多语言的实现

前台的多语言实现,即在JS中需要弹出一些提示也需要多语言。前台多语言的实现方法实现有很多,在本例中,我们采用的统一的管理方式,把JS多语言信息同样放在资源文件中,只不过在一个公共的地方,把资源序列成一个json对象,然后JS中便可以使用了。当然,在实现此功能时,需要做一些缓存的工作。主要代码如下:

public static Dictionary<string, string> JsonResources = new Dictionary<string, string>();

//把资源文件序列化成JSON
public static string GetJsonResource()
{
string key = string.Format("JSResource.{0}", System.Threading.Thread.CurrentThread.CurrentCulture.Name);
if (!JsonResources.ContainsKey(key))
{
JavaScriptSerializer serialzer = new JavaScriptSerializer();
ResourceSet rs = JSResource.ResourceManager.GetResourceSet(System.Threading.Thread.CurrentThread.CurrentCulture, true, true);
string json = string.Format("[{0}]", serialzer.Serialize(rs.OfType<DictionaryEntry>().ToDictionary(x => x.Key, x => x.Value)));
JsonResources.Add(key, json);
}
return JsonResources[key];
} protected override void OnPreRenderComplete(EventArgs e)
{
//输出JSON对象到页面
Page.ClientScript.RegisterStartupScript(Page.GetType(), "", "<script language='javascript'>var json=eval(" + ResourceCache.GetJsonResource() + ");JSResource=json[0];</script>");
}

在页面中就可以使用JSResource对象了,如alert(window.JSResource.JSMsg);

四 页面中的元素自动匹配资源文件

此功能有一个前提就是资源文件中的KEY为控件ID并且为页面指定特定资源文件,这样我们就可以为控件自动匹配了。在匹配的过程中,如果在指定的资源文件中未找到,那么会到公共的文件中查找。

注意:

1>为页面指定特定资源文件,主要是用于多个页面(模块)共享一个资源,模块的大小可以自己控制;

2>有一个公共的资源文件,在整个项目中,总有一些信息是各个模块所通用的;

主要代码:

    public class ResourceFactory
{
public static ResourceAccess GetResource(System.Resources.ResourceManager resMgr)
{
return new ResourceAccess(resMgr, CommonResource.ResourceManager);
}
} public class ResourceAccess
{
private ResourceManager resourceManager = null; private ResourceManager commonResourceManager = null; public ResourceAccess(ResourceManager resourceManager,ResourceManager commonResourceManager)
{
this.resourceManager = resourceManager;
this.commonResourceManager = commonResourceManager;
} public string GetString(string name)
{
string str = this.resourceManager.GetString(name); if (string.IsNullOrEmpty(str))
{
str = this.commonResourceManager.GetString(name);
if (string.IsNullOrEmpty(str))
{
str = string.Format("【{0}】not exist", name);
}
}
return str;
}
} public class BasePage:Page
{
#region Mult Language
protected override void InitializeCulture()
{
string language = "en";//默认为英文
if (Session["Language"] != null) language = Session["Language"].ToString();
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(language);
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(language);
} public System.Resources.ResourceManager PageResourceManager { set; get; }
private ResourceAccess resourceAccess;
private Literal lit;
private Button btn;
private LinkButton libtn; protected override void OnPreRenderComplete(EventArgs e)
{
//输出JSON对象到页面
Page.ClientScript.RegisterStartupScript(Page.GetType(), "", "<script language='javascript'>var json=eval(" + ResourceCache.GetJsonResource() + ");JSResource=json[0];</script>");
if (!IsPostBack)
{
//绑定页面的文本
if (PageResourceManager != null)
{
resourceAccess = ResourceFactory.GetResource(PageResourceManager);
//we do not use recursion, because it create too much stack.
foreach (Control c in Page.Controls)//Large control of page,like HTML,Form
{
foreach (Control childC in c.Controls)//Normal control of page, like button, literal
{
BindControlLanguage(childC); foreach (Control childCC in childC.Controls) //Container control of page(if one contrl has child controls)
{
BindControlLanguage(childCC); foreach (Control childCCC in childCC.Controls)
{
BindControlLanguage(childCCC);
foreach (Control childCCCC in childCCC.Controls)
{
BindControlLanguage(childCCCC);
}
}
}
}
}
}
}
base.OnPreRenderComplete(e);
} private void BindControlLanguage(Control c)
{
if (c is Literal)
{
lit = (Literal)c;
if (lit.Text == "")
{
lit.Text = resourceAccess.GetString(lit.ID);
}
}
else if (c is Button)
{
btn = (Button)c;
btn.Text = resourceAccess.GetString(btn.ID);
}
else if (c is LinkButton)
{
libtn = (LinkButton)c;
if (libtn.Text == "")
{
libtn.Text = resourceAccess.GetString(libtn.ID);
}
}
}
#endregion
}

五 最终效果

英文版本

中版本

全部代码下载

ASP.NET 多语言的实现(后台消息+前台消息+页面自动绑定)的更多相关文章

  1. 后台向前台响应的json数据格式的一些问题

    最近在写后台向前台easyUI页面发送数据时遇到的一些报错. 首先easyUI内部封装了许多的方法和对象,以至于很多参数都不清楚,需要查询,其次easyUI也是有内置ajax所以从后台响应回来的数据一 ...

  2. 由ASP.NET所谓前台调用后台、后台调用前台想到HTTP——理论篇

    工作两年多了,我会经常尝试给公司小伙伴儿们解决一些问题,几个月下来我发现初入公司的小朋友最爱问的问题就三个 1. 我想前台调用后台的XXX方法怎么弄啊? 2. 我想后台调用前台的XXX JavaScr ...

  3. 在Asp.Net MVC中用Ajax回调后台方法

    在Asp.Net MVC中用Ajax回调后台方法基本格式: var operData = ...; //传递的参数(action中定义的) var type = ...; //传递的参数(action ...

  4. Asp.Net Web API开发微信后台

    如果说用Asp.Net开发微信后台是非主流,那么Asp.Net Web API的微信后台绝对是不走寻常路. 需要说明的是,本人认为Asp.Net Web API在开发很多不同的请求方法的Restful ...

  5. [ASP.NET MVC]如何定制Numeric属性/字段验证消息

    原文:[ASP.NET MVC]如何定制Numeric属性/字段验证消息 对于一个Numeric属性/字段,ASP.NET MVC会自动进行数据类型的验证(客户端验证),以确保输入的是一个有效的数字, ...

  6. Django模版语言 格式化显示 后台datatime()时间

    Django模版语言 格式化显示 后台datatime()时间 场景描述:

  7. DWR实现后台推送消息到web页面

    DWR简介 DWR(Direct Web Remoting)可用于实现javascript直接调用java函数和后台直接调用页面javascript代码,后者可用作服务端推送消息到Web前端. (服务 ...

  8. 由ASP.NET所谓前台调用后台、后台调用前台想到HTTP——实践篇(二)

    在由ASP.NET所谓前台调用后台.后台调用前台想到HTTP——理论篇中描述了一下ASP.NET新手的三个问题及相关的HTTP协议内容,在由ASP.NET所谓前台调用后台.后台调用前台想到HTTP—— ...

  9. Asp.Net Web API 2第四课——HttpClient消息处理器

    Asp.Net Web API 导航   Asp.Net Web API第一课:入门http://www.cnblogs.com/aehyok/p/3432158.html Asp.Net Web A ...

随机推荐

  1. AJAX文件上传实践与分析,带HTML5文件上传API。

    对于HTML5已经支持AJAX文件上传了,但如果需要兼容的话还是得用一点小技巧的,HTML5等等介绍,先来看看以前我们是怎么写的. 网上可能会有一些叫AJAX文件上传插件,但在AJAX2.0之前是不可 ...

  2. 如何用sublime 编写sass

    使用了Sublime Text也有一段时日了,然后在现在而言,小觉的coding工具已经非其莫属了,接着小觉因为近期忙着项目的原因,同时还要抽空编辑博客的原因,就暂时把它放在一旁了,现在偶然想起也就说 ...

  3. Cwinux源码解析系列

      Cwinux源码解析系列

  4. PHP的学习--cookie和session

    最近读了一点<PHP核心技术与最佳实践>,看了cookie和session,有所收获,结合之前的认识参考了几篇博客,总结一下-- 1. PHP的COOKIE cookie 是一种在远程浏览 ...

  5. Android进程间通信之socket通信

    用Java中的socket编程. 通过socket实现两个应用之间的通信,可以接收和发送数据,同时将接收到的数据显示在activity界面上. Server端: ServerLastly.java p ...

  6. 你真的了解setTimeout和setInterval吗?

    博客园的代码排版真难用,编辑时候是好的,一保存就是乱了——本文也同时发表在我另一独立博客上 你真的了解setTimeout和setInterval吗?,可以移步至这里吧 setTimeout和setI ...

  7. 【Java基础】序列化与反序列化深入分析

    一.前言 复习Java基础知识点的序列化与反序列化过程,整理了如下学习笔记. 二.为什么需要序列化与反序列化 程序运行时,只要需要,对象可以一直存在,并且我们可以随时访问对象的一些状态信息,如果程序终 ...

  8. 【Android】Android Camera原始帧格式转换 —— 获取Camera图像(一)

     概述: 做过Android Camera图像采集和处理的朋友们应该都知道,Android手机相机采集的原始帧(RawFrame)默认是横屏格式的,而官方API有没有提供一个设置Camera采集图像的 ...

  9. Head插件——学习Elasticsearch的锋刃利器!

    在学习Elasticsearch的过程中,必不可少需要通过一些工具查看es的运行状态以及数据.如果都是通过rest请求,未免太过麻烦,而且也不够人性化. 此时,head可以完美的帮助你快速学习和使用e ...

  10. 阅读《LEARNING HARD C#学习笔记》知识点总结与摘要三

    最近工作较忙,手上有几个项目等着我独立开发设计,所以平时工作日的时候没有太多时间,下班累了就不想动,也就周末有点时间,今天我花了一个下午的时间来继续总结与整理书中要点,在整理的过程中,发现了书中的一些 ...