lokalizace pomocí gettext (gettextExtractor + MyTranslator)
- kedlas
- Člen | 6
Ahoj, pořád se mi nedaří rozchodit svůj web jako vícejazyčný. Mám nastavené 2 jazyky a pro ně routy za pomoci persistentního parametru $lang takže mi teď fungují adresy www.mysite.cz/cs/ i www.mysite.cz/en/. V současnosti mám ve zdrojácích české texty zapsané v latte {_'Text'}. Použil jsem gettextExtractor od Karla Klímy pro vytažení veškerých textů z .php a .latte souborů. Správně se mi vytvořily .po soubory iobsahující požadované msgid a msgstr řetězce. V poeditu jsem si tento .po soubor zeditoval a uložil ho do app/locale/en/LC_messages/messages.mo.
Pak jsem po vzoru charlie.cz vytvořil třídu MyTranslator a umístil jí do /libs.
<?php
class MyTranslator implements Nette\Localization\ITranslator
{
/**
* Translates the given string.
* @param string message
* @param int plural count
* @return string
*/
/*
public function translate($message, $count = NULL)
{
return '...';
}*/
public $countRegexp = '#\%([0-9]+\$)*d#';
public $paramsRegexp = '#\%([0-9]+\$)*[fs]#';
/**
* Gets the Gettext ready
*
* @param string $locale
* @param string $directory
* @param string $domain
*/
public function __construct($locale, $directory, $domain = 'messages') {
// gettext mandatory settings
putenv("LANG=$locale");
setlocale(LC_ALL, $locale);
// language pack path: $directory/$locale/LC_$domain/$domain.mo
// example: application/locale/cs/LC_MESSAGES/messages.mo
bindtextdomain($domain, $directory);
textdomain($domain);
bind_textdomain_codeset($domain, 'UTF-8');
//\Nette\Diagnostics\Debugger::dump($directory.'/'.$locale.'/LC_'.$domain.'/'.$domain.'.mo');
//\Nette\Diagnostics\Debugger::dump(fopen($directory.'/'.$locale.'/LC_'.$domain.'/'.$domain.'.mo', 'r'));
}
/**
* Translates the given string.
* @param string message
* @param int count
* @return string
*/
public function translate($message, $count = NULL) {
$pars = func_get_args();
if (!preg_match($this->countRegexp, $message)) {
// message is not in plural
$message = gettext($message);
//\Nette\Diagnostics\Debugger::dump($message);
} else {
// finds the position of the integer parameter
$split = preg_split($this->countRegexp, $message);
$n = preg_match($this->paramsRegexp, $split[0]);
if (!isset($pars[$n+1])) // parameter does not exists
throw new InvalidArgumentException('...');
$message = ngettext($message, $message, $pars[$n+1]);
}
if (count($pars)>1) {
array_shift($pars);
return vsprintf($message, $pars);
}
return $message;
}
}
A nyní nastává můj problém a to ten, že mi metoda gettext() zavolaná v metodě translate() MyTranslatoru nevrací anglický překlad nýbrž ten původní český. Jediné co mě napadlo bylo zkontrolovat, jestli skutečně exsituje a definuji v konstruktoru MyTranslatoru správnou cestu k .mo souboru. To mám zdá se dobře.
Nevíte někdo jak dostat ty správné překlady z locale/en/LC_messages/messages.mo?
Díky moc za radu dost se v tomto ztrácím.
- kedlas
- Člen | 6
ještě doplnění – v base presenteru volám translator:
public function beforeRender() {
$this->template->registerFilter('Nette\Templates\CurlyBracketsFilter::invoke');
Nette\Environment::setVariable('lang', $this->lang);
$translator = new MyTranslator(Nette\Environment::getVariable('lang'), __DIR__ . '/../locale');
$this->template->setTranslator($translator);
}
- h4kuna
- Backer | 740
Koukám že se snažíš použít nativní gettext, udlělám si reklamu :).
Je tam vyrobené makro které mění chování defaultního makra {_''} na to, aby se překládalo přes gettext. Nic do šablony nenastavuj nemusíš používat žádnou metodu setTranslator. Nezapomeň že gettext překládá jen statické texty takže použití _($foo) není optimální, protože pak se ti ve slovníku budou hromadit texty $foo, $bar… Na vytažení textů z aplikace GettextExtractor nebo poedit jsou dostačující. Manuál na rozchození by měl stačit pokud ne napiš mi na mail.
- pavel.simecek
- Člen | 11
Zdravím. Vím, že píšu s křížkem po funuse, ale přijde mi správné dát relevatní komentář k lokalizci Nette, ve které je jinak dosti nepořádek.
(1) Nejdřív to kedlas:
Ta tvoje implementace působí trochu nesmyslně. Např. tohle neodpovídá
tomu, k čemu je funkce ngettext určená
$message = ngettext($message, $message, $pars[$n+1]);
ngettext nedělá nic jiného než že vrací překlad prvního nebo druhého parametru na základě toho jestli třetí parametr je 1 nebo větší.
Chápu, že se asi snažíš nějak tam zakomponovat parametrizaci překladů, ale takto to nepůjde. Bohužel rozhraní Translator pro parametrizaci nedáva podporu – není tam na to ani funkce ani parametry. Takže na to zapomeň a řeš to pomocí printf nebo si na to napiš zvláštní makro. Jiná přímá cesta není.
(2) To h4kuna:
Ten tvůj framework jsem zkoušel chvíli rozjet, ale vzdal jsem to. Důvody
jsou dvojí:
(a) Dokumentace rozchození vypadá dosti neúplně. Asi nebudeš souhlasit, ale
zajímalo by mě, kolik uživatelů to podle toho zvládlo. Nechápu proč tam
místo nesrozumitelného návodu nemáš zdroják minimální Nette aplikace,
kde bys to měl rozchozený.
(b) Používáš prvky PHP 5.4 a to bez toho, abys na to kdekoli upozornil. To
mě fakt trochu vytočilo.
Závěrem pro náhodného čtenáře:
Buď zkuste použít Kdyby/Translation, ten je jediný, který se tváří
živě. Sám jsem ho už neměl sílu zkoušet, poté co jsem vyzkoušel
2 jiné nefunkční addony. Nebo si implementujte ITranslator sami, ale
nepoužívejte kód výše – to vám nebude fungovat.
- Tomáš Votruba
- Moderator | 1114
@pavel.simecek Kdyby\Translation je jasná volba, je velmi živý a funkční :)
Editoval Tomáš Votruba (27. 6. 2014 9:01)
- pavel.simecek
- Člen | 11
Tomáši, je někde nějaký příklad, jak Kdyby\Translation použít s gettext? Filip Procházka někde psal, že by to mělo jít, ale jak, to už jsem nenašel.
Tomáš Votruba napsal(a):
@pavel.simecek Kdyby\Translation je jasná volba, je velmi živý a funkční :)
- Filip Procházka
- Moderator | 4668
@pavel.simecek Můžeš snadno použít slovníky gettextu, translator je umí načítat. Stačí je dát do správné složky a správně pojmenovat soubory, potom bys měl v panelu vidět, že se načetly. Loader se vybírá podle koncovky souboru.