Większość metod tłumaczenia używa różnego rodzaju plików do przetrzymywania informacji o "wyglądzie" tekstu w danej wersji językowej, dlatego też znaczną część wpisy poświęcę omawianiu tych różnych "plikowych tworów".
Na początku był define
A jeśli nawet nie na początku, to jest to droga, która w ten czy inny sposób wydaje się "prosta i oczywista".
define ('Hello_World', "Witaj Świecie"); echo constant('Hello_World'); echo Hello_World;Oczywiście przy wykorzystaniu takiej metody wszelkie definicje tekstów powinny być umieszczane w osobnym pliku dla każdej wersji językowej i w zależności od potrzeb includowawne.
Co ciekawe odwoływanie się do zdefiniowanej stałej przy użyciu constant() trwa dłużej niż bezpośrednie wywołanie:
pure: 0.5458300113678 with constant: 0.85419201850891
Metoda ta jednak nie sprawdza się w przypadku większych portali, gdzie liczba tłumaczeń przechodzi w setki czy nawet tysiące. Do tego dochodzi całkowity brak wsparcia po stronie IDE (brak auto uzupełniania i innych cudów techniki).
A gdyby tak tablicę
Co prawda tablica sama w sobie również wsparcia od IDE nie oferuje, ale daje większe możliwości segregacji wpisów (np. poprzez tworzenie wielu wymiarów).
define: 0.4133129119873 define with constant: 0.88955783843994 array: 0.35322785377502 multi array: 0.42432999610901Poza tym jak widać po osiąganych czasach wykorzystanie tablicy okazuje się lepszą metodą niż definiowanie stałych (co zaskakujące nie jest) i dopiero wykorzystanie wielowymiarowych tablic zbliża te czasy do siebie.
.ini czyli coś prawie zapomnianego
Dziś już prawie nikt nie używa plików .ini - bo i po co skoro są choćby XML.. Jednak ogromną zaletą plików .ini jest ich mały narzut związany z obsługą danych - nie potrzeba wieloznakowych tagów zarówno otwieranych, jak i zamykanych... nie - wystarczy klucz i znak '='. Czego rezultatem jest zaskakująca wydajność (czas liczony łącznie z parsowaniem pliku!):
define: 0.43395209312439 define with constant: 0.94658613204956 array: 0.36954712867737 multi array: 0.44773697853088 ini array: 0.42291903495789Do tego PHP zapewnia wbudowany parser plików .ini - parse_ini_file() - tak więc stworzenie translacji na tej zasadzie jest dość proste. Poza tym pliki .ini są dość popularnym sposobem trzymania danych konfiguracyjnych dla np. bazy danych :)
Minusem wbudowanego parsera jest jednak fakt, że wygenerowana tablica może mieć maksymalnie 2 wymiary.
Profesjonalny gettext
W świecie PHP oczywiście istnieją również rozwiązania dedykowane dla lokalizacji - w tym przypadku jest to zbiór funkcji, do których generalnie odnosi się poprzez słowo "gettext". Funkcje te tak naprawdę dostępne są w wielu różnych językach programowania albo dzięki natywnym bibliotekom, albo dzięki pracy zwykłych "szarych" użytkowników. Zaletą gettexta jest jego profesjonalne podejście do zagadnienia - podczas pracy z nim dostajemy pliki z jasno opisanymi wystąpieniami każdego elementu, który mamy przetłumaczyć. No właśnie - tutaj tak naprawdę specjalny "szperacz" wyszukuje frazy, które mamy przetłumaczyć, więc możemy spokojnie pisać i testować kod nie obawiając się, że nagle dostaniemy błąd o braku danego wpisuj w tablicy czy nieistnieniu jakiejś zmiennej.
Jeśli przypadkiem poszukujecie kompilatra dla gettext to polecam zajrzeć na http://savannah.gnu.org/projects/gettext.
Natywny gettext
Wbudowany gettext wymaga zainstalowania (i uruchomienia) na serwerze rozszerzenia php_gettext.
define: 0.030115127563477 define with constant: 0.061676025390625 array: 0.021489143371582 multi array: 0.027302980422974 ini array: 0.02887487411499 Czas dla gettext (native): 0.87748694419861
Porównując szybkość jego działania jednak szybko dojdziemy do wniosku, że wcale nie jest to taki wyśniony wydajnościowo sposób implementowania lokalizacji. Cóż za to jest on na pewno przyjemniejszy podczas pisania kodu i samego procesu translacji.
gettext dla ubogich
Może nie koniecznie dla ubogich w sensie dosłownym, a raczej dla ubogich pod względem możliwości serwera. Natywny getext ma to do siebie, że ładuje pliki z tłumaczeniami raz do pamięci i trzyma je generalnie tam aż do restartu serwera - owszem istnieją metody na obejście tego.. ale jeśli ktoś zajmuje się głównie tworzeniem strony i generalnie deweloperką to raczej będzie skłonny poświęcić trochę wydajności podczas testów na rzecz prostszego i szybszego w napisaniu kodu.Do tego dochodzi problem z aktualizacją słownika w przypadku serwerów współdzielonych - mało który admin zgodzi się na restart tylko dlatego, że nasz słowniczek zmienił tłumaczenia dla kilku elementów...
define: 0.031126976013184 define with constant: 0.062520980834961 array: 0.021286010742188 multi array: 0.02723503112793 ini array: 0.027822017669678 Czas dla gettext (native): 0.90787696838379 Czas dla gettext (custom): 1.8490700721741
Tak więc jeśli chcecie wypróbować tą nieoficjalną implementację to zapraszam na https://launchpad.net/php-gettext.
Sposoby z kosmosu
No może nie całkiem z kosmosu, bo czasami inaczej się po prostu nie da (lub wykorzystanie plikowych sposobów nie ma sensu). Ale jeśli ktoś opiera swoją wielojęzyczność elementów statycznych na bazie danych to znak, że coś się dzieje... By była jasność nie chodzi mi o elementy, które użytkownicy mogą dynamicznie dodawać do portalu, ale o tłumaczenia np. strony do logowania ^.^ Generalnie wszelkie odwołania do zewnętrznych zasobów (a baza danych takowym jest - no chyba, że mówimy o serwerze PHP znajdującym się na tej samej maszynie co baza, która to jeszcze trzyma wszystkie dane w pamięci podręcznej) to utrata cennego czasu i zasobów. Oczywiście można użyć tłumaczy online takich jak Google translate, altavista (Babel fish), czy bing translator... ale to trwa i wykorzystanie takich pereł polecałbym przenieść do JavaScriptu odpalanego przez klienta i to tylko i wyłącznie dla treści, których tłumaczenia po prostu nie jesteśmy w stanie dostarczyć.
Ciekawym sposobem podejścia do tematu jest wykorzystanie klas i zawartych w nich zmiennych jako kontenerów na tłumaczenia. Takie podejście ma ten plus, że zapewni nam auto uzupełnianie IDE i łatwość ładowania innych wersji językowych. Wadą jest wydajność, gdyż narzut związany z tworzeniem klasy powoduje, że czas konieczny na obsłużenie tego typu lokalizacji jest ok. 2 razy większy niż w przypadku deklarowania stałych za pomocą define().
Puenty brak
Cóż czasy mówią same za siebie, tak więc jeśli zależy wam na wydajności to z pewnością pomyślicie nad jakimś własnym rozwiązaniu opartym o pliki (dla leniuszków polecam zapoznać się z plikami .ini gdyż są bardzo wdzięczne pod względem tak możliwości łatwej translacji jak i użytkowania w aplikacji). Jeśli jednak już zamierzacie zagłębiać się w tajniki gettexta - technologia ta jest bardzo denerwująca (pomijając już fakt konieczności kompilacji, mergowania tłumaczeń...) choćby z tego powodu, że zwykle ciężko skłonić natywną wersję do poprawnego działania (wersja ~danilo zdecydowanie jest łatwiejsza w obsłudze) o wydajności nie mówiąc...
Chcących zaglądnąć w kod odsyłam do swojego chomika: (link)
Brak komentarzy:
Prześlij komentarz