Question

I´m developing a simple C# .NET 4.0 application, and want to have it localized in several languages. However, the satellite assemblies created for localization (i.e. the de/MyApp.resources.dll) would trash its simplicity by having to drag around those dlls and their folders.

That´s why I looked for a means to include those dll into the main (and only) assembly, so only the executable needed to be sent to the end user. I came across this very promising question and gave it a shot.

After adopting the class in the suggested solution, I replaced all occurences I could find of ResourceManager with SingleAssemblyResourceManager in the .Designer.cs files using FART in a pre-build command:

fart.exe "$(ProjectDir)*.Designer.cs "System.ComponentModel.ComponentResourceManager" "SingleAssemblyComponentResourceManager"

Then I created a batch file like so:

"%ProgramFiles%\ILRepack.exe" /t:exe /out:%1TempProg.exe %1%2.exe %1es\%2.resources.dll 
IF %ERRORLEVEL% NEQ 0 GOTO END

"%ProgramFiles%\ILRepack.exe" /t:exe /out:%1TempProg2.exe %1TempProg.exe %1de\%2.resources.dll
IF %ERRORLEVEL% NEQ 0 GOTO END

"%ProgramFiles%\ILRepack.exe" /t:exe /out:%1SA_%2.exe %1TempProg2.exe %1tr\%2.resources.dll 
IF %ERRORLEVEL% NEQ 0 GOTO END

del %1%2.exe 
del %1%2.pdb 
del %1TempProg.exe
del %1TempProg.pdb
del %1TempProg2.exe 
del %1TempProg2.pdb 
rmdir %1es /S /Q 
rmdir %1de /S /Q 
rmdir %1tr /S /Q 

:END 

And called it from a post-build command:

$(ProjectDir)postbuild.bat $(TargetDir) $(TargetName)

Note: TargetName and ProjectName are the same in this case.

Built it, successfully, but it´s not working as expected... The form should be displayed in the InstalledUICulture language (if available). To accomplish this, I added this line before InitializeComponent():

Thread.CurrentThread.CurrentUICulture = CultureInfo.InstalledUICulture;

Which did the trick in the "standard" version of the program. Not anymore. However! I also added a little control to change the language at runtime, via a ComboBox. Code is as follows:

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
  if (comboBox1.SelectedItem.ToString() == "English (Default)")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
      ChangeLanguage("en");
    }
  else if (comboBox1.SelectedItem.ToString() == "Español")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("es");
      ChangeLanguage("es");
    }
    else if (comboBox1.SelectedItem.ToString() == "Deutsch")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
      ChangeLanguage("de");
    }
    else if (comboBox1.SelectedItem.ToString() == "Turkce")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("tr");
      ChangeLanguage("tr");
    }
}

private void ChangeLanguage(string lang)
{
  foreach (Control c in this.Controls)
  {
    SingleAssemblyComponentResourceManager resources = new SingleAssemblyComponentResourceManager(typeof(Form1));
    resources.ApplyResources(c, c.Name, new CultureInfo(lang));
    if (c.ToString().StartsWith("System.Windows.Forms.GroupBox"))
    {
      foreach (Control child in c.Controls)
      {
          SingleAssemblyComponentResourceManager resources_child = new SingleAssemblyComponentResourceManager(typeof(Form1));
          resources_child.ApplyResources(child, child.Name, new CultureInfo(lang));
      }
    }
  }
}

And this does change the form language. So the dlls are actually included in the exe. Why then, does InitializeComponent not load the appropriate resources? I checked the Designer code and the ResourceManager had been replaced by SingleAssemblyResourceManager.

Also, other than the form button´s texts I have a strings.resx file per language, for MessageBoxes and whatnot, and that doesn´t seem to work either way. But that might be another question.

I am aware that the original solution was designed for a NET 2.0 environment, and that the ResourceSets are obsolete, but it is my understanding that it should work, even if its not recommended.

Any pointers as to where I should look into would be awesome.

Was it helpful?

Solution

As it turns out, I was eventually able to make it work, modifying slightly the CurrentUIculture line. It would seem the code does not try parental cultures (properly) because if I set it to the generic culture (that is, "de" instead of "de-DE") it works perfectly.

Thread.CurrentThread.CurrentUICulture = new CultureInfo(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName);

I discovered this since it was the only evident difference between the ApplyResources calls from InitializeComponent() and ChangeLanguage().

Now, I do not why this is and there certainly may be a better solution out there, but it´s the only fix I found so far.

The strings part still doesnt work though :/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top