This is the mail archive of the mailing list .

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: internationalization / localization of XSLT output

Chris Bayes wrote:
> What about
> <strings>
>    <str lang="en" name="Results of database query">Results of database
> query</str>
>    <str lang="de" name="Results of database query">Ergebnis der
> Datenbankabfrage</str>
>    <str lang="en" name="next page">next page</str>
>    <str lang="de" name="next page">naechste Seite</str>
> </strings>

XML has a facility for communicating language-specific information in a
standard way: the xml:lang attribute, which you can put on any element,
and it will apply to that element and all its descendants, until
redeclared, just like namespaces.

XSLT/XPath have a function for accessing the language that is in effect
for a given element, whether it is declared on that element on or one of
its ancestors: lang().

Some examples:

lang('en') will be true if the language for the current node is 'en-US' or 'en-GB'

lang('en-US') will be true if the language is 'en-US' but not if just 'en'

The rules for constructing language identifiers are covered in IETF RFC
1766. Most of the time they are a hyphenated combination of an ISO 639-1
language code and an ISO 3166-1 country code -- resembling the
"programmatic name of the entire locale" as returned by Java's
Locale.toString(), however there are differences and the locale should not
be considered to be synonymous with the language identifier that you would
use in xml:lang.

Anyway, if you had data like:

   <str xml:lang="en" name="Results of database query">Results of database query</str>
   <str xml:lang="de" name="Results of database query">Ergebnis der Datenbankabfrage</str>
   <str xml:lang="en" name="next page">next page</str>
   <str xml:lang="de" name="next page">naechste Seite</str>

And if you obtained a language identifier via an external top-level
parameter like before (nice to set a default, of course)...

<xsl:param name="Lang" select="'en-GB'"/>

then you could achieve maximum flexibility like this:

<xsl:variable name="StringFile" select="document('strings.xml')"/>
<xsl:variable name="PrimaryLang" select="substring-before($Lang,'-')"/>


<xsl:call-template name="getString">
  <xsl:with-param name="stringName" select="'next page'"/>


	given the info needed to produce a set of candidates ($str),
	pick the best of the bunch:
	1. $str[lang($Lang)][1]
	2. $str[lang($PrimaryLang)][1]
	3. $str[1]
	4. if not($str) then issue warning to STDERR
<xsl:template name="getString">
  <xsl:param name="stringName"/>
  <xsl:variable name="str" select="$StringFile/strings/str[@name=$stringName]"/>
    <xsl:when test="$str[lang($Lang)]">
      <xsl:value-of select="$str[lang($Lang)][1]"/>
    <xsl:when test="$str[lang($PrimaryLang)]">
      <xsl:value-of select="$str[lang($PrimaryLang)][1]"/>
    <xsl:when test="$str">
      <xsl:value-of select="$str[1]"/>
      <xsl:message terminate="no">
        <xsl:text>Warning: no string named '</xsl:text>
        <xsl:value-of select="$stringName"/>
        <xsl:text>' found.</xsl:text>

This takes the set of all strings that match the given name as candidates,
then it picks the best match based on language. It will let you do things
like match 'en' strings when 'en-GB' is given as the parameter, and will
gracefully fall back on the first candidate, if there are none that match 
the language you want. If that's not the behavior you desire, replace the
last xsl:when with:

  <xsl:when test="$str">
    <xsl:message terminate="no">
       <xsl:text>Warning: at least 1 string named '</xsl:text>
       <xsl:value-of select="$stringName"/>
       <xsl:text>' found, but none matched the language '</xsl:text>
       <xsl:value-of select="$PrimaryLang"/>

Have fun.

   - Mike
Mike J. Brown, software engineer at         My XML/XSL resources: in Denver, Colorado, USA 

 XSL-List info and archive:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]