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
="1.0"
<root>
<Number>34567.89</Number>
</root>
Sample XSLT without internationalization
='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:
='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
="1.0" ="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
="1.0" ="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
="1.0" ="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:
='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
="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!