简体   繁体   中英

WinForms localization. How to change the language of a Menu

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 ZRT 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?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM