Completed
Push — master ( 90072e...c81959 )
by Daniel
11:23
created

SymfonyMessageProvider::pluralise()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 12
nc 4
nop 4
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\i18n\Messages\Symfony;
4
5
use SilverStripe\Core\Config\Configurable;
6
use SilverStripe\Core\Injector\Injectable;
7
use SilverStripe\i18n\i18n;
8
use SilverStripe\i18n\Messages\MessageProvider;
9
use Symfony\Component\Translation\Translator;
10
11
/**
12
 * Implement message localisation using a symfony/translate backend
13
 */
14
class SymfonyMessageProvider implements MessageProvider
15
{
16
    use Injectable;
17
    use Configurable;
18
19
    /**
20
     * List of locales initialised
21
     *
22
     * @var array
23
     */
24
    protected $loadedLocales = [];
25
26
    /**
27
     * @var Translator
28
     */
29
    protected $translator = null;
30
31
    /**
32
     * List of source folder dirs to load yml localisations from
33
     *
34
     * @var array
35
     */
36
    protected $sourceDirs = [];
37
38
    /**
39
     * @return Translator
40
     */
41
    public function getTranslator()
42
    {
43
        return $this->translator;
44
    }
45
46
    /**
47
     * @param Translator $translator
48
     * @return $this
49
     */
50
    public function setTranslator($translator)
51
    {
52
        $this->translator = $translator;
53
        foreach ($translator->getFallbackLocales() as $locale) {
54
            $this->load($locale);
55
        }
56
        return $this;
57
    }
58
59
    /**
60
     * Load resources for the given locale
61
     *
62
     * @param string $locale
63
     */
64
    protected function load($locale)
65
    {
66
        if (isset($this->loadedLocales[$locale])) {
67
            return;
68
        }
69
70
        // Add full locale file. E.g. 'en_NZ'
71
        $this
72
            ->getTranslator()
73
            ->addResource('ss', $this->getSourceDirs(), $locale);
74
75
        // Add lang-only file. E.g. 'en'
76
        $lang = i18n::get_lang_from_locale($locale);
77
        if ($lang !== $locale) {
78
            $this
79
                ->getTranslator()
80
                ->addResource('ss', $this->getSourceDirs(), $lang);
81
        }
82
83
84
        $this->loadedLocales[$locale] = true;
85
    }
86
87
    public function translate($entity, $default, $injection)
88
    {
89
        // Ensure localisation is ready
90
        $locale = i18n::get_locale();
91
        $this->load($locale);
92
93
        // Prepare arguments
94
        $arguments = $this->templateInjection($injection);
95
96
        // Pass to symfony translator
97
        $result = $this->getTranslator()->trans($entity, $arguments, 'messages', $locale);
98
99
        // Manually inject default if no translation found
100
        if ($entity === $result) {
101
            $result = $this->getTranslator()->trans($default, $arguments, 'messages', $locale);
102
        }
103
104
        return $result;
105
    }
106
107
    public function pluralise($entity, $default, $injection, $count)
108
    {
109
        if (is_array($default)) {
110
            $default = $this->normalisePlurals($default);
111
        }
112
113
        // Ensure localisation is ready
114
        $locale = i18n::get_locale();
115
        $this->load($locale);
116
117
        // Prepare arguments
118
        $arguments = $this->templateInjection(array_merge(
119
            $injection,
120
            [ 'count' => $count ]
121
        ));
122
123
        // Pass to symfony translator
124
        $result = $this->getTranslator()->transChoice($entity, $count, $arguments, 'messages', $locale);
125
126
        // Manually inject default if no translation found
127
        if ($entity === $result) {
128
            $result = $this->getTranslator()->transChoice($default, $count, $arguments, 'messages', $locale);
0 ignored issues
show
Bug introduced by
It seems like $default can also be of type array; however, Symfony\Component\Transl...anslator::transChoice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
129
        }
130
131
        return $result;
132
    }
133
134
    /**
135
     * Get the list of /lang dirs to load localisations from
136
     *
137
     * @return array
138
     */
139
    public function getSourceDirs()
140
    {
141
        if (!$this->sourceDirs) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->sourceDirs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
142
            $this->setSourceDirs(i18n::get_lang_dirs());
143
        }
144
        return $this->sourceDirs;
145
    }
146
147
    /**
148
     * Set the list of /lang dirs to load localisations from
149
     *
150
     * @param array $sourceDirs
151
     * @return $this
152
     */
153
    public function setSourceDirs($sourceDirs)
154
    {
155
        $this->sourceDirs = $sourceDirs;
156
        return $this;
157
    }
158
159
    /**
160
     * Generate template safe injection parameters
161
     *
162
     * @param array $injection
163
     * @return array Injection array with all keys surrounded with {} placeholders
164
     */
165
    protected function templateInjection($injection)
166
    {
167
        $injection = $injection ?: [];
168
        // Rewrite injection to {} surrounded placeholders
169
        $arguments = array_combine(
170
            array_map(function ($val) {
171
                return '{' . $val . '}';
172
            }, array_keys($injection)),
173
            $injection
174
        );
175
        return $arguments;
176
    }
177
178
    /**
179
     * Convert ruby i18n plural form to symfony pipe-delimited form.
180
     *
181
     * @param array $parts
182
     * @return array|string
183
     */
184
    protected function normalisePlurals($parts)
185
    {
186
        return implode('|', $parts);
187
    }
188
}
189