Skip to content
This repository has been archived by the owner on Jan 8, 2020. It is now read-only.

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

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

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

coolmic opened this issue Oct 30, 2012 · 9 comments
Assignees
Milestone

Comments

@coolmic
Copy link
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
Copy link
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.

@coolmic
Copy link
Contributor Author

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 as completed Oct 31, 2012
@coolmic coolmic reopened this Oct 31, 2012
@ghost ghost assigned DASPRiD Nov 16, 2012
@ralphschindler
Copy link
Member

Is this still an issue?

@juriansluiman
Copy link
Contributor

I think the issue is reopened accidentally

@ralphschindler
Copy link
Member

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

@coolmic
Copy link
Contributor Author

coolmic commented Feb 8, 2013

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

https://github.com/DASPRiD/zf2/commit/c48c1cfc096a3e9f3323318e5e6c86d2132c8e0c
But it's still not merged

@ralphschindler
Copy link
Member

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

@DASPRiD
Copy link
Member

DASPRiD commented Feb 8, 2013

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

@samsonasik
Copy link
Contributor

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants