php

Aplicaciones multiidioma en PHP

El soporte para múltiples idiomas o lenguajes es una gran característica a la hora de desarrollar aplicaciones web con PHP, pues así podemos tener sitios traducidos sin mucho esfuerzo.

Múltiples idiomas con PHP

Aunque PHP soporta de manera nativa opciones como gettext para aplicaciones multilenguaje siempre vamos a necesitar una opción más robusta y simple.

Por ello es que hoy vengo a exponer un enfoque de cómo desarrollar aplicaciones multiidoma con PHP utilizando un componente de Symfony (no el framework, solo un componente que se puede integrar a cualquier proyecto) llamado translation.

El módulo translation

Para traducir mensajes podemos instalar el módulo de Symfony que funciona de manera aislada. Para ello utiliza Composer. Si no usas composer mira aquí cómo instalarlo, y aquí cómo adaptarlo.

Una vez que lo tengas, instala con:

composer require symfony/translation

Espera a que se instale y luego, en el archivo en donde vas a usar la app, carga el autoload:

<?php
include_once "vendor/autoload.php";

Estamos listos.

Primer acercamiento a la traducción

Comenzamos creando un traductor, instanciando un Translator pasándole el locale o idioma en el que se mostrarán los mensajes.

Es decir, aquí es en donde indicamos el idioma del usuario (puedes obtenerlo como se ve en este post o usar tus propios métodos)

<?php
$idioma = "es";
$traductor = new Translator($idioma);

Ahora a ese traductor le vamos a agregar recursos de traducción usando catálogos. Para comenzar vamos a usar el loader de arreglo, es decir, nuestras traducciones estarán en un arreglo así que lo agregamos así: (más tarde veremos cómo cargar las traducciones desde un fichero)

$traductor->addLoader("array", new ArrayLoader());

Eso agregó el loader, pero no ha agregado catálogos. Para agregarlos usamos:

<?php
$traductor->addResource("array", [
    "saludo" => "Hola, mundo",
], "es");

$traductor->addResource("array", [
    "saludo" => "Hello world!",
], "en");

Los argumentos de addResource son(en orden): tipo de loader, datos y locale o idioma. En este caso estoy usando es y en pero podrían ser más específicos como es_US, en_US, es_MX, etcétera.

Solo estoy definiendo el mensaje de saludo, que en inglés es Hello world! y en español es Hola mundo.

Finalmente definimos los idiomas fallback, es decir, los idiomas que se usarán en caso de que el idioma del traductor (el que especificamos al inicio) no encuentre una traducción:

<?php
$traductor->setFallbackLocales(["es"]); // Si no se encuentra el idioma, utilizamos es por defecto

Finalmente obtenemos el mensaje traducido accediendo a su clave:

<?php
$saludoTraducido = $traductor->trans("saludo");
echo $saludoTraducido;

Así que el código completo queda así:

<?php
include_once "vendor/autoload.php";
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Translator;
$idioma = "es";
$traductor = new Translator($idioma);
$traductor->addLoader("array", new ArrayLoader());
$traductor->addResource("array", [
    "saludo" => "Hola, mundo",
], "es");

$traductor->addResource("array", [
    "saludo" => "Hello world!",
], "en");
$traductor->setFallbackLocales(["es"]); // Si no se encuentra el idioma, utilizamos es por defecto

$saludoTraducido = $traductor->trans("saludo");
echo $saludoTraducido;

Lo que realmente cambiará la salida es el idioma que especificamos en $idioma en la línea 5. Si uso es, la salida es:

 

En cambio, cuando uso en, la salida es:

Así que en resumen hay que indicar el idioma al instanciar el traductor, este idioma lo puedes obtener de las preferencia de idioma del usuario, usar algún método de detección, ver la ip, etcétera.

Catálogos de traducción con JSON

Además de los arreglos podemos usar ficheros yaml, csv, json, entre otros. Mostraré un ejemplo para usar JSON. Voy a definir mis catálogos de idiomas.

El de español queda así:

{
    "saludo": "Hola mundo",
    "bienvenido": "Bienvenido, {usuario}"
}

El de inglés así:

{
    "saludo": "Hello world",
    "bienvenido": "Welcome, {usuario}"
}

Si te fijas es un objeto o diccionario en donde la clave es el identificador del mensaje y el valor es el mensaje.

Ahora vamos a ver el código que es muy parecido al anterior, aunque un poco más corto. En lugar de cargar un loader de Array, cargamos un JsonFileLoader:

<?php
$traductor->addLoader("json", new JsonFileLoader());

Y agregamos los catálogos:

<?php
$traductor->addResource("json", "idioma_es.json", "es");
$traductor->addResource("json", "idioma_en.json", "en");

Los argumentos son los mismos: el loader, los datos y el locale.

Nota importante: los archivos deben existir en el mismo directorio, y si no, asegúrate de escribir su ruta absoluta. Si la ruta es errónea fallará silenciosamente, es decir, no reportará errores y por lo tanto usará el idioma fallback.

Así que el código completo para tener varios idiomas en PHP usando archivos de JSON es el siguiente:

<?php
include_once "vendor/autoload.php";
use Symfony\Component\Translation\Loader\JsonFileLoader;
use Symfony\Component\Translation\Translator;
$idioma = "en";
$traductor = new Translator($idioma);
$traductor->addLoader("json", new JsonFileLoader());
$traductor->addResource("json", "idioma_es.json", "es");
$traductor->addResource("json", "idioma_en.json", "en");
$traductor->setFallbackLocales(["es"]); // Si no se encuentra el idioma, utilizamos es por defecto

$saludoTraducido = $traductor->trans("saludo");
echo $saludoTraducido;

Como ves, todo es igual, excepto la carga de recursos, pero fuera de eso seguimos invocando al método trans.

Formatear mensajes

Si te fijas bien, en los ejemplos he definido un mensaje de bienvenida. En inglés es:

Welcome, {usuario}

Y en español es:

Bienvenido, {usuario}

Al traducir mensajes con este componente podemos especificar variables. He definido la variable en llaves {} porque quiero, pero no es obligatorio (solo que así se entiende mejor la intención del mensaje) ya que se hace un remplazo completo.

Para pasar argumentos se hace lo siguiente:

<?php
$saludoTraducido = $traductor->trans("bienvenido", [
    "{usuario}" => "parzibyte",
]);

Como ves, en el segundo argumento indicamos un arreglo con los valores que se van a remplazar dentro de la cadena. Ahora sí, en inglés se ve así:

Y en español:

Por cierto, el código completo es el siguiente:

<?php
include_once "vendor/autoload.php";
use Symfony\Component\Translation\Loader\JsonFileLoader;
use Symfony\Component\Translation\Translator;
$idioma = "es";
$traductor = new Translator($idioma);
$traductor->addLoader("json", new JsonFileLoader());
$traductor->addResource("json", "idioma_es.json", "es");
$traductor->addResource("json", "idioma_en.json", "en");
$traductor->setFallbackLocales(["es"]); // Si no se encuentra el idioma, utilizamos es por defecto

$saludoTraducido = $traductor->trans("bienvenido", [
    "{usuario}" => "parzibyte",
]);
echo $saludoTraducido;

Conclusión y notas finales

Aunque lo veas complejo, no lo es tanto; pues podrías encerrar esto en una función o servicio y llamarlo desde otro lugar.

Recuerda: es tu deber identificar el idioma del usuario, puedes leerlo desde una base de datos, un parámetro GET, detectarlo, etcétera.

Esto que te mostré es un panorama general, si quieres ver la documentación oficial aquí la tienes.

Puedes ver el proyecto completo con todos los ejemplos en mi GitHub.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Servidor HTTP en Android con Flutter

El día de hoy te mostraré cómo crear un servidor HTTP (servidor web) en Android…

4 días hace

Imprimir automáticamente todos los PDF de una carpeta

En este post te voy a enseñar a designar una carpeta para imprimir todos los…

5 días hace

Guía para imprimir en plugin versión 1 desde Android

En este artículo te voy a enseñar la guía para imprimir en una impresora térmica…

1 semana hace

Añadir tasa de cambio en sistema de información

Hoy te voy a mostrar un ejemplo de programación para agregar un módulo de tasa…

2 semanas hace

Comprobar validez de licencia de plugin ESC POS

Los usuarios del plugin para impresoras térmicas pueden contratar licencias, y en ocasiones me han…

2 semanas hace

Imprimir euro € en impresora térmica

Hoy voy a enseñarte cómo imprimir el € en una impresora térmica. Vamos a ver…

4 semanas hace

Esta web usa cookies.