CaracteristiciPluginPrețuriResurse
Schimbă limba
ResurseCum să automatizezi traducerea .po în pipeline-ul tău CI/CD

Cum să automatizezi traducerea .po în pipeline-ul tău CI/CD

SimplePoTranslate Team9 iunie 2026
Cum să automatizezi traducerea .po în pipeline-ul tău CI/CD

Echipa ta face merge pe main de paisprezece ori pe zi. Fiecare dintre aceste merge-uri ar putea adăuga un șir de caractere nou, vizibil pentru utilizator – o etichetă de buton, un mesaj de eroare, un tooltip. Și fiecare dintre aceste șiruri de caractere începe să existe doar în engleză. Undeva în procesul tău de lansare, o persoană trebuie să observe noile șiruri de caractere, să le exporte, să le traducă, să le lipească înapoi și să recompileze. Acea persoană este un impediment (un blocaj), iar într-o echipă care livrează rapid, acest blocaj înseamnă că utilizatorii tăi germani văd placeholder-uri în engleză timp de două sprinturi.

Soluția este să automatizezi traducerea în pipeline-ul tău CI/CD, astfel încât noile șiruri de caractere să fie traduse la același merge care le-a introdus – fără intervenție umană în calea critică pentru cazurile de rutină. Acest lucru este pe deplin realizabil astăzi, dar numai dacă eviți capcana în care cad majoritatea echipelor: implementarea manuală de apeluri brute către LLM-uri care corup în liniște placeholder-urile tale %s și structura .po. Acest ghid prezintă un model realist de pipeline CI, un schelet funcțional de GitHub Actions și deciziile de design – idempotența, traducerea doar a elementelor noi, porțile de revizuire – care separă un pipeline util de unul care livrează build-uri defecte.

De ce traducerea manuală este un blocaj în procesul de lansare

Răspunsul la întrebarea „de ce să nu traduci pur și simplu înainte de fiecare lansare” este că sincronizarea nu se potrivește niciodată. Șirurile de caractere sunt adăugate continuu de dezvoltatori, dar traducerea se realizează în loturi de către o altă persoană, după un alt program. Decalajul dintre aceste două ritmuri este locul unde se acumulează datoria ta de localizare.

Problema celor două ritmuri

Imaginează-ți fluxul manual. Un dezvoltator adaugă __( 'Export to CSV', 'mytextdomain' ) și face merge. Nimeni nu regenerează fișierul .pot. Două săptămâni mai târziu, cineva rulează wp i18n make-pot, observă patruzeci de șiruri de caractere noi netraduse (unele de la dezvoltatori care au plecat între timp în vacanță), ghicește intenția pentru jumătate dintre ele și trimite un fișier .po unui traducător. Traducerea revine, este lipită, iar poate placeholder-urile au supraviețuit sau poate nu. Între timp, trei lansări au fost livrate cu acele șiruri de caractere în engleză.

Fiecare pas este manual, grupat în loturi și predispus la erori. Scopul automatizării CI/CD este de a condensa acest proces într-unul care rulează automat la fiecare merge, traduce doar ceea ce s-a schimbat efectiv și eșuează zgomotos când ceva pare greșit – transformând traducerea dintr-o sarcină periodică într-o parte invizibilă a pipeline-ului.

Modelul de pipeline: Extrage, Diferențiază, Traduce, Comite

La un nivel înalt, o sarcină de traducere automată rulează patru pași la fiecare merge către main: regenerează template-ul, detectează ce este nou, traduce doar acele șiruri de caractere și comite rezultatele înapoi. Tot procesul ar trebui să fie idempotent – rularea sa pe un merge fără modificări de șiruri de caractere trebuie să producă zero diferențe și zero „zgomot”.

Extrage și Diferențiază

Pasul unu este extragerea. Regenerează fișierul .pot din sursa curentă, astfel încât să reflecte fiecare șir de caractere din codebase:

wp i18n make-pot . languages/myplugin.pot

Pasul doi este diferența. Aceasta este cea mai importantă decizie de design din întregul pipeline. Nu vrei să retraduci fiecare șir de caractere la fiecare merge – asta irosește apelurile API, riscă retraducerea șirurilor de caractere pe care un om le-a corectat deja și produce diferențe (diff-uri) enorme de revizuire. În schimb, îmbini (merge) noul fișier .pot în fiecare fișier .po existent și traduci doar intrările care sunt acum goale (șirurile de caractere cu adevărat noi):

# Merge new template into each locale, preserving existing translations.
# Newly-added strings appear with empty msgstr; --backup=none keeps the tree clean.
for po in languages/*.po; do
    msgmerge --update --backup=none "$po" languages/myplugin.pot
done

După msgmerge, doar șirurile de caractere nou-nouțe au un msgstr gol. Tot ce a fost tradus anterior rămâne neatins. Această proprietate este ceea ce face pipeline-ul idempotent și ceea ce menține diff-urile tale de revizuire mici și ușor de revizuit.

Traduce și Comite

Pasul trei trimite doar acele intrări goale către un pas de traducere. Pasul patru comite fișierul .po actualizat, compilează .mo și regenerează orice JSON. Vom integra toate acestea în GitHub Actions în continuare.

Un schelet GitHub Actions

Iată răspunsul la întrebarea „cum arată de fapt acest lucru într-un fișier de workflow”: o sarcină declanșată la push pe main care rulează ciclul extract-diff-translate-commit și deschide un pull request cu rezultatele, în loc să comită direct pe main.

Fișierul de workflow

name: Translate on merge

on:
  push:
    branches: [ main ]

jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install WP-CLI and gettext
        run: |
          sudo apt-get update && sudo apt-get install -y gettext
          curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
          sudo mv wp-cli.phar /usr/local/bin/wp && sudo chmod +x /usr/local/bin/wp

      - name: Regenerate template and merge into locales
        run: |
          wp i18n make-pot . languages/myplugin.pot
          for po in languages/*.po; do
            msgmerge --update --backup=none "$po" languages/myplugin.pot
          done

      - name: Translate only new (empty) strings
        env:
          TRANSLATE_API_KEY: ${{ secrets.TRANSLATE_API_KEY }}
        run: ./scripts/translate-new-strings.sh languages/

      - name: Compile .mo and JSON
        run: |
          wp i18n make-mo languages/
          wp i18n make-json languages/ --no-purge

      - name: Open pull request with translations
        uses: peter-evans/create-pull-request@v6
        with:
          branch: chore/auto-translations
          title: "chore: auto-translate new strings"
          commit-message: "chore: auto-translate new strings"

Unde se ascunde munca reală

Pasul translate-new-strings.sh este locul unde are loc traducerea propriu-zisă. Versiunea naivă a acelui script citește fiecare intrare goală, o trimite către un API LLM, câte un șir de caractere odată, și lipește răspunsul înapoi. Această versiune naivă este exact capcana, și merită să fim expliciți cu privire la motiv.

De ce apelurile LLM implementate manual îți strică fișierele

Răspunsul scurt: apelurile brute către LLM-uri tratează șirurile tale .po ca proză, iar șirurile tale .po nu sunt proză – sunt date structurate cu placeholder-uri, forme de plural și context pe care un apel de chat-completion le distruge cu ușurință.

Coruperea Placeholder-urilor pe care nu o vei vedea în teste

Trimite Deleted %d of %s files către un endpoint general de chat și ai putea primi înapoi Supprimé %d des %s fichiers (OK) sau Supprimé %d de % s fichiers (un spațiu s-a strecurat în placeholder, iar acum sprintf() generează o eroare la rulare). Trimite o intrare de plural și modelul ar putea colapsa două forme într-una singură, stricând limbile cu mai mult de două categorii de plural. Trimite un șir de caractere cu <a href="%s"> și modelul ar putea traduce URL-ul sau ar putea elimina tag-ul. Niciuna dintre aceste erori nu apare în testele tale, decât dacă testezi în mod specific rezultatul redat în fiecare locală – ele apar ca erori de rulare în producție pentru utilizatori de la care nu poți citi rapoarte de bug-uri.

Capcana mentenanței

Poți încerca să te aperi împotriva acestui lucru cu prompt engineering și post-procesare regex, și multe echipe fac asta. Problema este că acum menții un motor de traducere fragil ca proiect secundar, redescoperind fiecare caz limită al placeholder-urilor pe care ecosistemul Gettext le-a rezolvat deja. Catalogăm modurile specifice în care variabilele sunt alterate – și cum să le previi – în traducerea fișierelor PO fără a strica variabilele de cod. Lecția de acolo se aplică direct: calitatea modelului este rareori problema; manipularea structurală în jurul său este.

Integrarea unui traducător cloud bazat pe API în CI

Acesta este punctul în care un serviciu de traducere bazat pe API înlocuiește ghicirea din scriptul translate-new-strings.sh. În loc să implementezi manual apeluri LLM și regex de post-procesare, pasul tău CI încarcă fișierul .po modificat către un serviciu care deja înțelege structura Gettext și returnează un output curat. Forma pipeline-ului rămâne identică – extrage, diferențiază, traduce, comite – dar pasul fragil din mijloc devine un singur apel API.

Apelul API care înlocuiește scriptul tău

SimplePoTranslate este construit exact pentru acest scop. Expune un API cloud potrivit pentru automatizare și CI, astfel încât pasul de traducere al workflow-ului tău devine o cerere care predă fișierul .po și primește înapoi unul tradus, fără bucle per șir de caractere. Funcționalitatea sa de Syntax Locking menține automat la locul lor %s, %1$s, {count}, HTML și token-urile de cod – întreaga clasă de bug-uri din secțiunea anterioară este gestionată de motor, mai degrabă decât de regex-uri pe care le-ai întreține tu. Cu suport complet pentru pluralul Gettext și msgctxt, formele de plural și contextul supraviețuiesc ciclului de prelucrare, lucru pe care un apel de chat-completion nu îl poate garanta.

Idempotența și poarta de revizuire rămân la latitudinea ta

Două decizii de design îți aparțin în continuare, indiferent de motorul pe care îl folosești. În primul rând, idempotența: continuă să traduci doar intrările goale după msgmerge, astfel încât merge-urile fără operații să nu producă nicio diferență. În al doilea rând, o poartă de revizuire: lasă job-ul să deschidă un pull request, așa cum face scheletul de mai sus, în loc să comită direct pe main. Traducerea automată este excelentă pentru a pune rapid șirurile de caractere în producție, dar o privire umană înainte de merge prinde rara eroare de context – iar un PR îți oferă acea privire fără a bloca cazul comun. Echipele care gestionează multe locale sau multe site-uri de clienți vor recunoaște acest model din fluxul de lucru ideal de localizare pentru agenții, unde același model de automatizare-apoi-revizuire se extinde pe zeci de proiecte.

Concluzie

Pentru a automatiza traducerea în CI/CD fără a livra build-uri defecte, modelul este consecvent: regenerează fișierul .pot la merge, msgmerge-uiește-l în fiecare locală pentru a scoate la iveală doar șirurile de caractere noi, traduce doar acele șiruri și comite rezultatul în spatele unei porți de revizuire (pull request). Idempotența îți menține diff-urile curate; poarta de revizuire ține traducerea rară greșită în afara producției.

Partea care trebuie făcută corect este pasul de traducere în sine. Apelurile LLM implementate manual vor corupe placeholder-urile și formele de plural în moduri pe care testele tale nu le vor prinde, iar tu vei petrece mai mult timp menținând „lipiciul” de traducere decât codul funcțional pe care îl servește. Un motor bazat pe API cu Syntax Locking elimină întregul mod de eșec, astfel încât pipeline-ul tău traduce șirurile de caractere noi la același merge care le-a introdus – iar utilizatorii tăi non-englezi încetează să mai vadă placeholder-uri în engleză.

Ești gata să automatizezi traducerea în pipeline-ul tău fără a strica placeholder-urile? Încearcă SimplePoTranslate gratuit — nu este necesar un card de credit. Începe cu nivelul gratuit, validează API-ul cu propriile tale fișiere .po și integrează-l în CI când ești pregătit.