What is Localization?
Localization is the process of adapting an application for a particular country, region or group by adding locale-specific components and by translating the strings used in the UI. Doing so will expand the reach of your application into new, distinct markets that may otherwise not use your product. For each locale/culture you wish to target, you will need a separate unique set of resources that match that local/culture.
This process involves making certain your application is “Internationalized” so that it can be easily adapted without structural changes. The types of things your application will want to be able to adapt to include mostly:
1. Language
For language, you will need to match the alphabet/script, numerals, writing direction and spelling/word variants that are used for the local/culture. For example, in the US we say “trunk” where as in the UK they say “boot”. Think there are only a few differences? Think again.
2. Culture
When it comes to culture you will need to adapt for images, colors, names, titles, phone numbers, postal codes, currency, weights, measures, paper sizes and more.
3. Writing Conventions
Each locale may also have its own writing conventions. This includes number formatting, time zones and date/time format.
Cultures are represented by a string that has the language and region denoted. Examples for German include:
de-DE German
de-AT German (Austria)
de-DE German (Germany)
de-CH German (Switzerland)
de-LI German (Liechtenstein)
de-LU German (Luxembourg)
For a complete list see this link.
Localizing Your Silverlight Application
There are a number of steps needed to get your application localized in Silverlight. In this tutorial, I will walk you through each and every step needed to setup localized strings for your application.
Make certain to follow each of these steps carefully as missing one step will can easily lead to ambiguous errors.
Step #1: Creating the Silverlight Application.
Create a Silverlight application using Visual Studio 2010 (I called mine Tip7_LocalizedApp).
Step #2: Add a Resource Folder.
Create a folder and give it a name like “Resources” in your Silverlight application project. I will be placing all localized string resource files in this folder.
Step #3: Add a Default Resource File
Right click on the Resource folder, choose “Add New Item” and select Resource. Name it something like “Strings” and click the “Add” button when ready. To the resource add a string called “AppName” and give it a value. Also, make certain to set the access modifier to Public so we can bind to it later. See the screenshot below.
Step #4: Add Another Resource File for Another Language
Repeat step #4 but this time let’s add a resource for Japanese based strings. The format you will want to use is Strings.<locale>.resx so let’s call in Strings.ja-jp.resx. In the example below, I have set the AppName to be 火炎球 which means ‘Fireball’ in Japanese. Keep the Access Modifier set to “No code generation” since we only need the code for the default one.
Step #5: Add a Namespace to MainPage.xaml
With your resources now created open up the file MainPage.xaml. In the UserControl declaration at the top of the file add an XML namespace that points to your application like this:
xmlns:local="clr-namespace:Tip7_LocalizedApp.Resources"
Step #6: Reference your String Resources.
Add a UserControl.Resource section that references the string resources we added. Give it a required key also that you will use to reference from your controls as seen here:
<UserControl.Resources>
<local:Strings x:Key="AppStrings"></local:Strings>
</UserControl.Resources>
Step #7: Bind to your String Resources
Next, let’s add a TextBlock control that binds to the AppName of our application. This is done via the following syntax:
<TextBlock Text="{Binding AppName, Source={StaticResource AppStrings}" />
At this point you might think you are good to go. However, if you were to run your application you would get an unhandled exception! This is due to a known issue/bug in the modifier for Visual Studio. Even though we set the Access Modifier = Public the constructor of the class is still set to be internal. Open up Strings.Designer.cs and change the constructor to be public:
public Strings() { }
Every time you open the resource designer and make a chance you will need to change this from internal to public. Fortunately, there is a work around. Create a resource wrapper class that instantiates and returns the resource object as such:
public class ResourceWrapper
{
private Resources.Strings appString;
public ResourceWrapper() { appString = new Resources.Strings(); }
public Resources.Strings AppStrings
{
get { return appString; }
}
}
Now, in your XAML, you can reference your resource through this class.
New Namespace Declaration:
xmlns:my="clr-namespace:Tip7_LocalizedApp"
Resource addition:
<UserControl.Resources>
<local:Strings x:Key="LocStrings" />
<my:ResourceWrapper x:Key="MyLocStrings"></my:ResourceWrapper>
</UserControl.Resources>
New binding:
<TextBlock Text="{Binding AppStrings.AppName, Source={StaticResource MyLocStrings}}" />
Step #8: Specify SupportedCultures in your Silverlight Project File
In order to switch between Japanese and English you will need to specify the SupportedCultures in our Silverlight projects file (Make note this is not the web site project but the Silverlight project). It’s a pain, but to accomplish this, right click on your Silverlight project node in the Visual Studko solution explorer and choose “Unload Project”. Right click again and choose “Edit Project”. Add the following to the <PropertyGroup> section:
<SupportedCultures>en-US;ja-JP</SupportedCultures>
Right click yet again and select “Reload project”.
Step #9. Target a Locale in your Web Page
Specify your target Locale in your web page to be Japanese. To accomplish this, open up your default ASPX page that contains your Silverlight control and add the following param types declarations to your Silverlight object:
<param name="culture" value="ja-JP" />
<param name="uiculture" value="ja-JP"/>
Run the application and you will see the following text in your TextBlock as expected:
Now try changing the culture and uiculture to be “en-US” in your ASPX page. Run it again and you will see the following:
Source: Tip7_LocalizedApp.zip
Thank you,
–Mike







With this solution, each time we modify our resource file, we have to change generated code.
So I suggest to make “ResourceWrapper” class in which create an instance of our resource :
public class ResourceWrapper
{
private AppStrings appString;
public ResourceWrapper(){appString = new AppString();}
public AppStrings AppStrings
{
get { return appStrings ; }
}
}
finally we add the ResourceWrapper in resource in xaml
and
FYI it looks like you have a typo:
“{Binding Source={StaticResource AppStrings}, Path=AppStrings.AppName}”
should be:
“{Binding Source={StaticResource AppStrings}, Path=AppName}”
or even better (IMHO):
“{Binding AppName, Source={StaticResource AppStrings}}”
David- You are correct, I had it right in my code and have updated the blog as well.
Julien – Your work around is great! I have added it to the tutorial. Thanks.
@Julien – One small nitpick on the wrapper approach: Is there any reason not to use a static instance of the Strings class? I’m sure it wouldn’t matter much since there is no instance data in the class, but it just seems like the right thing to do.
@Mike – Also if you use MVVM, it’s useful to have an “AppStrings” property on your base ViewModel so that the binding is even easier:
“{Binding AppStrings.AppName}”
// In ViewModelBase.cs:
private static readonly Strings _appStringsInstance = new Strings();
public Strings AppStrings
{
get { return _appStringsInstance; }
}
No additional resource declarations required (aside from setting your view model), and it cleans up the binding very nicely.
Can I know how to do localization without having the dlls of resource files in xap file? I want them in clientbin. I mean I dont want to increase my xap file size.
That would be a good Silverlight tip
How to decrease your xap file size
Thanks
Keep up your good work!
.peter.gfader.
http://peitor.blogspot.com/
http://twitter.com/peitor
Thanks for the great SL tips Mike – I’m a beginner and finding them useful. One thing – I am using VS2008, SL3 and I copied your ResourceWrapper code exactly from the d/l. However, after I change the language strings (so the codebehind regens) I get the following error on AppStrings (on the ResourceWrapper class):
Error 2 Inconsistent accessibility: property type ‘CC.Resources.CCV’ is less accessible than property ‘CC.Resources.ResourceWrapper.AppStrings’
It only works if I change the .resx codebehind accessors to public again from internal, which defeats the object of the wrapper?
Thanks
@hobbydotnet: Would Application Library Caching help in this case? http://msdn.microsoft.com/en-us/library/dd833069%28VS.95%29.aspx (I have not used it but it sounds like what you need)
Well, I tried this again and my Resource Wrapper still does not help – I always have to change the internal to public…
Here is my code:
namespace TourneyManager.Resources
{
public class ResourceWrapper
{
private TourneySetupView appString;
public ResourceWrapper() { appString = new TourneySetupView(); }
public TourneySetupView AppStrings
{
get { return appString; }
}
}
}
Ok, the problem is that I left the local static resource declared in the Resources section – so it was not using the one in the wrapper. I removed this and it worked fine (so only the wrapper is declared as a local resource).
followed every step and get:
The attachable property ‘Resources’ was not found in type ‘UserControl’.