| La serie sobre DXML.
Este artículo es el cuarto y último de la serie sobre el desarrollo de
interfaces de usuario en HTML dinámico (DHTML) para los sitios Web con
XML y XSL. En el primer artículo, utilizamos un archivo XML para almacenar
la información de la tabla de contenido (TDC) de un sitio, así como XSL,
CSS y scripts para generar una TDC en DHTML. En el segundo artículo, utilizamos
los mismos datos XML para generar menús DHTML como los que se utilizan
en el sitio Web microsoft.com y, en el tercer artículo, vimos tres formas
concretas de implementar los menús DHTML en los sitios Web.
En gran parte de este último artículo se asume que está familiarizado
con los conceptos y el código de los artículos anteriores. Si aún no lo
ha hecho, es aconsejable leer dichos artículos antes de continuar con
éste.
Traducción.
En esta ocasión implementaremos versiones de los menús DHTML traducidas
al japonés y al hebreo. Estos dos idiomas nos ofrecerán una perspectiva
interesante sobre todo lo necesario para traducir XML y DHTML a idiomas
con juegos de caracteres distintos del Europeo occidental y, en el caso
del hebreo, idiomas que se leen de derecha a izquierda o BiDi (bidireccionales).
El objetivo es demostrar que con una modificación mínima (además de la
traducción del contenido del archivo XML) de los archivos centrales (menus.xml,
menus.xsl, menus.jscript y menus.css) podemos presentar los menús DHTML
en cualquier idioma que admita el explorador.
A continuación se muestra la apariencia que tendrían los dos menús presentados
en DHTML:

Figura 1. Menús en japonés.

Figura 2. Menús en hebreo.
Tomaremos las versiones traducidas de los archivos XML, tanto en la codificación
del juego de caracteres específico del idioma como en Unicode UTF-8, y
presentaremos ambas salidas HTML, la específica del idioma y la Unicode.
Comentaremos las opciones necesarias para generar los archivos de inclusión
(#include) dinámicamente y sin conexión, y veremos todo lo que se debe
indicar al explorador para que la salida se presente de la forma prevista.
No desarrollaremos un tratado exhaustivo sobre la forma de traducir el
código (un tema agotador). Más bien veremos los principales conceptos
relacionados con este caso concreto, examinaremos el código de ejemplo
e iremos indicando lugares en los que obtener más información. Haremos
referencia repetidamente al código de ejemplo, por lo que recomendamos
copiar el código
de ejemplo antes de continuar. Consulte las instrucciones en el
archivo LEAME.txt incluido en el archivo comprimido.
Unicode vs los juegos de caracteres específicos
de idiomas.
El texto se puede mostrar de dos formas: en un juego de caracteres específico
del idioma o en Unicode. Unicode tiene varias ventajas: cada juego de
caracteres tiene su propio "espacio" en el juego de caracteres,
de modo que un visor habilitado para Unicode puede ver varios idiomas
al mismo tiempo. Por la misma razón, Unicode permite trabajar con un idioma
sin necesidad de especificar un juego de caracteres. No obstante, dado
que la compatibilidad con Unicode es relativamente reciente en muchas
aplicaciones, la práctica de especificar juegos de caracteres específicos
de los idiomas sigue siendo muy común. Las versiones 4.0 y 5 de Internet
Explorer son compatibles con Unicode, por lo que se recomienda el uso
de Unicode si el explorador de destino es uno de ellos.
Para obtener información general sobre Unicode, consulte Unicode
(en inglés) en el Web Workshop y Unicode,
juegos de caracteres y páginas de códigos (en inglés) en el sitio
sobre desarrollo de software global de Microsoft. Para obtener información
más detallada, consulte Juegos de caracteres (en inglés) en el sitio sobre
tipografía de Microsoft.
Traducción en el documento XML.
Además de traducir el contenido, en esta serie de artículos sólo se han
utilizado dos modificaciones de los datos XML en inglés. En primer lugar,
especificar la codificación del documento. En los menús en hebreo, si
el XML se hubiera escrito en el juego de caracteres específico del idioma,
windows-1255, la instrucción de procesamiento del XML tendría una apariencia
como la siguiente:
<?xml version="1.0" encoding="windows-1255"?>
Con el XML codificado en UTF-8 Unicode, la instrucción de procesamiento
tendría una apariencia como la siguiente:
<?xml version="1.0" encoding="UTF-8"?>
Dado que Internet Explorer 5 admite ambos juegos de caracteres, los archivos
XML "sin formato" tienen la misma apariencia al visualizarlos
en el explorador.

Figura 3. Archivo XML hebreo codificado
en windows-1255 visto en Internet Explorer 5.

Figura 4. Archivo XML hebreo codificado en UTF-8 visto en Internet
Explorer 5.
La segunda modificación de nuestro archivo consiste en especificar en
el XML el orden de lectura del contenido en un nodo DIR. En el caso del
hebreo (y del árabe), el orden de lectura es de derecha a izquierda, mientras
que en japonés es de izquierda a derecha. Lo utilizaremos en el XSL para
indicar al explorador la dirección en la que debe presentar el contenido.
No es preciso realizar ninguna otra modificación en el XML. En un momento
veremos las modificaciones necesarias para el XSL y scripts. Primero veremos
lo que se debe hacer en el servidor.
Traducción en el servidor de Web.
El trabajo con el texto traducido en el servidor de Web es muy sencillo
con Windows. Al igual que ocurre con los clientes, si realiza un procesamiento
ASP del XML, sólo debe asegurarse de que están instalados los paquetes
de idiomas apropiados en el sistema operativo. (Si sólo va a enviar HTML
o XML traducido, sin ningún trabajo en ASP, los paquetes de idiomas no
son necesarios.) Si trabaja con la versión en inglés, la compatibilidad
con los idiomas europeos occidentales ya está instalada. Puede descargar
paquetes de idiomas adicionales, como el japonés y el hebreo. Si ejecuta
Internet Explorer 5 en el servidor, lo cual es muy aconsejable en cualquier
caso, el propio explorador controla las actualizaciones de los paquetes
de idiomas. Sólo tiene que hacer clic en Herramientas | Windows Update
y seleccionar los paquetes de idiomas que necesite.
Internet Explorer 4.0 también admite la adición de paquetes de idiomas
adicionales con Windows Update, pero el número de idiomas compatibles
es menor. Por ejemplo, un documento en hebreo se puede ejecutar en cualquier
equipo Windows con Internet Explorer 5, mientras que otros exploradores,
incluido Internet Explorer 4.0, requieren la versión de Windows correspondiente
al idioma.
Cualquier archivo de páginas Active Server (ASP) que funcione con un
juego de caracteres no predeterminado debe tener especificada esta información
en la parte superior de la página con la directiva @CODEPAGE. Las directivas
se deben incluir en la primera línea de la página ASP, y las distintas
directivas se colocan en la misma línea. En el ejemplo siguiente se especifica
la página de códigos del japonés y el lenguaje de scripts predeterminado
para la página.
<% @ CODEPAGE="932" LANGUAGE="JScript"
%>
Para ejecutar japonés (o cualquier idioma) codificado en UTF-8 Unicode
sería necesaria la página de códigos siguiente.
<% @ CODEPAGE="65001" LANGUAGE="JScript"
%>
Sólo se puede especificar una página de códigos por documento, incluidas
todas las directivas #include.
Transformación dinámica del XML en el servidor.
Dado que todos los archivos de inclusión de una página heredan la página
de códigos del documento host, la inclusión se realiza después de especificar
la página de códigos. En el caso de nuestros ejemplos de inclusión dinámica
(ejemplos 3 y 8 del código de ejemplo), la instrucción transformNode()
se ejecuta de la forma habitual. El archivo XML se pasa a la inclusión
como un parámetro, en eso consiste la instrucción Request.QueryString
en realidad.
<%
// MENUS_DYN.INC
var sXml = String(Request.QueryString("xml"));
var sXsl = "menus.xsl";
var oXmlDoc = Server.CreateObject("Microsoft.XMLDOM");
oXmlDoc.async = false;
oXmlDoc.load(Server.MapPath(sXml));
if (0 != oXmlDoc.parseError.errorCode)
{
Response.Write('XML parseError on line ' + oXmlDoc.parseError.line);
Response.End();
}
var oXslDoc = Server.CreateObject("Microsoft.XMLDOM");
oXslDoc.async = false;
oXslDoc.load(Server.MapPath(sXsl));
if (0 != oXslDoc.parseError.errorCode)
{
Response.Write('XSL parseError on line ' + oXslDoc.parseError.line);
Response.End();
}
Response.Write(oXmlDoc.transformNode(oXslDoc));
%>
Tanto si se trabaja en UTF-8 como en una página de códigos específica
de un idioma, la inclusión dinámica se ocupa de sí misma.
Generación de una inclusión estática sin conexión.
Pueden existir buenas razones (la carga del servidor, por ejemplo) para
no transformar el XML en HTML dinámicamente en tiempo de ejecución y,
en su lugar, generar las inclusiones sin conexión y llamar en tiempo de
ejecución al HTML generado previamente (mostramos la forma de hacerlo
con Scripting.FileSystemObject). Este mismo enfoque sirve para el XML
traducido, con un truco importante si trabaja con juegos de caracteres
específicos de idiomas. Consulte el ejemplo 4 del código de ejemplo.
El intérprete XML funciona internamente con Unicode y pasa el Unicode
de forma predeterminada al realizar la transformación. Esto no supone
ningún problema al realizar la transformación dinámica, puesto que la
transformación recibe su entrada de codificación de la directiva CODEPAGE
del documento host. No obstante, al realizar la transformación sin conexión
en un archivo independiente, no existe tal entrada. Es preciso indicarle
al intérprete que trabajamos con una página de códigos, en lugar de Unicode
o la opción predeterminada del sistema. Para ello, se carga un objeto
"ficticio" con un documento XML en la codificación deseada y
se reemplaza el elemento documentElement por el del objeto transformado.
Finalmente, dado que FileSystemObject utiliza la configuración de idioma
del sistema, se debe utilizar el método XMLDocument.save() para guardar
el archivo estático. Todo esto es más sencillo de lo que parece.
<% @ LANGUAGE="JScript"
%>
<%
// MAKEMENU.ASP
var sLang = String(Request.QueryString("lang"));
if ("undefined" == sLang)
{
Response.Write('Especifique un idioma. ');
Response.End();
}
var sXml = "menus_" + sLang + ".xml";
var sXsl = "menus.xsl";
var oXmlDoc = Server.CreateObject("Microsoft.XMLDOM");
oXmlDoc.async = false;
oXmlDoc.load(Server.MapPath(sXml));
if (0 != oXmlDoc.parseError.errorCode)
{
Response.Write('XML parseError on line ' + oXmlDoc.parseError.line);
Response.End();
}
var oXslDoc = Server.CreateObject("Microsoft.XMLDOM");
oXslDoc.async = false;
oXslDoc.load(Server.MapPath(sXsl));
if (0 != oXslDoc.parseError.errorCode)
{
Response.Write('XSL parseError on line ' + oXslDoc.parseError.line);
Response.End();
}
// Truco para garantizar el paso del código deseado
// en el XML resultante
// Cargue el objeto XML con el archivo xml de menús
// convenientemente codificado
// y, a continuación, reemplace su documentElement con
// el del XML transformado
var oOutput = Server.CreateObject("Microsoft.XMLDOM");
oOutput.load(Server.MapPath(sXml));
var oTempOutput = Server.CreateObject("Microsoft.XMLDOM");
oXmlDoc.transformNodeToObject(oXslDoc,oTempOutput);
oOutput.documentElement = oTempOutput.documentElement;
var sIncFileName = "menus_stat_" + sLang + ".inc";
oOutput.save(Server.MapPath(sIncFileName));
%>
El código de dos letras del idioma se pasa a la página como un parámetro
y se convierte en la variable sLang, de modo que esta página ASP pueda
generar una inclusión ya creada con cualquier codificación. Observe el
uso de oTemp, cuya única finalidad es albergar el XML transformado y después
pasar documentElement a oOutput, el cual se ha "preparado" con
el correspondiente archivo menus-xx.xml que contiene la codificación adecuada.
De nuevo, esto es necesario por guardar en un archivo, pues una directiva
CODEPAGE no serviría de ayuda en este caso.
Si sólo trabaja en Unicode para la salida, no es necesario agregar este
truco. Consulte el ejemplo 9 del código de ejemplo.
Si no va a modificar el XML en el servidor (por ejemplo, simplemente
va a enviar el XML directamente al cliente) no es preciso especificar
una página de códigos en el archivo ASP.
Traducción en el explorador de Web.
Al igual que ocurre con el servidor, para trabajar con XML y HTML traducidos
en el cliente, es preciso que estén instalados los paquetes de idiomas
adecuados. Además, se deben realizar algunas modificaciones en el código
del lado del cliente: una etiqueta META de tipo y contenido (Content-Type)
que indique los caracteres en los que debe presentar el contenido el explorador;
un atributo DIR en los elementos traducidos (sólo es necesario para los
idiomas bidireccionales); y algún código JScript para situar los menús
a la derecha en los idiomas que se leen de derecha a izquierda.
Tipo de contenido META (Content-Type).
Para que Internet Explorer presente el contenido correctamente, debe
colocarse una etiqueta META en la sección HEAD del documento. Dicha etiqueta
especifica el tipo y contenido del HTML, como se muestra a continuación
para nuestros archivos HTML hebreos en windows-1255 y UTF-8.
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1255">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
Estos juegos de caracteres se corresponden directamente con los utilizados
en nuestros archivos XML, lo que facilita las cosas.
El atributo DIR.
Si observa los menús en hebreo (figura 2), verá que los menús se muestran
de derecha a izquierda, mientras que la línea "Aquí va el contenido
normal del documento" se muestra de izquierda a derecha. Para lograrlo
se ha especificado "RTL" (del inglés Right To Left, de derecha
a izquierda) en el atributo DIR (en inglés) de los elementos que se van
a presentar en este orden de lectura. DIR se puede establecer en elementos
individuales, en el elemento HTML (de nivel superior) o en una combinación
posterior.
A continuación se muestra el HTML inicial para el elemento <DIV>
de la barra de menús (MenuBar) de los menús en hebreo.
<DIV ID="divMenuBar" DIR="RTL"
ONMOUSEOVER="if (document.all) MenuBar_over();"
ONMOUSEOUT="if (document.all) MenuBar_out();"
ONSELECTSTART="return false;" >
Como se mencionó anteriormente, esta información sobre el orden de lectura
se almacena en la parte superior del documento XML y se pasa a la salida
HTML en la hoja de estilo XSL. Observe la cuarta línea de la Figura 3
o 4 anterior. A continuación se muestra el código responsable.
<xsl:attribute name="DIR"><xsl:value-of select="/TOPICLIST/DIR"/></xsl:attribute>
Simplemente se agrega esta línea allí donde se vayan a mostrar elementos
sensibles al orden de lectura en el XSL y dichos elementos tendrán la
información necesaria para mostrarse correctamente en el explorador.
Colocación de menús en scripts.
Aunque el atributo DIR controlará perfectamente el orden de lectura del
texto dentro de los elementos, no alineará automáticamente los menús a
la derecha de la barra de menús cuando sea necesario. Del mismo modo que
resultó necesario colocar estos elementos explícitamente en el script
para los menús en inglés, es preciso hacerlo para las codificaciones de
derecha a izquierda. Afortunadamente, podemos comprobar el valor del atributo
DIR y simplemente agregar una línea condicional de JScript que se ocupe
de ello.
A continuación se muestra el código modificado de la función OpenMenu().
eMenu.style.left = eSrc.parentElement.offsetLeft + divMenuBar.offsetLeft;
if ("RTL" == eMenu.getAttribute("dir").toUpperCase())
{
eMenu.style.left = eMenu.offsetLeft - eMenu.offsetWidth +
eSrc.parentElement.offsetWidth;
}
Si el orden de lectura, indicado por el atributo DIR del elemento, es
de derecha a izquierda, para ajustar la posición se resta el ancho del
menú y se agrega el ancho de la celda de la tabla. De este modo se alinea
el borde derecho del menú con el borde derecho del elemento asociado de
la barra de menús.
Si se desea evitar el ajuste de línea en los menús, el ancho del menú
no se debe codificar en el archivo .css, como ocurre en el caso actual,
sino establecerse dinámicamente (en porcentaje o en unidades "eme")
en OpenMenu() como una función de la longitud de la cadena más larga del
menú. Eso quedará como ejercicio para el lector.
Una modificación más.
He realizado otra modificación en el archivo XSL. En el código original
se utilizó el atributo TYPE de un elemento TOPICLIST para establecer el
Id. de la celda de la tabla de salida que se va a utilizar en el script.
Dado que había una posibilidad de que esto pudiera verse afectado por
el juego de caracteres, cambié el código para utilizar el método XSL uniqueID(en
inglés). Este método asigna un Id. numérico único, el cual debería eliminar
cualquier posible complicación de juego de caracteres al ejecutar el script
en vivo en el explorador. He mantenido el código original con marcas de
comentario en la hoja de estilo menus.xsl.
<xsl:attribute name="ID">tdMenuBarItem<xsl:eval>
uniqueID(this)</xsl:eval></xsl:attribute>
Conclusión e información adicional.
Utilizar XML para almacenar y transformar los menús traducidos es un
gran acierto. Se agrega un atributo y un elemento al archivo XML, una
línea al archivo XSL y una línea al archivo de scripts, y ya se puede
manejar cualquier idioma que admita el explorador.
La compatibilidad de idiomas mejorada de Internet Explorer 5 hace que
sea el explorador de destino ideal. Si se trata del explorador que utiliza
su audiencia, dé gracias por su fortuna y utilice UTF-8 Unicode como método
de codificación, ya que éste proporciona la compatibilidad de idiomas
basada en explorador más amplia y le libera de preocupaciones sobre páginas
de códigos. También es un estupendo entorno de desarrollo.
|