ugrás a tartalomhoz

Többnyelvűség támogatása sablonokban

szabo.b.gabor · 2010. Aug. 18. (Sze), 10.49

Alkalmazásfejlesztés során felmerülhet az igény arra, hogy a késztermék több nyelven legyen képes megjelenni. Erre a problémára szeretnék most egy egyszerű megoldást bemutatni.

Alap megoldásként felmerül, hogy használjunk valami szótár táblát, ahol valami szöveges kulcs alapján megtalálhatjuk az adott nyelvű kifejezést, ahol pedig meg szeretnénk jeleníteni valami szöveget, ott egy függvényt hívunk a kulcs paraméterrel, ami a lefordított értékkel tér vissza.


<!-- pelda.tpl -->

<h1><?= translate('udv_az_oldalon') ?></h1>
<ul>
	<li><a href="#"><?= translate('belepes') ?></a></li>
	<li><a href="#"><?= translate('blog') ?></a></li>
	<li><a href="#"><?= translate('kapcsolat') ?></a></li>
</ul>

Az én problémám ezzel az, hogy

  • sokáig tart begépelni (translate helyett lehetne t is a függvény neve, de nekem úgy sem tetszene),
  • ha nem enged meg az alkalmazás bármit kulcsként ([a-zA-Z_]{0,60}), akkor ki kell töltenem a fordítás értékeit is, ha normális kimenetet szeretnék látni már tesztelés alatt is,
  • a függvény nagy valószínűséggel végrehajt egy lekérdezést (ha százszor használjuk egy oldal megjelenítésekor, akkor százat) – talán ez az amiért a leginkább unszimpatikus.

Ilyen gyötrelmek között próbáltam létrehozni valami olyan megoldást, ami

  • kis terhelést rak a fejlesztő vállára,
  • rugalmas,
  • adatbázisbarát.

Végül arra jutottam, hogy valamilyen markuppal kell jelölni, hogy mely szövegeket kell lefordítani. Ezeket a kimenetre küldés előtt össze lehet gyűjteni és kicserélni. Jelölő karaktereknek a következő párost választottam: {% és %}.

<!-- pelda2.tpl -->

<h1>{% Üdv az oldalon %}</h1>
<ul>
	<li><a href="#">{% Belépés %}</li>
	<li><a href="#">{% Blog %}</li>
	<li><a href="#">{% Kapcsolat %}</li>
</ul>

A példán látszik, hogy nem jelent túl sok plusz munkát egy sablont felkészíteni a többnyelvűségre. Kimenetre küldés előtt pedig szépen összegyűjthetők a lefordítandó kifejezések, használhatjuk az adatbázisban például az md5 hash értéküket keresési kulcsként (persze ha a fordító munkáját is meg akarjuk könnyíteni, nem árt eltárolni az eredeti értékeket is). Ha nem találnák fordítást a szöveghez, akkor egyszerűen elhagyhatjuk a jelölő karaktersorozatokat és értelmes kimenetet látunk.

A markup bővíthető plusz karakterek hozzáadásával, és nyilván felmerülhet még csomó probléma, csak az alapötletet szerettem volna bemutatni, igény esetén szívesen mutatok be részletesebb megoldást.

 
1

gettext

Török Gábor · 2010. Aug. 18. (Sze), 10.59
a függvény nagy valószínűséggel végrehajt egy lekérdezést (ha százszor használjuk egy oldal megjelenítésekor, akkor százat) – talán ez az amiért a leginkább unszimpatikus.

A te megoldásodban is megvan ugyanez az „overhead”, csak más formában. Ha lefordítod a sablont build során, ezt megkerülheted, de ez az első módszerre is igaz.

Másfelől erre van szabványos, beépített támogatás: a gettext.

    <li><a href="#"><?= _('Belépés') ?></li>  
2

Ehhez annyit tennék még

kuka · 2010. Aug. 18. (Sze), 11.32
Ehhez annyit tennék még hozzá, hogy a gettext elterjedt eszköz, ezért
  • kapható hozzá egy csomó (többnyire GPL licenszű) szerszám
  • az így készített fordítást más programban (nem feltétlenül PHP) is használhassuk
3

Fordítók

Török Gábor · 2010. Aug. 18. (Sze), 11.51
+ a fordítók munkáját segíti a több tucat gettextre épülő fordítóprogram.
4

Cpanel vs threadSafe

tlof · 2010. Aug. 18. (Sze), 12.02
Ehhez annyit tennék hozzá, hogy a CPanel mint elterjedt hosting platform esetén tele leszel megmagyarázhatatlan hibákkal, félig fordított oldalakkal.

A doksi is felhívja a figyelmet arra, hogy ez nem thread-safe alkalmazás. Tehát viccess elemek fognak képződni.

Példa:
1, elindul az alkalmazásod. Kap egy default locale-t.
2, beállitasz valamilyen nyelvet a setlocale() parancsal. Ez az egész threadre érvényes
3, elkezded a kiírást.
4, ugyan abban a threadben elindul még egy php alkalmazás. Kap egy default locale-t. Ez az egész threadre érvényes.
5, a scripted a lap alját már hibásan fordítja le.

Nem véletlenül nem használja ezt a módot alapértelmezettként sem a wordpress, sem a drupal.
8

Gettext overhead

Joó Ádám · 2010. Aug. 18. (Sze), 18.08
A po állományt is fel kell dolgozni, ráadásul külön eszköz kell a létrehozásához. Sokkal egyszerűbb és hatékonyabb a programnyelv megfelelő adatstruktúrájában (PHP estén asszociatív tömb) tárolni a fordításokat.
14

igazabol amennyire latom a

Tyrael · 2010. Aug. 18. (Sze), 21.37
igazabol amennyire latom a nyero megoldas az a gettext szintaxisa normalisabb tarolobol taplalva.
http://framework.zend.com/manual/en/zend.translate.adapter.html

Tyrael
5

Erre is csak egy egysoros

deejayy · 2010. Aug. 18. (Sze), 15.09
Erre is csak egy egysoros függvényemet tudnám bepasztolni, ahogyan az elmúlt alkalommal is:

function lang($r = array(), $str = "") {
    return preg_replace("/#([0-9A-Z_]+)#/e", "array_key_exists('$1', \$r) && \$r['$1']?\$r['$1']:'$1'", $str);
}
Pl.

#NUMMESSAGES#: {msgcount}
Ebbe aztán lehet beletenni hibakezelést, hogy mivan akkor, ha nem létezik fordítás, szépen kirakni logba, vagy riasztást küldeni, esetleg hetente felülvizsgálni, hogy mik jöttek elő.

Hátránya (vagy mégsem?), hogy a magyart is meg kell írni.
6

Ezt úgy érted, hogy a

kuka · 2010. Aug. 18. (Sze), 15.32
Ezt úgy érted, hogy a függvény használata előtt a teljes fordítást betéped a memóriába egy tömbbe?
7

Igazából nevezz engem szűk

bugadani · 2010. Aug. 18. (Sze), 17.29
Igazából nevezz engem szűk látókörűnek, vagy tapasztalatlannak, de nem látok megoldást. Vagy lehúzza egyben az összes fordítanivalót, vagy egyesével. Ergó vagy a memóriát viszi, vagy pedig a kismillióhoz közelítő adatbázislekérést, esetleg fájlműveletet halmoz fel. Személy szerint, amíg néhány száz fordítandó szóról van csak szó, inkább lekérem egyben őket. (Igaz, ha oldalnyi szövegekről lenne szó, én is kétszer meggondolnám...)
9

Azért se nevezlek. ;) Én csak

kuka · 2010. Aug. 18. (Sze), 18.14
Azért se nevezlek. ;) Én csak az említett fordítási módszer másik felére lettem volna kiváncsi. Az a fordítás állomány lehet strukturált is, esetleg mezei indexxel az egyes részek gyors eléréséhez fseek()-el. Vagy valami egészen más.
13

nem mind1 viszont, hogy

Tyrael · 2010. Aug. 18. (Sze), 21.32
nem mind1 viszont, hogy futasi idoben hivodik meg a templatebol minden egyes nyelvi kulcsra a "_" fuggveny, vagy pedig lebuildeled placeholderekkel a kimenetet, majd utana osszeszeded a bufferelt output-bol a forditando szovegeket, es egy multi-get -tel egyszerre kered le, es helyettesited be a nyelvi kulcsokat.

Tyrael
19

kb ennyi lényegét látom én is a dolognak

szabo.b.gabor · 2010. Aug. 19. (Cs), 13.52
aztán, hogy fordítás közben mit csinálunk éppen.. én a fordítandó dolgokat lekérem adatbázisból, de akár azt is megnézhetném, hogy mennyi van meg cache-ben épp, és csak a maradék szükségeseket kérem le. A lényeg mindenesetre annyi, hogy ha akarom 1 függvényhívás a fordítás, ezért is nem kezdtem el fordító osztályt bemutatni, mert nem az az 'igazi ötlet'.
21

igen, en ertettem a

Tyrael · 2010. Aug. 19. (Cs), 14.12
igen, en ertettem a lenyeget.

Tyrael
17

Most épp egy 160 kifejezéses

deejayy · 2010. Aug. 19. (Cs), 07.07
Most épp egy 160 kifejezéses adatbázisom van, ami összesen 6k. Ennél még az adatbázis osztály is nagyobb :) Az egész fájlban egy tömb van, amit include-olok, és ezáltal lesz egy globális nyelv változóm, amit átpasszolok a fordítófüggvénynek.
18

Értem. Akkor tökéletesen

kuka · 2010. Aug. 19. (Cs), 08.35
Értem. Akkor tökéletesen megfelel a tömb. Annyit vétek bármivel is bonyolítani.
10

És a magyar sosem változik?

Joó Ádám · 2010. Aug. 18. (Sze), 18.14
Ez egészen addig működőképes, amíg fel nem merül az igény, hogy a belépést bejelentkezésre cseréld. Ezért kell szimbolikus kulcsokat használni, és a magyar fordítást is elkészíteni.
12

+1

inf · 2010. Aug. 18. (Sze), 20.08
Yepp, vagy kell külön nyelvi fájl, amiből kiveszi, hogy melyik szimbólumnak mi az értéke, vagy le kell másolni a sablonfájlokat és megírni a másik nyelvre is, viszont ez utóbbi esetben problémás a sablonok módosítása.
22

Valamint ha ugyanarra a

tgr · 2010. Aug. 20. (P), 20.27
Valamint ha ugyanarra a magyar szóra más-más helyeken más az angol megfelelő, akkor jöhetnek az undorító trükkök, hogy pl. különböző számű szóköz a végére. Az elsődleges nyelvű szöveget használni kulcsnak elsőre kényelmesnek tűnik, de valójában végtelen szopássorozathoz vezet az esetek nagy részében.
23

És hát persze a paraméterek,

tgr · 2010. Aug. 20. (P), 20.30
És hát persze a paraméterek, egyesszám-többesszám, magyarban még ráadásul a hangrend és a végződések igazítása (egyes más nyelvekben meg a birtokos mód és hasonlók) hamar agyonbonyolítják a szépnek megálmodott sablonnyelvet.
11

ha már sablon, akkor a smarty

barii · 2010. Aug. 18. (Sze), 18.28
ha már sablon, akkor a smarty jut eszembe, ahol config fájl van, és abban szekciók
én ugy csináltam, hogy pl fórum szekcióba teszem ami a fórum.tpl-hez kell majd, és akkor csak azt teszi a memóriába, ami kell a fórumhoz.
minden nyelvhez van egy-egy .conf....
15

Cache

zsoc · 2010. Aug. 18. (Sze), 23.56
Plusz, esetleg egy template cache sem árt, ha már a smarty-t említjük... A teljesítmény kérdését akár így le is lehet redukálni. Az már más kérdés, hogy így valószínűleg elveszik az egyszerűség varázsa.
16

Nyelvesítés

janoszen · 2010. Aug. 19. (Cs), 06.36
Igazából nekem nagyon kellemetlen tapasztalatom van a JIT fordításokkal, a profiler szerint az egyik szoftveremben a futási idő 38%-át (!) veszi el az, hogy fordít. Ha pár száz kulcsnál többről van szó, mindenképpen érdemes az adott nyelvre statikusan lefordítani a sablont, a rendszerben pedig ehhez megfelelő támogatást biztosítani.

Ami a szövegeket illeti, szerintem is szimbolikus kulcsokat érdemes használni, különben nagyon könnyen előjön a WTF érzés, amikor egy év múlva elolvasod a sablont és köze nincs a felületen megjelenő szövegekhez.
20

Nem gátol meg semmi sem

szabo.b.gabor · 2010. Aug. 19. (Cs), 13.54
Nem gátol meg semmi sem abban, hogy az így előkészített sablonokat előre lefordítsd, valamint abban sem, hogy szimbolikus kulcsokat használj.
24

Soha nem fogom megérteni,

virág · 2010. Aug. 23. (H), 15.07
Soha nem fogom megérteni, hogy miért kell a spanyolviaszt újra és újra feltalálni...A nyelvesítésre van egy csomó jól használható módszer, a cachelésre is - inkább ezeket lenne érdemes körbejárni, és ha vannak femerülő problémák, akkor azokat kivesézni, de persze nem vagyok semmi jónak az elrontója, csak picit vicces a többnyelvűségről 2010-ben így kezdeni egy bejegyzést:

"Alkalmazásfejlesztés során felmerülhet az igény arra, hogy a késztermék több nyelven legyen képes megjelenni. Erre a problémára szeretnék most egy egyszerű megoldást bemutatni."

Nem írom le, hogy miért, de szerintem már jónéhány éve (úgy 5-6 minimum) minden, 100 kódsornál hosszabb webalkalmazást illik többnyelvűre csinálni, az egyszerű megoldás amit leírsz az pedig egy csomó nyelvesítési módszerből már ismert, így semmi új nincs benne. De nem kívánok vitatkozni, mindenki csinálja ahogyan jól esik, mindez biztosan csak engem zavart, remélem nem baj, ha van itt egy ilyen vélemény is. :)
25

Nekem az időmből, energiámból

szabo.b.gabor · 2010. Aug. 25. (Sze), 07.33
Nekem az időmből, energiámból és tudásomból ennyire futotta. Spanyolviaszújrafeltalálás nekem szimpatikusabb, mint egy-egy elterjedt megoldás hibáival, kötöttségeivel együtt élni. Én pl se a Drupal-t, se a Joomla-t nem szeretem, és lehet hogy majd csinálok egy százezredik ugyanolyan szar CMS-t, de lehet hogy akár jobb is lesz, vagy csak simán más.

Elhiszem, hogy létezik olyan nyelvesítési módszer, ami ugyanezt a megoldást használja, én nem ismertem egyet sem, és a weblabor keresőjéből sem jutottam el olyan oldalra, ahol be lenne mutatva.

Írj olyan bejegyzést, amilyet szeretnél olvasni és jobb lesz a világ :)
26

Hátha megérted

Joó Ádám · 2010. Aug. 29. (V), 18.05
Ha a szerkesztői döntéseket azon az alapon hoznánk, számunkra hordoz-e újdonságot egy-egy beküldött tartalom, nem sok minden jelenne meg a lap hasábjain.

Vannak itt kezdők is.