开发者

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

开发者 https://www.devze.com 2023-02-15 22:53 出处:网络
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 trans

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 开发者_如何学Python= 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...


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);


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


An alternate approach, put in the following as test code:

string[] resources = 
    System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();

In debugging, check the contents of resources to see if it matches what you are loading with ResourceManager.

Especially note, if you get something like 'MyAssembly..Resources.resources', then you will need to explicitly add 'Resources' to the ResourceManager constructor:

    private static readonly ResourceManager stringTable =
 new ResourceManager("MyAssembly.Resources", Assembly.GetExecutingAssembly());
0

精彩评论

暂无评论...
验证码 换一张
取 消