Можно ли получить все загруженные локали при использовании адаптера Zend i18n и Gettext? - PullRequest
0 голосов
/ 01 октября 2018

Мы в основном имеем ту же конфигурацию и шаблон, что и этот пример :

[
    'translator' => [
        'locale' => 'en_US',
        'translation_file_patterns' => [
            [
                'base_dir' => __DIR__ . '/../languages/phpArray',
                'type'     => 'phpArray',
                'pattern'  => '%s.php',
            ],
            [
                'base_dir' => __DIR__ . '/../languages/gettext',
                'type'     => 'gettext',
                'pattern'  => '%s.mo',
            ],
        ],
    ],
]

И мне нужно получить список всех загруженных локалей от переводчика, чтобы я мог построитьВыбор языка.Позже мы добавим больше локалей, и я хотел бы сохранить эту динамику, основываясь на доступных переводах.

Возможно ли это и как?

1 Ответ

0 голосов
/ 02 октября 2018

Хорошо, я нашел это интересным испытанием, поэтому я сделал это:)

Пожалуйста, обратите внимание, что в вашем конфиге, как и в вопросе, вы устанавливаете локаль на en_US.Если вы разрешаете пользователям выбирать локаль, вы должны динамически обновлять этот параметр (это я не создал для вас ;-))

В том, что я создал, используется FilesystemCache .Вы можете использовать что-то еще, если хотите.

Для проверки я создал несколько файлов в папке language/ случайного модуля:

  • nl_NL
  • test
  • donuts_are-lovely
  • вкусные пончики

(обратите внимание, что выше используются различные разделители)

Требуемая конфигурация

'caches' => [
    'FilesystemCache' => [
        'adapter' => [
            'name'    => Filesystem::class,
            'options' => [
                // Store cached data in this directory.
                'cache_dir' => './data/cache',
                // Store cached data for 1 hour.
                'ttl' => 60*60*1
            ],
        ],
        'plugins' => [
            [
                'name' => 'serializer',
                'options' => [
                ],
            ],
        ],
    ],
],
'service_manager' => [
    'factories' => [
        LocaleOptionsManager::class  => LocaleOptionsManagerFactory::class,
    ],
],

Итак,здесь некоторые вещи должны стать понятными.Использование data/cache/ в качестве каталога кеша.Я также создал LocaleOptionsManager и Фабрику для него.

LocaleOptionsManager

<?php

namespace User\Service;

use Zend\Cache\Storage\StorageInterface;

class LocaleOptionsManager
{
    /**
     * @var StorageInterface
     */
    protected $cache;

    /**
     * @var array
     */
    protected $config;

    public function __construct(StorageInterface $cache, array $config)
    {
        $this->setCache($cache);
        $this->setConfig($config);
    }

    /**
     * @param bool $forceCreate
     *
     * @return array
     */
    public function __invoke(bool $forceCreate = false) : array
    {
        if ($forceCreate) {
            // Must recreate cache - remove current locale options
            $this->getCache()->removeItem('locale_options');
        }

        // Loads locale options from cache into $cache. Result (bool) of whether action succeeded loaded into $result
        $cache = $this->getCache()->getItem('locale_options', $result);

        if ($result) {
            // Loading cache (above) succeeded, return cache contents
            return $cache;
        }

        // Above loading of cache didn't succeed or didn't exist, create new cache

        $options = [];
        foreach ($this->getConfig() as $config) {
            if (
                array_key_exists('base_dir', $config)
                && isset($config['base_dir'])
                && array_key_exists('pattern', $config)
                && isset($config['pattern'])
            ) {
                // str_replace used to replace "%s" with "*" to make it a regex pattern accepted by glob()
                foreach (glob(str_replace('%s', '*', $config['base_dir'] . DIRECTORY_SEPARATOR . $config['pattern'])) as $fileName) {
                    // Specifically returns filename without extension - see: http://php.net/manual/en/function.pathinfo.php
                    $options[] = pathinfo($fileName, PATHINFO_FILENAME);
                }
            }
        }

        // Save supported locales to cache
        if ($this->getCache()->setItem('locale_options', $options)) {

            return $options;
        }

        return [];
    }

    /**
     * @return StorageInterface
     */
    public function getCache() : StorageInterface
    {
        return $this->cache;
    }

    /**
     * @param StorageInterface $cache
     *
     * @return LocaleOptionsManager
     */
    public function setCache(StorageInterface $cache) : LocaleOptionsManager
    {
        $this->cache = $cache;

        return $this;
    }

    /**
     * @return array
     */
    public function getConfig() : array
    {
        return $this->config;
    }

    /**
     * @param array $config
     */
    public function setConfig(array $config) : void
    {
        $this->config = $config;
    }

}

Как видите, реальное действие заключается в этой функции __invoke.Встроенные комментарии должны объяснить, что происходит, если у вас есть какие-либо вопросы, задавайте!

LocaleOptionsManagerFactory

<?php

namespace User\Factory\Service;

use Interop\Container\ContainerInterface;
use User\Service\LocaleOptionsManager;
use Zend\Cache\Storage\StorageInterface;
use Zend\ServiceManager\Factory\FactoryInterface;

class LocaleOptionsManagerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $config = $container->get('Config');

        /** @var StorageInterface $cache */
        $cache = $container->get('FilesystemCache');

        if (
            array_key_exists('translator', $config)
            && array_key_exists('translation_file_patterns', $config['translator'])
            && count($config['translator']['translation_file_patterns']) > 0
        ) {
            return new LocaleOptionsManager($cache, $config['translator']['translation_file_patterns']);
        }

        return new LocaleOptionsManager($cache, []);
    }
}

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

Как использовать его в форме

Хорошо, просто, как если бы вы были на самом деле Выберите, только вы должны предоставить значения.

Конструктор формы&& init ()

public function __construct($name = null, array $options = [])
{
    if ( ! array_key_exists('locale_options', $options)) {
        throw new Exception('Locale options not received. Are you a teapot?', 418);
    }

    parent::__construct($name, $options);
}

public function init()
{
    $this->add(
        [
            'name'     => 'language',
            'required' => true,
            'type'     => Select::class,
            'options'  => [
                'label'         => _('Select language'),
                'value_options' => $this->options['locale_options'],
            ],
        ]
    );

    // other fields
}

Я использую универсальную фабрику для генерации моих форм и наборов полей (см. мой github, если хотите), но чтобы добавить эти опции, я сделал следующее:

public function __invoke(ContainerInterface $container, $requestedName, array $options = null) : AbstractForm
{
    $localeOptions = $container->get(LocaleOptionsManager::class);

    $options = [];
    // set key/value to same string (a Select has the "key" as the 'value' in the HTML)
    foreach ($localeOptions() as $option) {
        $options['locale_options'][$option] = $option;
    }

    $this->options = $options;

    // THIS IS MY GENERIC INVOKE - CREATE YOUR OWN FORM HERE
    return parent::__invoke($container, $requestedName, $options);
}

Все это дает мне результат на изображении ниже:

Result

...