【问题标题】:Use 4-digit years for localised dates in a Twig template在 Twig 模板中使用 4 位数年份作为本地化日期
【发布时间】:2014-02-06 13:59:17
【问题描述】:

我在 Symfony 2.4 项目中使用 Twig Intl Extension 来本地化日期:

{{ post.published_at|localizeddate('short', 'none', locale) }}

这很好用,但不会以yyyy 格式显示全年,而是使用yy 格式。

这样,2013 年 12 月 31 日将根据区域设置显示为 31/12/2013 或 12/31/2013,而不是 31/12/13 或 31/12/13。

有没有办法在本地化日期中使用 4 位数年份?

【问题讨论】:

  • 在我的机器配置中,我有四位数字,但在其他配置中,我只有 2 位数字。 Y不知道它们之间有什么区别。但我认为有一种方法可以在没有 Twig 扩展的情况下做到这一点

标签: date symfony twig locale


【解决方案1】:

我终于成功了!

我以这种方式扩展了默认的 Twig Intl Extension:

<?php
namespace Acme\DemoBundle\Twig;

class AcmeIntlExtension extends \Twig_Extensions_Extension_Intl
{
    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('localizeddate', array($this, 'twigLocalizedDateFilter'), array('needs_environment' => true)),
        );
    }

    public function twigLocalizedDateFilter($env, $date, $dateFormat = 'medium', $timeFormat = 'medium', $locale = null, $timezone = null, $format = null)
    {
        $date = twig_date_converter($env, $date, $timezone);

        $formatValues = array(
            'none'   => \IntlDateFormatter::NONE,
            'short'  => \IntlDateFormatter::SHORT,
            'medium' => \IntlDateFormatter::MEDIUM,
            'long'   => \IntlDateFormatter::LONG,
            'full'   => \IntlDateFormatter::FULL,
        );

        $formatter = \IntlDateFormatter::create(
            $locale,
            $formatValues[$dateFormat],
            $formatValues[$timeFormat],
            $date->getTimezone()->getName(),
            \IntlDateFormatter::GREGORIAN,
            $format
        );

        if ($format === null) {
            // Replace yy to y (but yyy should be kept yyy, and yyyy kept as yyyy)
            // This way, years are NEVER shown as "yy" (eg. 14), but always like "yyyy" (eg. 2014)
            $pattern = preg_replace(':(^|[^y])y{2,2}([^y]|$):', '$1y$2', $formatter->getPattern());

            $formatter->setPattern($pattern);
        }

        return $formatter->format($date->getTimestamp());
    }
}

它在我的 Symfony 的 app/config.yml 文件中声明:

services:
    acme.twig.extension.intl:
        class: Acme\DemoBundle\Twig\AcmeIntlExtension
        tags:
            - { name: twig.extension }

我将默认模式更改为将“yy”替换为“y”(这是 4 位数年份的格式,如下所述:http://userguide.icu-project.org/formatparse/datetime)。

这样,它适用于所有格式和所有语言环境。

【讨论】:

  • 我做了一个改动,让你可以使用新旧方式,只需添加_year即可:
【解决方案2】:

您扩展 intl 扩展的解决方案很好,但您可以更轻松地做到这一点。如果您深入查看文档,您会发现该扩展有一个 format 参数。所以你可以这样做:

{{ post.published_at|localizeddate('short', 'none', locale, null, 'd/m/y HH:mm') }}

格式遵循 ICU 格式指南。对于 4 位数年份,您可以使用 y 或 yyyy。完整文档:http://userguide.icu-project.org/formatparse/datetime

希望对你有帮助。

【讨论】:

    【解决方案3】:

    对 Michaël Perrin 的回答进行了更改,以便能够通过将 _year 添加到日期格式来使用新旧方式。

    使用以下命令创建文件 app/src/Myproject/MyBundle/Twig/Extension/IntlExtension.php:

    <?php
    namespace Myproject\MyBundle\Twig\Extension;
    
    /**
     * Extension of Twig Intl Extension to add support fo showing 4-digit year. Add
     * '_year' to the date format for it to work, i.e. short_year instead of short.
     */
    class IntlExtension extends \Twig_Extensions_Extension_Intl
    {
    
        /**
         * A new filter must be added for this extension to work. Since this extension
         * extends an existing one, the filter should be loaded after the original one.
         *
         * @return array
         */
        public function getFilters()
        {
            $filters = [];
    
            // Add all filters but the localizeddate created by the parent.
            foreach (parent::getFilters() as $filter) {
                if ('localizeddate' !== $filter->getName()) {
                    $filters[] = $filter;
                }
            }
    
            // Add custom version of 'localizeddate' which adds support showing 4-digit years.
            $filters[] = new \Twig_SimpleFilter('localizeddate', array($this, 'twigLocalizedDateFilter'), array('needs_environment' => true));
    
            return $filters;
        }
    
        /**
         * If the date format has _year in it, the format returned by Intl, will be
         * changed to show a 4-digit year.
         *
         * @param \Twig_Environment $env
         * @param \DateTime $date
         * @param string $dateFormat
         * @param string $timeFormat
         * @param string $locale
         * @param string $timezone
         * @param string $format
         * @return string
         */
        public function twigLocalizedDateFilter(\Twig_Environment $env, $date, $dateFormat = 'medium', $timeFormat = 'medium', $locale = null, $timezone = null, $format = null, $calendar = 'gregorian')
        {
            $date = twig_date_converter($env, $date, $timezone);
    
            $formatValues = array(
                'none' => \IntlDateFormatter::NONE,
                'short' => \IntlDateFormatter::SHORT,
                'medium' => \IntlDateFormatter::MEDIUM,
                'long' => \IntlDateFormatter::LONG,
                'full' => \IntlDateFormatter::FULL,
            );
    
            $formatter = \IntlDateFormatter::create(
                $locale,
                $formatValues[$this->getDateFormat($dateFormat)],
                $formatValues[$timeFormat],
                PHP_VERSION_ID >= 50500 ? $date->getTimezone() : $date->getTimezone()->getName(),
                'gregorian' === $calendar ? \IntlDateFormatter::GREGORIAN : \IntlDateFormatter::TRADITIONAL,
                $format
            );
    
            if ($format === null && $this->showFullYear($dateFormat)) {
                // Replace yy to y (but yyy should be kept yyy, and yyyy kept as yyyy)
                // This way, years are NEVER shown as "yy" (eg. 14), but always like "yyyy" (eg. 2014)
                $pattern = preg_replace(':(^|[^y])y{2,2}([^y]|$):', '$1y$2', $formatter->getPattern());
    
                $formatter->setPattern($pattern);
            }
    
            return $formatter->format($date->getTimestamp());
        }
    
        /**
         * If the given date format has _year in it, true is returned, otherwise false.
         *
         * @param string $dateFormat
         * @return boolean
         */
        protected function showFullYear($dateFormat)
        {
            return (strpos($dateFormat, '_year') !== false);
        }
    
        /**
         * The date format will be returned without the part '_year' if it contains it.
         * @param string $dateFormat
         * @return string
         */
        protected function getDateFormat($dateFormat)
        {
            return str_replace('_year', '', $dateFormat);
        }
    }
    

    当然还有 app/config/config.yml 中的添加

    services:
        myproject.twig.extension.intl:
            class: Myproject\MyBundle\Twig\Extension\IntlExtension
            tags:
                - { name: twig.extension }
    

    【讨论】:

      【解决方案4】:

      试试这个:

      {{ post.published_at|localizeddate('d/m/Y', 'none', locale) }}
      

      您可以使用自己的格式和特殊的 pkaceholders,例如 Y 表示 YYYY 日期格式,查看有关 localizeddate 过滤器的文档。

      【讨论】:

      • 问题是它不再使用本地化了。例如,对于 en_US 语言环境,日期将始终显示为 31/12/2013 而不是 12/31/2013...
      • 我明白了,我认为您需要为您的案例手动实现本地化
      • 我认为你是对的……但这真的太糟糕了!无论如何感谢您的帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-18
      • 1970-01-01
      • 2015-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多