Passed
Push — feat_i18n ( 76c9c8...651855 )
by Arnaud
12:12 queued 08:35
created

Twig::setLocale()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Cecil.
7
 *
8
 * Copyright (c) Arnaud Ligny <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Cecil\Renderer;
15
16
use Cecil\Builder;
17
use Cecil\Renderer\Twig\Extension as TwigExtension;
18
use Cecil\Util;
19
use Symfony\Bridge\Twig\Extension\TranslationExtension;
20
use Symfony\Component\Translation\Formatter\MessageFormatter;
21
use Symfony\Component\Translation\IdentityTranslator;
22
use Symfony\Component\Translation\Loader\MoFileLoader;
23
use Symfony\Component\Translation\Translator;
24
25
/**
26
 * Class Twig.
27
 */
28
class Twig implements RendererInterface
29
{
30
    /** @var \Twig\Profiler\Profile */
31
    public $profile;
32
33
    /** @var \Twig\Environment */
34
    private $twig;
35
36
    /** @var Translator */
37
    private $translator;
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function __construct(Builder $builder, $templatesPath)
43
    {
44
        // load layouts
45
        $loader = new \Twig\Loader\FilesystemLoader($templatesPath);
46
        // default options
47
        $loaderOptions = [
48
            'debug'            => $builder->isDebug(),
49
            'strict_variables' => true,
50
            'autoescape'       => false,
51
            'auto_reload'      => true,
52
            'cache'            => false,
53
        ];
54
        // use Twig cache?
55
        if ($builder->getConfig()->get('cache.templates.enabled')) {
56
            $templatesCachePath = \Cecil\Util::joinFile(
57
                $builder->getConfig()->getCachePath(),
58
                (string) $builder->getConfig()->get('cache.templates.dir')
59
            );
60
            $loaderOptions = array_replace($loaderOptions, ['cache' => $templatesCachePath]);
61
        }
62
        // create the Twig instance
63
        $this->twig = new \Twig\Environment($loader, $loaderOptions);
64
        // set date format
65
        $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
66
            ->setDateFormat($builder->getConfig()->get('date.format'));
67
        // set timezone
68
        if ($builder->getConfig()->has('date.timezone')) {
69
            $this->twig->getExtension(\Twig\Extension\CoreExtension::class)
70
                ->setTimezone($builder->getConfig()->get('date.timezone'));
71
        }
72
        // adds extensions
73
        $this->twig->addExtension(new TwigExtension($builder));
74
        $this->twig->addExtension(new \Twig\Extension\StringLoaderExtension());
75
        // i18n
76
        $locale = $builder->getConfig()->getLanguageProperty('locale');
77
        $this->translator = new Translator($locale, new MessageFormatter(new IdentityTranslator()));
0 ignored issues
show
Bug introduced by
It seems like $locale can also be of type null; however, parameter $locale of Symfony\Component\Transl...anslator::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

77
        $this->translator = new Translator(/** @scrutinizer ignore-type */ $locale, new MessageFormatter(new IdentityTranslator()));
Loading history...
78
        $this->translator->addLoader('mo', new MoFileLoader());
79
        if (count($builder->getConfig()->getLanguages()) > 1) {
80
            foreach ($builder->getConfig()->getLanguages() as $lang) {
81
                $translationFile = realpath(Util::joinFile($builder->getConfig()->getSourceDir(), \sprintf('translations/messages.%s.mo', $lang['locale'])));
82
                if (Util\File::getFS()->exists($translationFile)) {
83
                    $this->translator->addResource('mo', $translationFile, $lang['locale']);
84
                }
85
            }
86
        } else {
87
            $translationFile = realpath(Util::joinFile($builder->getConfig()->getSourceDir(), \sprintf('translations/messages.%s.mo', $locale)));
88
            if (Util\File::getFS()->exists($translationFile)) {
89
                $this->translator->addResource('mo', $translationFile, $locale);
0 ignored issues
show
Bug introduced by
It seems like $locale can also be of type null; however, parameter $locale of Symfony\Component\Transl...anslator::addResource() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

89
                $this->translator->addResource('mo', $translationFile, /** @scrutinizer ignore-type */ $locale);
Loading history...
90
            }
91
        }
92
        $this->twig->addExtension(new TranslationExtension($this->translator));
93
        // filters fallback
94
        $this->twig->registerUndefinedFilterCallback(function ($name) use ($builder) {
95
            switch ($name) {
96
                case 'localizeddate':
97
                    return new \Twig\TwigFilter($name, function (\DateTime $value = null) use ($builder) {
98
                        return date((string) $builder->getConfig()->get('date.format'), $value->getTimestamp());
0 ignored issues
show
Bug introduced by
The method getTimestamp() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

98
                        return date((string) $builder->getConfig()->get('date.format'), $value->/** @scrutinizer ignore-call */ getTimestamp());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
99
                    });
100
            }
101
102
            return false;
103
        });
104
        // debug
105
        if ($builder->isDebug()) {
106
            // dump()
107
            $this->twig->addExtension(new \Twig\Extension\DebugExtension());
108
            // profiler
109
            $this->profile = new \Twig\Profiler\Profile();
110
            $this->twig->addExtension(new \Twig\Extension\ProfilerExtension($this->profile));
111
        }
112
        /**
113
         * Backward compatibility.
114
         */
115
        if (extension_loaded('intl')) {
116
            $this->twig->addExtension(new \Twig\Extensions\IntlExtension());
117
            $builder->getLogger()->debug('Intl extension is loaded');
118
        }
119
        if (extension_loaded('gettext')) {
120
            $this->twig->addExtension(new \Twig\Extensions\I18nExtension());
121
            $builder->getLogger()->debug('Gettext extension is loaded');
122
        }
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function setLocale(string $locale): void
129
    {
130
        $this->translator->setLocale($locale);
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136
    public function addGlobal(string $name, $value): void
137
    {
138
        $this->twig->addGlobal($name, $value);
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144
    public function render(string $template, array $variables): string
145
    {
146
        return $this->twig->render($template, $variables);
147
    }
148
}
149