Test Failed
Push — master ( 8c47c2...3acf9f )
by Steve
12:37
created

engine/classes/Elgg/I18n/Translator.php (12 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Elgg\I18n;
3
4
use Elgg\Config;
5
6
/**
7
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
8
 *
9
 * @access private
10
 *
11
 * @since 1.10.0
12
 */
13
class Translator {
14
15
	/**
16
	 * @var Config
17
	 */
18
	private $config;
19
20
	/**
21
	 * Constructor
22
	 *
23
	 * @param Config $config Elgg config
24
	 */
25 322
	public function __construct(Config $config) {
26 322
		$this->config = $config;
27 322
		$this->defaultPath = dirname(dirname(dirname(dirname(__DIR__)))) . "/languages/";
28 322
	}
29
30
	/**
31
	 * Given a message key, returns an appropriately translated full-text string
32
	 *
33
	 * @param string $message_key The short message code
34
	 * @param array  $args        An array of arguments to pass through vsprintf().
35
	 * @param string $language    Optionally, the standard language code
36
	 *                            (defaults to site/user default, then English)
37
	 *
38
	 * @return string Either the translated string, the English string,
39
	 * or the original language string.
40
	 */
41 41
	public function translate($message_key, array $args = [], $language = "") {
0 ignored issues
show
translate uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
42
		// TODO find a way to cache getLanguage() and get rid of this
43 41
		static $CURRENT_LANGUAGE;
44
		
45 41
		if (!is_string($message_key) || strlen($message_key) < 1) {
46
			_elgg_services()->logger->warn(
47
				'$message_key needs to be a string in ' . __METHOD__ . '(), ' . gettype($message_key) . ' provided'
48
			);
49
			return '';
50
		}
51
		
52 41
		if (!$CURRENT_LANGUAGE) {
53
			$CURRENT_LANGUAGE = $this->getCurrentLanguage();
54
		}
55 41
		if (!$language) {
56 22
			$language = $CURRENT_LANGUAGE;
57
		}
58
59 41
		$this->ensureTranslationsLoaded($language);
60
61 41
		$notice = '';
62 41
		$string = $message_key;
63
64
		// avoid dupes without overhead of array_unique
65 41
		$langs[$language] = true;
66 41
		$langs['en'] = true;
67
68 41
		foreach (array_keys($langs) as $try_lang) {
69 41
			if (isset($GLOBALS['_ELGG']->translations[$try_lang][$message_key])) {
70 40
				$string = $GLOBALS['_ELGG']->translations[$try_lang][$message_key];
71
72
				// only pass through if we have arguments to allow backward compatibility
73
				// with manual sprintf() calls.
74 40
				if ($args) {
75 33
					$string = vsprintf($string, $args);
76
				}
77
78 40
				break;
79
			} else {
80 3
				$notice = sprintf(
81 3
					'Missing %s translation for "%s" language key',
82 3
					($try_lang === 'en') ? 'English' : $try_lang,
83 3
					$message_key
84
				);
85
			}
86
		}
87
88 41
		if ($notice) {
89 3
			_elgg_services()->logger->notice($notice);
90
		}
91
92 41
		return $string;
93
	}
94
95
	/**
96
	 * Add a translation.
97
	 *
98
	 * Translations are arrays in the Zend Translation array format, eg:
99
	 *
100
	 *	$english = array('message1' => 'message1', 'message2' => 'message2');
101
	 *  $german = array('message1' => 'Nachricht1','message2' => 'Nachricht2');
102
	 *
103
	 * @param string $country_code   Standard country code (eg 'en', 'nl', 'es')
104
	 * @param array  $language_array Formatted array of strings
105
	 *
106
	 * @return bool Depending on success
107
	 */
108 138
	public function addTranslation($country_code, $language_array) {
0 ignored issues
show
addTranslation uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
109
110 138
		if (!isset($GLOBALS['_ELGG']->translations)) {
111
			$GLOBALS['_ELGG']->translations = [];
112
		}
113
114 138
		$country_code = strtolower($country_code);
115 138
		$country_code = trim($country_code);
116 138
		if (is_array($language_array) && $country_code != "") {
117 138
			if (sizeof($language_array) > 0) {
118 138
				if (!isset($GLOBALS['_ELGG']->translations[$country_code])) {
119 7
					$GLOBALS['_ELGG']->translations[$country_code] = $language_array;
120
				} else {
121 138
					$GLOBALS['_ELGG']->translations[$country_code] = $language_array + $GLOBALS['_ELGG']->translations[$country_code];
122
				}
123
			}
124 138
			return true;
125
		}
126
		return false;
127
	}
128
129
	/**
130
	 * Get the current system/user language or "en".
131
	 *
132
	 * @return string The language code for the site/user or "en" if not set
133
	 */
134
	public function getCurrentLanguage() {
135
		$language = $this->detectLanguage();
136
137
		if (!$language) {
138
			$language = 'en';
139
		}
140
141
		return $language;
142
	}
143
144
	/**
145
	 * Detect the current system/user language or false.
146
	 *
147
	 * @return string The language code (eg "en") or false if not set
148
	 */
149 1
	public function detectLanguage() {
150 1
		$url_lang = _elgg_services()->input->get('hl');
151 1
		if ($url_lang) {
152 1
			return $url_lang;
153
		}
154
155
		$user = _elgg_services()->session->getLoggedInUser();
156
		$language = false;
157
158
		if (($user) && ($user->language)) {
159
			$language = $user->language;
160
		}
161
162
		if (!$language) {
163
			$site_language = $this->config->getVolatile('language');
164
			if ($site_language) {
165
				$language = $site_language;
166
			}
167
		}
168
169
		return $language ? $language : false;
170
	}
171
172
	/**
173
	 * Load both core and plugin translations
174
	 *
175
	 * By default this loads only English and the language of the logged
176
	 * in user.
177
	 *
178
	 * The optional $language argument can be used to load translations
179
	 * on-demand in case we need to translate something to a language not
180
	 * loaded by default for the current request.
181
	 *
182
	 * @param string $language Language code
183
	 * @access private
184
	 */
185
	public function loadTranslations($language = null) {
0 ignored issues
show
loadTranslations uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
186
		if (elgg_is_system_cache_enabled()) {
187
			$loaded = true;
188
189
			if ($language) {
190
				$languages = [$language];
191
			} else {
192
				$languages = array_unique(['en', $this->getCurrentLanguage()]);
193
			}
194
195
			foreach ($languages as $language) {
196
				$data = elgg_load_system_cache("$language.lang");
197
				if ($data) {
198
					$this->addTranslation($language, unserialize($data));
199
				} else {
200
					$loaded = false;
201
				}
202
			}
203
204
			if ($loaded) {
205
				$GLOBALS['_ELGG']->i18n_loaded_from_cache = true;
206
				// this is here to force
207
				$GLOBALS['_ELGG']->language_paths[$this->defaultPath] = true;
208
				return;
209
			}
210
		}
211
212
		// load core translations from languages directory
213
		$this->registerTranslations($this->defaultPath, false, $language);
214
215
		// Plugin translation have already been loaded for the default
216
		// languages by ElggApplication::bootCore(), so there's no need
217
		// to continue unless loading a specific language on-demand
218
		if ($language) {
1 ignored issue
show
Bug Best Practice introduced by
The expression $language of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
219
			$this->loadPluginTranslations($language);
220
		}
221
	}
222
223
	/**
224
	 * Load plugin translations for a language
225
	 *
226
	 * This is needed only if the current request uses a language
227
	 * that is neither English of the same as the language of the
228
	 * logged in user.
229
	 *
230
	 * @param string $language Language code
231
	 * @return void
232
	 * @throws \PluginException
233
	 */
234
	private function loadPluginTranslations($language) {
235
		// Get active plugins
236
		$plugins = _elgg_services()->plugins->find('active');
237
238
		if (!$plugins) {
239
			// Active plugins were not found, so no need to register plugin translations
240
			return;
241
		}
242
243
		foreach ($plugins as $plugin) {
244
			$languages_path = "{$plugin->getPath()}languages/";
245
246
			if (!is_dir($languages_path)) {
247
				// This plugin doesn't have anything to translate
248
				continue;
249
			}
250
251
			$language_file = "{$languages_path}{$language}.php";
252
253
			if (!file_exists($language_file)) {
254
				// This plugin doesn't have translations for the requested language
255
256
				$name = $plugin->getDisplayName();
257
				_elgg_services()->logger->notice("Plugin $name is missing translations for $language language");
258
259
				continue;
260
			}
261
262
			// Register translations from the plugin languages directory
263
			if (!$this->registerTranslations($languages_path, false, $language)) {
264
				throw new \PluginException(sprintf('Cannot register languages for plugin %s (guid: %s) at %s.',
265
					[$plugin->getID(), $plugin->guid, $languages_path]));
266
			}
267
		}
268
	}
269
270
	/**
271
	 * Registers translations in a directory assuming the standard plugin layout.
272
	 *
273
	 * @param string $path Without the trailing slash.
274
	 *
275
	 * @return bool Success
276
	 */
277
	public function registerPluginTranslations($path) {
278
		$languages_path = rtrim($path, "\\/") . "/languages";
279
280
		// don't need to have translations
281
		if (!is_dir($languages_path)) {
282
			return true;
283
		}
284
285
		return $this->registerTranslations($languages_path);
286
	}
287
288
	/**
289
	 * When given a full path, finds translation files and loads them
290
	 *
291
	 * @param string $path     Full path
292
	 * @param bool   $load_all If true all languages are loaded, if
293
	 *                         false only the current language + en are loaded
294
	 * @param string $language Language code
295
	 *
296
	 * @return bool success
297
	 */
298
	public function registerTranslations($path, $load_all = false, $language = null) {
0 ignored issues
show
registerTranslations uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
299
		$path = sanitise_filepath($path);
300
301
		// Make a note of this path just incase we need to register this language later
302
		if (!isset($GLOBALS['_ELGG']->language_paths)) {
303
			$GLOBALS['_ELGG']->language_paths = [];
304
		}
305
		$GLOBALS['_ELGG']->language_paths[$path] = true;
306
307
		_elgg_services()->logger->info("Translations loaded from: $path");
308
309
		if ($language) {
310
			$load_language_files = ["$language.php"];
311
			$load_all = false;
312
		} else {
313
			// Get the current language based on site defaults and user preference
314
			$current_language = $this->getCurrentLanguage();
315
316
			$load_language_files = [
317
				'en.php',
318
				"$current_language.php"
319
			];
320
321
			$load_language_files = array_unique($load_language_files);
322
		}
323
324
		$handle = opendir($path);
325
		if (!$handle) {
326
			_elgg_services()->logger->error("Could not open language path: $path");
327
			return false;
328
		}
329
330
		$return = true;
331
		while (false !== ($language_file = readdir($handle))) {
332
			// ignore bad files
333
			if (substr($language_file, 0, 1) == '.' || substr($language_file, -4) !== '.php') {
334
				continue;
335
			}
336
337
			if (in_array($language_file, $load_language_files) || $load_all) {
338
				$result = include_once($path . $language_file);
339
				if ($result === false) {
340
					$return = false;
341
					continue;
342
				} elseif (is_array($result)) {
343
					$this->addTranslation(basename($language_file, '.php'), $result);
344
				}
345
			}
346
		}
347
348
		return $return;
349
	}
350
351
	/**
352
	 * Reload all translations from all registered paths.
353
	 *
354
	 * This is only called by functions which need to know all possible translations.
355
	 *
356
	 * @todo Better on demand loading based on language_paths array
357
	 *
358
	 * @return void
359
	 */
360
	public function reloadAllTranslations() {
0 ignored issues
show
reloadAllTranslations uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
361
		static $was_already_called;
362
		if ($was_already_called) {
363
			return;
364
		}
365
366
		if (!empty($GLOBALS['_ELGG']->i18n_loaded_from_cache)) {
367
			$cache = elgg_get_system_cache();
368
			$cache_dir = $cache->getVariable("cache_path");
369
			$filenames = elgg_get_file_list($cache_dir, [], [], [".lang"]);
370
			foreach ($filenames as $filename) {
371
				// Look for files matching for example 'en.lang', 'cmn.lang' or 'pt_br.lang'.
372
				// Note that this regex is just for the system cache. The original language
373
				// files are allowed to have uppercase letters (e.g. pt_BR.php).
374
				if (preg_match('/(([a-z]{2,3})(_[a-z]{2})?)\.lang$/', $filename, $matches)) {
375
					$language = $matches[1];
376
					$data = elgg_load_system_cache("$language.lang");
377
					if ($data) {
1 ignored issue
show
Bug Best Practice introduced by
The expression $data of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
378
						$this->addTranslation($language, unserialize($data));
379
					}
380
				}
381
			}
382
		} else {
383
			foreach ($GLOBALS['_ELGG']->language_paths as $path => $dummy) {
384
				$this->registerTranslations($path, true);
385
			}
386
		}
387
388
		$was_already_called = true;
389
	}
390
391
	/**
392
	 * Return an array of installed translations as an associative
393
	 * array "two letter code" => "native language name".
394
	 *
395
	 * @return array
396
	 */
397
	public function getInstalledTranslations() {
0 ignored issues
show
getInstalledTranslations uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
398
399
400
		// Ensure that all possible translations are loaded
401
		$this->reloadAllTranslations();
402
403
		$installed = [];
404
405
		$admin_logged_in = _elgg_services()->session->isAdminLoggedIn();
406
407
		foreach ($GLOBALS['_ELGG']->translations as $k => $v) {
408
			if ($this->languageKeyExists($k, $k)) {
409
				$lang = $this->translate($k, [], $k);
410
			} else {
411
				$lang = $this->translate($k);
412
			}
413
			
414
			$installed[$k] = $lang;
415
			
416
			if (!$admin_logged_in || ($k === 'en')) {
417
				continue;
418
			}
419
			
420
			$completeness = $this->getLanguageCompleteness($k);
421
			if ($completeness < 100) {
422
				$installed[$k] .= " (" . $completeness . "% " . $this->translate('complete') . ")";
423
			}
424
		}
425
426
		return $installed;
427
	}
428
429
	/**
430
	 * Return the level of completeness for a given language code (compared to english)
431
	 *
432
	 * @param string $language Language
433
	 *
434
	 * @return int
435
	 */
436
	public function getLanguageCompleteness($language) {
0 ignored issues
show
getLanguageCompleteness uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
437
438
439
		// Ensure that all possible translations are loaded
440
		$this->reloadAllTranslations();
441
442
		$language = sanitise_string($language);
443
444
		$en = count($GLOBALS['_ELGG']->translations['en']);
445
446
		$missing = $this->getMissingLanguageKeys($language);
447
		if ($missing) {
448
			$missing = count($missing);
449
		} else {
450
			$missing = 0;
451
		}
452
453
		//$lang = count($GLOBALS['_ELGG']->translations[$language]);
454
		$lang = $en - $missing;
455
456
		return round(($lang / $en) * 100, 2);
457
	}
458
459
	/**
460
	 * Return the translation keys missing from a given language,
461
	 * or those that are identical to the english version.
462
	 *
463
	 * @param string $language The language
464
	 *
465
	 * @return mixed
466
	 */
467
	public function getMissingLanguageKeys($language) {
0 ignored issues
show
getMissingLanguageKeys uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
468
469
470
		// Ensure that all possible translations are loaded
471
		$this->reloadAllTranslations();
472
473
		$missing = [];
474
475
		foreach ($GLOBALS['_ELGG']->translations['en'] as $k => $v) {
476
			if ((!isset($GLOBALS['_ELGG']->translations[$language][$k]))
477
			|| ($GLOBALS['_ELGG']->translations[$language][$k] == $GLOBALS['_ELGG']->translations['en'][$k])) {
478
				$missing[] = $k;
479
			}
480
		}
481
482
		if (count($missing)) {
483
			return $missing;
484
		}
485
486
		return false;
487
	}
488
489
	/**
490
	 * Check if a given language key exists
491
	 *
492
	 * @param string $key      The translation key
493
	 * @param string $language The specific language to check
494
	 *
495
	 * @return bool
496
	 * @since 1.11
497
	 */
498 20
	function languageKeyExists($key, $language = 'en') {
0 ignored issues
show
languageKeyExists uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
499 20
		if (empty($key)) {
500
			return false;
501
		}
502
503 20
		$this->ensureTranslationsLoaded($language);
504
505 20
		if (!array_key_exists($language, $GLOBALS['_ELGG']->translations)) {
506
			return false;
507
		}
508
509 20
		return array_key_exists($key, $GLOBALS['_ELGG']->translations[$language]);
510
	}
511
512
	/**
513
	 * Make sure translations are loaded
514
	 *
515
	 * @param string $language Language
516
	 * @return void
517
	 */
518 43
	private function ensureTranslationsLoaded($language) {
0 ignored issues
show
ensureTranslationsLoaded uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
519 43
		if (!isset($GLOBALS['_ELGG']->translations)) {
520
			// this means we probably had an exception before translations were initialized
521
			$this->registerTranslations($this->defaultPath);
522
		}
523
524 43
		if (!isset($GLOBALS['_ELGG']->translations[$language])) {
525
			// The language being requested is not the same as the language of the
526
			// logged in user, so we will have to load it separately. (Most likely
527
			// we're sending a notification and the recipient is using a different
528
			// language than the logged in user.)
529
			$this->loadTranslations($language);
530
		}
531 43
	}
532
533
	/**
534
	 * Returns an array of language codes.
535
	 *
536
	 * @return array
537
	 */
538
	public static function getAllLanguageCodes() {
539
		return [
540
			"aa", // "Afar"
541
			"ab", // "Abkhazian"
542
			"af", // "Afrikaans"
543
			"am", // "Amharic"
544
			"ar", // "Arabic"
545
			"as", // "Assamese"
546
			"ay", // "Aymara"
547
			"az", // "Azerbaijani"
548
			"ba", // "Bashkir"
549
			"be", // "Byelorussian"
550
			"bg", // "Bulgarian"
551
			"bh", // "Bihari"
552
			"bi", // "Bislama"
553
			"bn", // "Bengali; Bangla"
554
			"bo", // "Tibetan"
555
			"br", // "Breton"
556
			"ca", // "Catalan"
557
			"cmn", // "Mandarin Chinese" // ISO 639-3
558
			"co", // "Corsican"
559
			"cs", // "Czech"
560
			"cy", // "Welsh"
561
			"da", // "Danish"
562
			"de", // "German"
563
			"dz", // "Bhutani"
564
			"el", // "Greek"
565
			"en", // "English"
566
			"eo", // "Esperanto"
567
			"es", // "Spanish"
568
			"et", // "Estonian"
569
			"eu", // "Basque"
570
			"eu_es", // "Basque (Spain)"
571
			"fa", // "Persian"
572
			"fi", // "Finnish"
573
			"fj", // "Fiji"
574
			"fo", // "Faeroese"
575
			"fr", // "French"
576
			"fy", // "Frisian"
577
			"ga", // "Irish"
578
			"gd", // "Scots / Gaelic"
579
			"gl", // "Galician"
580
			"gn", // "Guarani"
581
			"gu", // "Gujarati"
582
			"he", // "Hebrew"
583
			"ha", // "Hausa"
584
			"hi", // "Hindi"
585
			"hr", // "Croatian"
586
			"hu", // "Hungarian"
587
			"hy", // "Armenian"
588
			"ia", // "Interlingua"
589
			"id", // "Indonesian"
590
			"ie", // "Interlingue"
591
			"ik", // "Inupiak"
592
			"is", // "Icelandic"
593
			"it", // "Italian"
594
			"iu", // "Inuktitut"
595
			"iw", // "Hebrew (obsolete)"
596
			"ja", // "Japanese"
597
			"ji", // "Yiddish (obsolete)"
598
			"jw", // "Javanese"
599
			"ka", // "Georgian"
600
			"kk", // "Kazakh"
601
			"kl", // "Greenlandic"
602
			"km", // "Cambodian"
603
			"kn", // "Kannada"
604
			"ko", // "Korean"
605
			"ks", // "Kashmiri"
606
			"ku", // "Kurdish"
607
			"ky", // "Kirghiz"
608
			"la", // "Latin"
609
			"ln", // "Lingala"
610
			"lo", // "Laothian"
611
			"lt", // "Lithuanian"
612
			"lv", // "Latvian/Lettish"
613
			"mg", // "Malagasy"
614
			"mi", // "Maori"
615
			"mk", // "Macedonian"
616
			"ml", // "Malayalam"
617
			"mn", // "Mongolian"
618
			"mo", // "Moldavian"
619
			"mr", // "Marathi"
620
			"ms", // "Malay"
621
			"mt", // "Maltese"
622
			"my", // "Burmese"
623
			"na", // "Nauru"
624
			"ne", // "Nepali"
625
			"nl", // "Dutch"
626
			"no", // "Norwegian"
627
			"oc", // "Occitan"
628
			"om", // "(Afan) Oromo"
629
			"or", // "Oriya"
630
			"pa", // "Punjabi"
631
			"pl", // "Polish"
632
			"ps", // "Pashto / Pushto"
633
			"pt", // "Portuguese"
634
			"pt_br", // "Portuguese (Brazil)"
635
			"qu", // "Quechua"
636
			"rm", // "Rhaeto-Romance"
637
			"rn", // "Kirundi"
638
			"ro", // "Romanian"
639
			"ro_ro", // "Romanian (Romania)"
640
			"ru", // "Russian"
641
			"rw", // "Kinyarwanda"
642
			"sa", // "Sanskrit"
643
			"sd", // "Sindhi"
644
			"sg", // "Sangro"
645
			"sh", // "Serbo-Croatian"
646
			"si", // "Singhalese"
647
			"sk", // "Slovak"
648
			"sl", // "Slovenian"
649
			"sm", // "Samoan"
650
			"sn", // "Shona"
651
			"so", // "Somali"
652
			"sq", // "Albanian"
653
			"sr", // "Serbian"
654
			"sr_latin", // "Serbian (Latin)"
655
			"ss", // "Siswati"
656
			"st", // "Sesotho"
657
			"su", // "Sundanese"
658
			"sv", // "Swedish"
659
			"sw", // "Swahili"
660
			"ta", // "Tamil"
661
			"te", // "Tegulu"
662
			"tg", // "Tajik"
663
			"th", // "Thai"
664
			"ti", // "Tigrinya"
665
			"tk", // "Turkmen"
666
			"tl", // "Tagalog"
667
			"tn", // "Setswana"
668
			"to", // "Tonga"
669
			"tr", // "Turkish"
670
			"ts", // "Tsonga"
671
			"tt", // "Tatar"
672
			"tw", // "Twi"
673
			"ug", // "Uigur"
674
			"uk", // "Ukrainian"
675
			"ur", // "Urdu"
676
			"uz", // "Uzbek"
677
			"vi", // "Vietnamese"
678
			"vo", // "Volapuk"
679
			"wo", // "Wolof"
680
			"xh", // "Xhosa"
681
			"yi", // "Yiddish"
682
			"yo", // "Yoruba"
683
			"za", // "Zuang"
684
			"zh", // "Chinese"
685
			"zh_hans", // "Chinese Simplified"
686
			"zu", // "Zulu"
687
		];
688
	}
689
690
	/**
691
	 * Normalize a language code (e.g. from Transifex)
692
	 *
693
	 * @param string $code Language code
694
	 *
695
	 * @return string
696
	 */
697
	public static function normalizeLanguageCode($code) {
698
		$code = strtolower($code);
699
		$code = preg_replace('~[^a-z0-9]~', '_', $code);
700
		return $code;
701
	}
702
}
703