Una persona me lo ha pedido, así que aquí está como prometí la traducción de mi
mensaje original en inglés, para quienes no se defienden bien en esta lengua. No he traducido los nombres de los comandos ni de las variables. Me parece que no es necesario y que con las explicaciones y los comentarios del código basta. Si aun así alguien tiene alguna duda, que me escriba.
Creo que este método es fácil de implementar y de usar para cualquier usuario. No hace falta ser programador, tan sólo estar familiarizado un poco con CMSMS.
[
Actualización (2009-08-26): Pierre-Luc ha escrito
un módulo llamado Babel, basado en este método, más fácil de usar y con más prestaciones.]
[
Actualización (2009-09-23): Después de casi tres años,
he decidido dejar de usar CMSMS. El motivo es que el sistema se está volviendo desmesuradamente complejo para mis necesidades. Además las últimas versiones han hecho que buena parte de mi código dejara de funcionar. Las páginas en que usaba CMSMS las estoy pasando a un programa creado por mí, mucho más sencillo y productivo, de estilo wiki, sin base de datos y programable directamente en PHP sin capas ni interfaces ni complicaciones.]
Características del método propuesto
- * Basta una única plantilla para todas las páginas de todas las lenguas (aunque por supuesto se puede usar más).
- * Sólo hacen falta dos comandos de plantilla (llamados habitualmente "tags personalizados", "UDT" o "User Defined Tags").
- * Admite cualquier número de lenguas.
- * No obliga a que las páginas tengan siempre versiones en las demás lenguas.
- * Los alias de las páginas pueden ser totalmente distintos para cada lengua.
- * Permite especificar una página predeterminada para cada lengua, para cuando no existe una traducción disponible.
- * Los botones del menú de lenguas son totalmente configurables, con cualquier código XHTML, texto o imágenes.
- * El menú de lenguas es configurable con parámetros para hacer lo siguiente:
- [li] - Mostrar los títulos de página en lugar de los botones configurados.
- - Mostrar un enlace inactivo a la página actual, o bien no mostrar nada.
- - Mostrar un enlace a la página predeterminada cuando no haya traducción disponible, o bien no mostrar nada.
- - Mostrar un enlace inactivo cuando no se haya especificado página predeterminada, o bien no mostrar nada.
[/li]
- * Código PHP totalmente comentado. Fácil de entender y de adaptar.
Paso 1: Crear la jerarquía del contenido
En la sección de contenido, crea en la raíz una entrada de cabecera (tipo "Section Header") para cada lengua que vayas a usar en tus páginas:
1) Dale el nombre que quieras (por ejemplo el nombre de la lengua); este nombre no será público.
2) Como alias, ponle el código estándar ISO de dos letras de la lengua (por ejemplo, "es" para el castellano, "en" para el inglés", "pt" para el portugués...)
3) Desmarca la opción "Mostrar en menú", pues no queremos que este elemento se muestre después en los menús de navegación.
A partir de ahora, todo el contenido que crees (páginas, nuevas cabeceras de sección) debes colgarlo bajo la lengua que le corresponda. Es decir, es como si tuvieras una rama principal del árbol de contenido para cada lengua.
Paso 2: Obtener la lengua de cada página
Crea un nuevo comando de plantilla (lo que se llama habitualmente "tag personalizado" o "UDT").
Para ello ve al menú "Extensiones/Tags personalizados". Dale el nombre
assign_page_lang.
El código de dicho comando es el que sigue (cópialo de aquí y pégalo):
Code: Select all
/*
Asigna la variable de plantilla $page_lang dependiendo de la raíz a la que pertenezca la página actual.
El alias de la raíz debe ser el código de la lengua (de dos letras).
2008-02-02 Marcos Cruz (http://alinome.net)
Segunda versión, sin matriz.
Referencias:
http://wiki.cmsmadesimple.org/index.php/Share_your_tags_here#Get_a_page.27s_root_parent.27s_alias
*/
global $gCms;
global $smarty;
$manager =& $gCms->GetHierarchyManager();
$result = '??';
$thisPage = $gCms->variables['content_id'];
$currentNode = &$manager->sureGetNodeById($thisPage);
while( isset($currentNode) && $currentNode->getLevel() >= 0 )
{
$currentContent =& $currentNode->getContent();
$result = $currentContent->Alias();
$currentNode =& $currentNode->getParentNode();
}
$smarty->assign('page_lang',$result);
Ese comando navega hacia arriba en el árbol de contenido desde la página actual hasta que no puede subir más, es decir, hasta que llega a la cabecera de sección que representa la lengua, y entonces guarda en
la variable de plantilla $page_lang el código de la lengua, que es como vimos el alias de dicha cabecera.
Ahora simplemente debes poner la instrucción al comienzo de tu plantilla de página (o en todas, si usas varias):
Paso 3: Elegir el contenido de tus páginas en función de la lengua
Una vez que la plantilla ha ejecutado el comando anterior, la variable de plantilla
$page_lang contiene el código de la lengua y puedes usarla en la plantilla o
en las páginas para elegir el contenido:
Ejemplo 1. Marcar correctamente la lengua de la página en la etiqueta :
Code: Select all
<__html xmlns='http://www.w3.org/1999/xhtml' xml:lang='{$page_lang}'>
Ejemplo 2. Poner el título del sitio en la plantilla:
Code: Select all
{if $page_lang == 'es'}<h1>Título en castellano</h1>
{elseif $page_lang == 'eo'}<h1>Esperanto-titolo</h1>
{else}<h1>English title</h1>
{/if}
En cualquier lugar de una plantilla o de una página o de un bloque de contenido puedes usar la variable para tomar decisiones.
Paso 4: Crear el menú de contenido
¿Cómo mostrar con el comando de plantilla
{menu} sólo el menú de navegación de las páginas de la lengua correspondiente?
Un método es usar el parámetro
start_element, para seleccionar la cabecera de sección raíz de la lengua. Esto mostrará sólo las páginas de ese elemento y de sus descendientes. Por ejemplo:
Code: Select all
<div id='menu'>
{if $page_lang == "es"}{menu template='my_menu' start_element='1.1'}
{else}{menu template='my_menu' start_element='2.1'}
{/if}
</div>
Otro método es usar el parámetro
start_level. En este caso basta un solo comando
{menu}:
Code: Select all
<div id='menu'>
{menu template='my_menu' start_level='2'}
</div>
Lee la ayuda del módulo de menú para aprender cómo usar estos y otros parámetros y haz pruebas. (El parámetro "start_level" no me resulta fácil de entender: con ciertos valores me pone marcas "" en exceso y con otros me las quita y tengo que ponerlas yo en la plantilla... Busca la combinación que funcione en tu caso y comprueba si el XHTML resultante es correcto.
Paso 5: Especificar las traducciones disponibles de cada página
Pon esto en la parte superior de tu plantilla:
Code: Select all
{content block='Other languages' oneline='true' assign='other_languages' wysiwyg='false'}
Eso creará un bloque de contenido nuevo en cada página que saldrá en el formulario donde se escribe el contenido de la misma. El parámetro "block" puede tener el valor que te guste, pues es sólo el título del bloque, lo que verás en el formulario. El parámetro "assign" hace que el contenido de este bloque no se muestre en las páginas sino que se asigne a una variable de plantilla con el nombre especificado. Eso es lo que nos interesa. Este bloque de contenido lo usaremos para guardar en él los nombres de las páginas que contienen traducciones de la página actual, de la siguiente manera:
en=alias-de-la-versión-inglesa;pt=alias-de-la-versión-portuguesa;de=alias-de-la-versión-alemana
No se puede usar espacios. Los códigos de lenguas son los ISO de dos letras (hay de tres también, pero habría que modificar un poco el programa para usarlos). Cada versión debe separarse con un punto y coma. Puedes poner tantas versiones como quieras en cualquier orden, no afecta para nada. Puede haber páginas que no tengan ninguna traducción disponible y otras que tengan muchas.
Paso 6: Crear el menú de lenguas
Crea un nuevo comando de plantilla (igual que antes, en el menú "Extensiones/Tags personalizados") y llámalo
language_menu.
Copia y pega en él el código que sigue (tiene muchos comentarios para facilitar su comprensión):
Code: Select all
/*
Crea un menú de lenguas (versión 5).
2008-02-06 Por/Far/By Marcos Cruz (http://alinome.net)
*/
global $gCms;
// ----------------------------------------------------------------
// Parámetros
// ¿Mostrar el título de página en los enlaces? (true/false)
// (si es "false", mostrar los botones predefinidos)
$show_title = isset($params['show_title']) ? $params['show_title'] : false;
// ¿Mostrar un enelace inactivo a la página actual? (true/false)
// (si es "false", no se crea ninguna entrada en el menú para la página actual)
$show_current = isset($params['show_current']) ? $params['show_current'] : false;
// Si no hay una traducción disponible, ¿mostrar un enelace a la página predeterminada de esa lengua? (true/false)
// (si es "false", no se crea ninguna entrada en el menú para dicha página)
$show_default = isset($params['show_default']) ? $params['show_default'] : true;
// Si el parámetro "show_default" es "false" o bien no hay se ha especificado página predeterminada, ¿mostrar un enlace inactivo? (true/false)
// (si es "false", no se crea ninguna entrada en el menú para dicha página)
$show_inactive = isset($params['show_inactive']) ? $params['show_inactive'] : true;
// ----------------------------------------------------------------
// Constantes
define ("DEFAULT_PAGE",0);
define ("BUTTON",1);
// ----------------------------------------------------------------
// Datos sobre las lenguas, comunes a todas las páginas
/*
La matriz $languages guarda información sobre todas las lenguas del sitio
Su clave índice es el código de la lengua.
Cada elemento es a su vez una matriz que contiene dos elementos:
0) La página opcional predeterminada para la lengua (que se usará cuando no haya una traducción válida,
siempre que el parámetro "show_default" sea "true"). Puede estar vacío (en cuyo caso el parámetro "show_inactive" decidirá lo que hay que hacer).
1) El código (X)HTML del botón de enlace (usado cuando el parámetro "show_title" sea "false" o no haya sido especificado).
Para hacer el código más legible, en el bucle principal que crea el menú se accede a estos elementos mediante las constantes DEFAULT_PAGE y BUTTON.
*/
// Matriz de ejemplo para cinco lenguas. Adáptala a tus necesidades.
$languages = array(
'en' => array('home', '<span xml:lang="en">English</span>'),
'es' => array('inicio', '<span xml:lang="es">Castellano</span>'),
'eo' => array('komenco', '<span xml:lang="eo">Esperanto</span>'),
'lt' => array('pradinis', '<span xml:lang="lt">Lietuviškai</span>'),
'ru' => array('glavnaja', '<span xml:lang="ru">Pусский</span>') );
// ----------------------------------------------------------------
// Variables sobre la página actual
$page_lang = $gCms->smarty->get_template_vars('page_lang'); // obtener la variable de plantilla page_lang , que fue asignada por el comando de plantilla {assign_page_lang}
// ----------------------------------------------------------------
// Versiones en otra lengua de la página actual
/*
La variable de plantilla $other_languages es asignada con un bloque de contenido en la plantilla, por ejemplo:
{content block='Other languages' oneline='true' assign=other_languages wysiwyg='false'}
Para cada página, este bloque ha de rellenarse con una cadena de texto con el formato siguiente:
"c1=página1;c2=página2;c3=página3" (no se puede poner espacios),
donde c(n) representa el código de la lengua (de dos letras);
puede especificarse cualquier número de lenguas en cualquier orden.
Dicha cadena es convertida en la matriz $language_versions.
*/
$other_languages = $gCms->smarty->get_template_vars('other_languages');
foreach ( explode(';', $other_languages) as $other_language )
{
$language_codes[]=substr($other_language, 0, 2);
$language_pages[]=substr($other_language, 3);
}
$language_versions = array_combine($language_codes, $language_pages);
/*
echo '<p><strong>DEBUG</strong>:';
echo "<br/>language_codes="; print_r($language_codes);
echo "<br/>language_pages="; print_r($language_pages);
echo "<br/>language_versions="; print_r($language_versions);
echo '</p>';
*/
// ----------------------------------------------------------------
function smarty_tag ($smarty_tag)
{
// Ejecuta un comando de plantilla.
// Referencias:
// http://wiki.cmsmadesimple.org/index.php/User_Handbook/Admin_Panel/Extensions/User_Defined_Tags#How_to_Execute_Smarty_Tags_from_A_User_Defined_Tag_.28UDT.29
global $gCms;
/*
echo '<p><strong>smarty_tag DEBUG</strong>:';
echo "<br/>smarty_tag=$smarty_tag";
echo '</p>';
*/
$smarty = &$gCms->GetSmarty();
$smarty->_compile_source('temporary template', $smarty_tag, $_compiled);
@ob_start();
$smarty->_eval('?>' . $_compiled);
$_contents = @ob_get_contents();
@ob_end_clean();
echo $_contents;
}
// ----------------------------------------------------------------
function smarty_cms_selflink ($page, $text, $more)
{
// Ejecuta el comando de plantilla {cms_selflink}.
/*
echo '<p><strong>smarty_self_link DEBUG</strong>:';
echo "<br/>page=$page";
echo "<br/>text=$text";
echo "<br/>more=$more";
echo '</p>';
*/
smarty_tag ("{cms_selflink page=$page" . ( (empty($text)) ? '' : " text='$text'" ) . ' more="' . $more . '"}');
}
// ----------------------------------------------------------------
function valid_page($page_alias)
{
// ¿Es correcto un alias de página?
// Comprueba si un alias de página efectivamente existe (si está en blanco el resultado será también negativo).
// Referencias:
// http://forum.cmsmadesimple.org/index.php/topic,3778.msg20921.html#msg20921
global $gCms;
$manager =& $gCms->GetHierarchyManager();
$node =& $manager->getNodeByAlias($page_alias);
return ( $node != null );
}
// ----------------------------------------------------------------
function current_page_title()
{
// Devuelve el título de la página actual.
// Se necesita sólo para crear un enlace inactivo a la página actual cuando el parámetro "show_title" es "true".
// Referencias:
// http://forum.cmsmadesimple.org/index.php/topic,3778.msg20921.html#msg20921
// http://forum.cmsmadesimple.org/index.php/topic,3778.msg21051.html#msg21051
global $gCms;
$this_page = $gCms->variables['content_id'];
$manager =& $gCms->GetHierarchyManager();
$node =& $manager->GetNodeById($this_page);
$content =& $node->getContent();
return $content->Name();
}
// ----------------------------------------------------------------
// Crea el menú
/*
echo '<p><strong>DEBUG</strong>:';
echo "<br/>page_lang=$page_lang";
echo "<br/>show_title=$show_title";
echo "<br/>show_current=$show_current";
echo "<br/>page_title=$page_title";
echo "<br/>language_versions="; print_r($language_versions);
echo "<br/>language_buttons="; print_r($language_buttons);
echo '</p>';
*/
echo '<ul>';
foreach ( $languages as $language_code => $language ) // explorar todas las posibles lenguas del sitio
{
// $language_code = código de la lengua a la que hay que crear un enlace
// $language[DEFAULT_PAGE] = la página predeterminada para la lengua, a usar cuando no se ha definido una alternativa o ésta no es válida
// $language[BUTTON] = (X)HTML usado como botón para el enlace, cuando el parámetro "show_title" es "false".
/*
echo '<p><strong>menu DEBUG</strong>:';
echo "<br/>language_code=$language_code";
echo "<br/>language="; print_r($language);
echo '</p>';
*/
if ( $language_code != $page_lang )
{
$alternative_page = $language_versions[$language_code];
// echo "alternative_page=$alternative_page"; // DEBUG
if ( valid_page($alternative_page) )
{
echo '<li>';
// echo "ALTERNATIVE: $alternative_page"; // DEBUG
smarty_cms_selflink($alternative_page,($show_title == true ) ? "" : $language[BUTTON], "hreflang='".$language_code."'");
echo '</li>';
}
else // no hay alternativa válida para esta lengua
{
if ( $show_default == true and valid_page($language[DEFAULT_PAGE]) )
{
echo '<li>';
// echo 'NO ALTERNATIVE! DEFAULT: '; // DEBUG
smarty_cms_selflink($language[DEFAULT_PAGE],( ($show_title == true ) ? "" : $language[BUTTON] ) , "hreflang='".$language_code."'");
echo '</li>';
}
else
{
if ( $show_inactive == true )
{
echo '<li class="inactive">';
// echo 'DEFAULT CAN NOT BE USED! INACTIVE BUTTON: '; // DEBUG
echo $language[BUTTON] . '</li>';
}
}
}
}
elseif ( $show_current == true )
{
// echo 'SHOW CURRENT'; // DEBUG
echo '<li class="currentpage">' . ( ($show_title == true) ? current_page_title() : $language[BUTTON] ) . '</li>';
}
}
echo '</ul>';
Ahora configura el código según tus necesidades: Cambia la matriz
$languages con las lenguas que necesitas, la página predeterminada para cada una y su botón (X)HTML. Eso es todo. El orden de las lenguas en la matriz será el orden de los botones en el menú.
Ya puedes poner el nuevo comando
{language_menu} en el lugar deseado de tu plantilla (pero siempre después del bloque de contenido "Other languages"; por eso en el
Paso 5 colocamos dicho bloque en la parte superior de la plantilla). El menú en sí es sólo una lista . El aspecto dependerá por supuesto de los estilos que apliques. Para ello probablemente necesites encerrar el menú en un con identificador único. Por ejemplo:
Code: Select all
<div id='langmenu'>
{language_menu}
</div>
También puedes usar los parámetros opcionales (que están explicados en detalle en el propio código):
Code: Select all
<div id='langmenu'>
{language_menu show_title=false show_current=true show_default=true show_inactive=false}
</div>
En el código hay algunos comentarios marcados con la palabra "DEBUG". Encierran instrucciones útiles mientras se modifica el código, para localizar posibles errores. Si no tienes intención de modificar el programa puedes borrarlos.
Fin
Eso es todo. Espero que os sea útil.
Estoy usando este sistema en un sitio personal y funciona muy bien. Mandaré la dirección cuando esté bonito, pues aún no tiene contenido. Este es el sitio, por si queréis ver este método en funcionamiento: http://cartasaalien.eu.
Adaptación para PHP 4
Un usuario ha propuesto en el foro inglés
un parche para poder usar este método con PHP4. Se trata de un reemplazo para una función que es exclusiva de PHP5.