服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 分享两种实现Winform程序的多语言支持的多种解决方案

分享两种实现Winform程序的多语言支持的多种解决方案

2021-12-22 13:58梦在旅途 C#

本篇文章主要介绍了分享两种实现Winform程序的多语言支持的多种解决方案,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧。

因公司业务需要,需要将原有的ERP系统加上支持繁体语言,但不能改变原有的编码方式,即:普通程序员感受不到编码有什么不同。经过我与几个同事的多番沟通,确定了以下两种方案:

方案一:在窗体基类中每次加载并显示窗体时,会自动递归遍历含文本显示的控件(Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,StatusStrip,TabPage,ToolStrip,RadioButton,DateTimePicker,DataGridView,CheckedListBox,TreeView,MenuStrip),并根据不同的控件类型的文本属性调用简繁转换方法进行转换并重新设置新的相应文本属性的内容(比如:繁体内容)

优点:编码简单,对普通程序员的编码无影响(除窗体类的基类由Form类变成MyStyleFormBase类);

缺点:因每次打开窗体都需要遍历控件并进行简繁转换,如果界面上的控件较多,则可能导致打开窗体较慢,影响用户体验,且子控件的文本内容改变时需程序员手动通知,无法自动感知并转换。

具体实现思路如下:

一.对Form类进行二次封装(继承),定义一个MyStyleFormBase类,并在里面加入每次加载并显示窗体类型时,会自动递归遍历含文本显示的控件,并根据不同的控件类型的文本属性调用简繁转换方法进行转换并重新设置新的相应文本属性的内容,这样当所有的窗体都继承MyStyleFormBase类时,均默认就实现了遍历与转换的过程,程序员无需再次编码,甚至都无需知道存在遍历与转换的过程,从而提高了代码的复用性,具体代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class MyStyleFormBase : Form
 
{
 
 public MyStyleFormBase()
 
 {
 
 if (!Thread.CurrentThread.CurrentUICulture.Name.Equals("zh-CHS", StringComparison.OrdinalIgnoreCase)) //如果是简体,则无需转换
 
 {
 
 base.TextChanged += MyStyleFormBase_TextChanged;
 
 base.Shown += MyStyleFormBase_Shown;
 
 }
 
 }
 
 
 
 private void MyStyleFormBase_TextChanged(object sender, EventArgs e)
 
 {
 
 this.Text = LanguageHelper.GetLanguageText(this.Text);
 
 }
 
 
 
 private void MyStyleFormBase_Shown(object sender, EventArgs e)
 
 {
 
 LanguageHelper.SetControlLanguageText(this);
 
 base.ControlAdded += MyStyleFormBase_ControlAdded;
 
 }
 
 
 
 private void MyStyleFormBase_ControlAdded(object sender, ControlEventArgs e)
 
 {
 
 LanguageHelper.SetControlLanguageText(e.Control);
 
 }
 
 
 
 /// <summary>
 
 /// 强制通知子控件改变消息
 
 /// </summary>
 
 /// <param name="target"></param>
 
 protected virtual void PerformChildrenChange(Control target)
 
 {
 
 LanguageHelper.SetControlLanguageText(target);
 
 }
 
 
 
 /// <summary>
 
 /// 弹出消息框
 
 /// </summary>
 
 /// <param name="text"></param>
 
 /// <param name="caption"></param>
 
 /// <param name="buttons"></param>
 
 /// <param name="icon"></param>
 
 /// <param name="defaultButton"></param>
 
 /// <returns></returns>
 
 protected DialogResult MessageBoxShow(string text, string caption, MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1)
 
 {
 
 return MessageBox.Show(LanguageHelper.GetLanguageText(text), LanguageHelper.GetLanguageText(caption), buttons, icon, defaultButton);
 
 }
 
}

代码逻辑简要说明:

1.当当前UI的文化区域不为中文简体时(因为本程序本身都是基于简体开发的),就订阅窗体显示事件Shown及窗体标题改变事件TextChanged,作用:当窗体显示时,则会遍历控件并转换为繁体,当标题的文本改变时,也会自动转换为繁体;

2.当窗体显示后订阅窗体的控件增加事件ControlAdded,作用:当窗体显示后,若后续存在代码增加控件时,会自动将控件及其子控件进行繁体的转换,保证一个都不漏;

3.增加一个消息提示框方法,目的是弹出消息窗口前能够将简体文本转换成繁体文本;

4.增加一个强制通知子控件改变消息的方法PerformChildrenChange,当某个控件的文本内容或增加子控件发生时,由于窗体本身无法捕获到,故需要调用该方法来遍历与转换子控件的文本内容;(感觉这里不太好,但目前没有更好的办法,如果大家有更好的办法,欢迎留言评论)

 二、LanguageHelper:语方转换公共类(目前仅支持简繁转换,依赖于:ChineseConverter.dll)代码如下:

由于代码过长,请点击下载

该类逻辑很简单,就是从一个父控件开始,遍历所有的子控件,并根据不同的控件类型将控件相应的文本内容转换成简体或繁体,调用方法:SetControlLanguageText

以上二步就实现了多语言的支持了(准确的说是简繁转换),应用到项目中很简单,只需将窗体默认的基类Form改成:MyStyleFormBase即可,如:public partial class FormTest : MyStyleFormBase

方案二:由控件依据当前区域信息+缓存语言字典直接实现各控件自行转换

优点:无需遍历,各控件自行根据区域信息自支转换,因此效率较高,对普通程序员的编码无影响(除窗体类的基类由Form类变成MyStyleFormBase类外,还需要使用支持多语言的控件,这些控件均由普通控件二次封装得来,保留原有的所有属性及事件);

缺点:需将所有带文本显示的控件(如:Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,StatusStrip,TabPage,ToolStrip,RadioButton,DateTimePicker,DataGridView,CheckedListBox,TreeView)均进行二次封装,控件统一命名为:MyStyleXXX

 涉及的控件较多,编码相对复杂;

具体实现思路如下:

一.对Form类进行二次封装(继承),定义一个MyStyleFormBase类,里面加入对窗体标题进行修改时,能自动进行多语言转换功能,具体代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public partial class MyStyleFormBase : Form
 
{
 public MyStyleFormBase()
 {
 base.TextChanged += MyStyleFormBase_TextChanged;
 }
 private void MyStyleFormBase_TextChanged(object sender, EventArgs e)
 
 {
 if (!Common.IsChsLanguage())
 { this.Text = LanguageHelper.GetLanguageText(this.Text); }
 }
 /// <summary>
 /// 弹出消息框
 /// </summary>
 /// <param name="text"></param>
 /// <param name="caption"></param>
 /// <param name="buttons"></param>
 /// <param name="icon"></param>
 /// <param name="defaultButton"></param>
 /// <returns></returns>
 protected DialogResult MessageBoxShow(string text, string caption = "提示", MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1)
 
 {
 if (!Common.IsChsLanguage())
 
 {
 
 text = LanguageHelper.GetLanguageText(text);
 caption = LanguageHelper.GetLanguageText(caption);
 }
 return MessageBox.Show(text, caption, buttons, icon, defaultButton);
 }
}

代码逻辑很简单,就是订阅一个Form.TextChanged事件,以便当根据IsChsLanguage(判断是否为简体模式)判断不是简体时,则需进行Form.Text转换

二.定义多语言支持普通控件及容器控件接口(IMultiLanguageControl、IMultiLanguageContainerControl),具体代码如下:(此处仅是为了作一个规范,支持手动设置转换控件的文本内容)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/// <summary>
/// 支持多语言普通控件(无子控件)
/// </summary>
public interface IMultiLanguageControl
{
 string DefaultLangText { get; }
 string CurrentLangText { get; set; }
}
/// <summary>
/// 支持多语言容器控件(包含子控件)
/// </summary>
public interface IMultiLanguageContainerControl
{
 Dictionary<object, string> DefaultLangTexts { get; }
 Dictionary<object, string> CurrentLangTexts { get; set; }
 Control this[string ctrlName] { get; set; }
 void SetItemCurrentLangText(string ctrlName, string langText);
event EventHandler<ChildrenAddedEventArgs> ChildrenChanged;
}
public class ChildrenAddedEventArgs : EventArgs
 
{
 public Dictionary<object, string> LangTexts { get; private set; }
 public ChildrenAddedEventArgs()
 {
 LangTexts = new Dictionary<object, string>();
 
 }
 public ChildrenAddedEventArgs(Dictionary<object, string> langTexts)
 
 { this.LangTexts = langTexts; }
 
 public string this[object key]
 {get
 {
return LangTexts[key];
 }
set
 {
 LangTexts[key] = value;
 } }}

三、实现支持多语言普通控件:基于原有标准控件(Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,RadioButton,DateTimePicker)进行二次封装,实现IMultiLanguageControl接口,各控件代码如下:

以下是MyStyleButton定义代码,MyStyleCheckBox、MyStyleGroupBox、MyStyleLabel、MyStyleLinkLabel、MyStyleTextBox、MyStyleRadioButton里面的实现代码均相同

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public partial class MyStyleButton : MyButton, IMultiLanguageControl
 
 {
 static Dictionary<string, string> LanDict = new Dictionary<string, string>();
 public MyStyleButton()
 { }
 
 public override string Text
 
 {
 
 get
 
 {
 
 if (!DesignMode && System.Threading.Thread.CurrentThread.CurrentUICulture.Name != "zh-CHS")
 {
 if (LanDict.ContainsKey(DefaultLangText))
 
 {
 return CurrentLangText;
 
 }
else
 {
 string langText = LanguageHelper.GetLanguageText(base.Text);
 LanDict[base.Text] = langText;
return langText;
 }
 
 }
 return base.Text;
 
 }
set
 {
 base.Text = value;
 }
 }
 [Browsable(false)]
 
 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 
 public string DefaultLangText
 
 {
 
 get
 
 {
 
 return base.Text;
 
 }
 }
 
 [Browsable(false)]
 
 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 
 public string CurrentLangText
 
 {
 get
 {
try
 {
 
 return LanDict[DefaultLangText];
 
 }
 catch (Exception)
 {
 
 return "";
 }
 }
 
set
 {
 
 if (System.Threading.Thread.CurrentThread.CurrentUICulture.Name != "zh-CHS")
 
 {
 
 if (LanDict.ContainsKey(DefaultLangText))
 
 {
 
 LanDict[DefaultLangText] = value;
 
 }
 
 else
 
 {
 
 LanDict.Add(DefaultLangText, value);
 
 }
 
 }
 
 }
 
 }
 
 }

二次封装这些控件的目的是:1.暴露统一的属性,便于直接遍历并赋值(需手动改变文本内容语言的情况);2.当文本内容发生改变时,能够根据语言缓存字典,快速直接的自我简繁转换,无需再次遍历;

四、实现支持多语言容器控件:基于原有标准控件(StatusStrip,TabPage,ToolStrip,DataGridView,CheckedListBox,TreeView)进行二次封装,实现IMultiLanguageContainerControl接口,各控件代码如下:

MyStyleDataGridView:

由于代码过长,请点击下载

MyStyleTabControl:

由于代码过长,请点击下载

二次封装这些控件的目的是:1.暴露统一的属性,便于直接遍历并赋值(仅当直接改变文本内容语言时需要);2.当文本内容或子控件文本内容或新增子控件发生改变时,能够根据语言缓存字典,快速直接的自我简繁转换,无需再次遍历;

五.LanguageHelper:语方转换公共类,与方案一原理相同,但相对方案一要简单很多,代码如下:

由于代码过长,请点击下载

Common.IsChsLanguage方法定义如下:

?
1
2
3
4
5
6
7
public static bool IsChsLanguage()
 
{
 
 return System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Equals("zh-CHS", StringComparison.OrdinalIgnoreCase);
 
}

多语言支持的容器类控件的实现难点是:捕获子控件文本内容的改变,由于没有现成的事件或方法,故需要通过其它的途径来实现文本内容改时能够进行处理。

以上就是本文的全部内容,有人可能会说,为何不采用资源文件的形式,原因文章一开头就说明了,是在原有的系统上,且不能改变原有的编码风格,故才花了这么大的力气来实现这个简繁转换的功能,我公司经领导确认最终采用的方案二。文中若有不足,欢迎交流,谢谢!

注:控件的实现代码都贴出来了,大家若需要的话,可以直接COPY走,另外为了系统安全,简繁体的系统截图我就不贴出来了,大家可以自行测试。

原文链接:http://www.cnblogs.com/zuowj/p/5878228.html

延伸 · 阅读

精彩推荐
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20