Descubre Su Número De Ángel
Lost in translation: mejora del sistema de localización de Sprout Social
Localizar una aplicación dinámica como Sprout Social en varios idiomas es una tarea compleja. Traducir el texto que aparece en la aplicación es solo la mitad de la historia. También implica desarrollar nuestra aplicación de una manera que facilite la extracción y el intercambio de ese texto por las traducciones. En Sprout, nos apoyamos en proveedores externos para las traducciones. Pero aún necesitamos herramientas para extraer, agrupar y enviar solicitudes de traducción a esos proveedores y luego entregar y entregar las traducciones a los usuarios finales.
Durante años, el equipo de ingeniería de Sprout se las arregló con una solución de localización personalizada, ya que las soluciones de código abierto aún estaban madurando. Nos permitió acomodar a nuestros clientes más grandes en nuestros idiomas admitidos, pero carecía de algunas características útiles. En este artículo, describiré nuestro nuevo sistema de localización, cómo aborda los escenarios de localización más complicados y cómo introdujimos esos cambios de forma incremental en toda la organización de ingeniería web.
Nuestro viejo sistema
Para comprender nuestro nuevo sistema de localización, primero debe comprender cómo funcionaba nuestro antiguo sistema y las áreas en las que podíamos mejorarlo.
Sintaxis del mensaje
La localización de aplicaciones funciona abstrayendo el texto que es visible para el usuario final en unidades de cadena, llamadas mensajes. Estos mensajes se extraen y se envían a los traductores. Al abstraer estas cadenas, podemos intercambiarlas fácilmente según el idioma preferido del usuario final.
Estos mensajes pueden ser simples cadenas estáticas como 'Hola, mundo' o tener marcadores de posición como 'Hola, {nombre}' o formato de texto enriquecido como 'Hola, mundo'. Dado que estas funciones deben serializarse en cadenas, necesita una sintaxis que tanto los traductores como el código de la aplicación entiendan para traducir y representar correctamente el texto.
Parte de lo que dificultó el uso de nuestro antiguo sistema de localización fue que creamos nuestra propia sintaxis y mantuvimos un 'analizador' casero para dicha sintaxis. El mantenimiento de este código requería mucho tiempo y la sintaxis era bastante mínima. Queríamos características adicionales para ayudar a representar mensajes más complejos.
Ejemplo: en la aplicación Sprout, necesitamos una forma de representar 'Tienes X publicaciones', donde X es un valor numérico dinámico.
Considere el caso plural, “Tienes 5 publicaciones ”. Considere el caso singular, 'Usted tiene 1 correo ”. Considere el caso “0”. Considere los idiomas que pueden tener una gramática para el caso '1', como el chino y el japonés. Considere los idiomas que tienen una gramática para el caso en que X es un 'número grande', como el árabe, el polaco y el ruso.
Gestión de mensajes
Tenemos mensajes que podemos enviar a los traductores e intercambiar en nuestra aplicación. Nuestra aplicación necesita una forma de almacenar estos mensajes y entregarlos a nuestros usuarios finales.
Nuestro antiguo sistema almacenaba todos nuestros mensajes en archivos JSON (los llamamos 'archivos lang'), que se administraban manualmente. Hicimos referencia a los mensajes en estos archivos usando ID en nuestro código javascript fuente. Cuando un usuario quería la aplicación en español, enviábamos nuestros archivos en español y luego el javascript mostraba el mensaje en español correspondiente usando la ID.
Por motivos de rendimiento, intentamos servir solo los mensajes de los usuarios que estaban en esa página, por lo que teníamos archivos lang separados para las diferentes páginas de la aplicación. Este era un sistema válido, pero a medida que nuestro equipo y nuestra aplicación escalaban, significó más tiempo manual para el desarrollador creando y administrando estos ID y archivos lang.

Para agregar un nuevo mensaje a la aplicación, los desarrolladores tenían que agregarlo manualmente al archivo lang correcto con una identificación única para hacer referencia a ese mensaje. A veces, nos encontrábamos con problemas de colisiones de ID y errores tipográficos de ID que hacían que faltara el idioma en la aplicación. Agregar texto a la aplicación web se sintió tedioso con numerosos pasos que no eran intuitivos.
Nuestra nueva solución
Al conocer estas deficiencias, los ingenieros web de toda la organización del Producto crearon un grupo de trabajo de localización para desarrollar una solución. Nos reuníamos regularmente para intercambiar ideas. Después de un proceso de investigación en profundidad, decidimos migrar la aplicación Sprout de nuestro sistema de localización casero para usar FormatJS. reaccionar-intl biblioteca y construir una infraestructura a su alrededor para administrar nuestros mensajes. React-intl fue la biblioteca de localización de código abierto más rica en funciones y popular en el ecosistema de JavaScript y se integró bien en nuestra base de código.
Sintaxis del mensaje
Queríamos una solución más robusta y no queríamos crear algo desde cero. Adoptamos el Sintaxis de mensajes de UCI , una sintaxis estandarizada que se utiliza en aplicaciones Java, PHP y C, y captura las complejidades de los mensajes de aplicaciones dinámicas. El reaccionar-intl La biblioteca también admite el análisis y la representación de mensajes de sintaxis de mensajes ICU.

Este es un ejemplo de cómo la sintaxis de mensajes ICU captura casos plurales. Este es el mensaje en inglés y ruso. Observe cómo cuando los traductores convierten este mensaje a otros idiomas, pueden agregar y quitar casos según sea necesario para respaldar correctamente el idioma. La traducción rusa de este mensaje agrega 'pocos' y 'muchos' casos.
La sintaxis de mensajes de ICU ha sido probada en batalla por muchas aplicaciones en innumerables idiomas. Podíamos confiar en que podría satisfacer las sofisticadas necesidades de nuestros clientes y que había muchas soluciones y/o recursos educativos para cualquier pregunta de localización que encontráramos.
69 significado ángel
Gestión de mensajes
Desarrollamos un sistema utilizando herramientas proporcionadas por FormatJS que automatizaría el proceso de agregar, eliminar y almacenar mensajes. Esto implicó algunos cambios filosóficos en la forma en que abordamos el almacenamiento y la referencia de mensajes.
Un cambio importante con respecto a nuestro antiguo sistema que fomenta FormatJS fue usar nuestro código de interfaz de usuario como la fuente de la verdad para los mensajes. En nuestro sistema anterior, la fuente de los mensajes y el uso de los mensajes estaban en dos lugares diferentes, lo que significaba que teníamos que mantenerlos sincronizados. Nuestro nuevo sistema mantiene las fuentes de mensajes con el resto del código de la interfaz de usuario. Simplemente necesitamos ejecutar un script que extraiga todos los mensajes de los archivos de la interfaz de usuario para generar nuestros archivos lang, y el contenido del mensaje se convierte en las ID únicas con la ayuda de una función hash.

Este cambio coloca los mensajes con el código de la interfaz de usuario y tuvo varios beneficios:
- Más legible: No más identificaciones diseñadas para robots en nuestro código de interfaz de usuario. Ahora podemos leer los mensajes en inglés en el código de la interfaz de usuario y comprender qué texto verá el usuario.
- No manual IDs: Estos ID que solo usaban las máquinas ahora los generan las máquinas y, por definición, son únicos por mensaje.
- No hay archivos lang administrados manualmente: Los desarrolladores no deberían necesitar tocar estos archivos lang. Nuestros scripts gestionan la adición y eliminación de los mensajes.
¿Cómo migramos?
Pero, ¿cómo migramos todo nuestro equipo de ingeniería web y la base de código a este nuevo sistema? Dividimos esto en cuatro hitos: poner a prueba el nuevo sistema, educar a nuestro equipo, desaprobar el sistema antiguo y migrar a nuestra nueva solución.
Pilotando el nuevo sistema
El grupo de trabajo probó el nuevo sistema en secciones específicas de la aplicación para tener una idea de sus mejores prácticas y el alcance completo de la migración. Esto hizo que el nuevo sistema se configurara en el lado del cliente (poly-fills, etc.) y en el lado de compilación de la aplicación. Esto nos permitió repetir la experiencia del desarrollador y mitigar el riesgo.
Educación
Tomamos lo que aprendimos del piloto y lo usamos para educar a todo el equipo de ingeniería web. Desarrollamos preguntas frecuentes y otra documentación y presentaciones educativas para ayudar a los desarrolladores a usar la nueva biblioteca. Es fácil subestimar este paso, pero esta parte de una migración es extremadamente importante. No importa cuán bueno sea su nuevo sistema: las personas deben saber cómo y por qué deben usarlo.
También desarrollamos un programa de embajadores en el que cada equipo de características web de Sprout tenía un Embajador de localización designado, que era responsable de ayudar a educar a su equipo sobre el nuevo sistema y de informar problemas o puntos débiles al grupo de trabajo.
Esto nos permitió delegar las responsabilidades educativas e identificar problemas específicos de equipos individuales.
Desaprobación del antiguo sistema
Después de que confiamos en la experiencia del desarrollador, el conocimiento compartido y el potencial de escala del nuevo sistema, descartamos el sistema antiguo. Creamos algunas reglas de eslint personalizadas y usamos la herramienta de linting, férula , para bloquear el uso del sistema anterior y permitir los usos existentes. A partir de este momento, se esperaba que los ingenieros web utilizaran el nuevo sistema al escribir código nuevo.
Migrando a nuestro nuevo sistema
Con confianza en nuestro nuevo sistema y una cantidad fija de usos antiguos, comenzamos a migrar.
Muchos usos tenían equivalentes uno a uno en el nuevo sistema. Donde existen estos equivalentes, pudimos automatizar la migración escribiendo un código-mod usando jscodeshift . Pudimos ejecutar iterativamente el mod de código sobre secciones de la base de código, aprendiendo y solucionando problemas a medida que avanzábamos. Quedaban tan pocos casos extremos que no podían modificarse con código fácilmente que nos sentimos cómodos arreglándolos manualmente.
Desenrollar
¿Por qué optamos por un enfoque tan iterativo en lugar de intentar migrar todo a la vez? El uso de un enfoque iterativo es parte de la cultura de ingeniería de Sprout y creemos en el aprendizaje y la mejora constantes.
Al abordar la migración de esta manera, pudimos aprender sobre la marcha, ajustando y solucionando problemas en tiempo real. También podríamos revertir los cambios si la migración comenzara a bloquear el desarrollo de aplicaciones. Nuestro enfoque iterativo nos permitió progresar mientras trabajábamos en otras iniciativas y nos permitió marcar cambios importantes con un grupo más pequeño antes de implementarlo para todos. Los mismos principios de desarrollo de funciones para una aplicación se aplican al desarrollo de herramientas internas para desarrolladores.
Aprendizajes y conclusiones
Reimaginar nuestro sistema de localización fue una tarea enorme en toda la organización de ingeniería web. Mi consejo para otras personas que enfrentan proyectos o desafíos similares sería:
- Utilice estándares ampliamente adoptados: ¿Por qué crear una sintaxis de mensaje personalizada cuando los ingenieros que han pasado años pensando en este espacio problemático ya desarrollaron una sintaxis de mensaje ICU?
- Considere colocar elementos relacionados: Hará que agregarlos, cambiarlos y eliminarlos sea mucho más fácil.
- Adopte un lanzamiento iterativo: Diseñe la implementación de su cambio de una manera que le permita aprender sobre la marcha. No puede anticipar todo, así que cree un espacio para recurrir en su plan.
- Comparte tus aprendizajes: La educación es la mitad de un despliegue. No importa cuán bueno sea su nuevo sistema si la gente no sabe cómo usarlo o por qué es mejor.
Para obtener más información sobre la cultura de ingeniería de Sprout, consulte nuestro página de carreras hoy.
Compartir Con Tus Amigos: