Silverlight 4 + RIA Services – Ready for Business: Localizing Business Application


To continue our series, let’s look at localizing our business applications.  In today’s global village, it is often no longer OK to support only one language.   Many real world business applications need to support multiple languages.  To demonstrate the pattern, let’s look at localizing the Silverlight Business Application Template.

Update (3/28): I added a bit more explanation about setting culture in Visual Studio..   

You can download the completed solution.

 

Here it is in English side-by-side with a localized version (notice the Hebrew is rendered Right-To-Left correctly):

image 

image

 

 

Let’s start by creating a new Silverlight Business Application.   Notice there is a server and a client project in the solution.   The strings that are needed in both the server and client project are located in the server project and those that are only ever needed in the Silverlight client are in the client project.  Let’s start with the server.  

image

In the Resources folder we see two sets of resources.  One for the Error messages and another for registration details.  These are in a the ResX format which is an Xml file format that has been around for a long time.. there are many localization tools outside of VS that support this format.  Here I will show the localization in VS. 

 

One setup step before we get started.  You need to explicitly tell Visual Studio what languages are supported in by the Silverlight application.  Unfortunately, this is not supported by the VS Project Properties dialog, so you need to edit the Silverlight Applications csproj file directly.   

Right click on the Silverlight project and unload

image

Right click again and select “Edit MyApp.csproj

image

Then find the SupportedCultures attribute and add the full list of cultures your application supports.

image

Then right click on the project and re-load project. 

 

Ok, done with the setup, on to the actual localization.

The first step is to create a copy of each of these files with the [Local].resx extension.  For example, I created one called “ErrorResources.he.resx”.  Here is a full list of cultures codes

Then open the file in VS and you see a nice editing experience.  Simply replace the English text with the translated version.

Below is the translation experience in progress:

image

Repeat for the RegistrationDataResources.resx file. 

Next we need to make these new *.he.resx accessible from the client.   First let’s find the client resources directory.  Notice the English resources are already linked in here.  We need to add the Hebrew ones we just created. 

image

 

Right click and add an Existing Item

 

image

Then browser to the ErrorResources.he.resx file in the web project.

image

Then select add as Link

image

Repeat for the other localized files from on the client.

image

In ApplicationStrings.resx and ApplicationStrings.he.resx I added one additional value to indicate flow direction

image 

 

I then made two very small tweaks to the template to use this value.  In each top level window, I need to set the flow direction.

in Main.xaml:

<UserControl 
  x:Class="LocalizedBusinessApplication.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  FlowDirection="{Binding Path=ApplicationStrings.FlowDirection, Source={StaticResource ResourceWrapper}}" >

and in View\LoginRegistrationWindow.xaml

<controls:ChildWindow
  x:Class="LocalizedBusinessApplication.LoginUI.LoginRegistrationWindow"
  x:Name="childWindow" 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  Width="400" 
  Title="{Binding Path=ApplicationStrings.LoginWindowTitle, Source={StaticResource ResourceWrapper}}"
  Style="{StaticResource LogRegWindowStyle}"
  FlowDirection="{Binding Path=ApplicationStrings.FlowDirection, Source={StaticResource ResourceWrapper}}" 
  Closing="LoginWindow_Closing">

 

Now, we are ready to run the app. 

image

It looks great, but it is all English.. how can we test the localization?  Simply change your language in the browser.

In IE that is Tools\Internet Options

image

Make sure Hebrew is first. Then hit refresh on the page and…

image 

 

What I showed here was how to localize a Silverlight application using the Business Application Template. 

 

Enjoy!

Comments (22)

  1. Mahendran Shanmugham says:

    Excellent Handson Sample. Really Very Good work.

  2. Krudo Meir says:

    Hi Brad,

    Thanks for this Blog Post it’s very helpful,

    Now with Silverlight 4 – Right to Left Support we can start developing silverlight application in Israel.

    by the way great talk at DevAcademy 4,

    see you on Wednesday

  3. Your sample works only when you use this namespace structure. Change your default namespace for the web to "MyCompany.Server" and on the client to "MyCompany.Client" and you can forget the resource on the client. Would be nice when MS provides some support for these scenarios.

    I solved it by changing the .Designer files and adding some compiler directives. But this is only a temporary solution.

  4. Matt says:

    When is WCF Ria Services or WCF Data Services going to support DateTimeOffset?  This is critical functionality missing to support SQL 2008.

  5. BradA says:

    Eric — Good call, I noticed the same thing and opened a couple of bugs.  I am not sure we can get the fixed in V1, but they are on the radar.

    Matt – DateTimeOffset is important, but we just could not get it done this release..  it is very high on the list for the next release

  6. Max says:

    Would you please say, how to chage language programmatically?

  7. Mikea says:

    Hi Brad,

    If I change my browse language settings  (ie8) to ‘he’ your sample works wonderfully.

    However, if I copy your ApplicationStrings.he.resx to ApplicationStrings.af.resx and change my browser language to my local regional setting ‘af’ or ‘af-za’, then the localised settings just get ignored.

    Is there somewhere else I need to change it ?

  8. BradA says:

    @Mikea — did you do the "add as link" section of this post for the new file?

  9. Mikea says:

    Hi Brad,

    Yes, I did the ‘add as link’ section.

    As a test, I renamed each of your .he.resx files to .fr.resx and did the ‘add as link’ bit to include the relevant Web files in the SL project and changed my browser language to French [fr]. This also didn’t work. I only get the ‘default’ strings.

    Are you able to get your project to work with somthing other than [he],  maybe [fr] ?

  10. Phil Harris says:

    Brad

    Thanks for the ideas . We have to target Spanish here in Texas.

    How do you manage attribute based validations / labels, descriptions for Spanish and English at the Entity level ?

  11. BradA says:

    @Mikea – Dohh — Thanks for commenting.. I seem to have left out a very important and Non-obvious step.  You have to edit the Silverlight csproj to add the cultures that are supported.  I updated the post above to show how to do that and I am updating the sample to show a 2nd culture – french – as well.  

  12. Mikea says:

    I made the changes to the csproj and now it works.

    Thanks!

  13. Kathleen MacMahon says:

    Hi Brad,

    Your recent blog postings have been very informative and timely given our project.

    We are having a problem with the resource file usage and the Required() property, which I reported on the forums.  

    Possibly its just user error (often it can be) 🙂  But I’m hoping to find a solution.

    http://forums.silverlight.net/forums/p/171552/387063.aspx#387063

    Kathleen

  14. jwaxster says:

    Hi,

    After working with VS 2010 and SL4 with the new changes to the business application template, I found that the "linked resource files" were causing intermittent problems.

    I ended up creating a separate App.Res.dll silverlight component project and placing the resources there. Then I referenced this project from the App and App.Web projects – things seem to be working smoothly since this change.

    Just thought this may help.

    Jonathan

  15. BG says:

    I started following the steps explained above, 1 .created a new SL project, edited project for adding culture he,fr-FR etc,

    2. created resurce files(ApplicationStrings.he.resx) for ‘he’ with three string, after that added reference to App.xaml then

    xmlns:res="clr-namespace:SilverlightControlApp.Resources"

    3. created

    <Application.Resources>

               <ResourceDictionary>

                   <ResourceDictionary.MergedDictionaries>

                       <ResourceDictionary>

                       <res:ApplicationStrings x:Key="ResourceWrapper" />                        

                       </ResourceDictionary>

                   </ResourceDictionary.MergedDictionaries>

               </ResourceDictionary>

           </Application.Resources>

    4. later control binding is done as follows

    <Button Content="{Binding Path=ApplicationStrings.LoginButton, Source={StaticResource ResourceWrapper}}" Height="23" HorizontalAlignment="Left" Margin="178,140,0,0" Name="button1" VerticalAlignment="Top" Width="75" />

    I am not able see the resurce string binding to control, control text is blank.

    Please help on this very critical!

  16. BradA says:

    I am sorry, I can’t tell right off what the issue is.  can you get the solution I created to work on your machine?

    Is the silverlight client picking up the right culture?  ViewSource and see if the params are right going to the SL control.  

  17. BG says:

    Yes your solution is working perfect, when I change culture in brower, labels are responding with brower culture.

    When we bind the control to resurce class, during designtime itself we can see the text which gets from resource file, this itself not happening. I tried lot of things for binding, even I have changed the constructor from internal to public. please let me if you need any sepcific data to identify the problem. Also I am working on 2010 RC veersion april release.

    Can you pls upload a simple SL app with two label in page1 and 2 buttons in another page with localization applied?

  18. BG says:

     <%

                 string currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture.ToString();

                 Response.Cookies.Add(new HttpCookie("MyApp-culture", currentCulture));

             %>

     <param name="uiculture" value="<%= System.Threading.Thread.CurrentThread.CurrentCulture %>" />

    Above lines of code are not able to get the current culture from browser. Please help me to get the current culture set in the browser. I need to set the <parm /> value to crrently selected culture to culture parm in the .aspx page.

    Do I need to wrirte any code at client end?

  19. mitkodi says:

    Eric, you can solve the problem with namespaces if you edit client project file and add LogicalName to the EmbeddedResource elements for each linked resource: <LogicalName>MyCompany.Server.Resources.ErrorResources.resources</LogicalName>

    <LogicalName>MyCompany.Server.Resources.ErrorResources.he.resources</LogicalName> to

  20. BG says:

    Thank you, it started working, we need set the culture as below.

    <%@ Page Language="C#" AutoEventWireup="true" UICulture="auto" Culture="auto" %>

    and set the current thread in the param section for SL as below.

    <param name="uiculture" value="<%= System.Threading.Thread.CurrentThread.CurrentCulture %>" />

    Thank you everone once again.

  21. Aaron says:

    Will anyone be finishing this series now that Brad is leaving MS?  It sure would be helpful as there is a major lack of good documentation of WCF RIA out there.

    Thanks!

  22. per h says:

    What about dataannotation validation messages ?, I can't understand how to use resx messages for clientside validation.  My genererad entitties code is commented with this

    // Unable to generate the following attribute(s) due to the following error(s):

           //

           // – The validation attribute 'System.ComponentModel.DataAnnotations.StringLengthAttribute' declared ErrorMessageResourceName='DealMetadata_DealStatus_range_fel_1_3' which was not found on declared ErrorMessageResourceType 'RoadrunnerRIAservices.server.Resources.ErrorResources'.

           // [StringLengthAttribute(3, ErrorMessageResourceName = "DealMetadata_DealStatus_range_fel_1_3", ErrorMessageResourceType = typeof(RoadrunnerRIAservices.server.Resources.ErrorResources), MinimumLength = 1)]

           //

    Pls  Advice.

Skip to main content