Home. 
.

transparent

transparent

transparent

Altova Mailing List Archives


Re: tool for managing XSL variables in different languages?

From: "Marrow" <marrow@---------.--.-->
To: NULL
Date: 9/2/2004 3:42:00 PM
Hi Sebastian,

First off, there are a few features in XML and XSLT that can assist you with
localization, e.g...

In XML there is a pre-defined attribute of xml:lang which can contain
language (and optionally, national dialect) values.  The useful thing about
utilising the xml:lang rather than defining your own 'lang' attribute is
that the xml:lang is decended down the tree for you until it is overridden.
In XSLT you have the lang() function - which can be used to query/test XML
based upon it's xml:lang attribute.  The lang() function also gives you a
certain amount of fallback functionality (see below) and also is one of the
few parts of XML that is not case-sensitive.

So given those features there are several ways in which you can go about
providing a localization system for use in XSLT.

As an example...

Say you had a single vocabulary XML document that defined all of your
'tokenized' words, e.g. something like...

== Vocabulary.xml ===============================
<?xml version="1.0"?>
<vocab xml:lang="EN-GB"> <!-- this lang gives the default/fallback
language -->
  <language name="English (GB)">
    <token name="bin">Dustbin</token>
    <token name="trousers">Trousers</token>
    <token name="errtest">Something</token>
  </language>
  <language name="English (US)" xml:lang="en-us">
    <token name="bin">Trash can</token>
    <token name="trousers">Pants</token>
  </language>
  <language name="Deutsch" xml:lang="de">
    <token name="bin">Mülleimer</token>
    <token name="trousers">Hose</token>
  </language>
</vocab>
== end of Vocabulary.xml ========================

using the lang() function in XSLT if you did used the XPath selection...
        /vocab/language/token[@name = 'bin'][lang('en')]
it would give you the nodes...
       <token name="bin">Dustbin</token>
       <token name="bin">Trash can</token>
because both are defined under an element whose xml:lang is "en" (i.e.
"en-gb" and "en-us").
So if you do a more specific selection of...
        /vocab/language/token[@name = 'bin'][lang('en-gb')]
this would give just the node...
       <token name="bin">Dustbin</token>

So utilising that in XSLT could look something like...


== TestVocab.xsl ===============================
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="lang-select" select="'en'"/>

<xsl:output method="text"/>
<!-- get the vocabulary document -->
<xsl:variable name="vocab-doc" select="document('Vocabulary.xml')/*"/>
<!-- pick the token words from the vocab document according to the selected
language -->
<!-- also providing fallback when the selected language does not exist -->
<xsl:variable name="vocab"
select="$vocab-doc/language[lang($lang-select)]/token |

$vocab-doc/language[lang(/vocab/@default-lang)][not(/vocab/language[lang($la
ng-select)])][1]/token"/>

<xsl:template match="/">
  <xsl:value-of select="$vocab[@name = 'bin']"/>
</xsl:template>
</xsl:stylesheet>
== end of TestVocab.xsl ========================

NB.  Selecting the approriate tokens into the $vocab variable once saves you
keep specifying the language in later XPath expressions.

Also, some people like to keep each language in a seperate XML document - in
which case you could use system entities to accomplish this and still only
refer to one document() in your XSLT, e.g.

== Vocabulary.xml ===============================
<?xml version="1.0"?>
<!DOCTYPE includes [
  <!ENTITY en-gb SYSTEM "VocabEN-GB.xml">
  <!ENTITY en-us SYSTEM "VocabEN-US.xml">
  <!ENTITY de SYSTEM "VocabDE.xml">
]>
<vocab xml:lang="EN-GB"> <!-- this lang gives the default/fallback
language -->
  &en-gb;
  &en-us;
  &de;
</vocab>
== end of Vocabulary.xml ========================

and the the individual language XML documents...

== VocabEN-GB.xml ===============================
<language name="English (GB)" xml:lang="en-gb">
  <token name="bin">Dustbin</token>
  <token name="trousers">Trousers</token>
  <token name="errtest">Something</token>
</language>
== end of VocabEN-GB.xml ========================

== VocabEN-US.xml ===============================
<language name="English (US)" xml:lang="en-us">
  <token name="bin">Trash can</token>
  <token name="trousers">Pants</token>
</language>
== end of VocabEN-US.xml ========================

== VocabDE.xml ===============================
<language name="Deutsch" xml:lang="de">
  <token name="bin">Mülleimer</token>
  <token name="trousers">Hose</token>
</language>
== end of VocabDE.xml ========================


Using such a system it would then be fairly 'easy' to write a stylesheet
that
checked the existence of each token in the languages, e.g.

== CheckVocab.xsl ===============================
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>

<xsl:variable name="vocab" select="/vocab/language[lang('invalid')]/token |

/vocab/language[lang(/vocab/@xml:lang)][not(/vocab/language[lang('invalid')]
)][1]/token"/>

<xsl:key name="kXMLLangAtts" match="@xml:lang" use="'x'"/>
<xsl:key name="kDistinctLanguages" match="@xml:lang"
use="translate(substring(.,1,2),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmn
opqrstuvwxyz')"/>
<xsl:key name="kDistinctLangDialect" match="@xml:lang"
use="translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"
/>
<xsl:key name="kDistinctTokens" match="token" use="@name"/>
<xsl:variable name="ucase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lcase" select="'abcdefghijklmnopqrstuvwxyz'"/>

<xsl:variable name="vDistinctLanguages"
select="key('kXMLLangAtts','x')[generate-id() =
generate-id(key('kDistinctLanguages',translate(substring(.,1,2),$ucase,$lcas
e)))]"/>
<xsl:variable name="vDistinctTokens"
select="/vocab/language/token[generate-id() =
generate-id(key('kDistinctTokens',@name))]"/>

<xsl:template match="/">
  <html>
    <head>
      <title>
        <xsl:text>My Vocabulary Checks</xsl:text>
      </title>
    </head>
    <body>
      <h2>
        <xsl:text>Vocabulary Checks</xsl:text>
      </h2>
      <hr/>
      <table border="1">
        <tr>
          <th rowspan="2" align="center" valign="bottom">
            <xsl:text>Token</xsl:text>
          </th>
          <th rowspan="2" align="center" valign="bottom">
            <xsl:text>Default</xsl:text>
            <br/>
            <xsl:text>Value</xsl:text>
          </th>
          <xsl:for-each select="$vDistinctLanguages">
            <xsl:variable name="this-lang"
select="translate(substring(.,1,2),$ucase,$lcase)"/>
            <xsl:variable name="no-dialects"
select="count(key('kDistinctLanguages',$this-lang)[contains(.,'-')][generate
-id() =
generate-id(key('kDistinctLangDialect',translate(.,$ucase,$lcase)))])+1"/>
            <th align="center" colspan="{$no-dialects}">
              <xsl:text>Language: </xsl:text>
              <xsl:value-of select="$this-lang"/>
            </th>
          </xsl:for-each>
        </tr>
        <tr>
          <xsl:for-each select="$vDistinctLanguages">
            <xsl:variable name="this-lang"
select="translate(substring(.,1,2),$ucase,$lcase)"/>
            <th>
              <xsl:value-of select="$this-lang"/>
            </th>
            <xsl:variable name="dialects"
select="key('kDistinctLanguages',$this-lang)[contains(.,'-')][generate-id()
= generate-id(key('kDistinctLangDialect',translate(.,$ucase,$lcase)))]"/>
            <xsl:for-each select="$dialects">
              <th>
                <xsl:value-of select="translate(.,$ucase,$lcase)"/>
              </th>
            </xsl:for-each>
          </xsl:for-each>
        </tr>
        <xsl:for-each select="$vDistinctTokens">
          <xsl:sort/>
          <tr>
            <th align="left">
              <xsl:value-of select="@name"/>
            </th>
            <td>
              <xsl:value-of select="$vocab[@name = current()/@name]"/>
            </td>
            <xsl:variable name="this-name" select="@name"/>
            <xsl:for-each select="$vDistinctLanguages">
              <xsl:variable name="this-lang"
select="translate(substring(.,1,2),$ucase,$lcase)"/>
              <xsl:variable name="dialects"
select="key('kDistinctLanguages',$this-lang)[contains(.,'-')][generate-id()
= generate-id(key('kDistinctLangDialect',translate(.,$ucase,$lcase)))]"/>
              <td>
                <xsl:variable name="this-token"
select="/vocab/language[lang($this-lang)]/token[@name = $this-name]"/>
                <xsl:choose>
                  <xsl:when test="$this-token">
                    <xsl:value-of select="$this-token"/>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:attribute name="bgcolor">
                      <xsl:text>Red</xsl:text>
                    </xsl:attribute>
                    <xsl:text>(undefined)</xsl:text>
                  </xsl:otherwise>
                </xsl:choose>
              </td>
              <xsl:for-each select="$dialects">
                <td>
                  <xsl:variable name="this-token"
select="/vocab/language[lang(current())]/token[@name = $this-name]"/>
                  <xsl:choose>
                    <xsl:when test="$this-token">
                      <xsl:value-of select="$this-token"/>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:attribute name="bgcolor">
                        <xsl:text>Red</xsl:text>
                      </xsl:attribute>
                      <xsl:text>(undefined)</xsl:text>
                    </xsl:otherwise>
                  </xsl:choose>
                </td>
              </xsl:for-each>
            </xsl:for-each>
          </tr>
        </xsl:for-each>
      </table>
    </body>
  </html>
</xsl:template>
</xsl:stylesheet>
== end of CheckVocab.xsl ========================


HTH
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator


"Sebastian Kerekes" <sebastian.kerekes@g...> wrote in message
news:1094127960.327398@n......
> Marrow wrote:
>
> > Hi,
> >
> > Using variables and including them?  That seems a long way to do things?
> >
> > Show a short example of what you are doing - perhaps there's a better
way of
> > achieving your goal. ;)
>
> Ok, here's a very simple and short example:
>
> Somewhere at the top of the document i have my variables. The variables
> need to have different content depending on the language I want to use.
> So my XSL is a JSP file that gets a "language" parameter and includes
> the file with the right language.
>
> When the JSP finishes processing, the result is a XSL with for the
> specific language passed with "language". For "en" the result is:
>
>
> <xsl:variable name="text.greetings" select="'Username'" />
> <b><xsl:value-of select="$text.greetings" /></b>
>
> for "de" it's:
>
> <xsl:variable name="text.greetings" select="'Benutzername'" />
> <b><xsl:value-of select="$text.greetings" /></b>
>
> and so on.
>
> I found this approach in a book, and it seems ok to me, but if you have
> any other (more common, more elegant) solutions, feel free to post them ;)
>
>  > To your original question...
>  > You could use XSLT itself to perform the checks to ensure that a word
is
>  > defined in each language.
>
> Uuuhm .. how? How would you solve this?
>
> Greetings, Sebastian




transparent
Print
Mail
Like It
Disclaimer
.

These Archives are provided for informational purposes only and have been generated directly from the Altova mailing list archive system and are comprised of the lists set forth on www.altova.com/list/index.html. Therefore, Altova does not warrant or guarantee the accuracy, reliability, completeness, usefulness, non-infringement of intellectual property rights, or quality of any content on the Altova Mailing List Archive(s), regardless of who originates that content. You expressly understand and agree that you bear all risks associated with using or relying on that content. Altova will not be liable or responsible in any way for any content posted including, but not limited to, any errors or omissions in content, or for any losses or damage of any kind incurred as a result of the use of or reliance on any content. This disclaimer and limitation on liability is in addition to the disclaimers and limitations contained in the Website Terms of Use and elsewhere on the site.

.
.

transparent

transparent