20 proyectos, 20 idiomas, fecha límite ayer. Parte 3

Artículo final sobre la integración de Serge + Smartcat . En este artículo, le diré cómo escalamos a Serge a toda la empresa, consideramos 4 integraciones no estándar y, como beneficio adicional, hablaremos de 2 características que pueden simplificar su vida.

Artículos anteriores:

20 proyectos, 20 idiomas, fecha límite ayer
20 proyectos, 20 idiomas, fecha límite ayer. Parte 2

Escalabilidad


En un artículo anterior, hablé sobre cómo configurar Serge para un único repositorio. En nuestra empresa, tenemos varias docenas de repositorios que necesitan traducciones, por lo que se asignó un servidor separado para la localización. La estructura y el entorno del archivo son completamente idénticos a los descritos en el artículo anterior. Cada repositorio usa su propia instancia de Serge. Para no ejecutar comandos manualmente, cada instancia tiene una corona, que ejecuta sucesivamente los comandos de Serge: recibir nuevas líneas del repositorio, recibir nuevas traducciones, analizar, enviar nuevas líneas a Smartcat y enviar nuevas traducciones a Gitlab.

Opciones de integración


Dos conjuntos de idiomas en un repositorio.


Comencemos con el caso más simple. Imagine que su repositorio tiene varios conjuntos de archivos de recursos. Por ejemplo, las cadenas de cliente y las API de aplicación se almacenan en el mismo repositorio, pero en directorios diferentes. El cliente se traduce a 20 idiomas, la API a 6.

Objetivo : organizar un suministro independiente de traducciones en cada uno de los directorios.
Solución :

  1. Configure 2 proyectos en Smartcat: en 6 idiomas y en 20.
  2. Configure 2 proyectos en el servidor de localización.
  3. En el primer proyecto, agregue la línea our $ unmerged_branch_mask = '^ (translateAPI-)' en el archivo project1.cfg ; # procesar ramas no fusionadas que coinciden con esta máscara , donde " translateAPI- " es el prefijo del nombre de la rama. El prefijo le indicará a Serge que esta rama necesita traducciones en el directorio API.
  4. En el archivo project1.serge.tmpl , especifique la ruta a los archivos de recursos en el directorio API en el parámetro source_dir .
  5. Del mismo modo, para el segundo proyecto en el archivo project2.cfg agregue la línea our $ unmerged_branch_mask = '^ (translateCLIENT-)'; # procesar ramas no fusionadas que coinciden con esta máscara , donde " translateCLIENT " es el prefijo para las ramas de este proyecto. El prefijo le indicará a Serge que esta rama necesita traducciones en el directorio del Cliente.
  6. En el archivo project2.serge.tmpl , especifique la ruta a los archivos de recursos en el directorio CLIENTE en el parámetro source_dir .

Tenga en cuenta que los prefijos deben ser únicos entre todos los proyectos configurados para un repositorio.

En total, tenemos 2 proyectos en Smartcat y 2 proyectos correspondientes en el servidor de localización. Ambos proyectos miran el mismo repositorio en Gitlab, pero en diferentes directorios. Serge, usando el prefijo de rama, entiende qué líneas necesita enviar para traducir. Para calcular la diferencia, se usa la misma rama de traducción base.

Swagger de localización


En nuestra empresa, todos los productos, incluida la documentación, están localizados. Ahora estamos introduciendo la generación automática de documentación de swagger, y nos enfrentamos a la necesidad de localizarla.
Tarea : localizar swagger con un mínimo esfuerzo.

Solución : en el archivo myproject.tmpl.serge , agregue el objeto de datos al objeto analizador y enumere en él los campos cuyo valor debe extraerse y enviarse para su traducción:

parser { plugin parse_json data { path_matches \/(summary|description)$ } } 

Una tarea similar : es necesario traducir textos de un archivo, pero no todos, sino solo los legales. Otros textos son proporcionados por un equipo de marketing. Para no complicar la estructura y no crear un archivo adicional para textos legales, las claves de todas las líneas legales recibieron el prefijo "legal":

 parser { plugin parse_json data { path_matches ^\/legal\..* } } 

Sutilezas de las traducciones legales


Otro caso interesante. Tenemos un documento legal, cuyos términos varían de un país a otro. Pero, sin embargo, esta es una aplicación y los archivos de recursos están en el mismo directorio.

Objetivo : en el marco de un proyecto para traducir varios documentos, cada documento debe traducirse a un idioma específico.

Lo que se ha hecho :

  1. Se creó un directorio apropiado para cada país, dentro del cual se encontraba un archivo fuente en inglés relevante para ese país.
  2. La ruta de la variable source_dir se especifica en el directorio compartido con archivos de recursos.
  3. Permitimos la búsqueda de archivos de recursos en todos los subdirectorios : source_process_subdirs YES
  4. Agregamos un nuevo complemento a la lista de complementos llamados, que le permite enviar cada archivo de recursos específico al idioma deseado. Como guía, use el nombre del directorio donde se encuentra:

 callback_plugins { :feature_branch { plugin feature_branch data { master_job job.base-translate } } :limit_languages { plugin limit_languages data { # all rules are processed top to bottom; each rule can add or remove languages # so the most priority rules are placed at the bottom if { # by default, don't localize file_matches . then { exclude_all_languages YES } } if { file_matches de-au\/ then { include_languages de-AT } } if { file_matches li-LI\/ then { include_languages li } } if { file_matches pt\/ then { include_languages pt-BR } } if { file_matches zh-Hans\/ then { include_languages zh-Hans } } # and so on.. } } 

Localización al almacenar filas en la base de datos


Nuestro sistema tiene una parte del código que almacena las traducciones en la base de datos y, por varias razones, no puede pasar a archivos de recursos en el repositorio. Sin embargo, necesitamos poder entregar traducciones de forma rápida y automática.

Tarea : Organice un proceso de localización continua si las filas no se almacenan en el repositorio, sino en la base de datos.

Solución :

  1. Cree un repositorio, recopile y agrupe en él todas las líneas de la base de datos de acuerdo con el principio que nos resulte conveniente (por el número de idiomas de traducción o por productos).
  2. Crea un proyecto en Smartcat.
  3. Comience el ciclo estándar de localización continua.
  4. Combinar ramas de traducción en la rama base-traducir.
  5. Por corona, verifique el valor hash de la última confirmación en base-translate. Si el hash ha cambiado, es decir, se han generado nuevas traducciones, analice diff entre el hash anterior y el actual, y envíe filas nuevas / modificadas a la base de datos.

Características de bonificación


Alertas


Las alertas básicas de Smartcat no eran adecuadas para nosotros, ya que cada equipo desea recibir notificaciones solo sobre sus sucursales y solo sobre la disponibilidad completa de las traducciones en todos los archivos de recursos del producto.

Se decidió aprovechar la disponibilidad de todas las traducciones en el repositorio y, si están completamente listas, enviar notificaciones al mensajero corporativo, en nuestro caso, Google Chat.

Tarea : organizar alertas en el repositorio, donde 8 equipos pueden comprometerse, duplicar todas las alertas en el canal del departamento de documentación técnica.

Solución :

  1. Acuerde con cada equipo que el nombre de las sucursales debe contener el nombre del equipo. Todavía use el prefijo translate- para indicar ramas que necesitan traducción.
  2. Cree una canalización que se ejecute solo para ramas con el prefijo translate-.
  3. En la tubería, determine a qué comando pertenece la rama, verifique la presencia de líneas con un valor vacío y, si no hay ninguna, envíe notificaciones de preparación al canal apropiado. Como el código es bastante voluminoso, lo puse en un script.

Ci


 check-translations: stage: check-translations image: node:8.14.0 tags: - devops script: - chmod +x ./notification.sh - ./notification.sh only: - base-translate - /^translate.*$/ when: always 

Guión de alerta


 #!/bin/bash hangouts(){ curl -X POST --max-time 180 -H "Content-Type: application/json; charset=UTF-8" --data "{ \"cards\": [{\"header\": {\"title\": \"LOCALIZATION IS READY\",\"subtitle\": \"REPOSITORY NAME\",\"imageUrl\": \"https://avatanplus.com/files/resources/mid/5775880ee27f8155a31b7a50.png\"},\"sections\": [{\"widgets\": [{\"keyValue\": {\"topLabel\": \"Translation is finished in the branch\",\"content\": \"$1\"}}]},{\"widgets\": [{\"buttons\": [{\"textButton\": {\"text\": \"SEE COMMIT\",\"onClick\": {\"openLink\": {\"url\": \"https://gitlab.loc/common/publisher-client/commit/$2\"}}}}]}]}]}]}" "$3" || true } cd app/translations if echo "$CI_COMMIT_REF_NAME" | grep "commandname1"; then grep -rl '\:\s\"\"' *.json >> result.file if [ -s network.file ]; then echo "Translations are not ready"; cat result.file else hangouts $CI_COMMIT_REF_NAME $CI_COMMIT_SHA $HANGOUTS_NOTIFICATIONS_COMMAND_NAME_1 hangouts $CI_COMMIT_REF_NAME $CI_COMMIT_SHA $HANGOUTS_NOTIFICATIONS_DOC fi fi if echo "$CI_COMMIT_REF_NAME" | grep "commandname2"; then grep -rl '\:\s\"\"' *.json >> result.file if [ -s result.file ]; then echo "Translations are not ready"; cat result.file else hangouts $CI_COMMIT_REF_NAME $CI_COMMIT_SHA $HANGOUTS_NOTIFICATIONS_COMMAND_NAME_2 hangouts $CI_COMMIT_REF_NAME $CI_COMMIT_SHA $HANGOUTS_NOTIFICATIONS_DOC fi fi ... if echo "$CI_COMMIT_REF_NAME" | grep "commandname8"; then grep -rl '\:\s\"\"' *.json >> result.file if [ -s result.file ]; then echo "Translations are not ready"; cat result.file else hangouts $CI_COMMIT_REF_NAME $CI_COMMIT_SHA $HANGOUTS_NOTIFICATIONS_COMMAND_NAME_8 hangouts $CI_COMMIT_REF_NAME $CI_COMMIT_SHA $HANGOUTS_NOTIFICATIONS_DOC fi fi 

Asignaciones de traductor a través de Smartcat API




Así es como se ve nuestro gerente de localización cuando llega el momento de asignar todas las ramas para la traducción.

En promedio, tenemos más de 10 sucursales en nuestro trabajo todos los días. En Smartcat, cada par de idiomas es un documento separado, y los traductores deben asignarse a cada documento. Manualmente Imagínese: 40-60 citas todos los días. Para simplificar este proceso, hicimos una cita a través de la API y también la pusimos en marcha. Este trabajo se inicia con el botón. Una pregunta razonable: ¿por qué no hacer asignaciones automáticas al enviar transferencias, y no hacer una llamada al método en el complemento Smartcat, y no en la tubería?

Hay varias razones para esta decisión:

  1. El factor humano. A pesar de que construimos procesos y tratamos de adherirnos a ellos, las líneas no leídas o las líneas sin contexto entran regularmente en Smartcat. La asignación automática en este caso significaría gastos adicionales para nosotros, ya que algunas líneas se enviarían para traducción dos veces: antes y después de la edición.
  2. Distribución de roles. Los proyectos son configurados y gestionados a nivel del servidor de localización por el ingeniero de localización o el escritor técnico del proyecto. Las citas y la comunicación con los traductores son manejadas por el gerente de localización. Por lo tanto, las tareas deben ser manejables, transparentes y accesibles a través de la GUI.

Solución: cuando el gerente de localización considera que las líneas en esta rama están listas para la traducción, presiona un botón en Gitlab. El equipo completo de traductores está asignado a esta rama. La tarea la toma el traductor que respondió primero.

Ci


 assignee: stage: assignee image: node:8.14.0 tags: - devops script: - chmod +x ./assignee.sh - ./assignee.sh only: - base-translate - /^translate.*$/ - assignee when: manual 

Script de asignación


 #!/bin/bash if echo "$CI_COMMIT_REF_NAME" | grep "translate-"; then node -pe "JSON.parse(process.argv[1]).documents.forEach(function(elem){ if(elem.name.indexOf(\"$CI_COMMIT_REF_NAME\") !== -1) { console.log(elem.id) } });" "$(curl -XGET -H "Authorization: Basic $SMARTCAT_API_KEY" -H "Content-type: application/json" "https://smartcat.ai/api/integration/v1/project/$SMARTCAT_PROJECT_ID")" >> documents fi sed '$d' documents > documents.list while read LINE; do bash -c "curl -XPOST -H 'Authorization: Basic $SMARTCAT_API_KEY' -H "Content-type:application/json" -d '{"documentIds":[\""$LINE"\"],"stageNumber": 1}' 'https://smartcat.ai/api/integration/v1/document/assignFromMyTeam'";done < documents.list 

Esto concluye mi serie de artículos sobre integración y configuración de localizaciones continuas. Estaré encantado de responder cualquiera de sus preguntas.

Source: https://habr.com/ru/post/452580/


All Articles