Localization in Whidbey
Before I describe how Windows Forms localization works in Whidbey, let us first take a look at how it works in VS 2002/2003. Consider a Form with a Button control on it. When you mark it Localizable = True in the property grid, the designer generates code for the Button that looks like this:
this
.button1.AccessibleDescription = resources.GetString("button1.AccessibleDescription");
this.button1.AccessibleName = resources.GetString("button1.AccessibleName");
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)(resources.GetObject("button1.Anchor")));
this.button1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("button1.BackgroundImage")));
this.button1.Dock = ((System.Windows.Forms.DockStyle)(resources.GetObject("button1.Dock")));
this.button1.Enabled = ((bool)(resources.GetObject("button1.Enabled")));
this.button1.FlatStyle = ((System.Windows.Forms.FlatStyle)(resources.GetObject("button1.FlatStyle")));
this.button1.Font = ((System.Drawing.Font)(resources.GetObject("button1.Font")));
this.button1.Image = ((System.Drawing.Image)(resources.GetObject("button1.Image")));
this.button1.ImageAlign = ((System.Drawing.ContentAlignment)(resources.GetObject("button1.ImageAlign")));
...
where 'resources' is an instance of the ResourceManager class. Basically, the serializer pushes the values of all properties on Button that are marked with LocalizableAttribute.Yes to the resource file and generates code to pull these values when the form is constructed. This allows the localizer to set different values for these properties based on the culture. Depending on the culture the application gets run under, the property values will be pulled back from the appropriate resource (with fallback to neutral and default culture resources when values are not found in a specific culture resource file).
So if you are developing a component, all you need to do is mark the set of properties on it that you think can vary based on culture with LocalizableAttribute.Yes and you are all set. If you are an app developer, things are even simpler - just set Localizable = True on your Form.
You will notice, though, that there is some room for improvement in this model. Here are some drawbacks:
1) Does not scale very well - Components typically have a large number of localizable properties - for example, the Button control has about 20 of them. This means that each time the form is constructed, 20 property values are retrieved from the resource file and set on the Button. For a large form with 100 controls, that adds up to 2000 properties on average. The interesting thing here is that these properties are only potentially localizable - it is possible and even likely that only a small number of them have actually been localized in different cultures. For example, if the button does not have a background image in the default culture, it most likely doesn't in other cultures as well. Yet, the code will retrieve the value (null) from the resource file on form construction.
2) Code bloat in InitializeComponent - In a non-localized form, the serializer will typically only generate code for properties that have been set to non-default values. However, when you turn localization on, it will generate code for all localizable properties, as shown above. This usually means a lot more lines of code in InitializeComponent.
3) Clutter in the resource file - Each of the localizable properties also get their values pushed into the resource files, even properties that have default values and for which the developer probably has no intention of setting non-default values.
So in Whidbey, we spent some time thinking about how we could improve this model and address these drawbacks. Obviously, we had to remain backward compatible, so we couldn't simply start over and invent a new model. I will now describe what we did come up with.
In Whidbey, we support two localization models - PropertyAssignment and PropertyReflection. PropertyAssignment is similar to the model described above. PropertyReflection indicates that the designer will use the ComponentResourceManager class to reflect on properties by name to fill them at runtime. This uses reflection at runtime so it can be slow, but it scales better for large numbers of properties with default values. The designer loader can specify how localization should work through a CodeDomLocalizationProvider, but let's not discuss those details now - what's important is that the Visual Studio designer in Whidbey uses the PropertyReflection model by default.
This means that the code in InitializeComponent will look simply like:
resources.ApplyResources(
this.button1, "button1");
As mentioned above, this call will use reflection to pull values from the appropriate resource file. The designer will only push non-defaultproperty values into the resources, so typically these will be far fewer than in the VS 2002/2003. So essentially, we are now optimizing for the common case - where a large number of properties have default values. The code in InitializeComponent is very concise and we only push non-default values into resources, so (2) and (3) are addressed too.
Comments
- Anonymous
August 03, 2004
why is there no localization provider for whidbey .... I found that localization works best for large scenarios with a DB backend ... especially with SQL caching in 2.0 - Anonymous
August 03, 2004
My biggest problem with the WinForms Designer localization implementation is that it leaves no room for custom strings/resources that aren't tied to a Form (such as an error message in a MessageBox). What I had to do was write a simple console app that was executed as a Post Build step. This app calls ResGen.exe and Al.exe on each Form's .resx file, and the custom .resx files, and replaces the satellite Assembly created by the standard build.
When I was first researching .NET localization, I hoped that something like this wasn't necessary, given that so much of localization is built right in. Would it be possible to somehow allow extra resources be added so that extra steps like this aren't necessary? - Anonymous
August 03, 2004
Yes, reflection is dog-slow, and pulls in another assembly. But I never could figure an alternative that would work with custom properties, either, except helper classes generated at design time.
Will this work with other root designers, such as VG.net www.vgdotnet.com ? We implemented localization the same way as windows forms, for the first pass. - Anonymous
August 04, 2004
Stefan: I guess you could write a IDesignerSerializationProvider that does something like this.
Andy: Yes, we have been thinking about better support for localization of project level resources. If you can, please log a suggestion through the MSDN product feedback page - that would help the team prioritize this feature request better.
Frank: This will work as long as you use the CodeDomDesignerLoader - this class adds the IDesignerSerializationProvider that handles localization. - Anonymous
August 19, 2004
The comment has been removed - Anonymous
August 25, 2004
Guy: I don't know if we have exposed an option in the VS 2005 designer to set the CodeDomLocalizationModel. I was referring to the fact that custom loaders can specify a CodeDomLocalizationModel by adding a CodeDomLocalizationProvider.
I will see if I can find out about whether there is an option to control the localization model within the VS designer. - Anonymous
August 30, 2004
Guy: To follow up on the above, it turns out we indeed don't provide a way to control the localization model in the VS designer. - Anonymous
September 21, 2005
Hyperlink to "localization models" fails - Anonymous
September 21, 2005
Looks like MSDN has relocated some of the pre-release documentation to http://msdn2.microsoft.com. I have updated the links - thanks. - Anonymous
October 15, 2005
Andy wrote:
<quote>
# re: Localization in Whidbey
Wednesday, August 04, 2004 4:30 AM by Andy
My biggest problem with the WinForms Designer localization implementation is that it leaves no room for custom strings/resources that aren't tied to a Form (such as an error message in a MessageBox).
</quote>
Yes, you can create a custom string resources that are not tired to a Form. You create a strings.resx file.
Here is a link to a MSDN article that describes how to do it for a Web Form, but the process is pretty much the same for a Windows Form.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbwlkwalkthroughlocalizingwebforms.asp
Basically, you create the strings.resx file, and then you use a ResourceManager to load the named strings in that resource file. - Anonymous
February 01, 2006
Very interesting article, Raghavendra. I take it that Brian Pepin's Localization filter (as described here http://windowsforms.net/articles/localizationfilter.aspx) isn't relevant with the PropertyReflection model?
Also, I would guess that even with the PropertyReflection model there is still resource fall back happening at times, which can affect performance. So, do the suggestions by David Gutierrez (in http://blogs.msdn.com/bclteam/archive/2005/10/11/479330.aspx) to reduce resource probing still applies?
Thanks,
Notre - Anonymous
February 01, 2006
Notre: You are right on both counts. Brian's localization filter is not required with the PropertyReflection model.
David's suggestion still applies though, since resource lookup will continue to happen for the properties that are actually localized into different cultures. - Anonymous
August 24, 2006
Localization in Whidbey is an interesting post by Raghavendra Prabhu