|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @author Andreas Ergenzinger <[email protected]> |
|
4
|
|
|
* @author Andreas Fischer <[email protected]> |
|
5
|
|
|
* @author Bart Visscher <[email protected]> |
|
6
|
|
|
* @author Bernhard Posselt <[email protected]> |
|
7
|
|
|
* @author Felix Moeller <[email protected]> |
|
8
|
|
|
* @author Jakob Sack <[email protected]> |
|
9
|
|
|
* @author Jan-Christoph Borchardt <[email protected]> |
|
10
|
|
|
* @author Joas Schilling <[email protected]> |
|
11
|
|
|
* @author Jörn Friedrich Dreyer <[email protected]> |
|
12
|
|
|
* @author Lennart Rosam <[email protected]> |
|
13
|
|
|
* @author Lukas Reschke <[email protected]> |
|
14
|
|
|
* @author Morris Jobke <[email protected]> |
|
15
|
|
|
* @author Robin Appelman <[email protected]> |
|
16
|
|
|
* @author Robin McCorkell <[email protected]> |
|
17
|
|
|
* @author Scrutinizer Auto-Fixer <[email protected]> |
|
18
|
|
|
* @author Thomas Müller <[email protected]> |
|
19
|
|
|
* @author Thomas Tanghus <[email protected]> |
|
20
|
|
|
* @author Vincent Petry <[email protected]> |
|
21
|
|
|
* |
|
22
|
|
|
* @copyright Copyright (c) 2015, ownCloud, Inc. |
|
23
|
|
|
* @license AGPL-3.0 |
|
24
|
|
|
* |
|
25
|
|
|
* This code is free software: you can redistribute it and/or modify |
|
26
|
|
|
* it under the terms of the GNU Affero General Public License, version 3, |
|
27
|
|
|
* as published by the Free Software Foundation. |
|
28
|
|
|
* |
|
29
|
|
|
* This program is distributed in the hope that it will be useful, |
|
30
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
31
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
32
|
|
|
* GNU Affero General Public License for more details. |
|
33
|
|
|
* |
|
34
|
|
|
* You should have received a copy of the GNU Affero General Public License, version 3, |
|
35
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/> |
|
36
|
|
|
* |
|
37
|
|
|
*/ |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* This class is for i18n and l10n |
|
41
|
|
|
*/ |
|
42
|
|
|
class OC_L10N implements \OCP\IL10N { |
|
43
|
|
|
/** |
|
44
|
|
|
* cache |
|
45
|
|
|
*/ |
|
46
|
|
|
protected static $cache = array(); |
|
47
|
|
|
protected static $availableLanguages = array(); |
|
48
|
|
|
|
|
49
|
|
|
/** |
|
50
|
|
|
* The best language |
|
51
|
|
|
*/ |
|
52
|
|
|
protected static $language = ''; |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* App of this object |
|
56
|
|
|
*/ |
|
57
|
|
|
protected $app; |
|
58
|
|
|
|
|
59
|
|
|
/** |
|
60
|
|
|
* Language of this object |
|
61
|
|
|
*/ |
|
62
|
|
|
protected $lang; |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* Translations |
|
66
|
|
|
*/ |
|
67
|
|
|
private $translations = array(); |
|
68
|
|
|
|
|
69
|
|
|
/** |
|
70
|
|
|
* Plural forms (string) |
|
71
|
|
|
*/ |
|
72
|
|
|
private $pluralFormString = 'nplurals=2; plural=(n != 1);'; |
|
73
|
|
|
|
|
74
|
|
|
/** |
|
75
|
|
|
* Plural forms (function) |
|
76
|
|
|
*/ |
|
77
|
|
|
private $pluralFormFunction = null; |
|
78
|
|
|
|
|
79
|
|
|
/** |
|
80
|
|
|
* get an L10N instance |
|
81
|
|
|
* @param string $app |
|
82
|
|
|
* @param string|null $lang |
|
83
|
|
|
* @return \OCP\IL10N |
|
84
|
|
|
* @deprecated Use \OC::$server->getL10NFactory()->get() instead |
|
85
|
|
|
*/ |
|
86
|
1 |
|
public static function get($app, $lang=null) { |
|
87
|
1 |
|
return \OC::$server->getL10NFactory()->get($app, $lang); |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* The constructor |
|
92
|
|
|
* @param string $app app requesting l10n |
|
93
|
|
|
* @param string $lang default: null Language |
|
94
|
|
|
* |
|
95
|
|
|
* If language is not set, the constructor tries to find the right |
|
96
|
|
|
* language. |
|
97
|
|
|
*/ |
|
98
|
121 |
|
public function __construct($app, $lang = null) { |
|
99
|
121 |
|
$this->app = $app; |
|
100
|
121 |
|
$this->lang = $lang; |
|
101
|
121 |
|
} |
|
102
|
|
|
|
|
103
|
|
|
/** |
|
104
|
|
|
* @return string |
|
105
|
|
|
*/ |
|
106
|
6 |
|
public static function setLanguageFromRequest() { |
|
107
|
6 |
|
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { |
|
108
|
5 |
|
$available = self::findAvailableLanguages(); |
|
109
|
|
|
|
|
110
|
|
|
// E.g. make sure that 'de' is before 'de_DE'. |
|
111
|
5 |
|
sort($available); |
|
112
|
|
|
|
|
113
|
5 |
|
$preferences = preg_split('/,\s*/', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])); |
|
114
|
5 |
|
foreach ($preferences as $preference) { |
|
115
|
5 |
|
list($preferred_language) = explode(';', $preference); |
|
116
|
5 |
|
$preferred_language = str_replace('-', '_', $preferred_language); |
|
117
|
5 |
View Code Duplication |
foreach ($available as $available_language) { |
|
|
|
|
|
|
118
|
5 |
|
if ($preferred_language === strtolower($available_language)) { |
|
119
|
2 |
|
if (!self::$language) { |
|
120
|
2 |
|
self::$language = $available_language; |
|
121
|
2 |
|
} |
|
122
|
2 |
|
return $available_language; |
|
123
|
|
|
} |
|
124
|
5 |
|
} |
|
125
|
3 |
View Code Duplication |
foreach ($available as $available_language) { |
|
|
|
|
|
|
126
|
3 |
|
if (substr($preferred_language, 0, 2) === $available_language) { |
|
127
|
2 |
|
if (!self::$language) { |
|
128
|
2 |
|
self::$language = $available_language; |
|
129
|
2 |
|
} |
|
130
|
2 |
|
return $available_language; |
|
131
|
|
|
} |
|
132
|
3 |
|
} |
|
133
|
1 |
|
} |
|
134
|
1 |
|
} |
|
135
|
|
|
|
|
136
|
2 |
|
self::$language = 'en'; |
|
137
|
|
|
// Last try: English |
|
138
|
2 |
|
return 'en'; |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
/** |
|
142
|
|
|
* @param $transFile |
|
143
|
|
|
* @param bool $mergeTranslations |
|
144
|
|
|
* @return bool |
|
145
|
|
|
*/ |
|
146
|
3 |
|
public function load($transFile, $mergeTranslations = false) { |
|
147
|
3 |
|
$this->app = true; |
|
148
|
|
|
|
|
149
|
3 |
|
$json = json_decode(file_get_contents($transFile), true); |
|
150
|
3 |
|
if (!is_array($json)) { |
|
151
|
|
|
return false; |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
3 |
|
$this->pluralFormString = $json['pluralForm']; |
|
155
|
3 |
|
$translations = $json['translations']; |
|
156
|
|
|
|
|
157
|
3 |
|
if ($mergeTranslations) { |
|
158
|
|
|
$this->translations = array_merge($this->translations, $translations); |
|
159
|
|
|
} else { |
|
160
|
3 |
|
$this->translations = $translations; |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
3 |
|
return true; |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
170 |
|
protected function init() { |
|
167
|
170 |
|
if ($this->app === true) { |
|
168
|
112 |
|
return; |
|
169
|
|
|
} |
|
170
|
82 |
|
$app = OC_App::cleanAppId($this->app); |
|
171
|
82 |
|
$lang = str_replace(array('\0', '/', '\\', '..'), '', $this->lang); |
|
172
|
82 |
|
$this->app = true; |
|
173
|
|
|
// Find the right language |
|
174
|
82 |
|
if(is_null($lang) || $lang == '') { |
|
175
|
3 |
|
$lang = self::findLanguage($app); |
|
176
|
3 |
|
} |
|
177
|
|
|
|
|
178
|
|
|
// Use cache if possible |
|
179
|
82 |
|
if(array_key_exists($app.'::'.$lang, self::$cache)) { |
|
180
|
74 |
|
$this->translations = self::$cache[$app.'::'.$lang]['t']; |
|
181
|
74 |
|
} else{ |
|
182
|
8 |
|
$i18nDir = self::findI18nDir($app); |
|
183
|
8 |
|
$transFile = strip_tags($i18nDir).strip_tags($lang).'.json'; |
|
184
|
|
|
// Texts are in $i18ndir |
|
185
|
|
|
// (Just no need to define date/time format etc. twice) |
|
186
|
8 |
|
if((OC_Helper::isSubDirectory($transFile, OC::$SERVERROOT.'/core/l10n/') |
|
187
|
8 |
|
|| OC_Helper::isSubDirectory($transFile, OC::$SERVERROOT.'/lib/l10n/') |
|
188
|
8 |
|
|| OC_Helper::isSubDirectory($transFile, OC::$SERVERROOT.'/settings') |
|
189
|
8 |
|
|| OC_Helper::isSubDirectory($transFile, OC_App::getAppPath($app).'/l10n/') |
|
190
|
8 |
|
) |
|
191
|
8 |
|
&& file_exists($transFile)) { |
|
192
|
|
|
// load the translations file |
|
193
|
|
|
$this->load($transFile); |
|
194
|
|
|
} |
|
195
|
|
|
|
|
196
|
|
|
//merge with translations from theme |
|
197
|
|
|
$theme = \OC::$server->getConfig()->getSystemValue('theme'); |
|
198
|
|
|
if (!empty($theme)) { |
|
199
|
|
|
$transFile = OC::$SERVERROOT.'/themes/'.$theme.substr($transFile, strlen(OC::$SERVERROOT)); |
|
200
|
|
|
if (file_exists($transFile)) { |
|
201
|
|
|
$this->load($transFile, true); |
|
202
|
|
|
} |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
8 |
|
self::$cache[$app.'::'.$lang]['t'] = $this->translations; |
|
206
|
|
|
} |
|
207
|
82 |
|
} |
|
208
|
|
|
|
|
209
|
|
|
/** |
|
210
|
|
|
* Creates a function that The constructor |
|
211
|
|
|
* |
|
212
|
|
|
* If language is not set, the constructor tries to find the right |
|
213
|
|
|
* language. |
|
214
|
|
|
* |
|
215
|
|
|
* Parts of the code is copied from Habari: |
|
216
|
|
|
* https://github.com/habari/system/blob/master/classes/locale.php |
|
217
|
|
|
* @param string $string |
|
218
|
|
|
* @return string |
|
219
|
|
|
*/ |
|
220
|
5 |
|
protected function createPluralFormFunction($string){ |
|
221
|
5 |
|
if(preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) { |
|
222
|
|
|
// sanitize |
|
223
|
5 |
|
$nplurals = preg_replace( '/[^0-9]/', '', $matches[1] ); |
|
224
|
5 |
|
$plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] ); |
|
225
|
|
|
|
|
226
|
5 |
|
$body = str_replace( |
|
227
|
5 |
|
array( 'plural', 'n', '$n$plurals', ), |
|
228
|
5 |
|
array( '$plural', '$n', '$nplurals', ), |
|
229
|
5 |
|
'nplurals='. $nplurals . '; plural=' . $plural |
|
230
|
5 |
|
); |
|
231
|
|
|
|
|
232
|
|
|
// add parents |
|
233
|
|
|
// important since PHP's ternary evaluates from left to right |
|
234
|
5 |
|
$body .= ';'; |
|
235
|
5 |
|
$res = ''; |
|
236
|
5 |
|
$p = 0; |
|
237
|
5 |
|
for($i = 0; $i < strlen($body); $i++) { |
|
238
|
5 |
|
$ch = $body[$i]; |
|
239
|
|
|
switch ( $ch ) { |
|
240
|
5 |
|
case '?': |
|
241
|
2 |
|
$res .= ' ? ('; |
|
242
|
2 |
|
$p++; |
|
243
|
2 |
|
break; |
|
244
|
5 |
|
case ':': |
|
245
|
2 |
|
$res .= ') : ('; |
|
246
|
2 |
|
break; |
|
247
|
5 |
|
case ';': |
|
248
|
5 |
|
$res .= str_repeat( ')', $p ) . ';'; |
|
249
|
5 |
|
$p = 0; |
|
250
|
5 |
|
break; |
|
251
|
5 |
|
default: |
|
252
|
5 |
|
$res .= $ch; |
|
253
|
5 |
|
} |
|
254
|
5 |
|
} |
|
255
|
|
|
|
|
256
|
5 |
|
$body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);'; |
|
257
|
5 |
|
return create_function('$n', $body); |
|
258
|
|
|
} |
|
259
|
|
|
else { |
|
260
|
|
|
// default: one plural form for all cases but n==1 (english) |
|
261
|
|
|
return create_function( |
|
262
|
|
|
'$n', |
|
263
|
|
|
'$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);' |
|
264
|
|
|
); |
|
265
|
|
|
} |
|
266
|
|
|
} |
|
267
|
|
|
|
|
268
|
|
|
/** |
|
269
|
|
|
* Translating |
|
270
|
|
|
* @param string $text The text we need a translation for |
|
271
|
|
|
* @param array $parameters default:array() Parameters for sprintf |
|
272
|
|
|
* @return \OC_L10N_String Translation or the same text |
|
273
|
|
|
* |
|
274
|
|
|
* Returns the translation. If no translation is found, $text will be |
|
275
|
|
|
* returned. |
|
276
|
|
|
*/ |
|
277
|
143 |
|
public function t($text, $parameters = array()) { |
|
278
|
143 |
|
return new OC_L10N_String($this, $text, $parameters); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
/** |
|
282
|
|
|
* Translating |
|
283
|
|
|
* @param string $text_singular the string to translate for exactly one object |
|
284
|
|
|
* @param string $text_plural the string to translate for n objects |
|
285
|
|
|
* @param integer $count Number of objects |
|
286
|
|
|
* @param array $parameters default:array() Parameters for sprintf |
|
287
|
|
|
* @return \OC_L10N_String Translation or the same text |
|
288
|
|
|
* |
|
289
|
|
|
* Returns the translation. If no translation is found, $text will be |
|
290
|
|
|
* returned. %n will be replaced with the number of objects. |
|
291
|
|
|
* |
|
292
|
|
|
* The correct plural is determined by the plural_forms-function |
|
293
|
|
|
* provided by the po file. |
|
294
|
|
|
* |
|
295
|
|
|
*/ |
|
296
|
40 |
|
public function n($text_singular, $text_plural, $count, $parameters = array()) { |
|
297
|
40 |
|
$this->init(); |
|
298
|
40 |
|
$identifier = "_${text_singular}_::_${text_plural}_"; |
|
299
|
40 |
|
if( array_key_exists($identifier, $this->translations)) { |
|
300
|
11 |
|
return new OC_L10N_String( $this, $identifier, $parameters, $count ); |
|
301
|
|
|
}else{ |
|
302
|
29 |
|
if($count === 1) { |
|
303
|
4 |
|
return new OC_L10N_String($this, $text_singular, $parameters, $count); |
|
304
|
|
|
}else{ |
|
305
|
25 |
|
return new OC_L10N_String($this, $text_plural, $parameters, $count); |
|
306
|
|
|
} |
|
307
|
|
|
} |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
|
|
/** |
|
311
|
|
|
* getTranslations |
|
312
|
|
|
* @return array Fetch all translations |
|
313
|
|
|
* |
|
314
|
|
|
* Returns an associative array with all translations |
|
315
|
|
|
*/ |
|
316
|
|
|
public function getTranslations() { |
|
317
|
131 |
|
$this->init(); |
|
318
|
131 |
|
return $this->translations; |
|
319
|
|
|
} |
|
320
|
|
|
|
|
321
|
|
|
/** |
|
322
|
|
|
* getPluralFormFunction |
|
323
|
|
|
* @return string the plural form function |
|
324
|
|
|
* |
|
325
|
|
|
* returned function accepts the argument $n |
|
326
|
|
|
*/ |
|
327
|
|
|
public function getPluralFormFunction() { |
|
328
|
11 |
|
$this->init(); |
|
329
|
11 |
|
if(is_null($this->pluralFormFunction)) { |
|
330
|
5 |
|
$this->pluralFormFunction = $this->createPluralFormFunction($this->pluralFormString); |
|
331
|
5 |
|
} |
|
332
|
11 |
|
return $this->pluralFormFunction; |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* Localization |
|
337
|
|
|
* @param string $type Type of localization |
|
338
|
|
|
* @param array|int|string $data parameters for this localization |
|
339
|
|
|
* @param array $options |
|
340
|
|
|
* @return string|false |
|
341
|
|
|
* |
|
342
|
|
|
* Returns the localized data. |
|
343
|
|
|
* |
|
344
|
|
|
* Implemented types: |
|
345
|
|
|
* - date |
|
346
|
|
|
* - Creates a date |
|
347
|
|
|
* - params: timestamp (int/string) |
|
348
|
|
|
* - datetime |
|
349
|
|
|
* - Creates date and time |
|
350
|
|
|
* - params: timestamp (int/string) |
|
351
|
|
|
* - time |
|
352
|
|
|
* - Creates a time |
|
353
|
|
|
* - params: timestamp (int/string) |
|
354
|
|
|
*/ |
|
355
|
|
|
public function l($type, $data, $options = array()) { |
|
356
|
41 |
|
if ($type === 'firstday') { |
|
357
|
2 |
|
return $this->getFirstWeekDay(); |
|
|
|
|
|
|
358
|
|
|
} |
|
359
|
39 |
|
if ($type === 'jsdate') { |
|
360
|
|
|
return $this->getDateFormat(); |
|
361
|
|
|
} |
|
362
|
|
|
|
|
363
|
39 |
|
$this->init(); |
|
364
|
39 |
|
$value = new DateTime(); |
|
365
|
39 |
|
if($data instanceof DateTime) { |
|
366
|
27 |
|
$value = $data; |
|
367
|
39 |
|
} elseif(is_string($data) && !is_numeric($data)) { |
|
368
|
|
|
$data = strtotime($data); |
|
369
|
|
|
$value->setTimestamp($data); |
|
370
|
|
|
} else { |
|
371
|
12 |
|
$value->setTimestamp($data); |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
|
|
// Use the language of the instance, before falling back to the current user's language |
|
375
|
39 |
|
$locale = $this->lang; |
|
376
|
39 |
|
if ($locale === null) { |
|
377
|
6 |
|
$locale = self::findLanguage(); |
|
378
|
6 |
|
} |
|
379
|
39 |
|
$locale = $this->transformToCLDRLocale($locale); |
|
380
|
|
|
|
|
381
|
39 |
|
$options = array_merge(array('width' => 'long'), $options); |
|
382
|
39 |
|
$width = $options['width']; |
|
383
|
|
|
switch($type) { |
|
384
|
39 |
|
case 'date': |
|
385
|
10 |
|
return Punic\Calendar::formatDate($value, $width, $locale); |
|
386
|
30 |
|
case 'datetime': |
|
387
|
22 |
|
return Punic\Calendar::formatDatetime($value, $width, $locale); |
|
388
|
8 |
|
case 'time': |
|
389
|
8 |
|
return Punic\Calendar::formatTime($value, $width, $locale); |
|
390
|
|
|
default: |
|
391
|
|
|
return false; |
|
392
|
|
|
} |
|
393
|
|
|
} |
|
394
|
|
|
|
|
395
|
|
|
/** |
|
396
|
|
|
* The code (en, de, ...) of the language that is used for this OC_L10N object |
|
397
|
|
|
* |
|
398
|
|
|
* @return string language |
|
399
|
|
|
*/ |
|
400
|
|
|
public function getLanguageCode() { |
|
401
|
5 |
|
return $this->lang ? $this->lang : self::findLanguage(); |
|
402
|
|
|
} |
|
403
|
|
|
|
|
404
|
|
|
/** |
|
405
|
|
|
* find the best language |
|
406
|
|
|
* @param string $app |
|
407
|
|
|
* @return string language |
|
408
|
|
|
* |
|
409
|
|
|
* If nothing works it returns 'en' |
|
410
|
|
|
*/ |
|
411
|
|
|
public static function findLanguage($app = null) { |
|
412
|
18 |
|
if (self::$language != '' && self::languageExists($app, self::$language)) { |
|
413
|
10 |
|
return self::$language; |
|
414
|
|
|
} |
|
415
|
|
|
|
|
416
|
8 |
|
$config = \OC::$server->getConfig(); |
|
417
|
8 |
|
$userId = \OC_User::getUser(); |
|
418
|
|
|
|
|
419
|
8 |
|
if($userId && $config->getUserValue($userId, 'core', 'lang')) { |
|
420
|
|
|
$lang = $config->getUserValue($userId, 'core', 'lang'); |
|
421
|
|
|
self::$language = $lang; |
|
422
|
|
|
if(self::languageExists($app, $lang)) { |
|
423
|
|
|
return $lang; |
|
424
|
|
|
} |
|
425
|
|
|
} |
|
426
|
|
|
|
|
427
|
8 |
|
$default_language = $config->getSystemValue('default_language', false); |
|
428
|
|
|
|
|
429
|
8 |
|
if($default_language !== false) { |
|
430
|
2 |
|
return $default_language; |
|
431
|
|
|
} |
|
432
|
|
|
|
|
433
|
6 |
|
$lang = self::setLanguageFromRequest(); |
|
434
|
6 |
|
if($userId && !$config->getUserValue($userId, 'core', 'lang')) { |
|
435
|
|
|
$config->setUserValue($userId, 'core', 'lang', $lang); |
|
436
|
|
|
} |
|
437
|
|
|
|
|
438
|
6 |
|
return $lang; |
|
439
|
|
|
} |
|
440
|
|
|
|
|
441
|
|
|
/** |
|
442
|
|
|
* find the l10n directory |
|
443
|
|
|
* @param string $app App that needs to be translated |
|
444
|
|
|
* @return string directory |
|
445
|
|
|
*/ |
|
446
|
|
|
protected static function findI18nDir($app) { |
|
447
|
|
|
// find the i18n dir |
|
448
|
9 |
|
$i18nDir = OC::$SERVERROOT.'/core/l10n/'; |
|
449
|
9 |
|
if($app != '') { |
|
450
|
|
|
// Check if the app is in the app folder |
|
451
|
8 |
|
if(file_exists(OC_App::getAppPath($app).'/l10n/')) { |
|
452
|
2 |
|
$i18nDir = OC_App::getAppPath($app).'/l10n/'; |
|
453
|
2 |
|
} |
|
454
|
|
|
else{ |
|
455
|
6 |
|
$i18nDir = OC::$SERVERROOT.'/'.$app.'/l10n/'; |
|
456
|
|
|
} |
|
457
|
8 |
|
} |
|
458
|
9 |
|
return $i18nDir; |
|
459
|
|
|
} |
|
460
|
|
|
|
|
461
|
|
|
/** |
|
462
|
|
|
* find all available languages for an app |
|
463
|
|
|
* @param string $app App that needs to be translated |
|
464
|
|
|
* @return array an array of available languages |
|
465
|
|
|
*/ |
|
466
|
|
|
public static function findAvailableLanguages($app=null) { |
|
467
|
|
|
// also works with null as key |
|
468
|
5 |
|
if(isset(self::$availableLanguages[$app]) && !empty(self::$availableLanguages[$app])) { |
|
469
|
4 |
|
return self::$availableLanguages[$app]; |
|
470
|
|
|
} |
|
471
|
1 |
|
$available=array('en');//english is always available |
|
472
|
1 |
|
$dir = self::findI18nDir($app); |
|
473
|
1 |
View Code Duplication |
if(is_dir($dir)) { |
|
|
|
|
|
|
474
|
1 |
|
$files=scandir($dir); |
|
475
|
1 |
|
foreach($files as $file) { |
|
476
|
1 |
|
if(substr($file, -5, 5) === '.json' && substr($file, 0, 4) !== 'l10n') { |
|
477
|
1 |
|
$i = substr($file, 0, -5); |
|
478
|
1 |
|
$available[] = $i; |
|
479
|
1 |
|
} |
|
480
|
1 |
|
} |
|
481
|
1 |
|
} |
|
482
|
|
|
|
|
483
|
1 |
|
$config = \OC::$server->getConfig(); |
|
484
|
1 |
|
// merge with translations from theme |
|
485
|
|
|
$theme = $config->getSystemValue('theme'); |
|
486
|
|
|
if(!empty($theme)) { |
|
487
|
|
|
$themeDir = \OC::$SERVERROOT . '/themes/' . $theme . substr($dir, strlen(\OC::$SERVERROOT)); |
|
488
|
|
View Code Duplication |
if(is_dir($themeDir)) { |
|
|
|
|
|
|
489
|
|
|
$files=scandir($dir); |
|
490
|
|
|
foreach($files as $file) { |
|
491
|
|
|
if(substr($file, -5, 5) === '.json' && substr($file, 0, 4) !== 'l10n') { |
|
492
|
|
|
$i = substr($file, 0, -5); |
|
493
|
10 |
|
$available[] = $i; |
|
494
|
10 |
|
} |
|
495
|
|
|
} |
|
496
|
|
|
} |
|
497
|
|
|
} |
|
498
|
|
|
|
|
499
|
|
|
self::$availableLanguages[$app] = $available; |
|
500
|
|
|
return $available; |
|
501
|
|
|
} |
|
502
|
|
|
|
|
503
|
|
|
/** |
|
504
|
|
|
* @param string $app |
|
505
|
|
|
* @param string $lang |
|
506
|
|
|
* @return bool |
|
507
|
|
|
*/ |
|
508
|
|
|
public static function languageExists($app, $lang) { |
|
509
|
|
|
if ($lang === 'en') {//english is always available |
|
510
|
|
|
return true; |
|
511
|
|
|
} |
|
512
|
|
|
$dir = self::findI18nDir($app); |
|
513
|
|
|
if(is_dir($dir)) { |
|
514
|
|
|
return file_exists($dir.'/'.$lang.'.json'); |
|
515
|
|
|
} |
|
516
|
|
|
return false; |
|
517
|
2 |
|
} |
|
518
|
2 |
|
|
|
519
|
2 |
|
/** |
|
520
|
|
|
* @return string |
|
521
|
|
|
* @throws \Punic\Exception\ValueNotInList |
|
522
|
|
|
*/ |
|
523
|
41 |
|
public function getDateFormat() { |
|
524
|
|
|
$locale = $this->getLanguageCode(); |
|
525
|
|
|
$locale = $this->transformToCLDRLocale($locale); |
|
526
|
|
|
return Punic\Calendar::getDateFormat('short', $locale); |
|
527
|
41 |
|
} |
|
528
|
|
|
|
|
529
|
|
|
/** |
|
530
|
|
|
* @return int |
|
531
|
|
|
*/ |
|
532
|
|
|
public function getFirstWeekDay() { |
|
533
|
|
|
$locale = $this->getLanguageCode(); |
|
534
|
|
|
$locale = $this->transformToCLDRLocale($locale); |
|
535
|
|
|
return Punic\Calendar::getFirstWeekday($locale); |
|
536
|
|
|
} |
|
537
|
|
|
|
|
538
|
|
|
private function transformToCLDRLocale($locale) { |
|
539
|
|
|
if ($locale === 'sr@latin') { |
|
540
|
|
|
return 'sr_latn'; |
|
541
|
|
|
} |
|
542
|
|
|
|
|
543
|
|
|
return $locale; |
|
544
|
|
|
} |
|
545
|
|
|
} |
|
546
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.