1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* The plurals class provides support for plural forms in PMF translations. |
4
|
|
|
* |
5
|
|
|
* PHP Version 5.4 |
6
|
|
|
* |
7
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public License, |
8
|
|
|
* v. 2.0. If a copy of the MPL was not distributed with this file, You can |
9
|
|
|
* obtain one at http://mozilla.org/MPL/2.0/. |
10
|
|
|
* |
11
|
|
|
* @category phpMyFAQ |
12
|
|
|
* @package Language |
13
|
|
|
* @author Aurimas Fišeras <[email protected]> |
14
|
|
|
* @copyright 2009-2014 Aurimas Fišeras and phpMyFAQ Team |
15
|
|
|
* @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 |
16
|
|
|
* @link http://www.phpmyfaq.de |
17
|
|
|
* @since 2009-07-30 |
18
|
|
|
*/ |
19
|
|
|
|
20
|
|
|
if (!defined('IS_VALID_PHPMYFAQ')) { |
21
|
|
|
exit(); |
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* PMF_Language_Plurals |
26
|
|
|
* |
27
|
|
|
* @category phpMyFAQ |
28
|
|
|
* @package Language |
29
|
|
|
* @author Aurimas Fišeras <[email protected]> |
30
|
|
|
* @copyright 2009-2014 Aurimas Fišeras and phpMyFAQ Team |
31
|
|
|
* @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 |
32
|
|
|
* @link http://www.phpmyfaq.de |
33
|
|
|
* @since 2009-07-30 |
34
|
|
|
*/ |
35
|
|
|
class PMF_Language_Plurals |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* The currently loaded PMF translations |
39
|
|
|
* |
40
|
|
|
* @var array |
41
|
|
|
*/ |
42
|
|
|
private $PMF_TRANSL = []; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* The number of plural forms for current language $lang |
46
|
|
|
* |
47
|
|
|
* @var integer |
48
|
|
|
*/ |
49
|
|
|
private $nPlurals; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* The language code of current language |
53
|
|
|
* |
54
|
|
|
* @var string |
55
|
|
|
*/ |
56
|
|
|
private $lang; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* True when there is no support for plural forms in current language $lang |
60
|
|
|
* |
61
|
|
|
* @var boolean |
62
|
|
|
*/ |
63
|
|
|
private $useDefaultPluralForm; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Constructor |
67
|
|
|
* |
68
|
|
|
* @param array $translation PMF translation array for current language |
69
|
|
|
* @return void |
70
|
|
|
*/ |
71
|
|
|
public function __construct($translation) |
72
|
|
|
{ |
73
|
|
|
$this->PMF_TRANSL = $translation; |
74
|
|
|
$this->nPlurals = (int)$this->PMF_TRANSL['nplurals']; |
75
|
|
|
$this->lang = $this->PMF_TRANSL['metaLanguage']; |
76
|
|
|
|
77
|
|
|
if ($this->plural($this->lang, 0) != -1) { |
78
|
|
|
$this->useDefaultPluralForm = false; |
79
|
|
|
} else { |
80
|
|
|
// @todo update $this->PMF_TRANSL with English plural messages for fall-back |
81
|
|
|
// @todo display warning!? |
82
|
|
|
//echo "function plural_".$this->PMF_TRANSL['metaLanguage']." was not found for language ".$this->PMF_TRANSL['language']) |
|
|
|
|
83
|
|
|
$this->useDefaultPluralForm = true; |
84
|
|
|
} |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Determines the correct plural form for integer $n |
89
|
|
|
* Returned integer is from interval [0, $nPlurals) |
90
|
|
|
* |
91
|
|
|
* @param integer $n The number used to determine the plural form |
92
|
|
|
* @return integer |
93
|
|
|
* @access private |
94
|
|
|
*/ |
95
|
|
|
private function _getPlural($n) |
96
|
|
|
{ |
97
|
|
|
if ($this->useDefaultPluralForm) { |
98
|
|
|
// this means we have to fallback to English, so return correct English plural form |
99
|
|
|
return $this->plural('en', $n); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
$plural = $this->plural($this->lang, $n); |
103
|
|
|
if ($plural > $this->nPlurals-1) { |
104
|
|
|
// incorrectly defined plural function or wrong $nPlurals |
105
|
|
|
return $this->nPlurals-1; |
106
|
|
|
} else { |
107
|
|
|
return $plural; |
108
|
|
|
} |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Helper function that returns the translation template in the correct plural form |
113
|
|
|
* If translation is missing, message in English plural form is returned |
114
|
|
|
* |
115
|
|
|
* @param string $msgID Message identificator |
116
|
|
|
* @param integer $n The number used to determine the plural form |
117
|
|
|
* @return string |
118
|
|
|
*/ |
119
|
|
|
public function getMsgTemplate($msgID, $n) |
120
|
|
|
{ |
121
|
|
|
$plural = $this->_getPlural($n); |
122
|
|
|
if (isset($this->PMF_TRANSL[$msgID][$plural])) { |
123
|
|
|
return $this->PMF_TRANSL[$msgID][$plural]; |
124
|
|
|
} else { |
125
|
|
|
// translation for current plural form (>2, since we allways have 2 English plural forms) |
126
|
|
|
// in current language is missing, so as a last resort return default English plural form |
127
|
|
|
return $this->PMF_TRANSL[$msgID][1]; |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Returns a translated string in the correct plural form, |
133
|
|
|
* produced according to the formatting of the message. |
134
|
|
|
* |
135
|
|
|
* @param string $msgID Message identificator |
136
|
|
|
* @param integer $n The number used to determine the plural form |
137
|
|
|
* @return string |
138
|
|
|
*/ |
139
|
|
|
public function getMsg($msgID, $n) |
140
|
|
|
{ |
141
|
|
|
return sprintf($this->getMsgTemplate($msgID, $n), $n); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Returns the plural form for language $lang or -1 if language $lang is not supported |
146
|
|
|
* |
147
|
|
|
* @param string $lang The language code |
148
|
|
|
* @param integer $n The number used to determine the plural form |
149
|
|
|
* @return integer |
150
|
|
|
* @link http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms |
151
|
|
|
*/ |
152
|
|
|
private function plural($lang, $n) |
153
|
|
|
{ |
154
|
|
|
switch ($lang) { |
155
|
|
|
// Note: expressions in .po files are not strict C expressions, so extra braces might be |
156
|
|
|
// needed for that expression to work here (for example see 'lt') |
157
|
|
|
case 'ar': |
158
|
|
|
return ($n == 0) ? 0 : ($n == 1 ? 1 : ($n == 2 ? 2 : (($n%100 >= 3 && $n%100 <= 10) ? 3 : (($n%100 >= 11 && $n%100 <= 99) || ($n%100 == 1) || ($n%100 == 2) ? 4 : 5)))); |
159
|
|
|
case 'bn': |
160
|
|
|
return 0; |
161
|
|
|
case 'cy': |
162
|
|
|
return ($n == 1) ? 0 : ($n == 2 ? 1 : (($n != 8 && $n != 11) ? 2 : 3)); |
163
|
|
|
case 'cs': |
164
|
|
|
return ($n == 1) ? 0 : (($n >= 2 && $n <= 4) ? 1 : 2); |
165
|
|
|
case 'da': |
166
|
|
|
return $n != 1; |
167
|
|
|
case 'de': |
168
|
|
|
return $n != 1; |
169
|
|
|
case 'el': |
170
|
|
|
return $n != 1; |
171
|
|
|
case 'en': |
172
|
|
|
return $n != 1; |
173
|
|
|
case 'es': |
174
|
|
|
return $n != 1; |
175
|
|
|
case 'eu': |
176
|
|
|
return $n != 1; |
177
|
|
|
case 'fa': |
178
|
|
|
return $n != 1; |
179
|
|
|
case 'fi': |
180
|
|
|
return $n != 1; |
181
|
|
|
case 'fr': |
182
|
|
|
return $n > 1; |
183
|
|
|
case 'he': |
184
|
|
|
return $n != 1; |
185
|
|
|
case 'hi': |
186
|
|
|
return $n != 1; |
187
|
|
|
case 'hu': |
188
|
|
|
return $n != 1; |
189
|
|
|
case 'id': |
190
|
|
|
return 0; |
191
|
|
|
case 'it': |
192
|
|
|
return $n != 1; |
193
|
|
|
case 'ja': |
194
|
|
|
return 0; |
195
|
|
|
case 'ko': |
196
|
|
|
return 0; |
197
|
|
View Code Duplication |
case 'lt': |
198
|
|
|
return ($n%10 == 1 && $n%100 != 11) ? 0 : ($n%10 >= 2 && ($n%100 < 10 || $n%100 >= 20) ? 1 : 2); |
199
|
|
|
case 'lv': |
200
|
|
|
return ($n%10 == 1 && $n%100 != 11) ? 0 : ($n != 0 ? 1 : 2); |
201
|
|
|
case 'nb': |
202
|
|
|
return $n != 1; |
203
|
|
|
case 'nl': |
204
|
|
|
return $n != 1; |
205
|
|
View Code Duplication |
case 'pl': |
206
|
|
|
return ($n == 1) ? 0 : ($n%10 >= 2 && $n%10 <= 4 && ($n%100 < 10 || $n%100 >= 20) ? 1 : 2); |
207
|
|
|
case 'pt': |
208
|
|
|
return $n != 1; |
209
|
|
|
case 'pt-br': |
210
|
|
|
return $n > 1; |
211
|
|
|
case 'ro': |
212
|
|
|
return ($n == 1) ? 0 : (($n == 0 || ($n%100 > 0 && $n%100 < 20)) ? 1 : 2); |
213
|
|
View Code Duplication |
case 'ru': |
214
|
|
|
return ($n%10 == 1 && $n%100 != 11) ? 0 : ($n%10 >= 2 && $n%10 <= 4 && ($n%100 < 10 || $n%100 >= 20) ? 1 : 2); |
215
|
|
|
case 'sl': |
216
|
|
|
return ($n%100 == 1) ? 0 : ($n%100 == 2 ? 1 : ($n%100 == 3 || n%100 == 4 ? 2 : 3)); |
217
|
|
View Code Duplication |
case 'sr': |
218
|
|
|
return ($n%10 == 1 && $n%100 != 11) ? 0 : ($n%10 >= 2 && $n%10 <= 4 && ($n%100 < 10 || $n%100 >= 20) ? 1 : 2); |
219
|
|
|
case 'sv': |
220
|
|
|
return $n != 1; |
221
|
|
|
case 'th': |
222
|
|
|
return 0; |
223
|
|
|
case 'tr': |
224
|
|
|
return 0; |
225
|
|
|
case 'tw': |
226
|
|
|
return 0; |
227
|
|
View Code Duplication |
case 'uk': |
228
|
|
|
return ($n%10 == 1 && $n%100 != 11) ? 0 : ($n%10 >= 2 && $n%10 <= 4 && ($n%100 < 10 || $n%100 >= 20) ? 1 : 2); |
229
|
|
|
case 'vi': |
230
|
|
|
return 0; |
231
|
|
|
case 'zh': |
232
|
|
|
return 0; |
233
|
|
|
default: |
234
|
|
|
//plural expressions can't return negative values, so use -1 to signal unsupported language |
235
|
|
|
return -1; |
236
|
|
|
} |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
} |
240
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.