Dau câteodată de vreo secvență de cod care mă surprinde prin ingeniozitate sau prin abordare. Ăsta este un exemplu.
Dacă a trebuit vreodată să faci vreo traducere complexă în cod, cel mai probabil te-ai lovit de niște limitări. Cu cât sunt mai multe traduceri, cu atât mai mare riscul de conflicte ciudate.
Discourse este o platformă care trebuie să existe în câteva localizări, printre care și română. Cum extragi textul de tradus dacă ai ceva de genul:
[There are «5 unread»] [and «25 new» topics remaining], or browse other topics in «Category»
(ce este între «»
este link, ce este între []
este opțional)
Direct din limbajul de programare ai nevoie de câteva condiționale întortocheate:
txt = ''; if UNREAD or NEW: txt += There are if UNREAD: txt += «5 unread» If NEW txt += and if NEW txt += «25 new» topics remaining ......
Iar asta ar fi așa, basic și hardcoded. Dar dacă ținem cont că treaba asta trebuie să fie accesibilă traducătorilor (deci nu în codul sursă), de numerele din text și de faptul că numerele au reguli de exprimare în unele limbi (e.g. „un subiect” vs „5 subiecte” vs „25 de subiecte”) dar în altele nu, că unele secțiuni sunt afișate doar în anumite condiții… Oh boy.
În Pragmatic Programmers am citit că un programator bun are abilitatea de a putea scrie propriul DSL – un mini-limbaj care îți rezolvă o problemă foarte specifică. Iar oamenii de la Discourse au făcut… fix asta.
Expresia de mai sus este codată într-un fișier .yml
așa:
There { UNREAD, plural, =0 {} one { is <a href='{basePath}/unread'># unread</a> } other { are <a href='{basePath}/unread'># unread</a> } } { NEW, plural, =0 {} one { {BOTH, select, true{and } false {is } other{}} <a href='{basePath}/new'># new</a> topic} other { {BOTH, select, true{and } false {are } other{}} <a href='{basePath}/new'># new</a> topics} } remaining, or {CATEGORY, select, true {browse other topics in {catLink}} false {{latestLink}} other {}}
La o primă vedere pare extrem de complicat, doar că… nu este:
{ UNREAD, // trimis de backend plural, // dată, număr, plural, timp, sau select =0 { Text afișat când sunt zero UNREAD } =2 { Când sunt 2 UNREAD } // sau orice număr one { text afișat când este un singur UNREAD } few { sub 20 } // (în română, dar în alte limbi poate fi ignorat, poate fi ajustat) other { peste 20 } }
(Știi cum se spune că testele pot ține loc de documentație? Uite aici)
Toată povestea asta, chiar dacă nu este perfectă, este good enough, pentru că are destulă flexibilitate pentru a traduce ditamai platforma (bine, pe de altă parte, nu este nevoie decât în foarte puține locuri de treaba asta).
Există și o bibliotecă JS pentru asta care, din ce îmi dau seama, face cam același lucru.
Gradle, tool de build are propriul dsl. Este bazat pe Kotlin
https://docs.gradle.org/current/dsl/index.html