Using Resx Files with a ResourceManager

The framework provides the ability to create a ResourceManager that reads from files via CreateFileBasedResourceManager, but it looks for files with a .resources extension.  Sure I could rename all my .resx files to .resources, but what kind of hacker would I be then? 

Why use resx files you ask?  Mostly so that the end user can easily customize strings that appear in the application.  All you need is notepad, an XML editor, or better yet, Lutz Roeder's Resourcer.  The code below will look in a folder called 'Strings' (relative to your executable) for your resx files that use the naming convention 'Strings.<culture>.resx' e.g. Strings.en-US.resx, Strings.fr-FR.resx, etc.

ResxResourceManager resourceManager = new ResxResourceManager("Strings", "Strings");
string test = resourceManager.GetString("Test");

The code for the ResxResourceManager is painfully simple, and would be even simpler if Microsoft would have made the private constructor on ResourceManager protected, but whatcha gonna do?

public class ResxResourceManager : ResourceManager
{
  public ResxResourceManager(string baseName, string resourceDir)
  {
    BaseNameField = baseName;
    ResourceSets = new Hashtable();

    Type baseType = GetType().BaseType;
    BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField;

    baseType.InvokeMember("moduleDir", flags, null, this, new object[] {resourceDir});
    baseType.InvokeMember("_userResourceSet", flags, null, this, new object[] {typeof(ResXResourceSet)});
    baseType.InvokeMember("UseManifest", flags, null, this, new object[] {false});
  }

  protected override string GetResourceFileName(CultureInfo culture)
  {
    string resourceFileName = base.GetResourceFileName(culture);
    return resourceFileName.Replace(".resources", ".resx");
  }
}

posted @ Wednesday, August 01, 2007 3:45 PM


Print

Comments on this entry:

# re: Using Resx Files with a ResourceManager

Left by Jeff Brown at 8/1/2007 10:29 PM
Gravatar

Gotta love Microsoft APIs... *sigh*

# re: Using Resx Files with a ResourceManager

Left by Jørn Cornelius Olsen at 1/23/2008 1:02 AM
Gravatar

I have run into this kind of issue several times (too often). Sometimes they make the members private or internal for no discernible reason. The we either have to dublicate lots of code using Reflector or use reflection, hoping that we run in a full trust context.
Anyway for this particular problem you could alternatively have made the private constructor protected in you subclass and just call the private base constructor using reflection.
Like this:
public class ResxResourceManager:ResourceManager {
protected ResxResourceManager(string baseName, string resourceDir, Type usingResourceSet) {
Type baseType=GetType().BaseType;
BindingFlags flags=BindingFlags.NonPublic|BindingFlags.Instance;
ConstructorInfo ctor=baseType.GetConstructor(flags, null,
new Type[] { typeof(string), typeof(string), typeof(Type) }, null);
ctor.Invoke(this, flags, null, new object[] { baseName, resourceDir, usingResourceSet }, CultureInfo.InvariantCulture);
}

public ResxResourceManager(string baseName, string resourceDir)
:this(baseName, resourceDir, typeof(ResXResourceSet)) {
}
}

# re: Using Resx Files with a ResourceManager

Left by Anders Øyvind Sætre at 8/8/2008 7:34 AM

Hi. I tried using your ResxResourceManager, but didn't manage to make it work. MissingManifestResourceException etc.

But I used the lines:
Type resource = typeof(Resources.Site);
ResourceManager rm = new ResourceManager(resource);
rm.GetString(preFix + customString);

Site is a a resx-file in AppGlobalResources-folder. That worked, which was just the thing I needed. Thought I should tell, in case I need it later and forgot. :P

Thanks.

# re: Using Resx Files with a ResourceManager

Left by Anders Øyvind Sætre at 8/8/2008 7:34 AM

Hi. I tried using your ResxResourceManager, but didn't manage to make it work. MissingManifestResourceException etc.

But I used the lines:
Type resource = typeof(Resources.Site);
ResourceManager rm = new ResourceManager(resource);
rm.GetString(preFix + customString);

Site is a a resx-file in AppGlobalResources-folder. That worked, which was just the thing I needed. Thought I should tell, in case I need it later and forgot. :P

Thanks.

# Sorry

Left by Anders Øyvind Sætre at 8/8/2008 7:42 AM

Sorry about the duplicate, I use Opera, and spent some minutes on writing the comment, hopefully you can easily remove one of them.

Bet this one will be a duplicate too, then I just say "Oops!".

Your comment:



 (will not be displayed)


 
 
 
Please add 4 and 2 and type the answer here:
 

Live Comment Preview:

 
«August»
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456