With many more applications coming up with localized versions, it is important to test if the application is ready for that after moving the resources out of the code. We have easy ways of taking strings out of the code, using resx files, satellite DLLs, and external string files (a client side js file). A quick test would be to see if all the strings are picked up from an external file. One step further would be to make sure strings in other languages (the localized ones) are displayed properly in our application. As many point out, it is important to test with European and Asian languages that use multi-byte encoding. I started off with this testing, and thought that I will copy-paste some of the strings from the web on these languages to carry out the testing. On looking around the web, I got to know about Google Translate and I was excited, and I found a way to test my application in all languages that Google supports! As I started with it, oh, it was a pain... picking up strings one by one, translating them into the different languages .... I thought it would have been good if I had an automatic tool (there is Google for that to search and tell me!).
Google returned me with a result, a way of calling Google Translate from our application, a good article and accompanying source code by Peter A. Bromberg. I thought I got what I wanted and with two lines of code I could make it work for me, but it was not so, it made me explore so many other stuff and finally made me post here so that many others could benefit and also help me refine my first C# application.
I fully agree with Peter on "don't reinvent the wheel", having been with application development for over 7 years. I have gained most part of my knowledge through the web with those who had shared their two cents. I started with his code and ran it on my machine. Oops, I didn't get the result. On getting into debug mode, I found that the web scraper he was using, WebWagon, did not support proxies. Once again, it was Google time and I added the code below to use the default proxy authentication to get his code working:
hrqURL.Proxy = (WebProxy) GlobalProxySelection.Select;
hrqURL.Proxy.Credentials = CredentialCache.DefaultCredentials;
Then I started off with my project, translating my resx file, and upgrading it with version after versions. The first version used direct XML parsing of the resx file as I was not aware of
ResXResourceReader. The second version included support for strings in a js file also as some string resources were part of the client side script. The next version removed the XML parsing and used
ResXResourceWriter. Then, to avoid the screen hanging, I added thread support and a progress bar to the application, and I have attached that version here. I am still thinking of working on a version supporting Altavista's Babelfish also. (I am very well aware that this code will break once the Google Translate page or the Babelfish page changes, but I hope it won't be in the near future and always there will be some one to break it through and get it working!)
Using the code
I have used Peter's WebWagon project as it is other than the few tweaks to get it working for me. The first one was the proxy support as I said earlier. Asian characters were not getting returned properly in his code and that was the main requirement for me to go for this application. I did a lot of trial and error to get this piece of code into WebWagon so that it supported UTF-8 encoding:
hrqURL.Method = "GET";
hrqURL.ContentType = "application/x-www-form-urlencoded";
hrqURL.UserAgent = "Mozilla/4.0 (compatible;" +
" MSIE 6.0; Windows NT 5.1)";
Also, the encoding of the return data from the webpage was also missing. I added that to get the data encoded properly.
StreamReader srdrInput = new
The project I have added is straightforward; for resx files, loop through the resource strings and call Translate using the
ResxResourceReader, and for js, read line by line and call Translate.
ResXResourceReader rsxr = new ResXResourceReader(fileName);
ResXResourceWriter rsxTranslated = new ResXResourceWriter(outputFileName);
IDictionaryEnumerator id = rsxr.GetEnumerator();
pct = new object;
foreach (DictionaryEntry d in rsxr)
int percentTranslated = (int)(count*100/totalStrings);
string strval = d.Value.ToString();
string translatedtxt = TranslateString(strval);
For getting the progress bar working, I had to do some additional coding, to get the total number of strings to be translated. For js files, I went through the file till the end once, to get all the strings. For resx, I thought using XML parsing would be much faster and used a piece of code I already had in my first version:
XmlDocument rootNode = new XmlDocument();
XmlNodeList dataNodes = rootNode.SelectNodes("//root/data");
int totalStrings = dataNodes.Count;
Points of interest
As my first application in C#, I got a chance to know more stuff about: web scraping, multithreading, XML parsing, and using different UI controls, and lot more!
- V1.0 - Initial update on 26 Dec 2005.
- 27 Oct 2006 - Fixed code to work with the new changes in the Google Translate page.