Witaj, Gościu O nas | Kontakt | Mapa
Wortal Forum PHPEdia.pl Planeta Kubek IRC Przetestuj się!

Wprowadzenie do OPT cz. 1

Interfejs wielojęzyczny

Przejdźmy teraz do nowego zagadnienia. Przypuśćmy, że tworzysz duży projekt skierowany nie tylko na rynek polski, ale i klientów zagranicznych. Niestety nasz rodzimy język jest dopiero na początku realizacji planu zawładnięcia światem, dlatego lepiej jest założyć, że taki Brytyjczyk lub Niemiec nie potrafi się nim jeszcze posługiwać. Wynika z tego, iż nasza witryna musi posiadać wielojęzyczny interfejs: wszystkie komunikaty i napisy zmieniają się w zależności od tego, jaką wersję językową wybrał sobie internauta. Do normalnego systemu szablonów musielibyśmy przekazywać tony informacji lub wykorzystywać w szablonach bezpośrednio elementy silnika PHP witryny, aby nieco ułatwić ten proces. OPT normalnym systemem szablonów jednak nie jest i posiada specjalny mechanizm ułatwiający tworzenie wielojęzycznych interfejsów. Tradycyjnie, zacznijmy jednak od szablonu:

<html>
<head>
  <title>Open Power Template: i18n</title>
</head>
<body>
<p>{$page1@intro}</p>
<p>{$page1@preview}</p>
<ul>
	<li>{literal}{$global@yes}{/literal}: {$global@yes}</li>
	<li>{literal}{$global@no}{/literal}: {$global@no}</li>
	<li>{literal}{$global@maybe}{/literal}: {$global@maybe}</li>
</ul>
{apply($page1@counter, 1)}
<p>{$page1@counter}</p>
{apply($page1@counter, 2)}
<p>{$page1@counter}</p>
</body>
</html>

W kodzie poumieszczane są nowe, niespotykane dotąd rodzaje bloków mające postać {$grupa@nazwa}. Są to tzw. bloki językowe, które zaznaczają miejsca, w których mają pojawić się jakieś komunikaty interfejsu. OPT, napotykając taki blok, odczytuje sobie z niego ID komunikatu oraz grupy, do której należy, po czym samodzielnie pobiera go sobie ze zdefiniowanego wcześniej systemu i18n. Dodam jeszcze, że użyta w szablonie instrukcja {literal} powoduje wyświetlanie znajdujących się wewnątrz niej tagów OPT, zamiast ich przetwarzania. Zastosowałem ją tutaj, aby wyświetlić nazwy wykorzystywanych bloków językowych.

Kolejnym ciekawym elementem jest funkcja apply(). Jej zadanie można wytłumaczyć następująco: czasami niektóre dane muszą być umieszczone wewnątrz komunikatu, co ma miejsce np. w takim przypadku: "Na stronie jest 17 użytkowników on-line". Widzimy, że "17" jest wartością dynamiczną, która musi być zassana z jakiegoś bloku. Mamy dwa wyjścia: albo rozbijemy komunikat na dwa, np. $stats@users_online1 i $stats@users_online2, a między nimi umieścimy blok, lub... zastosujemy funkcję apply(), która odnajdzie w tekście specjalny znacznik ( %s) i wstawi w jego miejsce jakąś wartość dynamiczną. Właśnie tak robimy powyżej: mamy dynamiczny blok językowy $page@counter, który ma treść "Licznik: %s.". Odpowiednią liczbę umieszczamy na miejscu %s właśnie za pomocą funkcji apply().

Aby używać wielojęzycznych interfejsów, musimy w kodzie PHP połączyć OPT z jednym z nich. Biblioteka zezwala na wykorzystanie dwóch rodzajów interfejsu:

  1. 1.Proceduralny - do OPT podpinamy dwuwymiarową tablicę asocjacyjną wiążącą ID komunikatów z ich treścią. Obiektowy - do OPT podpinamy obiekt klasy implementującej interfejs ioptI18n - klasa ta ma za zadanie udostępniać żądane komunikaty za pomocą odpowiednich metod. Oczywiście daje nam to znacznie większe pole do popisu - możemy wtedy zaprogramować np. automatyczne wczytywanie grup komunikatów, gdy są używane po raz pierwszy.

Zajmiemy się najpierw pierwszym z nich. Skrypt jest tutaj niezwykle prosty: tworzymy sobie tablicę z wszystkimi tekstami, po czym podpinamy ją do OPT metodą optClass::setDefaultI18n():

<?php
	define('OPT_DIR', './lib/');
	require('./lib/opt.class.php');
	
	$daneJezykowe = array(
		'global' => array(
			'yes' => 'Tak',
			'no' => 'Nie',
			'maybe' => 'Być może'		
		),
		'page1' => array(
			'intro' => 'Witaj w testowym projekcie opartym
				o Open Power Template!',
			'preview' => 'Podgląd możliwości i18n',
			'counter' => 'Licznik: %s'
		)
	);
 
	try
	{ 
		$tpl = new optClass;
		$tpl -> root = './templates/';
		$tpl -> compile = './templates_c/';
		$tpl -> gzipCompression = true;
		$tpl -> httpHeaders(OPT_HTML);
		
		$tpl -> setDefaultI18n($daneJezykowe);
		
		$tpl -> parse('szablon3.tpl'); 
	}
	catch(optException $exception)
	{ 
		optErrorHandler($exception); 
	}
?>

Uruchamiamy skrypt i niby wszystko działa, ale jednak coś jest nie tak. Spójrzmy na nasz licznik. Drugie wywołanie funkcji apply() wcale nie zaktualizowało licznika! Powód jest prosty - rezultat jej działania nadpisał oryginalny tekst, kasując znacznik. W końcu gdzieś musiał on trafić, a skoro do dyspozycji jest tylko jedna tablica... Jest jednak sposób, aby temu zaradzić, a mianowicie napisać własny, obiektowy interfejs i18n.

<?php
	define('OPT_DIR', './lib/');
	require('./lib/opt.class.php');
	
	class i18n implements ioptI18n
	{
		private $tpl;
		private $replacements = array();
		private $data = array(
			'global' => array(
				'yes' => 'Tak',
				'no' => 'Nie',
				'maybe' => 'Być może'		
			),
			'page1' => array(
				'intro' => 'Witaj w testowym projekcie opartym
					o Open Power Template!',
				'preview' => 'Podgląd możliwości i18n',
				'counter' => 'Licznik: %s'
			)
		);
		
		static private $instance;
		
		private function __construct(){ }
		
		public function setOptInstance(optClass $tpl)
		{
			$this -> tpl = $tpl;
		} // end setOptInstance();
		
		static public function getInstance()
		{
			if(!is_object(self::$instance))
			{
				self::$instance = new i18n;
			}
			return self::$instance;
		} // end getInstance();  
  
	 	public function put($group, $text_id)
	 	{
			if(isset($this -> replacements[$group][$text_id]))
			{
				return $this -> replacements[$group][$text_id];
			}
			return $this -> data[$group][$text_id]; 	
		} // end put();
 
		public function apply($group, $text_id)
		{
			$args = func_get_args();
			unset($args[0]);
			unset($args[1]);
			$this -> replacements[$group][$text_id]
				= vsprintf($this -> data[$group][$text_id], $args);
		} // end apply();
		
		public function putApply($group, $text_id)
		{
			$args = func_get_args();
			unset($args[0]);
			unset($args[1]);
			return vsprintf($this -> data[$group][$text_id], $args);
		} // end apply();	
	}
 
	try
	{ 
		$tpl = new optClass;
		$tpl -> root = './templates/';
		$tpl -> compile = './templates_c/';
		$tpl -> gzipCompression = true;
		$tpl -> httpHeaders(OPT_HTML);
		
		$tpl -> setObjectI18n(i18n::getInstance());
		
		$tpl -> parse('szablon3.tpl'); 
	}
	catch(optException $exception)
	{ 
		optErrorHandler($exception); 
	}
?>

Przyjrzyjmy się dokładniej klasie i18n. Po interfejsie ioptI18n implementuje ona następujące metody:

  1. put($group, $text_id) - metoda zwraca treść komunikatu $text_id w grupie $group.
  2. apply($group, $text_id, ...) - nasza własna implementacja funkcji apply(). Pobiera ona zmienną liczbę parametrów - pierwsze dwa to oczywiście nazwa grupy oraz ID tekstu, natomiast dalsze to wartości do umieszczenia w podanym bloku językowym. Znaczniki %s najlepiej podmieniać funkcją vsprintf(), która ma wszystko, co nam jest potrzebne.
  3. putApply($group, $text_id, ...) - ta metoda jest wprowadzona dla wygody programisty, który może interfejs wykorzystywać także poza OPT. Działa ona tak, jak apply(), lecz zamiast zapisywać rezultat do jakiegoś bufora, zwraca go.
  4. setOptInstance(optClass $tpl) - pobiera obiekt klasy optClass.

Podana powyżej implementacja wykorzystuje wzorzec singleton, aby mieć pewność, że po skrypcie nie będzie się pałętać 10 obiektów interfejsu językowego. Oryginalne komunikaty zapisane są w tablicy $replacements, a teksty zmodyfikowane przez apply() trafiają do tablicy $data - dzięki takiemu podziałowi nasza klasa prawidłowo obsłuży podany wyżej szablon; oryginalny komunikat źródłowy nigdy nie zostanie nadpisany.

Koniec części 1

Poznaliśmy właśnie podstawowe zasady i mechanizmy dostępne w OPT. Część druga tego artykułu jest w całości poświęcona systemowi komponentów. Nie tylko nauczymy się z nich korzystać, ale też napiszemy własny. Zapraszam do lektury części drugiej.

Informacje na podobny temat:
Wasze opinie
Wszystkie opinie użytkowników: (11)
Dużej różnicy w stosunku do Smarty nie widać
Sobota 16 Kwiecień 2011 12:28:13 am - neosatan <pawel.kuznik_at_gmail.com>

Niestety, z wielkim rozczarowaniem doczytałem do końca arta. OPT był mi zachwalany jako genialna alternatywa dla SMARTY, lecz przynajmniej po tym artykule muszę stwierdzić, że OPT nie rozwiązuje problemów, które są w SMARTY (lub nie zostały takowe wspomniane). Moje wrażenie jest mniej więcej takie, że OPT jest bardzo podobne do SMARTY. Twórcy OPT zamiast tworzyć nowy, bardzo podobny silnik szablonów, mogli zaproponować współpracę twórcą SMARTY, lub wydanie alternatywnej wersji.
Muszę powiedzieć, że SMARTY (przynajmniej na razie) góruje nad OPT tym, że jest akceptowany za granicą, co jest plusem dla programistów pracujących również z zagranicznymi firmami.
Tak, czy owak artykuł skłonił mnie do bliższego przyjrzenia się OPT.

OPT
Wtorek 30 Czerwiec 2009 4:19:12 pm - pearl1985

Zrobiłem sobie dzisiaj porównanie szablonów między smarty a opt i szczerze powiem, że o ile obydwa systemy szablonów generują pliki php i je później includują do zdobycia danych do wyjścia, to smarty robi to znacznie szybciej (<!-- Skrypt wykonał się w 0.0013339519500732 sekund --> dla smarty, <!-- Skrypt wykonał się w 0.032589912414551 sekund --> dla opt). Reasumując jaki z tego wniosek? Moim zdaniem lepiej napisać prostą klasę, która będzie składowała dane i potem robiła include już napisanego przez nas szablonu w php. A w tym php odpowiednie odwoływanie się do zmiennych przechowywanych przez klasę np. template.

ciekawe
Sobota 19 Styczeń 2008 2:02:05 pm - potreb

Jestem pod wrażeniem, jakby nie było jest to dość wielka alternatywa dla smarty

Ankieta
Czwartek 18 Październik 2007 6:59:19 pm - grzesk98 <grzegorz.kowalewski_at_gmail.com>

Jeśli moglibyście wypełnić ankietę na temat systemów szablonów:

http://ankiety.boby.pl/index.php?module=polls&action=fillup&poll_id=74

z góry dzięki.

OPT
Poniedziałek 08 Październik 2007 2:28:35 pm - Diabl0

Czy OPT w pełni obsługuje obiekty w szablonach? Chodzi mi o kostrukcje takie jak:
{$zmienna->metoda1()->metoda2();}

Smarty sobie niestety nie radzi z takim czymś a znacznie ułatwiło by mi to pracę.

Brak porównań do Smarty
Niedziela 01 Lipiec 2007 11:10:05 pm - Diabl0

Wszystko bardzo fajnie i ładnie, ale brakuje mi w treści porównań względem Smarty'ego. Jak wiadomo przyzwyczajenie jest silne i dla kogoś kto już używa (używał) Smarty i szuka czegoś innego/lepszego takie porównania i wyjaśnienia były by bardzo wygodne.
Przy porównywaniu chętnie bym także zobaczył informację o wydajności - Smarty jest fajne i baaardzo elastyczne ale z wydajnością nie jest wesoło i informacje o wydajności OPT w stosunku do Smarty mogły by sporo osób skusić do sprawdzenia tego w praktyce.

ee tam
Czwartek 10 Maj 2007 3:30:38 am - yacho

i tak odchodzi sie od znacznikow w szablonach na rzecz plain php templates - nie oszukujmy sie - kazdy szablon ma jakas logike prezentacji i nie ma co sie oszukiwac ze kiedys maksymalnie to sie uprosci - co jest wazne to separacja i enkapsulacja warstw - a sama skladnia juz nie tak mocno.

Odp dla sh4dow
Piątek 16 Marzec 2007 7:57:59 pm - slump <slump_ilawa_at_wp.pl>

sh4dow jeśli oczekujesz odp na te pytania napisz do zyxa lub skorzystaj z openpb.net/forum :) celowo nie daję jako link aby nie było za dużego spamu w tym komentarzu.

Pytanie
Czwartek 01 Marzec 2007 9:34:32 am - sh4dow

Tak sie zastanawiam, jak mozna krytykowac sposob nazewnictwa metod/funkcji. No w sumie i dlaczego camel style ma byc "eleganckim" nazewnictwem ? Wiem czepiam sie ale tak jakos nie daje mi to spokoju.
A co do wsparcia wielojęzykowego to tutaj bym mocno polemizowal i zastanawial sie raczej jak mozna by to raczej poprawic. Bo sorki ale jesli ja mam baze gdzie jest okolo 5000 kluczy i do tego 6 jezykow to nie chcial bym widziec jak te pliki i tablice z tlumaczeniami by wygladaly.

koment
Środa 28 Luty 2007 1:40:27 pm - mrm

dobry art

koment
Środa 28 Luty 2007 1:39:19 pm - mrm

bardzo fajny artykul

Mentax.pl    NQ.pl- serwery z dodatkiem świętego spokoju...   
O nas | Kontakt | Mapa serwisu
Copyright (c) 2003-2022 php.pl    Wszystkie prawa zastrzeżone    Powered by eZ publish Content Management System eZ publish Content Management System