The example of the task used for demonstration
We have a Windows Forms application, which must support three languages: English, Italian, and Russian. So, in the status bar of the application, the following string should be printed: "Date: {current date}", in the language of the user's locale.
The solution given by Microsoft
Microsoft recommends to do the following:
- Create one .resx file for each of the language supported for storing the text resources.
- Add in each of the files, a string with a common resource identifier, for example, "
IDS_DATE
", with the text written using the proper language. For example, for the English version, the text will be "Date: {0}". - Write the code like the following:
string messageTemplate = resourceManager.GetString( "IDS_DATE" );
string finalMessage = string.Format( messageTemplate, new DateTime() );
Note
It is possible to find the information about the usage of resources in .NET. For example, here.
It seems that everything is OK but let's look at the code more attentively:
- If to change the name of the identifier in the resources or if there is a mistake in writing of this name in the code, the compiler does not report about any error, as in the code the name is stored as a string.
- Often the textual resources are the templates of the messages. These templates contain some parameters, and as the templates are declared in a separate file, it creates an additional risk of the fact that the number or the sequence of the parameters during the formatting of the template will be incorrect.
ResxWrap as the tool for resolving such problems
The tool ResxWrap - the generator of class-wrappers for textual resources from .resx files - was created for resolving this type of problems. The class-wrappers give the user the possibility to work with resources in a much more convenient manner. For the above example, it would be enough to write:
string finalMessage = generatedWrapper.IDS_DATE( new DateTime() );
What doest it change?
- Instead of two lines of code, we have only one. It is not bad to reduce twice the amount of the routine code.
- If the name of the identifier is changed, we are safe now, as the compiler will report about an error, because the class-wrapper will not contain any more, the method
IDS_DATE
. - If we change the number of arguments in the textual template "
IDS_DATE
", it will not also be a problem. The compiler will give us again a message about an error, as the signature of appropriate method of the class-wrapper will be changed as well. - While editing the call of the method, it is possible to look at the reference for every parameter to be sure that the sequence is correct.
How to generate the class-wrapper
ResxWrap is a tool managed by command line arguments. Returning to our example, having supposed that our project has the namespace by default "SampleApp", the files of the project are located in the directory "C:\My Projects\SampleApp", and the file of resources is called "StringTable.resx". So, for generating the class-wrapper, it will be enough to launch the tool with the following arguments:
ResxWrap SampleApp "C:\My Projects\SampleApp\" StringTable
When generating is over, in the directory of the project, a new file will appear named "__StringTable.cs", which will contain a definition of the class with the same name and declared in the same namespace.
Of course, it is also possible to write a .bat file, and every time after changing in "StringTable.resx" to launch the generation again, but for safety, it is better to add one line in Pre-build Event Command Line in the settings of the project. For this, it is enough to write in the case of our example:
ResxWrap SampleApp ${ProjectDir} StringTable
Let's look inside
The generated class contains:
- The constructor for the initialization of the protected field of the type
System.Resources.ResourceManager
; - Read-only static fields with the names for each identifier of the resource declared in .resx file;
- The methods and read-only properties, returning textual values for every resource.
If the textual string contains parameters, then the signature of the method will contain the appropriate number of parameters accompanied with documentation comments. The body of the method besides the loading of the template of the textual message will also contain the call of String.Format
preparing the final version of the message.
Resume
So, if you have decided to use ResxWrap tool for development of a project, you must:
- Add a call of the tool ResxWrap in the file of the project;
- Recompile the project;
-
Add the generated file of the class-wrapper to the list of the project files;
- Create an instance of the class-wrapper;
- Call the appropriate method or property for extracting necessary textual resources.