Issues (2010)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

wp-includes/l10n.php (6 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
/**
3
 * Core Translation API
4
 *
5
 * @package WordPress
6
 * @subpackage i18n
7
 * @since 1.2.0
8
 */
9
10
/**
11
 * Retrieves the current locale.
12
 *
13
 * If the locale is set, then it will filter the locale in the {@see 'locale'}
14
 * filter hook and return the value.
15
 *
16
 * If the locale is not set already, then the WPLANG constant is used if it is
17
 * defined. Then it is filtered through the {@see 'locale'} filter hook and
18
 * the value for the locale global set and the locale is returned.
19
 *
20
 * The process to get the locale should only be done once, but the locale will
21
 * always be filtered using the {@see 'locale'} hook.
22
 *
23
 * @since 1.5.0
24
 *
25
 * @global string $locale
26
 * @global string $wp_local_package
27
 *
28
 * @return string The locale of the blog or from the {@see 'locale'} hook.
29
 */
30
function get_locale() {
31
	global $locale, $wp_local_package;
32
33
	if ( isset( $locale ) ) {
34
		/**
35
		 * Filters WordPress install's locale ID.
36
		 *
37
		 * @since 1.5.0
38
		 *
39
		 * @param string $locale The locale ID.
40
		 */
41
		return apply_filters( 'locale', $locale );
42
	}
43
44
	if ( isset( $wp_local_package ) ) {
45
		$locale = $wp_local_package;
46
	}
47
48
	// WPLANG was defined in wp-config.
49
	if ( defined( 'WPLANG' ) ) {
50
		$locale = WPLANG;
51
	}
52
53
	// If multisite, check options.
54
	if ( is_multisite() ) {
55
		// Don't check blog option when installing.
56
		if ( wp_installing() || ( false === $ms_locale = get_option( 'WPLANG' ) ) ) {
57
			$ms_locale = get_site_option( 'WPLANG' );
58
		}
59
60
		if ( $ms_locale !== false ) {
61
			$locale = $ms_locale;
62
		}
63
	} else {
64
		$db_locale = get_option( 'WPLANG' );
65
		if ( $db_locale !== false ) {
66
			$locale = $db_locale;
67
		}
68
	}
69
70
	if ( empty( $locale ) ) {
71
		$locale = 'en_US';
72
	}
73
74
	/** This filter is documented in wp-includes/l10n.php */
75
	return apply_filters( 'locale', $locale );
76
}
77
78
/**
79
 * Retrieve the translation of $text.
80
 *
81
 * If there is no translation, or the text domain isn't loaded, the original text is returned.
82
 *
83
 * *Note:* Don't use translate() directly, use __() or related functions.
84
 *
85
 * @since 2.2.0
86
 *
87
 * @param string $text   Text to translate.
88
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
89
 *                       Default 'default'.
90
 * @return string Translated text
91
 */
92
function translate( $text, $domain = 'default' ) {
93
	$translations = get_translations_for_domain( $domain );
94
	$translations = $translations->translate( $text );
95
96
	/**
97
	 * Filters text with its translation.
98
	 *
99
	 * @since 2.0.11
100
	 *
101
	 * @param string $translations Translated text.
102
	 * @param string $text         Text to translate.
103
	 * @param string $domain       Text domain. Unique identifier for retrieving translated strings.
104
	 */
105
	return apply_filters( 'gettext', $translations, $text, $domain );
106
}
107
108
/**
109
 * Remove last item on a pipe-delimited string.
110
 *
111
 * Meant for removing the last item in a string, such as 'Role name|User role'. The original
112
 * string will be returned if no pipe '|' characters are found in the string.
113
 *
114
 * @since 2.8.0
115
 *
116
 * @param string $string A pipe-delimited string.
117
 * @return string Either $string or everything before the last pipe.
118
 */
119
function before_last_bar( $string ) {
120
	$last_bar = strrpos( $string, '|' );
121
	if ( false === $last_bar ) {
122
		return $string;
123
	} else {
124
		return substr( $string, 0, $last_bar );
125
	}
126
}
127
128
/**
129
 * Retrieve the translation of $text in the context defined in $context.
130
 *
131
 * If there is no translation, or the text domain isn't loaded the original
132
 * text is returned.
133
 *
134
 * *Note:* Don't use translate_with_gettext_context() directly, use _x() or related functions.
135
 *
136
 * @since 2.8.0
137
 *
138
 * @param string $text    Text to translate.
139
 * @param string $context Context information for the translators.
140
 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
141
 *                        Default 'default'.
142
 * @return string Translated text on success, original text on failure.
143
 */
144
function translate_with_gettext_context( $text, $context, $domain = 'default' ) {
145
	$translations = get_translations_for_domain( $domain );
146
	$translations = $translations->translate( $text, $context );
147
	/**
148
	 * Filters text with its translation based on context information.
149
	 *
150
	 * @since 2.8.0
151
	 *
152
	 * @param string $translations Translated text.
153
	 * @param string $text         Text to translate.
154
	 * @param string $context      Context information for the translators.
155
	 * @param string $domain       Text domain. Unique identifier for retrieving translated strings.
156
	 */
157
	return apply_filters( 'gettext_with_context', $translations, $text, $context, $domain );
158
}
159
160
/**
161
 * Retrieve the translation of $text.
162
 *
163
 * If there is no translation, or the text domain isn't loaded, the original text is returned.
164
 *
165
 * @since 2.1.0
166
 *
167
 * @param string $text   Text to translate.
168
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
169
 *                       Default 'default'.
170
 * @return string Translated text.
171
 */
172
function __( $text, $domain = 'default' ) {
173
	return translate( $text, $domain );
174
}
175
176
/**
177
 * Retrieve the translation of $text and escapes it for safe use in an attribute.
178
 *
179
 * If there is no translation, or the text domain isn't loaded, the original text is returned.
180
 *
181
 * @since 2.8.0
182
 *
183
 * @param string $text   Text to translate.
184
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
185
 *                       Default 'default'.
186
 * @return string Translated text on success, original text on failure.
187
 */
188
function esc_attr__( $text, $domain = 'default' ) {
189
	return esc_attr( translate( $text, $domain ) );
190
}
191
192
/**
193
 * Retrieve the translation of $text and escapes it for safe use in HTML output.
194
 *
195
 * If there is no translation, or the text domain isn't loaded, the original text is returned.
196
 *
197
 * @since 2.8.0
198
 *
199
 * @param string $text   Text to translate.
200
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
201
 *                       Default 'default'.
202
 * @return string Translated text
203
 */
204
function esc_html__( $text, $domain = 'default' ) {
205
	return esc_html( translate( $text, $domain ) );
206
}
207
208
/**
209
 * Display translated text.
210
 *
211
 * @since 1.2.0
212
 *
213
 * @param string $text   Text to translate.
214
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
215
 *                       Default 'default'.
216
 */
217
function _e( $text, $domain = 'default' ) {
218
	echo translate( $text, $domain );
219
}
220
221
/**
222
 * Display translated text that has been escaped for safe use in an attribute.
223
 *
224
 * @since 2.8.0
225
 *
226
 * @param string $text   Text to translate.
227
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
228
 *                       Default 'default'.
229
 */
230
function esc_attr_e( $text, $domain = 'default' ) {
231
	echo esc_attr( translate( $text, $domain ) );
232
}
233
234
/**
235
 * Display translated text that has been escaped for safe use in HTML output.
236
 *
237
 * @since 2.8.0
238
 *
239
 * @param string $text   Text to translate.
240
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
241
 *                       Default 'default'.
242
 */
243
function esc_html_e( $text, $domain = 'default' ) {
244
	echo esc_html( translate( $text, $domain ) );
245
}
246
247
/**
248
 * Retrieve translated string with gettext context.
249
 *
250
 * Quite a few times, there will be collisions with similar translatable text
251
 * found in more than two places, but with different translated context.
252
 *
253
 * By including the context in the pot file, translators can translate the two
254
 * strings differently.
255
 *
256
 * @since 2.8.0
257
 *
258
 * @param string $text    Text to translate.
259
 * @param string $context Context information for the translators.
260
 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
261
 *                        Default 'default'.
262
 * @return string Translated context string without pipe.
263
 */
264
function _x( $text, $context, $domain = 'default' ) {
265
	return translate_with_gettext_context( $text, $context, $domain );
266
}
267
268
/**
269
 * Display translated string with gettext context.
270
 *
271
 * @since 3.0.0
272
 *
273
 * @param string $text    Text to translate.
274
 * @param string $context Context information for the translators.
275
 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
276
 *                        Default 'default'.
277
 * @return string Translated context string without pipe.
278
 */
279
function _ex( $text, $context, $domain = 'default' ) {
280
	echo _x( $text, $context, $domain );
281
}
282
283
/**
284
 * Translate string with gettext context, and escapes it for safe use in an attribute.
285
 *
286
 * @since 2.8.0
287
 *
288
 * @param string $text    Text to translate.
289
 * @param string $context Context information for the translators.
290
 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
291
 *                        Default 'default'.
292
 * @return string Translated text
293
 */
294
function esc_attr_x( $text, $context, $domain = 'default' ) {
295
	return esc_attr( translate_with_gettext_context( $text, $context, $domain ) );
296
}
297
298
/**
299
 * Translate string with gettext context, and escapes it for safe use in HTML output.
300
 *
301
 * @since 2.9.0
302
 *
303
 * @param string $text    Text to translate.
304
 * @param string $context Context information for the translators.
305
 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
306
 *                        Default 'default'.
307
 * @return string Translated text.
308
 */
309
function esc_html_x( $text, $context, $domain = 'default' ) {
310
	return esc_html( translate_with_gettext_context( $text, $context, $domain ) );
311
}
312
313
/**
314
 * Translates and retrieves the singular or plural form based on the supplied number.
315
 *
316
 * Used when you want to use the appropriate form of a string based on whether a
317
 * number is singular or plural.
318
 *
319
 * Example:
320
 *
321
 *     $people = sprintf( _n( '%s person', '%s people', $count, 'text-domain' ), number_format_i18n( $count ) );
322
 *
323
 * @since 2.8.0
324
 *
325
 * @param string $single The text to be used if the number is singular.
326
 * @param string $plural The text to be used if the number is plural.
327
 * @param int    $number The number to compare against to use either the singular or plural form.
328
 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
329
 *                       Default 'default'.
330
 * @return string The translated singular or plural form.
331
 */
332 View Code Duplication
function _n( $single, $plural, $number, $domain = 'default' ) {
0 ignored issues
show
This function seems to be duplicated in your project.

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.

Loading history...
333
	$translations = get_translations_for_domain( $domain );
334
	$translation = $translations->translate_plural( $single, $plural, $number );
335
336
	/**
337
	 * Filters the singular or plural form of a string.
338
	 *
339
	 * @since 2.2.0
340
	 *
341
	 * @param string $translation Translated text.
342
	 * @param string $single      The text to be used if the number is singular.
343
	 * @param string $plural      The text to be used if the number is plural.
344
	 * @param string $number      The number to compare against to use either the singular or plural form.
345
	 * @param string $domain      Text domain. Unique identifier for retrieving translated strings.
346
	 */
347
	return apply_filters( 'ngettext', $translation, $single, $plural, $number, $domain );
348
}
349
350
/**
351
 * Translates and retrieves the singular or plural form based on the supplied number, with gettext context.
352
 *
353
 * This is a hybrid of _n() and _x(). It supports context and plurals.
354
 *
355
 * Used when you want to use the appropriate form of a string with context based on whether a
356
 * number is singular or plural.
357
 *
358
 * Example:
359
 *
360
 *     $people = sprintf( _n( '%s person', '%s people', $count, 'context', 'text-domain' ), number_format_i18n( $count ) );
361
 *
362
 * @since 2.8.0
363
 *
364
 * @param string $single  The text to be used if the number is singular.
365
 * @param string $plural  The text to be used if the number is plural.
366
 * @param int    $number  The number to compare against to use either the singular or plural form.
367
 * @param string $context Context information for the translators.
368
 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
369
 *                        Default 'default'.
370
 * @return string The translated singular or plural form.
371
 */
372 View Code Duplication
function _nx($single, $plural, $number, $context, $domain = 'default') {
0 ignored issues
show
This function seems to be duplicated in your project.

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.

Loading history...
373
	$translations = get_translations_for_domain( $domain );
374
	$translation = $translations->translate_plural( $single, $plural, $number, $context );
375
376
	/**
377
	 * Filters the singular or plural form of a string with gettext context.
378
	 *
379
	 * @since 2.8.0
380
	 *
381
	 * @param string $translation Translated text.
382
	 * @param string $single      The text to be used if the number is singular.
383
	 * @param string $plural      The text to be used if the number is plural.
384
	 * @param string $number      The number to compare against to use either the singular or plural form.
385
	 * @param string $context     Context information for the translators.
386
	 * @param string $domain      Text domain. Unique identifier for retrieving translated strings.
387
	 */
388
	return apply_filters( 'ngettext_with_context', $translation, $single, $plural, $number, $context, $domain );
389
}
390
391
/**
392
 * Registers plural strings in POT file, but does not translate them.
393
 *
394
 * Used when you want to keep structures with translatable plural
395
 * strings and use them later when the number is known.
396
 *
397
 * Example:
398
 *
399
 *     $messages = array(
400
 *      	'post' => _n_noop( '%s post', '%s posts', 'text-domain' ),
401
 *      	'page' => _n_noop( '%s pages', '%s pages', 'text-domain' ),
402
 *     );
403
 *     ...
404
 *     $message = $messages[ $type ];
405
 *     $usable_text = sprintf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
406
 *
407
 * @since 2.5.0
408
 *
409
 * @param string $singular Singular form to be localized.
410
 * @param string $plural   Plural form to be localized.
411
 * @param string $domain   Optional. Text domain. Unique identifier for retrieving translated strings.
412
 *                         Default null.
413
 * @return array {
414
 *     Array of translation information for the strings.
415
 *
416
 *     @type string $0        Singular form to be localized. No longer used.
417
 *     @type string $1        Plural form to be localized. No longer used.
418
 *     @type string $singular Singular form to be localized.
419
 *     @type string $plural   Plural form to be localized.
420
 *     @type null   $context  Context information for the translators.
421
 *     @type string $domain   Text domain.
422
 * }
423
 */
424
function _n_noop( $singular, $plural, $domain = null ) {
425
	return array( 0 => $singular, 1 => $plural, 'singular' => $singular, 'plural' => $plural, 'context' => null, 'domain' => $domain );
426
}
427
428
/**
429
 * Registers plural strings with gettext context in POT file, but does not translate them.
430
 *
431
 * Used when you want to keep structures with translatable plural
432
 * strings and use them later when the number is known.
433
 *
434
 * Example:
435
 *
436
 *     $messages = array(
437
 *      	'post' => _n_noop( '%s post', '%s posts', 'context', 'text-domain' ),
438
 *      	'page' => _n_noop( '%s pages', '%s pages', 'context', 'text-domain' ),
439
 *     );
440
 *     ...
441
 *     $message = $messages[ $type ];
442
 *     $usable_text = sprintf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
443
 *
444
 * @since 2.8.0
445
 *
446
 * @param string $singular Singular form to be localized.
447
 * @param string $plural   Plural form to be localized.
448
 * @param string $context  Context information for the translators.
449
 * @param string $domain   Optional. Text domain. Unique identifier for retrieving translated strings.
450
 *                         Default null.
451
 * @return array {
452
 *     Array of translation information for the strings.
453
 *
454
 *     @type string $0        Singular form to be localized. No longer used.
455
 *     @type string $1        Plural form to be localized. No longer used.
456
 *     @type string $2        Context information for the translators. No longer used.
457
 *     @type string $singular Singular form to be localized.
458
 *     @type string $plural   Plural form to be localized.
459
 *     @type string $context  Context information for the translators.
460
 *     @type string $domain   Text domain.
461
 * }
462
 */
463
function _nx_noop( $singular, $plural, $context, $domain = null ) {
464
	return array( 0 => $singular, 1 => $plural, 2 => $context, 'singular' => $singular, 'plural' => $plural, 'context' => $context, 'domain' => $domain );
465
}
466
467
/**
468
 * Translates and retrieves the singular or plural form of a string that's been registered
469
 * with _n_noop() or _nx_noop().
470
 *
471
 * Used when you want to use a translatable plural string once the number is known.
472
 *
473
 * Example:
474
 *
475
 *     $messages = array(
476
 *      	'post' => _n_noop( '%s post', '%s posts', 'text-domain' ),
477
 *      	'page' => _n_noop( '%s pages', '%s pages', 'text-domain' ),
478
 *     );
479
 *     ...
480
 *     $message = $messages[ $type ];
481
 *     $usable_text = sprintf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
482
 *
483
 * @since 3.1.0
484
 *
485
 * @param array  $nooped_plural Array with singular, plural, and context keys, usually the result of _n_noop() or _nx_noop().
486
 * @param int    $count         Number of objects.
487
 * @param string $domain        Optional. Text domain. Unique identifier for retrieving translated strings. If $nooped_plural contains
488
 *                              a text domain passed to _n_noop() or _nx_noop(), it will override this value. Default 'default'.
489
 * @return string Either $single or $plural translated text.
490
 */
491
function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {
492
	if ( $nooped_plural['domain'] )
493
		$domain = $nooped_plural['domain'];
494
495
	if ( $nooped_plural['context'] )
496
		return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );
497
	else
498
		return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );
499
}
500
501
/**
502
 * Load a .mo file into the text domain $domain.
503
 *
504
 * If the text domain already exists, the translations will be merged. If both
505
 * sets have the same string, the translation from the original value will be taken.
506
 *
507
 * On success, the .mo file will be placed in the $l10n global by $domain
508
 * and will be a MO object.
509
 *
510
 * @since 1.5.0
511
 *
512
 * @global array $l10n          An array of all currently loaded text domains.
513
 * @global array $l10n_unloaded An array of all text domains that have been unloaded again.
514
 *
515
 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
516
 * @param string $mofile Path to the .mo file.
517
 * @return bool True on success, false on failure.
518
 */
519
function load_textdomain( $domain, $mofile ) {
520
	global $l10n, $l10n_unloaded;
521
522
	$l10n_unloaded = (array) $l10n_unloaded;
523
524
	/**
525
	 * Filters whether to override the .mo file loading.
526
	 *
527
	 * @since 2.9.0
528
	 *
529
	 * @param bool   $override Whether to override the .mo file loading. Default false.
530
	 * @param string $domain   Text domain. Unique identifier for retrieving translated strings.
531
	 * @param string $mofile   Path to the MO file.
532
	 */
533
	$plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile );
534
535
	if ( true == $plugin_override ) {
536
		unset( $l10n_unloaded[ $domain ] );
537
538
		return true;
539
	}
540
541
	/**
542
	 * Fires before the MO translation file is loaded.
543
	 *
544
	 * @since 2.9.0
545
	 *
546
	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
547
	 * @param string $mofile Path to the .mo file.
548
	 */
549
	do_action( 'load_textdomain', $domain, $mofile );
550
551
	/**
552
	 * Filters MO file path for loading translations for a specific text domain.
553
	 *
554
	 * @since 2.9.0
555
	 *
556
	 * @param string $mofile Path to the MO file.
557
	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
558
	 */
559
	$mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
560
561
	if ( !is_readable( $mofile ) ) return false;
562
563
	$mo = new MO();
564
	if ( !$mo->import_from_file( $mofile ) ) return false;
565
566
	if ( isset( $l10n[$domain] ) )
567
		$mo->merge_with( $l10n[$domain] );
568
569
	unset( $l10n_unloaded[ $domain ] );
570
571
	$l10n[$domain] = &$mo;
572
573
	return true;
574
}
575
576
/**
577
 * Unload translations for a text domain.
578
 *
579
 * @since 3.0.0
580
 *
581
 * @global array $l10n          An array of all currently loaded text domains.
582
 * @global array $l10n_unloaded An array of all text domains that have been unloaded again.
583
 *
584
 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
585
 * @return bool Whether textdomain was unloaded.
586
 */
587
function unload_textdomain( $domain ) {
588
	global $l10n, $l10n_unloaded;
589
590
	$l10n_unloaded = (array) $l10n_unloaded;
591
592
	/**
593
	 * Filters whether to override the text domain unloading.
594
	 *
595
	 * @since 3.0.0
596
	 *
597
	 * @param bool   $override Whether to override the text domain unloading. Default false.
598
	 * @param string $domain   Text domain. Unique identifier for retrieving translated strings.
599
	 */
600
	$plugin_override = apply_filters( 'override_unload_textdomain', false, $domain );
601
602
	if ( $plugin_override ) {
603
		$l10n_unloaded[ $domain ] = true;
604
605
		return true;
606
	}
607
608
	/**
609
	 * Fires before the text domain is unloaded.
610
	 *
611
	 * @since 3.0.0
612
	 *
613
	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
614
	 */
615
	do_action( 'unload_textdomain', $domain );
616
617
	if ( isset( $l10n[$domain] ) ) {
618
		unset( $l10n[$domain] );
619
620
		$l10n_unloaded[ $domain ] = true;
621
622
		return true;
623
	}
624
625
	return false;
626
}
627
628
/**
629
 * Load default translated strings based on locale.
630
 *
631
 * Loads the .mo file in WP_LANG_DIR constant path from WordPress root.
632
 * The translated (.mo) file is named based on the locale.
633
 *
634
 * @see load_textdomain()
635
 *
636
 * @since 1.5.0
637
 *
638
 * @param string $locale Optional. Locale to load. Default is the value of get_locale().
639
 * @return bool Whether the textdomain was loaded.
640
 */
641
function load_default_textdomain( $locale = null ) {
642
	if ( null === $locale ) {
643
		$locale = get_locale();
644
	}
645
646
	// Unload previously loaded strings so we can switch translations.
647
	unload_textdomain( 'default' );
648
649
	$return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" );
650
651
	if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists(  WP_LANG_DIR . "/admin-$locale.mo" ) ) {
652
		load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" );
653
		return $return;
654
	}
655
656
	if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) {
657
		load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
658
	}
659
660
	if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) )
661
		load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" );
662
663
	return $return;
664
}
665
666
/**
667
 * Loads a plugin's translated strings.
668
 *
669
 * If the path is not given then it will be the root of the plugin directory.
670
 *
671
 * The .mo file should be named based on the text domain with a dash, and then the locale exactly.
672
 *
673
 * @since 1.5.0
674
 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
675
 *
676
 * @param string $domain          Unique identifier for retrieving translated strings
677
 * @param string $deprecated      Optional. Use the $plugin_rel_path parameter instead. Default false.
678
 * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
679
 *                                Default false.
680
 * @return bool True when textdomain is successfully loaded, false otherwise.
681
 */
682
function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
683
	/**
684
	 * Filters a plugin's locale.
685
	 *
686
	 * @since 3.0.0
687
	 *
688
	 * @param string $locale The plugin's current locale.
689
	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
690
	 */
691
	$locale = apply_filters( 'plugin_locale', get_locale(), $domain );
692
693
	$mofile = $domain . '-' . $locale . '.mo';
694
695
	// Try to load from the languages directory first.
696
	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) {
697
		return true;
698
	}
699
700
	if ( false !== $plugin_rel_path ) {
701
		$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
702
	} elseif ( false !== $deprecated ) {
703
		_deprecated_argument( __FUNCTION__, '2.7.0' );
704
		$path = ABSPATH . trim( $deprecated, '/' );
705
	} else {
706
		$path = WP_PLUGIN_DIR;
707
	}
708
709
	return load_textdomain( $domain, $path . '/' . $mofile );
710
}
711
712
/**
713
 * Load the translated strings for a plugin residing in the mu-plugins directory.
714
 *
715
 * @since 3.0.0
716
 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
717
 *
718
 * @param string $domain             Text domain. Unique identifier for retrieving translated strings.
719
 * @param string $mu_plugin_rel_path Optional. Relative to `WPMU_PLUGIN_DIR` directory in which the .mo
720
 *                                   file resides. Default empty string.
721
 * @return bool True when textdomain is successfully loaded, false otherwise.
722
 */
723 View Code Duplication
function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
0 ignored issues
show
This function seems to be duplicated in your project.

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.

Loading history...
724
	/** This filter is documented in wp-includes/l10n.php */
725
	$locale = apply_filters( 'plugin_locale', get_locale(), $domain );
726
727
	$mofile = $domain . '-' . $locale . '.mo';
728
729
	// Try to load from the languages directory first.
730
	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) {
731
		return true;
732
	}
733
734
	$path = trailingslashit( WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' ) );
735
736
	return load_textdomain( $domain, $path . '/' . $mofile );
737
}
738
739
/**
740
 * Load the theme's translated strings.
741
 *
742
 * If the current locale exists as a .mo file in the theme's root directory, it
743
 * will be included in the translated strings by the $domain.
744
 *
745
 * The .mo files must be named based on the locale exactly.
746
 *
747
 * @since 1.5.0
748
 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
749
 *
750
 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
751
 * @param string $path   Optional. Path to the directory containing the .mo file.
752
 *                       Default false.
753
 * @return bool True when textdomain is successfully loaded, false otherwise.
754
 */
755 View Code Duplication
function load_theme_textdomain( $domain, $path = false ) {
0 ignored issues
show
This function seems to be duplicated in your project.

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.

Loading history...
756
	/**
757
	 * Filters a theme's locale.
758
	 *
759
	 * @since 3.0.0
760
	 *
761
	 * @param string $locale The theme's current locale.
762
	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
763
	 */
764
	$locale = apply_filters( 'theme_locale', get_locale(), $domain );
765
766
	$mofile = $domain . '-' . $locale . '.mo';
767
768
	// Try to load from the languages directory first.
769
	if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile ) ) {
770
		return true;
771
	}
772
773
	if ( ! $path ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $path of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false 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...
774
		$path = get_template_directory();
775
	}
776
777
	return load_textdomain( $domain, $path . '/' . $locale . '.mo' );
778
}
779
780
/**
781
 * Load the child themes translated strings.
782
 *
783
 * If the current locale exists as a .mo file in the child themes
784
 * root directory, it will be included in the translated strings by the $domain.
785
 *
786
 * The .mo files must be named based on the locale exactly.
787
 *
788
 * @since 2.9.0
789
 *
790
 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
791
 * @param string $path   Optional. Path to the directory containing the .mo file.
792
 *                       Default false.
793
 * @return bool True when the theme textdomain is successfully loaded, false otherwise.
794
 */
795
function load_child_theme_textdomain( $domain, $path = false ) {
796
	if ( ! $path )
0 ignored issues
show
Bug Best Practice introduced by
The expression $path of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false 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...
797
		$path = get_stylesheet_directory();
798
	return load_theme_textdomain( $domain, $path );
799
}
800
801
/**
802
 * Loads plugin and theme textdomains just-in-time.
803
 *
804
 * When a textdomain is encountered for the first time, we try to load
805
 * the translation file from `wp-content/languages`, removing the need
806
 * to call load_plugin_texdomain() or load_theme_texdomain().
807
 *
808
 * Holds a cached list of available .mo files to improve performance.
809
 *
810
 * @since 4.6.0
811
 * @access private
812
 *
813
 * @see get_translations_for_domain()
814
 * @global array $l10n_unloaded An array of all text domains that have been unloaded again.
815
 *
816
 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
817
 * @return bool True when the textdomain is successfully loaded, false otherwise.
818
 */
819
function _load_textdomain_just_in_time( $domain ) {
820
	global $l10n_unloaded;
821
822
	$l10n_unloaded = (array) $l10n_unloaded;
823
824
	static $cached_mofiles = null;
825
826
	// Short-circuit if domain is 'default' which is reserved for core.
827
	if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) {
828
		return false;
829
	}
830
831
	if ( null === $cached_mofiles ) {
832
		$cached_mofiles = array();
833
834
		$locations = array(
835
			WP_LANG_DIR . '/plugins',
836
			WP_LANG_DIR . '/themes',
837
		);
838
839
		foreach ( $locations as $location ) {
840
			foreach ( get_available_languages( $location ) as $file ) {
841
				$cached_mofiles[] = "{$location}/{$file}.mo";
842
			}
843
		}
844
	}
845
846
	$locale = get_locale();
847
	$mofile = "{$domain}-{$locale}.mo";
848
849 View Code Duplication
	if ( in_array( WP_LANG_DIR . '/plugins/' . $mofile, $cached_mofiles ) ) {
850
		return load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile );
851
	}
852
853 View Code Duplication
	if ( in_array( WP_LANG_DIR . '/themes/' . $mofile, $cached_mofiles ) ) {
854
		return load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile );
855
	}
856
857
	return false;
858
}
859
860
/**
861
 * Return the Translations instance for a text domain.
862
 *
863
 * If there isn't one, returns empty Translations instance.
864
 *
865
 * @since 2.8.0
866
 *
867
 * @global array $l10n
868
 *
869
 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
870
 * @return Translations|NOOP_Translations A Translations instance.
871
 */
872
function get_translations_for_domain( $domain ) {
873
	global $l10n;
874
	if ( isset( $l10n[ $domain ] ) || ( _load_textdomain_just_in_time( $domain ) && isset( $l10n[ $domain ] ) ) ) {
875
		return $l10n[ $domain ];
876
	}
877
878
	static $noop_translations = null;
879
	if ( null === $noop_translations ) {
880
		$noop_translations = new NOOP_Translations;
881
	}
882
883
	return $noop_translations;
884
}
885
886
/**
887
 * Whether there are translations for the text domain.
888
 *
889
 * @since 3.0.0
890
 *
891
 * @global array $l10n
892
 *
893
 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
894
 * @return bool Whether there are translations.
895
 */
896
function is_textdomain_loaded( $domain ) {
897
	global $l10n;
898
	return isset( $l10n[ $domain ] );
899
}
900
901
/**
902
 * Translates role name.
903
 *
904
 * Since the role names are in the database and not in the source there
905
 * are dummy gettext calls to get them into the POT file and this function
906
 * properly translates them back.
907
 *
908
 * The before_last_bar() call is needed, because older installs keep the roles
909
 * using the old context format: 'Role name|User role' and just skipping the
910
 * content after the last bar is easier than fixing them in the DB. New installs
911
 * won't suffer from that problem.
912
 *
913
 * @since 2.8.0
914
 *
915
 * @param string $name The role name.
916
 * @return string Translated role name on success, original name on failure.
917
 */
918
function translate_user_role( $name ) {
919
	return translate_with_gettext_context( before_last_bar($name), 'User role' );
920
}
921
922
/**
923
 * Get all available languages based on the presence of *.mo files in a given directory.
924
 *
925
 * The default directory is WP_LANG_DIR.
926
 *
927
 * @since 3.0.0
928
 *
929
 * @param string $dir A directory to search for language files.
930
 *                    Default WP_LANG_DIR.
931
 * @return array An array of language codes or an empty array if no languages are present. Language codes are formed by stripping the .mo extension from the language file names.
932
 */
933
function get_available_languages( $dir = null ) {
934
	$languages = array();
935
936
	$lang_files = glob( ( is_null( $dir) ? WP_LANG_DIR : $dir ) . '/*.mo' );
937
	if ( $lang_files ) {
938
		foreach ( $lang_files as $lang_file ) {
939
			$lang_file = basename( $lang_file, '.mo' );
940
			if ( 0 !== strpos( $lang_file, 'continents-cities' ) && 0 !== strpos( $lang_file, 'ms-' ) &&
941
				0 !== strpos( $lang_file, 'admin-' ) ) {
942
				$languages[] = $lang_file;
943
			}
944
		}
945
	}
946
947
	return $languages;
948
}
949
950
/**
951
 * Get installed translations.
952
 *
953
 * Looks in the wp-content/languages directory for translations of
954
 * plugins or themes.
955
 *
956
 * @since 3.7.0
957
 *
958
 * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
959
 * @return array Array of language data.
960
 */
961
function wp_get_installed_translations( $type ) {
962
	if ( $type !== 'themes' && $type !== 'plugins' && $type !== 'core' )
963
		return array();
964
965
	$dir = 'core' === $type ? '' : "/$type";
966
967
	if ( ! is_dir( WP_LANG_DIR ) )
968
		return array();
969
970
	if ( $dir && ! is_dir( WP_LANG_DIR . $dir ) )
971
		return array();
972
973
	$files = scandir( WP_LANG_DIR . $dir );
974
	if ( ! $files )
975
		return array();
976
977
	$language_data = array();
978
979
	foreach ( $files as $file ) {
980
		if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "$dir/$file" ) ) {
981
			continue;
982
		}
983
		if ( substr( $file, -3 ) !== '.po' ) {
984
			continue;
985
		}
986
		if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
987
			continue;
988
		}
989
		if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) )  {
990
			continue;
991
		}
992
993
		list( , $textdomain, $language ) = $match;
994
		if ( '' === $textdomain ) {
995
			$textdomain = 'default';
996
		}
997
		$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "$dir/$file" );
998
	}
999
	return $language_data;
1000
}
1001
1002
/**
1003
 * Extract headers from a PO file.
1004
 *
1005
 * @since 3.7.0
1006
 *
1007
 * @param string $po_file Path to PO file.
1008
 * @return array PO file headers.
1009
 */
1010
function wp_get_pomo_file_data( $po_file ) {
1011
	$headers = get_file_data( $po_file, array(
1012
		'POT-Creation-Date'  => '"POT-Creation-Date',
1013
		'PO-Revision-Date'   => '"PO-Revision-Date',
1014
		'Project-Id-Version' => '"Project-Id-Version',
1015
		'X-Generator'        => '"X-Generator',
1016
	) );
1017
	foreach ( $headers as $header => $value ) {
1018
		// Remove possible contextual '\n' and closing double quote.
1019
		$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
1020
	}
1021
	return $headers;
1022
}
1023
1024
/**
1025
 * Language selector.
1026
 *
1027
 * @since 4.0.0
1028
 * @since 4.3.0 Introduced the `echo` argument.
1029
 *
1030
 * @see get_available_languages()
1031
 * @see wp_get_available_translations()
1032
 *
1033
 * @param string|array $args {
1034
 *     Optional. Array or string of arguments for outputting the language selector.
1035
 *
1036
 *     @type string   $id                           ID attribute of the select element. Default empty.
1037
 *     @type string   $name                         Name attribute of the select element. Default empty.
1038
 *     @type array    $languages                    List of installed languages, contain only the locales.
1039
 *                                                  Default empty array.
1040
 *     @type array    $translations                 List of available translations. Default result of
1041
 *                                                  wp_get_available_translations().
1042
 *     @type string   $selected                     Language which should be selected. Default empty.
1043
 *     @type bool|int $echo                         Whether to echo the generated markup. Accepts 0, 1, or their
1044
 *                                                  boolean equivalents. Default 1.
1045
 *     @type bool     $show_available_translations  Whether to show available translations. Default true.
1046
 * }
1047
 * @return string HTML content
1048
 */
1049
function wp_dropdown_languages( $args = array() ) {
1050
1051
	$args = wp_parse_args( $args, array(
1052
		'id'           => '',
1053
		'name'         => '',
1054
		'languages'    => array(),
1055
		'translations' => array(),
1056
		'selected'     => '',
1057
		'echo'         => 1,
1058
		'show_available_translations' => true,
1059
	) );
1060
1061
	$translations = $args['translations'];
1062
	if ( empty( $translations ) ) {
1063
		require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
1064
		$translations = wp_get_available_translations();
1065
	}
1066
1067
	/*
1068
	 * $args['languages'] should only contain the locales. Find the locale in
1069
	 * $translations to get the native name. Fall back to locale.
1070
	 */
1071
	$languages = array();
1072
	foreach ( $args['languages'] as $locale ) {
1073
		if ( isset( $translations[ $locale ] ) ) {
1074
			$translation = $translations[ $locale ];
1075
			$languages[] = array(
1076
				'language'    => $translation['language'],
1077
				'native_name' => $translation['native_name'],
1078
				'lang'        => current( $translation['iso'] ),
1079
			);
1080
1081
			// Remove installed language from available translations.
1082
			unset( $translations[ $locale ] );
1083
		} else {
1084
			$languages[] = array(
1085
				'language'    => $locale,
1086
				'native_name' => $locale,
1087
				'lang'        => '',
1088
			);
1089
		}
1090
	}
1091
1092
	$translations_available = ( ! empty( $translations ) && $args['show_available_translations'] );
1093
1094
	$output = sprintf( '<select name="%s" id="%s">', esc_attr( $args['name'] ), esc_attr( $args['id'] ) );
1095
1096
	// Holds the HTML markup.
1097
	$structure = array();
1098
1099
	// List installed languages.
1100
	if ( $translations_available ) {
1101
		$structure[] = '<optgroup label="' . esc_attr_x( 'Installed', 'translations' ) . '">';
1102
	}
1103
	$structure[] = '<option value="" lang="en" data-installed="1">English (United States)</option>';
1104 View Code Duplication
	foreach ( $languages as $language ) {
1105
		$structure[] = sprintf(
1106
			'<option value="%s" lang="%s"%s data-installed="1">%s</option>',
1107
			esc_attr( $language['language'] ),
1108
			esc_attr( $language['lang'] ),
1109
			selected( $language['language'], $args['selected'], false ),
1110
			esc_html( $language['native_name'] )
1111
		);
1112
	}
1113
	if ( $translations_available ) {
1114
		$structure[] = '</optgroup>';
1115
	}
1116
1117
	// List available translations.
1118
	if ( $translations_available ) {
1119
		$structure[] = '<optgroup label="' . esc_attr_x( 'Available', 'translations' ) . '">';
1120 View Code Duplication
		foreach ( $translations as $translation ) {
1121
			$structure[] = sprintf(
1122
				'<option value="%s" lang="%s"%s>%s</option>',
1123
				esc_attr( $translation['language'] ),
1124
				esc_attr( current( $translation['iso'] ) ),
1125
				selected( $translation['language'], $args['selected'], false ),
1126
				esc_html( $translation['native_name'] )
1127
			);
1128
		}
1129
		$structure[] = '</optgroup>';
1130
	}
1131
1132
	$output .= join( "\n", $structure );
1133
1134
	$output .= '</select>';
1135
1136
	if ( $args['echo'] ) {
1137
		echo $output;
1138
	}
1139
1140
	return $output;
1141
}
1142