14

I want to make my program multilingual. I have successfully made the program multilingual via Form's Localizable and Language properties. It made some .resx files. Then I deleted non-needed files such as images (which they are the same in all langauges) etc from the .resx files.

The problem is, for example, it also generates a folder called "en" and in that folder, another generated file is called "ProjectName.resources.dll".

Is there anyway to embed this resource file to the .exe? Adding it to the resources and setting Build Action to "Embedded Resource" doesn't work also.

Thanks.

Mickey
  • 943
  • 1
  • 19
  • 41
PythEch
  • 932
  • 2
  • 9
  • 21
  • http://stackoverflow.com/questions/1453755/how-to-embed-a-satellite-assembly-into-the-exe-file – Matthew Abbott Sep 20 '11 at 17:16
  • I tried ILMerge already before posting this. Tried Assembly Linker but couldn't make it work. csc.exe gave some errors because of references and seems assembly linker causes the executable to not use resources dll. – PythEch Sep 20 '11 at 18:23
  • I don't understand why MS forces to re-invent the wheel... – PythEch Sep 20 '11 at 19:03
  • Satellite assemblies must be stored in a subdirectory that has the culture name. Each DLL contains the resources localized for that culture. This is by design, trying to change it will break localization. – Hans Passant Sep 20 '11 at 19:11
  • 1
    That is strange that you can embed and also merge everything like 3rd party dependencies/references but you can't embed a satellite assembly :( So it seems, I need to build my own language changing method... – PythEch Sep 21 '11 at 06:23
  • Telling to the program to load resources dll in the Temp directory would also solve my problem. Is there anyway to set the path? – PythEch Sep 21 '11 at 07:03
  • It seems no luck :/ Embedding the satellite assembly and extracting it before runtime with System and Hidden attributes, is only thing I can do for now. – PythEch Sep 21 '11 at 11:27
  • I've finally embedded .en.resources to the exe but it didn't make sense. I think Hans Passant is right :( – PythEch Sep 24 '11 at 08:52

2 Answers2

7

In .NET Framework 4 you can embed resource library into executable.

http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx

Just create same structure ( with localized folders 'lib/en', 'lib/de' ) and embed them.

private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) {
    AssemblyName MissingAssembly = new AssemblyName(args.Name);
    CultureInfo ci = MissingAssembly.CultureInfo;

    ...
    resourceName = "MyApp.lib." + ci.Name.Replace("-","_") + "." + MissingAssembly.Name + ".dll";
    var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)
    ...
}
IvanP
  • 263
  • 7
  • 21
  • When I add the localized folders with the dll resources, I get the error "The resource name "MyApp.MyApp.resources.dll" cannot be used more than once. If I now exclude my resx files from the project, I no longer get this error but I now get another error: "TranslatedStrings is not a member of Resources". My resx files are called "TranslatedStrings.resx", "TranslatedStrings.it.resx", etc. – JohnRDOrazio Feb 16 '16 at 08:29
2

You've asked this question a while ago and you've already accepted an answer, but still I'll try to provide an alternative way. I had the same problem and this is how I solved it:

I added the dll as a Ressource to my C#-Project and added this code to my Main-Method (the one that starts your main winform).

public static void Main(string[] args)
{
    if (InitdeDEDll()) // Create dll if it's missing.
    {
        // Restart the application if the language-package was added
        Application.Restart();
        return;
    }
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new YOURMAINFORM());
}

private static bool InitdeDEDll() // Initialize the German de-DE DLL
{
    try
    {
        // Language of my package. This will be the name of the subfolder.
        string language = "de-DE";
        return TryCreateFileFromRessource(language, @"NAMEOFYOURDLL.dll",
            NAMESPACEOFYOURRESSOURCE.NAMEOFYOURDLLINRESSOURCEFILE);
    }
    catch (Exception)
    {
        return false;
    }
}

private static bool TryCreateFileFromRessource(string subfolder, string fileName, byte[] buffer)
{
    try
    {
        // path of the subfolder
        string subfolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + (subfolder != "" ? @"\" : "") + subfolder;

        // Create subfolder if it doesn't exist
        if (!Directory.Exists(subfolder))
            Directory.CreateDirectory(subfolderPath);


        fileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\" + subfolder + (subfolder!=""?@"\":"") + fileName;
        if (!File.Exists(fileName)) // if the dll doesn't already exist, it has to be created
        {
            // Write dll
            Stream stream = File.Create(fileName);
            stream.Write(buffer, 0, buffer.GetLength(0));
            stream.Close();
        }
        else
        {
            return false;
        }
    }
    catch
    {
        return false;
    }

    return true;
}

}

Note: This will create the folder and language-dll again if it's missing, so you don't have to care anymore that you copy that folder and the dll with your exe-file. If you want it to be completely vanished this won't be the right approach of course.

Mickey
  • 943
  • 1
  • 19
  • 41