Share two solutions to implement multilingual support for Winform programs

  • 2021-12-04 19:35:53
  • OfStack

Because of the company's business needs, it is necessary to add the original ERP system to support traditional languages, but the original coding mode cannot be changed, that is, ordinary programmers can't feel any difference in coding. After many times of communication with several colleagues, I have determined the following two schemes:

Scheme 1: Every time the form is loaded and displayed in the form base class, it will automatically recursively traverse the controls with text display (Button, CheckBox, GroupBox, Label, LinkLabel, TextBox, StatusStrip, TabPage, ToolStrip, RadioButton, DateTimePicker, DataGridView, CheckedListBox, TreeView, MenuStrip), and call the simple-complex conversion method according to the text attributes of different control types to convert and reset the contents of new corresponding text attributes (such as traditional content)

Advantages: Simple coding, no impact on the coding of ordinary programmers (except that the base class of form class changes from Form class to MyStyleFormBase class);

Disadvantages: Because every time you open a form, you need to traverse the controls and carry out simple and complex conversion. If there are many controls on the interface, it may lead to slow opening of the form and affect the user experience. Moreover, when the text content of child controls changes, you need to notify manually by programmers, which cannot automatically perceive and convert.

The specific implementation ideas are as follows:

1. Encapsulate (inherit) the Form class twice, Defines an MyStyleFormBase class, And add every time the form type is loaded and displayed, Controls with text display are automatically recursively traversed, According to the text attributes of different control types, simple and complex conversion methods are called to convert and reset the contents of new corresponding text attributes, In this way, when all forms inherit MyStyleFormBase class, the process of traversal and conversion is realized by default. Programmers do not need to code again, and even do not need to know that there is a process of traversal and conversion, thus improving the reusability of the code. The specific code is as follows:


public class MyStyleFormBase : Form

{

 public MyStyleFormBase()

 {

 if (!Thread.CurrentThread.CurrentUICulture.Name.Equals("zh-CHS", StringComparison.OrdinalIgnoreCase)) // If it is simplified, no conversion is required 

 {

 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>

 ///  Force notification child controls to change messages 

 /// </summary>

 /// <param name="target"></param>

 protected virtual void PerformChildrenChange(Control target)

 {

 LanguageHelper.SetControlLanguageText(target);

 }

 

 /// <summary>

 ///  Pop-up message box 

 /// </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);

 }

} 

Brief description of code logic:

1. When the current cultural area of UI is not simplified Chinese (because the program itself is based on simplified development), subscribe to the form display event Shown and the form title change event TextChanged, function: When the form is displayed, it will traverse the control and convert it into traditional Chinese, and when the title text changes, it will automatically convert it into traditional Chinese;

2. When the form is displayed, the control that subscribes to the form increases the event ControlAdded. Function: When the form is displayed, if there is code to increase the control later, it will automatically convert the control and its sub-controls into traditional ones to ensure that no one is missed;

3. Add a message prompt box method to convert simplified text into traditional text before popping up the message window;

4. Add a method PerformChildrenChange to force the child control to change the message. When the text content of a control or the addition of a child control occurs, the form itself cannot capture it, so it is necessary to call this method to traverse and convert the text content of the child control; (I don't feel very good here, but there is no better way at present. If you have a better way, please leave a comment)

2. LanguageHelper: The common class for language transformations (currently only simple and complex transformations are supported, depending on: ChineseConverter. dll) has the following code:

Because the code is too long, please click Download

This kind of logic is very simple, that is, starting from a parent control, traversing all child controls, and converting the corresponding text content of the control into simplified or traditional according to different control types, calling the method: SetControlLanguageText

The above two steps have achieved multi-language support (to be exact, simple and complex conversion). It is very simple to apply to the project, just change the default base class Form of the form into MyStyleFormBase, such as public partial class FormTest MyStyleFormBase

Scheme 2: The control directly realizes the self-conversion of each control according to the current area information + cache language dictionary

Advantages: No need to traverse, each control self-support conversion according to regional information, so the efficiency is high, and there is no influence on the coding of ordinary programmers (except that the base class of form class changes from Form class to MyStyleFormBase class, it also needs to use controls supporting multiple languages, which are encapsulated twice by ordinary controls and retain all original attributes and events);

Disadvantages: All controls with text display (such as Button, CheckBox, GroupBox, Label, LinkLabel, TextBox, StatusStrip, TabPage, ToolStrip, RadioButton, DateTimePicker, DataGridView, CheckedListBox, TreeView) need to be packaged twice, and the control system 1 is named MyStyleXXX

There are many controls involved and the coding is relatively complex.

The specific implementation ideas are as follows:

1. The Form class for 2 encapsulation (inheritance), define a MyStyleFormBase class, which adds to the form title modification, can automatically carry out multilingual conversion function, the specific code is as follows:


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>
 ///  Pop-up message box 
 /// </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 = " Prompt ", 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);
 }
} 

The code logic is very simple, that is, subscribe to an Form. TextChanged event, so that Form. Text conversion is required when it is judged not to be simplified according to IsChsLanguage (judging whether it is simplified mode or not)

2. Defines the interface (IMultiLanguageControl, IMultiLanguageContainerControl) that supports common control and container control in multiple languages. The specific code is as follows: (This is only for the purpose of making a specification, and supports manually setting the text content of the conversion control)


/// <summary>
///  Support for multilingual common controls (no child controls) 
/// </summary>
public interface IMultiLanguageControl
{
 string DefaultLangText { get; } 
 string CurrentLangText { get; set; }
}
/// <summary>
///  Support for multilingual container controls (including child controls) 
/// </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;
 } }} 

3. Implementation of common controls supporting multi-language: Based on the original standard controls (Button, CheckBox, GroupBox, Label, LinkLabel, TextBox, RadioButton, DateTimePicker), the IMultiLanguageControl interface is encapsulated twice, and the codes of each control are as follows:

The following is the definition code of MyStyleButton, and the implementation codes of MyStyleCheckBox, MyStyleGroupBox, MyStyleLabel, MyStyleLinkLabel, MyStyleTextBox and MyStyleRadioButton are all the same


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);

 }

 }

 }

 }

 } 

The purpose of encapsulating these controls twice is: 1. Expose the attributes of system 1, which is convenient for direct traversal and assignment (the case of manually changing the text content language); 2. When the text content changes, the dictionary can be cached according to the language, and the self-simplification and complexity can be quickly and directly converted without traversing again;

4. Implementation of multi-language container controls: Based on the original standard controls (StatusStrip, TabPage, ToolStrip, DataGridView, CheckedListBox, TreeView), the IMultiLanguageContainerControl interface is implemented. The codes of each control are as follows:

MyStyleDataGridView:

Because the code is too long, please click Download

MyStyleTabControl:

Because the code is too long, please click Download

The purpose of encapsulating these controls twice is: 1. Expose the attributes of system 1, which is convenient for direct traversal and assignment (only needed when directly changing the text content language); 2. When the text content or the text content of the sub-control or the newly added sub-control changes, the dictionary can be cached according to the language, and the self-simplification and complexity can be quickly and directly converted without traversing again;

5. LanguageHelper: A common class for language transformations, which has the same principle as Scenario 1, but is much simpler than Scenario 1. The code is as follows:

Because the code is too long, please click Download

The Common. IsChsLanguage method is defined as follows:


public static bool IsChsLanguage()

{

 return System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Equals("zh-CHS", StringComparison.OrdinalIgnoreCase);

} 

The difficulty of multi-language container control is to capture the change of text content of child control. Because there is no ready-made event or method, it is necessary to use other ways to realize the change of text content.

The above is the whole content of this article. Some people may say, why not use the form of resource file? The reason explained at the beginning of Article 1 is that it is on the original system and cannot change the original coding style, so it takes so much effort to realize this simple and complex conversion function. Our company has finally adopted Scheme 2 after being confirmed by the leaders. If there are any deficiencies in this article, welcome to communicate, thank you!

Note: The implementation of the control code are posted out, if you need, you can go directly COPY, in addition to the security of the system, simplified and traditional screenshots of the system I will not post out, you can test.


Related articles: