‘localizáció’ címkével ellátott bejegyzések

Április – Lokalizáció hatékonyságának növelése

Zolnai Tamás, 2013. május 3. péntek

   Az előző hónapban elkezdett kódtisztítást folytattam ebben a hónapban is. Több olyan megoldást töröltem, mely a régi rendszer maradványaként volt jelen a kódban. Ezzel egyrészről a kód olvashatóságát és annak egyértelműségét sikerült javítani, másrészről több helyen a feldolgozásból is sikerült törölni néhány felesleges műveletet, így javítva annak hatékonyságán. Ezen felül sikerült egy speciális adatstruktúrát implementálni, melynek köszönhetően a lokalizációs programok hatékonyabban képesek keresni a felhasznált sztringek között.

   Az első változtatásom, ahogy azt már előző beszámolómban is előrevetítettem, a forrásfájlok és a PO fájlok közötti sztringátalakításokkal kapcsolatos. A megoldás alapvető koncepciója, hogy a lokalizációs programokat megvalósító osztályok és a PO osztályok közötti kommunikációban a sztringek normál alakban szerepelnek, semmi olyan átalakítást nem tartalmazva, mely forrásfájlhoz köthető (Pl.: xml átalakítások, escape-elés). Így minden osztálynak csak a hozzá tartozó formátummal kell foglalkoznia és az ahhoz tartozó átalakításokat megvalósítania. Ennek az elkülönítésnek a jótékony hatása leginkább az *.src\*.hrc fájlokat feldolgozó transex3 program esetén figyelhető meg. Eddig a transex3 átalakításai három szinten jelentek meg: közvetlenül a transex3 forráskódjában (export.cxx), a lokalizációs programok által közösen használt kódban (merge.cxx) és a PO osztályok kódjában (po.cxx). Így valóban egy nehezen követhető megoldást sikerült leegyszerűsíteni.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=d885a85a48a4706934e170b7a6671e5e029089a0

   Ahogy említettem a kódban volt néhány mára már elavult koncepció. Az első ilyen, hogy a lokalizálni kívánt sztringekhez a rendszer eltárolt egy platform attribútumot. Ez egyedül a transex3 programhoz kapcsolódik, mivel az *.src\*.hrc fájlokban volt lehetőség makrók segítségével definiálni platform specifikus sztringeket. Bizonyára azóta más szinten oldották meg a platformok problémáját, mivel a lokalizáció mára már figyelmen kívül hagyja ezeket (a PO fájlok sem tárolják). Egy adatstruktúra azonban még őrizte ennek a megoldásnak az emlékét. A lefordított sztringek forráskódba való beemelése során, a PO fájlokból beolvasott sztringek adatai egy olyan map-ben voltak letárolva, melyben a kulcs ez a platform tulajdonság. Mivel azonban ma már nem használatos ez a tulajdonság ezért, minden esetben egy konstans sztring alapján történt a beszúrás és a keresés (bizonyára egy ideiglenes megoldás). Szóval minden esetben egyetlen adatról volt szó, de annak letárolására egy egész map-et használt a rendszer.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=be30e0e139ecc068665c8e46020b60356b05cfd6

   A felesleges adatstruktúra mellett ez a platform attribútum a feldolgozásban is felesleges sztringműveleteket jelentett, hiszen az adott makró definícióból ki kellett nyerni a tényleges platform azonosítót. Egy másik hasonló tulajdonság, mely növelte a feldolgozás műveleteit, a szélesség attribútum. Ez a tulajdonság szintén a transex3 programhoz és az általa feldolgozott *.src\*.hrc fájlokhoz köthető. Ezek a fájlok különböző felhasználói felületi elemeket definiálnak fix méretezéssel. Ezen méretek közül a szélesség mértékét valamiért külön felhasználták a lokalizáció során, de ma már ez sem használatos, így a feldolgozásnál külön nem kell foglalkozni vele.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=9e2d2822063729f450adb734f58106bb64695ce6

   Egy másik régi koncepció volt, hogy a forrásfájlokba, melyekből ma kizárólag az angol stringeket emeljük ki, régen más nyelvű stringek is bekerültek, és az akkor még SDF outputba ezeket is kiemelték a lokalizációs programok. Ahhoz, hogy több nyelvű forrásfájlt ilyen módon fel lehessen dolgozni, le kellett tárolni a különböző nyelvek azonosítóit és azokat felhasználva lehetett eltárolni, illetve kiírni az adott string egyes nyelvi megfelelőit. A több nyelvű koncepció megszűnésével azonban nem szűnt meg a nyelvazonosítókat tároló vektor (ez szintén egyetlen elemet (en-US) tárolt minden esetben) és megmaradtak az ezen vektor bejárását célzó ciklusok is, melyek ciklusmagja minden esetben csak egyszer futott le. Így a kód nem igazán tükrözte a tényleges tevékenységet.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=4146406205ce6f939944685e1931dcd45f3de708
és
http://cgit.freedesktop.org/libreoffice/core/commit/?id=f167f037351d953e324eb97d6055064efa2d7f59

   Miután sikerült a forráskódból kitakarítani az ily módon megmaradt felesleges kódok nagy részét, áttértem a hatékonyság javításának egy konstruktívabb formájára. Az egyes lokalizálandó sztringek azonosítására négy sztring attribútum szolgál (fájlnév, csoportazonosító, közvetlenazonosító, típus). Mivel ezek közül egyik sem hagyható el, ezért az ezekből összegyúrt sztringazonosító általában elég hosszúvá válik. Éppen ezért az ilyen azonosító alapján való keresés kevéssé hatékony, mint például egy számból álló azonosító esetén. Ezért az adatok közötti keresés hatékonyságának érdekében egy speciálisabb adatstruktúrát hoztam létre, illetve az eddig használt egyszerű hash map-et (unordered_map) módosítottam egy kicsit.

  Az új adatstruktúra hatékonyságának megértéséhez elengedhetetlen megismerni egy kicsit jobban a lokalizáció folyamatát. Két dolgot kell látni. Egyrészről azt, hogy a PO fájlokban a sztringek sorrendje általában megegyezik azok felhasználásának a sorrendjével. Ugyanis ahogy már említettem a lokalizációnak két igen jól elkülöníthető része van: a sztringkiemelés POT fájlokba és a lefordított sztringek beírása a forrásfájlokba. Mindkét lépésben ugyanaz a feldolgozás fut le, és így az érintett sztringek sorrendje mindkét esetben megegyezik. Azonban a PO fájlok frissítésének van egy átfutási ideje és így a folyton változó forráskód ezt a sorrendiséget részben megsérti. Éppen ezért egy olyan adatstruktúrát kellett készíteni, mely ezt a részben teljesülő sorrendiséget használja ki.

   A másik dolog, hogy a PO-kból beolvasott sztringeket legtöbb esetben pontosan egyszer kell felhasználni. Ebből látszik, hogy ideális esetben, mikor a PO fájlok és a forrás fájlok között konzisztencia van, az említett hash map-et valójában a FIFO elv szerint használjuk, annak ellenére hogy ez nem látszik a használatán és a hatékonyságán. Mivel azonban gyakori az inkonzisztencia ezért nem használhatunk egy az egyben egy sor adattípust, hiszen abban nem lehet keresni szükség esetén. Ugyanakkor az eddig használt hash map hatékony keresési lehetőségeket nyújt, legalábbis a sztringkulcsos keresések körében (a probléma a kulcs típusa). Így egyenesen adódott a sor és a hash map egyesítésének ötlete.

   A megoldás lényege, hogy a hash map-en belül definiáltam egy beszúrási sorrendet úgy, hogy az egyes elemek mellé letároltam egy mutatót, mely a beszúrási sorrendben rákövetkező elemre mutat (A hash map-ben az elemek sorrendje teljesen a hash-eléstől függ így arra nem lehet támaszkodni). A lekérdezések során pedig, minden esetben az előzőleg lekérdezett elem rákövetkezőjével kezdjük a keresést. Minél nagyobb a konzisztencia a PO fájlok és a forrásfájlok között, annál kevesebb tényleges keresésre van szükség (ideális esetben 0). Az így módosított hash map interfésze változatlan, csak a működése illeszkedik jobban a FIFO elvre.

   Ez csak egy vázlatos leírása a megoldásnak. További aspektusait nem lenne érdemes itt kifejteni, de azt még érdemes megemlíteni, hogy a LibreOffice által támogatott összes nyelvre való futtatás során, a keresések száma átlagosan úgy egy tizedére illetve egy századára csökken, programtól függően. Ugyanakkor a tesztelés során még az egy századra való csökkenés esetén sem volt látható szignifikáns változás a futási időben. Úgy tűnik a sztringkeresés futási ideje elhanyagolható a feldolgozásé mellett.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=c7ef2522272579a12eecddded0cbed6d222d3742

Az utolsó hónapban a Base-zel fogok még dolgozni, úgyhogy a lokalizációs modullal való ismeretségem mintegy lezárásaként írtam minden osztályhoz egy rövid leírást az utókor számára.
http://cgit.freedesktop.org/libreoffice/core/commit/?id=29400c568a84339066ef238e836cfeb19f732873

Március – Lokalizáció megtisztítása

Zolnai Tamás, 2013. április 5. péntek

   Ez a hónap főleg háttérmunkálatokkal telt. Egyrészről az előzőleg bevezetett új adatbázis funkcióhoz (limit) kapcsolódóan jelent meg a rendszer által nyújtott osztályok néhány hiányossága, melyek kielégítő kiküszöböléséhez még olyan alapvető adatstruktúrához is hozzá kellett nyúlnom, mint a rendszerben használt string osztályok. Másrészről a lokalizáció átalakítása során sok helyen fennmaradtak olyan sajátosságok, melyek a már megszűnt SDF fájlformátumhoz kapcsolódnak és az új PO-s rendszerben teljesen feleslegesek.

   A limit megadására használható kombinált listával kapcsolatban két megemlítendő probléma jelent meg, mely problémák a LibreOffice-ban implementált funkciók alsóbb szintjeire vezettek el. Az első a kombinált listát megvalósító osztályhoz köthető (ComboBox). Ennek az osztálynak a tényleges megvalósítását nem kell ismerni a felhasználáshoz, csakis azt, hogy a hozzá tartozó interfész függvényei milyen inputra, milyen outputot adnak vissza. A CalcSize() függvénye karakterszám alapján kiszámolja a kombinált lista méretét. Az így kapott értékek mértékegységét (talán mm), illetve tényleges értékét szintén szükségtelen ismerni, hiszen ezt az értéket egyből tovább is lehet adni a megfelelő függvénynek, mely ez alapján megrajzolja a kombinált listát. Mindez a jól kialakított interfésznek, illetve az objektumorientált paradigmának köszönhető.

   A CalcSize() függvény azonban nem a jó szélesség értéket adta vissza, így a tényleges implementációt kellett felülvizsgálni. Szerencsére az implementációnak is több szintje van, így a mértékegység ismerete továbbra sem vált szükségessé. Ugyanis a függvény egyrészről kiszámolja az adott karakterszámnak megfelelő szélességet (egy karakter szélességét szintén egy függvény adja meg) és ezt korrigálja további értékekkel. Ilyen érték az aktuális stílusnak megfelelő szegély, illetve a legördülő lista lenyitásához használható nyíl mérete. Az előbbi korrekció volt az, ami hiányzott.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=3a31375528ad3d9fc49f5ab3982e96c9e46fa7af

   A másik probléma még mélyebb szintre vezetett. Nemcsak a felhasznált felhasználói felület elemeinek megfelelő osztályok implementációjába, hanem alapvető adatstruktúrák használatába is bele kellett mélyednem. A lekérdezésben elméletileg bármekkora limit érték megadható, mivel a visszatérési sorok száma is bármennyi lehet. Így a megadható érték korlátját csak az annak tárolására használt egészet megvalósító adattípus korlátjai jelentik (Int64). A probléma ott adódott, hogy a felhasznált osztály (NumericBox) az érték tárolásához használt egész típus maximumához közeli értékeket nem tudta lekezelni (Csak hogy milyen nagyságrendről van szó, ilyen szám például a 92 233 720 368 547 750).

    A probléma oka, hogy a NumericBox osztály belsőleg használ egy string → valós konverziót a túlcsordulás elkerülésére, mely string → egész konverzió esetén előfordulhat. A valós konverzió során azonban, túl nagy értékek esetén a konverzió kerekítéseket használ, és így az egész érték megváltozik. Ez pedig ahhoz vezet, hogy a beviteli mezőben más érték jelenik meg, mint amit a felhasználó begépelt. Ez azért nem okozott általában problémát, mivel a hasonló kombinált listák általában nagyságrendekkel alacsonyabb értékek begépelését engedik meg, ahol nem jelennek meg ezek a kerekítések.

    A megoldáshoz módosítani kellett a string osztályok részét képező string → egész konverziót, úgy hogy lekezelje a túlcsordulást. Majd az így módosított függvényt segítségével kellett lekezelni a viszonylag nagy egész értékeket. Ezzel a szélsőséges esetek helyes lekezelése mellett a hatékonyságot is sikerült némileg javítani, mivel a NumericBox a valós szám használatának köszönhetően rengeteg valós ↔ egész típuskonverziót is tartalmazott.

Túlcsordulás lekezelése:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=bd60d41176da540b01d7583cfe00637431967f39
Valós konverzió kiküszöbölése:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=84bac1799e528272ca808240508ca3f66272ee13

    A hónap további részében a lokalizáció területén végeztem néhány átalakítást. Elsőnek a lokalizáló programokban mintegy fantomként létező SDF formátum eltüntetése volt a cél. Ez a jelenlét főleg a kiemelés részfeladatára volt jellemző, ahol még ideiglenes SDF sorokat is generáltak a programok. Ez az ideiglenes SDF generálás azonban már olyan vékony köztes réteget képezett a lokalizáló programok és a PO fájlformátum között, hogy annak kiküszöbölése már egyszerűen megoldható volt. Ezzel sikerült a forrásfájlokban található összes SDF-re utaló elnevezést is eltüntetni.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=15a13bafccb96e6ab0cc5a23af6dd46715fa22c5

    Az SDF generálástól való megszabadulás során felszínre kerültek további olyan adatok és funkciók, melyek az SDF formátumhoz köthetők. Talán amit érdemes megemlíteni a lokalizációt végző programok parancssori paraméterei. Az SDF tárolási módjához kapcsolódott két olyan paraméter („project” és „projectroot”), melyek néhány string művelet megkönnyítését szolgálták. Ezek a műveletek azonban már az előző átalakítások során eltűntek, így ezt a két paramétert is lehet törölni.

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=56a52889e65a17e324fc10cf341690385f5a9dd9

    Az átalakítások során sikerült jobban megismerni a lokalizációt végző osztályokat. Ezen információk rendszerezésére való törekvésem eredményeként, illetve az átláthatóság javításának érdekében némileg átalakítottam a lokalizációt tartalmazó modult (l10ntool). Ezek az átalakítások tartalmi változást nem jelentenek, alapvetően csak a forráskód átrendezését. Ez magában foglalja a több helyen használt azonos függvények kiemelését egy közös fájlba és a nem használt függvények törlését (ezek nem az SDF kiküszöbölésével váltak feleslegessé, hanem még régről maradtak meg).

Eredmény:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=8e26b4783f1f47ff5d489e7df5869240eefd1071
és
http://cgit.freedesktop.org/libreoffice/core/commit/?id=9d64e7f2b723a7bc711c2acc8da99944b30761ef

  Az átláthatóság növelésének fő célja a mélyebb tartalmi változtatások kieszközölésének elősegítése, mely a következőkben a célom, hiszen a hatékonyságot ilyen módon lehet leginkább javítani. Az egyik ilyen tartalmi átalakítás a fájlformátumokhoz köthető string átalakításokhoz köthető. Ezek az átalakítások két részre bonthatók. Egyik részt jelentik a PO fájlformátum és a forráskódban található formátum közötti konverziók. Másik részét pedig az olyan átalakítások képezik, melyek a fordítók munkáját segítik elő, a PO fájlformátum megengedte kereteken belül. Ilyen például az XML karakterek átalakítása olvasható formába (<,> ,& ,",').

Jelenleg ezen dolgozom. Első ilyen tartalmú javításom a súgó fájlok lokalizációjához kapcsolódik:
http://cgit.freedesktop.org/libreoffice/core/commit/?id=ce51bf1a6ef36bbd1eea751add342cae6f1004d2