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 the locale ID of the WordPress installation. |
---|
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 | * Retrieves the locale of a user. |
---|
80 | * |
---|
81 | * If the user has a locale set to a non-empty string then it will be |
---|
82 | * returned. Otherwise it returns the locale of get_locale(). |
---|
83 | * |
---|
84 | * @since 4.7.0 |
---|
85 | * |
---|
86 | * @param int|WP_User $user_id User's ID or a WP_User object. Defaults to current user. |
---|
87 | * @return string The locale of the user. |
---|
88 | */ |
---|
89 | function get_user_locale( $user_id = 0 ) { |
---|
90 | $user = false; |
---|
91 | if ( 0 === $user_id && function_exists( 'wp_get_current_user' ) ) { |
---|
92 | $user = wp_get_current_user(); |
---|
93 | } elseif ( $user_id instanceof WP_User ) { |
---|
94 | $user = $user_id; |
---|
95 | } elseif ( $user_id && is_numeric( $user_id ) ) { |
---|
96 | $user = get_user_by( 'id', $user_id ); |
---|
97 | } |
---|
98 | |
---|
99 | if ( ! $user ) { |
---|
100 | return get_locale(); |
---|
101 | } |
---|
102 | |
---|
103 | $locale = $user->locale; |
---|
104 | return $locale ? $locale : get_locale(); |
---|
105 | } |
---|
106 | |
---|
107 | /** |
---|
108 | * Determine the current locale desired for the request. |
---|
109 | * |
---|
110 | * @since 5.0.0 |
---|
111 | * |
---|
112 | * @global string $pagenow |
---|
113 | * |
---|
114 | * @return string The determined locale. |
---|
115 | */ |
---|
116 | function determine_locale() { |
---|
117 | /** |
---|
118 | * Filters the locale for the current request prior to the default determination process. |
---|
119 | * |
---|
120 | * Using this filter allows to override the default logic, effectively short-circuiting the function. |
---|
121 | * |
---|
122 | * @since 5.0.0 |
---|
123 | * |
---|
124 | * @param string|null The locale to return and short-circuit, or null as default. |
---|
125 | */ |
---|
126 | $determined_locale = apply_filters( 'pre_determine_locale', null ); |
---|
127 | if ( ! empty( $determined_locale ) && is_string( $determined_locale ) ) { |
---|
128 | return $determined_locale; |
---|
129 | } |
---|
130 | |
---|
131 | $determined_locale = get_locale(); |
---|
132 | |
---|
133 | if ( is_admin() ) { |
---|
134 | $determined_locale = get_user_locale(); |
---|
135 | } |
---|
136 | |
---|
137 | if ( isset( $_GET['_locale'] ) && 'user' === $_GET['_locale'] && wp_is_json_request() ) { |
---|
138 | $determined_locale = get_user_locale(); |
---|
139 | } |
---|
140 | |
---|
141 | if ( ! empty( $_GET['wp_lang'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) { |
---|
142 | $determined_locale = sanitize_text_field( $_GET['wp_lang'] ); |
---|
143 | } |
---|
144 | |
---|
145 | /** |
---|
146 | * Filters the locale for the current request. |
---|
147 | * |
---|
148 | * @since 5.0.0 |
---|
149 | * |
---|
150 | * @param string $locale The locale. |
---|
151 | */ |
---|
152 | return apply_filters( 'determine_locale', $determined_locale ); |
---|
153 | } |
---|
154 | |
---|
155 | /** |
---|
156 | * Retrieve the translation of $text. |
---|
157 | * |
---|
158 | * If there is no translation, or the text domain isn't loaded, the original text is returned. |
---|
159 | * |
---|
160 | * *Note:* Don't use translate() directly, use __() or related functions. |
---|
161 | * |
---|
162 | * @since 2.2.0 |
---|
163 | * |
---|
164 | * @param string $text Text to translate. |
---|
165 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
166 | * Default 'default'. |
---|
167 | * @return string Translated text |
---|
168 | */ |
---|
169 | if (! function_exists('translate')) { |
---|
170 | function translate( $text, $domain = 'default' ) { |
---|
171 | $translations = get_translations_for_domain( $domain ); |
---|
172 | $translation = $translations->translate( $text ); |
---|
173 | |
---|
174 | /** |
---|
175 | * Filters text with its translation. |
---|
176 | * |
---|
177 | * @since 2.0.11 |
---|
178 | * |
---|
179 | * @param string $translation Translated text. |
---|
180 | * @param string $text Text to translate. |
---|
181 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
182 | */ |
---|
183 | return apply_filters( 'gettext', $translation, $text, $domain ); |
---|
184 | } |
---|
185 | } |
---|
186 | |
---|
187 | /** |
---|
188 | * Remove last item on a pipe-delimited string. |
---|
189 | * |
---|
190 | * Meant for removing the last item in a string, such as 'Role name|User role'. The original |
---|
191 | * string will be returned if no pipe '|' characters are found in the string. |
---|
192 | * |
---|
193 | * @since 2.8.0 |
---|
194 | * |
---|
195 | * @param string $string A pipe-delimited string. |
---|
196 | * @return string Either $string or everything before the last pipe. |
---|
197 | */ |
---|
198 | function before_last_bar( $string ) { |
---|
199 | $last_bar = strrpos( $string, '|' ); |
---|
200 | if ( false === $last_bar ) { |
---|
201 | return $string; |
---|
202 | } else { |
---|
203 | return substr( $string, 0, $last_bar ); |
---|
204 | } |
---|
205 | } |
---|
206 | |
---|
207 | /** |
---|
208 | * Retrieve the translation of $text in the context defined in $context. |
---|
209 | * |
---|
210 | * If there is no translation, or the text domain isn't loaded the original |
---|
211 | * text is returned. |
---|
212 | * |
---|
213 | * *Note:* Don't use translate_with_gettext_context() directly, use _x() or related functions. |
---|
214 | * |
---|
215 | * @since 2.8.0 |
---|
216 | * |
---|
217 | * @param string $text Text to translate. |
---|
218 | * @param string $context Context information for the translators. |
---|
219 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
220 | * Default 'default'. |
---|
221 | * @return string Translated text on success, original text on failure. |
---|
222 | */ |
---|
223 | function translate_with_gettext_context( $text, $context, $domain = 'default' ) { |
---|
224 | $translations = get_translations_for_domain( $domain ); |
---|
225 | $translation = $translations->translate( $text, $context ); |
---|
226 | /** |
---|
227 | * Filters text with its translation based on context information. |
---|
228 | * |
---|
229 | * @since 2.8.0 |
---|
230 | * |
---|
231 | * @param string $translation Translated text. |
---|
232 | * @param string $text Text to translate. |
---|
233 | * @param string $context Context information for the translators. |
---|
234 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
235 | */ |
---|
236 | return apply_filters( 'gettext_with_context', $translation, $text, $context, $domain ); |
---|
237 | } |
---|
238 | |
---|
239 | /** |
---|
240 | * Retrieve the translation of $text. |
---|
241 | * |
---|
242 | * If there is no translation, or the text domain isn't loaded, the original text is returned. |
---|
243 | * |
---|
244 | * @since 2.1.0 |
---|
245 | * |
---|
246 | * @param string $text Text to translate. |
---|
247 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
248 | * Default 'default'. |
---|
249 | * @return string Translated text. |
---|
250 | */ |
---|
251 | if (! function_exists('__')) { |
---|
252 | function __( $text, $domain = 'default' ) { |
---|
253 | return translate( $text, $domain ); |
---|
254 | } |
---|
255 | } |
---|
256 | |
---|
257 | /** |
---|
258 | * Retrieve the translation of $text and escapes it for safe use in an attribute. |
---|
259 | * |
---|
260 | * If there is no translation, or the text domain isn't loaded, the original text is returned. |
---|
261 | * |
---|
262 | * @since 2.8.0 |
---|
263 | * |
---|
264 | * @param string $text Text to translate. |
---|
265 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
266 | * Default 'default'. |
---|
267 | * @return string Translated text on success, original text on failure. |
---|
268 | */ |
---|
269 | function esc_attr__( $text, $domain = 'default' ) { |
---|
270 | return esc_attr( translate( $text, $domain ) ); |
---|
271 | } |
---|
272 | |
---|
273 | /** |
---|
274 | * Retrieve the translation of $text and escapes it for safe use in HTML output. |
---|
275 | * |
---|
276 | * If there is no translation, or the text domain isn't loaded, the original text |
---|
277 | * is escaped and returned.. |
---|
278 | * |
---|
279 | * @since 2.8.0 |
---|
280 | * |
---|
281 | * @param string $text Text to translate. |
---|
282 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
283 | * Default 'default'. |
---|
284 | * @return string Translated text |
---|
285 | */ |
---|
286 | function esc_html__( $text, $domain = 'default' ) { |
---|
287 | return esc_html( translate( $text, $domain ) ); |
---|
288 | } |
---|
289 | |
---|
290 | /** |
---|
291 | * Display translated text. |
---|
292 | * |
---|
293 | * @since 1.2.0 |
---|
294 | * |
---|
295 | * @param string $text Text to translate. |
---|
296 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
297 | * Default 'default'. |
---|
298 | */ |
---|
299 | function _e( $text, $domain = 'default' ) { |
---|
300 | echo translate( $text, $domain ); |
---|
301 | } |
---|
302 | |
---|
303 | /** |
---|
304 | * Display translated text that has been escaped for safe use in an attribute. |
---|
305 | * |
---|
306 | * @since 2.8.0 |
---|
307 | * |
---|
308 | * @param string $text Text to translate. |
---|
309 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
310 | * Default 'default'. |
---|
311 | */ |
---|
312 | function esc_attr_e( $text, $domain = 'default' ) { |
---|
313 | echo esc_attr( translate( $text, $domain ) ); |
---|
314 | } |
---|
315 | |
---|
316 | /** |
---|
317 | * Display translated text that has been escaped for safe use in HTML output. |
---|
318 | * |
---|
319 | * @since 2.8.0 |
---|
320 | * |
---|
321 | * @param string $text Text to translate. |
---|
322 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
323 | * Default 'default'. |
---|
324 | */ |
---|
325 | function esc_html_e( $text, $domain = 'default' ) { |
---|
326 | echo esc_html( translate( $text, $domain ) ); |
---|
327 | } |
---|
328 | |
---|
329 | /** |
---|
330 | * Retrieve translated string with gettext context. |
---|
331 | * |
---|
332 | * Quite a few times, there will be collisions with similar translatable text |
---|
333 | * found in more than two places, but with different translated context. |
---|
334 | * |
---|
335 | * By including the context in the pot file, translators can translate the two |
---|
336 | * strings differently. |
---|
337 | * |
---|
338 | * @since 2.8.0 |
---|
339 | * |
---|
340 | * @param string $text Text to translate. |
---|
341 | * @param string $context Context information for the translators. |
---|
342 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
343 | * Default 'default'. |
---|
344 | * @return string Translated context string without pipe. |
---|
345 | */ |
---|
346 | function _x( $text, $context, $domain = 'default' ) { |
---|
347 | return translate_with_gettext_context( $text, $context, $domain ); |
---|
348 | } |
---|
349 | |
---|
350 | /** |
---|
351 | * Display translated string with gettext context. |
---|
352 | * |
---|
353 | * @since 3.0.0 |
---|
354 | * |
---|
355 | * @param string $text Text to translate. |
---|
356 | * @param string $context Context information for the translators. |
---|
357 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
358 | * Default 'default'. |
---|
359 | * @return string Translated context string without pipe. |
---|
360 | */ |
---|
361 | function _ex( $text, $context, $domain = 'default' ) { |
---|
362 | echo _x( $text, $context, $domain ); |
---|
363 | } |
---|
364 | |
---|
365 | /** |
---|
366 | * Translate string with gettext context, and escapes it for safe use in an attribute. |
---|
367 | * |
---|
368 | * @since 2.8.0 |
---|
369 | * |
---|
370 | * @param string $text Text to translate. |
---|
371 | * @param string $context Context information for the translators. |
---|
372 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
373 | * Default 'default'. |
---|
374 | * @return string Translated text |
---|
375 | */ |
---|
376 | function esc_attr_x( $text, $context, $domain = 'default' ) { |
---|
377 | return esc_attr( translate_with_gettext_context( $text, $context, $domain ) ); |
---|
378 | } |
---|
379 | |
---|
380 | /** |
---|
381 | * Translate string with gettext context, and escapes it for safe use in HTML output. |
---|
382 | * |
---|
383 | * @since 2.9.0 |
---|
384 | * |
---|
385 | * @param string $text Text to translate. |
---|
386 | * @param string $context Context information for the translators. |
---|
387 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
388 | * Default 'default'. |
---|
389 | * @return string Translated text. |
---|
390 | */ |
---|
391 | function esc_html_x( $text, $context, $domain = 'default' ) { |
---|
392 | return esc_html( translate_with_gettext_context( $text, $context, $domain ) ); |
---|
393 | } |
---|
394 | |
---|
395 | /** |
---|
396 | * Translates and retrieves the singular or plural form based on the supplied number. |
---|
397 | * |
---|
398 | * Used when you want to use the appropriate form of a string based on whether a |
---|
399 | * number is singular or plural. |
---|
400 | * |
---|
401 | * Example: |
---|
402 | * |
---|
403 | * printf( _n( '%s person', '%s people', $count, 'text-domain' ), number_format_i18n( $count ) ); |
---|
404 | * |
---|
405 | * @since 2.8.0 |
---|
406 | * |
---|
407 | * @param string $single The text to be used if the number is singular. |
---|
408 | * @param string $plural The text to be used if the number is plural. |
---|
409 | * @param int $number The number to compare against to use either the singular or plural form. |
---|
410 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
411 | * Default 'default'. |
---|
412 | * @return string The translated singular or plural form. |
---|
413 | */ |
---|
414 | function _n( $single, $plural, $number, $domain = 'default' ) { |
---|
415 | $translations = get_translations_for_domain( $domain ); |
---|
416 | $translation = $translations->translate_plural( $single, $plural, $number ); |
---|
417 | |
---|
418 | /** |
---|
419 | * Filters the singular or plural form of a string. |
---|
420 | * |
---|
421 | * @since 2.2.0 |
---|
422 | * |
---|
423 | * @param string $translation Translated text. |
---|
424 | * @param string $single The text to be used if the number is singular. |
---|
425 | * @param string $plural The text to be used if the number is plural. |
---|
426 | * @param string $number The number to compare against to use either the singular or plural form. |
---|
427 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
428 | */ |
---|
429 | return apply_filters( 'ngettext', $translation, $single, $plural, $number, $domain ); |
---|
430 | } |
---|
431 | |
---|
432 | /** |
---|
433 | * Translates and retrieves the singular or plural form based on the supplied number, with gettext context. |
---|
434 | * |
---|
435 | * This is a hybrid of _n() and _x(). It supports context and plurals. |
---|
436 | * |
---|
437 | * Used when you want to use the appropriate form of a string with context based on whether a |
---|
438 | * number is singular or plural. |
---|
439 | * |
---|
440 | * Example of a generic phrase which is disambiguated via the context parameter: |
---|
441 | * |
---|
442 | * printf( _nx( '%s group', '%s groups', $people, 'group of people', 'text-domain' ), number_format_i18n( $people ) ); |
---|
443 | * printf( _nx( '%s group', '%s groups', $animals, 'group of animals', 'text-domain' ), number_format_i18n( $animals ) ); |
---|
444 | * |
---|
445 | * @since 2.8.0 |
---|
446 | * |
---|
447 | * @param string $single The text to be used if the number is singular. |
---|
448 | * @param string $plural The text to be used if the number is plural. |
---|
449 | * @param int $number The number to compare against to use either the singular or plural form. |
---|
450 | * @param string $context Context information for the translators. |
---|
451 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
452 | * Default 'default'. |
---|
453 | * @return string The translated singular or plural form. |
---|
454 | */ |
---|
455 | function _nx($single, $plural, $number, $context, $domain = 'default') { |
---|
456 | $translations = get_translations_for_domain( $domain ); |
---|
457 | $translation = $translations->translate_plural( $single, $plural, $number, $context ); |
---|
458 | |
---|
459 | /** |
---|
460 | * Filters the singular or plural form of a string with gettext context. |
---|
461 | * |
---|
462 | * @since 2.8.0 |
---|
463 | * |
---|
464 | * @param string $translation Translated text. |
---|
465 | * @param string $single The text to be used if the number is singular. |
---|
466 | * @param string $plural The text to be used if the number is plural. |
---|
467 | * @param string $number The number to compare against to use either the singular or plural form. |
---|
468 | * @param string $context Context information for the translators. |
---|
469 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
470 | */ |
---|
471 | return apply_filters( 'ngettext_with_context', $translation, $single, $plural, $number, $context, $domain ); |
---|
472 | } |
---|
473 | |
---|
474 | /** |
---|
475 | * Registers plural strings in POT file, but does not translate them. |
---|
476 | * |
---|
477 | * Used when you want to keep structures with translatable plural |
---|
478 | * strings and use them later when the number is known. |
---|
479 | * |
---|
480 | * Example: |
---|
481 | * |
---|
482 | * $message = _n_noop( '%s post', '%s posts', 'text-domain' ); |
---|
483 | * ... |
---|
484 | * printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) ); |
---|
485 | * |
---|
486 | * @since 2.5.0 |
---|
487 | * |
---|
488 | * @param string $singular Singular form to be localized. |
---|
489 | * @param string $plural Plural form to be localized. |
---|
490 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
491 | * Default null. |
---|
492 | * @return array { |
---|
493 | * Array of translation information for the strings. |
---|
494 | * |
---|
495 | * @type string $0 Singular form to be localized. No longer used. |
---|
496 | * @type string $1 Plural form to be localized. No longer used. |
---|
497 | * @type string $singular Singular form to be localized. |
---|
498 | * @type string $plural Plural form to be localized. |
---|
499 | * @type null $context Context information for the translators. |
---|
500 | * @type string $domain Text domain. |
---|
501 | * } |
---|
502 | */ |
---|
503 | function _n_noop( $singular, $plural, $domain = null ) { |
---|
504 | return array( 0 => $singular, 1 => $plural, 'singular' => $singular, 'plural' => $plural, 'context' => null, 'domain' => $domain ); |
---|
505 | } |
---|
506 | |
---|
507 | /** |
---|
508 | * Registers plural strings with gettext context in POT file, but does not translate them. |
---|
509 | * |
---|
510 | * Used when you want to keep structures with translatable plural |
---|
511 | * strings and use them later when the number is known. |
---|
512 | * |
---|
513 | * Example of a generic phrase which is disambiguated via the context parameter: |
---|
514 | * |
---|
515 | * $messages = array( |
---|
516 | * 'people' => _nx_noop( '%s group', '%s groups', 'people', 'text-domain' ), |
---|
517 | * 'animals' => _nx_noop( '%s group', '%s groups', 'animals', 'text-domain' ), |
---|
518 | * ); |
---|
519 | * ... |
---|
520 | * $message = $messages[ $type ]; |
---|
521 | * printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) ); |
---|
522 | * |
---|
523 | * @since 2.8.0 |
---|
524 | * |
---|
525 | * @param string $singular Singular form to be localized. |
---|
526 | * @param string $plural Plural form to be localized. |
---|
527 | * @param string $context Context information for the translators. |
---|
528 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. |
---|
529 | * Default null. |
---|
530 | * @return array { |
---|
531 | * Array of translation information for the strings. |
---|
532 | * |
---|
533 | * @type string $0 Singular form to be localized. No longer used. |
---|
534 | * @type string $1 Plural form to be localized. No longer used. |
---|
535 | * @type string $2 Context information for the translators. No longer used. |
---|
536 | * @type string $singular Singular form to be localized. |
---|
537 | * @type string $plural Plural form to be localized. |
---|
538 | * @type string $context Context information for the translators. |
---|
539 | * @type string $domain Text domain. |
---|
540 | * } |
---|
541 | */ |
---|
542 | function _nx_noop( $singular, $plural, $context, $domain = null ) { |
---|
543 | return array( 0 => $singular, 1 => $plural, 2 => $context, 'singular' => $singular, 'plural' => $plural, 'context' => $context, 'domain' => $domain ); |
---|
544 | } |
---|
545 | |
---|
546 | /** |
---|
547 | * Translates and retrieves the singular or plural form of a string that's been registered |
---|
548 | * with _n_noop() or _nx_noop(). |
---|
549 | * |
---|
550 | * Used when you want to use a translatable plural string once the number is known. |
---|
551 | * |
---|
552 | * Example: |
---|
553 | * |
---|
554 | * $message = _n_noop( '%s post', '%s posts', 'text-domain' ); |
---|
555 | * ... |
---|
556 | * printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) ); |
---|
557 | * |
---|
558 | * @since 3.1.0 |
---|
559 | * |
---|
560 | * @param array $nooped_plural Array with singular, plural, and context keys, usually the result of _n_noop() or _nx_noop(). |
---|
561 | * @param int $count Number of objects. |
---|
562 | * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. If $nooped_plural contains |
---|
563 | * a text domain passed to _n_noop() or _nx_noop(), it will override this value. Default 'default'. |
---|
564 | * @return string Either $single or $plural translated text. |
---|
565 | */ |
---|
566 | function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) { |
---|
567 | if ( $nooped_plural['domain'] ) |
---|
568 | $domain = $nooped_plural['domain']; |
---|
569 | |
---|
570 | if ( $nooped_plural['context'] ) |
---|
571 | return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain ); |
---|
572 | else |
---|
573 | return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain ); |
---|
574 | } |
---|
575 | |
---|
576 | /** |
---|
577 | * Load a .mo file into the text domain $domain. |
---|
578 | * |
---|
579 | * If the text domain already exists, the translations will be merged. If both |
---|
580 | * sets have the same string, the translation from the original value will be taken. |
---|
581 | * |
---|
582 | * On success, the .mo file will be placed in the $l10n global by $domain |
---|
583 | * and will be a MO object. |
---|
584 | * |
---|
585 | * @since 1.5.0 |
---|
586 | * |
---|
587 | * @global array $l10n An array of all currently loaded text domains. |
---|
588 | * @global array $l10n_unloaded An array of all text domains that have been unloaded again. |
---|
589 | * |
---|
590 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
591 | * @param string $mofile Path to the .mo file. |
---|
592 | * @return bool True on success, false on failure. |
---|
593 | */ |
---|
594 | function load_textdomain( $domain, $mofile ) { |
---|
595 | global $l10n, $l10n_unloaded; |
---|
596 | |
---|
597 | $l10n_unloaded = (array) $l10n_unloaded; |
---|
598 | |
---|
599 | /** |
---|
600 | * Filters whether to override the .mo file loading. |
---|
601 | * |
---|
602 | * @since 2.9.0 |
---|
603 | * |
---|
604 | * @param bool $override Whether to override the .mo file loading. Default false. |
---|
605 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
606 | * @param string $mofile Path to the MO file. |
---|
607 | */ |
---|
608 | $plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile ); |
---|
609 | |
---|
610 | if ( true == $plugin_override ) { |
---|
611 | unset( $l10n_unloaded[ $domain ] ); |
---|
612 | |
---|
613 | return true; |
---|
614 | } |
---|
615 | |
---|
616 | /** |
---|
617 | * Fires before the MO translation file is loaded. |
---|
618 | * |
---|
619 | * @since 2.9.0 |
---|
620 | * |
---|
621 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
622 | * @param string $mofile Path to the .mo file. |
---|
623 | */ |
---|
624 | do_action( 'load_textdomain', $domain, $mofile ); |
---|
625 | |
---|
626 | /** |
---|
627 | * Filters MO file path for loading translations for a specific text domain. |
---|
628 | * |
---|
629 | * @since 2.9.0 |
---|
630 | * |
---|
631 | * @param string $mofile Path to the MO file. |
---|
632 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
633 | */ |
---|
634 | $mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain ); |
---|
635 | |
---|
636 | if ( !is_readable( $mofile ) ) return false; |
---|
637 | |
---|
638 | $mo = new MO(); |
---|
639 | if ( !$mo->import_from_file( $mofile ) ) return false; |
---|
640 | |
---|
641 | if ( isset( $l10n[$domain] ) ) |
---|
642 | $mo->merge_with( $l10n[$domain] ); |
---|
643 | |
---|
644 | unset( $l10n_unloaded[ $domain ] ); |
---|
645 | |
---|
646 | $l10n[$domain] = &$mo; |
---|
647 | |
---|
648 | return true; |
---|
649 | } |
---|
650 | |
---|
651 | /** |
---|
652 | * Unload translations for a text domain. |
---|
653 | * |
---|
654 | * @since 3.0.0 |
---|
655 | * |
---|
656 | * @global array $l10n An array of all currently loaded text domains. |
---|
657 | * @global array $l10n_unloaded An array of all text domains that have been unloaded again. |
---|
658 | * |
---|
659 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
660 | * @return bool Whether textdomain was unloaded. |
---|
661 | */ |
---|
662 | function unload_textdomain( $domain ) { |
---|
663 | global $l10n, $l10n_unloaded; |
---|
664 | |
---|
665 | $l10n_unloaded = (array) $l10n_unloaded; |
---|
666 | |
---|
667 | /** |
---|
668 | * Filters whether to override the text domain unloading. |
---|
669 | * |
---|
670 | * @since 3.0.0 |
---|
671 | * |
---|
672 | * @param bool $override Whether to override the text domain unloading. Default false. |
---|
673 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
674 | */ |
---|
675 | $plugin_override = apply_filters( 'override_unload_textdomain', false, $domain ); |
---|
676 | |
---|
677 | if ( $plugin_override ) { |
---|
678 | $l10n_unloaded[ $domain ] = true; |
---|
679 | |
---|
680 | return true; |
---|
681 | } |
---|
682 | |
---|
683 | /** |
---|
684 | * Fires before the text domain is unloaded. |
---|
685 | * |
---|
686 | * @since 3.0.0 |
---|
687 | * |
---|
688 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
689 | */ |
---|
690 | do_action( 'unload_textdomain', $domain ); |
---|
691 | |
---|
692 | if ( isset( $l10n[$domain] ) ) { |
---|
693 | unset( $l10n[$domain] ); |
---|
694 | |
---|
695 | $l10n_unloaded[ $domain ] = true; |
---|
696 | |
---|
697 | return true; |
---|
698 | } |
---|
699 | |
---|
700 | return false; |
---|
701 | } |
---|
702 | |
---|
703 | /** |
---|
704 | * Load default translated strings based on locale. |
---|
705 | * |
---|
706 | * Loads the .mo file in WP_LANG_DIR constant path from WordPress root. |
---|
707 | * The translated (.mo) file is named based on the locale. |
---|
708 | * |
---|
709 | * @see load_textdomain() |
---|
710 | * |
---|
711 | * @since 1.5.0 |
---|
712 | * |
---|
713 | * @param string $locale Optional. Locale to load. Default is the value of get_locale(). |
---|
714 | * @return bool Whether the textdomain was loaded. |
---|
715 | */ |
---|
716 | function load_default_textdomain( $locale = null ) { |
---|
717 | if ( null === $locale ) { |
---|
718 | $locale = determine_locale(); |
---|
719 | } |
---|
720 | |
---|
721 | // Unload previously loaded strings so we can switch translations. |
---|
722 | unload_textdomain( 'default' ); |
---|
723 | |
---|
724 | $return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" ); |
---|
725 | |
---|
726 | if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) { |
---|
727 | load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" ); |
---|
728 | return $return; |
---|
729 | } |
---|
730 | |
---|
731 | if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) { |
---|
732 | load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" ); |
---|
733 | } |
---|
734 | |
---|
735 | if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) |
---|
736 | load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" ); |
---|
737 | |
---|
738 | return $return; |
---|
739 | } |
---|
740 | |
---|
741 | /** |
---|
742 | * Loads a plugin's translated strings. |
---|
743 | * |
---|
744 | * If the path is not given then it will be the root of the plugin directory. |
---|
745 | * |
---|
746 | * The .mo file should be named based on the text domain with a dash, and then the locale exactly. |
---|
747 | * |
---|
748 | * @since 1.5.0 |
---|
749 | * @since 4.6.0 The function now tries to load the .mo file from the languages directory first. |
---|
750 | * |
---|
751 | * @param string $domain Unique identifier for retrieving translated strings |
---|
752 | * @param string $deprecated Optional. Use the $plugin_rel_path parameter instead. Default false. |
---|
753 | * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides. |
---|
754 | * Default false. |
---|
755 | * @return bool True when textdomain is successfully loaded, false otherwise. |
---|
756 | */ |
---|
757 | function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) { |
---|
758 | /** |
---|
759 | * Filters a plugin's locale. |
---|
760 | * |
---|
761 | * @since 3.0.0 |
---|
762 | * |
---|
763 | * @param string $locale The plugin's current locale. |
---|
764 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
765 | */ |
---|
766 | $locale = apply_filters( 'plugin_locale', determine_locale(), $domain ); |
---|
767 | |
---|
768 | $mofile = $domain . '-' . $locale . '.mo'; |
---|
769 | |
---|
770 | // Try to load from the languages directory first. |
---|
771 | if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) { |
---|
772 | return true; |
---|
773 | } |
---|
774 | |
---|
775 | if ( false !== $plugin_rel_path ) { |
---|
776 | $path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' ); |
---|
777 | } elseif ( false !== $deprecated ) { |
---|
778 | _deprecated_argument( __FUNCTION__, '2.7.0' ); |
---|
779 | $path = ABSPATH . trim( $deprecated, '/' ); |
---|
780 | } else { |
---|
781 | $path = WP_PLUGIN_DIR; |
---|
782 | } |
---|
783 | |
---|
784 | return load_textdomain( $domain, $path . '/' . $mofile ); |
---|
785 | } |
---|
786 | |
---|
787 | /** |
---|
788 | * Load the translated strings for a plugin residing in the mu-plugins directory. |
---|
789 | * |
---|
790 | * @since 3.0.0 |
---|
791 | * @since 4.6.0 The function now tries to load the .mo file from the languages directory first. |
---|
792 | * |
---|
793 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
794 | * @param string $mu_plugin_rel_path Optional. Relative to `WPMU_PLUGIN_DIR` directory in which the .mo |
---|
795 | * file resides. Default empty string. |
---|
796 | * @return bool True when textdomain is successfully loaded, false otherwise. |
---|
797 | */ |
---|
798 | function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) { |
---|
799 | /** This filter is documented in wp-includes/l10n.php */ |
---|
800 | $locale = apply_filters( 'plugin_locale', determine_locale(), $domain ); |
---|
801 | |
---|
802 | $mofile = $domain . '-' . $locale . '.mo'; |
---|
803 | |
---|
804 | // Try to load from the languages directory first. |
---|
805 | if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) { |
---|
806 | return true; |
---|
807 | } |
---|
808 | |
---|
809 | $path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' ); |
---|
810 | |
---|
811 | return load_textdomain( $domain, $path . '/' . $mofile ); |
---|
812 | } |
---|
813 | |
---|
814 | /** |
---|
815 | * Load the theme's translated strings. |
---|
816 | * |
---|
817 | * If the current locale exists as a .mo file in the theme's root directory, it |
---|
818 | * will be included in the translated strings by the $domain. |
---|
819 | * |
---|
820 | * The .mo files must be named based on the locale exactly. |
---|
821 | * |
---|
822 | * @since 1.5.0 |
---|
823 | * @since 4.6.0 The function now tries to load the .mo file from the languages directory first. |
---|
824 | * |
---|
825 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
826 | * @param string $path Optional. Path to the directory containing the .mo file. |
---|
827 | * Default false. |
---|
828 | * @return bool True when textdomain is successfully loaded, false otherwise. |
---|
829 | */ |
---|
830 | function load_theme_textdomain( $domain, $path = false ) { |
---|
831 | /** |
---|
832 | * Filters a theme's locale. |
---|
833 | * |
---|
834 | * @since 3.0.0 |
---|
835 | * |
---|
836 | * @param string $locale The theme's current locale. |
---|
837 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
838 | */ |
---|
839 | $locale = apply_filters( 'theme_locale', determine_locale(), $domain ); |
---|
840 | |
---|
841 | $mofile = $domain . '-' . $locale . '.mo'; |
---|
842 | |
---|
843 | // Try to load from the languages directory first. |
---|
844 | if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile ) ) { |
---|
845 | return true; |
---|
846 | } |
---|
847 | |
---|
848 | if ( ! $path ) { |
---|
849 | $path = get_template_directory(); |
---|
850 | } |
---|
851 | |
---|
852 | return load_textdomain( $domain, $path . '/' . $locale . '.mo' ); |
---|
853 | } |
---|
854 | |
---|
855 | /** |
---|
856 | * Load the child themes translated strings. |
---|
857 | * |
---|
858 | * If the current locale exists as a .mo file in the child themes |
---|
859 | * root directory, it will be included in the translated strings by the $domain. |
---|
860 | * |
---|
861 | * The .mo files must be named based on the locale exactly. |
---|
862 | * |
---|
863 | * @since 2.9.0 |
---|
864 | * |
---|
865 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
866 | * @param string $path Optional. Path to the directory containing the .mo file. |
---|
867 | * Default false. |
---|
868 | * @return bool True when the theme textdomain is successfully loaded, false otherwise. |
---|
869 | */ |
---|
870 | function load_child_theme_textdomain( $domain, $path = false ) { |
---|
871 | if ( ! $path ) |
---|
872 | $path = get_stylesheet_directory(); |
---|
873 | return load_theme_textdomain( $domain, $path ); |
---|
874 | } |
---|
875 | |
---|
876 | /** |
---|
877 | * Load the script translated strings. |
---|
878 | * |
---|
879 | * @see WP_Scripts::set_translations() |
---|
880 | * @link https://core.trac.wordpress.org/ticket/45103 |
---|
881 | * @global WP_Scripts $wp_scripts The WP_Scripts object for printing scripts. |
---|
882 | * |
---|
883 | * @since 5.0.0 |
---|
884 | * |
---|
885 | * @param string $handle Name of the script to register a translation domain to. |
---|
886 | * @param string $domain The textdomain. |
---|
887 | * @param string $path Optional. The full file path to the directory containing translation files. |
---|
888 | * |
---|
889 | * @return false|string False if the script textdomain could not be loaded, the translated strings |
---|
890 | * in JSON encoding otherwise. |
---|
891 | */ |
---|
892 | function load_script_textdomain( $handle, $domain, $path = null ) { |
---|
893 | global $wp_scripts; |
---|
894 | |
---|
895 | $path = untrailingslashit( $path ); |
---|
896 | $locale = determine_locale(); |
---|
897 | |
---|
898 | // If a path was given and the handle file exists simply return it. |
---|
899 | $file_base = $domain === 'default' ? $locale : $domain . '-' . $locale; |
---|
900 | $handle_filename = $file_base . '-' . $handle . '.json'; |
---|
901 | if ( $path && file_exists( $path . '/' . $handle_filename ) ) { |
---|
902 | return file_get_contents( $path . '/' . $handle_filename ); |
---|
903 | } |
---|
904 | |
---|
905 | $obj = $wp_scripts->registered[ $handle ]; |
---|
906 | |
---|
907 | /** This filter is documented in wp-includes/class.wp-scripts.php */ |
---|
908 | $src = esc_url( apply_filters( 'script_loader_src', $obj->src, $handle ) ); |
---|
909 | |
---|
910 | $relative = false; |
---|
911 | $languages_path = WP_LANG_DIR; |
---|
912 | |
---|
913 | $src_url = wp_parse_url( $src ); |
---|
914 | $content_url = wp_parse_url( content_url() ); |
---|
915 | $site_url = wp_parse_url( site_url() ); |
---|
916 | |
---|
917 | // If the host is the same or it's a relative URL. |
---|
918 | if ( |
---|
919 | strpos( $src_url['path'], $content_url['path'] ) === 0 && |
---|
920 | ( ! isset( $src_url['host'] ) || $src_url['host'] !== $content_url['host'] ) |
---|
921 | ) { |
---|
922 | // Make the src relative the specific plugin or theme. |
---|
923 | $relative = trim( substr( $src, strlen( $content_url['path'] ) ), '/' ); |
---|
924 | $relative = explode( '/', $relative ); |
---|
925 | |
---|
926 | $languages_path = WP_LANG_DIR . '/' . $relative[0]; |
---|
927 | |
---|
928 | $relative = array_slice( $relative, 2 ); |
---|
929 | $relative = implode( '/', $relative ); |
---|
930 | } elseif ( ! isset( $src_url['host'] ) || $src_url['host'] !== $site_url['host'] ) { |
---|
931 | if ( ! isset( $site_url['path'] ) ) { |
---|
932 | $relative = trim( $src_url['path'], '/' ); |
---|
933 | } elseif ( ( strpos( $src_url['path'], $site_url['path'] ) === 0 ) ) { |
---|
934 | // Make the src relative to the WP root. |
---|
935 | $relative = substr( $src, strlen( $site_url['path'] ) ); |
---|
936 | $relative = trim( $relative, '/' ); |
---|
937 | } |
---|
938 | } |
---|
939 | |
---|
940 | // If the source is not from WP. |
---|
941 | if ( false === $relative ) { |
---|
942 | return false; |
---|
943 | } |
---|
944 | |
---|
945 | // Translations are always based on the unminified filename. |
---|
946 | if ( substr( $relative, -7 ) === '.min.js' ) { |
---|
947 | $relative = substr( $relative, 0, -7 ) . '.js'; |
---|
948 | } |
---|
949 | |
---|
950 | $md5_filename = $file_base . '-' . md5( $relative ) . '.json'; |
---|
951 | if ( $path && file_exists( $path . '/' . $md5_filename ) ) { |
---|
952 | return file_get_contents( $path . '/' . $md5_filename ); |
---|
953 | } |
---|
954 | if ( file_exists( $languages_path . '/' . $md5_filename ) ) { |
---|
955 | return file_get_contents( $languages_path . '/' . $md5_filename ); |
---|
956 | } |
---|
957 | |
---|
958 | return false; |
---|
959 | } |
---|
960 | |
---|
961 | /** |
---|
962 | * Loads plugin and theme textdomains just-in-time. |
---|
963 | * |
---|
964 | * When a textdomain is encountered for the first time, we try to load |
---|
965 | * the translation file from `wp-content/languages`, removing the need |
---|
966 | * to call load_plugin_texdomain() or load_theme_texdomain(). |
---|
967 | * |
---|
968 | * @since 4.6.0 |
---|
969 | * @access private |
---|
970 | * |
---|
971 | * @see get_translations_for_domain() |
---|
972 | * @global array $l10n_unloaded An array of all text domains that have been unloaded again. |
---|
973 | * |
---|
974 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
975 | * @return bool True when the textdomain is successfully loaded, false otherwise. |
---|
976 | */ |
---|
977 | function _load_textdomain_just_in_time( $domain ) { |
---|
978 | global $l10n_unloaded; |
---|
979 | |
---|
980 | $l10n_unloaded = (array) $l10n_unloaded; |
---|
981 | |
---|
982 | // Short-circuit if domain is 'default' which is reserved for core. |
---|
983 | if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) { |
---|
984 | return false; |
---|
985 | } |
---|
986 | |
---|
987 | $translation_path = _get_path_to_translation( $domain ); |
---|
988 | if ( false === $translation_path ) { |
---|
989 | return false; |
---|
990 | } |
---|
991 | |
---|
992 | return load_textdomain( $domain, $translation_path ); |
---|
993 | } |
---|
994 | |
---|
995 | /** |
---|
996 | * Gets the path to a translation file for loading a textdomain just in time. |
---|
997 | * |
---|
998 | * Caches the retrieved results internally. |
---|
999 | * |
---|
1000 | * @since 4.7.0 |
---|
1001 | * @access private |
---|
1002 | * |
---|
1003 | * @see _load_textdomain_just_in_time() |
---|
1004 | * |
---|
1005 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
1006 | * @param bool $reset Whether to reset the internal cache. Used by the switch to locale functionality. |
---|
1007 | * @return string|false The path to the translation file or false if no translation file was found. |
---|
1008 | */ |
---|
1009 | function _get_path_to_translation( $domain, $reset = false ) { |
---|
1010 | static $available_translations = array(); |
---|
1011 | |
---|
1012 | if ( true === $reset ) { |
---|
1013 | $available_translations = array(); |
---|
1014 | } |
---|
1015 | |
---|
1016 | if ( ! isset( $available_translations[ $domain ] ) ) { |
---|
1017 | $available_translations[ $domain ] = _get_path_to_translation_from_lang_dir( $domain ); |
---|
1018 | } |
---|
1019 | |
---|
1020 | return $available_translations[ $domain ]; |
---|
1021 | } |
---|
1022 | |
---|
1023 | /** |
---|
1024 | * Gets the path to a translation file in the languages directory for the current locale. |
---|
1025 | * |
---|
1026 | * Holds a cached list of available .mo files to improve performance. |
---|
1027 | * |
---|
1028 | * @since 4.7.0 |
---|
1029 | * @access private |
---|
1030 | * |
---|
1031 | * @see _get_path_to_translation() |
---|
1032 | * |
---|
1033 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
1034 | * @return string|false The path to the translation file or false if no translation file was found. |
---|
1035 | */ |
---|
1036 | function _get_path_to_translation_from_lang_dir( $domain ) { |
---|
1037 | static $cached_mofiles = null; |
---|
1038 | |
---|
1039 | if ( null === $cached_mofiles ) { |
---|
1040 | $cached_mofiles = array(); |
---|
1041 | |
---|
1042 | $locations = array( |
---|
1043 | WP_LANG_DIR . '/plugins', |
---|
1044 | WP_LANG_DIR . '/themes', |
---|
1045 | ); |
---|
1046 | |
---|
1047 | foreach ( $locations as $location ) { |
---|
1048 | $mofiles = glob( $location . '/*.mo' ); |
---|
1049 | if ( $mofiles ) { |
---|
1050 | $cached_mofiles = array_merge( $cached_mofiles, $mofiles ); |
---|
1051 | } |
---|
1052 | } |
---|
1053 | } |
---|
1054 | |
---|
1055 | $locale = determine_locale(); |
---|
1056 | $mofile = "{$domain}-{$locale}.mo"; |
---|
1057 | |
---|
1058 | $path = WP_LANG_DIR . '/plugins/' . $mofile; |
---|
1059 | if ( in_array( $path, $cached_mofiles ) ) { |
---|
1060 | return $path; |
---|
1061 | } |
---|
1062 | |
---|
1063 | $path = WP_LANG_DIR . '/themes/' . $mofile; |
---|
1064 | if ( in_array( $path, $cached_mofiles ) ) { |
---|
1065 | return $path; |
---|
1066 | } |
---|
1067 | |
---|
1068 | return false; |
---|
1069 | } |
---|
1070 | |
---|
1071 | /** |
---|
1072 | * Return the Translations instance for a text domain. |
---|
1073 | * |
---|
1074 | * If there isn't one, returns empty Translations instance. |
---|
1075 | * |
---|
1076 | * @since 2.8.0 |
---|
1077 | * |
---|
1078 | * @global array $l10n |
---|
1079 | * |
---|
1080 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
1081 | * @return Translations|NOOP_Translations A Translations instance. |
---|
1082 | */ |
---|
1083 | function get_translations_for_domain( $domain ) { |
---|
1084 | global $l10n; |
---|
1085 | if ( isset( $l10n[ $domain ] ) || ( _load_textdomain_just_in_time( $domain ) && isset( $l10n[ $domain ] ) ) ) { |
---|
1086 | return $l10n[ $domain ]; |
---|
1087 | } |
---|
1088 | |
---|
1089 | static $noop_translations = null; |
---|
1090 | if ( null === $noop_translations ) { |
---|
1091 | $noop_translations = new NOOP_Translations; |
---|
1092 | } |
---|
1093 | |
---|
1094 | return $noop_translations; |
---|
1095 | } |
---|
1096 | |
---|
1097 | /** |
---|
1098 | * Whether there are translations for the text domain. |
---|
1099 | * |
---|
1100 | * @since 3.0.0 |
---|
1101 | * |
---|
1102 | * @global array $l10n |
---|
1103 | * |
---|
1104 | * @param string $domain Text domain. Unique identifier for retrieving translated strings. |
---|
1105 | * @return bool Whether there are translations. |
---|
1106 | */ |
---|
1107 | function is_textdomain_loaded( $domain ) { |
---|
1108 | global $l10n; |
---|
1109 | return isset( $l10n[ $domain ] ); |
---|
1110 | } |
---|
1111 | |
---|
1112 | /** |
---|
1113 | * Translates role name. |
---|
1114 | * |
---|
1115 | * Since the role names are in the database and not in the source there |
---|
1116 | * are dummy gettext calls to get them into the POT file and this function |
---|
1117 | * properly translates them back. |
---|
1118 | * |
---|
1119 | * The before_last_bar() call is needed, because older installations keep the roles |
---|
1120 | * using the old context format: 'Role name|User role' and just skipping the |
---|
1121 | * content after the last bar is easier than fixing them in the DB. New installations |
---|
1122 | * won't suffer from that problem. |
---|
1123 | * |
---|
1124 | * @since 2.8.0 |
---|
1125 | * |
---|
1126 | * @param string $name The role name. |
---|
1127 | * @return string Translated role name on success, original name on failure. |
---|
1128 | */ |
---|
1129 | function translate_user_role( $name ) { |
---|
1130 | return translate_with_gettext_context( before_last_bar($name), 'User role' ); |
---|
1131 | } |
---|
1132 | |
---|
1133 | /** |
---|
1134 | * Get all available languages based on the presence of *.mo files in a given directory. |
---|
1135 | * |
---|
1136 | * The default directory is WP_LANG_DIR. |
---|
1137 | * |
---|
1138 | * @since 3.0.0 |
---|
1139 | * @since 4.7.0 The results are now filterable with the {@see 'get_available_languages'} filter. |
---|
1140 | * |
---|
1141 | * @param string $dir A directory to search for language files. |
---|
1142 | * Default WP_LANG_DIR. |
---|
1143 | * @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. |
---|
1144 | */ |
---|
1145 | function get_available_languages( $dir = null ) { |
---|
1146 | $languages = array(); |
---|
1147 | |
---|
1148 | $lang_files = glob( ( is_null( $dir ) ? WP_LANG_DIR : $dir ) . '/*.mo' ); |
---|
1149 | if ( $lang_files ) { |
---|
1150 | foreach ( $lang_files as $lang_file ) { |
---|
1151 | $lang_file = basename( $lang_file, '.mo' ); |
---|
1152 | if ( 0 !== strpos( $lang_file, 'continents-cities' ) && 0 !== strpos( $lang_file, 'ms-' ) && |
---|
1153 | 0 !== strpos( $lang_file, 'admin-' ) ) { |
---|
1154 | $languages[] = $lang_file; |
---|
1155 | } |
---|
1156 | } |
---|
1157 | } |
---|
1158 | |
---|
1159 | /** |
---|
1160 | * Filters the list of available language codes. |
---|
1161 | * |
---|
1162 | * @since 4.7.0 |
---|
1163 | * |
---|
1164 | * @param array $languages An array of available language codes. |
---|
1165 | * @param string $dir The directory where the language files were found. |
---|
1166 | */ |
---|
1167 | return apply_filters( 'get_available_languages', $languages, $dir ); |
---|
1168 | } |
---|
1169 | |
---|
1170 | /** |
---|
1171 | * Get installed translations. |
---|
1172 | * |
---|
1173 | * Looks in the wp-content/languages directory for translations of |
---|
1174 | * plugins or themes. |
---|
1175 | * |
---|
1176 | * @since 3.7.0 |
---|
1177 | * |
---|
1178 | * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'. |
---|
1179 | * @return array Array of language data. |
---|
1180 | */ |
---|
1181 | function wp_get_installed_translations( $type ) { |
---|
1182 | if ( $type !== 'themes' && $type !== 'plugins' && $type !== 'core' ) |
---|
1183 | return array(); |
---|
1184 | |
---|
1185 | $dir = 'core' === $type ? '' : "/$type"; |
---|
1186 | |
---|
1187 | if ( ! is_dir( WP_LANG_DIR ) ) |
---|
1188 | return array(); |
---|
1189 | |
---|
1190 | if ( $dir && ! is_dir( WP_LANG_DIR . $dir ) ) |
---|
1191 | return array(); |
---|
1192 | |
---|
1193 | $files = scandir( WP_LANG_DIR . $dir ); |
---|
1194 | if ( ! $files ) |
---|
1195 | return array(); |
---|
1196 | |
---|
1197 | $language_data = array(); |
---|
1198 | |
---|
1199 | foreach ( $files as $file ) { |
---|
1200 | if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "$dir/$file" ) ) { |
---|
1201 | continue; |
---|
1202 | } |
---|
1203 | if ( substr( $file, -3 ) !== '.po' ) { |
---|
1204 | continue; |
---|
1205 | } |
---|
1206 | if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) { |
---|
1207 | continue; |
---|
1208 | } |
---|
1209 | if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) { |
---|
1210 | continue; |
---|
1211 | } |
---|
1212 | |
---|
1213 | list( , $textdomain, $language ) = $match; |
---|
1214 | if ( '' === $textdomain ) { |
---|
1215 | $textdomain = 'default'; |
---|
1216 | } |
---|
1217 | $language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "$dir/$file" ); |
---|
1218 | } |
---|
1219 | return $language_data; |
---|
1220 | } |
---|
1221 | |
---|
1222 | /** |
---|
1223 | * Extract headers from a PO file. |
---|
1224 | * |
---|
1225 | * @since 3.7.0 |
---|
1226 | * |
---|
1227 | * @param string $po_file Path to PO file. |
---|
1228 | * @return array PO file headers. |
---|
1229 | */ |
---|
1230 | function wp_get_pomo_file_data( $po_file ) { |
---|
1231 | $headers = get_file_data( $po_file, array( |
---|
1232 | 'POT-Creation-Date' => '"POT-Creation-Date', |
---|
1233 | 'PO-Revision-Date' => '"PO-Revision-Date', |
---|
1234 | 'Project-Id-Version' => '"Project-Id-Version', |
---|
1235 | 'X-Generator' => '"X-Generator', |
---|
1236 | ) ); |
---|
1237 | foreach ( $headers as $header => $value ) { |
---|
1238 | // Remove possible contextual '\n' and closing double quote. |
---|
1239 | $headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value ); |
---|
1240 | } |
---|
1241 | return $headers; |
---|
1242 | } |
---|
1243 | |
---|
1244 | /** |
---|
1245 | * Language selector. |
---|
1246 | * |
---|
1247 | * @since 4.0.0 |
---|
1248 | * @since 4.3.0 Introduced the `echo` argument. |
---|
1249 | * @since 4.7.0 Introduced the `show_option_site_default` argument. |
---|
1250 | * |
---|
1251 | * @see get_available_languages() |
---|
1252 | * @see wp_get_available_translations() |
---|
1253 | * |
---|
1254 | * @param string|array $args { |
---|
1255 | * Optional. Array or string of arguments for outputting the language selector. |
---|
1256 | * |
---|
1257 | * @type string $id ID attribute of the select element. Default 'locale'. |
---|
1258 | * @type string $name Name attribute of the select element. Default 'locale'. |
---|
1259 | * @type array $languages List of installed languages, contain only the locales. |
---|
1260 | * Default empty array. |
---|
1261 | * @type array $translations List of available translations. Default result of |
---|
1262 | * wp_get_available_translations(). |
---|
1263 | * @type string $selected Language which should be selected. Default empty. |
---|
1264 | * @type bool|int $echo Whether to echo the generated markup. Accepts 0, 1, or their |
---|
1265 | * boolean equivalents. Default 1. |
---|
1266 | * @type bool $show_available_translations Whether to show available translations. Default true. |
---|
1267 | * @type bool $show_option_site_default Whether to show an option to fall back to the site's locale. Default false. |
---|
1268 | * } |
---|
1269 | * @return string HTML content |
---|
1270 | */ |
---|
1271 | function wp_dropdown_languages( $args = array() ) { |
---|
1272 | |
---|
1273 | $parsed_args = wp_parse_args( $args, array( |
---|
1274 | 'id' => 'locale', |
---|
1275 | 'name' => 'locale', |
---|
1276 | 'languages' => array(), |
---|
1277 | 'translations' => array(), |
---|
1278 | 'selected' => '', |
---|
1279 | 'echo' => 1, |
---|
1280 | 'show_available_translations' => true, |
---|
1281 | 'show_option_site_default' => false, |
---|
1282 | ) ); |
---|
1283 | |
---|
1284 | // Bail if no ID or no name. |
---|
1285 | if ( ! $parsed_args['id'] || ! $parsed_args['name'] ) { |
---|
1286 | return; |
---|
1287 | } |
---|
1288 | |
---|
1289 | // English (United States) uses an empty string for the value attribute. |
---|
1290 | if ( 'en_US' === $parsed_args['selected'] ) { |
---|
1291 | $parsed_args['selected'] = ''; |
---|
1292 | } |
---|
1293 | |
---|
1294 | $translations = $parsed_args['translations']; |
---|
1295 | if ( empty( $translations ) ) { |
---|
1296 | require_once( ABSPATH . 'wp-admin/includes/translation-install.php' ); |
---|
1297 | $translations = wp_get_available_translations(); |
---|
1298 | } |
---|
1299 | |
---|
1300 | /* |
---|
1301 | * $parsed_args['languages'] should only contain the locales. Find the locale in |
---|
1302 | * $translations to get the native name. Fall back to locale. |
---|
1303 | */ |
---|
1304 | $languages = array(); |
---|
1305 | foreach ( $parsed_args['languages'] as $locale ) { |
---|
1306 | if ( isset( $translations[ $locale ] ) ) { |
---|
1307 | $translation = $translations[ $locale ]; |
---|
1308 | $languages[] = array( |
---|
1309 | 'language' => $translation['language'], |
---|
1310 | 'native_name' => $translation['native_name'], |
---|
1311 | 'lang' => current( $translation['iso'] ), |
---|
1312 | ); |
---|
1313 | |
---|
1314 | // Remove installed language from available translations. |
---|
1315 | unset( $translations[ $locale ] ); |
---|
1316 | } else { |
---|
1317 | $languages[] = array( |
---|
1318 | 'language' => $locale, |
---|
1319 | 'native_name' => $locale, |
---|
1320 | 'lang' => '', |
---|
1321 | ); |
---|
1322 | } |
---|
1323 | } |
---|
1324 | |
---|
1325 | $translations_available = ( ! empty( $translations ) && $parsed_args['show_available_translations'] ); |
---|
1326 | |
---|
1327 | // Holds the HTML markup. |
---|
1328 | $structure = array(); |
---|
1329 | |
---|
1330 | // List installed languages. |
---|
1331 | if ( $translations_available ) { |
---|
1332 | $structure[] = '<optgroup label="' . esc_attr_x( 'Installed', 'translations' ) . '">'; |
---|
1333 | } |
---|
1334 | |
---|
1335 | // Site default. |
---|
1336 | if ( $parsed_args['show_option_site_default'] ) { |
---|
1337 | $structure[] = sprintf( |
---|
1338 | '<option value="site-default" data-installed="1"%s>%s</option>', |
---|
1339 | selected( 'site-default', $parsed_args['selected'], false ), |
---|
1340 | _x( 'Site Default', 'default site language' ) |
---|
1341 | ); |
---|
1342 | } |
---|
1343 | |
---|
1344 | // Always show English. |
---|
1345 | $structure[] = sprintf( |
---|
1346 | '<option value="" lang="en" data-installed="1"%s>English (United States)</option>', |
---|
1347 | selected( '', $parsed_args['selected'], false ) |
---|
1348 | ); |
---|
1349 | |
---|
1350 | // List installed languages. |
---|
1351 | foreach ( $languages as $language ) { |
---|
1352 | $structure[] = sprintf( |
---|
1353 | '<option value="%s" lang="%s"%s data-installed="1">%s</option>', |
---|
1354 | esc_attr( $language['language'] ), |
---|
1355 | esc_attr( $language['lang'] ), |
---|
1356 | selected( $language['language'], $parsed_args['selected'], false ), |
---|
1357 | esc_html( $language['native_name'] ) |
---|
1358 | ); |
---|
1359 | } |
---|
1360 | if ( $translations_available ) { |
---|
1361 | $structure[] = '</optgroup>'; |
---|
1362 | } |
---|
1363 | |
---|
1364 | // List available translations. |
---|
1365 | if ( $translations_available ) { |
---|
1366 | $structure[] = '<optgroup label="' . esc_attr_x( 'Available', 'translations' ) . '">'; |
---|
1367 | foreach ( $translations as $translation ) { |
---|
1368 | $structure[] = sprintf( |
---|
1369 | '<option value="%s" lang="%s"%s>%s</option>', |
---|
1370 | esc_attr( $translation['language'] ), |
---|
1371 | esc_attr( current( $translation['iso'] ) ), |
---|
1372 | selected( $translation['language'], $parsed_args['selected'], false ), |
---|
1373 | esc_html( $translation['native_name'] ) |
---|
1374 | ); |
---|
1375 | } |
---|
1376 | $structure[] = '</optgroup>'; |
---|
1377 | } |
---|
1378 | |
---|
1379 | // Combine the output string. |
---|
1380 | $output = sprintf( '<select name="%s" id="%s">', esc_attr( $parsed_args['name'] ), esc_attr( $parsed_args['id'] ) ); |
---|
1381 | $output .= join( "\n", $structure ); |
---|
1382 | $output .= '</select>'; |
---|
1383 | |
---|
1384 | if ( $parsed_args['echo'] ) { |
---|
1385 | echo $output; |
---|
1386 | } |
---|
1387 | |
---|
1388 | return $output; |
---|
1389 | } |
---|
1390 | |
---|
1391 | /** |
---|
1392 | * Determines whether the current locale is right-to-left (RTL). |
---|
1393 | * |
---|
1394 | * For more information on this and similar theme functions, check out |
---|
1395 | * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ |
---|
1396 | * Conditional Tags} article in the Theme Developer Handbook. |
---|
1397 | * |
---|
1398 | * @since 3.0.0 |
---|
1399 | * |
---|
1400 | * @global WP_Locale $wp_locale |
---|
1401 | * |
---|
1402 | * @return bool Whether locale is RTL. |
---|
1403 | */ |
---|
1404 | function is_rtl() { |
---|
1405 | global $wp_locale; |
---|
1406 | if ( ! ( $wp_locale instanceof WP_Locale ) ) { |
---|
1407 | return false; |
---|
1408 | } |
---|
1409 | return $wp_locale->is_rtl(); |
---|
1410 | } |
---|
1411 | |
---|
1412 | /** |
---|
1413 | * Switches the translations according to the given locale. |
---|
1414 | * |
---|
1415 | * @since 4.7.0 |
---|
1416 | * |
---|
1417 | * @global WP_Locale_Switcher $wp_locale_switcher |
---|
1418 | * |
---|
1419 | * @param string $locale The locale. |
---|
1420 | * @return bool True on success, false on failure. |
---|
1421 | */ |
---|
1422 | function switch_to_locale( $locale ) { |
---|
1423 | /* @var WP_Locale_Switcher $wp_locale_switcher */ |
---|
1424 | global $wp_locale_switcher; |
---|
1425 | |
---|
1426 | return $wp_locale_switcher->switch_to_locale( $locale ); |
---|
1427 | } |
---|
1428 | |
---|
1429 | /** |
---|
1430 | * Restores the translations according to the previous locale. |
---|
1431 | * |
---|
1432 | * @since 4.7.0 |
---|
1433 | * |
---|
1434 | * @global WP_Locale_Switcher $wp_locale_switcher |
---|
1435 | * |
---|
1436 | * @return string|false Locale on success, false on error. |
---|
1437 | */ |
---|
1438 | function restore_previous_locale() { |
---|
1439 | /* @var WP_Locale_Switcher $wp_locale_switcher */ |
---|
1440 | global $wp_locale_switcher; |
---|
1441 | |
---|
1442 | return $wp_locale_switcher->restore_previous_locale(); |
---|
1443 | } |
---|
1444 | |
---|
1445 | /** |
---|
1446 | * Restores the translations according to the original locale. |
---|
1447 | * |
---|
1448 | * @since 4.7.0 |
---|
1449 | * |
---|
1450 | * @global WP_Locale_Switcher $wp_locale_switcher |
---|
1451 | * |
---|
1452 | * @return string|false Locale on success, false on error. |
---|
1453 | */ |
---|
1454 | function restore_current_locale() { |
---|
1455 | /* @var WP_Locale_Switcher $wp_locale_switcher */ |
---|
1456 | global $wp_locale_switcher; |
---|
1457 | |
---|
1458 | return $wp_locale_switcher->restore_current_locale(); |
---|
1459 | } |
---|
1460 | |
---|
1461 | /** |
---|
1462 | * Whether switch_to_locale() is in effect. |
---|
1463 | * |
---|
1464 | * @since 4.7.0 |
---|
1465 | * |
---|
1466 | * @global WP_Locale_Switcher $wp_locale_switcher |
---|
1467 | * |
---|
1468 | * @return bool True if the locale has been switched, false otherwise. |
---|
1469 | */ |
---|
1470 | function is_locale_switched() { |
---|
1471 | /* @var WP_Locale_Switcher $wp_locale_switcher */ |
---|
1472 | global $wp_locale_switcher; |
---|
1473 | |
---|
1474 | return $wp_locale_switcher->is_switched(); |
---|
1475 | } |
---|