Windows Resource Localization Editor (WinRes)


As the name implies, the Windows Resource Localization Editor (WinRes) is a localization editor for Windows Forms resources (i.e., .resx and .resources, but not .restext and .txt). It is intended to be used by localizers to localize forms without the need for Visual Studio. WinRes is part of the .NET Framework SDK, so it is free; in comparison, only the Express editions of Visual Studio are free, and it would be impractical to insist that localizers install Visual Studio solely to localize forms. WinRes is essentially a cut-down version of the Visual Studio Forms Designer. In Figure 4.11, you can see WinRes being used to edit a form's resx file. The Properties Window on the right side is the same PropertyGrid component that Visual Studio uses. The Form Designer that occupies most of the window behaves in mostly the same way as the Form Designer in Visual Studio. The localizer needs to have the application's forms' resx (or resources) files, but at no point is the source code required. So for an external party to localize your forms, he would need to install the .NET Framework and the .NET Framework SDK; then you would need to send the localizer your application's forms' resx files. The localizer would localize these resx files and return them to you for reintegration into your application.

Figure 4.11. WinRes Editing a Default Resource


The idea is a good one, and if you are using the .NET Framework 2.0, you will probably find WinRes a useful tool. We return to WinRes in the .NET Framework 1.1 later. Figure 4.11 shows WinRes after it has opened an original, default form resource (say, Form1.resx). From here, the localizer can translate text, move and resize controls, and change fonts and other properties. The localizer cannot add new controls, delete existing controls, or add, edit, or delete events or source code.

When the localizer has finished with one target language, he can select File, Save As (see Figure 4.12) and save the work as a new culture (say, Form1.fr.resx). We return to the File Mode combo box in a moment.

Figure 4.12. WinRes File, Save As Dialog


Once saved (see Figure 4.13), WinRes shows the language in the title bar. The localizer can open any or all of the fallback resx, culture-neutral resx, or culture-specific resx files. The localizer also can create new culture versions of the resx files, so they are not limited to the cultures that developers originally supplied them with.

Figure 4.13. WinRes Editing a Culture-Neutral Resource


WinRes 1.1 Exception Messages

If you are using the .NET Framework 1.1 WinRes, you should be aware that its exception-reporting functionality is extremely limited. Most of the exception messages are not likely to be of much help in diagnosing the problem, and you are often left trying to work out by trial and error what WinRes is objecting to. Unlike WinRes in the .NET Framework 2.0, WinRes 1.1 also fails to load an entire form if a single control or property on the form cannot be processed. If you are stuck, check out Raghavendra Prabhu's blog entry at http://blogs.msdn.com/rprabhu/archive/2003/08/21/56536.aspx. Raghavendra is part of the .NET Client Team and has had to track down many WinRes problems.


Resource File Mode

The File, Save As dialog offers a File Mode combo box (see Figure 4.12). File Mode defaults to Visual Studio File Mode (VSFM) in the .NET Framework 2.0. No File Mode option exists in the .NET Framework 1.1, where WinRes can use only Single File Mode (SFM). The two modes differ in whether the files use resource inheritance: Visual Studio File Mode uses resource inheritance, and Single File Mode does not. So when you save the French version of the form using VSFM, the resx file contains only entries that are different from the parent, just as Visual Studio does. For example, if you add a button to a form, set the button's Text to Close, and set Form.Localizable to true, the form's resx file will contain these entries:

 <data name="button1.Text" xml:space="preserve">   <value>Close</value> </data> <data name="&gt;&gt;$this.Type" xml:space="preserve">   <value>System.Windows.Forms.Form, System.Windows.Forms,   Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089   </value> </data> <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">   <value>292, 266</value> </data> <data name="&gt;&gt;button1.Parent" xml:space="preserve">   <value>$this</value> </data> <data name="button1.Size" type="System.Drawing.Size, System.Drawing">   <value>75, 23</value> </data> <assembly alias="mscorlib" name="mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <data name="button1.TabIndex" type="System.Int32, mscorlib">   <value>0</value> </data> <data name="&gt;&gt;button1.ZOrder" xml:space="preserve">   <value>0</value> </data> <data name="$this.Text" xml:space="preserve">   <value>Form1</value> </data> <data name="button1.Location" type="System.Drawing.Point, System.Drawing">   <value>205, 231</value> </data> <data name="&gt;&gt;button1.Type" xml:space="preserve">   <value>System.Windows.Forms.Button, System.Windows.Forms,   Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089   </value> </data> <data name="&gt;&gt;button1.Name" xml:space="preserve">   <value>button1</value> </data> <data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">   <value>6, 13</value> </data> <data name="&gt;&gt;$this.Name" xml:space="preserve">   <value>Form1</value> </data> <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">   <value>True</value> </metadata> 


If you open the resx file in WinRes, change the button's Text to "Fermer", and save it to a new resx file using Visual Studio File Mode, the new resx will contain just a single entry:

 <data name="button1.Text" xml:space="preserve">   <value>Fermer</value> </data> 


As you would expect, these VSFM resx files are completely compatible with Visual Studio and can be exchanged between Visual Studio and WinRes without issue. Bear in mind, though, that because the resx "inherits" from its parent resx, WinRes must have access to the parent resx as well; otherwise, WinRes cannot open it (the actual error message is "Error - File : 'Form1.fr.resx' The default culture file for the current culture not found. Please add the default culture file."). I recommend using VSFM because the files are compatible with Visual Studio.

Visual Studio File Mode can be used only with .resx files; it cannot be used with .resources files because Visual Studio does not support editing of resources in .resources files.


The alternative File Mode is Single File Mode, and this is the only option available to the .NET Framework 1.1 WinRes. In Single File Mode, the resource file contains the complete resource information, which is necessary to render the form. No other resource files are necessary. So if you open a default form resource created by Visual Studio in WinRes and then save it using Single File Mode, the resource file will contain all the entries in the original resx with the values for the new culture, regardless of whether those values are the same as or different from the original resource. If you had saved the previous example using Single File Mode instead of Visual Studio File Mode, the entries would have been as follows:

 <data name="$this.Text" xml:space="preserve">   <value>Form1</value> </data> <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">   <value>292, 266</value> </data> <data name="&gt;&gt;$this.Name" xml:space="preserve">   <value>Form1</value> </data> <data name="&gt;&gt;$this.Type" xml:space="preserve">   <value>System.Windows.Forms.Form, System.Windows.Forms,   Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089   </value> </data> <assembly alias="mscorlib" name="mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <data name="button1.TabIndex" type="System.Int32, mscorlib">   <value>0</value> </data> <data name="button1.Size" type="System.Drawing.Size, System.Drawing">   <value>75, 23</value> </data> <data name="button1.Text" xml:space="preserve">   <value>Fermer</value> </data> <data name="button1.Location" type="System.Drawing.Point, System.Drawing">   <value>205, 231</value> </data> <data name="&gt;&gt;button1.Name" xml:space="preserve">   <value>button1</value> </data> <data name="&gt;&gt;button1.Type" xml:space="preserve">   <value>System.Windows.Forms.Button, System.Windows.Forms,   Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089   </value> </data> <data name="&gt;&gt;button1.Parent" xml:space="preserve">   <value>$this</value> </data> <data name="&gt;&gt;button1.ZOrder" xml:space="preserve">   <value>0</value> </data> 


Although the entries are in a different order than in the default resx file, they are all there, except for "$this.Localizable", which is assumed to be true.

WinRes 2.0 and Cultures

The list of cultures that the .NET Framework 2.0 supports depends on both the operating system on which the framework is running and the custom cultures that are installed on that machine. WinRes 2.0 cannot open resx files for unknown cultures, so if you develop using Windows XP Professional Service Pack 2 and create, say, a culture for Welsh (United Kingdom), but your localizer uses Windows Professional 2000, they will not be able to open the cy-GB.resx files for this culture. The same is true for any custom cultures that you create (e.g., Spanish (United States)). The latter problem can be solved simply by installing the required custom culture. The former problem can be solved either by creating a dummy custom culture for the missing culture and installing that culture on the target operating system, or hijacking a culture that you do not use that is known to be present on all operating systems. For example, imagine that you do not use the Malay (Malaysia) culture. You would rename all the cy-GB.resx files to ms-MY.resx files before sending the resx files to the localizer, and you would rename them all back again upon their return.

WinRes 1.1 and Visual Studio 2003 Compatibility

As has already been noted, the WinRes that ships in the .NET Framework 1.1 SDK does not offer a choice of File Modes because it supports only one: Single File Mode. This means that the culture-neutral and culture-specific files that WinRes creates are incompatible with Visual Studio, and vice versa. So if the localizer uses WinRes to open a default resx file and create a culture-neutral or culture-specific file, Visual Studio cannot open that file. And if developers create culture-neutral or culture-specific resx files using Visual Studio, WinRes cannot open those resx files. This implies that your development strategy must be an "either/or" approach in which you should commit either wholly to Visual Studio or wholly to WinRes with regard to culture-neutral and culture-specific resx files. However, with a little bit of ingenuity, this obstacle can be overcome.

Recall the earlier discussions on resource inheritance in this chapter. WinRes wants to "flatten" the resource inheritance so that each resx file is wholly contained. Visual Studio wants culture-neutral and culture-specific files to contain only the differences from their parent and, therefore, be dependent upon their parent file. The conclusion is that you can use both Visual Studio and WinRes to maintain the same resources, provided that you convert between Single File Mode and Visual Studio File Mode. The strategy works like this: The developers maintain all the resx files as part of the source code in whatever version control system you use. These resx files are used in the normal development process. When it is time to ship the resx files to the localizer to be translated, the resx files are put through a conversion process to convert them from Visual Studio File Mode to Single File Mode. The resulting files are then shipped off to the localizer. When the updated versions come back from the localizer, the files are converted back from Single File Mode to Visual Studio File Mode, and are incorporated back into the development process. This strategy is implemented in Chapter 14, "The Translator."

WinRes and Visual Form Inheritance

Visual form inheritance is a natural and obvious application of object-oriented programming; it applies the concept of class inheritance to forms. Inheritance is just as essential to form development as it is to class development. A good practice is to create a base form from which all other forms in the application inherit. This acts as a placeholder to which modifications can subsequently be made. The benefit is that to change all forms in an application, you need to make only a single change to the base form. The idea is often extended to create, say, a generic maintenance form from which all specific maintenance forms (e.g., a customer maintenance form and a contact maintenance form) inherit. There are several recommendations throughout this book for placing common code in a base form.

Using WinRes 2.0 with forms that use form inheritance requires an additional step. Before we can understand this step, we must look at the problem that WinRes 2.0 has with form inheritance. Assume that we have a form called BaseForm and a form that inherits from BaseForm, called MaintenanceForm and a form that inherits from MaintenanceForm, called CustomerMaintenanceForm. Assume also that we have French versions of each of these forms (i.e., BaseForm.fr.resx, MaintenanceForm.fr.resx, and CustomerMaintenanceForm.fr.resx). To localize the French BaseForm, the WinRes command is this:

 WinRes BaseForm.fr.resx 


This works just as you expect it to, and there is nothing special to report here. The problem comes when you try to localize the form that inherits from BaseForm:

 WinRes MaintenanceForm.fr.resx 


WinRes reports that it cannot load MaintenanceForm, and it uses a placeholder instead. WinRes shows all the controls that are specific to MaintenanceForm, but none of the controls that are inherited from BaseForm. To understand the problem (and the solution), we need to look inside the resx files. In BaseForm.resx, you find the definition for the BaseForm's Type:

 <data name="&gt;&gt;$this.Type" xml:space="preserve">   <value>System.Windows.Forms.Form, System.Windows.Forms,     Version=2.0.0.0, Culture=neutral,     PublicKeyToken=b77a5c561934e089</value> </data> 


From this entry, we learn that BaseForm inherits from System.Windows.Forms. Form, which is what we expect. In MaintenanceForm.resx, you find a similar entry for the MaintenanceForm's Type:

 <data name="&gt;&gt;$this.Type" xml:space="preserve">   <value>FormInheritanceExample.BaseForm, FormInheritanceExample,     Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</value> </data> 


From this entry, we learn that MaintenanceForm inherits from BaseForm, which we already know. However, if you consider what this entry means, you will see that MaintenanceForm inherits from the BaseForm in the FormInheritanceExample assembly. From this, you should learn that, as far as the resx file is concerned, Main-tenanceForm.resx does not inherit from the BaseForm.resx file; it inherits from the BaseForm class in the assembly. WinRes requires original assembly in addition to the MaintenanceForm.resx file to render the form correctly. When WinRes complains that it cannot load the type for the MaintenanceForm, it is complaining that it cannot find the assembly that contains the BaseForm (i.e., FormInheritanceExample.exe, in this example).

There are several solutions to this problem. Either add the assembly to the Global Assembly Cache (GAC) so that WinRes can find it, or copy the assembly into the same location as WinRes.exe. The former approach requires that you strong name your assemblies; if this is not acceptable, you must take the latter approach. The latter approach suffers from the problem that the .NET Framework SDK's bin directory rapidly becomes littered with erroneous application assemblies that have nothing to do with the .NET Framework SDK. A better solution is to turn the problem around and copy WinRes.exe to the assemblies' location and run WinRes from there.

Neither Visual Studio 2005 nor WinRes 2.0 displays localized versions of inherited controls. So when you view, say, the French form in Visual Studio 2005 or WinRes 2.0, you will see the French localized versions of all the controls introduced on that form, but the inherited controls will be shown using the fallback resources. The appearance for the developer and translator/localizer can be confusing. The resources, however, are correct, despite appearances.


WinRes 1.1 does not suffer from this issue because WinRes 1.1 does not support form inheritance. As has been noted previously, WinRes 1.1 supports Single File Mode only; as such, all resx files must contain the complete definition of the form. To localize forms that use form inheritance using WinRes 1.1 the resx files must be flattened. For example, to localize MaintenanceForm.fr.resx, a new MaintenanceForm.fr.resx file must be created that is the sum of BaseForm.resx plus BaseForm.fr.resx plus MaintenanceForm.resx plus MaintenanceForm.fr.resx.

WinRes Pros and Cons

WinRes is a great localization tool that has a number of pros and cons. On the pros side, WinRes provides localization facilities for a form in context. This means that the localizer sees the context in which translations are made and gets immediate feedback on the suitability of choices. They can see clipping problems, overlapping problems, and hot key clashes, and can decide whether the translation is correct within the context that it is being used. Don't underestimate the importance of this immediate visual feedback. From the localizer's point of view, WinRes is a great tool because the localizer can move and resize components, and change fonts, RightToLeft and ImeMode properties, and, indeed, any localizable property. Localizers like to be in control of these issues; after all, these issues make the difference between their jobs being localizers as opposed to merely translators.

On the cons side, developers might not want localizers to be able to change all the properties that they have access to. For example, developers might feel that the default resource should be designed to cope with all cultures and might adopt practices such as ensuring that controls set their AutoSize property to true and that the Font, ImeMode, and RightToLeft properties are set on an application-wide basis instead of on an individual control basis. You must establish who controls nontext properties in your resources (i.e., the developers or the localizer) before you get too far into your development. If you decide that these issues should be under developer control, there is no way you can prevent WinRes from allowing localizers to change properties. The solution is to write a utility to read in specific properties (such as Text) from the resx files coming back from the localizers, and apply them to the existing developer's resx files. In this way, only the localizer's translations are used; all other changes are dumped. Regardless of who has control over these properties, you might like to adopt the approach of applying the localizer's changes to the developers' "master" resx files so that the developers can continue to add and delete components to resx files while the localizer is working on the remote copy. See the "Reintegrating Resources" section of Chapter 14 for solutions to these problems.

Staying on the cons side, WinRes reads and writes only resx and resources files. If you have chosen to store your resources in a database (see Chapter 12, "Custom Resource Managers") or to use a different resource format, WinRes cannot be made to use it. Two possible solutions to this problem exist. One is to rewrite WinRes yourself. This is significantly more achievable in the .NET Framework 2.0 than in the .NET Framework 1.1, but it still represents a reasonable piece of work with specialized knowledge. If you were to rewrite WinRes, an additional benefit would be that you can specify which properties the localizer can see and change in the Property-Grid. The other possibility is to translate back and forth between the resx file format. So when you ship your application to the localizer, you export your resources to resx files; when the localizer returns the resx files, you import them back into your own resource source.

Another issue that might or might not bother you is that WinRes is a stand-alone executable. If you intend to invoke WinRes from within your application (see Chapter 14) so that the localizer can localize while wandering around the application, a better solution for WinRes is for it to be a component. The WinRes component would be part of the application instead of a separate executable. Apart from the neatness of this solution, this would mean that the localizer wouldn't have to install the .NET Framework SDK.

Another problem with WinRes is that if you are using the .NET Framework 1.1, you are stuck with Single File Mode and you have to write a translation facility to translate to and from Visual Studio File Mode, to allow both tools to coexist.

WinRes is revisited in Chapter 14, which covers some translator-specific issues. For a list of commercial alternatives to WinRes see Appendix B, "Information Resources."




.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