In my previous example i showed you how you can create a localizable Silverlight 2.0 application for just two languages. In this article i’ll expand on this and explain how to
1. Multi-language xap’s
2. Change a user control language at runtime
3. Using converters for placeholder substitution / replacement
4. Demo and Code
1. Multi-language xap’s
If you have played with the SupportedLanguages in SL 2.0 Beta 2, you would quickly notice that if you try to implement multiple culture resx files only the first language ever loads. There is a issue in Beta 2 is that the resource assemblies dlls can’t have the same name, even if they in different folders.
NB: This will be fixed in RTW 2.0.
eg:
fr\silverlightapplication1.resources.dll
de\silverlightapplication1.resources.dll
For a workaround to those impatient folks out there, to overcome the single language resource loading issue. Here is a simple script you can create, to set this correctly at compile time, using the appmanifest.xml and VS post-build events.
NB: Remove any values from <SupportedCultures></SupportedCultures> in the *.csproj file
i. Update your Properties\AppManifest.xml to include your new language assembly dlls and click save eg:
<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Deployment.Parts>
<AssemblyPart Source="SilverlightApplication1.de.resources.dll" />
<AssemblyPart Source="SilverlightApplication1.fr.resources.dll" />
<AssemblyPart Source="SilverlightApplication1.ja.resources.dll" />
</Deployment.Parts>
</Deployment>
ii. Add a vb script to your project folder that enables you to add files to zip archive called AddFilestoZip.vbs with the following code, you could also use winzip or any other zip command software, as xap are simply a renamed zip file
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.NameSpace(Wscript.arguments(0))
objFolder.CopyHere Wscript.arguments(1), &H10&
WScript.Sleep 500
iii. In Visual Studio project explorer right click on your Silverlight Application and select properties, click on the events tab and insert the following code into the Post-Build Events: Notice the culture list in bold in the batch for loop.
move "$(TargetDir)$(ProjectName).xap" "$(TargetDir)$(ProjectName).zip"
for %%i in (de fr ja) do (
move "$(TargetDir)%%i\$(ProjectName).resources.dll" "$(TargetDir)$(ProjectName).%%i.resources.dll"
cscript /nologo "$(SolutionDir)$(ProjectName)\addfiletozip.vbs" "$(TargetDir)$(ProjectName).zip" "$(TargetDir)$(ProjectName).%%i.resources.dll"
)
move "$(TargetDir)$(ProjectName).zip" "$(TargetDir)$(ProjectName).xap"
iv. Save and compile and you can see the strings load from the resource assembly for multiple cultures
2. Change a user control language at runtime
Surfers sometime want the update their user languages preferences inside the application at runtime rather having to restart the whole application. With asp.net or silverlight this is very easy, see sample below
// Update the app Culture and UICulture
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("ja-jp");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ja-jp");
Page page1 = new Page(); // Page is your user control xaml/class
LayoutRoot.Children.Clear(); // remove old control
LayoutRoot.Children.Add(page1); // re-add new control
3. Using a binding converter for placeholder substitution / replacement
In localization you often need to merge UI strings with DB data or other UI strings and because of the complexities of international grammar strings need to be in differing orders
Eg:
"The e-mail was sent successfully to {0}'s e-mail address."
"El e-mail fue enviado satisfactoriamente a la dirección e-mail de {0}"
To do this in asp.net or silverlight you can use String.Format, but with silverlight data binding we do this using a binding Converter to assist us.
In xaml you can use the following to replace String1
<TextBlock x:Name="String1" Text="{Binding String1, Converter={StaticResource StrReplace}, ConverterParameter='String2', Source={StaticResource LocStrings}}" />
public class PlaceholderSubstitution : IValueConverter {
public
object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){
return
String.Format((string)value, SilverlightApplication1.Resources.Resource1.ResourceManager.GetString(parameter.ToString(), System.Threading.Thread.CurrentThread.CurrentCulture));
}
public
object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{ throw new NotImplementedException("PlaceholderSubstitution does not use ConvertBack."); }
}
4. Demo and Code
Demo: http://silverlight.services.live.com/invoke/6655/LocSample/iframe.html
Soure code: http://cid-2b248d261d0e0035.skydrive.live.com/self.aspx/Public/SL-Multi-Loc.zip