localization, windows phone, wp7dev, wpdev

In the Spirit of Open Source…

I have been asked multiple times to Open Source my Localization Tool and I always wanted to do so. But somehow I did not find the time for Code Cleanup, setting up Github and so on. Even now I´m not Open sourcing it directly and I don´t even know if that would be helpful to anybody. But I´m showing you parts of the Code and explain how it works.

2015-12-23

What this Tool does in the first step is to take some Strings and translate them to a bunch of languages. I never updated the Tool to the latest Windows Phone Versions so some supported languages are not in the Tool.

I use the Microsoft Translator Online Service with its SOAP API for the translation process. All you need is to register your Application to get an authorized AppID to access the Online Service. The API itself is very simple, especially in the use case of our little Tool.

I just call something like:

string strTranslated = translator.Translate(„APPID„, textBoxEnglish1.Text, „en„, „de„);
textBoxGerman1.Text = strTranslated;
strTranslated = translator.Translate(„APPID„, textBoxEnglish2.Text, „en„, „de„);
textBoxGerman2.Text = strTranslated;

Imagine that repeated for all other available languages. The Online Translator Services supports a lot of the languages but not all. So i just copied the English Text to those Text fields directly.

That´s all I had to do for the basic translation and this was already the complete first step in the tool. The next step was up to the user who now could freely edit the strings and fine tune the translation. The next and final Step was to Save those strings to the corresponding resource DLLs. That was the more complex part but it used very old and long existing technics and APIs. To be honest I just grabbed some sample Code from MSDN and adjusted it to my needs.

The download of the Tool contained already an AppResLib.dll.  What I now had to do was to copy that DLL to a new file with a language ID and MUI extension.

That looked like:

//Neutral
System.IO.File.Copy(Application.StartupPath + „\\DLLs\\AppResLib.dll„, fbd.SelectedPath + „\\AppResLib.dll„, true);
//EN-US
System.IO.File.Copy(Application.StartupPath + „\\DLLs\\AppResLib.dll„, fbd.SelectedPath + „\\AppResLib.dll.0409.mui„, true);
//EN-UK
System.IO.File.Copy(Application.StartupPath + „\\DLLs\\AppResLib.dll„, fbd.SelectedPath + „\\AppResLib.dll.0809.mui„, true);

After that happened for all languages I only had to replace both String resources within those DLLs with the translated strings from the UI fields. I therefore created a native C++ DLL that exported two functions:

UpdateAppTitle & UpdateAppTitleString

I just include one of those functions for example here and explain it. The second function is more or less the same. Only the padding where to put the string is different.

That´s how the function looks:

WP7DLLUPDATERDLL_API int UpdateAppTitle(LPCWSTR strDLL,LPCWSTR strString)
{
HANDLE hUpdateRes = NULL;
BOOL result = FALSE;
LPVOID    pRes;
DWORD dwBlockSize = 16*sizeof(WCHAR);
DWORD dwReturn = 0;

hUpdateRes = BeginUpdateResource(strDLL, FALSE);
if(hUpdateRes != NULL)
{
dwBlockSize += wcslen(strString)*sizeof(WCHAR);
pRes = malloc(dwBlockSize);
WCHAR*    pParse = (WCHAR *)pRes;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
int nLen = 0;
*pParse++ = nLen = wcslen(strString);
for(int i = 0;i<nLen;i++)
*pParse++ = strString[i];
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;
*pParse++ = 0;

if(UpdateResource(hUpdateRes,RT_STRING,MAKEINTRESOURCE(7), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),pRes,dwBlockSize))
{
if(EndUpdateResource(hUpdateRes, FALSE))
dwReturn = 0;
else
dwReturn = GetLastError();
}
else
dwReturn = GetLastError();
}
else
dwReturn = GetLastError();
return dwReturn;
}

The function takes the String that has to be replaced and the DLL where it has to be replaced as a parameter and uses the UpdateResource API to do the actual work. Very easy and not complex even if the above code looks strange at first.  But how does it work in detail?

String resources in native DLLs come in Blocks containing 16 Strings. We need to update the string with the ID 100 for the App Title.  As those String (Or resource) IDs begin with 1 we need to Update the fifth string in the seventh Block. That is what those “*pParse++ = 0;” do. Set the string to 0. For the fifth string we first write the length of the string and afterwards the string itself to the Memory containing the Ressource Block. Within the UpdateResource API call we tell the API which Block to update . That´s the “MAKEINTRESOURCE(7)” parameter. After the call to EndUpdateResource the DLL contains the new string and based on the filename it can be used for the App Tile Strings. Interestingly this works just fine with the DLL Resource language set to English (US). It just depends on Filenaming conventions.

– Patrick

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s