1

Using C# and WinForms, I can set a form to be localizable, put a label on it, and set text for the label in as many languages as I want. The text will be stored as string resources in one resource file for each language. Then, a user can select a language and all labels on the form will change to the correct language.

This does not seem to work for combo boxes. I can add items to a combo box for a localizable form and they will be stored in resource files using names such as ComboBox1.Item, ComboBox1.Item1, and ComboBox1.Item2, but the displayed text does not change when the combo box changes.

I've seen various suggestions for how to localize combo boxes, based on binding them to dictionaries or lists of tuples, but it seems to me that if items are stored in resource strings, there should be some more automatic way to use those resource strings. Is there?

Edit: Here is what should be a minimal example. A form has a text box, a button, a label and a combo box. The label and combo box each have resources for French (fr-FR) and Spanish (es-ES). The language name is entered in the text box, and the button changes the form's language using the following method:

private void ChangeLanguage(string lang)
{
    ComponentResourceManager crm = new ComponentResourceManager(typeof(Form2));
    CultureInfo culture = CultureInfo.CreateSpecificCulture(lang);
    Thread.CurrentThread.CurrentCulture = culture;
    Thread.CurrentThread.CurrentUICulture = culture;

    foreach (Control c in this.Controls)
    {
        crm.ApplyResources(c, c.Name, culture);
    }

}

The result is that the label's text changes but the text of the combo box items does not.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
ROBERT RICHARDSON
  • 2,077
  • 4
  • 24
  • 57

1 Answers1

1

If you close and reopen the form, everything will work fine. But if you would like to change the culture without closing the form, you need to add extra processing for ComboBox:

if (c is ComboBox)
{
    var combo = (ComboBox)c;
    var count = combo.Items.Count;
    combo.Items.Clear();
    combo.BeginUpdate();
    for (int i = 0; i < count; i++)
    {
        var number = i == 0 ? "" : $"{i}";
        var item = crm.GetString($"{c.Name}.Items{number}");
        combo.Items.Add(item);
    }
    combo.EndUpdate();
}
crm.ApplyResources(c, c.Name);

Also keep in mind that your function is just applying the resource on the controls on the form and it's ignoring nested controls. For example, if some controls are hosted on a panel, it will ignore them. To fix this issue, take a look at this post.

Note:

In general , I recommend restarting the form to apply new language, because the custom logic is not limited to ComboBox, you need specific logic for ComboBox, ListBox, ListView, TreeView, DataGridView, ToolStrip, ContextMenuStrip, MenuStrip, StatusStrip and maybe smoe other controls which I forget to mention.

In short, I believe saving the selected culture in a setting and then Application.Restart() and applying culture in Main method is what you are looking for.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Thanks very much. I'm already aware that I need to handle controls that are nested in other controls. I'll try out your code and let you know how well it works. But I see no reason to doubt that it will. – ROBERT RICHARDSON Jun 22 '18 at 18:46
  • I had to tweak your code some. My compiler (VS 2012) did not like the $, so I had to use ToString() or string.Format(). But that still doesn't seem right to me. Your code has to know that the resource file contains strings named ComboBox1.Items, ComboBox1.Items1, and so on. For a label, my code does not have to know that. I don't have to have any special code for a label. The language just changes automatically when the CurrentUICulture gets changes. I should think that ComboBoxes should behave the same way. – ROBERT RICHARDSON Jun 22 '18 at 19:06
  • `crm.GetString($"{c.Name}.Items{number}");` is equivalent to `crm.GetString(string.Format("{0}.Items{1}", c.Name, number));` as you can see the code is quite generic and name of combo box is not hard-coded. So I can say, it's enough for you to replace body of `for` loop with what I shared in the answer. – Reza Aghaei Jun 23 '18 at 03:50
  • My compiler didn't like the dollar signs. But I'm more concerned about the need to add special code to handle combo boxes, and especially about the hard-coded names of the resource keys. I shouldn't have to know about them. It's different from the effortless changing of languages for label controls. – ROBERT RICHARDSON Jun 23 '18 at 17:53
  • There is no hard-coded resource key names. If you mean what I used in `GetString`, they always follow `Items, Items1, Items2, ...` pattern. It's completely generic code, don't worry. – Reza Aghaei Jun 23 '18 at 18:31
  • In general @ROBERTRICHARDSON , I recommend to restart the form to apply new language, because the custom logic is not limited to `ComboBox`, you need specific logic for `ComboBox`, `ListBox`, `ListView`, `TreeView`, `DataGridView`, `ToolStrip`, `ContextMenuStrip`, `MenuStrip`, `StatusStrip` and maybe smoe other controls which I forget to mention. – Reza Aghaei Jun 23 '18 at 18:39
  • In short, I believe saving the selected culture in a setting and then `Application.Restart()` and applying culture in `Main` method is what you are looking for. – Reza Aghaei Jun 23 '18 at 18:42
  • Thank you. That will probably be sufficient for my needs. I'll start a new thread for my next question (if I can't find the answer anywhere else. Thanks for all the time you have spent helping me here. – ROBERT RICHARDSON Jun 24 '18 at 00:04