r13-05.doc

(315 KB) Pobierz
Szablon dla tlumaczy

W niniejszym rozdziale:

·         Języki zachodnioeuropejskie

·         Hołdowanie lokalnym zwyczajom

·         Języki spoza Europy Zachodniej

·         Większa ilość języków

·         Dynamiczna negocjacja języka

·         Formularze HTML

Rozdział 13.

Internacjonalizacja

Pomimo swojej nazwy, sieć WWW musi przebyć jeszcze długą drogę, zanim będzie mogła być uważana za całkowicie światową. Oczywiście, kable doprowadzają zawartość sieci do prawie wszystkich krajów świata. Jednak, aby zawartość sieci była naprawdę międzynarodowa

Może nie pisz tyle razy pod rząd:światowe,swiatowa,światitd

, musi ona być możliwa do odczytania przez każdą osobę ją odbierającą — własność rzadko dziś spotykana, gdy większość stron WWW posiada jedynie wersję angielską.

Sytuacja zaczyna się jednak zmieniać. Wiele największych witryn WWW posiada obszary zaprojektowane dla języków innych niż angielski. Na przykład, strona główna firmy Netscape jest dostępna w języku angielskim pod adresem http://home.netscape.com/index.html, natomiast w wersji francuskojęzycznej pod adresem http://home.netscape.com/fr/index.html, a dla osób znających inne języki pod wieloma innymi URL-ami.

Serwery WWW mogą również obsługiwać rozwiązanie pojedyncze, w którym pojedynczy URL może zostać wykorzystany do przeglądania tej samej zawartości w różnych językach, których wybór zależny jest od preferencji klienta. To, który język zostanie wyświetlony jest uzależnione od konfiguracji przeglądarki[1]. Chociaż technika ta daje wrażenie, że następuje dynamiczne tłumaczenie, tak naprawdę serwer dysponuje po prostu kilkoma specjalnie nazwanymi wersjami statycznego dokumentu.

Podczas gdy te techniki działają dobrze w przypadku statycznych dokumentów, nie rozwiązują one jednak problemu internacjonalizacji i lokalizacji zawartości dynamicznej. Jest to temat niniejszego rozdziału. Opisane zostaną tu sposoby wykorzystania możliwości internacjonalizacji dodanych w JDK1.1. przez serwlety w celu prawdziwego rozszerzenia sieci WWW na cały świat.

Po pierwsze należy omówić terminologię. Internacjonalizacja (Internationalization — słowo często miłosiernie skracane do I18N, ponieważ rozpoczyna się od I, kończy na N, a pomiędzy nimi jest 18 liter) jest zadaniem uczynienia programu na tyle elastycznym, aby można go było uruchomić w każdym miejscu. Lokalizacja (Localization, często skracana do L10N) to proces ustawiania programu tak, aby działał w konkretnym miejscu. Większa część tego rozdziału opisuje internacjonalizację serwletów. Lokalizacja zostanie opisana jedynie na przykładach dat, godzin, liczb i innych obiektów, które domyślnie obsługuje Java.

Języki zachodnioeuropejskie

Na początku zostanie opisany sposób wyświetlania przez serwlet strony utworzonej w języku zachodnioeuropejskim, takim jak angielski, hiszpański, niemiecki, francuski, włoski, holenderski, norweski, fiński lub szwedzki. W przykładzie wyświetlony zostanie napis „Witaj świecie!” po hiszpańsku, jak przedstawiono to na rysunku 13.1.

Rysunek 13.1.

En Español — ¡Hola Mundo!

Proszę zauważyć zastosowanie specjalnych znaków ñ i ¡. Znaki takie jak te, chociaż praktycznie nieobecne w języku angielskim, są przypisane do języków zachodnioeuropejskich. Serwlety posiadają dwa sposoby generowania takich znaków — poprzez encje znakowe HTML i kody ucieczkowe Unicode.

Encje znakowe HTML

HTML 2.0 wprowadził możliwość wyświetlania specyficznych sekwencji znaków na stronie HTML jako znaku pojedynczego. Sekwencje te, nazywane encjami znakowymi, rozpoczynają się znakiem &, a kończą średnikiem (;). Encje znakowe mogą mieć nazwy, jak i wartości numeryczne. Na przykład, nazwana encja ñ przedstawia ñ, a ¡ przedstawia ¡. Kompletna lista znaków specjalnych i ich nazw jest podana w dodatku A, „Encje znakowe”. Przykład 13.1 przedstawia serwlet wykorzystujący nazwane encje w celu wyświetlenia „Witaj świecie” po hiszpańsku.

Przykład 13.1.

Powitanie dla posługujących się językiem hiszpańskim, przy pomocy nazwanych encji znakowych

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class WitajHiszpania extends HttpServlet {

 

  public void doGet(HttpServletRequest zad, HttpServletResponse odp)

                               throws ServletException, IOException {

    odp.setContentType("text/html");

    PrintWriter wyj = odp.getWriter();

    odp.setHeader("Content-Language", "es");

 

    wyj.println("<HTML><HEAD><TITLE>En Espa&ntilde;ol</TITLE></HEAD>");

    wyj.println("<BODY>");

    wyj.println("<H3>En Espa&ntilde;ol:</H3>");

    wyj.println("&iexcl;Hola Mundo!");

    wyj.println("</BODY<>/HTML>");

  }

}

Można zauważyć, że oprócz wykorzystywania encji znakowych powyższy serwlet nadaje swojemu nagłówkowi Content-Language wartość es. Nagłówek Content-Language jest wykorzystywany do określania języka następujących po nim encji. W tym przypadku serwlet wykorzystuje nagłówek do wskazania klientowi, że strona jest napisana w języku hiszpańskim (Español). Większość klientów ignoruje tę informację, lecz do dobrego tonu należy jej wysyłanie. Języki są zawsze przedstawiane przy pomocy dwuliterowych skrótów zapisanych małymi literami. Kompletna lista jest dostępna w standardzie ISO-639 pod adresem http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt.

Encje znakowe mogą być również określane przy pomocy liczb. Na przykład, &#241; przedstawia ñ, a &#161; przedstawia ¡. Liczba odnosi się do dziesiętnej wartości znaku w standardzie ISO-8859-1 (Latin-1), który zostanie opisany w dalszej części niniejszego rozdziału. Kompletna lista wartości numerycznych encji znakowych również znajduje się w dodatku E. Przykład 13-2 przedstawia serwlet WitajHiszpania zmieniony tak, aby wykorzystywał encje numeryczne.

Przykład 13.2.

Powitanie dla posługujących się językiem hiszpańskim, przy pomocy numerycznych encji znakowych

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class WitajHiszpania extends HttpServlet {

 

  public void doGet(HttpServletRequest zad, HttpServletResponse odp)

                               throws ServletException, IOException {

    odp.setContentType("text/html");

    PrintWriter wyj = odp.getWriter();

    odp.setHeader("Content-Language", "es");

 

    wyj.println("<HTML><HEAD><TITLE>En Espa&#241;ol</TITLE></HEAD>");

    wyj.println("<BODY>");

    wyj.println("<H3>En Espa&#241;ol:</H3>");

    wyj.println("&#161;Hola Mundo!");

    wyj.println("</BODY<>/HTML>");

  }

}

Niestety, z wykorzystaniem encji znakowych wiąże się jeden poważny problem — działają one jedynie ze stronami HTML. Jeżeli wynikiem serwletu nie jest kod HTML, strona będzie wyglądać podobnie do przedstawionej na rysunku 13.2. Aby obsługiwać wyniki nie będące HTML, należy wykorzystać kody ucieczkowe Unicode.

Rysunek 13.2.

Nie do końca hiszpański

 

Kody ucieczkowe Unicode

W Javie znaki, łańcuchy i identyfikatory są złożone wewnętrznie z 16-bitowych (2-bajtowych) znaków Unicode 2.0. Unicode został wprowadzony przez Unicode Consortium, które opisuje standard w następujący sposób (proszę zobaczyć http://unicode.org):

Światowy standard znaków Unicode to system kodowania znaków zaprojektowany w celu obsługi wymiany, przetwarzania i wyświetlania tekstów pisanych w różnych językach współczesnych. Dodatkowo, obsługuje on klasyczne i historyczne teksty w wielu językach pisanych.

W swojej aktualnej wersji (2.0) standard Unicode zawiera 38,885 osobno oznaczonych znaków odziedziczonych ze wspieranych skryptów. Znaki te umożliwiają obsługę głównych języków pisanych w Amerykach, Europie, Bliskim Wschodzie, Afryce, Indiach, Azji i rejonie Pacyfiku.

Większa ilość informacji na temat Unicode jest dostępna pod adresem http://www.unicode.org, a także w książce „The Unicode Standard, Version 2.0” (Addison-Wesley). Proszę zauważyć, że pomimo wprowadzenia Unicode 3.0, Java wciąż obsługuje wersję 2.0.

Wykorzystanie przez Javę Unicode jest bardzo ważne dla niniejszego rozdziału, ponieważ oznacza ono, że serwlet może wewnętrznie przedstawiać właściwie każdy znak w powszechnie stosowanym języku pisanym. 16-bitowe znaki Unicode są przedstawiane w 7-bitowym kodzie źródłowym US-ASCII przy pomocy kodów ucieczkowych Unicode o postaci \uxxxx, gdzie xxxx oznacza sekwencję czterech cyfr w formacie szesnastkowym. Kompilator Javy traktuje każda sekwencję ucieczkową jako pojedynczy znak.

Nieprzypadkowo i dla zachowania wygody pierwsze 256 znaków Unicode (\u0000 do \u00ff) są równe z 256 znakami ISO 8859-1 (Latin-1). Tak więc znak ñ może zostać opisany jako \u00f1, a znak ¡ jako \u00a1. Kompletna lista sekwencji ucieczkowych Unicode dla znaków ISO-8859-1 jest również zawarta w dodatku. Przykład 13.2 przedstawia WitajHiszpania przepisany przy pomocy kodów ucieczkowych Unicode.

Przykład 13.2.

Powitanie dla posługujących się językiem hiszpańskim, przy pomocy kodów ucieczkowych Unicode

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class WitajHiszpania extends HttpServlet {

 

  public void doGet(HttpServletRequest zad, HttpServletResponse odp)

                               throws ServletException, IOException {

    odp.setContentType("text/plain");

    PrintWriter wyj = odp.getWriter();

    odp.setHeader("Content-Language", "es");

 

    wyj.println("En Espa\u00f1ol:");

    wyj.println("\u00a1Hola Mundo!");

  }

}

Wynik powyższego serwletu wyświetla się prawidłowo, kiedy wykorzystywany jako część strony HTML lub kiedy wykorzystywany jest do wyświetlania zwykłego tekstu.

Hołdowanie lokalnym zwyczajom

Teraz wiadomo już jak wykorzystywać encje znakowe HTML lub kody ucieczkowe Unicode do wyświetlania znaków w językach zachodnioeuropejskich. Pozostaje pytanie, co powiedzieć przy pomocy tych języków? Generalnie, problem tłumaczenia najlepiej pozostawić odpowiedniemu zespołowi odpowiedzialnemu za lokalizację, Jednak w niektórych przypadkach Java dostarcza pewnej pomocy.

Na przykład, jeżeli oprócz powiedzenia „Witaj świecie” przykładowy serwlet powinien wyświetlać aktualną datę w formacie naturalnie rozumianym przez odbiorcę. To, co mogłoby być skomplikowanym problemem z formatowaniem jest tak naprawdę stosunkowo proste, ponieważ JDK 1.1 posiada wbudowaną obsługę lokalizacji dynamicznych obiektów takich jak daty i godziny.

Sztuczka polega na zastosowaniu egzemplarza java.text.DateFormat odpowiedniego dla docelowego odbiorcy. Obiekt DateFormat może przekonwertować Date do odpowiednio zlokalizowanego obiektu String. Na przykład, znacznik czasu utworzony w języku angielskim jako „February 16, 1998 12:36:18 PM PST” zostanie zapisany po hiszpańsku jako „16 de febrero de 1998 12:36:18 GMT-8:00”.

Obiekt DateFormat jest tworzony przy pomocy metody fabryki, która przyjmuje style formatowania (krótki, średni, długi, pełny) oraz obiektu java.util.Locale, który identyfikuje docelowego odbiorcę (amerykański angielski, podstawowy chiński itp.). Najpopularniejszy konstruktor Locale pobiera dwa parametry — dwuliterowy skrót języka zapisany małymi literami (jak opisano wcześniej) oraz dwuliterowy kod kraju zapisany dużymi literami zdefiniowany przez ISO-3166 (dostępny pod adresem http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html). Pusty łańcuch kodu kraju wskazuje na kraj domyślny dla danego języka.

Przykład 13.4 przedstawia serwlet WitajHiszpania wykorzystujący obiekt DateFormat w celu wyświetlenia aktualnego czasu w formacie naturalnie rozumianym przez odbiorców posługujących się językiem hiszpańskim.

Przykład 13.4.

Powitanie dla posługujących się językiem hiszpańskim, łącznie ze zlokalizowaną datą

import java.io.*;

import java.text.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

public class WitajHiszpania extends HttpServlet {

 

  public void doGet(HttpServletRequest zad, HttpServletResponse odp)

                               throws ServletException, IOException {

    odp.setContentType("text/plain");

    PrintWriter wyj = odp.getWriter();

    odp.setHeader("Content-Language", "es");

 

    Locale lokal = new Locale("es", "");

    DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG,

                                                    DateFormat.LONG,

                                                    lokal);

    fmt.setTimeZone(TimeZone.getDefault());

 

    wyj.println("En Espa\u00f1ol:");

    wyj.println("\u00a1Hola Mundo!");

    wyj.println(fmt.format(new Date()));

  }

}

Powyższy serwlet na początku tworzy obiekt Locale przedstawiający ogólne środowisko jako hiszpańskie. Następnie wykorzystuje ten Locale do utworzenia egzemplarza DateFormat, który formatuje daty w języku hiszpańskim. Następnie ustawia on strefę czasową na strefę domyślną (strefę czasową serwera). Dzieje się tak, ponieważ obiekt DateFormat formatuje swoje czasy w sposób taki, aby pasowały one do strefy czasowej, w której znajduje się domyślny klient, w tym przypadku Hiszpanii. Ponieważ serwlet ten nie może być pewnym, czy podejmuje właściwe decyzje, zamienia on wartość domyślną i ustawia strefę czasową tak, aby pasowała do serwera. Oczywiście lepsze byłoby ustawienie strefy czasowej tak, aby pasowała ona do miejsca, w którym znajduje się klient, ale nie jest to aktualnie możliwe bez dodatkowych informacji dostarczanych przez użytkownika. Ostatecznie, po wypowiedzeniu swojego „Witaj świecie”, serwlet wyświetla prawidłowo sformatowana datę i godzinę. Wynik działania powyższego skryptu jest przedstawiony na rysunku 13.3.

Rysunek 13.3.

Hola Mundo con Tiempo

 

Powyższy przykład stanowi jedynie bardzo krótki podgląd możliwości dynamicznego formatowania zawartości Javy. Osoby zainteresowane bardziej skomplikowanym formatowaniem powinny obejrzeć kilka przydatnych klas znajdujących się w pakiecie java.text. Szczególnie należy zwracać uwagę na te będące rozszerzeniem java.text.Format.

Języki spoza Europy Zachodniej

Teraz omówione zostanie tworzenie przez serwlet strony w języku spoza Europy Zachodniej, takim jak rosyjski, czeski, litewski czy japoński. Aby pojąć sposoby pracy związane z tymi językami, należy najpierw poznać pewne mechanizmy zachodzące poza ekranem w poprzednich przykładach.

Kodowanie

Na początku sytuacja zostanie omówiona z punktu widzenia przeglądarki. Proszę wyobrazić sobie spełnianie pracy przeglądarki. Wykonuje się żądanie HTTP dla pewnego URL-a i otrzymuje odpowiedź. Odpowiedź ta w najprostszym znaczeniu nie jest niczym więcej niż długą sekwencją bajtów. Ale w jaki sposób można się dowiedzieć, jak wyświetlić tę odpowiedź?

Popularnym i właściwie domyślnym sposobem jest przyjęcie, że każdy bajt reprezentuje jeden z 256 możliwych znaków, a następnie przyjęcie, że znak, który bajt reprezentuje może zostać określony przez wyszukanie wartości bajtu w pewnej tabeli. Domyślna tabela jest zdefiniowana przez standard ISO-8859-1, noszący także nazwę Latin-1. Zawiera on odwzorowanie typu bajt-do-znaku dla najpopularniejszych znaków stosowanych w językach zachodnioeuropejskich. Tak więc domyślnie przeglądarka może otrzymywać sekwencję bajtów i konwertować ją do sekwencji znaków zachodnioeuropejskich.

Co natomiast należy uczynić, jeżeli pragnie się otrzymać tekst, który nie jest napisany w języku zachodnioeuropejskim? Należy pobrać długą sekwencję bajtów odpowiedzi i zinterpretować ją w inny sposób, przy pomocy innego odwzorowania sekwencja-bajtów-do-znaku. Mówiąc językiem technicznym, należy zastosować inne kodowanie[2]. Istnieje nieskończona ilość potencjalnych kodowań. Na szczęście, najczęściej stosuje się jedynie kilkadziesiąt z nich.

Niektóre kodowania wykorzystują znaki jednobajtowe w sposób podobny do ISO-8859-1, chociaż z innym odwzorowaniem bajt-do-znaku. Na przykład, ISO-8859-5 definiuje odwzorowanie bajt-do-znaku dla znaków cyrylicy (alfabetu rosyjskiego), a ISO-8859-8 definiuje odwzorowanie dla alfabetu hebrajskiego[3].

Inne kodowania wykorzystują znaki wielobajtowe, w których jeden znak może być przedstawiany przez więcej niż jeden bajt. Najczęściej zdarza się to w przypadku języków zawierających tysiące znaków, takich jak chiński, japoński czy koreański — często nazywanych po prostu CJK. Kodowania wykorzystywane do wyświetlania tych języków to między innymi Big5 (chiński), Shift_JIS (japoński) i EUC-KR (koreański). Tabela zawierająca języki i odpowiadające im kodowania znajduje się w dodatku F, „Kodowania”.

Oznacza to, że jeżeli znane jest kodowanie, w którym zapisana została odpowiedź, można określić sposób interpretacji otrzymanych bajtów. Pozostaje jedno pytanie — jak określić kodowanie? Można wykonać to na dwa sposoby. Po pierwsze, można zażądać ujawnienia kodowania przez użytkownika. W przeglądarce Netscape Navigator 4 można to wykonać poprzez opcję menu ViewEncoding, w Netscape Navigator 6 poprzez ViewCharacter Coding. W przeglądarce Microsoft Internet Explorer 4 poprzez WidokCzcionki, a Microsoft Internet Explorer 5 poprzez WidokKodowanie. Podejście to często wymaga, aby użytkownik wypróbował kilku kodowań, zanim obraz zacznie wyglądać sensownie. Drugą możliwością jest określenie kodowania przez serwer (lub serwlet) w nagłówku Content-Type. Na przykład, następująca wartość Content-Type:

text/html; charset=ISO-8859-5

wskazuje, że wykorzystywane kodowanie to ISO-8859-5. Niestety, niektóre starsze przeglądarki mogą błędnie zinterpretować dodanie kodowania do nagłówka Content-Type.

Tworzenie wyników zakodowanych

Kiedy znana jest już zasada działania kodowań z perspektywy przeglądarki, można wrócić do perspektywy serwletu. Rola serwletu w tym działaniu jest następująca:

1.       Wybranie kodowania i ustawienie go dla serwletu.

2.&#x...

Zgłoś jeśli naruszono regulamin