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):

//// This is at the bottom of the LanguageLoader.cs file:
//publicclass ApplicationStrings
{
publicString MainForm_Button1Text = "Click me for a new dialog/form";
publicString 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.

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:

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:

/// This is at the bottom of the LanguageLoader.cs file:
//publicclass ApplicationStrings
{
publicString MainForm_Button1Text = "Click me for a new dialog/form";
publicString MainForm_Label1Text = "Hello, I'm a text label on the main form";
// these are new strings to be used in the dialog
publicString DialogForm_Label1Text = "I'm the top label";
publicString 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:

Comments and Discussions

Actually, everyone, this is a very good idea. Although the .NET Framework does have localization properties, the developer has to create the language files. This allows the user to create/customize the language files, something the .NET Framework does not provide, as far as I know.

Thanks Zac,I recently delivered an application that encompassed this approach any my customer said something to the effect of "why is it that no other applications allow me to make my own language files like yours?"

That's exactly the problem. The other approaches put the localization burden on the developer. My user wants to be the one to do the language "skinning".

I appreciate your comments. It's nice to have a positive response given the other ones!

Sorry about a late reply. I have been working on a programming application using ScintillaNET, a wrapper around the Scintilla Windows Control. I need it to be multilingual, but do not want to hard-code all strings/resources/etc in. Your idea is a great one, and it will allow my app to be multilingual for all, or almost all, languages. Thanks for the code!

I'm not trying to be defensive here, but I'm not sure why so many people refer to this as a re-inventing. I agree that there are existing approaches for localization - but I have not seen approaches where the user can create his own language file.

The requirement for my application was that the user must be able to create his own language files. In a sense, my requirement was to make a "skinnable" interface in terms of the words shown on the screen.

If there are other (better or worse) solutions that you know of, please let me know. I'd be interested in dropping this approach and adopting a better one.

I am a Chinese programmer and one of my hobbies is to localize programs I like. The most comfortable localization approaches for me are external plain text or XML language files, and also Win32/.NET resource files (or sections in compiled EXE, DLL files), since we have localization tools to facilitate our job.

Usually, a modest application will consist of several namespaces and various developers work on different parts. It is not so easy to centralize strings into a single class. Teamwork is another thing we should consider.

There's a gap to fill in this approach that the width or height of controls can not be changed with respect to text lengths among various languages. For example, please inspect the following two labels:

Refresh the screen for every [ ] seconds.

Label1Text=Refresh the screen for everyLabel2Text=seconds.

However, if I translate the above strings into Chinese, I'd have to use a different expression. Literally transated back to English will read:

Every [ ] seconds refresh the screen.

We can obviously see that Label1 should be shortened and Label2 should be lengthened. Otherwise controls on the interface will appear misplaced. We can't work around this in a solitary language file.

Another footnote for localization is file encoding which is worthy talking about with a few lines.

Thank you for taking the time to read my posting and for your informative comments. I agree that a more complete system should most certainly include your ideas. My project was rather small in scope and the approach I took was one to "get the job done". The posted solution worked well in my application, however there are definitley limitations.

You do know that complete fast and effective globalization is already built-in to the framework? It's blindingly fast compared to your approach, which will slow down horribly as the number of strings increases. Culture modules can be separate resource files and it's trivial to generate them from a customer's own translation file (in Excel or whatever). Also, other support (currencies, time date formats, numerical formats, calendars, LTR/RTL, module signing, security, sort-orders, culture-specific graphics, thread culture etc.) is already built-in. There is a lot more to globalization than strings, and it's now VERY easy to do it using the standard Microsoft methods.

Thanks for the input. I did look into this, and I do realize that there are more "professional" approaches. However Microsoft approach still requires something (a language-specific resource file) on my side. For this particular app I needed a totally "user side" approach where the customer can define and change his own strings - much like a "skin-able" user interface.

Do you know any approach to do the same on a multiplatform system?, I mean not using a Windows framework...I didn't found a multiplatform (Win, Linux, Mac) solution that shares the translation files (neither in this article), but would be very interesting...Thanks in advance,