Как пользоваться услугой переводчика внутри организации? - PullRequest
5 голосов
/ 23 ноября 2011

Допустим, у меня есть User сущность:

$user = new User(007);
echo $user->getName(); // display Bond
echo $user->getGender(); // display "Male";
echo $user->getDesignation() // display "Monsieur Bond" or "Mister Bond"

С этой функцией:

public function getDesignation() {
  if ($this->getGender() == 'Male') return "Monsieur ".$this->getName();
  else return "Madame ".$this->getName();
}

Как я могу использовать службу перевода внутри этой сущности для перевода "месье"и "Мадам"?

Кажется, что службу переводчика следует использовать только внутри Контроллера, но я думаю, что в этом случае целесообразно использовать ее внутри этой сущности.

Ответы [ 4 ]

8 голосов
/ 23 ноября 2011

Служба переводчика, как вы говорите, является «службой», которую вы можете использовать в любом классе (т. Е. Определить ее как службу и использовать контейнер инжектора зависимости). Таким образом, вы можете использовать переводчик практически где угодно.

Но такие субъекты, как Альдо сказал , не должны иметь такой ответственности. В худшем случае, если вы действительно хотите перевести вещи внутри сущности, вы можете передать транслятор сущности с помощью метода set, т.е.

$entity->setTranslator($translator);

но я также рекомендую вам создать класс, который будет обрабатывать проблему вне сущности, то есть с помощью шаблона ветки

{{ entity.property|trans }}).
4 голосов
/ 23 ноября 2011

Не стоит и вообще это невозможно.Согласно Принципу единой ответственности организация уже имеет свою цель, которая представляет данные в базе данных.Более того, перевод является вопросом представления, поэтому маловероятно, что вы захотите решить такую ​​проблему на уровне сущностей (если только вы не хотите предоставлять сущности, переведенные на разные языки, что является совершенно другой проблемой и даже не должно решаться с использованиемпереводчик).

Переосмыслите свою логику и попробуйте что-то другое для этого.Вы уверены, что не хотите делать этот перевод на слое представления?Это было бы лучше всего, наверное.В противном случае (если вашей логике действительно нужно иметь перевод на уровне модели), вы можете создать класс-оболочку для сущностей и фабрику для генерации этих «упакованных сущностей»;на этом заводе вы можете ввести услуги переводчика.

2 голосов
/ 21 апреля 2014

Я столкнулся с подобной проблемой и, наконец, нашел это решение.Это не прямой ответ на вашу проблему, потому что я также знаю, что сущность не должна иметь ничего общего с услугой, такой как переводчик.Поэтому вы должны оставить функцию getDesignation без изменений.Вместо этого, на уровне презентации, например, веточка, вы переводите это французское обозначение.

<div>{% trans %}{{ entity.designation }}{% endtrans %} {{ entity.name }}</div>

И в вашем messages.en.yml

Monsieur: Mr.
Madame: Mrs.
0 голосов
/ 04 января 2019

Я сталкивался с этой проблемой несколько раз за последние годы и всегда находил достаточно хороший обходной путь. На этот раз мои getIdentifyingName() методы, которые интенсивно используются во всем проекте (например, явный __toString()), должны были перевести некоторые ключевые слова, используемые на уровне данных, поэтому элегантного обходного пути не было.

Мое решение на этот раз - TranslateObject и соответствующая вспомогательная служба. TranslateObject - это простой объект, содержащий ключ перевода и массив заполнителей, которые также могут быть объектами TranslateObjects для обеспечения многоуровневой трансляции (например, getIdentifyingNameTranslateObject() вызывает другой связанный объект getIdentifyingNameTranslateObject() в одном из заполнителей):

namespace App\Utils;

class TranslateObject
{
    /** @var string */
    protected $transKey;
    /** @var array */
    protected $placeholders;

    public function __construct(string $transKey, array $placeholders = [])
    {
        $this->transKey = $transKey;
        $this->placeholders = self::normalizePlaceholders($placeholders);
    }

    public static function normalizePlaceholders(array $placeholders): array
    {
        foreach ($placeholders as $key => &$placeholder) {
            if (substr($key, 0, 1) !== '%' || substr($key, -1, 1) !== '%') {
                throw new \InvalidArgumentException('The $placeholder attribute must only contain keys in format "%placeholder%".');
            }
            if ($placeholder instanceof TranslateObject) {
                continue;
            }
            if (is_scalar($placeholder)) {
                $placeholder = ['value' => $placeholder];
            }
            if (!isset($placeholder['value']) || !is_scalar($placeholder['value'])) {
                throw new \InvalidArgumentException('$placeholders[\'%placeholder%\'][\'value\'] must be present and a scalar value.');
            }
            if (!isset($placeholder['translate'])) {
                $placeholder['translate'] = false;
            }
            if (!is_bool($placeholder['translate'])) {
                throw new \InvalidArgumentException('$placeholders[\'%placeholder%\'][\'translate\'] must be a boolean.');
            }
        }
        return $placeholders;
    }

    public function getTransKey(): string
    {
        return $this->transKey;
    }

    public function getPlaceholders(): array
    {
        return $this->placeholders;
    }
}

Помощник выглядит следующим образом и выполняет работу:

namespace App\Services;

use App\Utils\TranslateObject;
use Symfony\Contracts\Translation\TranslatorInterface;

class TranslateObjectHelper
{
    /** @var TranslatorInterface */
    protected $translator;

    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }

    public function trans(TranslateObject $translateObject): string
    {
        $placeholders = $translateObject->getPlaceholders();
        foreach ($placeholders as $key => &$placeholder) {
            if ($placeholder instanceof TranslateObject) {
                $placeholder = $this->trans($placeholder);
            }
            elseif (true === $placeholder['translate']) {
                $placeholder = $this->translator->trans($placeholder['value']);
            }
            else {
                $placeholder = $placeholder['value'];
            }
        }

        return $this->translator->trans($translateObject->getTransKey(), $placeholders);
    }
}

А затем внутри сущности есть метод getIdentifyingNameTranslateObject(), возвращающий TranslateObject.

/**
 * Get an identifying name as a TranslateObject (for use with TranslateObjectHelper)
 */
public function getIdentifyingNameTranslateObject(): TranslateObject
{
    return new TranslateObject('my.whatever.translation.key', [
        '%placeholder1%' => $this->myEntityProperty1,
        '%placeholderWithANeedOfTranslation%' => [
            'value' => 'my.whatever.translation.values.' . $this->myPropertyWithANeedOfTranslation,
            'translate' => true,
        ],
        '%placeholderWithCascadingTranslationNeeds%' => $this->getRelatedEntity()->getIdentifyingNameTranslateObject(),
    ]);
}

Когда мне нужно вернуть такое переведенное свойство, мне нужен доступ к моей внедренной службе TranslateObjectHelper и использование ее метода trans(), как в контроллере или любой другой службе:

$this->translateObjectHelper->trans($myObject->getIdentifyingNameTranslateObject());

Затем я создал фильтр веточек в виде простого помощника, подобного этому:

namespace App\Twig;

use App\Services\TranslateObjectHelper;
use App\Utils\TranslateObject;

class TranslateObjectExtension extends \Twig_Extension
{
    /** @var TranslateObjectHelper */
    protected $translateObjectHelper;

    public function __construct(TranslateObjectHelper $translateObjectHelper)
    {
        $this->translateObjectHelper = $translateObjectHelper;
    }

    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('translateObject', [$this, 'translateObject']),
        );
    }

    /**
    * sends a TranslateObject through a the translateObjectHelper->trans() method
    */
    public function translateObject(TranslateObject $translateObject): string
    {
        return $this->translateObjectHelper->trans($translateObject);
    }

    public function getName(): string
    {
        return 'translate_object_twig_extension';
    }
}

Так что в Twig я могу перевести так:

{{ myObject.getIdentifyingNameTranslateObject()|translateObject }}

В конце концов, мне «просто» нужно было найти все getIdentifyingName() вызовы (или .identifyingName в Twig) для этих объектов и заменить их на getIdentifyingNameTranslateObject() вызовом trans() метода * 1035. * (или фильтр translateObject в Twig).

...