Internacjonalizacja


Wstęp

Internacjonalizacja wspomaga tworzenie portali wielojęzycznych. Koncepcja polega na tym aby w kodzie aplikacji posługiwać się unikalnym 'kluczem' tłumaczenia, a w osobnym miejscu przechowywać tłumaczenia w różnych językach dla danego klucza.

W jPALIO tłumaczenia są przechowywane w bazie danych. Mając na uwadze względy wydajnościowe dostęp do tłumaczeń jest keszowany. Klucz tłumaczenia składa się następujących atrybutów:

Atrybut Opis Przykład
Język Język danego tłumaczenia eu pl ru
Kod tłumaczenia Unikalny identyfikator za pomocą którego programista odwołuje się do danego tłumaczenia firstName lastName
Kategoria Kategoria jest atrybutem opcjonalnym. Służy ona do rozróżniania dwóch lub więcej tłumaczeń o takich samych kodach.
W dalszej części tekstu.

Aby lepiej zobrazować przydatność kategorii posłużmy się przykładem. Załóżmy że mamy w portalu kod 'house' i jego tłumaczenie w języku polskim 'dom'. Lecz w jednym miejscu(np na formularzu z danymi adresowymi) chcielibyśmy użyć innego tłumaczenia, np. 'budynek'. W takim przypadku pierwsze tłumaczenie zostawiamy z pustą kategorią, natomiast drugiemu przypisujemy jakąś kategorię np. 'address'. Kategorie mogą też służyć do grupowania tłumaczeń np. wszystkie tłumaczenia na danej stronie mogą mieć taką samą kategorię.

 

Dodawanie języka

W jPALIO dodawanie nowego języka można zrealizować na dwa sposoby:

Używając metody $lang.setTranslation z nieistniejącym do tej pory kodem językiem programista spowoduje dodanie tego języka do systemu. Przykład:

$lang.setTranslation($@key, "en", $@category, $@translation)

Po zaimportowaniu pliku tłumaczeń, w którym jest użyty nowy kod języka, język ten zostanie automatycznie dodany do systemu. Więcej informacji o importowaniu plików tłumaczeń można znaleźć w artykule Export/Import tłumaczeń.

Zobacz także:


[Internacjonalizacja] Export/Import tłumaczeń
 

Ustawianie bieżącego języka

Aby mechanizm tłumaczeń mógł wybrać odpowiednie tłumaczenie musi wiedzieć jaki jest ustawiony bieżący język. Wybieranie bieżącego języka jest realizowane wg następującej kolejności:

  1. Wartość zmiennej globalnej o nazwie lang.languageCode.

  2. Wartość ciasteczka o nazwie [nazwa instancji].lang.languageCode.

  3. W celu zapewnienia kompatybilności wstecznej, jeżeli istnieje sesja to język określany jest na podstawie wartości zmiennej sesyjnej o nazwie: "LANGUAGE_DEFAULT".

  4. Jeżeli użytkownik jest zalogowany (istnieje sesja) to język określany jest na podstawie wpisu w tabelce p_users, kolumna language.

  5. Jeżeli dla danego użytkownika nie ma ustawionej kolumny p_users.language to język jest określany na podstawie języka domyślnego dla instancji (konfiguracja instancji)

  6. Jeżeli nie ma sesji oraz nie ma ustawionej zmiennej globalnej lang.languageCode język jest określany na podstawie języka domyślnego dla instancji (konfiguracja instancji)

Poniżej przedstawione zostały zalety i wady poszczególnych wariantów:

Ad. 1

Jest to dobre rozwiązanie gdy w systemie nie ma logowania dla każdego użytkownika (np. cały system ma dostęp publiczny). Wtedy ustawienie zmiennej lang.languageCode spowoduje wybranie bieżącego języka na jej podstawie. Ma to taką wadę, że aby w całym systemie mieć ustawioną zmienną lang.languageCode=”pl” należało by to robić na wszystkich stronach systemu. Można to ominąć przez wykorzystanie mechanizmu sticky param. W konfiguracji instancji robimy:

<url stickyParams="lang.languageCode=pl"/>

Spowoduje to zdefiniowanie lepkiego parametru, który będzie doczepiany do każdego urla wygenerowanego w systemie. Późniejsze przypisanie do zmiennej lang.languageCode innego kodu języka np.:

$=("lang.languageCode", 'en')

spowoduje zmianę języka. Powyższy przykład ze sticky param powoduje ustawienie języka globalnie dla całego systemu i wszystkich użytkowników wchodzących na jego strony.

Ad. 2

Jest to podobne rozwiązanie jak z punktu pierwszego i również zalecane jest jego stosowanie w systemach bez logowania per użytkownik. Różnica jest taka że zamiast ustawiania zmiennej globalnej musi zostać ustawione http cookie o nazwie [nazwa instancji].lang.languageCode:

$page.addCookie("instancjaAlfa.lang.languageCode", "pl")

Drugą różnica jest taka, że zmiana języka będzie miała zasięg tylko dla przeglądarki danego użytkownika, a nie globalnie dla całego systemu jak w poprzednim rozwiązaniu.

Ad. 3

Jest to tylko opcja tylko dla zachowania kompatybilności wstecznej. Zaleca się jednak używanie opcji z punktu nr 4.

Ad. 4
Jest to rozwiązanie zalecane dla systemów z logowaniem dla każdego użytkownika. Przy tworzeniu użytkownika można mu od razu przypisać język za pomocą wywołania:

$user.setLocale("pl")

Po zalogowaniu danego użytkownika ustawiony wcześniej język będzie wybrany przez mechanizm tłumaczeń.

Ad. 5

W przypadku braku ustawionego języka dla zalogowanego użytkownika, jako bieżący język zostanie ustawiona wartość z konfiguracji instancji. Ustawienie to ma zasięg globalny dla całego systemu.

Ad. 6

W przypadku braku zalogowanego użytkownika i braku ustawionej zmiennej lang.languageCode zostanie ustawiona wartość z konfiguracji instancji.

Używanie tłumaczeń

Mając ustawiony bieżący język jak opisano w poprzednim punkcie do tłumaczeń możemy odwoływać się przez metody z modułu $lang:

$// pobranie wartości dla tłumaczenia house bez żadnej kategorii
$lang.getTranslation("house")
$// pobranie wartości dla tłumaczenia house w kategorii address
$lang.getTranslation("house", "address")

Aby ułatwić pracę z tłumaczeniami w jPALIO istnieje dedykowany operator $#(...) którym można pobierać tłumaczenia. Ten sam przykład przy wykorzystaniu operatora wygląda następująco:

$// pobranie wartości dla tłumaczenia house bez żadnej kategorii
$#("house")
$// pobranie wartości dla tłumaczenia house w kategorii address
$#("house", "address")

W obiekcie Groovy do tłumaczeń odwołujemy się następujący sposób:

import palio.*
import palio.modules.*

Groovy.module("lang").getTranslation("house")
Groovy.module("lang").getTranslation("house", "address")

Poniżej przedstawię inne przydatne opcje mechanizmu tłumaczeń. Dla ułatwienia będę korzystał z operatora $#:

$// ustawienie bieżącej kategorii na address
$=("lang.languageCategoryCode", "address")
$// teraz poniższe wywołania zwrócą to samo tłumaczenie
$#("house")
$#("house", "address")
$// Zakladając że dla klucza 'ala' jest tłumaczenie '{0} ma {1}' w bieżącym języku.
$// Wtedy poniższe wywołanie zwróci Ala ma kota.
$#("ala", ["Ala", "kota"])

$// Przy parametryzowanych tłumaczeniach możemy wykorzystać również kategorię
$#("ala", "uczennica", ["Ala", "kota"])
$// pobieranie kodu bieżącego języka i wypisanie odpowiadającego mu języka na ekran
$if($==($lang.currentLanguage(), "pl"), {
Bieżący język: polski
})
$if($==($lang.currentLanguage(), "en"), {
Current language: English
})
$// pobranie listy języków
$=("langList", $lang.getLanguageList())
$// zablokowanie języka o zadanym id (zablokowany język nie jest zwracany przez getLanguageList())
$=(@plLangId, 1)
$lang.lockLanguage($@plLangId)
$// odblokowanie języka o zadanym id (zablokowany język nie jest zwracany przez getLanguageList())
$lang.unlockLanguage($@plLangId)
$// pobieranie listy kategorii
$=("catList", $lang.getCategoryList())
$// sprawdzenie czy kategoria istnieje
$if($lang.categoryExists("jakas_kategoria"), {
kategoria istnieje
}, {
kategoria nie istnieje
})

Dodawanie lub edycje języków, tłumaczeń i kategorii realizujemy za pomocą dwóch funkcji:

$lang.insertTranslation(String key, String languageCode, String categoryCode, String value)
$lang.setTranslation(String key, String languageCode, String categoryCode, String value)

Ich działanie jest prawie identyczne: dodają nowy lub aktualizują język, kategorię lub klucz tłumaczenia. Jedyną różnica pomiędzy nimi jest fakt, że metoda $lang.insertTranslation nie aktualizuje istniejących tłumaczeń, natomiast metoda $lang.setTranslation aktualizuje je.

Brak tłumaczeń

W przypadku braku tłumaczenia dla danego klucza domyślnie jest zwracana następująca wartość:

kod_języka#kod_kategorii#klucz

Można zmienić to zachowanie wykorzystując metody $lang.getTranslation(...) z parametrem 'String mode'. Parametr mode przyjmuje następujące:

Wsparcie w jDesignerze

Dla ułatwienia stosowania tłumaczeń w codziennej pracy w jDesignerze powstał panel tłumaczeń. Szczegóły jego obsługi można znaleźć w artykule: Dokumentacja > Środowisko programistyczne > jDesigner > Internacjonalizacja.

Export/Import tłumaczeń

Istnieje możliwość eksportu i importu tłumaczeń. Jest to szczególnie pomocne gdy mamy napisany system w jednym języku a chcemy wzbogacić go kolejny język. Możemy wtedy wyeksportować tłumaczenia, wysłać je do tłumacza a następnie zaimportować wynik pracy tłumacza.

Wyeksportowane tłumaczenia mają postać pliku xls o następującym formacie:

kategoria klucz pl en
page title tytuł title
person title tytuł szlachecki title
name nazwa name
... ... ... .

Aby do systemu dodać funkcjonalność eksportu tłumaczeń wystarczy zrobić stroną z jedno liniowym kodem:

$page.writeBinary($lang.exportTranslations())

Import tłumaczeń możemy robimy przy użyciu metody $lang.importTranslations(byte[])