使用 Zend i18n 和 Gettext 适配器时是否可以获取所有已加载的语言环境?
Is it possible to get all the loaded locales when using Zend i18n and Gettext adapter?
我们基本上具有与 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',
],
],
],
]
而且我需要从翻译器中获取所有已加载语言环境的列表,以便构建语言选择器。稍后我们将添加更多语言环境,我想根据可用的翻译保持这种动态。
这可能吗?如何实现?
好的,我发现这是一个有趣的挑战,所以我成功了:)
请注意,在您的配置中,正如问题中一样,您将语言环境设置为 en_US
。如果您允许用户 select 语言环境,则必须动态更新此设置(这不是我为您创建的 ;-))
我创建的使用 FilesystemCache。如果你愿意,你可以使用其他东西。
为了测试,我在随机模块的 language/
文件夹中创建了几个文件:
- nl_NL
- 测试
- 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, []);
}
}
为了确保 not 配置任何翻译器不会使应用程序崩溃,我们给它一个空数组作为第二个参数。如果您查看实际的 class,它只会将一个空数组设置为缓存(以及 return 那个),如果仅此而已。
如何在表单中使用它
好吧,很简单,就像您做其他任何事情一样 Select 真的,只是您必须提供值。
一个表单构造器&& 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);
}
所有这些给了我下图中的结果:
我们基本上具有与 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',
],
],
],
]
而且我需要从翻译器中获取所有已加载语言环境的列表,以便构建语言选择器。稍后我们将添加更多语言环境,我想根据可用的翻译保持这种动态。
这可能吗?如何实现?
好的,我发现这是一个有趣的挑战,所以我成功了:)
请注意,在您的配置中,正如问题中一样,您将语言环境设置为 en_US
。如果您允许用户 select 语言环境,则必须动态更新此设置(这不是我为您创建的 ;-))
我创建的使用 FilesystemCache。如果你愿意,你可以使用其他东西。
为了测试,我在随机模块的 language/
文件夹中创建了几个文件:
- nl_NL
- 测试
- 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, []);
}
}
为了确保 not 配置任何翻译器不会使应用程序崩溃,我们给它一个空数组作为第二个参数。如果您查看实际的 class,它只会将一个空数组设置为缓存(以及 return 那个),如果仅此而已。
如何在表单中使用它
好吧,很简单,就像您做其他任何事情一样 Select 真的,只是您必须提供值。
一个表单构造器&& 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);
}
所有这些给了我下图中的结果: