WinForms localization. How to change the language of a Menu

走远了吗. 提交于 2020-01-13 19:28:24

问题


EDIT: Although useful, the "duplicate" question does not give an answer to this question. First, the main theme here is Menus, so please don't mark this question duplicate to a question that is not.

I have been trying to understand correctly how to localize an application. Right now I have a form with a label, a menu and a listbox. I have localized the form so that now I have three resx files.

I used Z.R.T. answer to implement the listbox to change the language on runtime. Instead of his implementation of ApplyLocalization I used

 public void ApplyLocalization(CultureInfo ci)
   {
    //button1.Text = Properties.Resources.button;
    ComponentResourceManager componentResourceManager = new ComponentResourceManager(this.GetType());

    foreach (Control c in this.Controls)
      {
       componentResourceManager.ApplyResources(c, c.Name, ci);
       }

    }

With that I can succesfully translate the label only.

Debugging the process I can see that there are three Controls: (The listbox, the label and the menu). For the listbox ApplyResources do nothing. For the label it does change the language of the label. The problem is for the menu. When c is the menuStrip, ApplyResources only applies it to the menuStrip, but not the menu options that are the ones that needs to be translated. (Actually the same thing happens to the listbox since the contents of the listbox are not translated either)

My question is how can I apply the resources to the internals (submenus) of a menu so that the menu contents also gets translated?


回答1:


There are a few problems in your function:

  • Your function is just loop over the direct child controls of the form. It's not checking all the controls in controls hierarchy. For example controls which are hosted in containers like panel are not in Controls collection of the form.

  • Your function is also missing components like ContextMenu which are not in Controls collection of the form.

  • The function is treating all controls in the same way, while some controls need a custom logic. The problem is not limited to Menu or ListBox. You need specific logic for ComboBox, ListBox, ListView, TreeView, DataGridView, ToolStrip, ContextMenuStrip, MenuStrip, StatusStrip and maybe some other controls which I forget to mention. For example you can find the logic for ComboBox in this post.

Important Note: I believe saving the selected culture in a setting and then closing and reopening the form or the whole application and applying culture before showing the form or in Main method is a better option.

Anyway, here I'll share a solution here. Be informed that the solution will not solve all the problems that I mentioned above, but solves theproblem for MenuStrip and ToolStrip.

While you may learn new things from the following piece of code, I assume it's just for learning purpose. In general I advise you to read the Important note again!

Step 1 - Find all items of the MenuStrip or ToolStrip:

using System.Collections.Generic;
using System.Windows.Forms;
public static class ToolStripExtensions
{
    public static IEnumerable<ToolStripItem> AllItems(this ToolStrip toolStrip)
    {
        return toolStrip.Items.Flatten();
    }
    public static IEnumerable<ToolStripItem> Flatten(this ToolStripItemCollection items)
    {
        foreach (ToolStripItem item in items)
        {
            if (item is ToolStripDropDownItem)
                foreach (ToolStripItem subitem in 
                    ((ToolStripDropDownItem)item).DropDownItems.Flatten())
                        yield return subitem;
            yield return item;
        }
    }
}

Step 2 - Create a method to get all controls:

using System.Collections.Generic;
using System.Windows.Forms;
public static class ControlExtensions
{
    public static IEnumerable<Control> AllControls(this Control control)
    {
        foreach (Control c in control.Controls)
        {
            yield return c;
            foreach (Control child in c.Controls)
                yield return child;
        }
    }
}

Step 3 - Create the ChangeLanguage method and add the logic for different controls, for example in the following piece of code, I've added the logic for MenuStrip which is deriving from ToolStrip:

private void ChangeLanguage(string lang)
{
    var rm = new ComponentResourceManager(this.GetType());
    var culture = CultureInfo.CreateSpecificCulture(lang);
    Thread.CurrentThread.CurrentCulture = culture;
    Thread.CurrentThread.CurrentUICulture = culture;
    foreach (Control c in this.AllControls())
    {
        if (c is ToolStrip)
        {
            var items = ((ToolStrip)c).AllItems().ToList();
            foreach (var item in items)
                rm.ApplyResources(item, item.Name);
        }
        rm.ApplyResources(c, c.Name);
    }
}

Step 4 - Call the ChangeLanguage method:

ChangeLanguage("fa-IR");


来源:https://stackoverflow.com/questions/52178064/winforms-localization-how-to-change-the-language-of-a-menu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!