Localizing an application for different languages isn’t easy and it can be time-consuming to make sure that your application looks good in all languages. You might have forgotten to localize strings and have left them hardcoded in your native tongue. Some languages take more space than others and text in these might be truncated in the UI, especially for a smartphone app design. Then there is the issue of keeping track of which text in which language has been updated and signed off, especially if you’re doing a update to the visuals of the app for a new release.
Any help you can get from a tool can potentially save a lot of time in administration and help you fix those “loc bugs” more easily.
If your Windows Phone 8 or Windows Store application is available in multiple languages, or if you’re planning for this, then it’s worth looking into the Multilingual App Toolkit from Microsoft.
A WP8 project I was working was undergoing a major visual refresh. It was in the marketplace in several languages. We wanted to track the existing translations (these have been signed-off and should be left unchanged) and mark any new strings as needing translation. We wanted to detect where the designer/dev has hardcoded a string rather than placing it in the localization resources dictionary.
The “MAT” (Multilingual App Toolkit) seemed like a great fit for us – the “pseudo-language” feature in particular would help us spot omissions and truncations more easily.
What is pseudo-language?
Pseudo language is a made up “language” – it mangles your neutral language (in my case, English) and adds padding to make it take more space so that you can 1) tell it’s pseudo language and 2) predict where your truncations will occur. Where English (United Kingdom) is given a ISO language identifier of “en-GB”, pseudo-language is given a language identifier of “qps-PLOC”.
Our C#/XAML app uses a background agent which we use to generate “toast” text, which is also translated. So to keep a single .resx file that is shared by the application and the background agent, I had followed some advice to place the translation in its own class library. That way we’ve got a single set of strings to translate and they can be used from anywhere in the app – great…
…until I tried to enable the “pseudo-loc” feature in the MAT and get it to display in the WP8 emulator. All other languages were showing up fine apart from pseudo-loc which was stubbornly staying in the neutral language of English.
What is going on?
The localization process works by creating a “satellite assembly” (DLL) that contains your localized resources for each of your target languages. Each satellite assembly has the same name, but they are placed in separate folders in your output directory according to the name of the language’s “culture” or ISO identifier. So, for a “Localization” class library, the English (United Kingdom) satellite assembly “Localization.resources.dll” is placed in the “en-gb” folder.
Looking at the output directories (e.g. bin/Debug) and the unzipping the XAP to look inside it, I could see that in the final application, the satellite assembly for “qps-PLOC” was missing. This is what was stopping strings from showing in Pseudo language. Every other language had copied across fine. I’m not sure exactly why, but I suspect there is a problem with something in the (WP8?) common MSBUILD scripts for Visual Studio 2012 (I haven’t checked for VS2013 yet).
If I manually edited the XAP to add back the missing file in the path “qps-PLOC/Localization.resources.dll” and ran it on the emulator and the pseudo-language showed correctly.
With a bit of digging around I eventually figured out how to use the MSBUILD build language to add back the missing satellite assembly, so that pseudo-language would work correctly without needing to hack around in the final XAP. It requires an edit to the project of the final Windows Phone XAML app (for C# that’s the .csproj, for VB the .vbproj file). Just before the closing tag insert the following code:
<PropertyGroup> <ComputeIntermediateSatelliteAssembliesDependsOn> $(ComputeIntermediateSatelliteAssembliesDependsOn);AddPseudoLocSatelliteAssemblies </ComputeIntermediateSatelliteAssembliesDependsOn> </PropertyGroup> <Target Name="AddPseudoLocSatelliteAssemblies"> <ItemGroup> <IntermediateSatelliteAssembliesWithTargetPath Include="$(SolutionDir)\Localization\obj\$(Configuration)\qps-ploc\Localization.resources.dll"> <Culture>qps-ploc</Culture> <TargetPath>qps-ploc\Localization.resources.dll</TargetPath> </IntermediateSatelliteAssembliesWithTargetPath> </ItemGroup> </Target>
You will need to update both the “Include” location and the “TargetPath” above to match the actual path and name of the class library you are using.
Hopefully that help someone else in the same situation!