Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - Cannot getting a string from ResourceManager (from satellite assembly)

I'm developing a localisable application. In my "local" resource file, I've the language used by default (english) and if possible, I load the user's preference and culture and load strings translated in is language.

So what I've done :

private static CultureInfo _culture = CultureInfo.CurrentUICulture;
private static ResourceManager _manager;

private static void ToNeutralCulture()
{
    while (!_culture.IsNeutralCulture)
    {
        _culture = _culture.Parent;
    }
}

private static void LoadCulture()
{
    ResourceManager manager = Properties.Resources.ResourceManager;

    try
    {
        ToNeutralCulture();

        string assembly = Assembly.GetCallingAssembly().GetName().CodeBase;
        string assemblyDir = Path.GetDirectoryName(assembly);
        string assemblyName = Path.GetFileNameWithoutExtension(assembly);
        string resourceFileName = string.Format(CultureInfo.InvariantCulture,
            @"{0}\{1}_{2}.dll",
            assemblyDir,
            assemblyName,
            _culture.Name.ToUpper());

        FileInfo resourceFile = new FileInfo(resourceFileName);
        if (resourceFile.Exists)
        {
            Assembly resourceAssembly = Assembly.LoadFrom(resourceFile.FullName);
            string[] manifests = resourceAssembly.GetManifestResourceNames();

            if (manifests.Length == 1)
            {
                manager = new ResourceManager(manifests[0], resourceAssembly);
            }

            using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
            {
                IDictionaryEnumerator dict = reader.GetEnumerator();
                while (dict.MoveNext())
                {
                    string key = dict.Key as string;
                    object val = dict.Value;

                    //string mVal = manager.GetString(key);
                }
            }
        }
    }
    catch (Exception ex)
    {
        Trace.WriteLine(ex.Message);

        Trace.WriteLine(string.Format(CultureInfo.InvariantCulture,
            "Fail to loading culture {0}", 
            (_culture == null) ? "--" : _culture.EnglishName));
    }

    _manager = manager;
}

Assembly is correctly loaded and the enumerator will display me all resources present in the resource file, well, works fine except :

string mVal = manager.GetString(key);

When I uncommented this line, I've an System.Resources.MissingManifestResourceException, can someone tell me why?

Thanks !


[EDIT]

Project "MyApp"

namespace MyApp
{
    Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
    string[] manifests = resourceAssembly.GetManifestResourceNames();

    if (manifests.Length == 1)
    {
        manager = new ResourceManager(manifests[0], resourceAssembly);
    }

    // Throws the exception
    manager.GetString("PleaseCallIT", null);

    // Works
    using (ResourceReader reader = new ResourceReader(resourceAssembly.GetManifestResourceStream(manifests[0])))
    {
        IDictionaryEnumerator dict = reader.GetEnumerator();
        while (dict.MoveNext())
        {
            string key = dict.key as string; // PleaseCallIT
            object val = dict.value; // Please call IT.
        }
    }
}

Project "MyApp_FR" (Resources.Designer.cs auto-generated file)

namespace MyApp.Properties {
    // ...
    internal static string PleaseCallIT {
        get {
            return ResourceManager.GetString("PleaseCallIT", resourceCulture);
        }
    }
}

I don't understand...

like image 944
Arnaud F. Avatar asked Dec 13 '22 15:12

Arnaud F.


2 Answers

I found why, hope this will help someone that is in the same case.

So, I looked in MyApp_FR.dll the code generated to use the Resource file, it is :

new global::System.Resources.ResourceManager("MyApp_FR.Properties.Resources", typeof(Resources).Assembly);

but when retrieving the manifest file names, I got :

"MyApp_FR.Properties.Resources.resources"

Seems to be there is a .resource to much in this room... By removing it, I can use my ResourceManager normally, all works fine...

Final code :

Assembly resourceAssembly = Assembly.LoadFrom(resourceFileName);
string[] manifests = resourceAssembly.GetManifestResourceNames();
if (manifests.Length == 1)
{
    string manifest = manifests[0].Replace(".resources", string.Empty);
    manager = new ResourceManager(manifest, resourceAssembly);
}

// Works !
manager.GetString("PleaseCallIT", null);
like image 69
Arnaud F. Avatar answered Jan 20 '23 18:01

Arnaud F.


From Microsoft Support:

This problem occurs if you use a localized resource that exists in a satellite assembly that you created by using a .resources file that has an inappropriate file name. This problem typically occurs if you manually create a satellite assembly:

Try this KB:

http://support.microsoft.com/kb/839861

like image 39
ukhardy Avatar answered Jan 20 '23 17:01

ukhardy