Resource Governors


So far, we have seen the mechanics of reading and writing individual resource files, and the support that the .NET Framework offers for this. The .NET Framework offers no further support beyond this point. There is no abstraction from the physical nature of resources. The Visual Studio Resource Editor, for example, works solely with resx files; ResGen has different code branches to handle resx files separately from resources files and txt/restext files. Furthermore, all these resource implementations are file based and dependent upon the file system. The Resource Administrator clearly cannot make such assumptions, so a layer of abstraction from the physical implementation of resources is required. This section describes this layer of abstraction so that you can either use the same implementation to write new utilities or implement new classes to allow the Resource Administrator to work with a source of resources other than those already supported.

The resource abstraction layer is made up of Resource Governors and Resources Governors. A Resource Governor manages the physical implementation of a single resource (e.g., a resx file). A Resources Governor (Resources is plural) manages the physical implementation of a collection of Resource Governors. Resources Governors implement the IResourcesGovernor interface:

 public interface IResourcesGovernor {     string[] GetInvariantCultureBaseNames();     IResourceGovernor GetResourceGovernor(         string baseName, CultureInfo cultureInfo);     CultureInfo[] GetExistingCultures(string baseName);     bool IsFileBased {get;}     bool IsDatabaseBased {get;}     bool SupportsComments { get; set; }     bool Supportsfilereferences { get; set; }     bool CommentsAreOptional { get;}     bool filereferencesAreOptional { get;}     bool Exists { get;}     string ResourceFileAbsolutePath { get; }     string ResourceFileRelativePath { get; }     void Create(); } 


The classes that implement this interface are shown in Figure 10.13.

Figure 10.13. Class Hierarchy of Classes Implementing IResourcesGovernor


Resource Governors (Resource is singular) implement the IResourceGovernor interface:

 public interface IResourceGovernor {     ResourceSet ReadResourceSet();     void WriteResourceSet(ResourceSet resourceSet);     bool ResourceExists();     bool ResourceIsReadOnly();     bool ResourceKeyExists(string key);     bool AddResourceSet(ResourceSet resourceSet1,         ResourceSet resourceSet2);     bool ReintegrateResourceSet(         ResourceSet flattenedMasterResourceSet,         ResourceSet masterResourceSet,         ResourceSet incomingResourceSet,         AcceptResourceEntry acceptResourceEntry);     object CreateDataNode(string name, object value);     object Createfileref(string fileName, string typeName);     object Createfileref(string fileName, string typeName,         Encoding textFileEncoding);     string BaseName {get;}     CultureInfo CultureInfo {get;} } 


The classes that implement this interface are shown in Figure 10.14.

Figure 10.14. Class Hierarchy of Classes Implementing IResourceGovernor


To manipulate a collection of resources, start from an IResourcesGovernor (from either a ResXResourcesGovernor, ResourcesResourcesGovernor, or DbResourcesGovernor):

 IResourcesGovernor resourcesGovernor =     new ResXResourcesGovernor(@"C:\Apps\WindowsApplication1"); 


From here, you can get a list of invariant base names; the following code adds the base names to a ListBox:

 string[] baseNames =     resourcesGovernor.GetInvariantCultureBaseNames(); foreach(string baseName in baseNames) {     listBox1.Items.Add(baseName); } 


So if the C:\Apps\WindowsApplication1 folder contained Form1.resx, Form1.fr.resx, Form1Resources.resx, Form2.resx, and Form2.de.resx files, the ListBox would contain three base names: Form1, Form1Resources, and Form2.

The following listBox1.SelectedIndexChanged event displays the invariant resource entries for the selected resource:

 private void listBox1_SelectedIndexChanged(     object sender, System.EventArgs e) {     string baseName = ((ListBox) sender).SelectedItem.ToString();     IResourceGovernor resourceGovernor =         resourcesGovernor.GetResourceGovernor(         baseName, CultureInfo.InvariantCulture);     ResourceSet resourceSet = resourceGovernor.ReadResourceSet();     ShowResourceSet(resourceSet); } 


The event gets the resource base name from the ListBox. It calls IResourcesGovernor.GetResourceGovernor to get an IResourceGovernor for the given base name for the given culture. In this example using resx files, if the base name is "Form1Resources" and the culture is the invariant culture, this would create a resource governor for the "Form1Resources.resx" file. If the culture were German, it would create a resource governor for the "Form1Resources.de.resx" file. The ShowResourceSet method simply reads through the resources in the ResourceSet in the same way as shown earlier in this chapter.

You can see from the definition of IResourcesGovernor that the interface provides an Exists property to indicate whether the source of resources exists. In a file-based solution, this is whether the path exists, but in a database solution, this is whether the database exists. In addition, IResourcesGovernor provides a Create method to create the source of resources. In a file-based solution, this would simply create the path, but in a database solution, this would create the database and add the necessary tables. Similarly, the IResourceGovernor (Resource is singular) supports ReadResourceSet and WriteResourceSet methods to read and write ResourceSets, ResourceExists, and ResourceIsReadOnly methods to determine whether the resource exists and whether it is read only (which is entirely possible if the resources are file based and are under the control of a version-control system).

Data Nodes, Comments, and File References

I confess that I am disappointed with the implementation of ResXDataNodes and ResXfilerefs. On the one hand, I am delighted that there is built-in support for comments and file references. But on the other hand, I am disappointed that the existing implementation is closed and aimed solely at resx files. It is true that only resx files support comments and file references as far as the .NET Framework is concerned, but the .NET Framework supports creating new ResourceManager classes to read and write resources in any format. Some of these formats can also support comments and file references. A database, for example, could easily support comments. Furthermore, other resource file formats such as the Oasis XLIFF XML specification have additional information that needs to be carried around with resources. The implementation of the ResXDataNode and ResXFileRef classes does not lend itself to generalization or customization. The problem is that neither class inherits from a common ancestor that could be used for generalization, nor does either class support an interface that could be used for this purpose. In addition, the ResXDataNode class is sealed, preventing inheritance.

To support comments and file references (and potentially additional information) in formats other than resx files, I have created two new classes: ResourcesData-Node and Resourcesfileref (both available in the downloadable source code for this book). The ResourcesDataNode class is a generic counterpart to the ResXDataNode class and implements the IResourcesDataNode interface:

 public interface IResourcesDataNode {     string Comment { get; set; }     string Name { get; set; }     object Value { get; set; }     IResourcesfileref FileRef { get; set; } } 


The Resourcesfileref class is a generic counterpart to the ResXFileRef class and implements the IResourcesFileRef interface:

 public interface IResourcesfileref {     string FileName { get; set; }     string TypeName { get; set; }     Encoding TextFileEncoding { get; set; } } 


The IResourceGovernor interface supports the following methods to create data nodes and file references:

 object CreateDataNode(string name, object value); object Createfileref(string fileName, string typeName); object Createfileref(string fileName, string typeName,     Encoding textFileEncoding); 


In the ResXResourceGovernor class, these methods return ResXDataNode and ResXfileref objects. In other IResourceGovernor classes, these methods can return ResourcesDataNode and ResourcesFileRef objects. In IResourceGovernor classes that do not support data nodes and file references (e.g., the Resources-ResourceGovernor class, which manages .resources files), the CreateDataNode method simply returns the value of the node, and the CreateFileRef methods throw a NotImplementedException. The IResourcesGovernor interface has a Boolean property named SupportsComments that indicates whether comments are supported by the resource format and a property named SupportsFileReferences that indicates whether file references are supported by the resource format.

The Resource Administrator uses this infrastructure to support data nodes, comments, and file references in resource formats that support these concepts. You can use this same infrastructure in the creation of your own resource-manipulation tools.




.NET Internationalization(c) The Developer's Guide to Building Global Windows and Web Applications
.NET Internationalization: The Developers Guide to Building Global Windows and Web Applications
ISBN: 0321341384
EAN: 2147483647
Year: 2006
Pages: 213

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net