I have been searching about how to change the language of a Form that has the Localizable
attribute set to true.
https://msdn.microsoft.com/en-us/library/system.threading.thread.currentuiculture(v=vs.110).aspx
This is to set the language of the form, but this needs to be set before we instantiate the form. This cannot be called after this event.
Searching for information, I have seen the following question: https://stackoverflow.com/a/11738932/3286975 but, as a comment said, I have controls inside of a TabControl and a MenuStrip, so they aren't affected.
I have tried to modify this, by getting all the controls of the Form without luck.
In this menu I call the following callback:
private void englishToolStripMenuItem_Click_1(object sender, EventArgs e)
{
string lang = (string) ((ToolStripMenuItem) sender).Tag;
base.Culture = CultureInfo.CreateSpecificCulture(lang);
}
private void spanishToolStripMenuItem_Click(object sender, EventArgs e)
{
string lang = (string) ((ToolStripMenuItem) sender).Tag;
base.Culture = CultureInfo.CreateSpecificCulture(lang);
}
I change the Culture by using the Tag.
When I click it nothing happens. Also, I have modified a little bit the ApplyResources method from the mentioned answer.
private void ApplyResources(Control parent, CultureInfo culture)
{
this.resManager.ApplyResources(parent, parent.Name, culture);
foreach (Control ctl in parent.IterateAllChildren())
{
//this.ApplyResources(ctl, culture);
this.resManager.ApplyResources(ctl, ctl.Name, culture);
}
}
Where IterateAllChildren is the following: https://stackoverflow.com/a/16725020/3286975
Also, I tried with (System.LINQ): Controls.OfType<Label>()
(because I have one Label to test this) without luck...
But when I select the Spanish language, no text is changed.
So maybe, I'm failling with the childrens. Or maybe by calling the method CreateCulture
, I don't know.
Thanks in advance!
EDIT:
I have tested to get the Resource Manager of my form by the Culture Info and it returns the default one everytime:
ResourceSet resourceSet = new ResourceManager(typeof(frmCredentials)).GetResourceSet(new CultureInfo(lang), true, true);
foreach (DictionaryEntry entry in resourceSet)
{
string resourceKey = entry.Key.ToString();
object resource = entry.Value; //resourceSet.GetString(resourceKey);
if (resource.GetType().Equals(typeof(string)))
Console.WriteLine("Key: {0}\nValue: {1}\n\n", resourceKey, (string) resource);
}
Where new CultureInfo(lang)
, I haved tested also: new CultureInfo("es")
& Thread.CurrentThread.CurrentCulture
(CurrentUICulture) without luck. Is like it never exists or is replaced, but in my design and file explorer I can see the files.
EDIT2:
Maybe is because I'm using ILMerge to merge all dlls in a unique one. I'm reviewing this: Single-assembly multi-language Windows Forms deployment (ILMerge and satellite assemblies / localization) - possible?
Reply to EDIT2:
Yep, deleting ILMerge the problem is solved, and the first solution I gave resolves this. But for some reason, Spanish language is taken as the default language, and when I tried to get the resourceset from it, it didn't return me nothing.
Aso, I have set the Localizable attribute to false, and it didn't created a default resx file with values. I don't know if this is a good practice.
I will try something new...
After some tries, I have realized that several things are failing.
I have to say also that all the given help in this question is greatly appreciated, and also that the LocalizedForm snippet is very useful.
The first issue is that I have realized is that the controls that are under a level of more than 1 in the child hierarchy with this solution doesn't work.
And iterating over all the controls is a expensive task. Maybe mine is worst but has less iterations (because I only seach for Controls with Text)
What I do is the following, first, I search for the ResourceManager, take care! Because here is the second issue and is that if you use
CultureInfo.CreateSpecificCulture
insteadCultureInfo.GetCultureInfo
in some cases a new culture will be created and default values will be returned (Form1.resx
values instead ofForm1.es.resx
values (for example)).Once we have loaded all the value from the resx file, we iterate over all of them, and we delete the double >> (it appears in some cases) and we get the name of those Controls that only have declared the Text attribute.
The next step is find the Control and replace its Text...
Well, I have a little mess with the derived classes, that's why I created a try-catch system, because, Controls.Find search in all the Derived Classes I would prefer to be a little bit more specific but I don't know how... (That's why I created this question)
With this we haven't to save any object because we won't clear and recreate them.
The main problem here wasn't the way I was doing this, because it was correct. The problem is that Assemblies merged do weird things when you call for example this:
ResourceSet resourceSet = new ComponentResourceManager(GetType()).GetResourceSet(value, true, true);
The
value
will be the default... Something like that this Culture doesn't exist, and is because, the merged Assembly can't find the resx file.So, I will try
AppDomain.CurrentDomain.AssemblyResolve
that @ScottChamberlain has suggested to me. Or ILRepack maybe.Any help for optimization or ideas (in comments) of why this doesn't work will be appreciated!