Java na web XIII. - Internacionalizace

Č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.

Internacionalizace (i18n)

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

Překlad webové aplikace

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).

Ukládání řetězců

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é.

Import knihoven

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" %>

Zjištění jazyka

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.

Nahrání řetězců

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" />

Vkládání řetězců

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" />

Formátování dat a čísel

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í.

Úprava aplikace

Nyní už k naší aplikaci.

Úložiště

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.

Zjištění jazyka, nahrání a vkládání řetězců

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".

Závěr

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

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=1991