i18n a l10n?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
mh
Člen | 1
+
0
-

Nette neumí lokalizaci?

David Grudl
Nette Core | 8218
+
0
-

Co bys konkrétně potřeboval udělat?

brablc
Člen | 6
+
0
-

David Grudl napsal(a):

Co bys konkrétně potřeboval udělat?

Tak třeba my jsme potřebovali vyřešit problém s parametrizovanými překlady:

{_'There are %2$d messages for user %1$s', 'test', 10}

Kolegové to vyřešili takto:

class NjoyTranslator implements /*Nette\*/ITranslator
{
    ...

    public function translate($message, $plural = NULL)
    {
        if (isset($this->dictionary[$message]))
            $message = $this->dictionary[$message];

        $pars = func_get_args();

        if (count($pars)>1) {
            array_shift($pars);
            return vsprintf($message, $pars);
        }

        return $message;
    }
}

Parametr $plural je sám o sobě nedostatečný (viz http://www.gnu.org/…gettext.html#… ), proto jsme si dovolili ho ignorovat.

brablc
Člen | 6
+
0
-

Ještě bychom potřebovali něco jako neescapovany translate:

{!_'Please click here to view your <a href="/orderstatus.php">order status</a>.'}.

S naším rozšířením o parametry potom ještě přichází otázka, zda-li je lepší

{!_'Please click here to view your <a href="%s">order status</a>.', '/orderstatus.php'}.

nebo

{!_'Please click here to view your %sorder status%s.', '<a href="/orderstatus.php">',  '</a>'}.

Samozřejmě, že tu je vždy alternativa rozsekat to na spoustu řetězců, ale to není ideální z pohledu překladatele.

Jod
Člen | 701
+
0
-

A skúšali ste tanslator od Zendu?

brablc
Člen | 6
+
0
-

Jod napsal(a):

A skúšali ste tanslator od Zendu?

Teď nevím, jestli to je otázka na nás, pokud ano tak tohle není problém použitého adaptéru, ale problém rozhraní Nette\ITranslator a funkčnosti CurlyBracketsFilter. Naštěstí pro nás jsou všechny dodatečné parametry použity při volání translate metody, takže parametrizace dotazů nám funguje. Pokud se rozšíření CurlyBracketsFilter týká, tak tady navrhujeme patch:

Index: CurlyBracketsFilter.php
===================================================================
--- CurlyBracketsFilter.php     (revision 181)
+++ CurlyBracketsFilter.php     (working copy)
@@ -32,6 +32,7 @@
  * - {!=expression} echo without escaping
  * - {?expression} evaluate PHP statement
  * - {_expression} echo with escaping and translation
+ * - {!_expression} echo with translation and without escaping
  * - {link destination ...} control link
  * - {plink destination ...} presenter link
  * - {ajaxlink destination ...} ajax link
@@ -90,6 +91,7 @@

                '!=' => '<?php echo # ?>',
                '_' => '<?php echo $template->{$_cb->escape}($template->translate(#)) ?>',
+               '!_' => '<?php echo $template->translate(#) ?>',
                '=' => '<?php echo $template->{$_cb->escape}(#) ?>',
                '!$' => '<?php echo # ?>',
                '!' => '<?php echo # ?>',

Mimochodem, translátor od Zendu s gettext adaptérem jsme zkoušeli, ale je to trošku řešení přes ruku, navíc gettext parsuje binárně .mo soubory a natahuje řetězce do paměti, takže efektivní to také moc není. Náš translátor tedy zatím řeší parametry překladu, zobrazení defaultní jazykové mutace, pokud překlad chybí a nabízí základní podporu kontextu:

<?php

class NjoyTranslator implements /*Nette\*/ITranslator
{
    protected $dictPref;
    protected $dictDef;
    protected $filePref;
    protected $fileDef;

    /**
     * @param  string  file with associative array called $dictionary]
     */
    public function __construct($preferredDictionaryFile, $defaultDictionaryFile)
    {
        $this->filePref = $preferredDictionaryFile;
        $this->fileDef = $defaultDictionaryFile;
    }

    /**
     * Translates the given string.
     * @param  string   message
     * @param  int      plural
     * @return string
     */
    public function translate($message, $plural = NULL)
    {
        if (!$this->dictPref) {
            require_once($this->filePref);
            $this->dictPref = $dictionary;

            if ($this->filePref == $this->fileDef) {
                $this->dictDef = $this->dictPref;
            }
        }

        if (isset($this->dictPref[$message])) {
            $message = $this->dictPref[$message];
        }
        else {
            if (!$this->dictDef) {
                require_once($this->fileDef);
                $this->dictDef = $dictionary;
            }

            if (isset($this->dictDef[$message]))
                $message = $this->dictDef[$message];
            else if ( ($pos = strpos($message,'\\')) > 0)
                $message = substr($message, $pos+1);
        }

        $args = func_get_args();

        if (count($args)>1) {
            array_shift($args);
            return vsprintf($message, $args);
        }

        return $message;
    }
}
?>

Pokud překlad neexistuje, tak z defaultní mutace bude kontext (tedy vše před \\) odstraněn. Protože chceme psát delší odstavce pouze do překladových souborů a ve zdrojácích používat pouze identifikátory, tak plánujeme rozšíření kontexu například na:

'\\help\\how_to_change_password' => '...'

V takovém případě by se mohly překlady rozložit do více souborů, které by se jmenovaly podle svého kontextu a natahovaly by se do dictionary až v okamžiku potřeby. Ale těch možností, jak optimalizovat přebujelé překlady je spousta.

Takže když to shrnu, tak naše problémy s i18n jsou vyřešené (ale budeme rádi pokud dojde k přijetí našeho patche) a naše téměř minimalistické řešení uvedené výše by mělo být použitelné i pro ostatní, kteří neví, kde začít. Alespoň jako inspirace.

Jod
Člen | 701
+
0
-

To by sa dal taký translatátor pridať do distribúcie, ni? :)

David Grudl
Nette Core | 8218
+
0
-

brablc napsal(a):

Tak třeba my jsme potřebovali vyřešit problém s parametrizovanými překlady:

{_'There are %2$d messages for user %1$s', 'test', 10}

Kolegové to vyřešili takto:

Hezké řešení.

Parametr $plural je sám o sobě nedostatečný (viz http://www.gnu.org/…gettext.html#… ), proto jsme si dovolili ho ignorovat.

$plural je nevýstižný název, mělo by jít o počet prvků ($count by asi bylo lepší). Pokud by se překládala zpráva There are %d message, došlo by ke chtěnému vedlejšímu efektu – parametr počet by měl vlastně dvě funkce. Možná by bylo vhodné zprávy o více parametrech jako There are %2$d messages for user %1$s koncipovat tak, aby počet byl uveden jako druhý.

David Grudl
Nette Core | 8218
+
0
-

brablc napsal(a):

Takže když to shrnu, tak naše problémy s i18n jsou vyřešené (ale budeme rádi pokud dojde k přijetí našeho patche) a naše téměř minimalistické řešení uvedené výše by mělo být použitelné i pro ostatní, kteří neví, kde začít. Alespoň jako inspirace.

Už ho tam dávám. Vlastně jsem byl překvapen, že {!_ chybí ;)