usr/src/java/adr/xml/style/locale.xsl
changeset 809 8a6fba4105d7
equal deleted inserted replaced
808:2122a04679c0 809:8a6fba4105d7
       
     1 <?xml version="1.0"?>
       
     2 <!--
       
     3   Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
       
     4 
       
     5   CDDL HEADER START
       
     6 
       
     7    The contents of this file are subject to the terms of the
       
     8    Common Development and Distribution License (the "License").
       
     9    You may not use this file except in compliance with the License.
       
    10 
       
    11    You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
       
    12    or http://www.opensolaris.org/os/licensing.
       
    13    See the License for the specific language governing permissions
       
    14    and limitations under the License.
       
    15 
       
    16    When distributing Covered Code, include this CDDL HEADER in each
       
    17    file and include the License file at usr/src/OPENSOLARIS.LICENSE.
       
    18    If applicable, add the following below this CDDL HEADER, with the
       
    19    fields enclosed by brackets "[]" replaced with your own identifying
       
    20    information: Portions Copyright [yyyy] [name of copyright owner]
       
    21 
       
    22   CDDL HEADER END
       
    23 -->
       
    24 
       
    25 <!--
       
    26   * This stylesheet provides generalized localization support for xslt
       
    27   * stylesheets.
       
    28   *
       
    29   * To use:
       
    30   *
       
    31   * 1. Include this snippet in your stylesheet:
       
    32   *
       
    33   *     <xsl:import href="<path>/<to>/locale.xsl"/>
       
    34   *     <xsl:variable name="LOCALE_PKG_PREFIX" select="'someprefix-'"/>
       
    35   *
       
    36   *   ...where "someprefix" is a unique prefix that identifies the package or
       
    37   *   project containing your stylesheets.
       
    38   *
       
    39   * 2. Set the LANG param when processing your stylesheet.  This parameter takes
       
    40   *    the same form as the LANG environment variable (see environ(5)):
       
    41   *
       
    42   *       <language>[_<territory>][.<codeset>][@<modifier>]
       
    43   *
       
    44   *    For example, using xsltproc:
       
    45   *
       
    46   *       % /usr/bin/xsltproc -stringparam LANG "${LC_ALL:-${LANG}}" ...
       
    47   *
       
    48   * 3. Create a resource file:
       
    49   *
       
    50   *     <?xml version="1.0" encoding="utf-8"?>
       
    51   *     <resources>
       
    52   *       <string name="my.resource.property.greeting">
       
    53   *         Hello, {1}!  Have a good {2}!
       
    54   *       </string>
       
    55   *       <string name="my.resource.property.foo">
       
    56   *         Yadda yadda
       
    57   *       </string>
       
    58   *       ...
       
    59   *     </resources>
       
    60   *
       
    61   *   Save the resource file, relative to your stylesheet, as:
       
    62   *
       
    63   *     locale/${LOCALE_PKG_PREFIX}strings_<language>_<territory>@<modifier>.xml
       
    64   *     locale/${LOCALE_PKG_PREFIX}strings_<language>_<territory>.xml
       
    65   *     locale/${LOCALE_PKG_PREFIX}strings_<language>.xml
       
    66   *     locale/${LOCALE_PKG_PREFIX}strings.xml
       
    67   *
       
    68   *   ...where <language>, <territory>, and <modifier> are pulled from the $LANG
       
    69   *   setting above.  All such files are loaded if they exist.  Resources from
       
    70   *   more-specifically named files are preferred if there is more than one
       
    71   *   match.
       
    72   *
       
    73   * 4. From within your stylesheet, call the getString template to retrieve the
       
    74   *    resource:
       
    75   *
       
    76   *     <xsl:call-template name="getString">
       
    77   *       <xsl:with-param name="name" select="'my.resource.property.greeting'"/>
       
    78   *       <xsl:with-param name="params">
       
    79   *         <param>
       
    80   *           world
       
    81   *         </param>
       
    82   *         <param>
       
    83   *           <bold>day</bold>
       
    84   *         </param>
       
    85   *       </xsl:with-param>
       
    86   *     </xsl:call-template>
       
    87   *
       
    88   *   Note that a <param> can hold any XML result tree fragment (RTF), not just
       
    89   *   text.
       
    90   *
       
    91   * 5. Whitespace in each string resource is normalized (see the XSLT
       
    92   *    normalize-space() function) by default before being parameterized and
       
    93   *    returned by getString.  This can be overridden by setting the
       
    94   *    preserve-space attribute to "true" or "1" in the <string> or <resources>
       
    95   *    element of the resource file:
       
    96   *
       
    97   *     <?xml version="1.0" encoding="utf-8"?>
       
    98   *     <resources>
       
    99   *       <string name="my.resource.property.label"
       
   100   *         preserve-space="1">Name: </string>
       
   101   *       ...
       
   102   *     </resources>
       
   103   *
       
   104   *     or:
       
   105   *
       
   106   *     <?xml version="1.0" encoding="utf-8"?>
       
   107   *     <resources preserve-space="1">
       
   108   *       <string name="my.resource.property.label">Name: </string>
       
   109   *       <string name="my.resource.property.indent">    </string>
       
   110   *       ...
       
   111   *     </resources>
       
   112   -->
       
   113 
       
   114 <xsl:stylesheet version="1.0"
       
   115   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       
   116   xmlns:exsl="http://exslt.org/common">
       
   117 
       
   118   <!--
       
   119    * Parse a locale string of the form:
       
   120    * <language>[_<territory>][.<codeset>][@<modifier>]
       
   121    * into its constituent parts.
       
   122    *-->
       
   123   <xsl:param name="LANG"/>
       
   124 
       
   125   <xsl:template name="langparts" mode="locale">
       
   126     <xsl:param name="langstr" select="$LANG"/>
       
   127     <xsl:param name="searchchars" select="'_.@'"/>
       
   128 
       
   129     <xsl:choose>
       
   130       <xsl:when test="string-length($searchchars) = 0">
       
   131         <langpart type="^">
       
   132           <xsl:value-of select="$langstr"/>
       
   133         </langpart>
       
   134       </xsl:when>
       
   135 
       
   136       <xsl:otherwise>
       
   137         <xsl:variable name="c"
       
   138           select='substring($searchchars, string-length($searchchars), 1)'/>
       
   139 
       
   140         <xsl:variable name="newlangstr">
       
   141           <xsl:choose>
       
   142             <xsl:when test="contains($langstr, $c)">
       
   143               <xsl:value-of select="substring-before($langstr, $c)"/>
       
   144             </xsl:when>
       
   145             <xsl:otherwise>
       
   146               <xsl:value-of select="$langstr"/>
       
   147             </xsl:otherwise>
       
   148           </xsl:choose>
       
   149         </xsl:variable>
       
   150 
       
   151         <xsl:call-template name="langparts" mode="locale">
       
   152           <xsl:with-param name="langstr" select="$newlangstr"/>
       
   153           <xsl:with-param name="searchchars"
       
   154             select="substring($searchchars, 1,
       
   155             string-length($searchchars) - 1)"/>
       
   156         </xsl:call-template>
       
   157 
       
   158         <!-- Ignore codeset, if any -->
       
   159         <xsl:if test="$c != '.' and contains($langstr, $c)">
       
   160           <langpart type="{$c}">
       
   161             <xsl:value-of select="substring-after($langstr, $c)"/>
       
   162           </langpart>
       
   163         </xsl:if>
       
   164 
       
   165       </xsl:otherwise>
       
   166     </xsl:choose>
       
   167   </xsl:template>
       
   168 
       
   169   <!-- This should be overridden by the stylesheets that include this file -->
       
   170   <xsl:variable name="LOCALE_PKG_PREFIX"/>
       
   171 
       
   172   <!--
       
   173    * Based on the current node's <lang> element hierarchy (created in
       
   174    * the langparts template), load and combine all existing external resource
       
   175    * files using a ResourceBundle.getBundle-like algorithm:
       
   176    *
       
   177    * locale/${LOCALE_PKG_PREFIX}strings_<language>_<territory>@<modifier>.xml
       
   178    * locale/${LOCALE_PKG_PREFIX}strings_<language>_<territory>.xml
       
   179    * locale/${LOCALE_PKG_PREFIX}strings_<language>.xml
       
   180    * locale/${LOCALE_PKG_PREFIX}strings.xml
       
   181    -->
       
   182   <xsl:template match="lang" mode="locale">
       
   183     <xsl:param name="prefix"
       
   184       select="concat('locale/', $LOCALE_PKG_PREFIX, 'strings')"/>
       
   185     <xsl:param name="suffix" select="'.xml'"/>
       
   186 
       
   187     <!-- Language -->
       
   188     <xsl:if test="langpart[@type = '^']">
       
   189 
       
   190       <xsl:variable name="prefix.l">
       
   191         <xsl:value-of select="$prefix"/>
       
   192         <xsl:text>_</xsl:text>
       
   193         <xsl:value-of select="langpart[@type = '^']"/>
       
   194       </xsl:variable>
       
   195 
       
   196       <!-- Language + territory -->
       
   197       <xsl:if test="langpart[@type = '_']">
       
   198 
       
   199         <xsl:variable name="prefix.l.t">
       
   200           <xsl:value-of select="$prefix.l"/>
       
   201           <xsl:text>_</xsl:text>
       
   202           <xsl:value-of select="langpart[@type = '_']"/>
       
   203         </xsl:variable>
       
   204 
       
   205         <!-- Language + territory + modifier -->
       
   206         <xsl:if test="langpart[@type = '@']">
       
   207           <xsl:variable name="prefix.l.t.m">
       
   208             <xsl:value-of select="$prefix.l.t"/>
       
   209             <xsl:text>@</xsl:text>
       
   210             <xsl:value-of select="langpart[@type = '@']"/>
       
   211           </xsl:variable>
       
   212 
       
   213           <xsl:copy-of select="document(concat($prefix.l.t.m, $suffix))"/>
       
   214         </xsl:if>
       
   215 
       
   216         <xsl:copy-of select="document(concat($prefix.l.t, $suffix))"/>
       
   217       </xsl:if>
       
   218 
       
   219       <xsl:copy-of select="document(concat($prefix.l, $suffix))"/>
       
   220     </xsl:if>
       
   221 
       
   222     <xsl:copy-of select="document(concat($prefix, $suffix))"/>
       
   223   </xsl:template>
       
   224 
       
   225   <xsl:variable name="stringsrtf">
       
   226     <!-- Disect $LANG into its constituent parts -->
       
   227     <xsl:variable name="langparts">
       
   228       <lang>
       
   229         <xsl:call-template name="langparts" mode="locale"/>
       
   230       </lang>
       
   231     </xsl:variable>
       
   232 
       
   233     <!--
       
   234      * Create a node-set from the above RTF, then load appropriate external
       
   235      * localized files
       
   236      -->
       
   237     <xsl:apply-templates select="exsl:node-set($langparts)/lang" mode="locale"/>
       
   238   </xsl:variable>
       
   239 
       
   240   <xsl:variable name="strings" select="exsl:node-set($stringsrtf)"/>
       
   241 
       
   242   <!--
       
   243    * Locate the given string from the resource files discovered above.
       
   244    *
       
   245    * Arguments:
       
   246    *
       
   247    * name - the name of the <string> resource
       
   248    * params - an RTF of parameters to substitute for {N} within the found
       
   249    * string:
       
   250    *
       
   251    * <param>
       
   252    *   foo
       
   253    * <param>
       
   254    * <param>
       
   255    *   bar
       
   256    * <param>
       
   257    * ...
       
   258    -->
       
   259   <xsl:template name="getString">
       
   260     <xsl:param name="name"/>
       
   261     <xsl:param name="params"/>
       
   262 
       
   263     <xsl:variable name="string"
       
   264       select="($strings/resources/string[@name = $name])[1]"/>
       
   265 
       
   266     <!--
       
   267      * Look for a preserve-space attribute in the <string> or its parent
       
   268      * <resource> for guidance on whether space should be preserved.  If not
       
   269      * found in either element, default to false.
       
   270      *
       
   271      * Note: XSLT 1.0 forces variables to be RTFs when using child nodes
       
   272      * instead of the select attributes.  So add a non-empty string ("1") to
       
   273      * preserve space, then convert it to a boolean later.
       
   274      -->
       
   275     <xsl:variable name="preserve-space">
       
   276       <xsl:choose>
       
   277         <xsl:when test="$string/@preserve-space">
       
   278           <xsl:if test="$string/@preserve-space = 'true' or
       
   279             $string/@preserve-space = '1'">
       
   280             1
       
   281           </xsl:if>
       
   282         </xsl:when>
       
   283         <xsl:when test="$string/../@preserve-space">
       
   284           <xsl:if test="$string/../@preserve-space = 'true' or
       
   285             $string/../@preserve-space = '1'">
       
   286             1
       
   287           </xsl:if>
       
   288         </xsl:when>
       
   289       </xsl:choose>
       
   290     </xsl:variable>
       
   291 
       
   292     <xsl:variable name="text">
       
   293       <xsl:choose>
       
   294         <!--
       
   295          * Convert $preserve-space from an RTF to a string to a boolean, since
       
   296          * RTF-to-boolean conversion of a non-empty RTF always equals true
       
   297          -->
       
   298         <xsl:when test="not(boolean(string($preserve-space)))">
       
   299           <xsl:value-of select="normalize-space($string/text())"/>
       
   300         </xsl:when>
       
   301         <xsl:otherwise>
       
   302           <xsl:value-of select="$string/text()"/>
       
   303         </xsl:otherwise>
       
   304       </xsl:choose>
       
   305     </xsl:variable>
       
   306 
       
   307     <xsl:call-template name="parameterize" mode="locale">
       
   308       <xsl:with-param name="text" select="$text"/>
       
   309       <xsl:with-param name="params" select="exsl:node-set($params)"/>
       
   310     </xsl:call-template>
       
   311   </xsl:template>
       
   312 
       
   313   <xsl:template name="parameterize" mode="locale">
       
   314     <xsl:param name="text"/>
       
   315     <xsl:param name="params"/>
       
   316     <xsl:param name="level" select="1"/>
       
   317 
       
   318     <xsl:choose>
       
   319       <xsl:when test="$level > count($params/param)">
       
   320         <xsl:value-of select="$text"/>
       
   321       </xsl:when>
       
   322       <xsl:otherwise>
       
   323         <xsl:variable name="search" select="concat('{', $level, '}')"/>
       
   324         <xsl:choose>
       
   325           <xsl:when test="contains($text, $search)">
       
   326             <xsl:call-template name="parameterize" mode="locale">
       
   327               <xsl:with-param name="text"
       
   328                 select="substring-before($text, $search)"/>
       
   329               <xsl:with-param name="params" select="$params"/>
       
   330               <xsl:with-param name="level" select="$level + 1"/>
       
   331             </xsl:call-template>
       
   332             <xsl:copy-of select="$params/param[$level]/node()"/>
       
   333             <xsl:call-template name="parameterize" mode="locale">
       
   334               <xsl:with-param name="text"
       
   335                 select="substring-after($text, $search)"/>
       
   336               <xsl:with-param name="params" select="$params"/>
       
   337               <xsl:with-param name="level" select="$level"/>
       
   338             </xsl:call-template>
       
   339           </xsl:when>
       
   340           <xsl:otherwise>
       
   341             <xsl:call-template name="parameterize" mode="locale">
       
   342               <xsl:with-param name="text" select="$text"/>
       
   343               <xsl:with-param name="params" select="$params"/>
       
   344               <xsl:with-param name="level" select="$level + 1"/>
       
   345             </xsl:call-template>
       
   346           </xsl:otherwise>
       
   347         </xsl:choose>
       
   348       </xsl:otherwise>
       
   349     </xsl:choose>
       
   350   </xsl:template>
       
   351 </xsl:stylesheet>