20 Projekte, 20 Sprachen, Frist gestern. Teil 3

Letzter Artikel zur Serge + Smartcat-Integration . In diesem Artikel werde ich Ihnen erklären, wie wir Serge auf das gesamte Unternehmen skalieren, 4 nicht standardmäßige Integrationen berücksichtigen und als Bonus über zwei Funktionen sprechen, die Ihr Leben vereinfachen können.

Vorherige Artikel:

20 Projekte, 20 Sprachen, Frist gestern
20 Projekte, 20 Sprachen, Frist gestern. Teil 2

Skalierbarkeit


In einem früheren Artikel habe ich darüber gesprochen, wie Serge für ein einzelnes Repository konfiguriert wird. In unserem Unternehmen verfügen wir über mehrere Dutzend Repositorys, für die Übersetzungen erforderlich sind. Daher wurde ein separater Server für die Lokalisierung zugewiesen. Die Dateistruktur und die Umgebung sind völlig identisch mit den im vorherigen Artikel beschriebenen. Jedes Repository verwendet eine eigene Instanz von Serge. Um Befehle nicht manuell auszuführen, verfügt jede Instanz über eine Krone, die nacheinander Serge-Befehle ausführt: Empfangen neuer Zeilen aus dem Repository, Empfangen neuer Übersetzungen, Parsen, Senden neuer Zeilen an Smartcat und Senden neuer Übersetzungen an Gitlab.

Integrationsoptionen


Zwei Sätze von Sprachen in einem Repository


Beginnen wir mit dem einfachsten Fall. Stellen Sie sich vor, Ihr Repository verfügt über mehrere Sätze von Ressourcendateien. Beispielsweise werden Client-Zeichenfolgen und Anwendungs-APIs im selben Repository, jedoch in unterschiedlichen Verzeichnissen gespeichert. Der Client wird in 20 Sprachen übersetzt, die API in 6.

Ziel : Organisation einer unabhängigen Bereitstellung von Übersetzungen in jedem der Verzeichnisse.
Lösung :

  1. Richten Sie 2 Projekte in Smartcat ein: in 6 Sprachen und in 20.
  2. Richten Sie 2 Projekte auf dem Lokalisierungsserver ein.
  3. Fügen Sie im ersten Projekt die Zeile our unmerged_branch_mask = '^ (translateAPI-)' in die Datei project1.cfg ein . # verarbeitet nicht zusammengeführte Zweige, die dieser Maske entsprechen , wobei " translateAPI- " das Präfix für den Zweignamen ist. Das Präfix zeigt Serge an, dass dieser Zweig Übersetzungen im API-Verzeichnis benötigt.
  4. Geben Sie in der Datei project1.serge.tmpl den Pfad zu den Ressourcendateien im API-Verzeichnis im Parameter source_dir an .
  5. In ähnlicher Weise fügen Sie für das zweite Projekt in der Datei project2.cfg die Zeile our unmerged_branch_mask = '^ (translateCLIENT-)' hinzu. # Nicht zusammengeführte Zweige verarbeiten, die dieser Maske entsprechen , wobei " translateCLIENT " das Präfix für die Zweige dieses Projekts ist. Das Präfix zeigt Serge an, dass dieser Zweig Übersetzungen im Client-Verzeichnis benötigt.
  6. Geben Sie in der Datei project2.serge.tmpl den Pfad zu den Ressourcendateien im Verzeichnis CLIENT im Parameter source_dir an .

Bitte beachten Sie, dass Präfixe für alle Projekte, die für ein Repository konfiguriert sind, eindeutig sein müssen.

Insgesamt haben wir 2 Projekte in Smartcat und 2 entsprechende Projekte auf dem Lokalisierungsserver. Beide Projekte betrachten dasselbe Repository in Gitlab, jedoch in unterschiedlichen Verzeichnissen. Serge versteht anhand des Verzweigungspräfixes, welche Zeilen er zur Übersetzung senden muss. Zur Berechnung des Diff wird derselbe Basisübersetzungszweig verwendet.

Lokalisierung Swagger


In unserem Unternehmen sind alle Produkte einschließlich der Dokumentation lokalisiert. Jetzt führen wir die automatische Generierung von Dokumentation aus Swagger ein und müssen sie lokalisieren.
Aufgabe : Prahlerei mit minimalem Aufwand lokalisieren.

Lösung : Fügen Sie in der Datei myproject.tmpl.serge das Datenobjekt zum Parserobjekt hinzu und listen Sie darin die Felder auf, deren Wert extrahiert und zur Übersetzung gesendet werden muss:

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

Eine ähnliche Aufgabe : Es ist notwendig, Texte aus einer Datei zu übersetzen, aber nicht alle, sondern nur legale. Andere Texte werden von einem Marketing-Team bereitgestellt. Um die Struktur nicht zu komplizieren und keine zusätzliche Datei für Rechtstexte zu erstellen, erhielten die Schlüssel aller Rechtszeilen das Präfix „legal“:

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

Feinheiten juristischer Übersetzungen


Ein weiterer interessanter Fall. Wir haben ein Rechtsdokument, dessen Bedingungen von Land zu Land variieren. Dies ist jedoch eine Anwendung, und die Ressourcendateien befinden sich im selben Verzeichnis.

Ziel : Im Rahmen eines Projekts zur Übersetzung mehrerer Dokumente muss jedes Dokument in eine bestimmte Sprache übersetzt werden.

Was wurde getan :

  1. Für jedes Land wurde ein entsprechendes Verzeichnis erstellt, in dem sich eine für dieses Land relevante englische Quelldatei befand.
  2. Der Pfad für die Variable source_dir wird für das freigegebene Verzeichnis mit Ressourcendateien angegeben.
  3. Wir aktivieren die Suche nach Ressourcendateien in allen Unterverzeichnissen : source_process_subdirs YES
  4. Wir fügen der Liste der aufgerufenen Plug-Ins ein neues Plugin hinzu, mit dem Sie jede bestimmte Ressourcendatei in die gewünschte Sprache senden können. Verwenden Sie als Richtlinie den Namen des Verzeichnisses, in dem es liegt:

 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.. } } 

Lokalisierung beim Speichern von Zeilen in der Datenbank


Unser System enthält einen Teil des Codes, der Übersetzungen in der Datenbank speichert, und kann aus verschiedenen Gründen nicht in Ressourcendateien im Repository verschoben werden. Wir müssen jedoch in der Lage sein, Übersetzungen schnell und automatisch zu liefern.

Aufgabe : Organisieren Sie einen Prozess der kontinuierlichen Lokalisierung, wenn die Zeilen nicht im Repository, sondern in der Datenbank gespeichert sind.

Lösung :

  1. Erstellen Sie ein Repository, sammeln Sie alle Zeilen aus der Datenbank und gruppieren Sie sie nach dem für uns geeigneten Prinzip (entsprechend der Anzahl der Übersetzungssprachen oder Produkte).
  2. Erstellen Sie ein Projekt in Smartcat.
  3. Starten Sie den Standardzyklus der kontinuierlichen Lokalisierung.
  4. Überführen Sie Übersetzungszweige in den Basisübersetzungszweig.
  5. Überprüfen Sie anhand der Krone den Hash-Wert des letzten Commits in base-translate. Wenn sich der Hash geändert hat, dh neue Übersetzungen generiert wurden, analysieren Sie den Unterschied zwischen dem alten und dem aktuellen Hash und senden Sie neue / geänderte Zeilen an die Datenbank.

Bonusfunktionen


Warnungen


Grundlegende Smartcat-Warnungen waren für uns nicht geeignet, da jedes Team nur Benachrichtigungen über seine Niederlassungen und nur über die vollständige Bereitschaft von Übersetzungen in allen Ressourcendateien des Produkts erhalten möchte.

Es wurde beschlossen, auf der Verfügbarkeit aller Übersetzungen im Repository aufzubauen und, wenn diese vollständig fertig sind, Benachrichtigungen an den Corporate Messenger, in unserem Fall Google Chat, zu senden.

Aufgabe : Organisieren Sie Warnungen im Repository, wo 8 Teams festschreiben können, und duplizieren Sie alle Warnungen im Kanal der Abteilung für technische Dokumentation.

Lösung :

  1. Stimmen Sie mit jedem Team überein, dass der Name der Niederlassungen den Namen des Teams enthalten soll. Verwenden Sie weiterhin das Präfix translate-, um Zweige anzugeben, die übersetzt werden müssen.
  2. Erstellen Sie eine Pipeline, die nur für Zweige ausgeführt wird, denen translate- vorangestellt ist.
  3. Bestimmen Sie in der Pipeline, zu welchem ​​Befehl die Verzweigung gehört, prüfen Sie, ob Zeilen mit einem leeren Wert vorhanden sind, und senden Sie, falls keine vorhanden sind, Bereitschaftsbenachrichtigungen an den entsprechenden Kanal. Da der Code ziemlich umfangreich ist, habe ich ihn in ein Skript eingefügt.

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 

Alarmskript


 #!/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 

Übersetzerzuweisungen über die Smartcat-API




So sieht unser Lokalisierungsmanager aus, wenn es darum geht, alle Zweige für die Übersetzung zuzuweisen.

Im Durchschnitt arbeiten täglich mehr als 10 Niederlassungen. In Smartcat ist jedes Sprachpaar ein separates Dokument, und jedem dieser Dokumente müssen Übersetzer zugewiesen werden. Manuell. Stellen Sie sich vor: 40-60 Termine pro Tag. Um diesen Prozess zu vereinfachen, haben wir einen Termin über die API vereinbart und ihn ebenfalls in die Pipeline aufgenommen. Dieser Job wird über die Schaltfläche gestartet. Eine vernünftige Frage: Warum nicht automatisch Zuweisungen beim Senden von Übertragungen vornehmen und keinen Methodenaufruf im Smartcat-Plugin und nicht in der Pipeline platzieren?

Für diese Entscheidung gibt es mehrere Gründe:

  1. Menschlicher Faktor. Trotz der Tatsache, dass wir Prozesse erstellen und versuchen, diese einzuhalten, gelangen ungelesene Zeilen oder Zeilen ohne Kontext regelmäßig in Smartcat. Eine automatische Zuordnung würde in diesem Fall zusätzliche Kosten für uns bedeuten, da einige Zeilen zweimal zur Übersetzung gesendet würden: vor und nach der Bearbeitung.
  2. Rollenverteilung. Projekte werden auf Lokalisierungsserverebene vom Lokalisierungstechniker oder technischen Redakteur des Projekts konfiguriert und verwaltet. Termine und Kommunikation mit Übersetzern werden vom Lokalisierungsmanager übernommen. Daher müssen Zuweisungen über die GUI verwaltbar, transparent und zugänglich sein.

Lösung: Wenn die Lokalisierungsmanagerin der Ansicht ist, dass die Zeilen in diesem Zweig zur Übersetzung bereit sind, drückt sie in Gitlab eine Schaltfläche. Das gesamte Übersetzerteam ist dieser Branche zugeordnet. Die Aufgabe übernimmt der Übersetzer, der zuerst geantwortet hat.

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 

Zuweisungsskript


 #!/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 

Damit ist meine Artikelserie zur Integration und Konfiguration kontinuierlicher Lokalisierungen abgeschlossen. Gerne beantworte ich Ihre Fragen.

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


All Articles