• 自定义多语言的实现


    1背景

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

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

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

    • 分模块解决数据冗余问题;
    • 自动匹配页面与资源文件之间的联系;
    • 易于维护,能通过页面快速定位到资源文件中;

    2 资源存储于单个文件

    先不将最后解决方案贴出来,我们先看看解决方案的第一个版本(在此版本中未解决分模块解决数据冗余的问题, 但更容易理解一些),此方案与ASP.NET原有方案类似,Resource中的KEY是控件的ID,这样我们在BasePage中直接循环页面中的控件,然后根据控件ID找资源。

    类图:

    代码如下(其中ResourceAccess用ResourceAccess1表示,BasePage用BasePage1表示,CommonResource_EN 和CommonResource_CN是资源文件):

    View Code
        public class ResourceAccess1
        {
            private ResourceManager resourceManager = null;
    
            public ResourceAccess1(ResourceManager resourceManager)
            {
                this.resourceManager = resourceManager;
            }
    
    
            public string GetString(string name)
            {
                string str = this.resourceManager.GetString(name);
    
                if (string.IsNullOrEmpty(str))
                {
                    str = string.Format("【{0}】not exist", name);
                }
                return str;
            }
        }
    
    
        public class CommonResourceFactory
        {
    
            public static ResourceAccess GetResource(string lang)
            {
                ResourceAccess resourceAccess = null;
                switch (lang)
                {
                    case "CN":
                        {
                            resourceAccess = new ResourceAccess(CommonResource_CN.ResourceManager);
                            break;
                        }
                    default:
                        {
                            resourceAccess = new ResourceAccess(CommonResource_EN.ResourceManager);
                            break;
                        }
                }
                return resourceAccess;
            }
        }
    
    
        public class BasePage1 : Page
        {
            #region Mult Language
    
            private ResourceAccess resourceAccess;
            /// <summary>
            /// 是否重新加载语音
            /// </summary>
            public bool ReRenderLanguage;
    
            private Literal lit;
            private Button btn;
            private LinkButton libtn;
    
            protected override void OnPreRenderComplete(EventArgs e)
            {
                if (!IsPostBack || ReRenderLanguage)
                {
                    resourceAccess = ProductResourceFactory.GetResource("EN");//此处的语言EN,实际运行时,从SESSION中取出
                    
                    foreach (Control c in Page.Controls)//页面大对象
                    {
                        foreach (Control childC in c.Controls)//页面中的普通控件
                        {
                            BindControlLanguage(childC);
    
                            foreach (Control childCC in childC.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;
                    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;
                    libtn.Text = resourceAccess.GetString(libtn.ID);
                }
            }
    
            #endregion
        }

    说明:

    • 因为有一个系列对象创建的工作(CommonResource_EN,CommonResource_CN),所以用了一个简单工厂方法;
    • 因为原有简单工厂方法产生对象是ResourceManager, 在System.Resources 命名空间下,这样在引用这个工厂的地方就要引用这个空间,以及为了能在获取信息时做一些处理,所以我们加了一个代理,即ResourceAccess;
    • BasePage, 在OnPreRenderComplete事件与BindControlLanguage方法,是处理控件与资源文件映射的功能。其中如果需要加一些多语言的控件,可以在BindControlLanguage中添加;如果要处理一些功能,如为Repeater类的控件,动态添加一行时需要重新加载多语音,可以设置IsRenderLanguage=true,否则默认仅在页面第一次加载时做多语言。
    • 为什么在OnPreRenderComplete事件中做多语言,因为此事件在Page load 和控件事件之后,在呈现之前,这样我们就可以在控件事件中做一些设置处理。

    3 资源存储于多个文件

    此解决方案中解决了数据冗余的问题,并可以分模块来存储资源。

    类图:

    部分代码:

    View Code
        public interface IResourceFactory
        {
            ResourceAccess GetResource(string lang);
        }
    
    
    
        public class ProductResourceFactory : IResourceFactory
        {
            public ResourceAccess GetResource(string lang)
            {
                ResourceAccess resourceAccess = null;
                switch (lang)
                {
                    case "CN":
                        {
                            resourceAccess = new ResourceAccess(ProductResource_CN.ResourceManager, CommonResource_CN.ResourceManager);
                            break;
                        }
                    default:
                        {
                            resourceAccess = new ResourceAccess(ProductResource_EN.ResourceManager, CommonResource_EN.ResourceManager);
                            break;
                        }
                }
                return resourceAccess;
            }
        }
    
    
        public class ResourceAccess
        {
            private ResourceManager resourceManager = null;
    
            private ResourceManager commonResourceManager = null;
    
            public ResourceAccess(ResourceManager commonResourceManager)
            {
                this.commonResourceManager = commonResourceManager;
            }
    
            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 string GetComString(string name) 
            {
                string str = this.commonResourceManager.GetString(name);
                if (string.IsNullOrEmpty(str))
                {
                    str = string.Format("【{0}】not exist", name);
                }
                return str;
            }
        }
    
    public class BasePage : Page
        {
    
            public IResourceFactory BaseResourceFactory { set; get; }
    
            /// <summary>
            /// 是否重新加载语音
            /// </summary>
            public bool ReRenderLanguage;
    
            private ResourceAccess resourceAccess;
            private Literal lit;
            private Button btn;
            private LinkButton libtn;
    
            protected override void OnPreRenderComplete(EventArgs e)
            {
                if (!IsPostBack || ReRenderLanguage)
                {
                    if (BaseResourceFactory == null)// if BaseResourceFactory is null, then we see it as default "Name+ResourceFacotry"
                    {
                        string[] names = this.GetType().BaseType.Namespace.Split('.');
                        string name = names[names.Length - 1];
                        string resourceLayer = "BTS.Resource";
                        BaseResourceFactory = (IResourceFactory)Assembly.Load(resourceLayer).CreateInstance(string.Format("{0}.{1}ResourceFactory",resourceLayer, name));
                    }
                    if (BaseResourceFactory != null) 
                    {
                        resourceAccess = BaseResourceFactory.GetResource(loginInfo.Language);
                        //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;
                    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;
                    libtn.Text = resourceAccess.GetString(libtn.ID);
                }
            }
        }

    说明:

    • 因为要分不同的文件去存储资源信息,这样就产生了多系统的资源文件。并且在BasePage中处理这些代码相同,所以用了一个工厂方法,来解决多系列对象创建的工作。
    • 在BasePage中的OnPreRenderComplete事件中,判断了如果BaseResourceFactory不存在,则根据默认命名空间创建ResourceFactory,即页面的命名空间名称默认为工厂名称(去掉ResourceFactory),这样页面就不用做任何的处理了。如果页面的命名空间不是默认的,则需要设置BaseResourceFactory.
    • ResourceAccess中的GetString方法中的规则是:如果模块资源文件中未找到对应的资源,则去公共资源文件中去找。

    希望对您有所帮助,如果您有更好的解决方法,请告诉我。。。

  • 相关阅读:
    Android控件Editext、TextView属性详解
    修改Android签名证书keystore的密码、别名alias以及别名密码
    android 中如何限制 EditText 最大输入字符数
    keytool 错误 java.io.IOException: incorrect AVA format
    Android打包常见错误之Export aborted because fatal lint errors were found
    正则表达式之判断用户注册信息是否为汉字、字母和数字
    Android Dialog 系统样式讲解及透明背景
    Android中自定义Activity和Dialog的位置大小背景和透明度等
    字体在Android View中的输出 drawText
    怎么用CIFilter给图片加上各种各样的滤镜_1
  • 原文地址:https://www.cnblogs.com/dataadapter/p/2948844.html
Copyright © 2020-2023  润新知