Altova Mailing List Archives>Archive Index >comp.text.xml Archive Home >Recent entries >Thread Prev - Re: tool for managing XSL variables in different languages? [Thread Next] Re: tool for managing XSL variables in different languages?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 | ||||||
| Company | Legal | Press | Partners | Careers | Sitemap | Contact Us | Altova Blog | Mobile | Full Site | |||
|
