Internacionalizando javascript en symfony

En este nuevo desafío que he asumido recientemente me encuentro con tener que mantener y mejorar aplicaciones web que están desarrolladas sobre symfony 5. Este es un framework PHP (si, php, no me matéis) que tiene sus cosas buenas y sus cosas malas. Una de las buenas es que permite internacionalizar las aplicaciones sin demasiados problemas… Al menos la parte de html.

Symfony utiliza un sistema de plantillas twig que es donde se pueden realizar las traducciones poniendo {%trans%}cadena{%endtrans%} y luego simplemente tenemos que mantener los archivos de traducción de cada lenguaje y ya toda la magia sucede internamente y sin problemas.

Imagen generada por AI cuando le pedí que me hiciese una imagen para un post de programación

Pero, ¿Qué pasa con las cadenas que generamos en javascript? Los archivos .js se sirven estáticamente sin que pasen por el proceso de sustitución que se hace en los twig, no nos vale poner {%trans%}cadena{%endtrans%} en el js porque ese archivo nunca va a ser tratado por symfony ni por php ya puestos.

La solución que he terminado por implementar se basa en generar un archivo .js con las traducciones en base a una plantilla twig y cargarla cada vez que necesite traducir algo en un js. Para ello solo tenemos que dar estos pasos:

  1. Crear la ruta en routes.yml (o usar un decorador) para /jstrans.js o similar
  2. Crear un controlador para servir ese archivo, por ejemplo JavascriptController.php
  3. Crear un twig para el javascript, por ejemplo jstrans.js.twig
  4. Meter en el twig todas las cadenas y sus traducciones correspondientes
  5. Hacer que jstrans.js se cargue en todas las páginas que necesiten traducciones
  6. usar la función que traduce en los js que lo necesiten.

Aquí os dejo un ejemplo de cada uno de los archivos:

JavascriptController.php

class JavascriptController extends AbstractController
{
    public function __construct()
    {
        $this->config = new Config();
    }

    public function index(): Response
    {
        $response =  $this->render('javascript/jstrans.js.twig', [
            'controller_name' => 'JavascriptController',
        ])->setSharedMaxAge(3600)->setPublic();
        $response->headers->set('Content-Type','text/javascript');
        return $response;
    }
}

jstrans.js.twig

if (typeof jstrans == 'undefined') {

    var jstrans = {
        traducciones: {
            'Seleccionar': '{%trans%}Seleccionar{%endtrans%}',
            'Registros': '{%trans%}Registros{%endtrans%}',
            'No se han encontrado resultados': '{%trans%}No se han encontrado resultados{%endtrans%}',
        },
        // Función que traduce un texto
        translate: function (text) {
            if (jstrans.traducciones[text] != undefined) {
                return jstrans.traducciones[text];
            } else {
                return text;
            }
        }
    };
} else {
    console.log ('jstrans ya está definida');
}

Luego ya se meten las cadenas en, messages.en.yaml,, por ejemplo

Seleccionar: Select
Registros: Registers
No se han encontrado resultados: No results found

Y luego solo hay que usarlo en los archivos js de esta manera:

jstrans.translate("Seleccionar")

Y eso te dará la cadena traducida al idioma en el que se esté navegando.

¿Conoces algún método mejor para conseguir traducciones en los js de un proyecto symfony? déjame un comentario si es así…