Skip to content

Localization (multi language) of a RDLC report with Microsoft ReportViewer

June 8, 2011

In the previous post I wrote how to use the Microsoft ReportViewer with a report and a subreport in a WPF application. In this post I’am going to describe how you can localize a RDLC report because out of the box there is no support for localization. With localization I mean that all the labels, table headers, etc are being translated depending on a language setting in the application.

Because a RDLC report is just an ordinary XML file we execute the following steps to translate a report:

  1. load the report in a XML Document object
  2. find all the nodes with a specific attribute
  3. the value of this attribute is the actually name of a term in a resource file (*.resx)
  4. replace the value of this node with value retrieved from the resource file

I use the Visual Studio solution of my previous post about the ReportViewer as a starting point.

The report TextBox control has a property called ValueLocID. This property we use to store the name of a translated term which is stored in a resource file.

In the XML of the RDLC report the TextBox control property ValueLocID is stored in the LocID attribute of a Value element. The value of this attribute we are going to use to translate and replace the innerText of the Value element.

<Textbox Name="Textbox1">
  <CanGrow>true</CanGrow>
  <KeepTogether>true</KeepTogether>
  <Paragraphs>
    <Paragraph>
      <TextRuns>
        <TextRun>
          <Value rd:LocID="Customer">Customer:</Value>
          <Style>
            <FontWeight>Bold</FontWeight>
          </Style>
        </TextRun>
      </TextRuns>
      <Style />
    </Paragraph>
  </Paragraphs>
</Textbox>

Before the report is loaded into the ReportViewer we are going to translate the report with a helper class. In line 16 we load the report definition as a Stream object. This Stream object is the input for the TranslateReport method of the RdlcReportHelper class. The same steps are done for the subreport. In line 11 we set the current UI culture to Dutch (Netherlands) so all the TextBox controls which have a value set for the ValueLocID property are translated into Dutch.

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    // get the customers from the OData service
    IEnumerable<Customer> customers = Repository.GetCustomers();
    // get a reference to the WinForms ReportViewer control
    Microsoft.Reporting.WinForms.ReportViewer reportViewer = (Microsoft.Reporting.WinForms.ReportViewer)windowsFormsHost.Child;
    // subscribe to SubreportProcessing event for passing the related Orders data
    reportViewer.LocalReport.SubreportProcessing += new SubreportProcessingEventHandler(LocalReport_SubreportProcessing);
        
    // Change the CurrentUICulture to Dutch (Netherlands) 
    Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("nl-NL");
        
    // the report is included as an embedded resource in the assembly
    // load the report as a stream from the assembly   
    Assembly assembly = Assembly.GetExecutingAssembly();             
    Stream reportStream = assembly.GetManifestResourceStream("Wpf.ReportViewer.CustomerReport.rdlc");
    // translate the report
    reportStream = RdlcReportHelper.TranslateReport(reportStream);
    // load the report
    reportViewer.LocalReport.LoadReportDefinition(reportStream);
        
    Stream subreportStream = assembly.GetManifestResourceStream("Wpf.ReportViewer.OrdersReport.rdlc");
    // translate the subreport
    subreportStream = RdlcReportHelper.TranslateReport(subreportStream);
    // load the subreport
    reportViewer.LocalReport.LoadSubreportDefinition("Wpf.ReportViewer.OrdersReport.rdlc", subreportStream);
        
    // the CustomerReport has one dataset which must be filled
    reportViewer.LocalReport.DataSources.Add(new ReportDataSource("CustomerDataset", customers));
    // now let the ReportViewer render the report
    reportViewer.RefreshReport();
}

In the TranslateReport method of the RdlcReportHelper class we create a XDocument object from the Stream object. Then we iterate through all the Value elements. If a Value element has a LocID attribute we trying to find the translated term in a resource file using the value of the attribute.

public static class RdlcReportHelper
{
    public static Stream TranslateReport(Stream reportStream)
    {
        XDocument reportXml = XDocument.Load(reportStream);

        foreach (var element in reportXml.Descendants(XName.Get("Value", @"http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")))
        {
            XAttribute attribute = element.Attribute(XName.Get("LocID", @"http://schemas.microsoft.com/SQLServer/reporting/reportdesigner"));

            if (attribute != null)
            {
                string translatedValue = Resources.ReportResources.ResourceManager.GetString(attribute.Value);
                element.Value = string.IsNullOrEmpty(translatedValue) ? element.Value : translatedValue;
            }
        }

        Stream ms = new MemoryStream();
        reportXml.Save(ms, SaveOptions.OmitDuplicateNamespaces);
        ms.Position = 0;

        return ms;
    }
}

The Visual Studio 2010 solution can be downloaded from here

About these ads

From → .NET, ReportViewer, WPF

One Comment
  1. Markos permalink

    Long ago i developed a small app which I named ReportLocalizer (http://www.dotnetzone.gr/cs/blogs/jajaja/archive/2009/05/05/report-localizer-ver-0-5.aspx) and I use it to localize rdlc reports. It’s written in VS2008. You might find it useful.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: