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");
  }
}
«August»
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678