Un largo camino hacia los idiomas
He estado dando vueltas a una idea desde hace bastante tiempo que sonaba interesante y desafiante: ¿qué sería necesario para lograr soporte en varios idiomas para mi aplicación web con el menor mantenimiento posible? Además, considerando los costos como una limitación principal (este sitio no publica ningún anuncio y no utiliza ningún tipo de seguimiento, por lo que no hay ingresos aquí), ¿cómo sería una solución válida?
El plan
Todo comienza y termina con el motor de traducción a utilizar. Gracias al uso de Ubuntu como uno de mis controladores diarios, una vez descubrí una pequeña y agradable aplicación en la tienda de aplicaciones llamada "Argos translate", que es un motor de traducción de código abierto construido sobre los últimos modelos ML que son similares a los que impulsan DeepL . Si no conoce DeepL, es un gran traductor para usar de forma gratuita en su sitio web.
Pero volviendo a Argos: después de echar un vistazo al repositorio relacionado, vi que también hay un OSS python-lib disponible, que encajaría muy bien en un entorno autohospedado. Después de jugar durante un corto período de tiempo, decidí buscar algunos traductores a través de ofertas de SaaS, ya que todo el proceso de entrega de argos translate no funcionó tan bien como esperaba.
Por lo tanto, establecí otro servicio, Cloud Translations de GCP, que ofrece 500,000 caracteres gratis por mes y luego cobra algo de dinero por cada 1,000,000.
Se trata de almacenar en caché
Gracias a la configuración de Next.js con ISG (generación incremental de sitios), puedo solicitar las traducciones para cada página, lo que simplifica bastante la planificación, ya que no es necesario realizar una implementación única con todas las traducciones a la vez.
Aún así, no estaba seguro de cómo manejar el almacenamiento en caché de las cadenas traducidas. Claro, la red de borde de Vercel (donde se aloja esta PWA) puede aprovechar absolutamente esta tarea. Pero quería que las implementaciones fueran independientes de las traducciones. por eso creé una capa adicional de almacenamiento en caché a través de una instancia simple de Firestore, también alojada en GCP.
El mayor desafío fue analizar + reemplazar el contenido del bloque para cada artículo. Si no lo sabe. El contenido del bloque describe el cuerpo real del artículo, que es creado por mí en un CMS. Tras la traducción, esos bloques no están en texto sin formato, sino que están incrustados en una estructura de datos especial para permitir el almacenamiento de información semántica o metadatos. Detectar + traducir de manera confiable solo las cadenas relevantes fue una de las partes más importantes de esta implementación.
Un hombre, más de 12 idiomas
Los idiomas (actualmente) admitidos son:
- "en": inglés
- "de": alemán
- "fr": francés
- "es": español
- "eo": esperanto
- "el": griego
- "ja": japonés
- "ru": ruso
- "hola": hindi
- "él": hebreo
- "tr": turco
- "af": afrikáans
- "ar": árabe
- "ko": coreano
Para probar las diferentes variantes, simplemente coloque el código de idioma después de la URL base. Por ejemplo: "https://flaming.codes/fr". ¡Y eso es!
Resumiendo mi implementación, la configuración se ve así:
- cada página se construye estáticamente al menos cada 4 horas, pero solo a pedido; esto significa que se realiza un nuevo trabajo de traducción como máximo cada 4 horas para un sitio determinado
- las propias traducciones se cargan primero desde Firestore; solo si no hay nada disponible, las cadenas se traducen + se almacenan en caché en Firestore
Esta configuración funciona tan bien que no utilizaré ninguna traducción de forma clásica, p. Ej. creando manualmente archivos json que mantienen los pares clave-valor. Usaré la API de Cloud Translation para todo lo que necesite internacionalizarse, haciéndolo completamente dinámico. Gracias a estos cambios, la PWA tiene alrededor de 430 páginas al momento de la escritura.
Cada página se traduce del inglés a otros 13 idiomas, que representan los más hablados y los que se encuentran en todo el mundo entre ellos. ¡Veamos cómo evolucionará!
- Tom