Click here to Skip to main content
11,484,162 members (66,658 online)
Click here to Skip to main content

.NET Resource (.resx file) Translator

, 27 Aug 2012 CPOL 85.4K 4.6K 125
Rate this:
Please Sign up or sign in to vote.
A .NET resource (.resx file) translator. English to any other language.

Main Window

Introduction

Apart from the default language of the application (generally English), your software should support different languages since people prefer using software with a native language interface. For the worldwide distribution of an application, you need to translate the user interface to as many languages as possible. When you do that, you can say the application is Globalized.

The first step to globalize an application is setting the Localizable property of the Windows Form to true. When you create a Forms based Windows application, there is a resource (.resx) file associated with each form. This resource file is specific to a language which contains all locale specific details of that form.

In this article, we will discuss how to generate a different language resource file from the default English resource file.

Background

I have posted an article on Globalization/Internationalization too. Before reading this article, please read: Globalization, Internationalization (I18N), and Localization using C# and .NET 2.0.

Using the Code

The text translation is based on the translation provided by the Google Translator website (http://translate.google.com).

Although the Google Translator .NET API classes are available, The usage of these APIs are not free now. So I have updated the source code to read the translated data directly from website. 

Here, we have the Translator class which basically uses the Google Translator Website to translate the text. It sends the text with appropriate parameters to the website and extracts translated text from the response. 

/// <summary>
/// Translates the given text in the given language.
/// </summary>
/// <param name="targetLanguage">Target language.</param>
/// <param name="value">Text to be translated.</param>
/// <returns>Translated value of the given text.</returns>
public static string Translate(Language targetLanguage, string text)
{
    string translatedValue = string.Empty;
    try
    {
        string languagePair = string.Format("en|{0}", targetLanguage.Value);
        // Get the translated value.
        translatedValue = TranslateText(text, languagePair);
        Trace.WriteLine(string.Format("Given Text is {0} and Target Language is {1}. Result - {2}.",
            text, targetLanguage.Name, translatedValue));
    }
    catch (Exception ex)
    {
        string errorString = "Exception while translating, please check the connectivity." + ex.Message;
        Trace.WriteLine(errorString);
        throw new WebException(errorString);
    }
    return translatedValue;
}

Once the given text is translated in the target language, the only work left is creating a .resx file and adding the text into that file. The code given below performs this task:

/// <summary>
/// Translates the given resx in the specified language. new language resx
/// file will be created in the same folder and with the same name suffixed with
/// the locale name.
/// </summary>
/// <param name="targetLanguage">Language in which text to be translated.</param>
/// <param name="resxFilePath">Source resx file path</param>
public static void Write(Language targetLanguage, 
       string resxFilePath, bool onlyTextStrings)
{
    if (string.IsNullOrEmpty(resxFilePath))
    {
        throw new ArgumentNullException(resxFilePath, 
          "Resx file path cannot be null or empty");
    }
    if (targetLanguage == null)
    {
        throw new ArgumentNullException(targetLanguage, 
                  "Target Language cannot be null");
    }
    using (ResXResourceReader resourceReader = new ResXResourceReader(resxFilePath))
    {
        //string locale = targetLanguage.ToString().Substring(0, 2).ToLower();
        string locale = targetLanguage.Value.ToLower();
        #region Create locale specific directory.
        //string outputFilePath = Path.Combine(Path.GetDirectoryName(ResxFilePath),
            locale);
        //if (!Directory.Exists(outputFilePath))
        //{
        // Directory.CreateDirectory(outputFilePath);
        //} 
        #endregion
        // Create the required file name with locale.
        string outputFilePath = Path.GetDirectoryName(resxFilePath);
        string outputFileName = Path.GetFileNameWithoutExtension(resxFilePath);
        outputFileName += "." + locale + ".resx";
        outputFilePath = Path.Combine(outputFilePath, outputFileName);
        // Create a resx writer.
        using (ResXResourceWriter resourceWriter = new ResXResourceWriter(outputFilePath))
        {
            foreach (DictionaryEntry entry in resourceReader)
            {
                string key = entry.Key as string;
                // Check if the Key is UI Text element.
                if (!String.IsNullOrEmpty(key))
                {
                    if (onlyTextStrings)
                    {
                        if (!key.EndsWith(".Text"))
                        {
                            continue;
                        }
                    }
                    string value = entry.Value as string;
                    // check for null or empty
                    if (!String.IsNullOrEmpty(value))
                    {
                        // Get the translated value.
                        string translatedValue = Translator.Translate(targetLanguage,
                            value);
                        // add the key value pair.
                        resourceWriter.AddResource(key, translatedValue);
                    }
                }
            }
            // Generate resx file.
            resourceWriter.Generate();
        }
    }
}

Since the text translation happens at the Google website, it takes time to fetch the text and get the translated text. I have used the BackgroundWorker class to do this job. The BackgroundWorker initiates the process by Binding the channel and then sending and receiving the text with the specified languages.

The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.

private void myStartButton_Click(object sender, EventArgs e)
{
    *                 
    *            
    myBackgroundWorker.RunWorkerAsync(languages);        
    *
    *
}
void myBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    Language[] languages = e.Argument as Language[];
    PerformTranslation(languages, worker, e, myOnlyTextCheckBox.Checked);
}

Once you hit the Start Translation button on the UI, the BackgroundWorker starts the text translation. In case you want to abort the background process, call the CancelAsync() method and then check for the CancellationPending flag on the BackgoundWorker instance, and set DoWorkEventArgs - e.Cancel to true.

/// <summary>
/// Perform translation for each selected language for all selected resx files.
/// </summary>
/// <param name="languages">selected languages.</param>
/// <param name="worker">BackgroundWorker instance.</param>
/// <param name="e">DoWorkEventArgs.</param>
/// <param name="onlyTextStrings">true; to convert only '.Text' keys valus.</param>
private void PerformTranslation(Language[] languages, 
        BackgroundWorker worker, DoWorkEventArgs e, bool onlyTextStrings)
{
    int totalProgress = 0;
    foreach (string file in mySelectedFiles)
    {
        foreach (Language targetLanguage in languages)
        {
            if (worker.CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                ResxWriter.Write(targetLanguage, file, onlyTextStrings);
                totalProgress++;
                worker.ReportProgress(totalProgress);
            }
        }
    }
}

There could be two types of .resx files. When you set the Localizable property to true, the entire information of the form (specific to a locale) is moved to the .resx file, including location, size, etc. This is an auto generated resource file which contains the entries other than the UI text strings. Another option could be a user defined resource file, which contains only strings.

In the Resx Translator application UI, you can select the 'Convert only .Text key' checkbox in order to convert only strings of the auto generated .resx files. Translating entries other than strings can cause some serious errors. In the case of the user defined resource file, you can leave this option.

There are two components in this application - the Translator and the Config UIs. In the Translator UI, you can browse and select the .resx files. In the Config UI, you can select the languages in which you want to translate your English .resx files.

Once the translation starts, the progress bar and the status bar will indicate the whole process. Hope this tool will help you to generate resource files in different languages. Wink | ;)

Points of Interest 

It reads the translated data directly from website. You should have an active internet connection to get the translated data.  

Please go through the code for better understanding of translation/extraction process. 

Sometimes during development phase you may need to verify whether the application is truly localized (all UI Text is getting translated to target language/culture) or not. You can do this by just tweaking the Translator class code. For a particular language instead of actually translating the text just return the reversed text (or prefix/suffix one character). Now after loading the application in that particular language you can easily validate all the translated texts in the UI.  

History 

  • 23/08/2012 - Modified code to read translated data from Google Translator website.  
  • 08/02/2010 - Added details of APIs.
  • 04/02/2010 - Uploaded source code.
  • 04/02/2010 - Initial post.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Kumar, Ravikant INDIA Bangalore
Software Developer (Senior) Philips
India India
Have been working with computers since the early 00's. Since then I've been building, fixing, configuring, installing, coding and designing with them. At present I mainly code windows applications in C#, WCF, WPF and SQL. I'm very interested in Design Patterns and try and use these generic principles in all new projects to create truly n-tier architectures. Also I like to code for making the User Interface very attractive...
Follow on   Twitter

Comments and Discussions

 
QuestionDoes not HTML encode and HTML decode the data Pin
Gregory Morse20-May-14 22:18
memberGregory Morse20-May-14 22:18 
GeneralMy vote of 4 Pin
samthec2-Apr-13 5:00
membersamthec2-Apr-13 5:00 
SuggestionGIT hub more collaborative working Pin
Bryan Avery1-Nov-12 23:56
memberBryan Avery1-Nov-12 23:56 
QuestionError Pin
Rene Laviolette4-Sep-12 3:53
memberRene Laviolette4-Sep-12 3:53 
AnswerRe: Error Pin
Kumar, Ravikant INDIA Bangalore4-Sep-12 19:35
memberKumar, Ravikant INDIA Bangalore4-Sep-12 19:35 
Questionthis is very useful utility which saves lot of hours Pin
harikakakkireni30-Aug-12 22:04
memberharikakakkireni30-Aug-12 22:04 
AnswerRe: this is very useful utility which saves lot of hours Pin
Kumar, Ravikant INDIA Bangalore31-Aug-12 0:17
memberKumar, Ravikant INDIA Bangalore31-Aug-12 0:17 
GeneralMy vote of 4 Pin
Christian Amado27-Aug-12 10:22
memberChristian Amado27-Aug-12 10:22 
GeneralRe: My vote of 4 Pin
Kumar, Ravikant INDIA Bangalore31-Aug-12 0:22
memberKumar, Ravikant INDIA Bangalore31-Aug-12 0:22 
Questioncomment Pin
emrankhan24-Aug-12 9:37
memberemrankhan24-Aug-12 9:37 
AnswerRe: comment Pin
Kumar, Ravikant INDIA Bangalore31-Aug-12 0:21
memberKumar, Ravikant INDIA Bangalore31-Aug-12 0:21 
GeneralA good idea, but... Pin
Matt T Heffron23-Aug-12 7:42
memberMatt T Heffron23-Aug-12 7:42 
GeneralRe: A good idea, but... Pin
Kumar, Ravikant INDIA Bangalore23-Aug-12 18:35
memberKumar, Ravikant INDIA Bangalore23-Aug-12 18:35 
Questiontry this instead.. Pin
samthec16-Jun-12 4:06
membersamthec16-Jun-12 4:06 
AnswerRe: try this instead.. Pin
Kumar, Ravikant INDIA Bangalore23-Aug-12 0:50
memberKumar, Ravikant INDIA Bangalore23-Aug-12 0:50 
GeneralMy vote of 1 [modified] Pin
samthec16-Jun-12 2:15
membersamthec16-Jun-12 2:15 
GeneralRe: My vote of 1 Pin
Kumar, Ravikant INDIA Bangalore23-Aug-12 0:48
memberKumar, Ravikant INDIA Bangalore23-Aug-12 0:48 
GeneralRe: My vote of 1 Pin
FernandoUY23-Aug-12 12:07
memberFernandoUY23-Aug-12 12:07 
GeneralMy vote of 5 Pin
pathakpankaj14-May-12 21:19
memberpathakpankaj14-May-12 21:19 
GeneralRe: My vote of 5 Pin
Kumar, Ravikant INDIA Bangalore29-Jul-12 20:23
memberKumar, Ravikant INDIA Bangalore29-Jul-12 20:23 
GeneralMy vote of 3 Pin
Bishisht Bhatta29-Mar-12 22:32
memberBishisht Bhatta29-Mar-12 22:32 
GeneralRe: My vote of 3 Pin
Kumar, Ravikant INDIA Bangalore29-Jul-12 20:21
memberKumar, Ravikant INDIA Bangalore29-Jul-12 20:21 
GeneralMy vote of 5 Pin
manoj kumar choubey2-Feb-12 1:04
membermanoj kumar choubey2-Feb-12 1:04 
Questiongoogle translate is not free anymore, Pin
wei10000014-Jan-12 6:20
memberwei10000014-Jan-12 6:20 
AnswerRe: google translate is not free anymore, Pin
Hexadigm Systems27-Jan-12 6:55
memberHexadigm Systems27-Jan-12 6:55 
GeneralRe: google translate is not free anymore, Pin
Kumar, Ravikant INDIA Bangalore23-Aug-12 0:50
memberKumar, Ravikant INDIA Bangalore23-Aug-12 0:50 
GeneralMy vote of 4 Pin
Rajeshkumar Chavada27-Nov-11 20:35
memberRajeshkumar Chavada27-Nov-11 20:35 
GeneralRe: My vote of 4 Pin
Kumar, Ravikant INDIA Bangalore29-Jul-12 20:19
memberKumar, Ravikant INDIA Bangalore29-Jul-12 20:19 
QuestionWhen One File Translate then error generate Pin
Rajeshkumar Chavada27-Nov-11 20:34
memberRajeshkumar Chavada27-Nov-11 20:34 
AnswerRe: When One File Translate then error generate Pin
Kumar, Ravikant INDIA Bangalore5-Dec-11 22:30
memberKumar, Ravikant INDIA Bangalore5-Dec-11 22:30 
Question"индусcкий код" Pin
soad171515-Nov-11 2:58
membersoad171515-Nov-11 2:58 
QuestionGoogle translate API v2 Pin
pnduffy11-Oct-11 12:06
memberpnduffy11-Oct-11 12:06 
AnswerRe: Google translate API v2 Pin
Kumar, Ravikant INDIA Bangalore16-Nov-11 22:43
memberKumar, Ravikant INDIA Bangalore16-Nov-11 22:43 
AnswerRe: Google translate API v2 Pin
Kumar, Ravikant INDIA Bangalore23-Aug-12 0:53
memberKumar, Ravikant INDIA Bangalore23-Aug-12 0:53 
GeneralRe: Google translate API v2 Pin
pnduffy23-Aug-12 5:31
memberpnduffy23-Aug-12 5:31 
GeneralGetting error in VS2008 Pin
Mizan Rahman23-May-11 2:48
memberMizan Rahman23-May-11 2:48 
GeneralRe: Getting error in VS2008 Pin
invaders@earthling.net10-Jan-12 14:21
memberinvaders@earthling.net10-Jan-12 14:21 
GeneralRe: Getting error in VS2008 Pin
Kumar, Ravikant INDIA Bangalore12-Jan-12 22:58
memberKumar, Ravikant INDIA Bangalore12-Jan-12 22:58 
GeneralTranslate Language using resource file to my web site. Pin
Member 47502133-May-11 2:16
memberMember 47502133-May-11 2:16 
GeneralRe: Translate Language using resource file to my web site. Pin
Kumar, Ravikant India Bangalore9-May-11 1:03
memberKumar, Ravikant India Bangalore9-May-11 1:03 
Generalthanks for sharing - have 5 Pin
Pranay Rana30-Jan-11 19:54
memberPranay Rana30-Jan-11 19:54 
GeneralMy vote of 4 Pin
dfigure29-Dec-10 6:23
memberdfigure29-Dec-10 6:23 
GeneralDealing with legacy code pages Pin
dfigure29-Dec-10 6:20
memberdfigure29-Dec-10 6:20 
GeneralRe: My vote of 2 Pin
Kumar, Ravikant India Bangalore26-Dec-10 23:48
memberKumar, Ravikant India Bangalore26-Dec-10 23:48 
QuestionRe: My vote of 2 Pin
Chesnokov Yuriy27-Dec-10 0:51
memberChesnokov Yuriy27-Dec-10 0:51 
AnswerRe: My vote of 2 Pin
Kumar, Ravikant India Bangalore27-Dec-10 19:29
memberKumar, Ravikant India Bangalore27-Dec-10 19:29 
QuestionPoor exception handling and code layout, how do you handle ResXResourceReader exceptions? Pin
Chesnokov Yuriy26-Dec-10 22:51
memberChesnokov Yuriy26-Dec-10 22:51 
GeneralA really helpful tool Pin
Jax000000999999920-Aug-10 1:05
memberJax000000999999920-Aug-10 1:05 
GeneralGoogle API Access Notice Pin
peterfoo10-Aug-10 4:54
memberpeterfoo10-Aug-10 4:54 
GeneralRe: Google API Access Notice Pin
Kumar, Ravikant India Bangalore10-Aug-10 7:33
memberKumar, Ravikant India Bangalore10-Aug-10 7:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150520.1 | Last Updated 27 Aug 2012
Article Copyright 2010 by Kumar, Ravikant INDIA Bangalore
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid