How to: Make Rich Text Strings Localizable

Microsoft Silverlight will reach end of support after October 2021. Learn more.

In your Silverlight-based application, you may want to make a rich text string localizable. For example, suppose your non-localized string is the following:

<TextBlock>
   <Run Text="Hello " FontWeight="bold"/>
   <Run Text="world" />
</TextBlock>

You can make this content localizable by performing the following steps. This procedure assumes that you have already created the necessary resource files and created the class that returns the resources. (For more information, see Localizing Silverlight-based Applications.) In the case of this example, the resource file is named Resource1, and the class instance that returns the resources is named LocalizedStrings.

To make a rich text string localizable

  1. Translate the string that you want to make localizable into a format string and store it in a resource file. When you do this, you may need to change the word order (for example, by placing a non-bold word before a bold word). For example, we can add the following string resource named RichFormat to the Resource1 resource file.

    "{0}{2}Hello {3}{4}World{5}{1}"
    
  2. Define a value converter (a class that implements System.Windows.Data.IValueConverter). The following example defines a class named FormatConverter that implements IValueConverter and that is capable of handling the format string that is shown in step 1. Its Convert method takes a format string as the value parameter and calls the String.Format(String, array<Object[]) method to insert XAML into the format string. It then uses the XamlReader.Load method to parse the XAML rich text.

    Public Class FormatConverter : Implements System.Windows.Data.IValueConverter
    
       Public Sub FormatConverter()
       End Sub
    
       Public Function Convert(ByVal value As Object, ByVal targetType As Type, _
                             ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object _
                             Implements System.Windows.Data.IValueConverter.Convert
          Dim formatString As String = value.ToString()
    
          ' Escape special XML characters like <>&'
          formatString = New System.Xml.Linq.XText(formatString).ToString()
    
          Dim formatted As String = String.Format(formatString, _
                "<TextBlock xmlns='https://schemas.microsoft.com/winfx/2006/xaml/presentation'>", _
                "</TextBlock>", "<Run FontWeight='bold' Text='", "'/>", _
                    "<Run Text='", "'/>")
          Dim block As TextBlock = CType(System.Windows.Markup.XamlReader.Load(formatted), TextBlock)
          Return block
       End Function
    
       Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, _
                                 ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object _
                                 Implements System.Windows.Data.IValueConverter.ConvertBack
          Throw New NotSupportedException("The FormatConverter.ConvertBack method is not supported.")
       End Function
    End Class
    
    public class FormatConverter : System.Windows.Data.IValueConverter
    {
       public FormatConverter()
       {
       }
    
       public object Convert(object value, Type targetType,
                             object parameter, System.Globalization.CultureInfo culture)
       {
          string formatString = value.ToString();
    
          // Escape special XML characters like <>&'
          formatString = new System.Xml.Linq.XText(formatString).ToString();
    
          string formatted = String.Format(formatString,
                @"<TextBlock xmlns='https://schemas.microsoft.com/winfx/2006/xaml/presentation'>",
                "</TextBlock>", "<Run FontWeight='bold' Text='", @"'/>",
                    "<Run Text='", @"'/>");
          TextBlock block = (TextBlock)System.Windows.Markup.XamlReader.Load(formatted);
          return block;
       }
    
       public object ConvertBack(object value, Type targetType,
                                 object parameter, System.Globalization.CultureInfo culture)
       {
          throw new NotSupportedException("The FormatConverter.ConvertBack method is not supported.");
       }
    }
    
  3. Define an instance of the value converter in an accessible resource dictionary such as the <Application.Resources> section of App.xaml. For example, the following XAML defines a variable named formatConverter that is an instance of the FormatConverter type.

    <Application.Resources>
       <local:FormatConverter xmlns:local="clr-namespace:SilverlightApp" 
        x:Key="formatConverter" /> 
    </Application.Resources>
    
  4. Edit the XAML file to data bind to the format converter. In our example, we might also replace the TextBlock control with a ContentControl, as shown in the following XAML.

    <ContentControl HorizontalContentAlignment="Stretch"
                    VerticalContentAlignment="Stretch"
                    Content="{Binding Path=Resource1.RichFormat,
                    Source={StaticResource LocalizedStrings},
                    Converter={StaticResource formatConverter}}" />
    

    The converter can also extract the format string directly from the resource file instead of passing it as a binding source by using a statement such as the following.

    Dim formatString As String = My.Resources.Resource1.FormatString
    
    string formatString = Resource1.FormatString; 
    

    If you choose this approach, make sure that the binding has a Source or a DataContext. Otherwise, your value converter will not be called.