An easy approach to UI internationalization and culture change Written on November 25, 2008, by akafazov.
I am having the task to do internationalization on a software piece written in .NET. The app has to support multiple languages in the UI and the ability to change the UI language at runtime. So the task could be broken up in two parts:
- enable UI internationalization from resources files
- add the ability to change UI language at runtime
The first part seems quite easy, as Visual Studio already has built-in all of the infrastructure required: designer support for UI internationalization, .resx files with all resources in XML format, which are compiled to dlls for deployment. Although easy to do, this involves quite a bit of work with the designer, as all controls’ properties has to be set individually for every UI culture.
This is usually accomplished with the System.Resources.ResourceManager class and the GetObject method. The code looks something like this:
buttonEnvironment.Font =
((System.Drawing.Font)(resources.GetObject(class="str">"buttonEnvironment.Font")));
The line above sets the Font property of the buttonEnvironment control, given that this property is available in the resource files. Overall, this approach has several drawbacks:
- I have to set all properties individually. This sometimes requires hundreds of lines of code
- if I want move more properties to the resources instead of hardcoding them, I have to change both the resources files and the application code
- it makes it difficult to change the current UI culture, for example if I want to change the UI language in real time. This is because, all initialization code is in the *.Designer.cs file, which is generated by the designer. The code is in the InitializeComponent() method and if I call it, I would have to reset all properties of the controls, even those which are not resource-based.
Considering those points, I went for a custom solution, which includes all the benefits of the above method and doesn’t have any of the above problems. All this is done within a couple lines of code and can work with or separately from the existing internationalization methodology. This means, if you have already started translating your UI in the old-fashioned way, you can still take advantage of the new approach.
Here is the code:
System.ComponentModel.ComponentResourceManager resources = class="kwrd">null; class="kwrd">public Form1() { InitializeComponent(); class="kwrd">this.resources = class="kwrd">new ComponentResourceManager(class="kwrd">typeof(Form1)); } class="kwrd">private class="kwrd">void radioButton_Language_CheckedChanged(class="kwrd">object sender, EventArgs e) { class="kwrd">if (radioButton_Bulgarian.Checked) { System.Threading.Thread.CurrentThread.CurrentUICulture = class="kwrd">new System.Globalization.CultureInfo(class="str">"bg"); } class="kwrd">else class="kwrd">if (radioButton_German.Checked) { System.Threading.Thread.CurrentThread.CurrentUICulture = class="kwrd">new System.Globalization.CultureInfo(class="str">"de"); } class="kwrd">else class="kwrd">if (radioButton_English.Checked) { System.Threading.Thread.CurrentThread.CurrentUICulture = class="kwrd">new System.Globalization.CultureInfo(class="str">"en"); } ApplyAllResources(class="kwrd">this); } class="kwrd">private class="kwrd">void ApplyAllResources(Control c) { class="rem">// do not paint control while changing it's properties c.SuspendLayout(); class="rem">// apply all properties for the current UI culture from the assemble resources resources.ApplyResources(c, c.Name); class="rem">// apply all resources for child controls recursively class="kwrd">foreach (Control subControl class="kwrd">in c.Controls) { ApplyAllResources(subControl); } class="rem">// resume painting c.ResumeLayout(); }
We take advantage of the System.ComponentModel.ComponentResourceManager class and the ApplyResources method, which accepts the control and it’s name as parameters. It then goes forward to set all properties for this control, if available in the .resx files. So if you decide that you want to initialize a new property from the resources, just add it there, and the code doesn’t need to be touched. The function ApplyAllResources goes trough all child controls recursively, so all hundreds of lines of code is now reduced to a couple of lines. Simple and beautiful
You can download a sample C# project here.
Read more from the Programming category. If you would like to leave a comment, click here: Comment. or stay up to date with this post via RSS, or you can
Trackback from your site.
Social Bookmark :
Technorati,
Digg,
de.licio.us,
Yahoo,
Blinkbits,
Blogmarks,
Google,
Magnolia.
Leave a Comment
If you would like to make a comment, please fill out the form below.


