Creating Localization Tool with Silverlight

Since Silverlight 2 is in Beta 2 phase it’s definately time to create small application with it. Together with my friend we’e created small example application called Localization Tool. Idea in our example application is pretty simple... allow end users to modify texts used in application. And for the end user it should be easy, intuitive and of course fast. We used a lot of information available from internet in order to help us in the implementation (see links at the end of this post).

Before going into implementation details you can check out the final solution in action (click the image to open video in new window):

 Localization Tool

In our solution we took WCF + LINQ + SQL approach and created following simple datatable:
Localization Tool table
That table is then used to store data like this:
Localization Tool table data
After that we’ve created LINQ to SQL data class for our table:

Then we created service that provides data access to our localization table. All code behind that service is here:

 123456789101112131415161718192021222324252627282930313233343536373839404142
 using System;using System.Collections.Generic;using System.Linq;namespace LocalizationTool_Web{  public class LocalizationService : ILocalizationService  {    public List<Localization> GetLocalizationByLanguage(string language)    {      LocalizationDataClassesDataContext dataContext =         new LocalizationDataClassesDataContext();      var query = from localization in dataContext.Localizations            where localization.Language.Equals(language)            select localization;      return query.ToList();    }    public void UpdateLocalization(Localization localization)    {      LocalizationDataClassesDataContext dataContext =         new LocalizationDataClassesDataContext();      var updateRow = dataContext.Localizations.First(        loc =>           loc.LanguageKey.Equals(localization.LanguageKey) &&           loc.Language.Equals(localization.Language));      updateRow.Text = localization.Text;      updateRow.Comment = localization.Comment;      dataContext.SubmitChanges();    }    public String [] GetLocales()    {      LocalizationDataClassesDataContext dataContext =         new LocalizationDataClassesDataContext();      var query = (from localization in dataContext.Localizations             select localization.Language).Distinct();      return query.ToArray();    }  }}

Now we’re ready to create UI for our application! We’ve used stackpanels for the layout management and then we used few Style elements to make things look little bit better.
Here is small example about the styles in our App.xaml:

 

 123456789101112
 <Application xmlns="https://schemas.microsoft.com/client/2007"       xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"        x:Class="LocalizationTool.App">  <Application.Resources>        <Style x:Key="Border" TargetType="Border">      <Setter Property="CornerRadius" Value="10"/>      <Setter Property="Background" Value="#FFdedede"/>      <Setter Property="VerticalAlignment" Value="Top"/>      <Setter Property="Margin" Value="8,8,8,8"/>    </Style><!-- ... and few more styles ... –>

At the UserControl_Loaded we query for all the possible locales so that we can list them add the ListBox. Here is the code for that (unfortunately the code looks terrible since it’s splitted into several rows only for display reasons):

 

 123456789101112131415
 private void UserControl_Loaded(object sender, RoutedEventArgs e){  LocalizationClientService.LocalizationServiceClient client =     new LocalizationTool.LocalizationClientService.LocalizationServiceClient();  client.GetLocalesCompleted +=     new EventHandler<LocalizationClientService.GetLocalesCompletedEventArgs>      (client_GetLocalesCompleted);  client.GetLocalesAsync();}void client_GetLocalesCompleted(object sender,   LocalizationClientService.GetLocalesCompletedEventArgs e){  languages.ItemsSource = e.Result;}

Using that same method we query all the localizations specific for that selected locale. There’s nothing fancy about that.. but let’s look at the search functionality little bit closer.
Our search button was defined like this in our Page.xaml:

 

 123
 <TextBox Style="{StaticResource TextBox}"      TextChanged="searchCriteria_TextChanged"      x:Name="searchCriteria" />

And in our code behind we had following code to execute the query:

 

 12345678
 String search = searchCriteria.Text.ToLower();var query = from row in rows      where        row.LanguageKey.ToLower().Contains(search) ||        row.Text.ToLower().Contains(search) ||        row.Comment.ToLower().Contains(search)      select row;SetDatagridItemSource(query.ToArray());

And you can probably pretty easily see that actually that search box functionality doesn’t retrieve data from server at all. It uses the previously retrieved data (variable rows) and filters out it by using linq. Therefore the performance is really good.

We also added functionality to view two different languages at the same time. This helps to make the translations since the user can directly see what’s the equivalent row in another language. This was implemented withthe concept base language. User can select what language he/she wants to use at the compare. Here’s example of that:
 
This was implemented by using the RowDetails of datagrid. Here is the xaml of our datagrid:

 

 12345678910111213
 <System_Windows_Controls:DataGrid    AutoGenerateColumns="True" x:Name="resultsDatagrid"   Width="770" Height="290" Margin="10,10,10,10"   CommittingEdit="resultsDatagrid_CommittingEdit"   SelectionChanged="resultsDatagrid_SelectionChanged"   LoadingRowDetails="resultsDatagrid_LoadingRowDetails">  <System_Windows_Controls:DataGrid.RowDetailsTemplate>    <DataTemplate>      <StackPanel x:Name="tooltipPanel"              Orientation="Horizontal" Background="LightYellow" />    </DataTemplate>  </System_Windows_Controls:DataGrid.RowDetailsTemplate></System_Windows_Controls:DataGrid>

And in resultsDatagrid_LoadingRowDetails we just searched for the corresponding data row from our local base language array. If row was found then we dynamically created TextBoxes to display the values of base language.

This was just small example application that demonstrates the possibilities of Silverlight. Hopefully you got the idea that you can do pretty cool business applications with it.

Anyways... Happy hacking!

J

Silverlight.Net - Getting started
Silverlight 2 Beta1 + WCF + LINQ to SQL = a powerfull combination
Displaying SQL Database Data in a DataGrid using LINQ and WCF
Scott Guthrie: Silverlight Tutorial Part 3: Using Networking to Retrieve Data and Populate a DataGrid

LocalizationTool.zip