Co všechno vylepšíme
Na konci minulého dílu jsme si řekli, že naše fotoalbum je příliš jednoduché, a tudíž by nebylo od věci jej vylepšit. Protože naše fotky svou kvalitou dozajista přesahují hranice naší republiky, bylo by potřeba zpřístupnit album zahraničním zájemcům. Pro začátek by snad stačilo, kdyby album bylo dostupné také v angličtině a v němčině.
Abychom měli k dispozici i aplikaci z původního dílu, vytvoříme aplikaci novou, řekněme s názvem „album2“. Je asi zbytečné kopírovat soubory s obrázky do nové aplikace. Fotografie jsou konec konců jazykově nezávislé. Ukážeme si zde, jak aplikace „propojit“. Přesněji řečeno, jak Cocoonu říci, aby obrázky i jejich náhledy pro aplikaci „album2“ vzal z aplikace „album“.
Cílový jazyk budeme zadávat jako parametr lang
v URL. Možné hodnoty budou „en“ pro album v angličtině a „de“ pro album v němčině. Pokud bude mít parametr lang
jinou hodnotu nebo pokud bude chybět, album se zobrazí v češtině. URL pro album v různých jazycích tedy budou:
http://localhost:8888/album2/seznam.html http://localhost:8888/album2/seznam.html?lang=en http://localhost:8888/album2/seznam.html?lang=de
Abychom vizuálně odlišili naše upravené album od minulého, změníme i kaskádový styl, aby album mělo světlý text na tmavém pozadí. Nastává čas udělat potřebné změny. Celou aplikaci najdete v souboru cocoon03.zip.
Adresářová struktura
Adresářová struktura bude podobná jako v aplikaci „album“ z minulého článku. Sama aplikace bude sídlit v adresáři album2
, který je na stejné úrovni jako adresář album
z minulého dílu. Nebudeme potřebovat podadresář fotky
(obrázky vezmeme z minulé aplikace), naopak v adresáři texty
budou ještě podadresáře cesky
, kam přesuneme definici alba a popisy fotografií v češtině, pro další jazyky pak budeme mít podadresáře anglicky
a nemecky
. Protože do XML dat popisujících album jsou vkládány (transformátor CInclude) data jednotlivých fotografií, je potřeba při přesunu souboru album.xml
do adresáře cesky
upravit i cesty vkládaných souborů. Pro další jazyky musíme vytvořit příslušné soubory s popisem alba ( album.xml
) a popisy jednotlivých fotografií ( hg*.xml
), samozřejmě vždy v příslušném jazyce.
Krademe obrázky jiné aplikaci
V případě fotoalba většího rozsahu s více aplikacemi by asi nebylo vhodné mít kopie JPEG souborů v každé aplikaci. Větší soubory by zabíraly dost místa na disku, a pokud by byl jejich počet nezanedbatelný, narostla by (zbytečně) práce s jejich údržbou. Asi vás nepřekvapí, že Cocoon nabízí několik způsobů, jak využít zdroje jiné aplikace. My se podíváme na použití speciálního URL s názvem protokolu cocoon
. V mapě tedy změníme definice, které říkají, jak má Cocoon dodávat soubory *.jpg
a nahled/*.jpg
, na:
...
<map:match pattern="*.jpg">
<map:read type="image"
src="cocoon://album/{1}.jpg"
mime-type="image/jpeg"/>
</map:match>
<map:match pattern="nahled/*.jpg">
<map:read type="image"
src="cocoon://album/nahled/{1}.jpg"
mime-type="image/jpeg"/>
</map:match>
...
Všimněte si, že se v těchto speciálních URL používá virtuální jmenný prostor klienta. Je to logické, protože využíváme obrázky jiné aplikace a do jejího mapování klientského a serverového jmenného prostoru nevidíme. Nemusíme zde ani zadávat zmenšení původních obrázků na náhledy. Aplikace „album“ nám dodá náhledy již zmenšené podle konfigurace ve své mapě. Zkuste se zamyslet, jak by vypadala tato mapa, kdybychom chtěli například náhledy o rozměrech 70×70 pixelů. Dále se můžete zamyslet, zda bychom mohli využít z minulé aplikace soubor s kaskádovým stylem a soubor s XSL dokumentem. Řešení najdete na konci článku.
Na konci této „zlodějské“ kapitoly bych ještě rád připomněl, že hodnotou atributu src
nemusí být jen lokální soubor nebo zdroj z jiné aplikace, ale může tam být libovolné URL. Můžete tedy bez problémů využít zdroj z jiného webu. Pozor však na zachování autorských práv i normální slušnosti. Pokud chcete používat lokální soubory určené absolutní cestou, podívejte se do dokumentace na správný formát URL.
Dělíme rouru podle jazyků
Nyní potřebujeme nějak definovat, že pro angličtinu se mají použít soubory z adresáře texty/anglicky
, pro němčinu z adresáře texty/nemecky
, v ostatních případech pak použít soubory z adresáře texty/cesky
. Potřebujeme v mapě konstrukci typu „if-then-else“ nebo „select-case“. To zajišťují komponenty typu selektor (selector). Opět jich máme několik připraveno k přímému použití. V našem případě využijeme selektor závisející na hodnotě parametru HTTP požadavku. V mapě to bude vypadat:
...
<map:match pattern="seznam.html">
<map:select type="request-parameter">
<map:parameter name="parameter-name"
value="lang"/>
<map:when test="en">
<map:generate type="file"
src="texty/anglicky/album.xml"/>
</map:when>
<map:when test="de">
<map:generate type="file"
src="texty/nemecky/album.xml"/>
</map:when>
<map:otherwise>
<map:generate type="file"
src="texty/cesky/album.xml"/>
</map:otherwise>
</map:select>
<map:transform type="cinclude"/>
<map:transform src="xsl/seznam.xsl"/>
<map:serialize type="xhtml"/>
</map:match>
...
Původní řádek s generátorem byl nahrazen konstrukcí, která vybírá generátor podle hodnoty parametru lang
.
Selektory
Cocoon obsahuje několik selektorů. Implicitní je selektor, který umí otestovat typ prohlížeče. Můžete tak použít například jinou XSL transformaci pro zobrazení stránky v Netscapu/Mozille a jinou pro Internet Explorer. Kromě selektoru testujícího hodnotu parametru HTTP požadavku existují také selektory na hodnotu pole hlavičky HTTP požadavku, atributu uživatelské relace (session), cookie a další.
Moduly
V předchozím textu jsem zanedbal, že původní aplikace se dala spustit i s prázdným zdrojem (URL bylo: http://localhost:8888/album/
). Mapa pak přesměrovávala požadavek na (virtuální) soubor seznam.html
. Tato definice v mapě ovšem nezajistí přenos parametru lang
na přesměrované URL. Zde nám mohou pomoci moduly. Moduly nám přinášejí do mapy, řekněme, jakési primitivní volání funkce či přístup k proměnným. Zápis používá složené závorky, takže například zápis {request-param:lang}
v mapě se nahradí hodnotou parametru lang
z HTTP požadavku, zápis {date:format}
se nahradí řetězcem obsahujícím aktuální datum a čas.
Abychom zajistili přenos parametru lang
ve výše uvedeném případě, musíme map upravit takto:
...
<map:match pattern="">
<map:redirect-to
uri="seznam.html?lang={request-param:lang}"/>
</map:match>
...
Jedinou nevýhodou toho přístupu je, že pokud parametr lang
není vůbec použit, přesměrované URL končí ...seznam.html?lang=
, což nevypadá nijak zvlášť esteticky (ani inteligentně), nicméně funkci aplikace to nevadí.
Moduly a některé jejich parametry jsou definovány pro celý Cocoon (tj. staticky) v konfiguračním souboru cocoon.xconf
. Najdete jej v adresáři build/webapp/WEB-INF
. Zde je například definován formát pro zobrazení data a času modulu „date“. V základní instalaci Cocoonu najdete například modul pro generování náhodného čísla nebo modul pro výpočet hashe (message digest), což se může hodit např. pro ověřování hesel.
Závěrečné poznámky
Výše uvedený přístup k internacionalizaci rozhodně není jediný, který lze v Cocoonu použít. Cocoon nabízí i transformátor pro internacionalizaci aplikace, nicméně v našem jednoduchém fotoalbu by bylo jeho použití zbytečně komplikované.
Výše uvedenou aplikaci by šlo sestrojit i bez selektorů. Místo parametru lang
bychom museli určovat jazyk virtuálním adresářem, který by se mapoval do skutečného stejnojmenného adresáře. V tomto případě by se zřejmě dalo výhodně využít toho, že elementy map:match
se dají vnořovat. Selektory by nám pak mohly zbýt na jiné účely.
Naše fotoalbum je sice nyní o něco dokonalejší, ale rozhodně ne dokonalé. Příště ještě budeme pokračovat ve vylepšování.
Řešení
1. Změna velikosti náhledů:
...
<map:match pattern="nahled/*.jpg">
<map:read type="image"
src="cocoon://album/{1}.jpg"
mime-type="image/jpeg">
<map:parameter name="height" value="70"/>
<map:parameter name="width" value="70"/>
</map:read>
</map:match>
...
2. Soubor s kaskádovým stylem lze využít, protože v mapě aplikace „album“ je uvedeno, jak se vyřizuje požadavek na soubor s příponou .css
. Oproti tomu soubor s XSL dokumentem je v minulé aplikaci použit jen jako parametr XSL transformátoru. Cocoon neví, co má dělat s požadavkem na soubor s příponou .xsl
. V případě potřeby by to ovšem šlo do mapy dodefinovat.