Passed
Push — master ( e37dfe...becd39 )
by MusikAnimal
05:00
created

I18nHelper::getIntuition()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5.0061

Importance

Changes 0
Metric Value
cc 5
eloc 15
nc 5
nop 0
dl 0
loc 32
ccs 15
cts 16
cp 0.9375
crap 5.0061
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the I18nHelper.
4
 */
5
6
namespace AppBundle\Helper;
7
8
use DateTime;
9
use IntlDateFormatter;
10
use Intuition;
11
use NumberFormatter;
12
use Symfony\Component\Config\Definition\Exception\Exception;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\HttpFoundation\RequestStack;
16
use Symfony\Component\HttpFoundation\Session\SessionInterface;
17
18
/**
19
 * The I18nHelper centralizes all methods for i18n and l10n,
20
 * and interactions with the Intution library.
21
 */
22
class I18nHelper
23
{
24
    /** @var ContainerInterface The application's container interface. */
25
    protected $container;
26
27
    /** @var RequestStack The request stack. */
28
    protected $requestStack;
29
30
    /** @var SessionInterface User's current session. */
31
    protected $session;
32
33
    /** @var Intuition|null The i18n object. */
34
    private $intuition;
35
36
    /** @var NumberFormatter Instance of NumberFormatter class, used in localizing numbers. */
37
    protected $numFormatter;
38
39
    /** @var NumberFormatter Instance of NumberFormatter class for localizing percentages. */
40
    protected $percentFormatter;
41
42
    /** @var IntlDateFormatter Instance of IntlDateFormatter class, used in localizing dates. */
43
    protected $dateFormatter;
44
45
    /**
46
     * Constructor for the I18nHelper.
47
     * @param ContainerInterface $container
48
     * @param RequestStack $requestStack
49
     * @param SessionInterface $session
50
     */
51 25
    public function __construct(
52
        ContainerInterface $container,
53
        RequestStack $requestStack,
54
        SessionInterface $session
55
    ) {
56 25
        $this->container = $container;
57 25
        $this->requestStack = $requestStack;
58 25
        $this->session = $session;
59 25
    }
60
61
    /**
62
     * Get an Intuition object, set to the current language based on the query string or session
63
     * of the current request.
64
     * @return Intuition
65
     * @throws \Exception If the 'i18n/en.json' file doesn't exist (as it's the default).
66
     */
67 17
    public function getIntuition()
68
    {
69
        // Don't recreate the object.
70 17
        if ($this->intuition instanceof Intuition) {
71 13
            return $this->intuition;
72
        }
73
74
        // Find the path, and complain if English doesn't exist.
75 17
        $path = $this->container->getParameter('kernel.root_dir') . '/../i18n';
76 17
        if (!file_exists("$path/en.json")) {
77
            throw new Exception("Language directory doesn't exist: $path");
78
        }
79
80 17
        $useLang = 'en';
81
82
        // Current request doesn't exist in unit tests, in which case we'll fall back to English.
83 17
        if ($this->getRequest() !== null) {
84 11
            $useLang = $this->getIntuitionLang();
85
86
            // Save the language to the session.
87 11
            if ($this->session->get('lang') !== $useLang) {
88 11
                $this->session->set('lang', $useLang);
89
            }
90
        }
91
92
        // Set up Intuition, using the selected language.
93 17
        $intuition = new Intuition('xtools');
94 17
        $intuition->registerDomain('xtools', $path);
0 ignored issues
show
Bug introduced by
$path of type string is incompatible with the type array expected by parameter $dir of Intuition::registerDomain(). ( Ignorable by Annotation )

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

94
        $intuition->registerDomain('xtools', /** @scrutinizer ignore-type */ $path);
Loading history...
95 17
        $intuition->setLang(strtolower($useLang));
96
97 17
        $this->intuition = $intuition;
98 17
        return $intuition;
99
    }
100
101
    /**
102
     * Get the current language code.
103
     * @return string
104
     */
105 13
    public function getLang()
106
    {
107 13
        return $this->getIntuition()->getLang();
108
    }
109
110
    /**
111
     * Get the current language name (defaults to 'English').
112
     * @return string
113
     */
114 12
    public function getLangName()
115
    {
116 12
        return in_array(ucfirst($this->getIntuition()->getLangName()), $this->getAllLangs())
117 12
            ? $this->getIntuition()->getLangName()
118 12
            : 'English';
119
    }
120
121
    /**
122
     * Get all available languages in the i18n directory
123
     * @return array Associative array of langKey => langName
124
     */
125 12
    public function getAllLangs()
126
    {
127 12
        $messageFiles = glob($this->container->getParameter('kernel.root_dir').'/../i18n/*.json');
128
129 12
        $languages = array_values(array_unique(array_map(
130 12
            function ($filename) {
131 12
                return basename($filename, '.json');
132 12
            },
133 12
            $messageFiles
134
        )));
135
136 12
        $availableLanguages = [];
137
138 12
        foreach ($languages as $lang) {
139 12
            $availableLanguages[$lang] = ucfirst($this->getIntuition()->getLangName($lang));
140
        }
141 12
        asort($availableLanguages);
142
143 12
        return $availableLanguages;
144
    }
145
146
    /**
147
     * Whether the current language is right-to-left.
148
     * @param string|null $lang Optionally provide a specific lanuage code.
149
     * @return bool
150
     */
151 13
    public function isRTL($lang = null)
152
    {
153 13
        return $this->getIntuition()->isRTL(
154 13
            null === $lang ? $this->getLang() : $lang
155
        );
156
    }
157
158
    /******************** MESSAGE HELPERS ********************/
159
160
    /**
161
     * Get an i18n message.
162
     * @param string $message
163
     * @param array $vars
164
     * @return mixed|null|string
165
     */
166 11
    public function msg($message = '', $vars = [])
167
    {
168 11
        $vars = is_array($vars) ? $vars : [];
0 ignored issues
show
introduced by
The condition is_array($vars) is always true.
Loading history...
169 11
        return $this->getIntuition()->msg($message, ['domain' => 'xtools', 'variables' => $vars]);
170
    }
171
172
    /**
173
     * See if a given i18n message exists.
174
     * @param string $message The message.
175
     * @param array $vars
176
     * @return bool
177
     */
178
    public function msgExists($message = '', $vars = [])
179
    {
180
        return $this->getIntuition()->msgExists($message, array_merge(
181
            ['domain' => 'xtools'],
182
            ['variables' => is_array($vars) ? $vars : []]
0 ignored issues
show
introduced by
The condition is_array($vars) is always true.
Loading history...
183
        ));
184
    }
185
186
    /**
187
     * Get an i18n message if it exists, otherwise just get the message key.
188
     * @param string $message
189
     * @param array $vars
190
     * @return mixed|null|string
191
     */
192
    public function msgIfExists($message = '', $vars = [])
193
    {
194
        if (is_array($message)) {
0 ignored issues
show
introduced by
The condition is_array($message) is always false.
Loading history...
195
            $vars = $message;
196
            $message = $message[0];
197
            $vars = array_slice($vars, 1);
198
        }
199
        if ($this->msgExists($message, $vars)) {
200
            return $this->msg($message, $vars);
201
        } else {
202
            return $message;
203
        }
204
    }
205
206
    /************************ NUMBERS ************************/
207
208
    /**
209
     * Format a number based on language settings.
210
     * @param  int|float $number
211
     * @param  int $decimals Number of decimals to format to.
212
     * @return string
213
     */
214 14
    public function numberFormat($number, $decimals = 0)
215
    {
216 14
        if (!isset($this->numFormatter)) {
217 14
            $lang = $this->getIntuition()->getLang();
218 14
            $this->numFormatter = new NumberFormatter($lang, NumberFormatter::DECIMAL);
219
        }
220
221 14
        $this->numFormatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $decimals);
222
223 14
        return $this->numFormatter->format($number);
224
    }
225
226
    /**
227
     * Format a given number or fraction as a percentage.
228
     * @param  number  $numerator   Numerator or single fraction if denominator is ommitted.
229
     * @param  number  $denominator Denominator.
230
     * @param  integer $precision   Number of decimal places to show.
231
     * @return string               Formatted percentage.
232
     */
233 1
    public function percentFormat($numerator, $denominator = null, $precision = 1)
234
    {
235 1
        if (!isset($this->percentFormatter)) {
236 1
            $lang = $this->getIntuition()->getLang();
237 1
            $this->percentFormatter = new NumberFormatter($lang, NumberFormatter::PERCENT);
238
        }
239
240 1
        $this->percentFormatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $precision);
241
242 1
        if (!$denominator) {
243 1
            $quotient = $numerator / 100;
244
        } else {
245 1
            $quotient = $numerator / $denominator;
246
        }
247
248 1
        return $this->percentFormatter->format($quotient);
249
    }
250
251
    /************************ DATES ************************/
252
253
    /**
254
     * Localize the given date based on language settings.
255
     * @param string|int|DateTime $datetime
256
     * @param string $pattern Format according to this ICU date format.
257
     * @see http://userguide.icu-project.org/formatparse/datetime
258
     * @return string
259
     */
260 1
    public function dateFormat($datetime, $pattern = 'yyyy-MM-dd HH:mm')
261
    {
262 1
        if (!isset($this->dateFormatter)) {
263 1
            $this->dateFormatter = new IntlDateFormatter(
264 1
                $this->getIntuition()->getLang(),
265 1
                IntlDateFormatter::SHORT,
266 1
                IntlDateFormatter::SHORT
267
            );
268
        }
269
270 1
        if (is_string($datetime) || is_int($datetime)) {
271 1
            $datetime = new DateTime($datetime);
272
        }
273
274 1
        $this->dateFormatter->setPattern($pattern);
275
276 1
        return $this->dateFormatter->format($datetime);
277
    }
278
279
    /********************* PRIVATE MEHTODS *********************/
280
281
    /**
282
     * Determine the interface language, either from the current request or session.
283
     * @return string
284
     */
285 11
    private function getIntuitionLang()
286
    {
287 11
        $queryLang = $this->getRequest()->query->get('uselang');
288 11
        $sessionLang = $this->session->get('lang');
289
290 11
        if ($queryLang !== '' && $queryLang !== null) {
291 1
            return $queryLang;
292 11
        } elseif ($sessionLang !== '' && $sessionLang !== null) {
293
            return $sessionLang;
294
        }
295
296
        // English as default.
297 11
        return 'en';
298
    }
299
300
    /**
301
     * Shorthand to get the current request from the request stack.
302
     * @return Request
303
     * There is no request stack in the tests.
304
     * @codeCoverageIgnore
305
     */
306
    private function getRequest()
307
    {
308
        return $this->container->get('request_stack')->getCurrentRequest();
309
    }
310
}
311