Zend Framework

Zend_Translate_Adapter rerouting problem

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: 1.10.5
  • Fix Version/s: 1.10.6
  • Component/s: Zend_Translate
  • Labels:
    None

Description

Hello!

When there are 2 (or more) untranslated MessageIDs (one directly after the other), I got only the first one translated in the "routed" "fallback" language.

it's about these lines of code:
"if (array_key_exists($locale, $this->_options['route']) &&
!array_key_exists($locale, $this->_routed)"
and:
"$this->_routed[$locale] = true;"
in line 738 - 740 (and also 683 - 685) of Zend/Translate/Adapter.php

Example:
to translate:
ID1 (available in user-language)
ID2 (not available in user-language, routing to standard-language)
ID3 (not available in user-language, routing to standard-language)

ID1 is found in user-language-source and successfully returned - OK!

ID2 is NOT found in user-language-source;
setting "$this->_routed[USER_LANGUAGE] = true" and successfully return text from standard language - OK

ID3 is NOT found in user-language-source;
"$this->_routed[USER_LANGUAGE]" already is true
in lines 738/739 we have:
"if (array_key_exists($locale, $this->_options['route']) &&
!array_key_exists($locale, $this->_routed)"
an because of "!array_key_exists($locale, $this->_routed)"
we won't route, because we thougth, we already did...
we don't return the translation from the standard language, so
only the MessageID (ID3) will be returned...
-ERROR!!!

it's eroneous, that "$this->_routed" will be resetted AFTER:
"return $this->translate($messageId, $this->_options['route'][$locale]);
}"
by
"$this->_routed = array();" in line 744
but because of that "return $this->translate(..." we don't reach that point.

Best regards,
René Kerner.

Activity

Hide
Thomas Weidner added a comment -

The code works as expected. It would be nice if you give a real example instead of framework code.

This is a simple recursive methodcall as used in many other components and projects. When you follow the workflow you would see that _route is resetted before the rerouted translation is returned.

I can't see a failure wether in code nor within the testbed which tests the code.

Show
Thomas Weidner added a comment - The code works as expected. It would be nice if you give a real example instead of framework code. This is a simple recursive methodcall as used in many other components and projects. When you follow the workflow you would see that _route is resetted before the rerouted translation is returned. I can't see a failure wether in code nor within the testbed which tests the code.
Hide
René Kerner added a comment -

Ok, I'll explain a bit precisely.

In my application german (de) is the standard-locale and the german language-file would always be the complete one. for test-reasons, i changed my firefox-language-option to "en", so Zend_Locale retrieves english as the actual locale. but it's not completly translated.
so i wanted to reroute "en" to "de" if the identifiers aren't found in the "en"-languagefile.

application.ini
...

;----------------------------
; Zend_Locale
;----------------------------
resources.locale.default = "de"

;----------------------------
; Zend_Translate
;----------------------------
resources.translate.adapter = "Tacticx_Translate_Adapter_Gettext"
resources.translate.data = APPLICATION_PATH "/languages"
resources.translate.default = "de"
resources.translate.locale = "auto"
resources.translate.route.en = "de"
resources.translate.options.disableNotices = false
resources.translate.options.logUntranslated = true
resources.translate.options.scan = "directory"
resources.translate.options.ignore[] = "."
resources.translate.options.ignore.regex = "/\.po$/i"

...
Bootstrap.php
protected function _initTranslation()
    {
        $this->bootstrap('locale');
        $this->bootstrap('translate');
        $translate = Zend_Registry::get('Zend_Translate');
        $writer = new Zend_Log_Writer_Stream(APPLICATION_ROOT_PATH
                . '/data/logs/translation.log');
        $log = new Zend_Log($writer);
        // Diese der Übersetzungs-Instanz hinzufügen
        $translate->setOptions(array('log' => $log));
    }

    protected function _initNavigationMenu()
    {
        $this->bootstrap('locale');
        $this->bootstrap('translate');
        $this->bootstrap('translation');
        require_once(APPLICATION_ROOT_PATH . DIRECTORY_SEPARATOR . 'data'
                    . DIRECTORY_SEPARATOR . 'menu' . DIRECTORY_SEPARATOR
                    . 'menu.inc.php');
        // only stores an navigation-menu array in variable $menu
        Zend_Registry::set('Zend_Navigation', $menu);
data/menu/menu.php
$menu = new Zend_Navigation(
array(
    array(
        'label' => 'navigation::home',
        'uri' => '/',
        'pages' => array(
                       array(
                           'label' => 'navigation::login',
                           'controller' => 'access',
                       ),
                       array(
                           'label' => 'navigation::logout',
                           'action' => 'logout',
                           'controller' => 'access',
                       )
        ),
    ),
    array(
        'label' => 'navigation::organization_editor',
        'module' => 'mgr',
        'action' => 'index',
        'controller' => 'organization',
    ),

...

as you can see, the navigation labels are "identifiers", which should be translated by Zend_Translate.

The Zend_View_Helper_SOMETHING is used to create the menu-structure and there the labels got translated.

In that example the View_Helper_???... (i'm @home at the moment and can't say, which is used. tomorrow i'll again debug that and add that information) gets the Translator (I expect Zend_Translate from Zend_Registry) and calls ->translate("navigation::login");
locale is null and gets the currently user-locale (line 656, Zend/Translate/Adapter.php).

the next lines until line 707 are skipped, because the conditions don't match.
after that, because of missing languagefile-entries in the english-language-file, the next lines are skipped (conditions don't match) until line 735/736:

$this->_log($messageId, $locale);
        // use rerouting when enabled

then we come to the routing-part (lines 737 - 745):

if (!empty($this->_options['route'])) // isn't empty --> true
        {  // --> go in that if
            if (array_key_exists($locale, $this->_options['route']) &&  // exists --> true 
                !array_key_exists($locale, $this->_routed))         // doesn't exists --> true
            {   // --> go in that if
                $this->_routed[$locale] = true; // for that translator-object (let's call it: TO1) we set routed["en"] to true
                return $this->translate($messageId, $this->_options['route'][$locale]); // we call ->translate("...", "de") and it will return the right german languagefile-entry for that identifier
            }

            $this->_routed = array();  // is not called, because of "return $this->translate(...)" before
        }

in that navigation-menu, the next identifier also isn't translated in the english-language-file.

so we are in the same helper and have the same translator-object (TO1), which "$this->_routed[$locale]" value is still not resetted (I debugged that!!!). so: $this->_routed["en"] is true.

the view helper now calls with that translator (TO1) ->translate("the_next_identifier");
as before no line matches one of the if-conditions and we come to lines 737 - 745:

if (!empty($this->_options['route'])) // isn't empty --> true
        {  // --> go in that if
            if (array_key_exists($locale, $this->_options['route']) &&  // exists --> true 
                !array_key_exists($locale, $this->_routed))         // already EXISTS --> false
            {   // --> NOT go in that if
                $this->_routed[$locale] = true;
                return $this->translate($messageId, $this->_options['route'][$locale]);
            }

            $this->_routed = array();  // now it's resetted, but we didn't translate that identifier. for that translator-object only the next identifier will be translated...
        }

the reason is, that the reset:

$this->_routed = array();

is only resetted on three positions:
line 53, on initialization: private $_routed = array();
line 689, $this->_routed = array(); after Zend_Locale::isLocale-checks
line 744, $this->_routed = array(); after rerouting

more specific code-examples I can only support from work tomorrow.

what code examples do you need?

best regards,
rené

Show
René Kerner added a comment - Ok, I'll explain a bit precisely. In my application german (de) is the standard-locale and the german language-file would always be the complete one. for test-reasons, i changed my firefox-language-option to "en", so Zend_Locale retrieves english as the actual locale. but it's not completly translated. so i wanted to reroute "en" to "de" if the identifiers aren't found in the "en"-languagefile.
application.ini
...

;----------------------------
; Zend_Locale
;----------------------------
resources.locale.default = "de"

;----------------------------
; Zend_Translate
;----------------------------
resources.translate.adapter = "Tacticx_Translate_Adapter_Gettext"
resources.translate.data = APPLICATION_PATH "/languages"
resources.translate.default = "de"
resources.translate.locale = "auto"
resources.translate.route.en = "de"
resources.translate.options.disableNotices = false
resources.translate.options.logUntranslated = true
resources.translate.options.scan = "directory"
resources.translate.options.ignore[] = "."
resources.translate.options.ignore.regex = "/\.po$/i"

...
Bootstrap.php
protected function _initTranslation()
    {
        $this->bootstrap('locale');
        $this->bootstrap('translate');
        $translate = Zend_Registry::get('Zend_Translate');
        $writer = new Zend_Log_Writer_Stream(APPLICATION_ROOT_PATH
                . '/data/logs/translation.log');
        $log = new Zend_Log($writer);
        // Diese der Übersetzungs-Instanz hinzufügen
        $translate->setOptions(array('log' => $log));
    }

    protected function _initNavigationMenu()
    {
        $this->bootstrap('locale');
        $this->bootstrap('translate');
        $this->bootstrap('translation');
        require_once(APPLICATION_ROOT_PATH . DIRECTORY_SEPARATOR . 'data'
                    . DIRECTORY_SEPARATOR . 'menu' . DIRECTORY_SEPARATOR
                    . 'menu.inc.php');
        // only stores an navigation-menu array in variable $menu
        Zend_Registry::set('Zend_Navigation', $menu);
data/menu/menu.php
$menu = new Zend_Navigation(
array(
    array(
        'label' => 'navigation::home',
        'uri' => '/',
        'pages' => array(
                       array(
                           'label' => 'navigation::login',
                           'controller' => 'access',
                       ),
                       array(
                           'label' => 'navigation::logout',
                           'action' => 'logout',
                           'controller' => 'access',
                       )
        ),
    ),
    array(
        'label' => 'navigation::organization_editor',
        'module' => 'mgr',
        'action' => 'index',
        'controller' => 'organization',
    ),

...
as you can see, the navigation labels are "identifiers", which should be translated by Zend_Translate. The Zend_View_Helper_SOMETHING is used to create the menu-structure and there the labels got translated. In that example the View_Helper_???... (i'm @home at the moment and can't say, which is used. tomorrow i'll again debug that and add that information) gets the Translator (I expect Zend_Translate from Zend_Registry) and calls ->translate("navigation::login"); locale is null and gets the currently user-locale (line 656, Zend/Translate/Adapter.php). the next lines until line 707 are skipped, because the conditions don't match. after that, because of missing languagefile-entries in the english-language-file, the next lines are skipped (conditions don't match) until line 735/736:
$this->_log($messageId, $locale);
        // use rerouting when enabled
then we come to the routing-part (lines 737 - 745):
if (!empty($this->_options['route'])) // isn't empty --> true
        {  // --> go in that if
            if (array_key_exists($locale, $this->_options['route']) &&  // exists --> true 
                !array_key_exists($locale, $this->_routed))         // doesn't exists --> true
            {   // --> go in that if
                $this->_routed[$locale] = true; // for that translator-object (let's call it: TO1) we set routed["en"] to true
                return $this->translate($messageId, $this->_options['route'][$locale]); // we call ->translate("...", "de") and it will return the right german languagefile-entry for that identifier
            }

            $this->_routed = array();  // is not called, because of "return $this->translate(...)" before
        }
in that navigation-menu, the next identifier also isn't translated in the english-language-file. so we are in the same helper and have the same translator-object (TO1), which "$this->_routed[$locale]" value is still not resetted (I debugged that!!!). so: $this->_routed["en"] is true. the view helper now calls with that translator (TO1) ->translate("the_next_identifier"); as before no line matches one of the if-conditions and we come to lines 737 - 745:
if (!empty($this->_options['route'])) // isn't empty --> true
        {  // --> go in that if
            if (array_key_exists($locale, $this->_options['route']) &&  // exists --> true 
                !array_key_exists($locale, $this->_routed))         // already EXISTS --> false
            {   // --> NOT go in that if
                $this->_routed[$locale] = true;
                return $this->translate($messageId, $this->_options['route'][$locale]);
            }

            $this->_routed = array();  // now it's resetted, but we didn't translate that identifier. for that translator-object only the next identifier will be translated...
        }
the reason is, that the reset:
$this->_routed = array();
is only resetted on three positions: line 53, on initialization: private $_routed = array(); line 689, $this->_routed = array(); after Zend_Locale::isLocale-checks line 744, $this->_routed = array(); after rerouting more specific code-examples I can only support from work tomorrow. what code examples do you need? best regards, rené
Hide
René Kerner added a comment -

wrong translation example (application code follows!)

Show
René Kerner added a comment - wrong translation example (application code follows!)
Hide
René Kerner added a comment -

now some explanation for my screenshots:

I hava a StartController with an index-action.

application/views/scripts/start/index.phtml
STARTSEITE<br />
<?php
echo $this->translate('test1') . '<br />' . PHP_EOL;
echo $this->translate('test2') . '<br />' . PHP_EOL;
echo $this->translate('test3') . '<br />' . PHP_EOL;
echo $this->translate('test4') . '<br />' . PHP_EOL;
echo $this->translate('test5') . '<br />' . PHP_EOL;
echo $this->translate('test6') . '<br />' . PHP_EOL;
echo $this->translate('test7') . '<br />' . PHP_EOL;
echo $this->translate('test8') . '<br />' . PHP_EOL;
echo $this->translate('test9') . '<br />' . PHP_EOL;
echo $this->translate('test10') . '<br />' . PHP_EOL;
echo $this->translate('test11') . '<br />' . PHP_EOL;
echo $this->translate('test12') . '<br />' . PHP_EOL;
echo $this->translate('test13') . '<br />' . PHP_EOL;
echo $this->translate('test14') . '<br />' . PHP_EOL;

In german PO/MO-files I translated identifiers test1 - test4 and test7 - test12. test5, test6, test13 and test14 aren't translated.
This is correctly shown in picture one: "TRANSLATE_DE.png"

Then I switched my browser LANGUAGE_ACCEPT to "English [en]" and Zend_Locale will give this to Zend_Translate.
In the english languagefile nothing is translated at this time.

This should look like picture one and there should always be the german translation:
ü1 - ü4
test5, test6
ü7 - ü12
test13, test14
BUT I got:
ü1 - OK
test2 - ERROR
ü3 - OK
test4 - ERROR
test5 - OK
test6 - OK
ü7 - OK
test8 - ERROR
ü9 - OK
test10 - ERROR
ü11 - OK
test12 - ERROR
test13 - OK
test14 - OK
As you can see, only every second untranslated translation is correctly routed!

Then I translated some identifiers in the english languagefile, but only identifiers test4 - test7.
As you can see,

I should get:
ü1 - ü3
en4 - en7
ü8 - ü12
test13, test14

BUT I got:
ü1 - OK
test2 - ERROR
ü3 - OK
en4 - OK
en5 - OK
en6 - OK
en7 - OK
test8 - ERROR
ü9 - OK
test10 - ERROR
ü11 - OK
test12 - ERROR
test13 - OK
test14 - OK

So you can see only every second translation in case of language-rerouting is correct.

The reason is in the recursion.
Because of the RETURN command in "return $this->translate($messageId, $route_language)" the reset of $this->_routed[$routed_language] will only be reseted in a later call of $this->translate() for the next identifier. The right solution would be to save the returned value of the $this->translate($messageId, $route_language) to a variable. Then after the recursion reset or in code "unset($this->_routed[$currently_routed_language])". So you can prevent endless recursion in cyclic routing definitions (like EN => DE => FR => EN) when the identifier is not found.

And more precisly in german / Und auf Deutsch:
Es liegt daran, wie ich bereits beschrieben habe, dass im beim re-routen der rekursive Abstieg direkt mit einem RETURN gemacht wird.
Richtig wäre doch, das Ergebnis des rekursiven Abstiegs von $this->translate($messageId, $route_language) in eine variable zu speichern.
Nach erfolgreichem rekursivem Aufstieg "unset($this->_routed[$geroutete_sprache])" zu machen. und dann erst das RETURN.
So kann man verhindern, dass es eine endlose Rekursionschleife gibt, wenn der Bezeichner/Identifier bei einer zyklischen Routen-Definition (z.B. EN => DE => FR => EN) nicht gefunden wird.

Show
René Kerner added a comment - now some explanation for my screenshots: I hava a StartController with an index-action.
application/views/scripts/start/index.phtml
STARTSEITE<br />
<?php
echo $this->translate('test1') . '<br />' . PHP_EOL;
echo $this->translate('test2') . '<br />' . PHP_EOL;
echo $this->translate('test3') . '<br />' . PHP_EOL;
echo $this->translate('test4') . '<br />' . PHP_EOL;
echo $this->translate('test5') . '<br />' . PHP_EOL;
echo $this->translate('test6') . '<br />' . PHP_EOL;
echo $this->translate('test7') . '<br />' . PHP_EOL;
echo $this->translate('test8') . '<br />' . PHP_EOL;
echo $this->translate('test9') . '<br />' . PHP_EOL;
echo $this->translate('test10') . '<br />' . PHP_EOL;
echo $this->translate('test11') . '<br />' . PHP_EOL;
echo $this->translate('test12') . '<br />' . PHP_EOL;
echo $this->translate('test13') . '<br />' . PHP_EOL;
echo $this->translate('test14') . '<br />' . PHP_EOL;
In german PO/MO-files I translated identifiers test1 - test4 and test7 - test12. test5, test6, test13 and test14 aren't translated. This is correctly shown in picture one: "TRANSLATE_DE.png" Then I switched my browser LANGUAGE_ACCEPT to "English [en]" and Zend_Locale will give this to Zend_Translate. In the english languagefile nothing is translated at this time. This should look like picture one and there should always be the german translation: ü1 - ü4 test5, test6 ü7 - ü12 test13, test14 BUT I got: ü1 - OK test2 - ERROR ü3 - OK test4 - ERROR test5 - OK test6 - OK ü7 - OK test8 - ERROR ü9 - OK test10 - ERROR ü11 - OK test12 - ERROR test13 - OK test14 - OK As you can see, only every second untranslated translation is correctly routed! Then I translated some identifiers in the english languagefile, but only identifiers test4 - test7. As you can see, I should get: ü1 - ü3 en4 - en7 ü8 - ü12 test13, test14 BUT I got: ü1 - OK test2 - ERROR ü3 - OK en4 - OK en5 - OK en6 - OK en7 - OK test8 - ERROR ü9 - OK test10 - ERROR ü11 - OK test12 - ERROR test13 - OK test14 - OK So you can see only every second translation in case of language-rerouting is correct. The reason is in the recursion. Because of the RETURN command in "return $this->translate($messageId, $route_language)" the reset of $this->_routed[$routed_language] will only be reseted in a later call of $this->translate() for the next identifier. The right solution would be to save the returned value of the $this->translate($messageId, $route_language) to a variable. Then after the recursion reset or in code "unset($this->_routed[$currently_routed_language])". So you can prevent endless recursion in cyclic routing definitions (like EN => DE => FR => EN) when the identifier is not found. And more precisly in german / Und auf Deutsch: Es liegt daran, wie ich bereits beschrieben habe, dass im beim re-routen der rekursive Abstieg direkt mit einem RETURN gemacht wird. Richtig wäre doch, das Ergebnis des rekursiven Abstiegs von $this->translate($messageId, $route_language) in eine variable zu speichern. Nach erfolgreichem rekursivem Aufstieg "unset($this->_routed[$geroutete_sprache])" zu machen. und dann erst das RETURN. So kann man verhindern, dass es eine endlose Rekursionschleife gibt, wenn der Bezeichner/Identifier bei einer zyklischen Routen-Definition (z.B. EN => DE => FR => EN) nicht gefunden wird.
Hide
René Kerner added a comment -

wrong screenshot replaced

Show
René Kerner added a comment - wrong screenshot replaced
Hide
René Kerner added a comment -

In my project I'm using a self extended Zend_Translate_Adaper_Gettext. It's called Tacticx_Translate_Adaper_Gettext.
It's not the right place because it should be in a Tacticx_Translate_Adaper class, but for me it's acceptable there atm.
Here is an example for a corrected Zend/Translate/Adapter.php
I only show the added function and the corrected translate(...)-function.

Zend/Translate/Adapter.php - only with the correction!
private function _routeTranslate($_messageId, $_locale)
    {
        $this->_routed[$_locale] = true;
        $foreign_lang = $this->translate($_messageId, $this->_options['route'][$_locale]);
        unset($this->_routed[$_locale]);
        if(!isset($this->_routed))
            $this->_routed = array();
        return $foreign_lang;
    }

    /**
     * Translates the given string
     * returns the translation
     *
     * @see Zend_Locale
     * @param  string|array       $messageId Translation string, or Array for plural translations
     * @param  string|Zend_Locale $locale    (optional) Locale/Language to use, identical with
     *                                       locale identifier, @see Zend_Locale for more information
     * @return string
     */
    public function translate($messageId, $locale = null)
    {
        if($locale === null)
            $locale = $this->_options['locale'];
        $plural = null;
        if(is_array($messageId))
        {
            if(count($messageId) > 2)
            {
                $number = array_pop($messageId);
                if(!is_numeric($number))
                {
                    $plocale = $number;
                    $number  = array_pop($messageId);
                }
                else
                    $plocale = 'en';

                $plural    = $messageId;
                $messageId = $messageId[0];
            }
            else
                $messageId = $messageId[0];
        }

        // check if chosen locale is a valid locale
        if(!Zend_Locale::isLocale($locale, true, false))
        {
            if (!Zend_Locale::isLocale($locale, false, false))
            {
                // language does not exist, return original string
                $this->_log($messageId, $locale);
                // use rerouting when enabled
                if(!empty($this->_options['route']))
                {
                    if(array_key_exists($locale, $this->_options['route']) &&
                        !array_key_exists($locale, $this->_routed))
                    {
                        return $this->_routeTranslate($messageId, $locale);
                    }
                    $this->_routed = array();
                }

                if($plural === null)
                    return $messageId;

                $rule = Zend_Translate_Plural::getPlural($number, $plocale);
                if(!isset($plural[$rule]))
                    $rule = 0;
                return $plural[$rule];
            }
            $locale = new Zend_Locale($locale);
        }

        $locale = (string) $locale;
        if((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId]))
        {
            // return original translation
            if($plural === null)
                return $this->_translate[$locale][$messageId];
            $rule = Zend_Translate_Plural::getPlural($number, $locale);
            if(isset($this->_translate[$locale][$plural[0]][$rule]))
                return $this->_translate[$locale][$plural[0]][$rule];
        }
        else if(strlen($locale) != 2)
        { // faster than creating a new locale and separate the leading part
            $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));

            if((is_string($messageId) || is_int($messageId))
                && isset($this->_translate[$locale][$messageId]))
            { // return regionless translation (en_US -> en)
                if($plural === null)
                    return $this->_translate[$locale][$messageId];
                $rule = Zend_Translate_Plural::getPlural($number, $locale);
                if (isset($this->_translate[$locale][$plural[0]][$rule]))
                    return $this->_translate[$locale][$plural[0]][$rule];
            }
        }

        $this->_log($messageId, $locale);
        // use rerouting when enabled
        if (!empty($this->_options['route']))
        {
            if (array_key_exists($locale, $this->_options['route']) &&
                !array_key_exists($locale, $this->_routed))
            {
                return $this->_routeTranslate($messageId, $locale);
            }
            $this->_routed = array();
        }
        if ($plural === null)
            return $messageId;

        $rule = Zend_Translate_Plural::getPlural($number, $plocale);
        if (!isset($plural[$rule]))
            $rule = 0;
        return $plural[$rule];
    }
Show
René Kerner added a comment - In my project I'm using a self extended Zend_Translate_Adaper_Gettext. It's called Tacticx_Translate_Adaper_Gettext. It's not the right place because it should be in a Tacticx_Translate_Adaper class, but for me it's acceptable there atm. Here is an example for a corrected Zend/Translate/Adapter.php I only show the added function and the corrected translate(...)-function.
Zend/Translate/Adapter.php - only with the correction!
private function _routeTranslate($_messageId, $_locale)
    {
        $this->_routed[$_locale] = true;
        $foreign_lang = $this->translate($_messageId, $this->_options['route'][$_locale]);
        unset($this->_routed[$_locale]);
        if(!isset($this->_routed))
            $this->_routed = array();
        return $foreign_lang;
    }

    /**
     * Translates the given string
     * returns the translation
     *
     * @see Zend_Locale
     * @param  string|array       $messageId Translation string, or Array for plural translations
     * @param  string|Zend_Locale $locale    (optional) Locale/Language to use, identical with
     *                                       locale identifier, @see Zend_Locale for more information
     * @return string
     */
    public function translate($messageId, $locale = null)
    {
        if($locale === null)
            $locale = $this->_options['locale'];
        $plural = null;
        if(is_array($messageId))
        {
            if(count($messageId) > 2)
            {
                $number = array_pop($messageId);
                if(!is_numeric($number))
                {
                    $plocale = $number;
                    $number  = array_pop($messageId);
                }
                else
                    $plocale = 'en';

                $plural    = $messageId;
                $messageId = $messageId[0];
            }
            else
                $messageId = $messageId[0];
        }

        // check if chosen locale is a valid locale
        if(!Zend_Locale::isLocale($locale, true, false))
        {
            if (!Zend_Locale::isLocale($locale, false, false))
            {
                // language does not exist, return original string
                $this->_log($messageId, $locale);
                // use rerouting when enabled
                if(!empty($this->_options['route']))
                {
                    if(array_key_exists($locale, $this->_options['route']) &&
                        !array_key_exists($locale, $this->_routed))
                    {
                        return $this->_routeTranslate($messageId, $locale);
                    }
                    $this->_routed = array();
                }

                if($plural === null)
                    return $messageId;

                $rule = Zend_Translate_Plural::getPlural($number, $plocale);
                if(!isset($plural[$rule]))
                    $rule = 0;
                return $plural[$rule];
            }
            $locale = new Zend_Locale($locale);
        }

        $locale = (string) $locale;
        if((is_string($messageId) || is_int($messageId)) && isset($this->_translate[$locale][$messageId]))
        {
            // return original translation
            if($plural === null)
                return $this->_translate[$locale][$messageId];
            $rule = Zend_Translate_Plural::getPlural($number, $locale);
            if(isset($this->_translate[$locale][$plural[0]][$rule]))
                return $this->_translate[$locale][$plural[0]][$rule];
        }
        else if(strlen($locale) != 2)
        { // faster than creating a new locale and separate the leading part
            $locale = substr($locale, 0, -strlen(strrchr($locale, '_')));

            if((is_string($messageId) || is_int($messageId))
                && isset($this->_translate[$locale][$messageId]))
            { // return regionless translation (en_US -> en)
                if($plural === null)
                    return $this->_translate[$locale][$messageId];
                $rule = Zend_Translate_Plural::getPlural($number, $locale);
                if (isset($this->_translate[$locale][$plural[0]][$rule]))
                    return $this->_translate[$locale][$plural[0]][$rule];
            }
        }

        $this->_log($messageId, $locale);
        // use rerouting when enabled
        if (!empty($this->_options['route']))
        {
            if (array_key_exists($locale, $this->_options['route']) &&
                !array_key_exists($locale, $this->_routed))
            {
                return $this->_routeTranslate($messageId, $locale);
            }
            $this->_routed = array();
        }
        if ($plural === null)
            return $messageId;

        $rule = Zend_Translate_Plural::getPlural($number, $plocale);
        if (!isset($plural[$rule]))
            $rule = 0;
        return $plural[$rule];
    }
Hide
Thomas Weidner added a comment -

Please write your issues in english and not in other languages which people don't understand. Thnx.

Fixed with r22425.

Show
Thomas Weidner added a comment - Please write your issues in english and not in other languages which people don't understand. Thnx. Fixed with r22425.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: