[Enhancement] Add an easier way to use i18n view helpers. #2865

Closed
coolmic opened this Issue Oct 30, 2012 · 9 comments

Comments

Projects
None yet
5 participants
@coolmic
Contributor

coolmic commented Oct 30, 2012

hi, sorry for my bad English.

I have 2 issues.

If I use the translate helper :

echo $this->translate('hello');

and the translator is not set, it will throw an exception.

I am trying to make a reusable modules.
When I make French websites, I need the translator
But if I want to make English websites, I don't need it.
I guess the exception here is unnecessary.

The second issue, is the use of TextDomain.

I use one textDomain per modules, each module embed translation files.

If I want to generate a Form for example, I need to write

<?php
    $this->formLabel()->setTranslatorTextDomain('Ice\AdminAuth');
    $this->formElementErrors()->setTranslatorTextDomain('Ice\AdminAuth');
    $this->formInput()->setTranslatorTextDomain('Ice\AdminAuth');
    $this->formButton()->setTranslatorTextDomain('Ice\AdminAuth');
?>

<dl class="zend_form">
    <dt><?php echo $this->formLabel($form->get('name')) ?></dt>
    <dd><?php echo $this->formInput($form->get('name')) ?></dd>
    <?php echo $this->formElementErrors($form->get('name')) ?>

    <dt><?php echo $this->formLabel($form->get('password')) ?></dt>
    <dd><?php echo $this->formInput($form->get('password')) ?></dd>
    <?php echo $this->formElementErrors($form->get('password')) ?>

    <dd><?php echo $this->formButton($form->get('submit')) ?></dd>
</dl>

And if I use partials, the textdomain may be overwritten by another script.

I come with an idea : Why don't use another helper as Proxy.


use Zend\I18n\View\Helper\AbstractTranslatorHelper;
use Zend\I18n\Translator\TranslatorAwareInterface;

class TranslateProxy extends AbstractTranslatorHelper
{
    /**
     * @var array
     */
    protected $translatorTextDomainStack;


    public function __invoke($message = null, $textDomain = null, $locale = null)
    {
        if (is_null($message)) {
            return $this;
        }

        $translator = $this->getTranslator();
        if (null === $translator) {
            return $message;
        }

        if (null === $textDomain) {
            $textDomain = $this->getTranslatorTextDomain();
        }

        return $translator->translate($message, $textDomain, $locale);
    }

    public function pushTranslatorTextDomain($textDomain)
    {
        $this->translatorTextDomainStack[] = $this->getTranslatorTextDomain();
        $this->setTranslatorTextDomain($textDomain);
    }

    public function popTranslatorTextDomain()
    {
        $top = array_pop($this->translatorTextDomainStack);
        if (is_null($top)) {
            return null;
        }

        $prev = $this->getTranslatorTextDomain();
        $this->setTranslatorTextDomain($top);
        return $prev;
    }

    public function __call($name, $arguments) {
        $plugin = $this->getView()->plugin($name);

        if(!($plugin instanceof TranslatorAwareInterface)) {
            return call_user_func_array($plugin, $arguments);
        }

        $prevTextTranslator = $plugin->getTranslator();
        $prevTextDomain = $plugin->getTranslatorTextDomain();

        $plugin->setTranslator($this->getTranslator())
            ->setTranslatorTextDomain($this->getTranslatorTextDomain());

        $retVal = call_user_func_array($plugin, $arguments);

        $plugin->setTranslator($prevTextTranslator)
            ->setTranslatorTextDomain($prevTextDomain);

        return $retVal;
    }
}
// Start of the script
$translateProxy = $this->translateproxy();
$translateProxy->pushTranslatorTextDomain('Ice\AdminAuth');

//...

echo $translateProxy->formLabel($form->get('name'));
// Instead of  $this->formLabel

//...

$translateProxy->popTranslatorTextDomain(); // End of the script

On each scripts, we use pushTranslatorTextDomain and popTranslatorTextDomain to ensure there will not have any conflict if we use partial.

What do you think about that? I don't know if it can be PR.

@juriansluiman

This comment has been minimized.

Show comment Hide comment
@juriansluiman

juriansluiman Oct 31, 2012

Contributor

@coolmic for both your problems there are good alternatives.

First, usually you have translations for all your locales. It is a good practice to write all message "to-be-translated" as English sentences, but you translate these at all times, nevertheless of the default locale. There is no need to check if the language is English and then omit the translation.

Translators also give usually the key back as translation when it does not exist. So if you want to translate 'hello', you have a French translation 'hello' => 'bonjour'. If the locale is English, you see "hello". If the locale is French, you see "bonjour".

The second problem: it is in most cases easier to translate the labels directly in the form class itself. Your form looks something like this:

<?php

namespace MyModule\Form;

use Zend\Form\Form;
use Zend\I18n\Translate\Translator;

class MyForm extends Form
{
    public function __construct(Translator $translator)
    {
        $this->add(array(
            'name' => 'name',
            'options' => array(
                'label' => $translator->translate('Name:')
            ),
        );
    }
}

Every label is translated inside the form, so you can make your form view very simple:

<dl class="zend_form">
    <dt><?php echo $this->formLabel($form->get('name')) ?></dt>
    <dd><?php echo $this->formInput($form->get('name')) ?></dd>
    <?php echo $this->formElementErrors($form->get('name')) ?>
</dl>

If you match two forms you get form two different modules (and thus, two different text domains), you have no trouble in doing so.

Contributor

juriansluiman commented Oct 31, 2012

@coolmic for both your problems there are good alternatives.

First, usually you have translations for all your locales. It is a good practice to write all message "to-be-translated" as English sentences, but you translate these at all times, nevertheless of the default locale. There is no need to check if the language is English and then omit the translation.

Translators also give usually the key back as translation when it does not exist. So if you want to translate 'hello', you have a French translation 'hello' => 'bonjour'. If the locale is English, you see "hello". If the locale is French, you see "bonjour".

The second problem: it is in most cases easier to translate the labels directly in the form class itself. Your form looks something like this:

<?php

namespace MyModule\Form;

use Zend\Form\Form;
use Zend\I18n\Translate\Translator;

class MyForm extends Form
{
    public function __construct(Translator $translator)
    {
        $this->add(array(
            'name' => 'name',
            'options' => array(
                'label' => $translator->translate('Name:')
            ),
        );
    }
}

Every label is translated inside the form, so you can make your form view very simple:

<dl class="zend_form">
    <dt><?php echo $this->formLabel($form->get('name')) ?></dt>
    <dd><?php echo $this->formInput($form->get('name')) ?></dd>
    <?php echo $this->formElementErrors($form->get('name')) ?>
</dl>

If you match two forms you get form two different modules (and thus, two different text domains), you have no trouble in doing so.

@coolmic

This comment has been minimized.

Show comment Hide comment
@coolmic

coolmic Oct 31, 2012

Contributor

Yeah, the first one is not really an issue, I just want to avoid to instanciate the translator object, but it's probably an unnecessary optimization.

For the second one, the translation will be done 2 times,
and for formElementsErrors, it's an hassle with , because I have to translate each template message for each validator.

Well, the main purpose of this ticket is to have feedbacks about the TranslatorProxy.

Contributor

coolmic commented Oct 31, 2012

Yeah, the first one is not really an issue, I just want to avoid to instanciate the translator object, but it's probably an unnecessary optimization.

For the second one, the translation will be done 2 times,
and for formElementsErrors, it's an hassle with , because I have to translate each template message for each validator.

Well, the main purpose of this ticket is to have feedbacks about the TranslatorProxy.

@coolmic coolmic closed this Oct 31, 2012

@coolmic coolmic reopened this Oct 31, 2012

@ghost ghost assigned DASPRiD Nov 16, 2012

@ralphschindler

This comment has been minimized.

Show comment Hide comment
@ralphschindler

ralphschindler Feb 8, 2013

Member

Is this still an issue?

Member

ralphschindler commented Feb 8, 2013

Is this still an issue?

@juriansluiman

This comment has been minimized.

Show comment Hide comment
@juriansluiman

juriansluiman Feb 8, 2013

Contributor

I think the issue is reopened accidentally

Contributor

juriansluiman commented Feb 8, 2013

I think the issue is reopened accidentally

@ralphschindler

This comment has been minimized.

Show comment Hide comment
@ralphschindler

ralphschindler Feb 8, 2013

Member

Ok, I will close, it can be reopened if it is deemed still an issue.

Member

ralphschindler commented Feb 8, 2013

Ok, I will close, it can be reopened if it is deemed still an issue.

@coolmic

This comment has been minimized.

Show comment Hide comment
@coolmic

coolmic Feb 8, 2013

Contributor

I had spoken with dastrid, he reject the proxy, but liked the text domain stack.

DASPRiD/zf2@c48c1cf
But it's still not merged

Contributor

coolmic commented Feb 8, 2013

I had spoken with dastrid, he reject the proxy, but liked the text domain stack.

DASPRiD/zf2@c48c1cf
But it's still not merged

@ralphschindler

This comment has been minimized.

Show comment Hide comment
@ralphschindler

ralphschindler Feb 8, 2013

Member

@DASPRiD is that a WIP PR you're working on?

Member

ralphschindler commented Feb 8, 2013

@DASPRiD is that a WIP PR you're working on?

@DASPRiD

This comment has been minimized.

Show comment Hide comment
@DASPRiD

DASPRiD Feb 8, 2013

Member

@ralphschindler Yes it is. I'll try to get it ready for 2.2

Member

DASPRiD commented Feb 8, 2013

@ralphschindler Yes it is. I'll try to get it ready for 2.2

@samsonasik

This comment has been minimized.

Show comment Hide comment
@samsonasik

samsonasik Aug 29, 2014

Contributor

ping @DASPRiD any update for DASPRiD/zf2@c48c1cf ?

Contributor

samsonasik commented Aug 29, 2014

ping @DASPRiD any update for DASPRiD/zf2@c48c1cf ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment