Detección de idioma: la forma correcta
Construyo aplicaciones web multilingües con bastante frecuencia, y una de las preguntas que siempre surge es cómo detectar el idioma en el que debe mostrarse la aplicación. Una de las maneras más comunes que he encontrado es que las aplicaciones intentan determinar la ubicación del usuario, como el país, y establecen el idioma de la interfaz según el idioma oficial de ese país.
Sin embargo, no creo que esta sea la mejor solución. Cuando viajo a otros países, a menudo me ocurre que la aplicación se muestra en un idioma que no conozco. Por ejemplo, si voy a India, la web aparece en hindi, pero necesito buscar de inmediato una opción para elegir otro idioma porque, como turista en India, en realidad no hablo hindi.
La forma correcta, en mi opinión, sería detectar la preferencia de idioma que tengo configurada en el sistema que utilizo, para mostrarme la interfaz en el mismo idioma que mi dispositivo. Si tengo configurado el idioma en español, la interfaz debería mostrarse en español; de lo contrario, debería mostrarse en inglés, que suele ser más común.
Para detectar el idioma del sistema en el navegador, podemos utilizar el encabezado de solicitud Accept-Language
. En Laravel, crearemos un middleware para obtener este encabezado, procesarlo y cambiar la configuración de locale
de Laravel según el idioma preferido obtenido.
Creamos el middleware SetLocale
y separaremos cada uno de los idiomas obtenidos con Accept-Language
.
class SetLocale
{
public function handle(Request $request, Closure $next): Response
{
$list = explode(',', $request->server('HTTP_ACCEPT_LANGUAGE', ''));
}
}
En la variable list
, obtenemos valores como en-US;q=0.9
, fr;q=0.8
y es;q=0.7
. La primera sección es el locale
y la segunda sección es el factor de preferencia del idioma; cuanto más alto sea, mejor es el idioma preferido por el usuario.
A continuación, crearemos una colección locale
de Laravel con esos elementos y los transformaremos en una nueva colección, donde cada elemento tendrá locale
y factor
, y los ordenaremos por factor de manera descendente.
class SetLocale
{
public function handle(Request $request, Closure $next): Response
{
$list = explode(',', $request->server('HTTP_ACCEPT_LANGUAGE', ''));
$locales = Collection::make($list)
->map(function ($locale) {
$parts = explode(';', $locale);
$mapping['locale'] = trim($parts[0]);
if (isset($parts[1])) {
$factorParts = explode('=', $parts[1]);
$mapping['factor'] = $factorParts[1];
} else {
$mapping['factor'] = 1;
}
return $mapping;
})
->sortByDesc(function ($locale) {
return $locale['factor'];
});
}
}
Por último, obtenemos el primer locale
y configuramos la aplicación para que utilice ese locale
.
class SetLocale
{
public function handle(Request $request, Closure $next): Response
{
// ...
app()->setLocale($locales->first()['locale']);
return $next($request);
}
}
Ahora registramos el middleware en el grupo web
en bootstrap/app.php
:
return Application::configure(basePath: dirname(__DIR__))
// ...
->withMiddleware(function (Middleware $middleware) {
$middleware->appendToGroup('web', SetLocale::class);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
Con esto, nuestra aplicación Laravel establecerá el idioma de la interfaz según la preferencia del usuario, evitando errores como mostrar la interfaz en un idioma que el usuario no conoce.