Introduction
A recent application of mine required multi-lingual capabilities. The user of the software is happy to provide the language-specific strings for his language. I just need to give him the file. Multi-lingual applications and localization are discussed in lots of places, but I've not seen any easy approaches whereby the end user can create his own language by simply creating and editing a new “language file”. This skin-able approach to language provides a great deal of user customization, yet minimal expense in terms of hiring translators.
Background
This approach created an interesting programming challenge. What would this language file look like? How would the application load the language file and update the controls? What happens when I create new forms and controls in the future versions of the application (which have new text items) and the user is using an old language file? How do I access the “language library” from anywhere in my application without having to pass it from form to form?
These questions were basically answered by two words: Reflection and Singleton. OK, there are a lot more words that apply, but those were the two concepts that helped me finally get to a solution that I liked.
So without any further ado, here’s the approach.
- The
LanguageLoader
is a Singleton class that contains the applications strings and can read/write language files. This class can be accessed from anywhere in the project. If you update it from anywhere in the application, the updates are available elsewhere. This Singleton stuff is cool!
- You add strings to an “
ApplicationStrings
” class. This class is accessed by the LanguageLoader
(for loading and saving) via reflection. This reflection stuff is pretty cool too!
- For easy updating of controls, it helps if each form has a method that updates all of the strings on the form. This method can be called in the form’s “
Load
” method and can also be called when the language is changed by the user.
Using the Code
So let’s do it:
- Create a Windows Forms Application.
Let’s add a label. Visual Studio calls it “label1
.” I'm not feeling too creative, so let’s stay with that. We can also add a button and call it “button1
”.
- Now for the fun part. Add
LanguageLoader
and IniAccess
to the solution. In the LangaugeLoader
file, fill in the default value for the strings. (Look for the ApplicationStrings
class at the bottom of the file).
The strings need to be of the format: ParentForm_StringName
(more on this later):
public class ApplicationStrings
{
public String MainForm_Button1Text = "Click me for a new dialog/form";
public String MainForm_Label1Text = "Hello, I'm a text label on the main form";
}
- To get these strings to show up on the main form, add this method.You can call it from the Form’s “
Load
” method or anytime you want to update the strings.
private void UpdateLanguageOnControls()
{
button1.Text = LanguageLoader.appStrings.MainForm_Button1Text;
label1.Text = LanguageLoader.appStrings.MainForm_Label1Text;
}
private void Form1_Load(object sender, EventArgs e)
{
UpdateLanguageOnControls();
}
That’s basically it. Once the application runs, the file “EnglishUS.lng” will be created in the application folder. (Note: Vista may not allow the file to be written in the “Program Files” folder).
Creating a New Language
If you edit the LNG file (using NotePad or something similar), the edited strings will show up in the application. The language file is of the traditional INI format where each “section” is the name of the form and the “key” is the string’s name. The section and key are extracted from the string variable’s name. Do you remember the ParentForm_StringName
format from above? ParentForm
becomes the section and StringName
becomes the key.
-------- contents of EnglishUS.lng --------
[MainForm]
Button1Text=Click me for a new dialog/form
Label1Text=Hello, I'm a text label on the main form
-------------------------------------------------
To create a new language, simply open an existing language file and save it as a new name and change the strings accordingly:
-------- contents of PigLatin.lng --------
[MainForm]
Button1Text=ickClay emay orfay away ewnay ialog/formday
Label1Text=elloHay, I'mway away exttay abellay onway ethay ainmay ormfay
-------------------------------------------------
Applying the Language to a Dialog or Sub-Form
If a sub-form (dialog, etc.) needs language access, you can use the same approach that you used in the main form:
Add the sub-form’s strings to the ApplicationStrings
class:
public class ApplicationStrings
{
public String MainForm_Button1Text = "Click me for a new dialog/form";
public String MainForm_Label1Text = "Hello, I'm a text label on the main form";
public String DialogForm_Label1Text = "I'm the top label";
public String DialogForm_Label2Text = "I'm the bottom label";
}
Put the strings on the form by creating and calling a “UpdateLanguageOnControls
” method just like the one on the main form:
private void UpdateLanguageOnControls()
{
label1.Text = LanguageLoader.appStrings.DialogForm_Label1Text;
label2.Text = LanguageLoader.appStrings.DialogForm_Label2Text;
}
private void DialogForm_Load(object sender, EventArgs e)
{
UpdateLanguageOnControls();
}
Closing
So there it is: a quick (and perhaps dirty) approach to multi-lingual apps that allows users to create their own languages. I'd love your feedback so let the postings fly! Or in other words: oSay erethay itway isway: away uickqay and(ay erhapspay irty)day approachway otay ulti-lingualmay appsway atthay allowway usersway otay eatecray Special thanks to the Pig Latin converter at: http://www.onlineconversion.com/pig_latin.htm.
History
- 25th September, 2009: Initial post