简体   繁体   English

使用Zend i18n和Gettext适配器时是否可以获得所有已加载的语言环境?

[英]Is it possible to get all the loaded locales when using Zend i18n and Gettext adapter?

We are basically having the same configuration and pattern to this example : 我们基本上具有与该示例相同的配置和模式:

[
    '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',
            ],
        ],
    ],
]

And I need to get a list of all loaded locales from the translator so I can build a language selector. 而且我需要从翻译器获取所有加载的语言环境的列表,以便构建语言选择器。 We will be adding more locales later on, and I'd like to keep this dynamic, based on the available translations. 稍后我们将添加更多的语言环境,并且我希望根据可用的翻译保持动态。

Is this possible, and how? 这有可能吗?

Ok, I found this an interesting challenge, so I made it :) 好的,我发现这是一个有趣的挑战,所以我做到了:)

Please note that in your config, as it is in the question, you set you locale to en_US . 请注意,在配置中,就像在问题中一样,您将语言环境设置为en_US If you allow users to select a locale, you must update this setting dynamically (this I did not create for you ;-) ) 如果允许用户选择区域设置,则必须动态更新此设置(我没有为您创建此设置;-))

What I created uses FilesystemCache . 我创建的文件使用FilesystemCache You could use something else if you like. 如果愿意,您可以使用其他东西。

To test I created a few files in the language/ folder of a random module: 为了测试,我在一个随机模块的language/文件夹中创建了一些文件:

  • nl_NL nl_NL
  • test 测试
  • donuts_are-lovely donuts_are,可爱
  • yummy donuts 美味的甜甜圈

(note that above use different separators) (请注意,上面使用不同的分隔符)

Required config 必需的配置

'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,
    ],
],

So, here some stuff should become clear. 因此,这里有些东西应该变得清楚了。 Using data/cache/ as the cache directory. 使用data/cache/作为缓存目录。 I've also created a LocaleOptionsManager and a Factory for it. 我还为它创建了一个LocaleOptionsManager和一个Factory。

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;
    }

}

As you can see, the real action is in that __invoke function. 如您所见,真正的动作是在__invoke函数中。 The inline comments should explain what's happening, if you have any questions, do ask! 内联注释应解释发生了什么,如果您有任何疑问,请提出!

LocaleOptionsManagerFactory 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, []);
    }
}

To make sure that not having any translator configured does not crash the application, we're giving it an empty array as the second param. 为确保配置任何转换器不会使应用程序崩溃,我们将其空数组作为第二个参数。 If you look in the actual class, it will just set an empty array as cache (and also return that) if that's all there is. 如果您查看实际的类,那么只要存在,它就会将一个空数组设置为缓存(并返回该数组)。

How to use it in a Form 如何在表格中使用它

Well, easy, like you would any other Select really, only you must supply the values. 好吧,很容易,就像您真的要执行其他其他Select一样,只需提供值即可。

A form constructor && init() 表单构造器&& 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
}

I use a generic Factory to generate my Forms and Fieldsets (see my github if you like), but to add these options in, I did this: 我使用通用的Factory来生成我的Forms和Fieldsets(如果需要,请参见我的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);
}

All of this gives me the result in the image below: 所有这些使我在下图中得到了结果:

结果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM