Bune practici pentru traducerea unui site

Sunt atât de multe chestii legate de i18n care îmi sunt total necunoscute încât nu știu exact nici ce să caut nici de unde să încep. Până acum, singurul mod prin care am interacționat cu multilang a fost prin intermediul WordPress și al WPML (am sc ris aici mai multe), dar sunt curios despre ce se întâmplă în alte CMS-uri (chiar și cele custom).


Cam cum ar trebui tratat un site multi-lang? Ok, pentru textele statice avem gettext, dar cum ar trebui procedat cu conținutul propriu-zis (în special în partea de admin)?

  • Pagina de edit a unei pagini ar trebui să conțină câte un editor pentru fiecare limbă sau doar editor pentru limba curentă + link spre traduceri?
  • Assets (imagini, filme) urcate pentru o anume pagină ar trebui să fie disponibilie și în paginile traduse?
  • Dacă da, cum s-ar trata informațiile fiecărui asset (e.g. titlul imaginii)?

Pe frontend:

  • pentru un utilizator nou ar trebui să se facă redirect spre o anume limbă sau se afișează limba implicită?
  • dacă se face redirect, se face în funcție de:
  • IP
  • Browser language
  • Altceva?
2 Likes

M-am confrutat cu exact aceeasi problema chiar recent. Am avut o dezbatere pe tema redirect-ului. Dupa 2 saptamani de testing am constatat ca, din diverse motive, un redirect pe baza de IP nu e intotdeauna precis si poate duce de multe ori la confuzii.

Asa ca ne-am hotarat sa redirectionam pe baza limbii setate in browser. Unde din nou ne-am lovit de probleme in Internet Explorer 9 si 10, care in mod ironic, era unul din browserele dominante in randul vizitatorilor site-ului respectiv (deh, industrie :smile: ). Ne-am simtit nevoiti sa renuntam la redirect (mentionez ca in afara de IE 9 si 10, nu am intampinat dificultati in nici un browser, nici macar IE 8 sau Opera).

Cat despre back-end, mereu am folosit getcontent(sau asemanator, in functie de platforma) cu librarii i18n.

1 Like

Tocmai ce citeam articolul asta. Btw, din cate stiu eu @danstefancu a lucrat mult cu traducerea pe romana a WP. Poate ne ajuta cu cateva sfaturi in privinta asta.

@stefanbc: povestea asta e utilă doar dacă vrei wp în altă limbă decât cea default. Nu rezolvă problema unui site multi-language :wink:

In general, pentru content dinamic sunt 2 abordari:

  1. cate o varianta pentru fiecare limba la toate textele introduse in baza de date (si la modelarea DB-ului e discutie daca e relationala)
  2. pur si simplu item diferit pentru variantele de limba: pagina cu id=1 pt ro si cu id=2 pt en - asta e un pic mai greu daca ai ceva mai mult decat de afisat continut pe un graf de pagini

E mai bine sa lasi userul sa aleaga limba. Geolocatia e destul de accurate in 9x % din cazuri…

Noi avem multi clienti din Asia unde se folosesc foarte multe proxy-uri si VPN-uri. Din cauza asta geolocatia nu a fost o optiune viabila. Dar in general, ai dreptate, e destul de precis.

selector de limba atunci. beats everything.

In primul rand trebuie sa decizi ce tip de site multi-language faci: mirror sau languate standalone. Eu discut din prisma mea, cms custom.

Mirror - inseamna ca orice pagina de romana exista si in engleza,etc. De obicei astfel de variante sunt paguboase pentru trebuie produs content in toate limbile. Iar daca vrei sa adaugi o limba noua esti obligat sa produci la greu.

Standalone. Utilizatorul de cms isi poate construi contentul si ierarhia lui in fiecare limba, fara sa depinda una de alta. Din punctul meu de vedere, varianta asta este mult mai eficienta pentru client si pentru mine ca dezvoltator.

Pentru ambele variante, asseturile sunt separate, dar au share intre ele la asseturi. Editor la pagini este pentru fiecare limba in parte. Problema apare nomenclatoare (categorii, meniuri,etc), si aici am avut variante diverse de care nu sunt multumit (asa ca nu le spun :blush: ).

In ceea ce priveste limba afisata default: daca siteul se adreseaza in mod principal unei tari afisezi pentru tara aia. Alfel dupa IP.

Ba chiar te rog! Să știu la ce ar trebui să fiu atent

OK. Imi e rusine de ele dar let’s do it

  1. Varianta coloane multiple. sa zicem avem nomenclatorul culori:

    id, title
    1 rosu
    2 galben

Devine

id, title, title_en
1  rosu, red
2, galben, yellow
  1. un fel de eav:

tabela, id, translation, language_id
culori 1, red, english (ma rog id-ul lui)

Din perspectiva Drupal 7 (mare parte se aplică și pentru viitorul Drupal 8):

Există două tipuri de texte ce trebuiesc traduse

  • Conținut
  • Interfață

Conținutul îl traducem folosind “Entity translation” (ET). Asta înseamnă:

  • Avem același id pentru o pagină/entitate și mai multe traduceri atașate pentru fiecare field care trebuie tradus
  • Interfața de editare are tab-uri pentru fiecare limbă în care se traduce.
  • Pe pagina unde editezi traducerea putem omite field-urile care nu trebuiesc traduse (ex. galerie foto, câmpuri numerice, id-uri către alte entități) și simplifică mult interfața pentru translatori.
  • De asemenea, când editezi o traducere interfața adminului poate să fie în altă limbă decât cea pe care o editezi
  • În cazul în care unui field îi lipsește traducerea, putem face fallback la limba default pentru field-ul respectiv. Astfel putem afișa pagini parțial traduse.

În Drupal 6 (unii încă mai folosesc și în Drupal 7), exită și posibilitatea de a traduce creând entități diferite/clone pentru fiecare limbă (noi numim varianta asta Content Translation - CT). Ajungi astfel să ai “n” entități diferite pentru fiecare pagină, fiecare cu id propriu și un câmp de legătură care indică pagina tradusă (originala) și limba. Din punctul meu de vedere abordarea asta îți crează niște probleme:

  • Meniuri: trebuie să creezi intrări diferite cu fiecare ID pentru fiecare limbă (cu ET ai o singură intrare în lista de meniuri și se afișează conținutul în limba selectată)
  • În caz că utilizatorul accesează entitatea în limba greșită (wrong url) trebuie să cauți id-ul traducerii respective în db și să faci redirect către alt URL (cu ET problema asta e rezolvată de la sine fără redirect - afișezi direct câmpurile în limba selectată)
  • Dacă vrei să extragi statistici per pagină/entitate o să trebuiască să combini statisticile de la toate ID-urile (original + traduceri).
  • Atunci când creezi o traducere, clonezi pagina/entitatea inițială și ajungi să ai valori duplicate în db pentru câmpurile care nu trebuiesc traduse. Pe lângă asta, atunci când adaugi field-uri noi sau când vrei să modifici un câmp care nu trebuie tradus, trebuie să editezi fiecare traducere în parte.

Sunt tare curios cum e Wordpress din punctul ăsta de vedere.

Interfața
Orice text care e afișat se poate traduce folosind o interfață specială în admin. De cele mai multe ori clientul contribuie la traduce (noi nu traducem mai nimic - sau traducem doar câteva elemente de test). În cazul în care munca de traducere e foarte mare, folosim Translation Manangement Tools care oferă un workflow îmbunătățit pentru colaborarea cu traducători externi.

Redirect
Evităm să facem redirect bazându-ne pe IP sau Browser language. Aproape toate proiectele noastre au un language selector plasat cât mai sus (să nu trebuiască să faci scroll) și cât mai vizibil.

Regulile pentru selectarea limbii diferă de la proiect la proiect, însă sunt combinație de:

  • cookie (dacă s-a folosit selectorul)
  • limba definită în profil (dacă utilizatorul e logat)
  • limba default a site-ului (dacă accesezi direct homepage-ul)
  • language prefix (toate path-urile au prefix limba, de exemplu “/en/contact” sau “/de/contact”)

Arhitectura
Pentru field-uri de la conținut structura e deja definită de Drupal și pentru fiecare field avem o tabelă cu field-uri de felul:

  • entity_id
  • revision_id
  • language
  • delta (în caz că putem avea mai multe valori pentru câmpul respectiv)
  • val1, val2 … (valoarea/valorile respective)

Pentru interfață există o funcție t() prin care trecem toate stringurile. Ca parametrii are:

  • stringul care trebuie tradus
  • argumente (string-ul poate conține placeholdere care nu trebuiesc traduse și valorile pentru placeholdere le trimitem ca argument)
  • context (uneori același cuvând în engleză se traduce diferit în funcție de context. folosim asta pentru a diferenția înțelesurile).

Funcția t() vine la pachet cu alte funcționalități:

  • Interfață de căutare string/traducere (din păcate pentru conținut nu avem așa ceva)
  • Import/Export de traducere folosind fișiere .po
  • Download și update automat al traducerilor deja existente pe localize.drupal.org
4 Likes