PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 All 205 releases
booking / core / wpbc-translation.php

wpbc-translation.php in Booking Calendar 11.9, at core/wpbc-translation.php

1,668 lines 63.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version 1.0
4 * @package Booking Calendar
5 * @subpackage Translations Functions
6 * @category Functions
7 *
8 * @author wpdevelop
9 * @link https://wpbookingcalendar.com/
10 * @email [email protected]
11 *
12 * @modified 29.09.2015
13 */
14
15 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
16
17
18
19
20
21
22 /**
23 * Rechecking about the locale on this hook:
24 * add_action( 'plugins_loaded', 'wpbc_load_translation', 1000 );
25 * which is executed early then
26 * add_action( 'admin_init', 'wpbc_check_...' );
27 */
28 add_action( 'plugins_loaded', 'wpbc_load_translation', 1000 ); // Load translation
29
30
31 /**
32 * Load translation - Load country list after locale defined by some other translation plugin.
33 */
34 function wpbc_load_translation(){
35
36 //define( 'WPBC_LOCALE_RELOAD', 'fr_FR' ); wpbc_load_plugin_translation_file__mo( WPBC_LOCALE_RELOAD );
37
38
39 // Get reloaded 'booking' or current WordPress locale
40 $locale = wpbc_get_maybe_reloaded_booking_locale(); // if NOT defined WPBC_LOCALE_RELOAD define by current WordPress locale
41
42 // FixIn: 8.9.4.5.
43 if ( is_admin() && ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) {
44 //Reload locale for Ajax request
45 wpbc_check_ajax_locale__reload_it( $locale ); //
46 }
47
48 wpbc_load_country_list_file_php( $locale );
49
50 if ( ! wpbc_load_plugin_translation_file__mo( $locale ) ) {
51 wpbc_load_plugin_translation_file__mo( 'en_US' ); // Load default English translation, if other not available
52 }
53 }
54
55
56 /**
57 * Check ( $_REQUEST['wpdev_active_locale'] ) and Reload specific Locale for the Ajax request
58 */
59 function wpbc_check_ajax_locale__reload_it( $reloaded_locale ) { // FixIn: 8.4.5.1.
60
61 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
62 if ( ( isset( $_REQUEST['wpdev_active_locale'] ) ) || ( isset( $_REQUEST['wpbc_ajx_locale'] ) ) ) { // Reload locale according request parameter.
63
64 unload_textdomain( 'booking' );
65
66 /*
67 * Removed because, it's configured in $locale = wpbc_get_maybe_reloaded_booking_locale(); which is executed before this action
68 *
69 if ( ! defined( 'WPBC_LOCALE_RELOAD' ) ) { // $
70 define( 'WPBC_LOCALE_RELOAD', ( $_REQUEST['wpdev_active_locale'] ) );
71 }
72 */
73 add_filter( 'locale', 'wpbc_get_maybe_reloaded_booking_locale', 999 ); // Set filter to load the locale of the Booking Calendar
74
75 /**
76 * It's commented because inside of the function load_default_textdomain(); exist: unload_textdomain( 'default' ); which is unset( $l10n[ 'default' ] );
77 *
78 // Reload locale settings, it's required for the correct dates format
79 //if ( isset( $l10n['default'] ) ) { unset( $l10n['default'] ); } // Unload locale
80 */
81 load_default_textdomain(); // Load default locale
82
83 global $wp_locale;
84 $wp_locale = new WP_Locale(); // Reload class
85
86 wpbc_load_plugin_translation_file__mo( $reloaded_locale );
87
88
89 $current_locale = wpbc_get_current_wordpress_locale(); // 'en_US' or 'it_IT', etc...
90
91 if ( $current_locale != $reloaded_locale ) {
92
93 // The switch_to_locale() function is loaded before it can actually be used.
94 if ( function_exists( 'switch_to_locale' ) && isset( $GLOBALS['wp_locale_switcher'] ) ) {
95 $switched_locale = switch_to_locale( $reloaded_locale );
96 } else {
97 load_default_textdomain( $reloaded_locale );
98 }
99 }
100
101 }
102 }
103
104
105 /**
106 * Load MO translation file of plugin, like ../wp-content/plugins/booking/languages/booking-fr_FR.mo
107 *
108 * System firstly try to load MO from dir: ../wp-content/plugins/booking/languages
109 * then from: ../wp-content/languages/plugins/'
110 * otherwise: unload 'booking' textdomain
111 *
112 * @param string $locale default ''
113 *
114 * can be passed like: 'en_US' or 'it_IT'
115 *
116 * if '' then get WPBC_LOCALE_RELOAD locale,
117 * or if not reloaded then get current WordPress locale
118 * and define WPBC_LOCALE_RELOAD
119 *
120 * @return bool
121 */
122 function wpbc_load_plugin_translation_file__mo( $locale = '' ) {
123
124 $is_mo_loaded = false;
125 $domain = 'booking';
126
127 if ( empty( $locale ) ) {
128 $locale = wpbc_get_maybe_reloaded_booking_locale();
129 }
130
131
132 if ( ! empty( $locale ) ) {
133
134 $mofile_in_plugin_folder = WPBC_PLUGIN_DIR . '/languages/' . $domain . '-' . $locale . '.mo';
135
136 // we have long locale like en_US, get only 2 first letters, for general locale, like 'en'
137 $mofile_local_short = WPBC_PLUGIN_DIR . '/languages/' . $domain . '-' . substr( $locale, 0 , 2 ) . '.mo';
138
139 // Load from General folder /wp-content/languages/plugins/plugin-name-xx_XX.mo
140 $mofile_in_wp_folder = WP_LANG_DIR . '/plugins/' . $domain . '-' . $locale . '.mo'; //FixIn: 8.9.4.6 Fix '/languages/plugin/' to '/languages/plugins/ // FixIn: 8.7.7.1.
141
142
143 /**
144 * Try to load from the languages' directory first -> WP_LANG_DIR . '/plugins/' . $mofile
145 * If not possible, then from -> WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' )
146 *
147 */
148 $is_load_from_wp_repository = get_bk_option( 'booking_translation_load_from' );
149 if ( ( empty( $is_load_from_wp_repository ) ) || ( 'wp.org' == $is_load_from_wp_repository ) ) {
150
151 /**
152 * This function 'load_plugin_textdomain' load firstly from the '/wp-content/languages/plugins/' directory
153 *
154 * load_plugin_textdomain( $domain, false, WPBC_PLUGIN_DIRNAME . '/languages' )
155 *
156 * --> ../wp-content/languages/plugins/booking-fr_FR.mo !!!!
157 *
158 * In case if need to load directly, then use:
159 *
160 * load_textdomain( $domain, WPBC_PLUGIN_DIR . '/languages/' . $domain . '-' . $locale . '.mo' );
161 */
162
163 $plugin_rel_path = WPBC_PLUGIN_DIRNAME . '/languages';
164 // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound
165 $is_mo_loaded = load_plugin_textdomain( $domain, false, $plugin_rel_path );
166 }
167
168
169 if ( ! $is_mo_loaded ) {
170
171 if ( file_exists( $mofile_in_plugin_folder ) ) {
172
173 /**
174 * Direct load from ../wp-content/plugins/booking/languages/booking-fr_FR.mo
175 */
176
177 $is_mo_loaded = load_textdomain( $domain, $mofile_in_plugin_folder ); // FixIn: 8.9.4.5.
178
179 } elseif ( ( ! empty( $mofile_local_short ) ) && ( file_exists( $mofile_local_short ) ) ) { // FixIn: 8.1.3.13.
180
181 /**
182 * Direct load of short " booking-en.mo " MO file
183 */
184
185 $is_mo_loaded = load_textdomain( $domain, $mofile_local_short );
186
187 } elseif ( file_exists( $mofile_in_wp_folder ) ) { // FixIn: 8.9.4.6.
188
189 /**
190 * Here possible to use
191 * return load_plugin_textdomain( $domain, false, $plugin_rel_path );
192 *
193 * which firstly try to load from the language directory: ../wp-content/languages/plugins/booking-fr_FR.mo !!!!
194 *
195 * like this: load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile )
196 * and only after this try uses this: load_textdomain( $domain, WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' ) . '/' . $mofile );
197 *
198 * so that's why we are using direct loadinf: load_textdomain( $domain, $mofile_in_wp_folder ) ../wp-content/languages/plugin/booking-fr_FR.mo
199 */
200
201 $is_mo_loaded = load_textdomain( $domain, $mofile_in_wp_folder );
202 } else { // FixIn: 7.2.1.21.
203
204 $is_unloaded = unload_textdomain( $domain );
205 }
206 }
207 }
208
209 return $is_mo_loaded;
210 }
211
212
213 /**
214 * Load Country List file depends on plugin 'booking' locale
215 *
216 * @string $locale '' || 'en_US' || 'it_IT'
217 */
218 function wpbc_load_country_list_file_php( $locale ){ // FixIn: 8.8.2.5.
219
220 require_once WPBC_PLUGIN_DIR . '/core/lang/wpdev-country-list.php';
221
222 do_action( 'wpbc_country_list_loaded' ); // FixIn: 8.9.4.9.
223 }
224
225
226 /**
227 * Validate a locale received from a request.
228 *
229 * Locale values are used request-wide and can later be rendered inside JavaScript and HTML attributes. Accept only
230 * ASCII locale identifiers, such as "en", "en_US", "de_DE_formal", or "en-US". Invalid values must be rejected
231 * instead of sanitized into a different value. // FixIn: 11.4.3.2.
232 *
233 * @param mixed $locale Locale value from the request.
234 *
235 * @return string|false Valid locale, or false when the value is invalid.
236 */
237 function wpbc_validate_request_locale( $locale ) {
238
239 if ( ! is_string( $locale ) ) {
240 return false;
241 }
242
243 $locale = wp_unslash( $locale );
244
245 if (
246 ( '' === $locale )
247 || ( strlen( $locale ) > 32 )
248 || ( 1 !== preg_match( '/\A[A-Za-z0-9]+(?:[_-][A-Za-z0-9]+)*\z/D', $locale ) )
249 ) {
250 return false;
251 }
252
253 return $locale;
254 }
255
256
257 /**
258 * Get maybe reloaded 'booking' locale ( WPBC_LOCALE_RELOAD ) and if not defined WPBC_LOCALE_RELOAD define it.
259 *
260 * @return string
261 */
262 function wpbc_get_maybe_reloaded_booking_locale() {
263
264 if ( ( is_admin() && ( defined( 'DOING_AJAX' ) ) && ( DOING_AJAX ) ) ) {
265 $is_ajax = true;
266 } else {
267 $is_ajax = false;
268 }
269
270
271 /**
272 * Check active locale in some other translation plugins, like Polylang (NOT in Ajax), etc...
273 */
274 if ( ! $is_ajax ) { // FixIn: 8.9.4.7.
275
276 // Exception for Polylang plugin. It will force loading locale of Polylang plugin.
277 if ( function_exists( 'pll_current_language' ) ) { // FixIn: 8.1.2.5.
278 if ( defined( 'POLYLANG_VERSION' ) ) { // FixIn: 8.8.3.16.
279 if (
280 ( version_compare( POLYLANG_VERSION, '2.6.5', '<' ) ) // FixIn: 8.7.1.3.
281 || ( version_compare( POLYLANG_VERSION, '2.7.1', '>' ) ) // FixIn: 8.7.7.11.
282 ) {
283 $locale = pll_current_language( 'locale' );
284 if ( ! empty( $locale ) ) { // FixIn: 8.7.7.11.
285 return $locale;
286 }
287 }
288 }
289 }
290 }
291
292 $wpbc_ajx_locale = false;
293 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
294 if ( isset( $_REQUEST['wpdev_active_locale'] ) ) {
295 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
296 $wpbc_ajx_locale = wpbc_validate_request_locale( $_REQUEST['wpdev_active_locale'] );
297 }
298 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
299 if ( isset( $_REQUEST['wpbc_ajx_locale'] ) ) {
300 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
301 $wpbc_ajx_locale = wpbc_validate_request_locale( $_REQUEST['wpbc_ajx_locale'] );
302 }
303
304 // Reload locale ONLY in AJAX, and if `isset $_REQUEST['wpdev_active_locale']
305 if (
306 ( ! defined( 'WPBC_LOCALE_RELOAD' ) )
307 && ( ! empty( $wpbc_ajx_locale ) )
308 ){
309 if (
310 ( $is_ajax )
311 || (
312 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
313 ( isset( $_REQUEST['wpbc_ajx_locale_reload'] ) ) && ( 'force' == $_REQUEST['wpbc_ajx_locale_reload'] )
314 )
315 ) { // Reload locale according request parameter
316 define( 'WPBC_LOCALE_RELOAD', $wpbc_ajx_locale );
317 }
318 }
319
320
321
322 // If not defined than get current WordPress locale and define
323 if ( ! defined( 'WPBC_LOCALE_RELOAD' ) ) { // FixIn: 7.2.1.21.
324
325 $locale = wpbc_get_current_wordpress_locale(); // 'en_US' or 'it_IT', etc...
326
327 define( 'WPBC_LOCALE_RELOAD', $locale );
328 }
329
330 return WPBC_LOCALE_RELOAD;
331 }
332
333
334 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
335 /// Support
336 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
337
338 /**
339 * Get current WordPress locale, it is not relative to the Booking Calendar
340 *
341 * @return string 'en_US'
342 */
343 function wpbc_get_current_wordpress_locale(){
344
345 if ( function_exists( 'determine_locale' ) ) { //FixIn: 8.7.5.1 // FixIn: 8.7.3.15.
346 $current_locale = determine_locale();
347 } else {
348 if ( function_exists( 'get_user_locale' ) ) {
349 $current_locale = is_admin() ? get_user_locale() : get_locale();
350 } else {
351 $current_locale = get_locale();
352 }
353 }
354
355 return $current_locale; // 'en_US'
356 }
357
358
359 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
360 /// Filters for Locale of Booking Calendar
361 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
362
363 /**
364 * Check locale of plugin, and if previously were defined WPBC_LOCALE_RELOAD, then return our WPBC_LOCALE_RELOAD locale
365 *
366 * @param $locale 'en_US'
367 * @param string $plugin_domain 'booking' - it's Booking Calendar plugin locale
368 *
369 * @return mixed|string 'it_IT'
370 */
371 function wpbc_filter_recheck_plugin_locale( $locale, $plugin_domain = '' ) { // FixIn: 8.4.4.2.
372
373 if (
374 ( 'booking' == $plugin_domain )
375 && ( defined( 'WPBC_LOCALE_RELOAD' ) )
376 ) {
377 return WPBC_LOCALE_RELOAD;
378 }
379
380 return $locale;
381 }
382 add_filter( 'plugin_locale', 'wpbc_filter_recheck_plugin_locale', 100, 2 ); // When load_plugin_textdomain() is run, its get default locale and not that, we reupdate - WPBC_LOCALE_RELOAD
383
384
385
386 /**
387 * Overload loading of plugin translation files from "wp-content/languages/plugins" -> "wp-content/plugins/plugin_name/languages"
388 *
389 * W:\home\beta\www/wp-content/languages/plugins/booking-it_IT.mo -> W:\home\beta\www\wp-content\plugins\booking/languages/booking-it_IT.mo
390 *
391 * @param string $mofile
392 * @param type $domain
393 * @return string
394 */
395 function wpbc_filter_load_custom_plugin_translation_file( $mofile, $domain ) {
396
397 if ( $domain == 'booking' ) {
398 $mofile = WPBC_PLUGIN_DIR . '/languages/' . basename( $mofile );
399 }
400 return $mofile;
401 }
402 //add_filter( 'load_textdomain_mofile', 'wpbc_filter_load_custom_plugin_translation_file' , 10, 2 );
403
404
405
406 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
407 /// Support functions for [lang=xx_XX] shortcode
408 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
409
410 /**
411 * Translate content. Check for language sections -- [lang=xx_XX] shortcode. // FixIn: 10.0.0.46.
412 *
413 * @param mixed $content_orig Content containing optional language sections.
414 *
415 * @return string Translated content, or an empty string for unsupported values.
416 */
417 function wpbc_lang( $content_orig ) {
418 return wpdev_check_for_active_language( $content_orig );
419 }
420
421
422 /**
423 * Check plugin text for active language section -- [lang=xx_XX] shortcode
424 *
425 * @param mixed $content_orig Content containing optional language sections.
426 * @return string Translated content, or an empty string for unsupported values.
427 * Usage:
428 * $text = wpbc_lang( $text );
429 */
430 function wpdev_check_for_active_language( $content_orig ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
431
432 if ( is_string( $content_orig ) ) {
433 $content = $content_orig;
434 } elseif ( is_scalar( $content_orig ) ) {
435 $content = (string) $content_orig;
436 } elseif ( is_object( $content_orig ) && method_exists( $content_orig, '__toString' ) ) {
437 $content = (string) $content_orig;
438 } else {
439 return '';
440 }
441
442 $languages = array();
443 $content_ex = explode( '[lang', $content );
444
445 foreach ( $content_ex as $value ) {
446
447 if ( '=' === substr( $value, 0, 1 ) ) {
448
449 $pos_s = strpos( $value, '=' );
450 $pos_f = strpos( $value, ']' );
451 $key = trim( substr( $value, ( $pos_s + 1 ), ( $pos_f - $pos_s - 1 ) ) );
452 $value_l = trim( substr( $value, $pos_f + 1 ) );
453 $languages[ $key ] = $value_l;
454
455 } else {
456 $languages['default'] = $value;
457 }
458 }
459
460 $locale = wpbc_get_maybe_reloaded_booking_locale(); // $locale = 'fr_FR'.
461
462 if ( isset( $languages[ $locale ] ) ) {
463 $return_text = $languages[ $locale ];
464 } else {
465 $return_text = $languages['default'];
466 }
467
468 $return_text = wpbc_bk_check_qtranslate( $return_text, $locale );
469 $return_text = wpbc_check_wpml_tags( $return_text, $locale ); // FixIn: 5.4.5.8.
470
471 return $return_text;
472 }
473
474
475 /**
476 * Get help rows about configuration in_several languages with [lang=xx_XX] shortcode
477 *
478 * @return array - each item of array is text row for showing.
479 */
480 function wpbc_get_help_rows_about_config_in_several_languges() {
481
482 $field_options = array();
483 $field_options[] = '<strong>' . esc_html__('Configuration in several languages' ,'booking') . '</strong>';
484 /* translators: 1: ... */
485 $field_options[] = sprintf( __( '%1$s - start new translation section, where %2$s - locale of translation', 'booking' ),'<code>[lang=LOCALE]</code>','<code>LOCALE</code>');
486 /* translators: 1: ... */
487 $field_options[] = sprintf(__( 'Example #1: %s - start French translation section' ,'booking'),'<code>[lang=fr_FR]</code>');
488 /* translators: 1: ... */
489 $field_options[] = sprintf(__( 'Example #2: "%s" - English and French translation of some message' ,'booking'),'<code>Thank you for your booking.[lang=fr_FR]Je vous remercie de votre reservation.</code>');
490
491 return $field_options;
492 }
493
494
495 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
496 /// Support functions for Other Translation Plugins like WPML, qTranslate, etc...
497 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
498
499 /**
500 * Support function for WPML plugin
501 * Register and Translate everything in [wpml]Some Text to translate[/wpml] tags.
502 *
503 * @param string $text
504 * @param string $locale
505 *
506 * @return string
507 */
508 function wpbc_check_wpml_tags( $text, $locale='' ) { // FixIn: 5.4.5.8.
509
510 if ( $locale == '' ) {
511 $locale = wpbc_get_maybe_reloaded_booking_locale();
512 }
513 if ( strlen( $locale ) > 2 ) {
514 $locale = substr($locale, 0, 2 );
515 }
516
517 $is_tranlsation_exist_s = strpos( $text, '[wpml]' );
518 $is_tranlsation_exist_f = strpos( $text, '[/wpml]' );
519
520 if ( ( $is_tranlsation_exist_s !== false ) && ( $is_tranlsation_exist_f !== false ) ) {
521
522 $shortcode = 'wpml';
523
524 // Find anything between [wpml] and [/wpml] shortcodes. Magic here: [\s\S]*? - fit to any text
525 preg_match_all( '/\[' . $shortcode . '\]([\s\S]*?)\[\/' . $shortcode . '\]/i', $text, $wpml_translations, PREG_SET_ORDER );
526 //debuge( $wpml_translations );
527
528 foreach ( $wpml_translations as $translation ) {
529 $text_to_replace = $translation[0];
530 $translation_to_check = $translation[1];
531
532 if ( function_exists ( 'icl_register_string' ) ){
533
534 if ( false ) { // Depricated functions
535
536 // Help: https://wpml.org/documentation/support/translation-for-texts-by-other-plugins-and-themes/
537 icl_register_string('Booking Calendar', 'wpbc-' . tag_escape( $translation_to_check ) , $translation_to_check );
538
539 //TODO: Need to execurte this after deactivation of plugin or after updating of some option...
540 //icl_unregister_string ( 'Booking Calendar', 'wpbc-' . tag_escape( $translation_to_check ) );
541
542 if ( function_exists ( 'icl_translate' ) ){
543 $translation_to_check = icl_translate ( 'Booking Calendar', 'wpbc-' . tag_escape( $translation_to_check ) , $translation_to_check );
544 }
545
546 } else { // WPML Version: 3.2
547
548 // Help info: do_action( 'wpml_register_single_string', string $context, string $name, string $value )
549 // https://wpml.org/wpml-hook/wpml_register_string_for_translation/
550 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
551 do_action( 'wpml_register_single_string', 'Booking Calendar', 'wpbc-' . tag_escape( $translation_to_check ) , $translation_to_check );
552
553
554 // Help info: apply_filters( 'wpml_translate_single_string', string $original_value, string $context, string $name, string $$language_code )
555 // https://wpml.org/wpml-hook/wpml_translate_single_string/
556 //$translation_to_check = apply_filters( 'wpml_translate_single_string', $translation_to_check, 'Booking Calendar', 'wpbc-' . tag_escape( $translation_to_check ) );
557 $language_code = $locale;
558 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
559 $translation_to_check = apply_filters( 'wpml_translate_single_string', $translation_to_check, 'Booking Calendar', 'wpbc-' . tag_escape( $translation_to_check ), $language_code );
560
561 }
562 }
563 $text = str_replace( $text_to_replace, $translation_to_check, $text );
564 }
565 }
566
567 return $text;
568 }
569
570
571 /**
572 * Support function for qTranslate plugin
573 *
574 * @param $text
575 * @param string $locale
576 *
577 * @return false|mixed|string
578 */
579 function wpbc_bk_check_qtranslate( $text, $locale='' ){
580
581 if ($locale == '') {
582 $locale = wpbc_get_maybe_reloaded_booking_locale();
583 }
584 if (strlen($locale)>2) {
585 $locale = substr($locale, 0 ,2);
586 }
587
588 $is_tranlsation_exist = strpos($text, '<!--:'.$locale.'-->');
589
590 if ($is_tranlsation_exist !== false) {
591 $tranlsation_end = strpos($text, '<!--:-->', $is_tranlsation_exist);
592
593 $text = substr($text, $is_tranlsation_exist , ($tranlsation_end - $is_tranlsation_exist ) );
594 }
595
596 return $text;
597 }
598
599
600
601 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
602 // Translation Settings
603 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
604
605 /**
606 * Show translation buttons at Booking > Settings General page
607 */
608 function wpbc_translation_buttons_settings_section(){
609
610 if ( ( ! wpbc_is_this_demo() ) && ( current_user_can( 'activate_plugins' ) ) ){
611
612 ?><div class="wpbc_booking_system_info_buttons_align"><?php
613
614 echo
615 '<a class="button button tooltip_top"
616 data-original-title="'
617 /* translators: 1: ... */
618 . esc_attr( sprintf( __( 'Download translation PO files from %s and update the current translation version.', 'booking' ), 'wp.org / wpbookingcalendar.com' ) )
619 . '" href="'
620 . esc_url( wpbc_get_settings_url()
621 . '&system_info=show&_wpnonce='. wp_create_nonce( 'wpbc_settings_url_nonce' ) ) .'&update_translations=1#wpbc_general_settings_system_info_metabox">'
622 . esc_html__( 'Update Translations', 'booking' )
623 . '</a>';
624
625 echo '<a class="button button tooltip_top"
626 data-original-title="' . esc_attr( __( 'Show exist translations status', 'booking' ) ) . '"
627 href="' . esc_url( wpbc_get_settings_url() . '&system_info=show&_wpnonce=' . wp_create_nonce( 'wpbc_settings_url_nonce' ) ) . '&show_translation_status=1#wpbc_general_settings_system_info_metabox">' .
628 esc_html( __( 'Show translations status', 'booking' ) ) . '</a>';
629
630
631 if ( ( isset( $_SERVER['HTTP_HOST'] ) ) && ( 'beta' === $_SERVER['HTTP_HOST'] ) ) {
632
633 ?><div style="width:100%;height:2em;border-bottom:1px dashed #777;margin-bottom:1em;"></div><?php
634
635 // Link: http://server.com/wp-admin/admin.php?page=wpbc-settings&system_info=show&pot=1#wpbc_general_settings_system_info_metabox
636 echo
637 '<a class="button button-secondary tooltip_top"
638 data-original-title="Delete wpbc_all_translations(*).php files, before Updating POT file (manually)"
639 style="background:#fff9e6;" href="'
640 . esc_url( wpbc_get_settings_url()
641 . '&system_info=show&_wpnonce='. wp_create_nonce( 'wpbc_settings_url_nonce' ) ) .'&pot=erase__wpbc_all_translations#wpbc_general_settings_system_info_metabox">'
642 . '1. Erase Translation PHP files'
643 . '</a>';
644 echo
645 '<a class="button button-secondary tooltip_top"
646 data-original-title="Create or update wpbc_all_translations(*).php files, from actual POT file"
647 style="background:#fff9e6;"
648 href="'
649 . esc_url( wpbc_get_settings_url()
650 . '&system_info=show&_wpnonce='. wp_create_nonce( 'wpbc_settings_url_nonce' ) ) .'&pot=1#wpbc_general_settings_system_info_metabox">'
651 . '2. Generate Translation PHP from POT file'
652 . '</a>';
653
654 echo
655 '<a class="button button-secondary tooltip_top"
656 data-original-title="Just show WP.ORG translation status from ' . esc_attr( WP_LANG_DIR ) . '/plugins/' . ' "
657 style="background:#fff9e6;"
658 href="'
659 . esc_url( wpbc_get_settings_url()
660 . '&system_info=show&_wpnonce='. wp_create_nonce( 'wpbc_settings_url_nonce' ) ) .'&show_translation_status=2#wpbc_general_settings_system_info_metabox">'
661 . 'Translation status WP.ORG'
662 . '</a>';
663
664
665 echo
666 '<a class="button button-secondary tooltip_top"
667 data-original-title="Just show LOCAL translation status from ' . esc_attr( WPBC_PLUGIN_DIR ) . '/languages/' . ' "
668 style="background:#fff9e6;"
669 href="'
670 . esc_url( wpbc_get_settings_url()
671 . '&system_info=show&_wpnonce='. wp_create_nonce( 'wpbc_settings_url_nonce' ) ) .'&show_translation_status=3#wpbc_general_settings_system_info_metabox">'
672 . 'Translation status WPBC'
673 . '</a>';
674 }
675
676 ?></div><?php
677
678 }
679 }
680
681
682 // ======================================================================================================================
683 // Update Translations -- DOWNLOAD from WP.ORG and WPBC
684 // ======================================================================================================================
685
686
687 /**
688 * Update transaltions of plugin from WP repository
689 */
690 function wpbc_update_translations__from_wp() {
691
692 echo '<h2>' . esc_html__( 'Start updating translation files', 'booking' ) . '</h2>';
693 WPBC_Action_Scheduler_Compatibility::raise_memory_limit();
694 WPBC_Action_Scheduler_Compatibility::raise_time_limit( 300 );
695
696 $wpbc_download_result = false;
697 if ( 'translations_updated_from_wpbc' !== get_bk_option( 'booking_translation_update_status' ) ) {
698 $wpbc_download_result = wpbc_translation_download_from_wpbc();
699 }
700 if ( ( ! is_wp_error( $wpbc_download_result ) ) && ( false !== $wpbc_download_result ) ) {
701 update_bk_option( 'booking_translation_update_status', 'translations_updated_from_wpbc' );
702 }
703
704 $wp_org_translation_packages_arr = wpbc_get_translation_packages_arr_from_wp();
705 /**
706 * ..., array ( [language] => sk_SK
707 * [version] => 8.9.3
708 * [updated] => 2020-03-11 17:10:35
709 * [english_name] => Slovak
710 * [native_name] => Slovenčina
711 * [package] => https://downloads.wordpress.org/translation/plugin/booking/8.9.3/sk_SK.zip
712 * [iso] => Array ( [1] => sk, [2] => slk )
713 * ),
714 * ...
715 */
716
717 $download_result_arr = wpbc_transaltion_download_from_wp_org( $wp_org_translation_packages_arr );
718
719 echo '<h2>' . esc_html__( 'End updating translation files', 'booking' ) . '</h2>';
720 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
721
722 update_bk_option( 'booking_translation_update_status', 'translations_updated_from_wpbc_and_wp' );
723 }
724
725
726 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
727 /// Support functions for Update Translations
728 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
729
730 /**
731 * Update translation option, just after activation of plugin.
732 * It must be 0
733 */
734 function wpbc_update_translation_status_after_plugin_activation(){
735 update_bk_option( 'booking_translation_update_status', '0' );
736 }
737 add_bk_action( 'wpbc_other_versions_activation', 'wpbc_update_translation_status_after_plugin_activation' );
738
739
740 /**
741 * Download translations from wordpress.org, unpack it to the ../WP_LANG_DIR/plugins folder
742 *
743 * @param $wp_org_translation_packages_arr array of translations data from wp.org
744 * - required one option - $translation_package['package']
745 * - it's URL to zip archive of specific translation
746 *
747 * @return array or results
748 */
749 function wpbc_transaltion_download_from_wp_org( $wp_org_translation_packages_arr ){
750
751 $my_upgrader = wpbc_get_translation_upgrader_obj();
752
753 $result = array();
754
755 foreach ( $wp_org_translation_packages_arr as $translation_package ) {
756
757 $result[] = $my_upgrader->run( array(
758 'package' => $translation_package['package'], // Please always pass this.
759 'destination' => WP_LANG_DIR . '/plugins/', // WPBC_PLUGIN_DIR . '/lang/wp_org/', // ...and this.
760 'clear_destination' => false,
761 'abort_if_destination_exists' => false, // Abort if the destination directory exists. Pass clear_destination as false please.
762 'clear_working' => true,
763 'is_multi' => true,
764 'hook_extra' => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
765 ) );
766 }
767
768 return $result;
769 }
770
771
772 /**
773 * Download translations from wpbookingcalendar.com, unpack it to the ../WPBC_PLUGIN_DIR/languages/' folder
774 *
775 * @param WP_Upgrader_Skin|null $skin Optional authorized upgrader skin.
776 *
777 * @return array|bool|string|WP_Error - result
778 */
779 function wpbc_translation_download_from_wpbc( $skin = null ){
780
781 $my_upgrader = wpbc_get_translation_upgrader_obj( $skin );
782
783 $result = $my_upgrader->run( array(
784 'package' => 'https://wpbookingcalendar.com/download/languages/languages.zip', // Please always pass this.
785 'destination' => WPBC_PLUGIN_DIR . '/languages/', // WPBC_PLUGIN_DIR . '/lang/', // ...and this.
786 'clear_destination' => false,
787 'abort_if_destination_exists' => false, // Abort if the destination directory exists. Pass clear_destination as false please.
788 'clear_working' => true,
789 'is_multi' => false,
790 'hook_extra' => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
791 ) );
792
793 return $result;
794 }
795
796
797 /**
798 * Get translation Upgrader object
799 *
800 * @param WP_Upgrader_Skin|null $skin Optional authorized upgrader skin.
801 *
802 * @return WP_Upgrader obj
803 */
804 function wpbc_get_translation_upgrader_obj( $skin = null ){
805
806 require_once ABSPATH . 'wp-admin/includes/file.php';
807 require_once ABSPATH . 'wp-admin/includes/plugin.php';
808 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
809 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
810
811 require_once WPBC_PLUGIN_DIR . '/core/class/wpbc-class-upgrader-translation-skin.php';
812 if ( ! ( $skin instanceof WP_Upgrader_Skin ) ) {
813 $skin = new WPBC_Upgrader_Translation_Skin(
814 array( 'skip_header_footer' => true )
815 );
816 }
817
818 $my_upgrader = new WP_Upgrader( $skin );
819
820 $my_upgrader->init(); // it's required for defining skin messages
821
822 return $my_upgrader;
823 }
824
825
826 /**
827 * Get array of translation packages from WordPress.org
828 *
829 * @return array Array ( [0] => Array (
830 [language] => bg_BG
831 [version] => 8.9.3
832 [updated] => 2018-03-13 19:55:57
833 [english_name] => Bulgarian
834 [native_name] => Български
835 [package] => https://downloads.wordpress.org/translation/plugin/booking/8.9.3/bg_BG.zip
836 [iso] => Array ( [1] => bg, [2] => bul )
837 )
838 [1] ....
839 */
840 function wpbc_get_translation_packages_arr_from_wp(){
841
842 $translations_arr = array();
843
844 if ( ! is_admin() ) {
845 return $translations_arr;
846 }
847
848 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
849
850 $api = translations_api( 'plugins', array(
851 'slug' => 'booking',
852 'version' => WP_BK_VERSION_NUM, //'8.9.3',
853 ) );
854
855 if ( ( is_wp_error( $api ) ) || ( empty( $api['translations'] ) ) ) {
856 return $translations_arr;
857 } else {
858 $translations_arr = $api['translations'];
859 }
860
861 return $translations_arr;
862 }
863
864
865
866 //======================================================================================================================
867 // Get STATUS of translations in this website
868 //======================================================================================================================
869
870
871 function wpbc_show_translation_status_compare_wpbc_wp( ) {
872
873 WPBC_Action_Scheduler_Compatibility::raise_memory_limit();
874 WPBC_Action_Scheduler_Compatibility::raise_time_limit( 300 );
875
876 $params = array(
877 'sort_field_name' => 'locale'
878 , 'sort_order' => SORT_ASC
879 , 'sort_type' => SORT_STRING
880 );
881 $params['wp_available_languages'] = wpbc_get_available_language_locales_from_wp_org_api();
882
883 $current_locale = wpbc_get_maybe_reloaded_booking_locale(); // if NOT defined WPBC_LOCALE_RELOAD define by current WordPress locale
884
885 $is_echo = false;
886
887 $from_wp = wpbc_show_translation_status_from_wp( $is_echo, $params );
888 $from_wpbc = wpbc_show_translation_status_from_wpbc( $is_echo, $params );
889
890 $total_translations = 0;
891
892 $compared_translations = array();
893 // WPBC
894 foreach ( $from_wpbc as $po_translation ) {
895 $compared_translations[ $po_translation['locale'] ] = array(
896 'filename' => $po_translation['filename']
897 , 'locale' => $po_translation['locale']
898 , 'english_name' => $po_translation['english_name']
899 , 'total_wpbc' => $po_translation['total']
900 , 'error_wpbc' => $po_translation['error']
901 , 'percent_wpbc' => $po_translation['percent']
902 , 'done_wpbc' => $po_translation['done']
903 , 'untranslated_wpbc' => $po_translation['untranslated']
904 , 'fuzzy_wpbc' => $po_translation['fuzzy']
905
906 , 'total_wp' => 0
907 , 'error_wp' => 0
908 , 'percent_wp' => 0
909 , 'done_wp' => 0
910 , 'untranslated_wp' => 0
911 , 'fuzzy_wp' => 0
912 );
913 if ( $po_translation['total'] > $total_translations ) {
914 $total_translations = $po_translation['total'];
915 }
916 }
917
918
919 // WP_LANG_DIR
920 foreach ( $from_wp as $po_translation ) {
921
922 if ( isset( $compared_translations[ $po_translation['locale'] ] ) ) {
923 $default = $compared_translations[ $po_translation['locale'] ];
924 } else {
925 $default = array(
926 'total_wpbc' => 0
927 , 'error_wpbc' => 0
928 , 'percent_wpbc' => 0
929 , 'done_wpbc' => 0
930 , 'untranslated_wpbc' => 0
931 , 'fuzzy_wpbc' => 0
932 );
933 }
934
935 $compared_translations[ $po_translation['locale'] ] = wp_parse_args(
936 array(
937 'filename' => $po_translation['filename']
938 , 'locale' => $po_translation['locale']
939 , 'english_name' => $po_translation['english_name']
940 , 'total_wp' => $po_translation['total']
941 , 'error_wp' => $po_translation['error']
942 , 'percent_wp' => $po_translation['percent']
943 , 'done_wp' => $po_translation['done']
944 , 'untranslated_wp' => $po_translation['untranslated']
945 , 'fuzzy_wp' => $po_translation['fuzzy']
946 ),
947 $default
948 );
949 if ( $po_translation['total'] > $total_translations ) {
950 $total_translations = $po_translation['total'];
951 }
952 }
953
954 $new_compared_translations = array();
955 $current_active_translation = false;
956 foreach ( $compared_translations as $locale => $compared_translation ) {
957
958 $compared_translation['total'] = $total_translations;//( ( $compared_translation['total_wp'] > $compared_translation['total_wpbc'] ) ? $compared_translation['total_wp'] : $compared_translation['total_wpbc'] );
959
960 $compared_translation['done'] = ( ( $compared_translation['done_wp'] > $compared_translation['done_wpbc'] ) ? $compared_translation['done_wp'] : $compared_translation['done_wpbc'] );
961
962 $compared_translation['percent'] = round( ( $compared_translation['done'] * 100 ) / $compared_translation['total'], 2 );
963
964
965 $new_compared_translations[] = $compared_translation;
966 if ( $current_locale == $compared_translation['locale'] ) {
967 $current_active_translation = array();
968 $current_active_translation[] = $compared_translation;
969 }
970 }
971
972
973 //////////////////////////////////////////////////////////////////////////////////
974 // Sort translation array
975 //////////////////////////////////////////////////////////////////////////////////
976 $volume = array_column( $new_compared_translations, 'done' ); // default $params['sort_field_name'] = 'percent'
977 array_multisort( $volume, SORT_DESC, SORT_NUMERIC, $new_compared_translations );
978
979
980 //debuge( $new_compared_translations );
981
982 if ( ! empty( $current_active_translation ) ) {
983 $new_compared_translations = array_merge( $current_active_translation, $new_compared_translations );
984 }
985 $translation_message = '';
986 $is_already_shown_current_lang = false;
987 foreach ( $new_compared_translations as $translation_status ) {
988
989 if ( ( ! empty( $current_active_translation ) ) && ( $current_locale == $translation_status['locale'] ) && ($is_already_shown_current_lang)) {
990 continue;
991 }
992
993 $translation_message .= ( empty( $translation_status['english_name'] ) ? $translation_status['locale'] : $translation_status['english_name'] )
994 . " [{$translation_status['locale']}] "
995 . " better to use ". ( ( $translation_status['done_wpbc'] > $translation_status['done_wp'] ) ? "local" : "wordpress.org" ) . " translation"
996 . '<br/>'
997 . " Total translations: <strong>{$translation_status['percent']}%</strong> [ <strong>{$translation_status['done']}</strong> / {$translation_status['total']} ]"
998 . '<br/>'
999 . "Local translation. " //. esc_html( WPBC_PLUGIN_DIR . '/languages/' ) . " folder"
1000 . " Translated <strong>{$translation_status['done_wpbc']}</strong>"
1001 . ", fuzzy <strong>{$translation_status['fuzzy_wpbc']}</strong>"
1002 . ", not translated <strong>{$translation_status['untranslated_wpbc']}</strong>"
1003 . '<br/>'
1004 . "wordpress.org translation. " //. esc_html( WP_LANG_DIR . '/plugins/' ) . " folder"
1005 . " Translated <strong>{$translation_status['done_wp']}</strong>"
1006 . ", fuzzy <strong>{$translation_status['fuzzy_wp']}</strong>"
1007 . ", not translated <strong>{$translation_status['untranslated_wp']}</strong>"
1008 . '<hr/>';
1009
1010 if ( ( ! empty( $current_active_translation ) ) && ( $current_locale == $translation_status['locale'] ) ) {
1011 $is_already_shown_current_lang = true;
1012 }
1013 }
1014
1015 //////////////////////////////////////////////////////////////////////////////////
1016
1017 wpbc_show_message_in_settings( $translation_message, 'info' );
1018
1019 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1020 }
1021
1022 /**
1023 * Get or Show translation statuses from "WP_LANG_DIR" folder at Booking > Settings General page
1024 *
1025 * Link: http://server.com/wp-admin/admin.php?page=wpbc-settings&system_info=show&show_translation_status=1#wpbc_general_settings_system_info_metabox
1026 *
1027 * @param bool $is_echo
1028 * @param array $params array(
1029 'wp_available_languages' => array() - result of wpbc_get_available_language_locales_from_wp_org_api()
1030 , 'sort_field_name' => 'percent'
1031 , 'sort_order' => SORT_DESC
1032 , 'sort_type' => SORT_NUMERIC
1033 );
1034 *
1035 * @return array array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1036 error = false
1037 percent = {float} 98.11
1038 done = {int} 1870
1039 untranslated = {int} 16
1040 fuzzy = {int} 20
1041 english_name = "ro_RO"
1042 locale = "ro_RO"
1043 )
1044 , ...
1045 )
1046 */
1047 function wpbc_show_translation_status_from_wp( $is_echo = true, $params = array() ){
1048
1049 $defaults = array(
1050 'wp_available_languages' => array()
1051 , 'sort_field_name' => 'done'
1052 , 'sort_order' => SORT_DESC
1053 , 'sort_type' => SORT_NUMERIC
1054 );
1055 $params = wp_parse_args( $params, $defaults );
1056
1057
1058 if ( empty( $params['wp_available_languages'] ) ) {
1059 // Get available language locales from the WordPress.org API.
1060 $params['wp_available_languages'] = wpbc_get_available_language_locales_from_wp_org_api();
1061 }
1062
1063
1064 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1065 // Scan WP_LANG_DIR dir for PO files.
1066 if (1) {
1067 $plugin_translations_in_lang_dir = wp_get_installed_translations( 'plugins' );
1068
1069 $plugin_slug = 'booking';
1070
1071 if ( ! empty( $plugin_translations_in_lang_dir[ $plugin_slug ] ) ) {
1072 $plugin_translations_in_lang_dir = $plugin_translations_in_lang_dir[ $plugin_slug ];
1073 } else {
1074 $plugin_translations_in_lang_dir = array();
1075 }
1076
1077 $po_files_full_path_arr = array();
1078 foreach ( (array) $plugin_translations_in_lang_dir as $locale => $po_arr ) {
1079
1080 $po_files_full_path_arr[] = WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $locale . '.po';
1081 /**
1082 * array ( [0] => W:\w3\beta\www/wp-content/languages/plugins/booking-bg_BG.po
1083 * [1] => W:\w3\beta\www/wp-content/languages/plugins/booking-ca.po
1084 * ...
1085 * )
1086 */
1087 }
1088 }
1089 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1090
1091
1092 // Get array of translation statuses, like total, fuzzy, not translated...
1093 $translation_status_arr = wpbc_get_po_transaltion_statuses_of_files_arr( wp_parse_args(
1094 array(
1095 'po_files_full_path_arr' => $po_files_full_path_arr
1096 )
1097 , $params
1098 )
1099 );
1100 /**
1101 array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1102 error = false
1103 percent = {float} 98.11
1104 done = {int} 1870
1105 untranslated = {int} 16
1106 fuzzy = {int} 20
1107 english_name = "ro_RO"
1108 locale = "ro_RO"
1109 )
1110 , ...
1111 )
1112 */
1113
1114 if ( $is_echo ) {
1115
1116 $translation_message = '';
1117 foreach ( $translation_status_arr as $translation_status ) {
1118
1119 $translation_message .= ( empty( $translation_status['english_name'] ) ? $translation_status['locale'] : $translation_status['english_name'] )
1120 . " <strong>{$translation_status['percent']}%</strong> [ {$translation_status['done']} / {$translation_status['total']} ]"
1121 . ", fuzzy <strong>{$translation_status['fuzzy']}</strong>"
1122 . ", not translated <strong>{$translation_status['untranslated']}</strong>" . '<br/>';
1123
1124 }
1125
1126 wpbc_show_message_in_settings( $translation_message, 'info' );
1127
1128 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1129 }
1130
1131 return $translation_status_arr;
1132 }
1133
1134
1135 /**
1136 * Get or Show translation statuses from "{Booking Calendar Folder}" at Booking > Settings General page
1137 * Link: http://server.com/wp-admin/admin.php?page=wpbc-settings&system_info=show&show_translation_status=1#wpbc_general_settings_system_info_metabox
1138 *
1139 * @param bool $is_echo
1140 * @param array $params array(
1141 'wp_available_languages' => array() - result of wpbc_get_available_language_locales_from_wp_org_api()
1142 , 'sort_field_name' => 'percent'
1143 , 'sort_order' => SORT_DESC
1144 , 'sort_type' => SORT_NUMERIC
1145 );
1146 *
1147 * @return array array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1148 error = false
1149 percent = {float} 98.11
1150 done = {int} 1870
1151 untranslated = {int} 16
1152 fuzzy = {int} 20
1153 english_name = "ro_RO"
1154 locale = "ro_RO"
1155 )
1156 , ...
1157 )
1158 */
1159 function wpbc_show_translation_status_from_wpbc( $is_echo = true, $params = array() ){
1160
1161 $defaults = array(
1162 'wp_available_languages' => array()
1163 , 'sort_field_name' => 'percent'
1164 , 'sort_order' => SORT_DESC
1165 , 'sort_type' => SORT_NUMERIC
1166 );
1167 $params = wp_parse_args( $params, $defaults );
1168
1169
1170 if ( empty( $params['wp_available_languages'] ) ) {
1171 // Get available language locales from the WordPress.org API.
1172 $params['wp_available_languages'] = wpbc_get_available_language_locales_from_wp_org_api();
1173 }
1174
1175
1176 // Scan dir for PO files.
1177 if (1) {
1178 $po_files_array = wpbc_scan_dir_for_po_files( WPBC_PLUGIN_DIR . '/languages' ); // $po_files_array = array( "booking-ar.po", "booking-bel.po", "booking-bg_BG.po", ... )
1179 $po_files_full_path_arr = array();
1180 foreach ( $po_files_array as $po_file_name ) {
1181 $po_files_full_path_arr[] = WPBC_PLUGIN_DIR . '/languages/' . $po_file_name; // W:\w3\beta\www/wp-content/plugins/booking/languages/booking-ar.po
1182 }
1183 }
1184
1185 // Get array of translation statuses, like total, fuzzy, not translated...
1186 $translation_status_arr = wpbc_get_po_transaltion_statuses_of_files_arr( wp_parse_args(
1187 array(
1188 'po_files_full_path_arr' => $po_files_full_path_arr
1189 )
1190 , $params
1191 )
1192 );
1193 /**
1194 array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1195 error = false
1196 percent = {float} 98.11
1197 done = {int} 1870
1198 untranslated = {int} 16
1199 fuzzy = {int} 20
1200 english_name = "ro_RO"
1201 locale = "ro_RO"
1202 )
1203 , ...
1204 )
1205 */
1206
1207 if ( $is_echo ) {
1208 //////////////////////////////////////////////////////////////////////////////////
1209 $translation_message = '';
1210 foreach ( $translation_status_arr as $translation_status ) {
1211
1212 $translation_message .= ( empty( $translation_status['english_name'] ) ? $translation_status['locale'] : $translation_status['english_name'] )
1213 . " <strong>{$translation_status['percent']}%</strong> [ {$translation_status['done']} / {$translation_status['total']} ]"
1214 . ", fuzzy <strong>{$translation_status['fuzzy']}</strong>"
1215 . ", not translated <strong>{$translation_status['untranslated']}</strong>" . '<br/>';
1216
1217 }
1218
1219 //////////////////////////////////////////////////////////////////////////////////
1220
1221 wpbc_show_message_in_settings( $translation_message, 'info' );
1222
1223 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1224 }
1225
1226 return $translation_status_arr;
1227 }
1228
1229
1230 /**
1231 * Get Language names for all Locales from WordPress.org API
1232 *
1233 * @return array|array[]
1234 Array( ["nl_NL"] => array ( language = "nl_NL"
1235 version = "5.9"
1236 updated = "2022-02-10 16:24:09"
1237 english_name = "Dutch"
1238 native_name = "Nederlands"
1239 package = "https://downloads.wordpress.org/translation/core/5.9/nl_NL.zip"
1240 iso = array( "nl", "nld" )
1241 strings = array( continue = "Doorgaan" )
1242 ), ...
1243
1244 */
1245 function wpbc_get_available_language_locales_from_wp_org_api(){
1246
1247 // Get Language names for all Locales
1248 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
1249 /**
1250 * Array( ["nl_NL"] => array ( language = "nl_NL"
1251 version = "5.9"
1252 updated = "2022-02-10 16:24:09"
1253 english_name = "Dutch"
1254 native_name = "Nederlands"
1255 package = "https://downloads.wordpress.org/translation/core/5.9/nl_NL.zip"
1256 iso = array( "nl", "nld" )
1257 strings = array( continue = "Doorgaan" )
1258 * ), ...
1259 */
1260 if (function_exists('wp_get_available_translations')){
1261 $wp_api_available_languages = wp_get_available_translations(); // Get available translations from the WordPress.org API.
1262 } else {
1263 $wp_api_available_languages = array();
1264 }
1265
1266 return $wp_api_available_languages;
1267 }
1268
1269
1270 /**
1271 * Get array of translation statuses (like total, fuzzy, not translated) of each PO files
1272 *
1273 * @param $params (array) array(
1274 'po_files_full_path_arr' => array()
1275 , 'wp_available_languages' => array() - result of this function: wp_get_available_translations()
1276 , 'sort_field_name' => 'percent' - it can be any field from the returned array, like 'total'
1277 , 'sort_order' => SORT_DESC
1278 , 'sort_type' => SORT_NUMERIC
1279 )
1280 * 'po_files_full_path_arr' => array (
1281 0 = "W:\w3\beta\www\wp-content\plugins\booking/languages/booking-ar.po"
1282 1 = "W:\w3\beta\www\wp-content\plugins\booking/languages/booking-bel.po"
1283 * ...
1284 * )
1285 *
1286 * @return array array (
1287 0 = array (
1288 filename = "booking-ro_RO.po"
1289 locale = "ro_RO"
1290 total = {int} 1906
1291 error = false
1292 percent = {float} 98.11
1293 done = {int} 1870
1294 untranslated = {int} 16
1295 fuzzy = {int} 20
1296 english_name = "ro_RO"
1297 )
1298 , ...
1299 )
1300 */
1301 function wpbc_get_po_transaltion_statuses_of_files_arr( $params ){
1302
1303 $defaults = array(
1304 'po_files_full_path_arr' => array()
1305 , 'wp_available_languages' => array()
1306 , 'sort_field_name' => 'percent'
1307 , 'sort_order' => SORT_DESC
1308 , 'sort_type' => SORT_NUMERIC
1309 );
1310 $params = wp_parse_args( $params, $defaults );
1311
1312
1313 $translation_status_arr = array();
1314
1315 foreach ( $params['po_files_full_path_arr'] as $po_file_index => $pot_file_path ) {
1316
1317
1318 $translation_status = wpbc_get_po_translation_statuses($pot_file_path);
1319 /**
1320 * array( filename = "booking-ar.po", locale = "ar", total = {int} 1906, percent = {float} 97.74
1321 done = {int} 1863
1322 untranslated = {int} 17
1323 fuzzy = {int} 26
1324 error = false
1325 * )
1326 */
1327
1328 if ( ! empty( $params['wp_available_languages'][ $translation_status['locale'] ] ) ) {
1329 $translation_status['english_name'] = $params['wp_available_languages'][ $translation_status['locale'] ]['english_name'];
1330 } else {
1331 $translation_status['english_name'] = $translation_status['locale'];
1332 }
1333
1334 $translation_status_arr[] = $translation_status;
1335 }
1336
1337 //////////////////////////////////////////////////////////////////////////////////
1338 // Sort translation array
1339 //////////////////////////////////////////////////////////////////////////////////
1340 $volume = array_column( $translation_status_arr, $params['sort_field_name'] ); // default $params['sort_field_name'] = 'percent'
1341 array_multisort( $volume, $params['sort_order'], $params['sort_type'], $translation_status_arr );
1342
1343 return $translation_status_arr;
1344 }
1345
1346
1347 /**
1348 * Scan directory for PO files
1349 *
1350 * @param $dir_to_scan path to directory with PO files
1351 *
1352 * @return array array with names of PO files in this dir
1353 */
1354 function wpbc_scan_dir_for_po_files( $dir_to_scan ){
1355
1356 $found_files = array();
1357
1358 $files = scandir( $dir_to_scan );
1359 if ( ! $files ) {
1360 $found_files = array();
1361 }
1362
1363 foreach ( $files as $file ) {
1364 if ( '.' === $file[0] || is_dir( $dir_to_scan . "/$file" ) ) {
1365 continue;
1366 }
1367 if ( substr( $file, - 3 ) !== '.po' ) {
1368 continue;
1369 }
1370 $match_result = preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match );
1371 if ( ! $match_result ) {
1372 continue;
1373 }
1374 if ( ! in_array( substr( $file, 0, - 3 ) . '.mo', $files, true ) ) {
1375 continue;
1376 }
1377
1378 $found_files[] = $file;
1379 }
1380
1381 return $found_files;
1382 }
1383
1384
1385 /**
1386 * Get translation data statuses from PO file
1387 *
1388 * @param $pot_file_path string - full path to PO translation file
1389 *
1390 * @return array array of PO statuses
1391 */
1392 function wpbc_get_po_translation_statuses( $pot_file_path ){
1393
1394 $translation_status = array(
1395 'filename' => basename( $pot_file_path )
1396 , 'locale' => substr( $pot_file_path, ( strrpos( $pot_file_path, '-' ) + 1 ), - 3 )
1397 , 'total' => 0
1398 , 'error' => false
1399 );
1400
1401 if ( is_readable( $pot_file_path ) ) {
1402
1403 if ( ! class_exists( 'PO' ) ) {
1404 require_once ABSPATH . WPINC . '/pomo/po.php';
1405 }
1406
1407 if ( class_exists( 'PO' ) ) {
1408
1409 $po = new PO();
1410 $is_good = $po->import_from_file( $pot_file_path );
1411
1412 if ( $is_good ) {
1413
1414 $transaltion_total = count( $po->entries );
1415 $transaltion_no = 0;
1416 $transaltion_fuzzy = 0;
1417
1418 foreach ( $po->entries as $po_index => $po_item ) {
1419
1420 $translation = $po_item;
1421
1422 if ( 0 == count( $translation->translations ) ) {
1423 $transaltion_no++;
1424 } elseif ( true === in_array( 'fuzzy', $translation->flags ) ) {
1425 $transaltion_fuzzy++;
1426 }
1427 }
1428
1429 $transaltion_done = $transaltion_total - $transaltion_no - $transaltion_fuzzy;
1430 $transaltion_percent = round( ( $transaltion_done * 100 ) / $transaltion_total, 2 );
1431
1432 $translation_status = wp_parse_args(
1433 array(
1434 'percent' => $transaltion_percent
1435 , 'done' => $transaltion_done
1436 , 'total' => $transaltion_total
1437 , 'untranslated' => $transaltion_no
1438 , 'fuzzy' => $transaltion_fuzzy
1439 )
1440 , $translation_status );
1441
1442 } else {
1443 $translation_status['error'] = 'Import translation from PO file failed';
1444 }
1445 } else {
1446 $translation_status['error'] = 'Can not access to PO class';
1447 }
1448
1449 } else {
1450 $translation_status['error'] = 'File not readable';
1451 }
1452 return $translation_status;
1453 }
1454
1455
1456
1457 /**
1458 * Load translation POT file, and generate PHP file with all translations relative to plugin.
1459 * Link: http://server.com/wp-admin/admin.php?page=wpbc-settings&system_info=show&pot=1#wpbc_general_settings_system_info_metabox
1460 */
1461 function wpbc_pot_to_php() {
1462 return;
1463 /*
1464 * $shortcode = 'wpml';
1465
1466 // Find anything between [wpml] and [/wpml] shortcodes. Magic here: [\s\S]*? - fit to any text
1467 preg_match_all( '/\[' . $shortcode . '\]([\s\S]*?)\[\/' . $shortcode . '\]/i', $text, $wpml_translations, PREG_SET_ORDER );
1468 //debuge( $wpml_translations );
1469
1470 foreach ( $wpml_translations as $translation ) {
1471
1472 */
1473
1474 $pot_file = WP_PLUGIN_DIR . '/' . trim( WPBC_PLUGIN_DIRNAME . '/languages/booking.pot' , '/' );
1475
1476 if ( !is_readable( $pot_file ) ) {
1477 wpbc_show_message_in_settings( 'POT file not found: ' . $pot_file , 'error' );
1478 return false;
1479 } else
1480 wpbc_show_message_in_settings( 'POT file found: ' . $pot_file , 'info' );
1481
1482
1483 if ( ! class_exists( 'PO' ) )
1484 require_once ABSPATH . WPINC . '/pomo/po.php';
1485
1486 if ( class_exists( 'PO' ) ) {
1487
1488 $po = new PO();
1489 $po->import_from_file( $pot_file );
1490
1491 wpbc_show_message_in_settings( 'Found <strong>' . count($po->entries) . '</strong> translations' , 'info' );
1492
1493 // FixIn: 8.7.3.6.
1494 $translation_files = array();
1495
1496
1497 // Generate content of the file
1498 //$all_translations = '<?php function wpbc_all_translations() { $wpbc_all_translations = array(); ';
1499
1500 $lines_number = 1;
1501 $all_translations = '';
1502 foreach ( $po->entries as $transaltion => $transaltion_obj ) {
1503
1504 $transaltion = str_replace( "'", "\'", $transaltion );
1505 $all_translations .= ' $wpbc_all_translations[] = __(\''. $transaltion .'\', \'booking\'); /* translators: 1: ... */ ' . "\n";
1506 $lines_number++;
1507
1508 // Maximum number of lines in such files
1509 if ( $lines_number >= 998 ) {
1510 $file_number = count( $translation_files ) + 1;
1511 $translation_files[] = '<?php function wpbc_all_translations' . $file_number . '() { $wpbc_all_translations = array(); ' . "\n" . $all_translations . " } ";
1512 $all_translations = '';
1513 $lines_number = 1;
1514 }
1515
1516 }
1517
1518 if ( ! empty( $all_translations ) ) {
1519 $file_number = count( $translation_files ) + 1;
1520 $translation_files[] = '<?php function wpbc_all_translations' . $file_number . '() { $wpbc_all_translations = array(); ' . "\n" . $all_translations . " } ";
1521 }
1522
1523
1524 //$all_translations .= ' } ';
1525
1526 foreach ( $translation_files as $file_number => $file_content ) {
1527
1528 // Path to new PHP file with all
1529 $new_php_file = WP_PLUGIN_DIR . '/' . trim( WPBC_PLUGIN_DIRNAME . '/core/lang/wpbc_all_translations' . ( ( ! empty( $file_number ) ) ? $file_number : '' ) . '.php', '/' ); // FixIn: 8.9.4.12.
1530 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
1531 $fh = fopen( $new_php_file, 'w' );
1532 if ( false === $fh ) {
1533 wpbc_show_message_in_settings( 'Can not create or edit PHP file: ' . $new_php_file, 'error' );
1534
1535 return false;
1536 }
1537 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
1538 $res = fwrite( $fh, $file_content );
1539 if ( false === $res ) {
1540 wpbc_show_message_in_settings( 'Some error during saving data into file ' . $new_php_file, 'error' );
1541
1542 return false;
1543 }
1544 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
1545 $res = fclose( $fh );
1546
1547 wpbc_show_message_in_settings( 'Completed! [ ' . htmlentities( $new_php_file ) . ' ]', 'info' );
1548 }
1549
1550 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1551
1552 return $res;
1553
1554 } else {
1555 wpbc_show_message_in_settings( 'PO class does not exist or do not loaded' , 'error' );
1556 }
1557
1558
1559
1560 // $filename = $pot_file;
1561 // $reader = new POMO_FileReader( $filename );
1562 ////debuge($reader);
1563 // if ( ! $reader->is_resource() ) {
1564 // return false;
1565 // }
1566 //
1567 // $file_data = $reader->read_all();
1568 //
1569 // $mo = new PO();
1570 // $pomo_reader = new POMO_StringReader($file_data);
1571 // $mo->import_from_reader( $pomo_reader );
1572 //debuge($mo) ;
1573 // if ( isset( $l10n[$domain] ) )
1574 // $mo->merge_with( $l10n[$domain] );
1575
1576
1577
1578 }
1579
1580
1581 /**
1582 * Delete PHP translation files, before updating POT file in plugin, manually.
1583 * @return void
1584 */
1585 function wpbc_delete_translation_php_files(){
1586
1587 $path_arr = array(
1588 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations.php',
1589 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations1.php',
1590 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations2.php',
1591 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations3.php',
1592 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations4.php',
1593 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations5.php'
1594 );
1595
1596
1597 foreach ( $path_arr as $path ) {
1598
1599 if ( file_exists( $path ) ) {
1600 if ( is_file( $path ) ) {
1601 if ( ! wp_delete_file( $path ) ) {
1602 throw new \RuntimeException( 'Failed to unlink ' . esc_html( $path ) . ': ' . var_export( error_get_last(), true ) ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped, WordPress.PHP.DevelopmentFunctions.error_log_var_export
1603 } else {
1604 echo '<p style="color:red;">Deleted: ' . esc_html( $path ) . '</p>';
1605 }
1606 }
1607 }
1608 }
1609 }
1610
1611
1612 // $translation = apply_filters( "gettext_{$domain}", $translation, $text, $domain );
1613
1614 // FixIn: 9.1.3.2.
1615 /**
1616 * Check consistency of translations. For situations, when translators made mistakes with missed symbols like %s or additional items
1617 *
1618 * @param $translation
1619 * @param $text
1620 * @param $domain
1621 *
1622 * @return string
1623 */
1624 function wpbc_check_translations( $translation, $text, $domain ){
1625
1626 $check_symbols = array( 's', 'd', 'f', 'b', 'c', 'e', 'E', 'F', 'g', 'G', 'h', 'H', 'o', 'u', 'x', 'X' );
1627 foreach ( $check_symbols as $check_symbol ) {
1628 $text_count = substr_count( $text, '%' . $check_symbol );
1629 $translation_count = substr_count( $translation, '%' . $check_symbol );
1630
1631 if ( $text_count != $translation_count ) { // Number of %s in translation != number of %s in original text -- ERROR in translation
1632
1633 /*
1634 $booking_translation_errors = new WP_Error( 'booking_translation_consistency', 'Translation consistency error', array(
1635 'text' => $text,
1636 'translation' => $translation,
1637 'symbol_error' => '%' . $check_symbol
1638 ) );
1639 */
1640 return $text;
1641 }
1642
1643 }
1644
1645 $text_count = substr_count( $text, '%' );
1646 $translation_count = substr_count( $translation, '%' );
1647 if ( $text_count != $translation_count ) {
1648 return $text;
1649 }
1650
1651 return $translation;
1652 }
1653 add_filter( 'gettext_booking', 'wpbc_check_translations', 1000, 3 ); // check Booking Calendar translation terms
1654 add_filter( 'gettext_booking-manager', 'wpbc_check_translations', 1000, 3 ); // check Booking Manager translation terms
1655
1656 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1657 // Deprecated
1658 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1659
1660 /**
1661 * Deprecated
1662 */
1663 function wpbc_get_booking_locale() {
1664 return wpbc_get_maybe_reloaded_booking_locale();
1665 }
1666
1667
1668