Issues

ZF-8694: Zend_Form_Decorator_Label Attempts to Translate Labels Twice

Description

There exists an issue with Zend_Form translating labels which becomes apparent when Zend_Translate logging is enabled.

When a form is rendered the form loops through the decorators running their render method. The following code is called as a result of rendering the label.

Zend_Form_Decorator_Label Line #253


        $label = $element->getLabel();
        $label = trim($label);

        if (empty($label)) {
            return '';
        }

        if (null !== ($translator = $element->getTranslator())) {
            $label = $translator->translate($label);
        }

The above code retrieves the label from the element object and the runs validation methods and then proceeds to translate the message. Below is the code for the $element->getLabel() method.

Zend_Form_Element Line #606


    public function getLabel()
    {
        $translator = $this->getTranslator();
        if (null !== $translator) {
            return $translator->translate($this->_label);
        }

        return $this->_label;
    }

As you can see this method ALSO translates the text before sending it back to the decorator. This means the Element object is returning translated text back to the decorator which then is attempting to translate already translated text. This causes the Zend_Translate class to log a notice in its log file notifying the user it is missing a translation.

The fix is an obvious one, simply removing the duplicate code from the Zend_Form_Decorator_Label dealing with translation will solve the problem as their corresponding elements should already be translating the content for them.

Please note this also is affecting the Submit button and I have not been able to trace which decorator is causing that problem, although I assume the problem is the same. You will probably want to check through all of the decorators to check if any others are doing the same.

Brad

Comments

With reference to the final note about the Submit button, this has been reported as ZF-8764.

For us this issue is very important, as far as we have an interactive translation mode. It allows to change the site texts right where you see them in the graphical user interface. To do this we have to append stuff to translated strings on the runtime. Like this:


<?php

set_include_path(
    implode(
        PATH_SEPARATOR,
        array(dirname(__FILE__) . '/library', get_include_path())
    )
);

require_once 'Zend/Loader/Autoloader.php';

Zend_Loader_Autoloader::getInstance()->registerNamespace('Zend_');

class TrickyAdapter extends Zend_Translate_Adapter_Array {
    public function translate($messageId, $locale = null) {
        return parent::translate($messageId, $locale) . '[XY]';
    }
}

Zend_Registry::set(
    'Zend_Translate',
    new Zend_Translate('TrickyAdapter', array('en' => array()))
);

function simple_form() {
    return new Zend_Form(
        array(
            'method' => 'post',
            
            'elements' => array(
                'title' => array(
                    'type' => 'text',
                    
                    'options' => array(
                        'label' => 'Bug title',
                    )
                ),
                
                'submit' => array(
                    'type' => 'button',
                    'options' => array(
                        'label' => 'Send',
                        'type' => 'submit',
                    )
                ),
            )
        )
    );
}

echo "\n" . simple_form()->render(new Zend_View()) . "\n\n";

Under ZF 1.9.7 the code above outputs:


Bug title[XY]   Send[XY]

While under ZF 1.10.0 and 1.10.1 it's:


Bug title[XY][XY]   Send[XY][XY]

The question is whether the translation should be restricted to the element's or the Label decorator's getLabel() method. I think it makes the most sense to place the translation in the decorator - as close to the user as possible, but I am not sure if this change will break anything depending on the element doing the translation.

The only legitimate place to translate the value is where the value is received - i.e. in element's getLabel() method. Decorator's purpose is to receive some value and wrap it around the current content. Not tu modify it in any way.

This can be fixed fast, by commenting these lines

  • Zend_Form_Element_Submit - Line 80 to 83 <-- These most be also commented since you already call the parent method get label, which will result in a double translation from Zend_Form_Element
  • Zend_Form_Decorator_Label - Line 260 to 263 <-- Decorator should not be used for translation, it is out of purpose

OK, it's bug hunt days again. Time to bump this issue. Any chance to see it fixed this time? It's been around for ages, as well as the proposed simple fix, like in the previous comment.

BTW, the issue with Zend_Form_Element_Submit has been silently fixed in the meantime, but it still occurs with Zend_Form_Decorator_Label.

Patch attached. Holger - where did you check that the issue with {{Zend_Form_Element_Submit}} has been already fixed. It wasn't in my trunk.

It has not been fixed in Zend_Form_Element_Submit itself - in fact, removing the translate() call there would result in an untranslated label. Something else in the code path has changed so that now only Zend_Form_Decorator_Label is still affected.

I don't know where this change has been made and whether the new behavior is intentional or just happened to stop the bug from occurring. The facts are: with the current implementation, the label gets translated once for Zend_Form_Element_Submit::getLabel() (correct) and twice for Zend_Form_Decorator_Label::getLabel() (incorrect). This might need more investigation, but removing the translate() call from Zend_Form_Decorator_Label::getLabel() would at least be an interim solution that actually works. It could easily be reverted if it turns out to be the wrong place for the fix.

The fix has been proposed and known to work flawlessly by several users for a long time, so I think it would be safe to provide it as a working solution. There are already discussions about restructuring and where translations should actually be done, but that's more of a long term goal.

Somewhere between 1.11.7 and 1.11.10, a change to Zend_Form_Element_Submit was introduced. The label no longer gets translated if the patch to Zend_Form_Decorator_Label is applied. If that patch is reverted, the problem with the double-translated labels shows up again.

An updated patch that works for 1.11.10 is available at http://svn.savannah.nongnu.org/viewvc/checkout/…

The updated patch of Holger works also fine for me in v1.11.11. Thanks!

Got an entire day wasted figuring out why my label is translated into the wrong text.

For example we got a tag english "or" Translated to dutch to "of" Got translated again english "of" to "van"

Please fix this with the remove translate from the decorator label. That seems to be the right solution.

btw the latest svn revision 24561 still has this problem

Removing the translate code block from: Form/Decorator/Label.php Form/Decorator/Description.php Form/Element/Submit.php

Since translate happen in Form/Element.php, It works fine in my application and solve this issue in v1.11.11 i believe

No updates??

Any updates? The bug is still existent in 1.12.0

@[~ice-breaker] The patch needs a review by the cr-team.

Hi,

While it's still under review, I would propose the following fix for the Zend_Form_Element Class.

The below allows to pass an arg (named "translation_params" in the proposed fix) through the "attribs" property of the form element that will be used as the variables within the label. In our case, this was necessary because labels may depend on some vars, so we needed a way to pass this vars to the the translator. As the translator doesn't handle vars per default, I had to use the view helper which already handles that.

public function getLabel()
{
    // if there is a label to translate,
    // then we check for a valid translator to perform the translation
    if ( $this->_label !== null
            && null !== ($translator = $this->getTranslator())) {
        return $this->getView()->translate(
                $this->_label,
                $this->getAttrib('translation_params')
            );
    }

    return $this->_label;

}

Regards, Frej.

  • {{Zend_Form_Element_Submit}} was fixed with ZF-8764.
  • {{Zend_Form_Element}} contains no translation in the {{getDescription()}} method.
  • Only {{Zend_Form_Decorator_Label}} needs an update.

Fixed on trunk (25242) and release-1.12 (25243)

(Unit test for Description decorator included.)