Přestože mám rád řešení využívající zavedené existující produkty a Gettext je bezesporu kvalitní knihovna, není vždy možné toto rozšíření použít. Důvody jsou dva – jednak rozšíření nemusí být na hostingu k dispozici a jednak při vkládání nové jazykové hlášky nebo i úpravě stávajícího překladu je nutné vytvořit jeho binární podobu. A to je podstatná nevýhoda, protože v PHP neexistuje pro tuto operaci interní funkce, takže je potřeba volat externí příkaz, což také není možné vždy. Překlady se navíc ukládají do textového souboru a nikoli do databáze, což může znesnadňovat jejich editaci.

Pokud tedy chceme mít lokalizaci zcela ve svých rukou, můžeme si vytvořit vlastní systém. Překlady budou uložené v databázi, na stránku je budeme vypisovat vlastní funkcí a na získání seznamu překládaných textů ze zdrojového kódu si vytvoříme vlastní skript.

Začněme vytvořením databázové tabulky:

CREATE TABLE preklady (
   id int NOT NULL AUTO_INCREMENT,
   idf varchar(250) NOT NULL, — jednoznačný identifikátor textu
   jazyk char(2) NOT NULL, — dvoupísmenný kód jazyka
   preklad text NOT NULL, — překlad
   UNIQUE (jazyk, idf),
   PRIMARY KEY (id)
);

Překlady z tabulky může získávat takováto funkce:

<?php
function lang($idf)
{
   global $LANG; // nastaveno na základě části URL, session proměnné nebo cookie
   $row = mysql_fetch_row(mysql_query(„SELECT preklad FROM preklady WHERE idf = ‚“ . addslashes($idf) . „‚ AND jazyk = ‚$LANG'“));
   return ($row ? $row[0] : $idf); // při neexistujícím překladu je vrácen identifikátor
}
?>

Pokud je na stránce překládaných textů hodně, nebo pokud databáze běží na jiném serveru, takže každý dotaz něco stojí, je lepší všechny texty načíst najednou:

<?php
function lang_static($idf)
{
   global $LANG;
   static $preklady;
   if (!isset($preklady)) {
      $preklady = array();
      $result = mysql_query(„SELECT idf, preklad FROM preklady WHERE jazyk = ‚$LANG'“);
      while ($row = mysql_fetch_assoc($result)) {
         $preklady[$row[„idf“]] = $row[„preklad“];
      }
      mysql_free_result($result);
   }
   return (isset($preklady[$idf]) ? $preklady[$idf] : $idf);
}
?>

Při prvním volání funkce se na základě proměnné $LANG naplní pole $preklady, které se následně používá pro vracení přeložených textů. Dotaz do databáze je tedy položen pouze jeden, zaplaceno je za to ale tím, že jsou všechny překlady po dobu běhu skriptu drženy v paměti.

Tabulku preklady lze naplnit například tímto kódem:

<?php
$pattern = ‚~lang\\((„([^\\\\]*\\\\.)*[^\\\\“]*“|\'([^\\\\]*\\\\.)*[^\\\\\‘]*\‘)\\)~U‘;
foreach (glob(„*.php“) as $filename) {
   preg_match_all($pattern, file_get_contents($filename), $matches);
   foreach ($matches[1] as $val) {
      mysql_query(„INSERT INTO preklady (idf, jazyk, preklad) VALUES ($val, ‚$LANG‘, $val)“);
   }
}
?>

Skript projde všechny soubory *.php v aktuálním adresáři, najde v nich volání funkce lang() a parametry této funkce uloží do tabulky preklady. Regulární výraz je trochu složitější, ale rozumí si s řetězci uzavřenými do jednoduchých i dvojitých uvozovek a nerozhodí ho ani použitá zpětná lomítka. Systém ale samozřejmě nebude fungovat v případě, že budou přímo v řetězci použity proměnné, takže je podobně jako u knihovny Gettext nutné používat formátovací řetězce spolu s funkcí sprintf nebo podobnou.

Uvedený kód by do databáze zdánlivě mohl vložit identifikátory, které tam už jsou, tomu je ale zabráněno unikátním indexem (jazyk, idf), který tabulka preklady obsahuje. Jako identifikátor lze použít v zásadě libovolný řetězec, ale protože funkce lang() vrací v případě neexistence překladu právě tento identifikátor (podobně jako to dělá knihovna Gettext), vyplatí se jako identifikátor používat smysluplný text ve výchozím jazyce.

Uvedený kód nabízí pouze základní funkčnost, ale rozšíření například o skloňování (různé překlady v závislosti na počtu) by mělo být poměrně přímočaré. Podobně jednoduché by bylo i rozšíření skriptu o vazbu na jednotlivé soubory – tak, aby se v každém souboru načítaly jen ty překlady, které budou potřeba.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět