Páginas multi-idioma con PHP

  • Por
Para realizar una página web multi-idioma necesitamos solucionar varios problemas con la traducción de los textos en diferentes idiomas.
Para realizar una página web multi-idioma necesitamos solucionar varios problemas o casuísticas. Vamos a numerarlas rápidamente y posteriormente daremos una posible solución para cada una.

  1. Traducción de textos planos
  2. Traducción de textos que están insertados en una base de datos
  3. Traducción de textos mezclados con valores de variables

En líneas generales, la solución pasa por tener guardados en variables todos los textos que se van a mostrar en la página. Podemos utilizar variables tal cual o bien generar un array con todos los textos a traducir, lo que puede mejorar la organización del código.

Veamos las explicaciones de los tres casos señalados anteriormente.

1) Podemos tener textos planos que traducir, es decir, textos que simplemente debemos colocarlos en un idioma u otro, dependiendo de la preferencia del usuario.

Por ejemplo, tenemos que poner escribir palabra "nombre" en la página. En español escribiremos "nombre", pero cuando se visite el sitio en inglés, escribiríamos "name".

Esto lo estamos solucionando con un fichero de texto, en el que tenemos como variables todas las palabras o frases planas que se necesitan escribir en la página, en varios idiomas. Así tenemos un fichero con las palabras y frases en español, otro con las del idioma inglés y, por ejemplo, otro con las de portugués.

Las variables que estamos utilizando son del estilo $idioma_loquesea. Por ejemplo, en el fichero en español podemos tener varias palabras y frases como estas:

$idioma_nombre = "nombre";
$idioma_direccion = "dirección";
$idioma_error_usuario = "Hemos detectado un error con el usuario";

En el idioma inglés tendríamos un fichero parecido a este: (perdonar si mis traducciones no son del todo correctas)

$idioma_nombre = "name";
$idioma_direccion = "address";
$idioma_error_usuario = "We have detected an user error";


En las páginas multi-idioma, detectaríamos el idioma que ha seleccionado el usuario, para incluir un fichero de idioma u otro.

Luego, al mostrar un texto, podríamos sacar algo como esto:

echo $idioma_nombre . ": pepe";
echo $idioma_direccion . ": C/ corona, 2";


Dependiendo del fichero de idioma que se haya incluido tendremos un resultado distinto. En español saldría:

nombre: pepe
dirección: C/ corona, 2

Si hubiéramos incluido el fichero de idioma inglés, obtendríamos como salida

name: pepe
address: C/ corona, 2

2) Podemos tener otro caso de elementos a traducir más complejo. Supongamos que tenemos una tabla de países. Los países se llaman de manera distinta en cada idioma, así que de alguna manera tenemos que almacenar el nombre del país para muchos idiomas distintos.

Esto se puede hacer de varias maneras. Por ejemplo, podríamos tener una tabla con los identificadores de los países y la traducción para cada idioma. Luego, en la página dependiendo del idioma, tendríamos que mostrar un texto u otro para el país, seleccionando la traducción que necesitamos para el país.

Por ejemplo, podríamos tener la tabla pais, de esta manera:

id_pais - nombre_pais_es - nombre_pais_en
1 - España - Spain
2 - Italia - Italy
3 - Francia - France

Luego, al recuperar los nombres de los países, podríamos hacer algo como esto:

if ($lenguaje_seleccionado = "ES"){
    $ssql = "select id_pais, nombre_pais_es as 'nom_pais' from pais";
}else{
   $ssql = "select id_pais, nombre_pais_en as 'nom_pais' from pais";
}


Luego, recuperaríamos los datos de la tabla y en el campo 'nom_pais' tendremos la traducción que necesitamos.

Pero esto no nos gusta, porque no nos estamos abstrayendo del idioma del usuario para mostrar el nombre del país. Es decir, en el código de la aplicación tenemos que hacer cosas distintas para cada idioma. Lo mejor sería programar la página igual, sin tener que preguntar en ningún momento el idioma en el que estamos trabajando, así no habrá que tocar el código nunca para incorporar nuevos idiomas, ni estamos mezclando la lógica de la aplicación con la lógica de la gestión del idioma.

Una solución para mejorar esto es utilizar un fichero de texto para los nombres de los países y tener un fichero de texto para cada idioma, de manera similar a lo que habíamos comentado para el caso anterior.

Dentro de este fichero, tendremos los nombres de los países, en un archivo independiente para cada idioma. Los nombres los podemos meter en un array para facilitar su gestión, con los índices iguales al identificador utilizado en la tabla país.

Para el idioma español tendríamos:

$idioma_nombre_pais[1] = "España";
$idioma_nombre_pais[2] = "Italia";
$idioma_nombre_pais[3] = "Francia";

Para el idioma inglés, tendríamos:

$idioma_nombre_pais[1] = "Spain";
$idioma_nombre_pais[2] = "Italy";
$idioma_nombre_pais[3] = "France";


Luego, al seleccionar los distintos países de la base de datos, la sentencia SQL será la misma:

$ssql = "select id_pais from pais";

Al mostrar los nombres de países, tan sólo tenemos que acceder al array $idioma_nombre_pais, con el índice del país que se desea mostrar. Es decir, el código será el mismo, aunque el resultado al visualizar el nombre de país dependerá del archivo de idioma que hayamos cargado (en español o inglés). Por ejemplo, si quisiéramos mostrar un elemento de formulario <select> con los distintos países el código sería:

echo "<select name='id_pais'>";
$ssql = "select id_pais from pais";
$rs = mysql_query($ssq);
while ($fila = mysql_fetch_object($rs)){
   echo "<option value='" . $fila->id_pais . "'>";
echo $idioma_nombre_pais[$fila->id_pais];
echo "</option>";
}
echo "</select>";

3) El último caso que vamos a ver en las traducciones es una mezcla entre textos planos y valores de variables. Por ejemplo, pensemos en una frase como esta:

Tienes X documentos subidos, Y abiertos

Donde X es el valor de una variable numérica, al igual que Y. Lógicamente, en lugar de la X o la Y, lo que queremos ver es el valor numérico que tengan esas variables.

Para implementar cómodamente esta parte del sistema multi-idioma, podemos utilizar la función printf(), que es parecida a echo, pero aparte de la cadena a mostrar, permite indicar otros parámetros con valores que se que se sustituirán en la cadena, antes de mostrarla en la página. Veamos con un ejemplo esto.

La cadena en español que queremos mostrar es:

$idioma_documentos_abiertos = "tienes %1u documentos subidos, %2u abiertos";

En inglés, este mismo mensaje quedaría:

$idioma_documentos_abiertos = "You have upload %1u documents, %2u open";

Con "%1u" en la cadena hemos especificado un parámetro y con "%2u" hemos especificado otro parámetro. Ambos se debe sustituir por un valor que también enviaremos a printf(). Del parámetro "%1u", la parte del "%1" hace referencia al primer parámetro y la "u" dice que es numérico, en base 10, sin decimales.

En la llamada a printf() debemos especificar la cadena a mostrar y los parámetros que se deben sustituir en la cadena, en nuestro ejemplo 2.

printf($idioma_documentos_abiertos, 6, 4);

Esto tendrá como salida, para la frase en español:

tienes 6 documentos subidos, 4 abiertos

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

Gabriel Luraschi

16/2/2006
Y qué pasa con los juegos de caracteres?

La ñ en sitios con juegos de caracteres en inglés aparece como un simbolito. Lo que se podría hacer es traducir todos los caracteres necesarios a sus respectivas representaciones HTML, ej:

& = &amp;
< = &lt;
...

Saldos.

PD: También hay potentes herramientas como GETTEXT que permiten traducir sitios completos hasta en CHINO, con sus respectivos juegos de caracteres. No viene mal una ojeada a esto.

Henryay

17/2/2006
Me parece muy interesante este articulo, pero q pasa con el posicionamiento?, es decir, los keywords, description... en q idioma deberian estar? o tambien hay q crearlo un file para su traducción? y si es asi, esto lo reconocen los buscadores?. Hay muchas paginas q tienen cada idioma en diferentes carpetas, pues de esta manera ponen los keywords... en la carpeta segun el idioma q este. Claro q esta manera no es tan eficiente pues si quiero modificar algo en ES(español) tengo q modificarlo para todos los idiomas y eso no es eficiente. Gracias

Paco Fernández

17/2/2006
Bien, y si el idioma es árabe ¿cómo hacemos?

Javier

18/2/2006
La solución que presentáis es correcta pero tiene una componente de tirar líneas excesivas. Podíes hacer una artículo de cómo utilizar GETTEXT para hacer sitios multiidiomas mucho más potente

Joel Hoyos

01/7/2006
Muy bueno, pero no es mejor hacerlo con XML?

Saludos
Joel Hoyos

Henry Ortiz

20/9/2006
me gustaría que analizaran las siguientes URLS

http://www.google.com/support/webmasters?hl=en

http://www.google.com/support/webmasters?hl=fr

http://www.google.com/support/webmasters?hl=jp

como pueden ver, "HL" define el lenguaje, estoy casi seguro que lo que hacen es guardar en una sola base de datos o tabla todos los textos o articulos ya traducidos, y ubican por ejemplo "mi mamá me mima" en una sola fila con todos los campos de diferentes idiomas los diferentes textos traducidos, asi el juego de registros sería super rápido y el sql muy sencillo. Incluso las modificaciones quedarían fácil.

simplemente la variable hl diría cual campo de la tabla deberá usar.

sql en español= traiga el campo "japones" de la tabla textos donde el numero unico del texto sea "un numero de id".

si estoy mal corrijanme que apenas empiezé con esto.

Juan Carlos

21/12/2006
Aqui hay un buen manual para Construir aplicaciones multilenguaje con gettext

http://www.aeoris.net/escritos/php/construir-aplicaciones-multilenguaje-con-gettext.html#funcionamiento

ZasKan

03/11/2012
Ayuda: Problema con sistema multidioma
Hola a todos,

Estoy desarrollando una herramienta con función multi idioma.
Tengo los valores de cada etiqueta en base de datos, en una tabla en la que recojo los valores:

TextId
LangId
Text

Utilizo la siguiente función para rescatar el valor de las etiquetas:

function GetTag($tag)
{
$UserLG = $_SESSION["UserLG"];
$query = "SELECT Text FROM InterfaceText where TextId = $tag and LangId = '$UserLG' limit 1;";
try
{
$dbh = DatabaseHelpers::getDatabaseConnection();
$stmt = $dbh->prepare($query);
$success = $stmt->execute();
if ($success)
{

$TextResult = $stmt->fetch();
echo $TextResult["Text"];
}
$dbh = null;
}
catch (PDOException $e)
{
$userID = 0;
}
}

Luego las recupero de la siguiente forma

<input type="text" value="<?php GetTag('10') ?>" />


Cuando lo ejecuto desde mi servidor local todo funciona correctamente, pero al hacerlo desde mi hosting, muchas etiquetas se quedan vacías. Pienso que es por la cantidad de queries que estoy lanzando a la base de datos ya que, me da la impresión de que se imprime la página antes de que el servidor haya recibido todo el contenido de la base de datos.
Alguien tiene idea de que puede estar pasando y si el sistema que utilizo es correcto?

Muchas gracias a todos por adelantado.

cosix

09/7/2014
herramienta en línea para la localización de software
Si usted está interesado en crear sitios web multi-idioma yo recomiendo altamente esta rápida y intuitiva herramienta en línea para la localización de software: https://poeditor.com/

Jmojpar

24/4/2018
Otra solución
He estado leyendo vuestros comentario y se me ha ocurrio la idea de crear dos páginas, es decir: www.tu-pagina.com/es y www.tu-pagina.es/en, así colocaríamos en el header de cada una de ellas un if que comprobase que casilla de idioma se encuentra marcada en cada momento, es decir, si la casilla del idioma se encuentra en español la página va a recuperar toda la información de la carpeta/es (www.tu-pagina.com/es), sin embargo por otro lado si la casilla de idioma se encuntra en inglés va a recuperar toda la informacion de la carpetra /en (www.tu-pagina.com/en).