09 maja 2008

Umiędzynarodowienie w Apache Wicket

Tempo rozwoju Apache Wicket może zdumiewać, gdyż jeszcze nie tak dawno podnosiłem wersję Wicket mojej testowej aplikacji do 1.3.3, a już mamy 1.4-m1. Z pomocą Apache Maven 2 temat sprowadził się do uaktualnienia pom.xml, w którym podniosłem wersję Wicketa oraz Spring Framework (do wersji 2.5.4). Jedną z głównych zmian w Wicketa 1.4 jest skorzystanie z mechanizmu wzorców w Javie (Java Generics), tak że musiałem zmienić sygnaturę metody WicketDemoApplication.getHomePage(), która zawęziła typ zwracanych obiektów do Class<? extends org.apache.wicket.Page>.
 c:\projs\sandbox\wicket-demo\src\main\java\pl\jaceklaskowski\wicket\WicketDemoApplication.java:[66,20] getHomePage() 
in pl.jaceklaskowski.wicket.WicketDemoApplication cannot override getHomePage() in org.apache.wicket.Application;
attempting to use incompatible return type
found : java.lang.Class<?>
required: java.lang.Class<? extends org.apache.wicket.Page>
Do mojej prezentacji Wicketa na kolejnym,wtorkowym spotkaniu Warszawa JUG pozostało już niewiele dni, więc kończąc lekturę książki Pro Wicket (Apress) trafiłem na rozdział przedstawiający mechanizm i18n - umiędzynarodowienia, który polega na przeniesieniu napisów do plików properties z przypisaniem im identyfikatorów wraz z ich wykorzystaniem w dedykowanych znacznikach <wicket:message>. Identyfikatory są niezmienne i zapisane są w ciele stron aplikacji, podczas gdy ich wartości zależne od języka są zapisane w plikach properties. Wskazanie miejsca umiędzynarodowienia polega na skorzystaniu ze znacznika <wicket:message key="..." />, który odszuka właściwego napisu dla podanego klucza (identyfikatora) wskazanego przez atrybut key. Pozostaje przedstawić, gdzie pliki properties powinny się znajdować. Jest kilka wariantów umieszczenia pliku properties, co daje nam różne poziomy granulacji komunikatów dla pojedyńczego formularza, pojedyńczej strony, dla całej grupy stron czy dla całej aplikacji. Nie wnikając w niepotrzebne szczegóły, umieszczę napisy w pliku odpowiadającym nazwie strony. Cała radość w "czystość" plików HTML została nieznacznie zaburzona wprowadzeniem specyficznych dla Wicketa znaczników <wicket:message>.

Oto strona DaneOsobowe.html ze znacznikami <wicket:message/>:
 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:wicket="http://wicket.apache.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wicket Demo App</title>
</head>
<body>
<strong>Wicket Demo App</strong>
<span wicket:id="komunikaty"></span>
<form wicket:id="daneOsobowe" action="">
<table>
<tr>
<td><wicket:message key="imie" />:</td>
<td colspan="2"><input type="text" wicket:id="imie" /></td>
</tr>
<tr>
<td><wicket:message key="nazwisko" />:</td>
<td colspan="2"><input type="text" wicket:id="nazwisko" /></td>
</tr>
<tr>
<td><wicket:message key="login" />:</td>
<td colspan="2"><input type="text" wicket:id="login" /></td>
</tr>
<tr>
<td><wicket:message key="miejscowosc" />:</td>
<td><select wicket:id="miejscowosc">
<option>Cokolwiek</option>
</select></td>
<td><input type="submit" value="Zatwierdź" /></td>
</tr>
</table>
</form>
</body>
</html>
i odpowiadający jej plik DaneOsobowe.properties z wartościami kluczy:
 imie=Imi\u0119
nazwisko=Nazwisko
login=Login
miejscowosc=Miejscowo\u015b\u0107
W zasadzie to plik DaneOsobowe.properties powinienem był nazwać DaneOsobowe_pl.properties, aby wskazać jaki język plik zawiera, ale dla prostoty przykłady postanowiłem zaniechać tego.

I to tyle. Teraz wystarczy przenieść wszystkie napisy do odpowiednich plików properties i stworzyć wiele ich wersji językowych dla każdego wspieranego przez aplikację języka. I to bez modyfikacji kodu źródłowego! Wprowadzenie obsługi wersji językowej dla kolejnego języka sprowadza się teraz do dodania kolejnego pliku properties.

Pytanie konkursowe: Jaka jest geneza akronimu i18n, który tłumaczy się jako umiędzynarodowienie? Nagród nie przewiduje się.

3 komentarze:

  1. "Jaka jest geneza akronimu i18n, który tłumaczy się jako umiędzynarodowienie?"

    Umiędzynarodowienie, czyli po angielsku "internationalization". Wyraz ten liczy sobie 20 liter. Pomiędzy jego pierwszą i ostatnią literą jest więc dokładnie 18 liter - stąd akronim.

    Kontynuując konkurs, czy ktoś może rozwinąć akronim p13n? :)

    OdpowiedzUsuń
  2. Czy tylko mi się wydaje, że "umiędzynarodowienie" brzmi paskudnie. Aż ciężko to napisać bez zastanawiania się. "Internacjonalizacja" jakoś brzmi dla mnie normalniej.

    OdpowiedzUsuń
  3. Stare dobre Javowe ProprtyResourceBundle :). Odkrywczy IMO w kontekście Java+Web+i18n mechanizm lokalizacji aplikacji oferuje Google Web Toolkit. W przypadku stałych (constants), używane są pliki properties z odpowiednimi "narodowymi" sufixami, jak w klasycznym ResourceBundle. Różnica polega natomiast na sposobie dostępu do tych zasobów - tworzy się specjalny interface, gdzie nazwy metod odpowiadają kluczom w pliku properties. Używanie takiego interface polega na wywoływaniu "statycznie typowanych" metod (które mogą zwracać nie tylko Stringi, ale także inne typy podstawowe), nie zaś na powoływaniu się na "nietypowany" klucz prowadzący do lokalizowanego zasobu. W przypadku klasycznej aplikacji Javowej implementacja takiego interface mogłaby zostać wygenerowana w locie z pomocą reflection i dynamicznego proxy. Twórcy GWT idą jednak jeszcze dalej - oferują mechanizm tzw. "deffered binding", czyli w skrócie "po co robić w runtime to, co można uzyskać w trakcie kompilacji".

    OdpowiedzUsuń