Lekce 15 - Šablonovací systém XSLT v PHP - Vícejazyčné šablony
V minulé lekci, Šablonovací systém XSLT v PHP - Jednoduché čtení RSS, jsme si ukázali jednoduché čtení RSS pomocí transformace XSLT.
Transformace XSLT je nástroj vhodný i pro vícejazyčné šablony. Dnes si ukážeme jednoduchý způsob vytváření vícejazyčných šablon v XSLT.
Vícejazyčný web
Možná je načase vytáhnout zbraně silnějšího kalibru. Co když chceme vytvořit vícejazyčný web? Možností je několik. Například můžeme všechny texty uložit do databáze, před vlastní prezentací si je vytáhnout a použít v šabloně. Myšlenka je to lákavá a zřejmě i velmi často používána.
Uvedené řešení však má několik nevýhod. Například zbytečnou zátěž databáze při hromadném výběru celého slovníku. Co kdybychom měli každý slovník v jiném souboru? Stejně ho vždy musíme přečíst celý. Jako obvykle však musíme vybrat vhodný formát. Jenže když už výstupní šablonu mám v XSLT, co kdybych udělal v XSLT i slovník? Ano, tohle řešení funguje.
Šablona
Vhodný postup jsem našel na jednom webu, i když nebyl zcela ideální.
Proto jsem ho přizpůsobil svým potřebám. Nejprve tedy výstupní šablona,
kterou uložím do souboru sablona.xsl
:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> <xsl:output method="html" cdata-section-elements="a"/> <xsl:variable name="lang.webname">Český název webu</xsl:variable> <xsl:template match="/stranka"> <xsl:text disable-output-escaping="yes"><!DOCTYPE html></xsl:text> <html lang="{$lang}"> <head> <xsl:apply-templates select="title"/> <link rel="StyleSheet" href="/style.css" type="text/css" /> </head> <body> <h1><xsl:value-of select="$lang.webname"/></h1> <p><xsl:value-of select="$lang.text"/></p> </body> </html> </xsl:template> </xsl:stylesheet>
Je vidět, že zde používáme proměnné $lang
,
$lang.webname
a $lang.text
. Tyto texty budeme chtít
napsat v požadovaném jazyce.
Překlady
Vytvořím tedy další soubory.
Prvně pro český jazyk lang-cs.xsl
:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> <xsl:import href="sablona.xsl"/> <xsl:output method="html" encoding="utf-8" indent="yes"/> <xsl:variable name="lang">cs</xsl:variable> <xsl:variable name="lang.webname">Český název webu</xsl:variable> <xsl:variable name="lang.text">Český pevný text</xsl:variable> </xsl:stylesheet>
A druhý pro anglický jazyk lang-en.xsl
:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'> <xsl:import href="sablona.xsl"/> <xsl:output method="html" encoding="utf-8" indent="yes"/> <xsl:variable name="lang">en</xsl:variable> <xsl:variable name="lang.webname">English webname</xsl:variable> <xsl:variable name="lang.text">English fixed text</xsl:variable> </xsl:stylesheet>
Pro každý jazyk si napíšeme další slovník s uvedenou strukturou.
Výstupní šablona stále zůstává jen jedna. Všimněme si, že jsem v
původní šabloně definoval hodnotu proměnné $lang.webname
.
Pokud bychom ji zapomněli definovat ve slovníku, bude použita jako defaultní
hodnota.
A jak dál? Už skoro nic. Jen je potřebné zavolat ten správný slovník, viz předchozí lekce:
$sablona = new DOMDocument(); $sablona->load('lang-cs.xsl'); $xsl = new XSLTProcessor(); $xsl->importStyleSheet($sablona); $dokument = new DOMDocument(); $dokument->load('sablona.xsl'); echo($xsl->transformToXML($dokument));
Výsledek:
Toto řešení má jednu nevýhodu:
- Pro každou šablonu je nutná sada jazykových šablon. Ovšem většinou si vystačíme s jedinou šablonou na celý portál a proto je tato nevýhoda nepodstatná.
A rychlost? Zpracování šablony se slovníkem, který měl 1000 slov trvalo
na mém Celeronu cca 100 ms
. Většinou si však vystačíme s
desetinovým i kratším, proto i výstupní časy budou kratší než
10 ms
. Databázi by to trvalo déle.
K čemu se to hodí? Hlavně k lokalizaci menu, hlavního nadpisu, patičky, copyrightu a dalších pevných textů, které se generují na většině podstránek. Nehodí se na dynamická menu, tedy menu rozšiřovaná do databáze. Takové menu je lepší řešit přímo v databázi.
Prezentace stromové struktury z databáze
Nedávno jsem se v diskuzním fóru zmínil o tom, že jsem vyřešil prezentace stromové struktury z databáze. Nelze to dělat přímo v databázi, protože relační databáze na takový typ dat nejsou stavěny. Je však možné zkombinovat to nejlepší z databáze i PHP.
Nejprve si založíme databázi a naplníme ji nějakými daty:
> sqlite3 tree.sqlite BEGIN TRANSACTION; CREATE TABLE strom ( id integer primary key autoincrement, gid int, pid int, nazev text ); INSERT INTO "strom" VALUES (1, 1, NULL, 'první vlákno'); INSERT INTO "strom" VALUES (2, 1, NULL, 'první vlákno 2'); INSERT INTO "strom" VALUES (3, 1, 1, 'první vlákno 3'); INSERT INTO "strom" VALUES (4, 2, NULL, 'druhé vlákno 1'); INSERT INTO "strom" VALUES (5, 2, NULL, 'druhé vlákno 2'); INSERT INTO "strom" VALUES (6, 2, 4, 'druhé vlákno 13'); INSERT INTO "strom" VALUES (7, 2, 4, 'druhé vlákno 14'); INSERT INTO "strom" VALUES (8, 2, 1, 'druhé vlákno 15'); INSERT INTO "strom" VALUES (9, 2, 7, 'druhé vlákno 141'); INSERT INTO "strom" VALUES (10, 2, 7, 'druhé vlákno 142'); INSERT INTO "strom" VALUES (11, 2, 9, 'Příšerně žluťoučký kůň úpěl ďábelské ódy'); INSERT INTO "strom" VALUES (12, 2, 5, 'Přidaný text'); DELETE FROM sqlite_sequence; INSERT INTO "sqlite_sequence" VALUES ('strom', 12); COMMIT;
Význam sloupců:
id
- jednoznačná identifikace záznamugid
- identifikace stromu. V jedné tabulce může být víc stromůpid
- označení rodiče aktuálního záznamunazev
- jakýkoli text
Jako primární klíč ponechám id
, pro větší fórum je
vhodné udělat další index podle gid
.
Data už máme, zbývá nám pouze jejich výpis:
$databaze = new PDO('sqlite:tree.sqlite'); $dotaz = $databaze->prepare('SELECT id, pid, nazev FROM strom WHERE gid=? ORDER BY id;'); $dotaz->execute(array(2)); $xml = new DOMdocument(); $elementy = array(); $elementy[0] = $xml->appendChild(new DOMElement('forum')); while ($radek = $dotaz->fetch(PDO::FETCH_ASSOC)) { $id = $radek['id']; $pid = $radek['pid'] ?? 0; $pid = isset($elementy[$pid]) ? $pid : 0; $elementy[$id] = $elementy[$pid]->appendChild(new DOMElement('item', $radek['nazev'])); } $xsl = new DOMdocument(); $xsl->load('strom.xsl'); $xslt = new XSLTProcessor(); $xslt->importStylesheet($xsl); echo($xslt->transformToXML($xml));
Jak je vidět, v průběhu načítání dat z něj vytváříme stromovou strukturu v paměti. Tuto strukturu už přímo předáme šablonovacímu systému.
Výstupní šablona strom.xsl
:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="UTF-8"/> <xsl:template match="/"> <xsl:text disable-output-escaping="yes"><!DOCTYPE html></xsl:text> <html> <xsl:apply-templates/> </html> </xsl:template> <xsl:template match="/forum"> <head> <title>Diskuzní fórum</title> <link rel="stylesheet" type="text/css" href="style.css"/> </head> <body> <xsl:apply-templates/> </body> </xsl:template> <xsl:template match="item"> <div class="vetvicka"> <xsl:apply-templates/> </div> </xsl:template> </xsl:stylesheet>
A nakonec ještě odkazovaný kaskádový styl style.css
. Ten
pro náš účel nemusí být vůbec dlouhý:
.vetvicka { margin-left: 4%; }
A to je vše:
Aby z toho vzniklo opravdové diskuzní fórum, musel bych přidat vstupní formulář, jeho zpracování a uložení dat do databáze. K tomu by se hodila nějaká antispamová ochrana a administrační rozhraní pro moderátora. Pro náročnější bychom přidali ještě registraci uživatelů, přístupová práva... Chybí toho ještě hodně.
Uvedený příklad vůbec neřeší běhové chyby ani formátování příspěvku. Je to jen ukázka jednoduché prezentace stromového diskuzního fóra.
V další lekci, Práce s dokumenty Excel v PHP - Úvod a první skripty, se začneme věnovat knihovně PhpSpreadsheet pro
práci s tabulkovými dokumenty a vytvoříme první .xlsx
soubor.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 2x (5.28 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP