Diff: STRATO-apps/wordpress_03/app/wp-includes/l10n.php
Keine Baseline-Datei – Diff nur gegen leer.
1
-
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 The current locale.
26
+
* @global string $wp_local_package Locale code of the 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
+
/** This filter is documented in wp-includes/l10n.php */
35
+
return apply_filters( 'locale', $locale );
36
+
}
37
+
38
+
if ( isset( $wp_local_package ) ) {
39
+
$locale = $wp_local_package;
40
+
}
41
+
42
+
// WPLANG was defined in wp-config.
43
+
if ( defined( 'WPLANG' ) ) {
44
+
$locale = WPLANG;
45
+
}
46
+
47
+
// If multisite, check options.
48
+
if ( is_multisite() ) {
49
+
// Don't check blog option when installing.
50
+
if ( wp_installing() ) {
51
+
$ms_locale = get_site_option( 'WPLANG' );
52
+
} else {
53
+
$ms_locale = get_option( 'WPLANG' );
54
+
if ( false === $ms_locale ) {
55
+
$ms_locale = get_site_option( 'WPLANG' );
56
+
}
57
+
}
58
+
59
+
if ( false !== $ms_locale ) {
60
+
$locale = $ms_locale;
61
+
}
62
+
} else {
63
+
$db_locale = get_option( 'WPLANG' );
64
+
if ( false !== $db_locale ) {
65
+
$locale = $db_locale;
66
+
}
67
+
}
68
+
69
+
if ( empty( $locale ) ) {
70
+
$locale = 'en_US';
71
+
}
72
+
73
+
/**
74
+
* Filters the locale ID of the WordPress installation.
75
+
*
76
+
* @since 1.5.0
77
+
*
78
+
* @param string $locale The locale ID.
79
+
*/
80
+
return apply_filters( 'locale', $locale );
81
+
}
82
+
83
+
/**
84
+
* Retrieves the locale of a user.
85
+
*
86
+
* If the user has a locale set to a non-empty string then it will be
87
+
* returned. Otherwise it returns the locale of get_locale().
88
+
*
89
+
* @since 4.7.0
90
+
*
91
+
* @param int|WP_User $user User's ID or a WP_User object. Defaults to current user.
92
+
* @return string The locale of the user.
93
+
*/
94
+
function get_user_locale( $user = 0 ) {
95
+
$user_object = false;
96
+
97
+
if ( 0 === $user && function_exists( 'wp_get_current_user' ) ) {
98
+
$user_object = wp_get_current_user();
99
+
} elseif ( $user instanceof WP_User ) {
100
+
$user_object = $user;
101
+
} elseif ( $user && is_numeric( $user ) ) {
102
+
$user_object = get_user_by( 'id', $user );
103
+
}
104
+
105
+
if ( ! $user_object ) {
106
+
return get_locale();
107
+
}
108
+
109
+
$locale = $user_object->locale;
110
+
111
+
return $locale ? $locale : get_locale();
112
+
}
113
+
114
+
/**
115
+
* Determines the current locale desired for the request.
116
+
*
117
+
* @since 5.0.0
118
+
*
119
+
* @global string $pagenow The filename of the current screen.
120
+
* @global string $wp_local_package Locale code of the package.
121
+
*
122
+
* @return string The determined locale.
123
+
*/
124
+
function determine_locale() {
125
+
/**
126
+
* Filters the locale for the current request prior to the default determination process.
127
+
*
128
+
* Using this filter allows to override the default logic, effectively short-circuiting the function.
129
+
*
130
+
* @since 5.0.0
131
+
*
132
+
* @param string|null $locale The locale to return and short-circuit. Default null.
133
+
*/
134
+
$determined_locale = apply_filters( 'pre_determine_locale', null );
135
+
136
+
if ( $determined_locale && is_string( $determined_locale ) ) {
137
+
return $determined_locale;
138
+
}
139
+
140
+
if (
141
+
isset( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] &&
142
+
( ! empty( $_GET['wp_lang'] ) || ! empty( $_COOKIE['wp_lang'] ) )
143
+
) {
144
+
if ( ! empty( $_GET['wp_lang'] ) ) {
145
+
$determined_locale = sanitize_locale_name( $_GET['wp_lang'] );
146
+
} else {
147
+
$determined_locale = sanitize_locale_name( $_COOKIE['wp_lang'] );
148
+
}
149
+
} elseif (
150
+
is_admin() ||
151
+
( isset( $_GET['_locale'] ) && 'user' === $_GET['_locale'] && wp_is_json_request() )
152
+
) {
153
+
$determined_locale = get_user_locale();
154
+
} elseif (
155
+
( ! empty( $_REQUEST['language'] ) || isset( $GLOBALS['wp_local_package'] ) )
156
+
&& wp_installing()
157
+
) {
158
+
if ( ! empty( $_REQUEST['language'] ) ) {
159
+
$determined_locale = sanitize_locale_name( $_REQUEST['language'] );
160
+
} else {
161
+
$determined_locale = $GLOBALS['wp_local_package'];
162
+
}
163
+
}
164
+
165
+
if ( ! $determined_locale ) {
166
+
$determined_locale = get_locale();
167
+
}
168
+
169
+
/**
170
+
* Filters the locale for the current request.
171
+
*
172
+
* @since 5.0.0
173
+
*
174
+
* @param string $determined_locale The locale.
175
+
*/
176
+
return apply_filters( 'determine_locale', $determined_locale );
177
+
}
178
+
179
+
/**
180
+
* Retrieves the translation of $text.
181
+
*
182
+
* If there is no translation, or the text domain isn't loaded, the original text is returned.
183
+
*
184
+
* *Note:* Don't use translate() directly, use __() or related functions.
185
+
*
186
+
* @since 2.2.0
187
+
* @since 5.5.0 Introduced `gettext-{$domain}` filter.
188
+
*
189
+
* @param string $text Text to translate.
190
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
191
+
* Default 'default'.
192
+
* @return string Translated text.
193
+
*/
194
+
function translate( $text, $domain = 'default' ) {
195
+
$translations = get_translations_for_domain( $domain );
196
+
$translation = $translations->translate( $text );
197
+
198
+
/**
199
+
* Filters text with its translation.
200
+
*
201
+
* @since 2.0.11
202
+
*
203
+
* @param string $translation Translated text.
204
+
* @param string $text Text to translate.
205
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
206
+
*/
207
+
$translation = apply_filters( 'gettext', $translation, $text, $domain );
208
+
209
+
/**
210
+
* Filters text with its translation for a domain.
211
+
*
212
+
* The dynamic portion of the hook name, `$domain`, refers to the text domain.
213
+
*
214
+
* @since 5.5.0
215
+
*
216
+
* @param string $translation Translated text.
217
+
* @param string $text Text to translate.
218
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
219
+
*/
220
+
$translation = apply_filters( "gettext_{$domain}", $translation, $text, $domain );
221
+
222
+
return $translation;
223
+
}
224
+
225
+
/**
226
+
* Removes last item on a pipe-delimited string.
227
+
*
228
+
* Meant for removing the last item in a string, such as 'Role name|User role'. The original
229
+
* string will be returned if no pipe '|' characters are found in the string.
230
+
*
231
+
* @since 2.8.0
232
+
*
233
+
* @param string $text A pipe-delimited string.
234
+
* @return string Either $text or everything before the last pipe.
235
+
*/
236
+
function before_last_bar( $text ) {
237
+
$last_bar = strrpos( $text, '|' );
238
+
if ( false === $last_bar ) {
239
+
return $text;
240
+
} else {
241
+
return substr( $text, 0, $last_bar );
242
+
}
243
+
}
244
+
245
+
/**
246
+
* Retrieves the translation of $text in the context defined in $context.
247
+
*
248
+
* If there is no translation, or the text domain isn't loaded, the original text is returned.
249
+
*
250
+
* *Note:* Don't use translate_with_gettext_context() directly, use _x() or related functions.
251
+
*
252
+
* @since 2.8.0
253
+
* @since 5.5.0 Introduced `gettext_with_context-{$domain}` filter.
254
+
*
255
+
* @param string $text Text to translate.
256
+
* @param string $context Context information for the translators.
257
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
258
+
* Default 'default'.
259
+
* @return string Translated text on success, original text on failure.
260
+
*/
261
+
function translate_with_gettext_context( $text, $context, $domain = 'default' ) {
262
+
$translations = get_translations_for_domain( $domain );
263
+
$translation = $translations->translate( $text, $context );
264
+
265
+
/**
266
+
* Filters text with its translation based on context information.
267
+
*
268
+
* @since 2.8.0
269
+
*
270
+
* @param string $translation Translated text.
271
+
* @param string $text Text to translate.
272
+
* @param string $context Context information for the translators.
273
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
274
+
*/
275
+
$translation = apply_filters( 'gettext_with_context', $translation, $text, $context, $domain );
276
+
277
+
/**
278
+
* Filters text with its translation based on context information for a domain.
279
+
*
280
+
* The dynamic portion of the hook name, `$domain`, refers to the text domain.
281
+
*
282
+
* @since 5.5.0
283
+
*
284
+
* @param string $translation Translated text.
285
+
* @param string $text Text to translate.
286
+
* @param string $context Context information for the translators.
287
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
288
+
*/
289
+
$translation = apply_filters( "gettext_with_context_{$domain}", $translation, $text, $context, $domain );
290
+
291
+
return $translation;
292
+
}
293
+
294
+
/**
295
+
* Retrieves the translation of $text.
296
+
*
297
+
* If there is no translation, or the text domain isn't loaded, the original text is returned.
298
+
*
299
+
* @since 2.1.0
300
+
*
301
+
* @param string $text Text to translate.
302
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
303
+
* Default 'default'.
304
+
* @return string Translated text.
305
+
*/
306
+
function __( $text, $domain = 'default' ) {
307
+
return translate( $text, $domain );
308
+
}
309
+
310
+
/**
311
+
* Retrieves the translation of $text and escapes it for safe use in an attribute.
312
+
*
313
+
* If there is no translation, or the text domain isn't loaded, the original text is returned.
314
+
*
315
+
* @since 2.8.0
316
+
*
317
+
* @param string $text Text to translate.
318
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
319
+
* Default 'default'.
320
+
* @return string Translated text on success, original text on failure.
321
+
*/
322
+
function esc_attr__( $text, $domain = 'default' ) {
323
+
return esc_attr( translate( $text, $domain ) );
324
+
}
325
+
326
+
/**
327
+
* Retrieves the translation of $text and escapes it for safe use in HTML output.
328
+
*
329
+
* If there is no translation, or the text domain isn't loaded, the original text
330
+
* is escaped and returned.
331
+
*
332
+
* @since 2.8.0
333
+
*
334
+
* @param string $text Text to translate.
335
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
336
+
* Default 'default'.
337
+
* @return string Translated text.
338
+
*/
339
+
function esc_html__( $text, $domain = 'default' ) {
340
+
return esc_html( translate( $text, $domain ) );
341
+
}
342
+
343
+
/**
344
+
* Displays translated text.
345
+
*
346
+
* @since 1.2.0
347
+
*
348
+
* @param string $text Text to translate.
349
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
350
+
* Default 'default'.
351
+
*/
352
+
function _e( $text, $domain = 'default' ) {
353
+
echo translate( $text, $domain );
354
+
}
355
+
356
+
/**
357
+
* Displays translated text that has been escaped for safe use in an attribute.
358
+
*
359
+
* Encodes `< > & " '` (less than, greater than, ampersand, double quote, single quote).
360
+
* Will never double encode entities.
361
+
*
362
+
* If you need the value for use in PHP, use esc_attr__().
363
+
*
364
+
* @since 2.8.0
365
+
*
366
+
* @param string $text Text to translate.
367
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
368
+
* Default 'default'.
369
+
*/
370
+
function esc_attr_e( $text, $domain = 'default' ) {
371
+
echo esc_attr( translate( $text, $domain ) );
372
+
}
373
+
374
+
/**
375
+
* Displays translated text that has been escaped for safe use in HTML output.
376
+
*
377
+
* If there is no translation, or the text domain isn't loaded, the original text
378
+
* is escaped and displayed.
379
+
*
380
+
* If you need the value for use in PHP, use esc_html__().
381
+
*
382
+
* @since 2.8.0
383
+
*
384
+
* @param string $text Text to translate.
385
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
386
+
* Default 'default'.
387
+
*/
388
+
function esc_html_e( $text, $domain = 'default' ) {
389
+
echo esc_html( translate( $text, $domain ) );
390
+
}
391
+
392
+
/**
393
+
* Retrieves translated string with gettext context.
394
+
*
395
+
* Quite a few times, there will be collisions with similar translatable text
396
+
* found in more than two places, but with different translated context.
397
+
*
398
+
* By including the context in the pot file, translators can translate the two
399
+
* strings differently.
400
+
*
401
+
* @since 2.8.0
402
+
*
403
+
* @param string $text Text to translate.
404
+
* @param string $context Context information for the translators.
405
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
406
+
* Default 'default'.
407
+
* @return string Translated context string without pipe.
408
+
*/
409
+
function _x( $text, $context, $domain = 'default' ) {
410
+
return translate_with_gettext_context( $text, $context, $domain );
411
+
}
412
+
413
+
/**
414
+
* Displays translated string with gettext context.
415
+
*
416
+
* @since 3.0.0
417
+
*
418
+
* @param string $text Text to translate.
419
+
* @param string $context Context information for the translators.
420
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
421
+
* Default 'default'.
422
+
*/
423
+
function _ex( $text, $context, $domain = 'default' ) {
424
+
echo _x( $text, $context, $domain );
425
+
}
426
+
427
+
/**
428
+
* Translates string with gettext context, and escapes it for safe use in an attribute.
429
+
*
430
+
* If there is no translation, or the text domain isn't loaded, the original text
431
+
* is escaped and returned.
432
+
*
433
+
* @since 2.8.0
434
+
*
435
+
* @param string $text Text to translate.
436
+
* @param string $context Context information for the translators.
437
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
438
+
* Default 'default'.
439
+
* @return string Translated text.
440
+
*/
441
+
function esc_attr_x( $text, $context, $domain = 'default' ) {
442
+
return esc_attr( translate_with_gettext_context( $text, $context, $domain ) );
443
+
}
444
+
445
+
/**
446
+
* Translates string with gettext context, and escapes it for safe use in HTML output.
447
+
*
448
+
* If there is no translation, or the text domain isn't loaded, the original text
449
+
* is escaped and returned.
450
+
*
451
+
* @since 2.9.0
452
+
*
453
+
* @param string $text Text to translate.
454
+
* @param string $context Context information for the translators.
455
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
456
+
* Default 'default'.
457
+
* @return string Translated text.
458
+
*/
459
+
function esc_html_x( $text, $context, $domain = 'default' ) {
460
+
return esc_html( translate_with_gettext_context( $text, $context, $domain ) );
461
+
}
462
+
463
+
/**
464
+
* Translates and retrieves the singular or plural form based on the supplied number.
465
+
*
466
+
* Used when you want to use the appropriate form of a string based on whether a
467
+
* number is singular or plural.
468
+
*
469
+
* Example:
470
+
*
471
+
* printf( _n( '%s person', '%s people', $count, 'text-domain' ), number_format_i18n( $count ) );
472
+
*
473
+
* @since 2.8.0
474
+
* @since 5.5.0 Introduced `ngettext-{$domain}` filter.
475
+
*
476
+
* @param string $single The text to be used if the number is singular.
477
+
* @param string $plural The text to be used if the number is plural.
478
+
* @param int $number The number to compare against to use either the singular or plural form.
479
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
480
+
* Default 'default'.
481
+
* @return string The translated singular or plural form.
482
+
*/
483
+
function _n( $single, $plural, $number, $domain = 'default' ) {
484
+
$translations = get_translations_for_domain( $domain );
485
+
$translation = $translations->translate_plural( $single, $plural, $number );
486
+
487
+
/**
488
+
* Filters the singular or plural form of a string.
489
+
*
490
+
* @since 2.2.0
491
+
*
492
+
* @param string $translation Translated text.
493
+
* @param string $single The text to be used if the number is singular.
494
+
* @param string $plural The text to be used if the number is plural.
495
+
* @param int $number The number to compare against to use either the singular or plural form.
496
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
497
+
*/
498
+
$translation = apply_filters( 'ngettext', $translation, $single, $plural, $number, $domain );
499
+
500
+
/**
501
+
* Filters the singular or plural form of a string for a domain.
502
+
*
503
+
* The dynamic portion of the hook name, `$domain`, refers to the text domain.
504
+
*
505
+
* @since 5.5.0
506
+
*
507
+
* @param string $translation Translated text.
508
+
* @param string $single The text to be used if the number is singular.
509
+
* @param string $plural The text to be used if the number is plural.
510
+
* @param int $number The number to compare against to use either the singular or plural form.
511
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
512
+
*/
513
+
$translation = apply_filters( "ngettext_{$domain}", $translation, $single, $plural, $number, $domain );
514
+
515
+
return $translation;
516
+
}
517
+
518
+
/**
519
+
* Translates and retrieves the singular or plural form based on the supplied number, with gettext context.
520
+
*
521
+
* This is a hybrid of _n() and _x(). It supports context and plurals.
522
+
*
523
+
* Used when you want to use the appropriate form of a string with context based on whether a
524
+
* number is singular or plural.
525
+
*
526
+
* Example of a generic phrase which is disambiguated via the context parameter:
527
+
*
528
+
* printf( _nx( '%s group', '%s groups', $people, 'group of people', 'text-domain' ), number_format_i18n( $people ) );
529
+
* printf( _nx( '%s group', '%s groups', $animals, 'group of animals', 'text-domain' ), number_format_i18n( $animals ) );
530
+
*
531
+
* @since 2.8.0
532
+
* @since 5.5.0 Introduced `ngettext_with_context-{$domain}` filter.
533
+
*
534
+
* @param string $single The text to be used if the number is singular.
535
+
* @param string $plural The text to be used if the number is plural.
536
+
* @param int $number The number to compare against to use either the singular or plural form.
537
+
* @param string $context Context information for the translators.
538
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
539
+
* Default 'default'.
540
+
* @return string The translated singular or plural form.
541
+
*/
542
+
function _nx( $single, $plural, $number, $context, $domain = 'default' ) {
543
+
$translations = get_translations_for_domain( $domain );
544
+
$translation = $translations->translate_plural( $single, $plural, $number, $context );
545
+
546
+
/**
547
+
* Filters the singular or plural form of a string with gettext context.
548
+
*
549
+
* @since 2.8.0
550
+
*
551
+
* @param string $translation Translated text.
552
+
* @param string $single The text to be used if the number is singular.
553
+
* @param string $plural The text to be used if the number is plural.
554
+
* @param int $number The number to compare against to use either the singular or plural form.
555
+
* @param string $context Context information for the translators.
556
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
557
+
*/
558
+
$translation = apply_filters( 'ngettext_with_context', $translation, $single, $plural, $number, $context, $domain );
559
+
560
+
/**
561
+
* Filters the singular or plural form of a string with gettext context for a domain.
562
+
*
563
+
* The dynamic portion of the hook name, `$domain`, refers to the text domain.
564
+
*
565
+
* @since 5.5.0
566
+
*
567
+
* @param string $translation Translated text.
568
+
* @param string $single The text to be used if the number is singular.
569
+
* @param string $plural The text to be used if the number is plural.
570
+
* @param int $number The number to compare against to use either the singular or plural form.
571
+
* @param string $context Context information for the translators.
572
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
573
+
*/
574
+
$translation = apply_filters( "ngettext_with_context_{$domain}", $translation, $single, $plural, $number, $context, $domain );
575
+
576
+
return $translation;
577
+
}
578
+
579
+
/**
580
+
* Registers plural strings in POT file, but does not translate them.
581
+
*
582
+
* Used when you want to keep structures with translatable plural
583
+
* strings and use them later when the number is known.
584
+
*
585
+
* Example:
586
+
*
587
+
* $message = _n_noop( '%s post', '%s posts', 'text-domain' );
588
+
* ...
589
+
* printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
590
+
*
591
+
* @since 2.5.0
592
+
*
593
+
* @param string $singular Singular form to be localized.
594
+
* @param string $plural Plural form to be localized.
595
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
596
+
* Default null.
597
+
* @return array {
598
+
* Array of translation information for the strings.
599
+
*
600
+
* @type string $0 Singular form to be localized. No longer used.
601
+
* @type string $1 Plural form to be localized. No longer used.
602
+
* @type string $singular Singular form to be localized.
603
+
* @type string $plural Plural form to be localized.
604
+
* @type null $context Context information for the translators.
605
+
* @type string|null $domain Text domain.
606
+
* }
607
+
*/
608
+
function _n_noop( $singular, $plural, $domain = null ) {
609
+
return array(
610
+
0 => $singular,
611
+
1 => $plural,
612
+
'singular' => $singular,
613
+
'plural' => $plural,
614
+
'context' => null,
615
+
'domain' => $domain,
616
+
);
617
+
}
618
+
619
+
/**
620
+
* Registers plural strings with gettext context in POT file, but does not translate them.
621
+
*
622
+
* Used when you want to keep structures with translatable plural
623
+
* strings and use them later when the number is known.
624
+
*
625
+
* Example of a generic phrase which is disambiguated via the context parameter:
626
+
*
627
+
* $messages = array(
628
+
* 'people' => _nx_noop( '%s group', '%s groups', 'people', 'text-domain' ),
629
+
* 'animals' => _nx_noop( '%s group', '%s groups', 'animals', 'text-domain' ),
630
+
* );
631
+
* ...
632
+
* $message = $messages[ $type ];
633
+
* printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
634
+
*
635
+
* @since 2.8.0
636
+
*
637
+
* @param string $singular Singular form to be localized.
638
+
* @param string $plural Plural form to be localized.
639
+
* @param string $context Context information for the translators.
640
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
641
+
* Default null.
642
+
* @return array {
643
+
* Array of translation information for the strings.
644
+
*
645
+
* @type string $0 Singular form to be localized. No longer used.
646
+
* @type string $1 Plural form to be localized. No longer used.
647
+
* @type string $2 Context information for the translators. No longer used.
648
+
* @type string $singular Singular form to be localized.
649
+
* @type string $plural Plural form to be localized.
650
+
* @type string $context Context information for the translators.
651
+
* @type string|null $domain Text domain.
652
+
* }
653
+
*/
654
+
function _nx_noop( $singular, $plural, $context, $domain = null ) {
655
+
return array(
656
+
0 => $singular,
657
+
1 => $plural,
658
+
2 => $context,
659
+
'singular' => $singular,
660
+
'plural' => $plural,
661
+
'context' => $context,
662
+
'domain' => $domain,
663
+
);
664
+
}
665
+
666
+
/**
667
+
* Translates and returns the singular or plural form of a string that's been registered
668
+
* with _n_noop() or _nx_noop().
669
+
*
670
+
* Used when you want to use a translatable plural string once the number is known.
671
+
*
672
+
* Example:
673
+
*
674
+
* $message = _n_noop( '%s post', '%s posts', 'text-domain' );
675
+
* ...
676
+
* printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
677
+
*
678
+
* @since 3.1.0
679
+
*
680
+
* @param array $nooped_plural {
681
+
* Array that is usually a return value from _n_noop() or _nx_noop().
682
+
*
683
+
* @type string $singular Singular form to be localized.
684
+
* @type string $plural Plural form to be localized.
685
+
* @type string|null $context Context information for the translators.
686
+
* @type string|null $domain Text domain.
687
+
* }
688
+
* @param int $count Number of objects.
689
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. If $nooped_plural contains
690
+
* a text domain passed to _n_noop() or _nx_noop(), it will override this value. Default 'default'.
691
+
* @return string Either $singular or $plural translated text.
692
+
*/
693
+
function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {
694
+
if ( $nooped_plural['domain'] ) {
695
+
$domain = $nooped_plural['domain'];
696
+
}
697
+
698
+
if ( $nooped_plural['context'] ) {
699
+
return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );
700
+
} else {
701
+
return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );
702
+
}
703
+
}
704
+
705
+
/**
706
+
* Loads a .mo file into the text domain $domain.
707
+
*
708
+
* If the text domain already exists, the translations will be merged. If both
709
+
* sets have the same string, the translation from the original value will be taken.
710
+
*
711
+
* On success, the .mo file will be placed in the $l10n global by $domain
712
+
* and will be a MO object.
713
+
*
714
+
* @since 1.5.0
715
+
* @since 6.1.0 Added the `$locale` parameter.
716
+
*
717
+
* @global MO[] $l10n An array of all currently loaded text domains.
718
+
* @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
719
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
720
+
*
721
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
722
+
* @param string $mofile Path to the .mo file.
723
+
* @param string $locale Optional. Locale. Default is the current locale.
724
+
* @return bool True on success, false on failure.
725
+
*/
726
+
function load_textdomain( $domain, $mofile, $locale = null ) {
727
+
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
728
+
global $l10n, $l10n_unloaded, $wp_textdomain_registry;
729
+
730
+
$l10n_unloaded = (array) $l10n_unloaded;
731
+
732
+
if ( ! is_string( $domain ) ) {
733
+
return false;
734
+
}
735
+
736
+
/**
737
+
* Filters whether to short-circuit loading .mo file.
738
+
*
739
+
* Returning a non-null value from the filter will effectively short-circuit
740
+
* the loading, returning the passed value instead.
741
+
*
742
+
* @since 6.3.0
743
+
*
744
+
* @param bool|null $loaded The result of loading a .mo file. Default null.
745
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
746
+
* @param string $mofile Path to the MO file.
747
+
* @param string|null $locale Locale.
748
+
*/
749
+
$loaded = apply_filters( 'pre_load_textdomain', null, $domain, $mofile, $locale );
750
+
if ( null !== $loaded ) {
751
+
if ( true === $loaded ) {
752
+
unset( $l10n_unloaded[ $domain ] );
753
+
}
754
+
755
+
return $loaded;
756
+
}
757
+
758
+
/**
759
+
* Filters whether to override the .mo file loading.
760
+
*
761
+
* @since 2.9.0
762
+
* @since 6.2.0 Added the `$locale` parameter.
763
+
*
764
+
* @param bool $override Whether to override the .mo file loading. Default false.
765
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
766
+
* @param string $mofile Path to the MO file.
767
+
* @param string|null $locale Locale.
768
+
*/
769
+
$plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile, $locale );
770
+
771
+
if ( true === (bool) $plugin_override ) {
772
+
unset( $l10n_unloaded[ $domain ] );
773
+
774
+
return true;
775
+
}
776
+
777
+
/**
778
+
* Fires before the MO translation file is loaded.
779
+
*
780
+
* @since 2.9.0
781
+
*
782
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
783
+
* @param string $mofile Path to the .mo file.
784
+
*/
785
+
do_action( 'load_textdomain', $domain, $mofile );
786
+
787
+
/**
788
+
* Filters MO file path for loading translations for a specific text domain.
789
+
*
790
+
* @since 2.9.0
791
+
*
792
+
* @param string $mofile Path to the MO file.
793
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
794
+
*/
795
+
$mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
796
+
797
+
if ( ! $locale ) {
798
+
$locale = determine_locale();
799
+
}
800
+
801
+
$i18n_controller = WP_Translation_Controller::get_instance();
802
+
803
+
// Ensures the correct locale is set as the current one, in case it was filtered.
804
+
$i18n_controller->set_locale( $locale );
805
+
806
+
/**
807
+
* Filters the preferred file format for translation files.
808
+
*
809
+
* Can be used to disable the use of PHP files for translations.
810
+
*
811
+
* @since 6.5.0
812
+
*
813
+
* @param string $preferred_format Preferred file format. Possible values: 'php', 'mo'. Default: 'php'.
814
+
* @param string $domain The text domain.
815
+
*/
816
+
$preferred_format = apply_filters( 'translation_file_format', 'php', $domain );
817
+
if ( ! in_array( $preferred_format, array( 'php', 'mo' ), true ) ) {
818
+
$preferred_format = 'php';
819
+
}
820
+
821
+
$translation_files = array();
822
+
823
+
if ( 'mo' !== $preferred_format ) {
824
+
$translation_files[] = substr_replace( $mofile, ".l10n.$preferred_format", - strlen( '.mo' ) );
825
+
}
826
+
827
+
$translation_files[] = $mofile;
828
+
829
+
foreach ( $translation_files as $file ) {
830
+
/**
831
+
* Filters the file path for loading translations for the given text domain.
832
+
*
833
+
* Similar to the {@see 'load_textdomain_mofile'} filter with the difference that
834
+
* the file path could be for an MO or PHP file.
835
+
*
836
+
* @since 6.5.0
837
+
* @since 6.6.0 Added the `$locale` parameter.
838
+
*
839
+
* @param string $file Path to the translation file to load.
840
+
* @param string $domain The text domain.
841
+
* @param string $locale The locale.
842
+
*/
843
+
$file = (string) apply_filters( 'load_translation_file', $file, $domain, $locale );
844
+
845
+
$success = $i18n_controller->load_file( $file, $domain, $locale );
846
+
847
+
if ( $success ) {
848
+
if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof MO ) {
849
+
$i18n_controller->load_file( $l10n[ $domain ]->get_filename(), $domain, $locale );
850
+
}
851
+
852
+
// Unset NOOP_Translations reference in get_translations_for_domain().
853
+
unset( $l10n[ $domain ] );
854
+
855
+
$l10n[ $domain ] = new WP_Translations( $i18n_controller, $domain );
856
+
857
+
$wp_textdomain_registry->set( $domain, $locale, dirname( $file ) );
858
+
859
+
return true;
860
+
}
861
+
}
862
+
863
+
return false;
864
+
}
865
+
866
+
/**
867
+
* Unloads translations for a text domain.
868
+
*
869
+
* @since 3.0.0
870
+
* @since 6.1.0 Added the `$reloadable` parameter.
871
+
*
872
+
* @global MO[] $l10n An array of all currently loaded text domains.
873
+
* @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
874
+
*
875
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
876
+
* @param bool $reloadable Whether the text domain can be loaded just-in-time again.
877
+
* @return bool Whether textdomain was unloaded.
878
+
*/
879
+
function unload_textdomain( $domain, $reloadable = false ) {
880
+
global $l10n, $l10n_unloaded;
881
+
882
+
$l10n_unloaded = (array) $l10n_unloaded;
883
+
884
+
/**
885
+
* Filters whether to override the text domain unloading.
886
+
*
887
+
* @since 3.0.0
888
+
* @since 6.1.0 Added the `$reloadable` parameter.
889
+
*
890
+
* @param bool $override Whether to override the text domain unloading. Default false.
891
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
892
+
* @param bool $reloadable Whether the text domain can be loaded just-in-time again.
893
+
*/
894
+
$plugin_override = apply_filters( 'override_unload_textdomain', false, $domain, $reloadable );
895
+
896
+
if ( $plugin_override ) {
897
+
if ( ! $reloadable ) {
898
+
$l10n_unloaded[ $domain ] = true;
899
+
}
900
+
901
+
return true;
902
+
}
903
+
904
+
/**
905
+
* Fires before the text domain is unloaded.
906
+
*
907
+
* @since 3.0.0
908
+
* @since 6.1.0 Added the `$reloadable` parameter.
909
+
*
910
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
911
+
* @param bool $reloadable Whether the text domain can be loaded just-in-time again.
912
+
*/
913
+
do_action( 'unload_textdomain', $domain, $reloadable );
914
+
915
+
// Since multiple locales are supported, reloadable text domains don't actually need to be unloaded.
916
+
if ( ! $reloadable ) {
917
+
WP_Translation_Controller::get_instance()->unload_textdomain( $domain );
918
+
}
919
+
920
+
if ( isset( $l10n[ $domain ] ) ) {
921
+
if ( $l10n[ $domain ] instanceof NOOP_Translations ) {
922
+
unset( $l10n[ $domain ] );
923
+
924
+
return false;
925
+
}
926
+
927
+
unset( $l10n[ $domain ] );
928
+
929
+
if ( ! $reloadable ) {
930
+
$l10n_unloaded[ $domain ] = true;
931
+
}
932
+
933
+
return true;
934
+
}
935
+
936
+
return false;
937
+
}
938
+
939
+
/**
940
+
* Loads default translated strings based on locale.
941
+
*
942
+
* Loads the .mo file in WP_LANG_DIR constant path from WordPress root.
943
+
* The translated (.mo) file is named based on the locale.
944
+
*
945
+
* @see load_textdomain()
946
+
*
947
+
* @since 1.5.0
948
+
*
949
+
* @param string $locale Optional. Locale to load. Default is the value of get_locale().
950
+
* @return bool Whether the textdomain was loaded.
951
+
*/
952
+
function load_default_textdomain( $locale = null ) {
953
+
if ( null === $locale ) {
954
+
$locale = determine_locale();
955
+
}
956
+
957
+
// Unload previously loaded strings so we can switch translations.
958
+
unload_textdomain( 'default', true );
959
+
960
+
$return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo", $locale );
961
+
962
+
if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) {
963
+
load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo", $locale );
964
+
return $return;
965
+
}
966
+
967
+
if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) || doing_action( 'wp_maybe_auto_update' ) ) {
968
+
load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo", $locale );
969
+
}
970
+
971
+
if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) {
972
+
load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo", $locale );
973
+
}
974
+
975
+
return $return;
976
+
}
977
+
978
+
/**
979
+
* Loads a plugin's translated strings.
980
+
*
981
+
* If the path is not given then it will be the root of the plugin directory.
982
+
*
983
+
* The .mo file should be named based on the text domain with a dash, and then the locale exactly.
984
+
*
985
+
* @since 1.5.0
986
+
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
987
+
* @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
988
+
*
989
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
990
+
* @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
991
+
*
992
+
* @param string $domain Unique identifier for retrieving translated strings
993
+
* @param string|false $deprecated Optional. Deprecated. Use the $plugin_rel_path parameter instead.
994
+
* Default false.
995
+
* @param string|false $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
996
+
* Default false.
997
+
* @return bool True when textdomain is successfully loaded, false otherwise.
998
+
*/
999
+
function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
1000
+
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
1001
+
/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
1002
+
global $wp_textdomain_registry, $l10n;
1003
+
1004
+
if ( ! is_string( $domain ) ) {
1005
+
return false;
1006
+
}
1007
+
1008
+
if ( false !== $plugin_rel_path ) {
1009
+
$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
1010
+
} elseif ( false !== $deprecated ) {
1011
+
_deprecated_argument( __FUNCTION__, '2.7.0' );
1012
+
$path = ABSPATH . trim( $deprecated, '/' );
1013
+
} else {
1014
+
$path = WP_PLUGIN_DIR;
1015
+
}
1016
+
1017
+
$wp_textdomain_registry->set_custom_path( $domain, $path );
1018
+
1019
+
// If just-in-time loading was triggered before, reset the entry so it can be tried again.
1020
+
if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
1021
+
unset( $l10n[ $domain ] );
1022
+
}
1023
+
1024
+
return true;
1025
+
}
1026
+
1027
+
/**
1028
+
* Loads the translated strings for a plugin residing in the mu-plugins directory.
1029
+
*
1030
+
* @since 3.0.0
1031
+
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
1032
+
* @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
1033
+
*
1034
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
1035
+
* @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
1036
+
*
1037
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
1038
+
* @param string $mu_plugin_rel_path Optional. Relative to `WPMU_PLUGIN_DIR` directory in which the .mo
1039
+
* file resides. Default empty string.
1040
+
* @return bool True when textdomain is successfully loaded, false otherwise.
1041
+
*/
1042
+
function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
1043
+
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
1044
+
/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
1045
+
global $wp_textdomain_registry, $l10n;
1046
+
1047
+
if ( ! is_string( $domain ) ) {
1048
+
return false;
1049
+
}
1050
+
1051
+
$path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' );
1052
+
1053
+
$wp_textdomain_registry->set_custom_path( $domain, $path );
1054
+
1055
+
// If just-in-time loading was triggered before, reset the entry so it can be tried again.
1056
+
if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
1057
+
unset( $l10n[ $domain ] );
1058
+
}
1059
+
1060
+
return true;
1061
+
}
1062
+
1063
+
/**
1064
+
* Loads the theme's translated strings.
1065
+
*
1066
+
* If the current locale exists as a .mo file in the theme's root directory, it
1067
+
* will be included in the translated strings by the $domain.
1068
+
*
1069
+
* The .mo files must be named based on the locale exactly.
1070
+
*
1071
+
* @since 1.5.0
1072
+
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
1073
+
* @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
1074
+
*
1075
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
1076
+
* @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
1077
+
*
1078
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
1079
+
* @param string|false $path Optional. Path to the directory containing the .mo file.
1080
+
* Default false.
1081
+
* @return bool True when textdomain is successfully loaded, false otherwise.
1082
+
*/
1083
+
function load_theme_textdomain( $domain, $path = false ) {
1084
+
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
1085
+
/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
1086
+
global $wp_textdomain_registry, $l10n;
1087
+
1088
+
if ( ! is_string( $domain ) ) {
1089
+
return false;
1090
+
}
1091
+
1092
+
if ( ! $path ) {
1093
+
$path = get_template_directory();
1094
+
}
1095
+
1096
+
$wp_textdomain_registry->set_custom_path( $domain, $path );
1097
+
1098
+
// If just-in-time loading was triggered before, reset the entry so it can be tried again.
1099
+
if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
1100
+
unset( $l10n[ $domain ] );
1101
+
}
1102
+
1103
+
return true;
1104
+
}
1105
+
1106
+
/**
1107
+
* Loads the child theme's translated strings.
1108
+
*
1109
+
* If the current locale exists as a .mo file in the child theme's
1110
+
* root directory, it will be included in the translated strings by the $domain.
1111
+
*
1112
+
* The .mo files must be named based on the locale exactly.
1113
+
*
1114
+
* @since 2.9.0
1115
+
*
1116
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
1117
+
* @param string|false $path Optional. Path to the directory containing the .mo file.
1118
+
* Default false.
1119
+
* @return bool True when the theme textdomain is successfully loaded, false otherwise.
1120
+
*/
1121
+
function load_child_theme_textdomain( $domain, $path = false ) {
1122
+
if ( ! $path ) {
1123
+
$path = get_stylesheet_directory();
1124
+
}
1125
+
return load_theme_textdomain( $domain, $path );
1126
+
}
1127
+
1128
+
/**
1129
+
* Loads the script translated strings.
1130
+
*
1131
+
* @since 5.0.0
1132
+
* @since 5.0.2 Uses load_script_translations() to load translation data.
1133
+
* @since 5.1.0 The `$domain` parameter was made optional.
1134
+
*
1135
+
* @see WP_Scripts::set_translations()
1136
+
*
1137
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
1138
+
*
1139
+
* @param string $handle Name of the script to register a translation domain to.
1140
+
* @param string $domain Optional. Text domain. Default 'default'.
1141
+
* @param string $path Optional. The full file path to the directory containing translation files.
1142
+
* @return string|false The translated strings in JSON encoding on success,
1143
+
* false if the script textdomain could not be loaded.
1144
+
*/
1145
+
function load_script_textdomain( $handle, $domain = 'default', $path = '' ) {
1146
+
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
1147
+
global $wp_textdomain_registry;
1148
+
1149
+
$wp_scripts = wp_scripts();
1150
+
1151
+
if ( ! isset( $wp_scripts->registered[ $handle ] ) ) {
1152
+
return false;
1153
+
}
1154
+
1155
+
$locale = determine_locale();
1156
+
1157
+
if ( ! $path ) {
1158
+
$path = $wp_textdomain_registry->get( $domain, $locale );
1159
+
}
1160
+
1161
+
$path = untrailingslashit( $path );
1162
+
1163
+
// If a path was given and the handle file exists simply return it.
1164
+
$file_base = 'default' === $domain ? $locale : $domain . '-' . $locale;
1165
+
$handle_filename = $file_base . '-' . $handle . '.json';
1166
+
1167
+
if ( $path ) {
1168
+
$translations = load_script_translations( $path . '/' . $handle_filename, $handle, $domain );
1169
+
1170
+
if ( $translations ) {
1171
+
return $translations;
1172
+
}
1173
+
}
1174
+
1175
+
$src = $wp_scripts->registered[ $handle ]->src;
1176
+
1177
+
if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $wp_scripts->content_url && str_starts_with( $src, $wp_scripts->content_url ) ) ) {
1178
+
$src = $wp_scripts->base_url . $src;
1179
+
}
1180
+
1181
+
$relative = false;
1182
+
$languages_path = WP_LANG_DIR;
1183
+
1184
+
$src_url = wp_parse_url( $src );
1185
+
$content_url = wp_parse_url( content_url() );
1186
+
$plugins_url = wp_parse_url( plugins_url() );
1187
+
$site_url = wp_parse_url( site_url() );
1188
+
$theme_root = get_theme_root();
1189
+
1190
+
// If the host is the same or it's a relative URL.
1191
+
if (
1192
+
( ! isset( $content_url['path'] ) || str_starts_with( $src_url['path'], $content_url['path'] ) ) &&
1193
+
( ! isset( $src_url['host'] ) || ! isset( $content_url['host'] ) || $src_url['host'] === $content_url['host'] )
1194
+
) {
1195
+
// Make the src relative the specific plugin or theme.
1196
+
if ( isset( $content_url['path'] ) ) {
1197
+
$relative = substr( $src_url['path'], strlen( $content_url['path'] ) );
1198
+
} else {
1199
+
$relative = $src_url['path'];
1200
+
}
1201
+
$relative = trim( $relative, '/' );
1202
+
$relative = explode( '/', $relative );
1203
+
1204
+
/*
1205
+
* Ensure correct languages path when using a custom `WP_PLUGIN_DIR` / `WP_PLUGIN_URL` configuration,
1206
+
* a custom theme root, and/or using Multisite with subdirectories.
1207
+
* See https://core.trac.wordpress.org/ticket/60891 and https://core.trac.wordpress.org/ticket/62016.
1208
+
*/
1209
+
1210
+
$theme_dir = array_slice( explode( '/', $theme_root ), -1 );
1211
+
$dirname = $theme_dir[0] === $relative[0] ? 'themes' : 'plugins';
1212
+
1213
+
$languages_path = WP_LANG_DIR . '/' . $dirname;
1214
+
1215
+
$relative = array_slice( $relative, 2 ); // Remove plugins/<plugin name> or themes/<theme name>.
1216
+
$relative = implode( '/', $relative );
1217
+
} elseif (
1218
+
( ! isset( $plugins_url['path'] ) || str_starts_with( $src_url['path'], $plugins_url['path'] ) ) &&
1219
+
( ! isset( $src_url['host'] ) || ! isset( $plugins_url['host'] ) || $src_url['host'] === $plugins_url['host'] )
1220
+
) {
1221
+
// Make the src relative the specific plugin.
1222
+
if ( isset( $plugins_url['path'] ) ) {
1223
+
$relative = substr( $src_url['path'], strlen( $plugins_url['path'] ) );
1224
+
} else {
1225
+
$relative = $src_url['path'];
1226
+
}
1227
+
$relative = trim( $relative, '/' );
1228
+
$relative = explode( '/', $relative );
1229
+
1230
+
$languages_path = WP_LANG_DIR . '/plugins';
1231
+
1232
+
$relative = array_slice( $relative, 1 ); // Remove <plugin name>.
1233
+
$relative = implode( '/', $relative );
1234
+
} elseif ( ! isset( $src_url['host'] ) || ! isset( $site_url['host'] ) || $src_url['host'] === $site_url['host'] ) {
1235
+
if ( ! isset( $site_url['path'] ) ) {
1236
+
$relative = trim( $src_url['path'], '/' );
1237
+
} elseif ( str_starts_with( $src_url['path'], trailingslashit( $site_url['path'] ) ) ) {
1238
+
// Make the src relative to the WP root.
1239
+
$relative = substr( $src_url['path'], strlen( $site_url['path'] ) );
1240
+
$relative = trim( $relative, '/' );
1241
+
}
1242
+
}
1243
+
1244
+
/**
1245
+
* Filters the relative path of scripts used for finding translation files.
1246
+
*
1247
+
* @since 5.0.2
1248
+
*
1249
+
* @param string|false $relative The relative path of the script. False if it could not be determined.
1250
+
* @param string $src The full source URL of the script.
1251
+
*/
1252
+
$relative = apply_filters( 'load_script_textdomain_relative_path', $relative, $src );
1253
+
1254
+
// If the source is not from WP.
1255
+
if ( false === $relative ) {
1256
+
return load_script_translations( false, $handle, $domain );
1257
+
}
1258
+
1259
+
// Translations are always based on the unminified filename.
1260
+
if ( str_ends_with( $relative, '.min.js' ) ) {
1261
+
$relative = substr( $relative, 0, -7 ) . '.js';
1262
+
}
1263
+
1264
+
$md5_filename = $file_base . '-' . md5( $relative ) . '.json';
1265
+
1266
+
if ( $path ) {
1267
+
$translations = load_script_translations( $path . '/' . $md5_filename, $handle, $domain );
1268
+
1269
+
if ( $translations ) {
1270
+
return $translations;
1271
+
}
1272
+
}
1273
+
1274
+
$translations = load_script_translations( $languages_path . '/' . $md5_filename, $handle, $domain );
1275
+
1276
+
if ( $translations ) {
1277
+
return $translations;
1278
+
}
1279
+
1280
+
return load_script_translations( false, $handle, $domain );
1281
+
}
1282
+
1283
+
/**
1284
+
* Loads the translation data for the given script handle and text domain.
1285
+
*
1286
+
* @since 5.0.2
1287
+
*
1288
+
* @param string|false $file Path to the translation file to load. False if there isn't one.
1289
+
* @param string $handle Name of the script to register a translation domain to.
1290
+
* @param string $domain The text domain.
1291
+
* @return string|false The JSON-encoded translated strings for the given script handle and text domain.
1292
+
* False if there are none.
1293
+
*/
1294
+
function load_script_translations( $file, $handle, $domain ) {
1295
+
/**
1296
+
* Pre-filters script translations for the given file, script handle and text domain.
1297
+
*
1298
+
* Returning a non-null value allows to override the default logic, effectively short-circuiting the function.
1299
+
*
1300
+
* @since 5.0.2
1301
+
*
1302
+
* @param string|false|null $translations JSON-encoded translation data. Default null.
1303
+
* @param string|false $file Path to the translation file to load. False if there isn't one.
1304
+
* @param string $handle Name of the script to register a translation domain to.
1305
+
* @param string $domain The text domain.
1306
+
*/
1307
+
$translations = apply_filters( 'pre_load_script_translations', null, $file, $handle, $domain );
1308
+
1309
+
if ( null !== $translations ) {
1310
+
return $translations;
1311
+
}
1312
+
1313
+
/**
1314
+
* Filters the file path for loading script translations for the given script handle and text domain.
1315
+
*
1316
+
* @since 5.0.2
1317
+
*
1318
+
* @param string|false $file Path to the translation file to load. False if there isn't one.
1319
+
* @param string $handle Name of the script to register a translation domain to.
1320
+
* @param string $domain The text domain.
1321
+
*/
1322
+
$file = apply_filters( 'load_script_translation_file', $file, $handle, $domain );
1323
+
1324
+
if ( ! $file || ! is_readable( $file ) ) {
1325
+
return false;
1326
+
}
1327
+
1328
+
$translations = file_get_contents( $file );
1329
+
1330
+
/**
1331
+
* Filters script translations for the given file, script handle and text domain.
1332
+
*
1333
+
* @since 5.0.2
1334
+
*
1335
+
* @param string $translations JSON-encoded translation data.
1336
+
* @param string $file Path to the translation file that was loaded.
1337
+
* @param string $handle Name of the script to register a translation domain to.
1338
+
* @param string $domain The text domain.
1339
+
*/
1340
+
return apply_filters( 'load_script_translations', $translations, $file, $handle, $domain );
1341
+
}
1342
+
1343
+
/**
1344
+
* Loads plugin and theme text domains just-in-time.
1345
+
*
1346
+
* When a textdomain is encountered for the first time, we try to load
1347
+
* the translation file from `wp-content/languages`, removing the need
1348
+
* to call load_plugin_textdomain() or load_theme_textdomain().
1349
+
*
1350
+
* @since 4.6.0
1351
+
* @access private
1352
+
*
1353
+
* @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
1354
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
1355
+
*
1356
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
1357
+
* @return bool True when the textdomain is successfully loaded, false otherwise.
1358
+
*/
1359
+
function _load_textdomain_just_in_time( $domain ) {
1360
+
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
1361
+
global $l10n_unloaded, $wp_textdomain_registry;
1362
+
1363
+
$l10n_unloaded = (array) $l10n_unloaded;
1364
+
1365
+
// Short-circuit if domain is 'default' which is reserved for core.
1366
+
if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) {
1367
+
return false;
1368
+
}
1369
+
1370
+
if ( ! $wp_textdomain_registry->has( $domain ) ) {
1371
+
return false;
1372
+
}
1373
+
1374
+
$locale = determine_locale();
1375
+
$path = $wp_textdomain_registry->get( $domain, $locale );
1376
+
if ( ! $path ) {
1377
+
return false;
1378
+
}
1379
+
1380
+
if ( ! doing_action( 'after_setup_theme' ) && ! did_action( 'after_setup_theme' ) ) {
1381
+
_doing_it_wrong(
1382
+
__FUNCTION__,
1383
+
sprintf(
1384
+
/* translators: 1: The text domain. 2: 'init'. */
1385
+
__( 'Translation loading for the %1$s domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the %2$s action or later.' ),
1386
+
'<code>' . $domain . '</code>',
1387
+
'<code>init</code>'
1388
+
),
1389
+
'6.7.0'
1390
+
);
1391
+
}
1392
+
1393
+
// Themes with their language directory outside of WP_LANG_DIR have a different file name.
1394
+
$template_directory = trailingslashit( get_template_directory() );
1395
+
$stylesheet_directory = trailingslashit( get_stylesheet_directory() );
1396
+
if ( str_starts_with( $path, $template_directory ) || str_starts_with( $path, $stylesheet_directory ) ) {
1397
+
$mofile = "{$path}{$locale}.mo";
1398
+
} else {
1399
+
$mofile = "{$path}{$domain}-{$locale}.mo";
1400
+
}
1401
+
1402
+
return load_textdomain( $domain, $mofile, $locale );
1403
+
}
1404
+
1405
+
/**
1406
+
* Returns the Translations instance for a text domain.
1407
+
*
1408
+
* If there isn't one, returns empty Translations instance.
1409
+
*
1410
+
* @since 2.8.0
1411
+
*
1412
+
* @global MO[] $l10n An array of all currently loaded text domains.
1413
+
*
1414
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
1415
+
* @return Translations|NOOP_Translations A Translations instance.
1416
+
*/
1417
+
function get_translations_for_domain( $domain ) {
1418
+
global $l10n;
1419
+
if ( isset( $l10n[ $domain ] ) || ( _load_textdomain_just_in_time( $domain ) && isset( $l10n[ $domain ] ) ) ) {
1420
+
return $l10n[ $domain ];
1421
+
}
1422
+
1423
+
static $noop_translations = null;
1424
+
if ( null === $noop_translations ) {
1425
+
$noop_translations = new NOOP_Translations();
1426
+
}
1427
+
1428
+
$l10n[ $domain ] = &$noop_translations;
1429
+
1430
+
return $noop_translations;
1431
+
}
1432
+
1433
+
/**
1434
+
* Determines whether there are translations for the text domain.
1435
+
*
1436
+
* @since 3.0.0
1437
+
*
1438
+
* @global MO[] $l10n An array of all currently loaded text domains.
1439
+
*
1440
+
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
1441
+
* @return bool Whether there are translations.
1442
+
*/
1443
+
function is_textdomain_loaded( $domain ) {
1444
+
global $l10n;
1445
+
return isset( $l10n[ $domain ] ) && ! $l10n[ $domain ] instanceof NOOP_Translations;
1446
+
}
1447
+
1448
+
/**
1449
+
* Translates role name.
1450
+
*
1451
+
* Since the role names are in the database and not in the source there
1452
+
* are dummy gettext calls to get them into the POT file and this function
1453
+
* properly translates them back.
1454
+
*
1455
+
* The before_last_bar() call is needed, because older installations keep the roles
1456
+
* using the old context format: 'Role name|User role' and just skipping the
1457
+
* content after the last bar is easier than fixing them in the DB. New installations
1458
+
* won't suffer from that problem.
1459
+
*
1460
+
* @since 2.8.0
1461
+
* @since 5.2.0 Added the `$domain` parameter.
1462
+
*
1463
+
* @param string $name The role name.
1464
+
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
1465
+
* Default 'default'.
1466
+
* @return string Translated role name on success, original name on failure.
1467
+
*/
1468
+
function translate_user_role( $name, $domain = 'default' ) {
1469
+
return translate_with_gettext_context( before_last_bar( $name ), 'User role', $domain );
1470
+
}
1471
+
1472
+
/**
1473
+
* Gets all available languages based on the presence of *.mo and *.l10n.php files in a given directory.
1474
+
*
1475
+
* The default directory is WP_LANG_DIR.
1476
+
*
1477
+
* @since 3.0.0
1478
+
* @since 4.7.0 The results are now filterable with the {@see 'get_available_languages'} filter.
1479
+
* @since 6.5.0 The initial file list is now cached and also takes into account *.l10n.php files.
1480
+
*
1481
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
1482
+
*
1483
+
* @param string $dir A directory to search for language files.
1484
+
* Default WP_LANG_DIR.
1485
+
* @return string[] An array of language codes or an empty array if no languages are present.
1486
+
* Language codes are formed by stripping the file extension from the language file names.
1487
+
*/
1488
+
function get_available_languages( $dir = null ) {
1489
+
global $wp_textdomain_registry;
1490
+
1491
+
$languages = array();
1492
+
1493
+
$path = is_null( $dir ) ? WP_LANG_DIR : $dir;
1494
+
$lang_files = $wp_textdomain_registry->get_language_files_from_path( $path );
1495
+
1496
+
if ( $lang_files ) {
1497
+
foreach ( $lang_files as $lang_file ) {
1498
+
$lang_file = basename( $lang_file, '.mo' );
1499
+
$lang_file = basename( $lang_file, '.l10n.php' );
1500
+
1501
+
if ( ! str_starts_with( $lang_file, 'continents-cities' ) && ! str_starts_with( $lang_file, 'ms-' ) &&
1502
+
! str_starts_with( $lang_file, 'admin-' ) ) {
1503
+
$languages[] = $lang_file;
1504
+
}
1505
+
}
1506
+
}
1507
+
1508
+
/**
1509
+
* Filters the list of available language codes.
1510
+
*
1511
+
* @since 4.7.0
1512
+
*
1513
+
* @param string[] $languages An array of available language codes.
1514
+
* @param string $dir The directory where the language files were found.
1515
+
*/
1516
+
return apply_filters( 'get_available_languages', array_unique( $languages ), $dir );
1517
+
}
1518
+
1519
+
/**
1520
+
* Gets installed translations.
1521
+
*
1522
+
* Looks in the wp-content/languages directory for translations of
1523
+
* plugins or themes.
1524
+
*
1525
+
* @since 3.7.0
1526
+
*
1527
+
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
1528
+
*
1529
+
* @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
1530
+
* @return array Array of language data.
1531
+
*/
1532
+
function wp_get_installed_translations( $type ) {
1533
+
global $wp_textdomain_registry;
1534
+
1535
+
if ( 'themes' !== $type && 'plugins' !== $type && 'core' !== $type ) {
1536
+
return array();
1537
+
}
1538
+
1539
+
$dir = 'core' === $type ? WP_LANG_DIR : WP_LANG_DIR . "/$type";
1540
+
1541
+
if ( ! is_dir( $dir ) ) {
1542
+
return array();
1543
+
}
1544
+
1545
+
$files = $wp_textdomain_registry->get_language_files_from_path( $dir );
1546
+
if ( ! $files ) {
1547
+
return array();
1548
+
}
1549
+
1550
+
$language_data = array();
1551
+
1552
+
foreach ( $files as $file ) {
1553
+
if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?)\.(?:mo|l10n\.php)/', basename( $file ), $match ) ) {
1554
+
continue;
1555
+
}
1556
+
1557
+
list( , $textdomain, $language ) = $match;
1558
+
if ( '' === $textdomain ) {
1559
+
$textdomain = 'default';
1560
+
}
1561
+
1562
+
if ( str_ends_with( $file, '.mo' ) ) {
1563
+
$pofile = substr_replace( $file, '.po', - strlen( '.mo' ) );
1564
+
1565
+
if ( ! file_exists( $pofile ) ) {
1566
+
continue;
1567
+
}
1568
+
1569
+
$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( $pofile );
1570
+
} else {
1571
+
$pofile = substr_replace( $file, '.po', - strlen( '.l10n.php' ) );
1572
+
1573
+
// If both a PO and a PHP file exist, prefer the PO file.
1574
+
if ( file_exists( $pofile ) ) {
1575
+
continue;
1576
+
}
1577
+
1578
+
$language_data[ $textdomain ][ $language ] = wp_get_l10n_php_file_data( $file );
1579
+
}
1580
+
}
1581
+
return $language_data;
1582
+
}
1583
+
1584
+
/**
1585
+
* Extracts headers from a PO file.
1586
+
*
1587
+
* @since 3.7.0
1588
+
*
1589
+
* @param string $po_file Path to PO file.
1590
+
* @return string[] Array of PO file header values keyed by header name.
1591
+
*/
1592
+
function wp_get_pomo_file_data( $po_file ) {
1593
+
$headers = get_file_data(
1594
+
$po_file,
1595
+
array(
1596
+
'POT-Creation-Date' => '"POT-Creation-Date',
1597
+
'PO-Revision-Date' => '"PO-Revision-Date',
1598
+
'Project-Id-Version' => '"Project-Id-Version',
1599
+
'X-Generator' => '"X-Generator',
1600
+
)
1601
+
);
1602
+
foreach ( $headers as $header => $value ) {
1603
+
// Remove possible contextual '\n' and closing double quote.
1604
+
$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
1605
+
}
1606
+
return $headers;
1607
+
}
1608
+
1609
+
/**
1610
+
* Extracts headers from a PHP translation file.
1611
+
*
1612
+
* @since 6.6.0
1613
+
*
1614
+
* @param string $php_file Path to a `.l10n.php` file.
1615
+
* @return string[] Array of file header values keyed by header name.
1616
+
*/
1617
+
function wp_get_l10n_php_file_data( $php_file ) {
1618
+
$data = (array) include $php_file;
1619
+
1620
+
unset( $data['messages'] );
1621
+
$headers = array(
1622
+
'POT-Creation-Date' => 'pot-creation-date',
1623
+
'PO-Revision-Date' => 'po-revision-date',
1624
+
'Project-Id-Version' => 'project-id-version',
1625
+
'X-Generator' => 'x-generator',
1626
+
);
1627
+
1628
+
$result = array(
1629
+
'POT-Creation-Date' => '',
1630
+
'PO-Revision-Date' => '',
1631
+
'Project-Id-Version' => '',
1632
+
'X-Generator' => '',
1633
+
);
1634
+
1635
+
foreach ( $headers as $po_header => $php_header ) {
1636
+
if ( isset( $data[ $php_header ] ) ) {
1637
+
$result[ $po_header ] = $data[ $php_header ];
1638
+
}
1639
+
}
1640
+
1641
+
return $result;
1642
+
}
1643
+
1644
+
/**
1645
+
* Displays or returns a Language selector.
1646
+
*
1647
+
* @since 4.0.0
1648
+
* @since 4.3.0 Introduced the `echo` argument.
1649
+
* @since 4.7.0 Introduced the `show_option_site_default` argument.
1650
+
* @since 5.1.0 Introduced the `show_option_en_us` argument.
1651
+
* @since 5.9.0 Introduced the `explicit_option_en_us` argument.
1652
+
*
1653
+
* @see get_available_languages()
1654
+
* @see wp_get_available_translations()
1655
+
*
1656
+
* @param string|array $args {
1657
+
* Optional. Array or string of arguments for outputting the language selector.
1658
+
*
1659
+
* @type string $id ID attribute of the select element. Default 'locale'.
1660
+
* @type string $name Name attribute of the select element. Default 'locale'.
1661
+
* @type string[] $languages List of installed languages, contain only the locales.
1662
+
* Default empty array.
1663
+
* @type array $translations List of available translations. Default result of
1664
+
* wp_get_available_translations().
1665
+
* @type string $selected Language which should be selected. Default empty.
1666
+
* @type bool|int $echo Whether to echo the generated markup. Accepts 0, 1, or their
1667
+
* boolean equivalents. Default 1.
1668
+
* @type bool $show_available_translations Whether to show available translations. Default true.
1669
+
* @type bool $show_option_site_default Whether to show an option to fall back to the site's locale. Default false.
1670
+
* @type bool $show_option_en_us Whether to show an option for English (United States). Default true.
1671
+
* @type bool $explicit_option_en_us Whether the English (United States) option uses an explicit value of en_US
1672
+
* instead of an empty value. Default false.
1673
+
* }
1674
+
* @return string HTML dropdown list of languages.
1675
+
*/
1676
+
function wp_dropdown_languages( $args = array() ) {
1677
+
1678
+
$parsed_args = wp_parse_args(
1679
+
$args,
1680
+
array(
1681
+
'id' => 'locale',
1682
+
'name' => 'locale',
1683
+
'languages' => array(),
1684
+
'translations' => array(),
1685
+
'selected' => '',
1686
+
'echo' => 1,
1687
+
'show_available_translations' => true,
1688
+
'show_option_site_default' => false,
1689
+
'show_option_en_us' => true,
1690
+
'explicit_option_en_us' => false,
1691
+
)
1692
+
);
1693
+
1694
+
// Bail if no ID or no name.
1695
+
if ( ! $parsed_args['id'] || ! $parsed_args['name'] ) {
1696
+
return;
1697
+
}
1698
+
1699
+
// English (United States) uses an empty string for the value attribute.
1700
+
if ( 'en_US' === $parsed_args['selected'] && ! $parsed_args['explicit_option_en_us'] ) {
1701
+
$parsed_args['selected'] = '';
1702
+
}
1703
+
1704
+
$translations = $parsed_args['translations'];
1705
+
if ( empty( $translations ) ) {
1706
+
require_once ABSPATH . 'wp-admin/includes/translation-install.php';
1707
+
$translations = wp_get_available_translations();
1708
+
}
1709
+
1710
+
/*
1711
+
* $parsed_args['languages'] should only contain the locales. Find the locale in
1712
+
* $translations to get the native name. Fall back to locale.
1713
+
*/
1714
+
$languages = array();
1715
+
foreach ( $parsed_args['languages'] as $locale ) {
1716
+
if ( isset( $translations[ $locale ] ) ) {
1717
+
$translation = $translations[ $locale ];
1718
+
$languages[] = array(
1719
+
'language' => $translation['language'],
1720
+
'native_name' => $translation['native_name'],
1721
+
'lang' => current( $translation['iso'] ),
1722
+
);
1723
+
1724
+
// Remove installed language from available translations.
1725
+
unset( $translations[ $locale ] );
1726
+
} else {
1727
+
$languages[] = array(
1728
+
'language' => $locale,
1729
+
'native_name' => $locale,
1730
+
'lang' => '',
1731
+
);
1732
+
}
1733
+
}
1734
+
1735
+
$translations_available = ( ! empty( $translations ) && $parsed_args['show_available_translations'] );
1736
+
1737
+
// Holds the HTML markup.
1738
+
$structure = array();
1739
+
1740
+
// List installed languages.
1741
+
if ( $translations_available ) {
1742
+
$structure[] = '<optgroup label="' . esc_attr_x( 'Installed', 'translations' ) . '">';
1743
+
}
1744
+
1745
+
// Site default.
1746
+
if ( $parsed_args['show_option_site_default'] ) {
1747
+
$structure[] = sprintf(
1748
+
'<option value="site-default" data-installed="1"%s>%s</option>',
1749
+
selected( 'site-default', $parsed_args['selected'], false ),
1750
+
_x( 'Site Default', 'default site language' )
1751
+
);
1752
+
}
1753
+
1754
+
if ( $parsed_args['show_option_en_us'] ) {
1755
+
$value = ( $parsed_args['explicit_option_en_us'] ) ? 'en_US' : '';
1756
+
$structure[] = sprintf(
1757
+
'<option value="%s" lang="en" data-installed="1"%s>English (United States)</option>',
1758
+
esc_attr( $value ),
1759
+
selected( '', $parsed_args['selected'], false )
1760
+
);
1761
+
}
1762
+
1763
+
// List installed languages.
1764
+
foreach ( $languages as $language ) {
1765
+
$structure[] = sprintf(
1766
+
'<option value="%s" lang="%s"%s data-installed="1">%s</option>',
1767
+
esc_attr( $language['language'] ),
1768
+
esc_attr( $language['lang'] ),
1769
+
selected( $language['language'], $parsed_args['selected'], false ),
1770
+
esc_html( $language['native_name'] )
1771
+
);
1772
+
}
1773
+
if ( $translations_available ) {
1774
+
$structure[] = '</optgroup>';
1775
+
}
1776
+
1777
+
// List available translations.
1778
+
if ( $translations_available ) {
1779
+
$structure[] = '<optgroup label="' . esc_attr_x( 'Available', 'translations' ) . '">';
1780
+
foreach ( $translations as $translation ) {
1781
+
$structure[] = sprintf(
1782
+
'<option value="%s" lang="%s"%s>%s</option>',
1783
+
esc_attr( $translation['language'] ),
1784
+
esc_attr( current( $translation['iso'] ) ),
1785
+
selected( $translation['language'], $parsed_args['selected'], false ),
1786
+
esc_html( $translation['native_name'] )
1787
+
);
1788
+
}
1789
+
$structure[] = '</optgroup>';
1790
+
}
1791
+
1792
+
// Combine the output string.
1793
+
$output = sprintf( '<select name="%s" id="%s">', esc_attr( $parsed_args['name'] ), esc_attr( $parsed_args['id'] ) );
1794
+
$output .= implode( "\n", $structure );
1795
+
$output .= '</select>';
1796
+
1797
+
if ( $parsed_args['echo'] ) {
1798
+
echo $output;
1799
+
}
1800
+
1801
+
return $output;
1802
+
}
1803
+
1804
+
/**
1805
+
* Determines whether the current locale is right-to-left (RTL).
1806
+
*
1807
+
* For more information on this and similar theme functions, check out
1808
+
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
1809
+
* Conditional Tags} article in the Theme Developer Handbook.
1810
+
*
1811
+
* @since 3.0.0
1812
+
*
1813
+
* @global WP_Locale $wp_locale WordPress date and time locale object.
1814
+
*
1815
+
* @return bool Whether locale is RTL.
1816
+
*/
1817
+
function is_rtl() {
1818
+
global $wp_locale;
1819
+
if ( ! ( $wp_locale instanceof WP_Locale ) ) {
1820
+
return false;
1821
+
}
1822
+
return $wp_locale->is_rtl();
1823
+
}
1824
+
1825
+
/**
1826
+
* Switches the translations according to the given locale.
1827
+
*
1828
+
* @since 4.7.0
1829
+
*
1830
+
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1831
+
*
1832
+
* @param string $locale The locale.
1833
+
* @return bool True on success, false on failure.
1834
+
*/
1835
+
function switch_to_locale( $locale ) {
1836
+
/* @var WP_Locale_Switcher $wp_locale_switcher */
1837
+
global $wp_locale_switcher;
1838
+
1839
+
if ( ! $wp_locale_switcher ) {
1840
+
return false;
1841
+
}
1842
+
1843
+
return $wp_locale_switcher->switch_to_locale( $locale );
1844
+
}
1845
+
1846
+
/**
1847
+
* Switches the translations according to the given user's locale.
1848
+
*
1849
+
* @since 6.2.0
1850
+
*
1851
+
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1852
+
*
1853
+
* @param int $user_id User ID.
1854
+
* @return bool True on success, false on failure.
1855
+
*/
1856
+
function switch_to_user_locale( $user_id ) {
1857
+
/* @var WP_Locale_Switcher $wp_locale_switcher */
1858
+
global $wp_locale_switcher;
1859
+
1860
+
if ( ! $wp_locale_switcher ) {
1861
+
return false;
1862
+
}
1863
+
1864
+
return $wp_locale_switcher->switch_to_user_locale( $user_id );
1865
+
}
1866
+
1867
+
/**
1868
+
* Restores the translations according to the previous locale.
1869
+
*
1870
+
* @since 4.7.0
1871
+
*
1872
+
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1873
+
*
1874
+
* @return string|false Locale on success, false on error.
1875
+
*/
1876
+
function restore_previous_locale() {
1877
+
/* @var WP_Locale_Switcher $wp_locale_switcher */
1878
+
global $wp_locale_switcher;
1879
+
1880
+
if ( ! $wp_locale_switcher ) {
1881
+
return false;
1882
+
}
1883
+
1884
+
return $wp_locale_switcher->restore_previous_locale();
1885
+
}
1886
+
1887
+
/**
1888
+
* Restores the translations according to the original locale.
1889
+
*
1890
+
* @since 4.7.0
1891
+
*
1892
+
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1893
+
*
1894
+
* @return string|false Locale on success, false on error.
1895
+
*/
1896
+
function restore_current_locale() {
1897
+
/* @var WP_Locale_Switcher $wp_locale_switcher */
1898
+
global $wp_locale_switcher;
1899
+
1900
+
if ( ! $wp_locale_switcher ) {
1901
+
return false;
1902
+
}
1903
+
1904
+
return $wp_locale_switcher->restore_current_locale();
1905
+
}
1906
+
1907
+
/**
1908
+
* Determines whether switch_to_locale() is in effect.
1909
+
*
1910
+
* @since 4.7.0
1911
+
*
1912
+
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1913
+
*
1914
+
* @return bool True if the locale has been switched, false otherwise.
1915
+
*/
1916
+
function is_locale_switched() {
1917
+
/* @var WP_Locale_Switcher $wp_locale_switcher */
1918
+
global $wp_locale_switcher;
1919
+
1920
+
return $wp_locale_switcher->is_switched();
1921
+
}
1922
+
1923
+
/**
1924
+
* Translates the provided settings value using its i18n schema.
1925
+
*
1926
+
* @since 5.9.0
1927
+
* @access private
1928
+
*
1929
+
* @param string|string[]|array[]|object $i18n_schema I18n schema for the setting.
1930
+
* @param string|string[]|array[] $settings Value for the settings.
1931
+
* @param string $textdomain Textdomain to use with translations.
1932
+
*
1933
+
* @return string|string[]|array[] Translated settings.
1934
+
*/
1935
+
function translate_settings_using_i18n_schema( $i18n_schema, $settings, $textdomain ) {
1936
+
if ( empty( $i18n_schema ) || empty( $settings ) || empty( $textdomain ) ) {
1937
+
return $settings;
1938
+
}
1939
+
1940
+
if ( is_string( $i18n_schema ) && is_string( $settings ) ) {
1941
+
return translate_with_gettext_context( $settings, $i18n_schema, $textdomain );
1942
+
}
1943
+
if ( is_array( $i18n_schema ) && is_array( $settings ) ) {
1944
+
$translated_settings = array();
1945
+
foreach ( $settings as $value ) {
1946
+
$translated_settings[] = translate_settings_using_i18n_schema( $i18n_schema[0], $value, $textdomain );
1947
+
}
1948
+
return $translated_settings;
1949
+
}
1950
+
if ( is_object( $i18n_schema ) && is_array( $settings ) ) {
1951
+
$group_key = '*';
1952
+
$translated_settings = array();
1953
+
foreach ( $settings as $key => $value ) {
1954
+
if ( isset( $i18n_schema->$key ) ) {
1955
+
$translated_settings[ $key ] = translate_settings_using_i18n_schema( $i18n_schema->$key, $value, $textdomain );
1956
+
} elseif ( isset( $i18n_schema->$group_key ) ) {
1957
+
$translated_settings[ $key ] = translate_settings_using_i18n_schema( $i18n_schema->$group_key, $value, $textdomain );
1958
+
} else {
1959
+
$translated_settings[ $key ] = $value;
1960
+
}
1961
+
}
1962
+
return $translated_settings;
1963
+
}
1964
+
return $settings;
1965
+
}
1966
+
1967
+
/**
1968
+
* Retrieves the list item separator based on the locale.
1969
+
*
1970
+
* @since 6.0.0
1971
+
*
1972
+
* @global WP_Locale $wp_locale WordPress date and time locale object.
1973
+
*
1974
+
* @return string Locale-specific list item separator.
1975
+
*/
1976
+
function wp_get_list_item_separator() {
1977
+
global $wp_locale;
1978
+
1979
+
if ( ! ( $wp_locale instanceof WP_Locale ) ) {
1980
+
// Default value of WP_Locale::get_list_item_separator().
1981
+
/* translators: Used between list items, there is a space after the comma. */
1982
+
return __( ', ' );
1983
+
}
1984
+
1985
+
return $wp_locale->get_list_item_separator();
1986
+
}
1987
+
1988
+
/**
1989
+
* Retrieves the word count type based on the locale.
1990
+
*
1991
+
* @since 6.2.0
1992
+
*
1993
+
* @global WP_Locale $wp_locale WordPress date and time locale object.
1994
+
*
1995
+
* @return string Locale-specific word count type. Possible values are `characters_excluding_spaces`,
1996
+
* `characters_including_spaces`, or `words`. Defaults to `words`.
1997
+
*/
1998
+
function wp_get_word_count_type() {
1999
+
global $wp_locale;
2000
+
2001
+
if ( ! ( $wp_locale instanceof WP_Locale ) ) {
2002
+
// Default value of WP_Locale::get_word_count_type().
2003
+
return 'words';
2004
+
}
2005
+
2006
+
return $wp_locale->get_word_count_type();
2007
+
}
2008
+
2009
+
/**
2010
+
* Returns a boolean to indicate whether a translation exists for a given string with optional text domain and locale.
2011
+
*
2012
+
* @since 6.7.0
2013
+
*
2014
+
* @param string $singular Singular translation to check.
2015
+
* @param string $textdomain Optional. Text domain. Default 'default'.
2016
+
* @param ?string $locale Optional. Locale. Default current locale.
2017
+
* @return bool True if the translation exists, false otherwise.
2018
+
*/
2019
+
function has_translation( string $singular, string $textdomain = 'default', ?string $locale = null ): bool {
2020
+
return WP_Translation_Controller::get_instance()->has_translation( $singular, $textdomain, $locale );
2021
+
}
2022
+