Český internet je oproti tomu mezinárodnímu pouhým rybníčkem. To (a nejen to) může být důvodem k internacionalizaci aplikací. V dnešním díle se budeme věnovat překladu a formátování, využívat k tomu budeme převážně knihovnu JSON Formatting.
3.9.2013 00:00 | Petr Horáček | přečteno 9365×
V minulých dvou dílech jsme se věnovali nástrojům, které slouží především vývojářům, dnes se již ale vrátíme k tvorbě uživatelského prostředí. Povíme si něco o internacionalizace obecně, knihovně JSTL Formatting a nakonec si předvedeme praktickou ukázku na naší aplikaci.
Pod pojmem internacionalizace (zmezinárodnění) se skrývá hned několik postupů. Především jde o překlad aplikace do více jazyků, mezi kterými lze libovolně přecházet (není tedy vytvořena pouze přeložená verze aplikace, ale je k dispozici více jazykových voleb). Jednou z vlastností internacionalizované aplikace by mělo být i přizpůsobení gramatiky a typografie (např.: úprava plurálů a zápis datových údajů).
Více si můžete o překladu softwaru přečíst zde: http://cs.wikipedia.org/wiki/Internacionalizace_a_lokalizace
Začneme zmezinárodněním uživatelského prostředí čistě pomocí překladu. Pro tento úkon bude stačit vytvoření souborů s řetězci a přidání nekolika řádek kódu do viewů (připadně přidat novou adresu do controlleru).
Pro účely internacionalizace budeme využívat formátovací tagy z knihovny JSTL (více zde: http://www.tutorialspoint.com/jsp/jsp_standard_tag_library.htm).
Jako úložiště různých jazykových verzí budou sloužit soubory s příponou propreties obsahující jednotlivé řetězce i jejich klíče (ve kterých lze uplatňovat princip tečkové konvence). Pro tyto soubory je vhodné v aplikaci vyhradit samostatný balíček.
Základní jazyk (nejčastěji angličtina, je zvolen pokud není možno uplatnit uživatelův jazyk) je umístěn v jazykově neoznačeném souboru (např. text.propreties) a může vypadat třeba takto:
greeting.morning = Good morning greeting.afternoon = Good afternoon greeting.evening = Good evening
Další jazykové mutace jsou umístěny v souborech označených pomocí ISO jazykových kódů. Soubor s českými řetězci (např. text_cs.propreties) by mohl vypadat třeba takto:
greeting.morning = Dobré ráno greeting.afternoon = Dobré odpoledne greeting.evening = Dobrý večer
Poznámka: NetBeans obsahuje nástroje usnadňující překlad, hodí se ale pouze do klasických aplikací (s řetězci umístěnými v kódu Javy), pro překlad webové aplikace jsou nepoužitelné.
V každém viewu bude potřeba získat proměnnou jazyka a nahrát řetězce z jejich úložiště. Pro tyto operace budeme potřebovat knihovny Formatting a Core, vložte tedy ne začátek všech viewů tento kód:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
V dalším kroku bude nutné zjistit uživatelem požadovaný jazyk a uložit jej jako proměnnou do současné session. Pro nastavení jazyka budeme využívat formulář s metodou GET, všechen přiřazovací kód bude umístěn ve viewu. Pod importy na začátku viewu tedy vložte toto:
<c:set var="language" value="${not empty param.language ? param.language : not empty language ? language : pageContext.request.locale}" scope="session" />
Do proměnné language (sdílené pro celou session) se pokusíme dosadit jazyk získaný z metody GET, pokud parametr nenalezneme, pokusíme se nahrát hodnotu již v session uloženou, pokud ani tu nenalezneme, zapíšeme jazyk získaný z HTTP hlavičky requestu.
Samotný formulář určený pro změnu jazyka by mohl vypadat třeba takto:
<form> <select id="language" name="language" onchange="submit()"> <option value="en" ${language == 'en' ? 'selected' : ''}> English </option> <option value="nl" ${language == 'cs' ? 'selected' : ''}> Česky </option> </select> </form>
Pokud si chcete v aplikaci udržet pěkné URL, můžete namísto metody GET využít POST v kombinaci se servletem, který zajistí úpravu session.
Po zjištění požadovaného jazyka stačí už jen určit jazyk a nahrát řetězce z určeného úložiště.
<fmt:setLocale value="${language}" /> <fmt:setBundle basename="cesta.k.i18n.retezcum" />
Nakonec nezbývá než uložené řetězce vložit do textu, to lze provést pomocí následujícího tagu:
<fmt:message key="klic.retezce" />
Knihovna JSTL Formatting také nabízí několik nástrojů sloužících pro výpis čísel či dat v daném formátu:
<fmt:formatNumber> <!-- Vypíše číselnou hodnotu ve specifikovaném formátu --> <fmt:parseNumber> <!-- Převede předaný řetězec na číslo --> <fmt:formatDate> <!-- Vypíše datum a/nebo čas ve specifikovaném formátu --> <fmt:parseDate> <!-- Převede řetězec na datový údaj --> <fmt:timeZone> <!-- Upraví výpis data a/nebo času v závislosti na časové zóně --> <fmt:setTimeZone> <!-- Nastaví požadovanou časovou zónu -->
Zápis českého data a času by mohl vypadat takto:
<fmt:formatDate pattern="h.mm d. M. yyyy" value="${now}" />
Doporučuji alespoň letmé prohlédnutí dokumentace knihovny, každý tag má celou řadu atributů a přednastavení.
Nyní už k naší aplikaci.
Začněme s úložištěm řetězců. Vytvořte tedy v naší aplikaci balíček internacionalizace a přidejte do něj soubor text.propreties:
base.header = Notebook base.title = Notebook login.username = Username login.password = Password login.submit = Login login.invalid = Username or password is incorrect. notes.header = Header notes.edit = Edit notes.delete = Delete notes.addnew = Add notes.warning.fillboth = You must fill in both fields. notes.warning.none = There are no notes yet.
a text_cs.propreties:
base.header = Zápisník base.title = Zápisník login.username = Přihlašovací jméno login.password = Heslo login.submit = Přihlásit login.invalid = Zadané údaje nejsou platné. notes.header = Nadpis notes.edit = Upravit notes.delete = Smazat notes.addnew = Přidat notes.warning.fillboth = Musíte vyplnit obě pole. notes.warning.none = Dosud nebyl přidán žádný zápisek.
Přidejte do všech šablon včetně tagu Base tento kód (pod import knihovny core):
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <c:set var="language" value="${not empty param.language ? param.language : not empty language ? language : pageContext.request.locale}" scope="session" /> <fmt:setLocale value="${language}" /> <fmt:setBundle basename="internacionalizace.text" />
Importujeme zde knihovnu formatting, nastavíme proměnnou language se zvoleným jazykem, ten následovně přiřadíme knihovně formatting a nakonec načteme úložiště řetězců.
Následovně nahraďte v těchto souborech všechny vypisované textové řetězce (i popisky tlačítek) kódem pro výpis uloženého řetězce, například nadpis v tagu Base se změní na:
<h1><fmt:message key="base.header" /></h1>
Problém nastane u předávání titulku v attributu titulek tagu Base, v tomto případě bude nutné předem si připravit proměnnou, kterou poté přiřadíme pomocí EL jako titulek. Upravte tedy ve všech viewech otevření tagu Base:
<fmt:message key="base.title" var="titulek" /> <m:Base titulek='${titulek}'>
Pro přecházení mezi jazyky využijeme formulář s prvkem select. Aby na stránkách využívajících metodu GET nedošlo k potížím (např.: Změna jazyka by přepsala attribut id v url a následovně by došlo k chybě.) přidáme do formuláře navíc cyklus předávající ve skrytých vstupech všechny již získané GET argumenty, krom nastavení jazyka. Vložte v tagu Base pod <h1>
nadpis toto:
<form action="" style="display: inline"> <c:forEach items="${param}" var="parameter"> <c:if test="${parameter.key != 'language'}"> <input type="hidden" name="${parameter.key}" value="${parameter.value}" /> </c:if> </c:forEach> <select name="language" onchange="submit()"> <option value="en" ${language == 'en' ? 'selected' : ''}> English </option> <option value="cs" ${language == 'cs' ? 'selected' : ''}> Česky </option> </select> </form>
Díky JavaScriptovému příkazu onchange="submit()"
se formulář po změně hodnoty automaticky odešle. Pomocí EL nastavíme v selectu aktuální jazyk jako vybraný.
Poznámka: Pokud chcete mít volbu jazyka a nadpis na jednom řádku, přidejte oběma prvkům attribut style="display: inline".
A to je vše, nyní je naše aplikace kompletní a plně připravená na nasazení do provozu. V příštím díle si popíšeme umístění aplikace na server a možnosti hostingu.
Zdrojové kódy aplikace naleznete na GitHubu: https://github.com/PetrHoracek/JavaNaWeb