Click here to Skip to main content
Click here to Skip to main content

How to localize XSLT

, 10 Apr 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Text in an XSLT may be localized by reading translated strings from an XML document. Numbers may also be localized.

Introduction

Text in an XSLT may be localized by reading translated strings from an XML document. Numbers may also be localized.

The XML document may contain either one language with one XML document for each language, or alternatively, a single XML document with all languages. The XML formats in the following example follows Microsoft .NET resource (.resx) files (one file per language) or a single TMX (translation memory exchange) document with all languages. Any format, however, may be used as long as the XPath used to read the text is consistent.

Using the code

Both options use the XPath document function to read the XML with the translated strings. Define parameters for each string used in the XSLT. Using parameters rather than variables allows the values to be overridden when the XSLT is transformed. Use xsl:value-of to display the translated text. When the transform is processed, pass the language code, for example, 'fr', and the URL to the resource XML document for the desired language.

In .NET, the XSLT arguments are passed using the XsltArgumentList class.

System.Xml.Xsl.XsltArgumentList args = new System.Xml.Xsl.XsltArgumentList();
args.AddParam("lang", "", "fr");
args.AddParam("localeUrl", "", "Resources.fr.resx");

But first, consider a sample data XML to process and a sample XSLT before internationalization.

Sample XML data document

<?xml version="1.0"?>
<root>
    <Number>34567.89</Number>
</root>

Sample XSLT without internationalization

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output encoding="utf-8" omit-xml-declaration="yes"/>

<xsl:template match="/root">
    The number is: <xsl:value-of select="Number"/>
</xsl:template>

</xsl:stylesheet>

Sample result

The number is: 34567.89.

Notice the number in the result is not formatted.

Localization of XSLT

Option 1: Create an XML file for each language

In the XSLT, define a parameter to accept the URL to the resource XML document for the selected language.

XSLT localized for RESX format with one RESX file for each language:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output encoding="utf-8" omit-xml-declaration="yes"/>

<xsl:param name="lang" select="'en'"/>

<xsl:param name="localeUrl" select="'Resources.resx'"/>
<xsl:variable name="localeXml" select="document($localeUrl)/*" />
<xsl:param name="NumberFormat" 
           select="$localeXml/data[@name='NumberFormat']/value/text()"/>
<xsl:param name="NumberCaption" 
           select="$localeXml/data[@name='NumberCaption']/value/text()"/>

<xsl:decimal-format name="en" 
  grouping-separator="," decimal-separator="." />
<xsl:decimal-format name="es" 
  grouping-separator="." decimal-separator="," />
<xsl:decimal-format name="fr" 
  grouping-separator=" " decimal-separator="," />

<xsl:template match="/root">
    <xsl:value-of select="$NumberCaption"/>
    <xsl:value-of select="' '"/>
    <xsl:value-of select="format-number(Number, $NumberFormat, $lang)"/>
</xsl:template>

</xsl:stylesheet>

Resource files in English, Spanish (es) and French (fr)

Resources.resx
<?xml version="1.0" encoding="utf-8" ?>
<root>
    <xsd:schema ...
    </xsd:schema>
    <resheader name="ResMimeType">
        <value>text/microsoft-resx</value>
    </resheader>
    <data name="NumberFormat" xml:space="preserve">
        <value>#,###.00</value>
    </data>
    <data name="NumberCaption" xml:space="preserve">
        <value>The number is:</value>
    </data>
</root>
Result

The number is: 34,567.89.

Notice that the number is formatted with a ',' as the thousands separator.

Resources.es.resx
<?xml version="1.0" encoding="utf-8" ?>
<root>
    <xsd:schema ...
    </xsd:schema>
    <resheader name="ResMimeType">
        <value>text/microsoft-resx</value>
    </resheader>
    <data name="NumberFormat" xml:space="preserve">
        <value>#.###,00</value>
    </data>
    <data name="NumberCaption" xml:space="preserve">
        <value>El número es:</value>
    </data>
</root>
Result

El número es: 34.567,89

Resources.fr.resx
<?xml version="1.0" encoding="utf-8" ?>
<root>
    <xsd:schema ...
    </xsd:schema>
    <resheader name="ResMimeType">
        <value>text/microsoft-resx</value>
    </resheader>
    <data name="NumberFormat" xml:space="preserve">
        <value># ###,00</value>
    </data>
    <data name="NumberCaption" xml:space="preserve">
        <value>Le nombre est:</value>
    </data>
</root>
Result

Le nombre est: 34 567,89

Option 2: Create a single XML file with all languages

XSLT localized for TMX format with one XML file with all languages:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output encoding="utf-8" omit-xml-declaration="yes"/>

<xsl:param name="lang" select="'en'"/>

<xsl:variable name="tmx" select="document('tmx.xml')/tmx/body"/>
<xsl:param name="NumberFormat" 
           select="$tmx/tu[@tuid='NumberFormat']/tuv[lang($lang)]/seg"/>
<xsl:param name="NumberCaption" 
           select="$tmx/tu[@tuid='NumberCaption']/tuv[lang($lang)]/seg"/>

<xsl:decimal-format name="en" grouping-separator="," decimal-separator="." />
<xsl:decimal-format name="es" grouping-separator="." decimal-separator="," />
<xsl:decimal-format name="fr" grouping-separator=" " decimal-separator="," />

<xsl:template match="/root">
    <xsl:value-of select="$NumberCaption"/>
    <xsl:value-of select="' '"/>
    <xsl:value-of select="format-number(Number, $NumberFormat, $lang)"/>
</xsl:template>

</xsl:stylesheet>

Translated XML document

tmx.xml
<?xml version="1.0"?>
<tmx>
  <body>
    <tu tuid="NumberFormat">
      <tuv xml:lang="en"><seg>#,###.00</seg></tuv>
      <tuv xml:lang="es"><seg>#.###,00</seg></tuv>
      <tuv xml:lang="fr"><seg># ###,00</seg></tuv>
    </tu>
    <tu tuid="NumberCaption">
      <tuv xml:lang="en"><seg>The number is:</seg></tuv>
      <tuv xml:lang="es"><seg>El número es:</seg></tuv>
      <tuv xml:lang="fr"><seg>Le nombre est:</seg></tuv>
    </tu>
  </body>
</tmx>

Go global!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Doug Domeny
Software Developer (Senior) Newforma
United States United States
A principal software engineer who has developed significant skills in software engineering and architecture, UI design, and technical writing. Skills include ASP.NET, HTML, XHTML, DOM, CSS, Web, Web Services, C#, VB.NET, XML, XSLT, XPath, JavaScript, jQuery, localization/internationalization, W3C XML Schema (XSD), and SQL. Served for many years on OASIS technical committees such as XML Localization Interchange File Format (XLIFF) and Open Architecture for XML Authoring and Localization (OAXAL). Holds a bachelor's degree in computer science and mathematics from Gordon College in Wenham, MA.
Follow on   LinkedIn

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermanoj kumar choubey15-Apr-12 23:00 
GeneralMy vote of 5 PinmemberSteve Aube 12-Mar-12 10:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 10 Apr 2012
Article Copyright 2012 by Doug Domeny
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid