16

To format a date in twig you usually use something like:

{{ meeting.date|date("m/d/Y") }}

Now, I have to localize this date (US m/d/y, NL d/m/y). What would be the best practice to do this in the twig? I do use Symfony 2, a workaround would be to do the translation in the controller but i would like to do this in the twig.

Roel Veldhuizen
  • 4,613
  • 8
  • 44
  • 78
  • possible duplicate of [How to render a DateTime object in a Twig template](http://stackoverflow.com/questions/8318914/how-to-render-a-datetime-object-in-a-twig-template) – Nic Wortel May 07 '14 at 07:04
  • To do this with sf2, there is an bundle : https://github.com/sonata-project/SonataIntlBundle – Yohan G. Feb 28 '12 at 13:12
  • @YohanG., The provided bundle does not change the behaviour of `|date` filter. It defines new filters which is not desired behaviour regarding the OP question – Peyman Mohamadpour Mar 13 '17 at 08:56

3 Answers3

40

What about the Intl Twig extension?

Usage in a twig template:

{{ my_date | localizeddate('full', 'none', locale) }}
Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
  • Great suggestion. Just don't forget to register the Intl extension, as explained here: http://nerdpress.org/2011/10/19/symfony-2-twig-enabling-native-twig-extensions/ (that page explains installing the Debug extension, but installing the Intl happens analogous) – Martijn May 20 '13 at 19:11
  • 2
    This should be the accepted answer. See [my answer on another question](http://stackoverflow.com/a/23424315/1001110) for more information on how to use the Intl extension. – Nic Wortel May 07 '14 at 07:06
  • 1
    There is a big problem, in twig documentation about this filter, there is no any mention about how to install it! – SaidbakR Jul 10 '14 at 23:19
  • [This answer](http://stackoverflow.com/a/17364600/305189) tells how to install it with composer – Pierre de LESPINAY Mar 31 '15 at 14:23
  • Useful, but seems not to be a robust solution as one should change all `|date` filters in twig files – Peyman Mohamadpour Mar 13 '17 at 09:09
7

I didn't want to install a whole extensions just for this stuff and need to do a few things automatically: It's also possible to write a helperclass (or expand an existing helper) in Bundle/Twig/Extensions for example like this:

public function foo(\Datetime $datetime, $lang = 'de_DE', $pattern = 'd. MMMM Y')
{
    $formatter = new \IntlDateFormatter($lang, \IntlDateFormatter::LONG, \IntlDateFormatter::LONG);
    $formatter->setPattern($pattern);
    return $formatter->format($datetime);
}

twig-Template:

{{ yourDateTimeObject|foo('en_US', 'd. MMMM Y') }}

The result is "12. February 2014" (or "12. Februar 2014" in de_DE and so on)

Franziska
  • 103
  • 3
  • 9
0

I really only wanted the day & month names to be translated according to the locale and wrote this twig extension. It accepts the normal DateTime->format() parameters and converts day & months names using strftime() if needed.

<?php

namespace AppBundle\Twig\Extension;

use Twig_Extension;
use Twig_SimpleFilter;
use DateTimeZone;
use DateTime;

class LocalizedDateExtension extends Twig_Extension
{
    protected static $conversionMap = [
        'D' => 'a',
        'l' => 'A',
        'M' => 'b',
        'F' => 'B',
    ];

    public function getFilters()
    {
        return [
            new Twig_SimpleFilter('localizeddate', [$this, 'localizeDate']),
        ];
    }

    protected static function createLocalizableTodo(&$formatString)
    {
        $newFormatString = '';
        $todo = [];

        $formatLength = mb_strlen($formatString);
        for ($i = 0; $i < $formatLength; $i++) {
            $char = $formatString[$i];
            if ('\'' === $char) {
                $newFormatString = $formatString[++$i]; //advance and add new character
            }
            if (array_key_exists($char, static::$conversionMap)) {
                $newFormatString.= '\!\L\O\C\A\L\I\Z\E\D\\'; //prefix char
                $todo[$char] = static::$conversionMap[$char];
            }
            $newFormatString.= $char;
        }
        $formatString = $newFormatString;
        return $todo;
    }

    public function localizeDate(DateTime $dateTime, $format, $timezone = null, $locale = null)
    {
        if (null !== $timezone && $dateTime->getTimezone()->getName() !== $timezone) {
            $dateTime = clone $dateTime;
            $dateTime->setTimezone(new DateTimeZone($timezone));
        }

        $todo = static::createLocalizableTodo($format);
        $output = $dateTime->format($format);

        //no localizeable parameters?
        if (0 === count($todo)) {
            return $output;
        }

        if ($locale !== null) {
            $currentLocale = setlocale(LC_TIME, '0');
            setlocale(LC_TIME, $locale);
        }
        if ($timezone !== null) {
            $currentTimezone = date_default_timezone_get();
            date_default_timezone_set($timezone);
        }

        //replace special parameters
        foreach ($todo as $placeholder => $parameter) {
            $output = str_replace('!LOCALIZED'.$placeholder, strftime('%'.$parameter, $dateTime->getTimestamp()), $output);
        }
        unset($parameter);

        if (isset($currentLocale)) {
            setlocale(LC_TIME, $currentLocale);
        }
        if (isset($currentTimezone)) {
            date_default_timezone_set($currentTimezone);
        }

        return $output;
    }
}
Bart
  • 863
  • 8
  • 19