Introduction
Translating your application to multiple languages can be very hard. Fortunately, with this code you will just have to write the translated version of each sentence in a text file.
Small note: Please excuse me for providing you with a Visual Studio 2010 solution, you can modify it by opening it in Notepad and changing 2010 to 2008. It will work just fine.
How It Works
When you call the Translate("Language Here")
method, the application checks if that selected language exists. By "exists", I mean if there is any text file with the translations in the "Languages" folder. If the language exists, it opens the text file, reads the data and starts translating. If not, it creates the text file.
That text file will contain the text of all the controls on your form, followed by an equal sign. What is before the equal sign is the original text, and what is after is the translated word. Write the translation after the equal mark, and then call the Translate()
method again. You will see that your controls' text will be changed.
Using the Code
The code is well commented, but you still need to know the order of execution.
I started by writing the constructor:
public Translator(Form toTranslate, string defaultLanguage)
{
mainForm = toTranslate;
Default = defaultLanguage;
CurrentLanguage = defaultLanguage;
if (!Directory.Exists("Languages"))
{
Directory.CreateDirectory("Languages");
}
Translate(Default);
}
When we initialize the translator, we will have to pass as parameters the form we want to translate, and our default language.
We translate to the default language because, if this is the first time we call the method, the default language file does not exist. We will use the language file with the default language as a point of reference when translating from a language to another. Let's say I translate from French to Japanese, I need to translate to the default language first, and then to Japanese. Therefore, we will have a file with the default language that will contain the same words to the left and right of the equal mark.
Next, the variables we will use:
Form mainForm;
string Default;
string CurrentLanguage;
struct wordsList
{
public string Original, Translated;
};
The wordsList struct
is for a easier usage of the Words[]
array.
The rest of the code works like this:
In the Translate()
method, we check if the current language is the default language. If it isn't we translate it to the default language. If it is, then we check if the language we selected exists. If it does, we open the text file with the translation, and we load the lines into the Words[]
array:
StreamReader langIn = File.OpenText("Languages\\" + Language);
while (!langIn.EndOfStream)
{
string Line = langIn.ReadLine();
Words[number] = new wordsList();
Words[number].Original = Line.Substring(0, Line.LastIndexOf("="));
Words[number].Translated = Line.Substring(Line.LastIndexOf("=") + 1);
number++;
}
langIn.Close();
We incremented the size of the Words
array as we add items to it. The words to the left of the equal mark in the text file are the original words, and the one to the right, the translated version.
After we load the words, we loop through each control on the form and check if any of the words match the text of the control. If it does, we change the text to the translated version:
foreach (Control control in mainForm.Controls)
{
for (int i = 0; i <= number; i++)
{
if (control.Text == Words[i].Original)
{
control.Text = Words[i].Translated;
break;
}
}
}
Finally, we check if there are any new words on the form. We loop thorough the controls and check if any of the words match the text of that control. If no word matches the control's text, we add it to the Words[]
array.
Later, we rewrite the text file with all the words array. This way, if the language file does not originally exist, we create it:
bool newWords = false;
foreach (Control control in mainForm.Controls)
{
bool ok = true;
for (int i = 0; i <= number; i++)
{
if (control.Text == Words[i].Original || control.Text == "")
ok = false;
}
if (ok)
{
newWords = true;
Words[number] = new wordsList();
Words[number].Original = control.Text;
Words[number].Translated = "";
number++;
}
}
if (newWords)
{
StreamWriter langOut = new StreamWriter("Languages\\" + Language);
for (int i = 0; i <= number; i++)
{
langOut.WriteLine(Words[i].Original + "=" + Words[i].Translated);
}
langOut.Close();
}
While all of this might translate our controls, if we have a message box to show, MessageBox.Show("Hello World");
it will not be translated. The following code can be used to translate any string
inside your source code:
public string tr(string toTranslate)
{
wordsList[] Words = new wordsList[1000];
int number = 0;
Words[number] = new wordsList();
if (File.Exists("Languages\\" + CurrentLanguage))
{
#region Reading
StreamReader langIn = File.OpenText("Languages\\" + CurrentLanguage);
while (!langIn.EndOfStream)
{
string Line = langIn.ReadLine();
Words[number] = new wordsList();
Words[number].Original = Line.Substring(0, Line.LastIndexOf("="));
Words[number].Translated =
Line.Substring(Line.LastIndexOf("=") + 1);
number++;
}
langIn.Close();
#endregion
#region Translating
for (int i = 0; i <= number; i++)
{
if (toTranslate== Words[i].Original)
{
return Words[i].Translated;
}
}
#endregion
#region Adding to translation file
StreamWriter langOut = new StreamWriter
("Languages\\" + CurrentLanguage);
for (int i = 0; i <= number; i++)
{
langOut.WriteLine(Words[i].Original + "=" + Words[i].Translated);
}
langOut.WriteLine(toTranslate + "=");
langOut.Close();
#endregion
}
return toTranslate;
}
To use it:
MessageBox.Show(translator.tr("Hello World"));
It will automatically translate it to the current language.
What is NOT Implemented
This current code will not translate menus or context menus. I am planning to complete this article once I write the code for the menus.
Also, you can't add words or sentences that contain the equal sign, because the words will be read wrong:
string Line = langIn.ReadLine();
Words[number] = new wordsList();
Words[number].Original = Line.Substring(0, Line.LastIndexOf("="));
Words[number].Translated = Line.Substring(Line.LastIndexOf("=") + 1);
number++;
I hope you enjoyed this article, more coming soon.
History