PluginProbe
Booking Calendar / 11.8.2
Booking Calendar v11.8.2
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 10.11 10.11.2 10.11.3 All 202 releases
booking / core / wpbc-translation.php

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

1,662 lines 63.5 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 info@wpbookingcalendar.com
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 * @return array|bool|string|WP_Error - result
776 */
777 function wpbc_translation_download_from_wpbc(){
778
779 $my_upgrader = wpbc_get_translation_upgrader_obj();
780
781 $result = $my_upgrader->run( array(
782 'package' => 'https://wpbookingcalendar.com/download/languages/languages.zip', // Please always pass this.
783 'destination' => WPBC_PLUGIN_DIR . '/languages/', // WPBC_PLUGIN_DIR . '/lang/', // ...and this.
784 'clear_destination' => false,
785 'abort_if_destination_exists' => false, // Abort if the destination directory exists. Pass clear_destination as false please.
786 'clear_working' => true,
787 'is_multi' => false,
788 'hook_extra' => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
789 ) );
790
791 return $result;
792 }
793
794
795 /**
796 * Get translation Upgrader object
797 *
798 * @return WP_Upgrader obj
799 */
800 function wpbc_get_translation_upgrader_obj(){
801
802 require_once ABSPATH . 'wp-admin/includes/file.php';
803 require_once ABSPATH . 'wp-admin/includes/plugin.php';
804 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
805 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
806
807 require_once WPBC_PLUGIN_DIR . '/core/class/wpbc-class-upgrader-translation-skin.php';
808 $skin = new WPBC_Upgrader_Translation_Skin(
809 array( 'skip_header_footer' => true )
810 );
811
812 $my_upgrader = new WP_Upgrader( $skin );
813
814 $my_upgrader->init(); // it's required for defining skin messages
815
816 return $my_upgrader;
817 }
818
819
820 /**
821 * Get array of translation packages from WordPress.org
822 *
823 * @return array Array ( [0] => Array (
824 [language] => bg_BG
825 [version] => 8.9.3
826 [updated] => 2018-03-13 19:55:57
827 [english_name] => Bulgarian
828 [native_name] => Български
829 [package] => https://downloads.wordpress.org/translation/plugin/booking/8.9.3/bg_BG.zip
830 [iso] => Array ( [1] => bg, [2] => bul )
831 )
832 [1] ....
833 */
834 function wpbc_get_translation_packages_arr_from_wp(){
835
836 $translations_arr = array();
837
838 if ( ! is_admin() ) {
839 return $translations_arr;
840 }
841
842 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
843
844 $api = translations_api( 'plugins', array(
845 'slug' => 'booking',
846 'version' => WP_BK_VERSION_NUM, //'8.9.3',
847 ) );
848
849 if ( ( is_wp_error( $api ) ) || ( empty( $api['translations'] ) ) ) {
850 return $translations_arr;
851 } else {
852 $translations_arr = $api['translations'];
853 }
854
855 return $translations_arr;
856 }
857
858
859
860 //======================================================================================================================
861 // Get STATUS of translations in this website
862 //======================================================================================================================
863
864
865 function wpbc_show_translation_status_compare_wpbc_wp( ) {
866
867 WPBC_Action_Scheduler_Compatibility::raise_memory_limit();
868 WPBC_Action_Scheduler_Compatibility::raise_time_limit( 300 );
869
870 $params = array(
871 'sort_field_name' => 'locale'
872 , 'sort_order' => SORT_ASC
873 , 'sort_type' => SORT_STRING
874 );
875 $params['wp_available_languages'] = wpbc_get_available_language_locales_from_wp_org_api();
876
877 $current_locale = wpbc_get_maybe_reloaded_booking_locale(); // if NOT defined WPBC_LOCALE_RELOAD define by current WordPress locale
878
879 $is_echo = false;
880
881 $from_wp = wpbc_show_translation_status_from_wp( $is_echo, $params );
882 $from_wpbc = wpbc_show_translation_status_from_wpbc( $is_echo, $params );
883
884 $total_translations = 0;
885
886 $compared_translations = array();
887 // WPBC
888 foreach ( $from_wpbc as $po_translation ) {
889 $compared_translations[ $po_translation['locale'] ] = array(
890 'filename' => $po_translation['filename']
891 , 'locale' => $po_translation['locale']
892 , 'english_name' => $po_translation['english_name']
893 , 'total_wpbc' => $po_translation['total']
894 , 'error_wpbc' => $po_translation['error']
895 , 'percent_wpbc' => $po_translation['percent']
896 , 'done_wpbc' => $po_translation['done']
897 , 'untranslated_wpbc' => $po_translation['untranslated']
898 , 'fuzzy_wpbc' => $po_translation['fuzzy']
899
900 , 'total_wp' => 0
901 , 'error_wp' => 0
902 , 'percent_wp' => 0
903 , 'done_wp' => 0
904 , 'untranslated_wp' => 0
905 , 'fuzzy_wp' => 0
906 );
907 if ( $po_translation['total'] > $total_translations ) {
908 $total_translations = $po_translation['total'];
909 }
910 }
911
912
913 // WP_LANG_DIR
914 foreach ( $from_wp as $po_translation ) {
915
916 if ( isset( $compared_translations[ $po_translation['locale'] ] ) ) {
917 $default = $compared_translations[ $po_translation['locale'] ];
918 } else {
919 $default = array(
920 'total_wpbc' => 0
921 , 'error_wpbc' => 0
922 , 'percent_wpbc' => 0
923 , 'done_wpbc' => 0
924 , 'untranslated_wpbc' => 0
925 , 'fuzzy_wpbc' => 0
926 );
927 }
928
929 $compared_translations[ $po_translation['locale'] ] = wp_parse_args(
930 array(
931 'filename' => $po_translation['filename']
932 , 'locale' => $po_translation['locale']
933 , 'english_name' => $po_translation['english_name']
934 , 'total_wp' => $po_translation['total']
935 , 'error_wp' => $po_translation['error']
936 , 'percent_wp' => $po_translation['percent']
937 , 'done_wp' => $po_translation['done']
938 , 'untranslated_wp' => $po_translation['untranslated']
939 , 'fuzzy_wp' => $po_translation['fuzzy']
940 ),
941 $default
942 );
943 if ( $po_translation['total'] > $total_translations ) {
944 $total_translations = $po_translation['total'];
945 }
946 }
947
948 $new_compared_translations = array();
949 $current_active_translation = false;
950 foreach ( $compared_translations as $locale => $compared_translation ) {
951
952 $compared_translation['total'] = $total_translations;//( ( $compared_translation['total_wp'] > $compared_translation['total_wpbc'] ) ? $compared_translation['total_wp'] : $compared_translation['total_wpbc'] );
953
954 $compared_translation['done'] = ( ( $compared_translation['done_wp'] > $compared_translation['done_wpbc'] ) ? $compared_translation['done_wp'] : $compared_translation['done_wpbc'] );
955
956 $compared_translation['percent'] = round( ( $compared_translation['done'] * 100 ) / $compared_translation['total'], 2 );
957
958
959 $new_compared_translations[] = $compared_translation;
960 if ( $current_locale == $compared_translation['locale'] ) {
961 $current_active_translation = array();
962 $current_active_translation[] = $compared_translation;
963 }
964 }
965
966
967 //////////////////////////////////////////////////////////////////////////////////
968 // Sort translation array
969 //////////////////////////////////////////////////////////////////////////////////
970 $volume = array_column( $new_compared_translations, 'done' ); // default $params['sort_field_name'] = 'percent'
971 array_multisort( $volume, SORT_DESC, SORT_NUMERIC, $new_compared_translations );
972
973
974 //debuge( $new_compared_translations );
975
976 if ( ! empty( $current_active_translation ) ) {
977 $new_compared_translations = array_merge( $current_active_translation, $new_compared_translations );
978 }
979 $translation_message = '';
980 $is_already_shown_current_lang = false;
981 foreach ( $new_compared_translations as $translation_status ) {
982
983 if ( ( ! empty( $current_active_translation ) ) && ( $current_locale == $translation_status['locale'] ) && ($is_already_shown_current_lang)) {
984 continue;
985 }
986
987 $translation_message .= ( empty( $translation_status['english_name'] ) ? $translation_status['locale'] : $translation_status['english_name'] )
988 . " [{$translation_status['locale']}] "
989 . " better to use ". ( ( $translation_status['done_wpbc'] > $translation_status['done_wp'] ) ? "local" : "wordpress.org" ) . " translation"
990 . '<br/>'
991 . " Total translations: <strong>{$translation_status['percent']}%</strong> [ <strong>{$translation_status['done']}</strong> / {$translation_status['total']} ]"
992 . '<br/>'
993 . "Local translation. " //. esc_html( WPBC_PLUGIN_DIR . '/languages/' ) . " folder"
994 . " Translated <strong>{$translation_status['done_wpbc']}</strong>"
995 . ", fuzzy <strong>{$translation_status['fuzzy_wpbc']}</strong>"
996 . ", not translated <strong>{$translation_status['untranslated_wpbc']}</strong>"
997 . '<br/>'
998 . "wordpress.org translation. " //. esc_html( WP_LANG_DIR . '/plugins/' ) . " folder"
999 . " Translated <strong>{$translation_status['done_wp']}</strong>"
1000 . ", fuzzy <strong>{$translation_status['fuzzy_wp']}</strong>"
1001 . ", not translated <strong>{$translation_status['untranslated_wp']}</strong>"
1002 . '<hr/>';
1003
1004 if ( ( ! empty( $current_active_translation ) ) && ( $current_locale == $translation_status['locale'] ) ) {
1005 $is_already_shown_current_lang = true;
1006 }
1007 }
1008
1009 //////////////////////////////////////////////////////////////////////////////////
1010
1011 wpbc_show_message_in_settings( $translation_message, 'info' );
1012
1013 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1014 }
1015
1016 /**
1017 * Get or Show translation statuses from "WP_LANG_DIR" folder at Booking > Settings General page
1018 *
1019 * Link: http://server.com/wp-admin/admin.php?page=wpbc-settings&system_info=show&show_translation_status=1#wpbc_general_settings_system_info_metabox
1020 *
1021 * @param bool $is_echo
1022 * @param array $params array(
1023 'wp_available_languages' => array() - result of wpbc_get_available_language_locales_from_wp_org_api()
1024 , 'sort_field_name' => 'percent'
1025 , 'sort_order' => SORT_DESC
1026 , 'sort_type' => SORT_NUMERIC
1027 );
1028 *
1029 * @return array array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1030 error = false
1031 percent = {float} 98.11
1032 done = {int} 1870
1033 untranslated = {int} 16
1034 fuzzy = {int} 20
1035 english_name = "ro_RO"
1036 locale = "ro_RO"
1037 )
1038 , ...
1039 )
1040 */
1041 function wpbc_show_translation_status_from_wp( $is_echo = true, $params = array() ){
1042
1043 $defaults = array(
1044 'wp_available_languages' => array()
1045 , 'sort_field_name' => 'done'
1046 , 'sort_order' => SORT_DESC
1047 , 'sort_type' => SORT_NUMERIC
1048 );
1049 $params = wp_parse_args( $params, $defaults );
1050
1051
1052 if ( empty( $params['wp_available_languages'] ) ) {
1053 // Get available language locales from the WordPress.org API.
1054 $params['wp_available_languages'] = wpbc_get_available_language_locales_from_wp_org_api();
1055 }
1056
1057
1058 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1059 // Scan WP_LANG_DIR dir for PO files.
1060 if (1) {
1061 $plugin_translations_in_lang_dir = wp_get_installed_translations( 'plugins' );
1062
1063 $plugin_slug = 'booking';
1064
1065 if ( ! empty( $plugin_translations_in_lang_dir[ $plugin_slug ] ) ) {
1066 $plugin_translations_in_lang_dir = $plugin_translations_in_lang_dir[ $plugin_slug ];
1067 } else {
1068 $plugin_translations_in_lang_dir = array();
1069 }
1070
1071 $po_files_full_path_arr = array();
1072 foreach ( (array) $plugin_translations_in_lang_dir as $locale => $po_arr ) {
1073
1074 $po_files_full_path_arr[] = WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $locale . '.po';
1075 /**
1076 * array ( [0] => W:\w3\beta\www/wp-content/languages/plugins/booking-bg_BG.po
1077 * [1] => W:\w3\beta\www/wp-content/languages/plugins/booking-ca.po
1078 * ...
1079 * )
1080 */
1081 }
1082 }
1083 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1084
1085
1086 // Get array of translation statuses, like total, fuzzy, not translated...
1087 $translation_status_arr = wpbc_get_po_transaltion_statuses_of_files_arr( wp_parse_args(
1088 array(
1089 'po_files_full_path_arr' => $po_files_full_path_arr
1090 )
1091 , $params
1092 )
1093 );
1094 /**
1095 array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1096 error = false
1097 percent = {float} 98.11
1098 done = {int} 1870
1099 untranslated = {int} 16
1100 fuzzy = {int} 20
1101 english_name = "ro_RO"
1102 locale = "ro_RO"
1103 )
1104 , ...
1105 )
1106 */
1107
1108 if ( $is_echo ) {
1109
1110 $translation_message = '';
1111 foreach ( $translation_status_arr as $translation_status ) {
1112
1113 $translation_message .= ( empty( $translation_status['english_name'] ) ? $translation_status['locale'] : $translation_status['english_name'] )
1114 . " <strong>{$translation_status['percent']}%</strong> [ {$translation_status['done']} / {$translation_status['total']} ]"
1115 . ", fuzzy <strong>{$translation_status['fuzzy']}</strong>"
1116 . ", not translated <strong>{$translation_status['untranslated']}</strong>" . '<br/>';
1117
1118 }
1119
1120 wpbc_show_message_in_settings( $translation_message, 'info' );
1121
1122 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1123 }
1124
1125 return $translation_status_arr;
1126 }
1127
1128
1129 /**
1130 * Get or Show translation statuses from "{Booking Calendar Folder}" at Booking > Settings General page
1131 * Link: http://server.com/wp-admin/admin.php?page=wpbc-settings&system_info=show&show_translation_status=1#wpbc_general_settings_system_info_metabox
1132 *
1133 * @param bool $is_echo
1134 * @param array $params array(
1135 'wp_available_languages' => array() - result of wpbc_get_available_language_locales_from_wp_org_api()
1136 , 'sort_field_name' => 'percent'
1137 , 'sort_order' => SORT_DESC
1138 , 'sort_type' => SORT_NUMERIC
1139 );
1140 *
1141 * @return array array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1142 error = false
1143 percent = {float} 98.11
1144 done = {int} 1870
1145 untranslated = {int} 16
1146 fuzzy = {int} 20
1147 english_name = "ro_RO"
1148 locale = "ro_RO"
1149 )
1150 , ...
1151 )
1152 */
1153 function wpbc_show_translation_status_from_wpbc( $is_echo = true, $params = array() ){
1154
1155 $defaults = array(
1156 'wp_available_languages' => array()
1157 , 'sort_field_name' => 'percent'
1158 , 'sort_order' => SORT_DESC
1159 , 'sort_type' => SORT_NUMERIC
1160 );
1161 $params = wp_parse_args( $params, $defaults );
1162
1163
1164 if ( empty( $params['wp_available_languages'] ) ) {
1165 // Get available language locales from the WordPress.org API.
1166 $params['wp_available_languages'] = wpbc_get_available_language_locales_from_wp_org_api();
1167 }
1168
1169
1170 // Scan dir for PO files.
1171 if (1) {
1172 $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", ... )
1173 $po_files_full_path_arr = array();
1174 foreach ( $po_files_array as $po_file_name ) {
1175 $po_files_full_path_arr[] = WPBC_PLUGIN_DIR . '/languages/' . $po_file_name; // W:\w3\beta\www/wp-content/plugins/booking/languages/booking-ar.po
1176 }
1177 }
1178
1179 // Get array of translation statuses, like total, fuzzy, not translated...
1180 $translation_status_arr = wpbc_get_po_transaltion_statuses_of_files_arr( wp_parse_args(
1181 array(
1182 'po_files_full_path_arr' => $po_files_full_path_arr
1183 )
1184 , $params
1185 )
1186 );
1187 /**
1188 array ( array ( filename = "booking-ro_RO.po", total = {int} 1906
1189 error = false
1190 percent = {float} 98.11
1191 done = {int} 1870
1192 untranslated = {int} 16
1193 fuzzy = {int} 20
1194 english_name = "ro_RO"
1195 locale = "ro_RO"
1196 )
1197 , ...
1198 )
1199 */
1200
1201 if ( $is_echo ) {
1202 //////////////////////////////////////////////////////////////////////////////////
1203 $translation_message = '';
1204 foreach ( $translation_status_arr as $translation_status ) {
1205
1206 $translation_message .= ( empty( $translation_status['english_name'] ) ? $translation_status['locale'] : $translation_status['english_name'] )
1207 . " <strong>{$translation_status['percent']}%</strong> [ {$translation_status['done']} / {$translation_status['total']} ]"
1208 . ", fuzzy <strong>{$translation_status['fuzzy']}</strong>"
1209 . ", not translated <strong>{$translation_status['untranslated']}</strong>" . '<br/>';
1210
1211 }
1212
1213 //////////////////////////////////////////////////////////////////////////////////
1214
1215 wpbc_show_message_in_settings( $translation_message, 'info' );
1216
1217 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1218 }
1219
1220 return $translation_status_arr;
1221 }
1222
1223
1224 /**
1225 * Get Language names for all Locales from WordPress.org API
1226 *
1227 * @return array|array[]
1228 Array( ["nl_NL"] => array ( language = "nl_NL"
1229 version = "5.9"
1230 updated = "2022-02-10 16:24:09"
1231 english_name = "Dutch"
1232 native_name = "Nederlands"
1233 package = "https://downloads.wordpress.org/translation/core/5.9/nl_NL.zip"
1234 iso = array( "nl", "nld" )
1235 strings = array( continue = "Doorgaan" )
1236 ), ...
1237
1238 */
1239 function wpbc_get_available_language_locales_from_wp_org_api(){
1240
1241 // Get Language names for all Locales
1242 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
1243 /**
1244 * Array( ["nl_NL"] => array ( language = "nl_NL"
1245 version = "5.9"
1246 updated = "2022-02-10 16:24:09"
1247 english_name = "Dutch"
1248 native_name = "Nederlands"
1249 package = "https://downloads.wordpress.org/translation/core/5.9/nl_NL.zip"
1250 iso = array( "nl", "nld" )
1251 strings = array( continue = "Doorgaan" )
1252 * ), ...
1253 */
1254 if (function_exists('wp_get_available_translations')){
1255 $wp_api_available_languages = wp_get_available_translations(); // Get available translations from the WordPress.org API.
1256 } else {
1257 $wp_api_available_languages = array();
1258 }
1259
1260 return $wp_api_available_languages;
1261 }
1262
1263
1264 /**
1265 * Get array of translation statuses (like total, fuzzy, not translated) of each PO files
1266 *
1267 * @param $params (array) array(
1268 'po_files_full_path_arr' => array()
1269 , 'wp_available_languages' => array() - result of this function: wp_get_available_translations()
1270 , 'sort_field_name' => 'percent' - it can be any field from the returned array, like 'total'
1271 , 'sort_order' => SORT_DESC
1272 , 'sort_type' => SORT_NUMERIC
1273 )
1274 * 'po_files_full_path_arr' => array (
1275 0 = "W:\w3\beta\www\wp-content\plugins\booking/languages/booking-ar.po"
1276 1 = "W:\w3\beta\www\wp-content\plugins\booking/languages/booking-bel.po"
1277 * ...
1278 * )
1279 *
1280 * @return array array (
1281 0 = array (
1282 filename = "booking-ro_RO.po"
1283 locale = "ro_RO"
1284 total = {int} 1906
1285 error = false
1286 percent = {float} 98.11
1287 done = {int} 1870
1288 untranslated = {int} 16
1289 fuzzy = {int} 20
1290 english_name = "ro_RO"
1291 )
1292 , ...
1293 )
1294 */
1295 function wpbc_get_po_transaltion_statuses_of_files_arr( $params ){
1296
1297 $defaults = array(
1298 'po_files_full_path_arr' => array()
1299 , 'wp_available_languages' => array()
1300 , 'sort_field_name' => 'percent'
1301 , 'sort_order' => SORT_DESC
1302 , 'sort_type' => SORT_NUMERIC
1303 );
1304 $params = wp_parse_args( $params, $defaults );
1305
1306
1307 $translation_status_arr = array();
1308
1309 foreach ( $params['po_files_full_path_arr'] as $po_file_index => $pot_file_path ) {
1310
1311
1312 $translation_status = wpbc_get_po_translation_statuses($pot_file_path);
1313 /**
1314 * array( filename = "booking-ar.po", locale = "ar", total = {int} 1906, percent = {float} 97.74
1315 done = {int} 1863
1316 untranslated = {int} 17
1317 fuzzy = {int} 26
1318 error = false
1319 * )
1320 */
1321
1322 if ( ! empty( $params['wp_available_languages'][ $translation_status['locale'] ] ) ) {
1323 $translation_status['english_name'] = $params['wp_available_languages'][ $translation_status['locale'] ]['english_name'];
1324 } else {
1325 $translation_status['english_name'] = $translation_status['locale'];
1326 }
1327
1328 $translation_status_arr[] = $translation_status;
1329 }
1330
1331 //////////////////////////////////////////////////////////////////////////////////
1332 // Sort translation array
1333 //////////////////////////////////////////////////////////////////////////////////
1334 $volume = array_column( $translation_status_arr, $params['sort_field_name'] ); // default $params['sort_field_name'] = 'percent'
1335 array_multisort( $volume, $params['sort_order'], $params['sort_type'], $translation_status_arr );
1336
1337 return $translation_status_arr;
1338 }
1339
1340
1341 /**
1342 * Scan directory for PO files
1343 *
1344 * @param $dir_to_scan path to directory with PO files
1345 *
1346 * @return array array with names of PO files in this dir
1347 */
1348 function wpbc_scan_dir_for_po_files( $dir_to_scan ){
1349
1350 $found_files = array();
1351
1352 $files = scandir( $dir_to_scan );
1353 if ( ! $files ) {
1354 $found_files = array();
1355 }
1356
1357 foreach ( $files as $file ) {
1358 if ( '.' === $file[0] || is_dir( $dir_to_scan . "/$file" ) ) {
1359 continue;
1360 }
1361 if ( substr( $file, - 3 ) !== '.po' ) {
1362 continue;
1363 }
1364 $match_result = preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match );
1365 if ( ! $match_result ) {
1366 continue;
1367 }
1368 if ( ! in_array( substr( $file, 0, - 3 ) . '.mo', $files, true ) ) {
1369 continue;
1370 }
1371
1372 $found_files[] = $file;
1373 }
1374
1375 return $found_files;
1376 }
1377
1378
1379 /**
1380 * Get translation data statuses from PO file
1381 *
1382 * @param $pot_file_path string - full path to PO translation file
1383 *
1384 * @return array array of PO statuses
1385 */
1386 function wpbc_get_po_translation_statuses( $pot_file_path ){
1387
1388 $translation_status = array(
1389 'filename' => basename( $pot_file_path )
1390 , 'locale' => substr( $pot_file_path, ( strrpos( $pot_file_path, '-' ) + 1 ), - 3 )
1391 , 'total' => 0
1392 , 'error' => false
1393 );
1394
1395 if ( is_readable( $pot_file_path ) ) {
1396
1397 if ( ! class_exists( 'PO' ) ) {
1398 require_once ABSPATH . WPINC . '/pomo/po.php';
1399 }
1400
1401 if ( class_exists( 'PO' ) ) {
1402
1403 $po = new PO();
1404 $is_good = $po->import_from_file( $pot_file_path );
1405
1406 if ( $is_good ) {
1407
1408 $transaltion_total = count( $po->entries );
1409 $transaltion_no = 0;
1410 $transaltion_fuzzy = 0;
1411
1412 foreach ( $po->entries as $po_index => $po_item ) {
1413
1414 $translation = $po_item;
1415
1416 if ( 0 == count( $translation->translations ) ) {
1417 $transaltion_no++;
1418 } elseif ( true === in_array( 'fuzzy', $translation->flags ) ) {
1419 $transaltion_fuzzy++;
1420 }
1421 }
1422
1423 $transaltion_done = $transaltion_total - $transaltion_no - $transaltion_fuzzy;
1424 $transaltion_percent = round( ( $transaltion_done * 100 ) / $transaltion_total, 2 );
1425
1426 $translation_status = wp_parse_args(
1427 array(
1428 'percent' => $transaltion_percent
1429 , 'done' => $transaltion_done
1430 , 'total' => $transaltion_total
1431 , 'untranslated' => $transaltion_no
1432 , 'fuzzy' => $transaltion_fuzzy
1433 )
1434 , $translation_status );
1435
1436 } else {
1437 $translation_status['error'] = 'Import translation from PO file failed';
1438 }
1439 } else {
1440 $translation_status['error'] = 'Can not access to PO class';
1441 }
1442
1443 } else {
1444 $translation_status['error'] = 'File not readable';
1445 }
1446 return $translation_status;
1447 }
1448
1449
1450
1451 /**
1452 * Load translation POT file, and generate PHP file with all translations relative to plugin.
1453 * Link: http://server.com/wp-admin/admin.php?page=wpbc-settings&system_info=show&pot=1#wpbc_general_settings_system_info_metabox
1454 */
1455 function wpbc_pot_to_php() {
1456
1457 /*
1458 * $shortcode = 'wpml';
1459
1460 // Find anything between [wpml] and [/wpml] shortcodes. Magic here: [\s\S]*? - fit to any text
1461 preg_match_all( '/\[' . $shortcode . '\]([\s\S]*?)\[\/' . $shortcode . '\]/i', $text, $wpml_translations, PREG_SET_ORDER );
1462 //debuge( $wpml_translations );
1463
1464 foreach ( $wpml_translations as $translation ) {
1465
1466 */
1467
1468 $pot_file = WP_PLUGIN_DIR . '/' . trim( WPBC_PLUGIN_DIRNAME . '/languages/booking.pot' , '/' );
1469
1470 if ( !is_readable( $pot_file ) ) {
1471 wpbc_show_message_in_settings( 'POT file not found: ' . $pot_file , 'error' );
1472 return false;
1473 } else
1474 wpbc_show_message_in_settings( 'POT file found: ' . $pot_file , 'info' );
1475
1476
1477 if ( ! class_exists( 'PO' ) )
1478 require_once ABSPATH . WPINC . '/pomo/po.php';
1479
1480 if ( class_exists( 'PO' ) ) {
1481
1482 $po = new PO();
1483 $po->import_from_file( $pot_file );
1484
1485 wpbc_show_message_in_settings( 'Found <strong>' . count($po->entries) . '</strong> translations' , 'info' );
1486
1487 // FixIn: 8.7.3.6.
1488 $translation_files = array();
1489
1490
1491 // Generate content of the file
1492 //$all_translations = '<?php function wpbc_all_translations() { $wpbc_all_translations = array(); ';
1493
1494 $lines_number = 1;
1495 $all_translations = '';
1496 foreach ( $po->entries as $transaltion => $transaltion_obj ) {
1497
1498 $transaltion = str_replace( "'", "\'", $transaltion );
1499 $all_translations .= ' $wpbc_all_translations[] = __(\''. $transaltion .'\', \'booking\'); /* translators: 1: ... */ ' . "\n";
1500 $lines_number++;
1501
1502 // Maximum number of lines in such files
1503 if ( $lines_number >= 998 ) {
1504 $file_number = count( $translation_files ) + 1;
1505 $translation_files[] = '<?php function wpbc_all_translations' . $file_number . '() { $wpbc_all_translations = array(); ' . "\n" . $all_translations . " } ";
1506 $all_translations = '';
1507 $lines_number = 1;
1508 }
1509
1510 }
1511
1512 if ( ! empty( $all_translations ) ) {
1513 $file_number = count( $translation_files ) + 1;
1514 $translation_files[] = '<?php function wpbc_all_translations' . $file_number . '() { $wpbc_all_translations = array(); ' . "\n" . $all_translations . " } ";
1515 }
1516
1517
1518 //$all_translations .= ' } ';
1519
1520 foreach ( $translation_files as $file_number => $file_content ) {
1521
1522 // Path to new PHP file with all
1523 $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.
1524 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
1525 $fh = fopen( $new_php_file, 'w' );
1526 if ( false === $fh ) {
1527 wpbc_show_message_in_settings( 'Can not create or edit PHP file: ' . $new_php_file, 'error' );
1528
1529 return false;
1530 }
1531 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
1532 $res = fwrite( $fh, $file_content );
1533 if ( false === $res ) {
1534 wpbc_show_message_in_settings( 'Some error during saving data into file ' . $new_php_file, 'error' );
1535
1536 return false;
1537 }
1538 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
1539 $res = fclose( $fh );
1540
1541 wpbc_show_message_in_settings( 'Completed! [ ' . htmlentities( $new_php_file ) . ' ]', 'info' );
1542 }
1543
1544 echo '<a class="button button-secondary" style="margin:10px 0;" href="' . esc_url( wpbc_get_settings_url() ) . '" >' . esc_html__( 'Go to Settings', 'booking' ) . '</a>';
1545
1546 return $res;
1547
1548 } else {
1549 wpbc_show_message_in_settings( 'PO class does not exist or do not loaded' , 'error' );
1550 }
1551
1552
1553
1554 // $filename = $pot_file;
1555 // $reader = new POMO_FileReader( $filename );
1556 ////debuge($reader);
1557 // if ( ! $reader->is_resource() ) {
1558 // return false;
1559 // }
1560 //
1561 // $file_data = $reader->read_all();
1562 //
1563 // $mo = new PO();
1564 // $pomo_reader = new POMO_StringReader($file_data);
1565 // $mo->import_from_reader( $pomo_reader );
1566 //debuge($mo) ;
1567 // if ( isset( $l10n[$domain] ) )
1568 // $mo->merge_with( $l10n[$domain] );
1569
1570
1571
1572 }
1573
1574
1575 /**
1576 * Delete PHP translation files, before updating POT file in plugin, manually.
1577 * @return void
1578 */
1579 function wpbc_delete_translation_php_files(){
1580
1581 $path_arr = array(
1582 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations.php',
1583 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations1.php',
1584 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations2.php',
1585 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations3.php',
1586 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations4.php',
1587 WPBC_PLUGIN_DIR . '/core/lang/wpbc_all_translations5.php'
1588 );
1589
1590
1591 foreach ( $path_arr as $path ) {
1592
1593 if ( file_exists( $path ) ) {
1594 if ( is_file( $path ) ) {
1595 if ( ! wp_delete_file( $path ) ) {
1596 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
1597 } else {
1598 echo '<p style="color:red;">Deleted: ' . esc_html( $path ) . '</p>';
1599 }
1600 }
1601 }
1602 }
1603 }
1604
1605
1606 // $translation = apply_filters( "gettext_{$domain}", $translation, $text, $domain );
1607
1608 // FixIn: 9.1.3.2.
1609 /**
1610 * Check consistency of translations. For situations, when translators made mistakes with missed symbols like %s or additional items
1611 *
1612 * @param $translation
1613 * @param $text
1614 * @param $domain
1615 *
1616 * @return string
1617 */
1618 function wpbc_check_translations( $translation, $text, $domain ){
1619
1620 $check_symbols = array( 's', 'd', 'f', 'b', 'c', 'e', 'E', 'F', 'g', 'G', 'h', 'H', 'o', 'u', 'x', 'X' );
1621 foreach ( $check_symbols as $check_symbol ) {
1622 $text_count = substr_count( $text, '%' . $check_symbol );
1623 $translation_count = substr_count( $translation, '%' . $check_symbol );
1624
1625 if ( $text_count != $translation_count ) { // Number of %s in translation != number of %s in original text -- ERROR in translation
1626
1627 /*
1628 $booking_translation_errors = new WP_Error( 'booking_translation_consistency', 'Translation consistency error', array(
1629 'text' => $text,
1630 'translation' => $translation,
1631 'symbol_error' => '%' . $check_symbol
1632 ) );
1633 */
1634 return $text;
1635 }
1636
1637 }
1638
1639 $text_count = substr_count( $text, '%' );
1640 $translation_count = substr_count( $translation, '%' );
1641 if ( $text_count != $translation_count ) {
1642 return $text;
1643 }
1644
1645 return $translation;
1646 }
1647 add_filter( 'gettext_booking', 'wpbc_check_translations', 1000, 3 ); // check Booking Calendar translation terms
1648 add_filter( 'gettext_booking-manager', 'wpbc_check_translations', 1000, 3 ); // check Booking Manager translation terms
1649
1650 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1651 // Deprecated
1652 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1653
1654 /**
1655 * Deprecated
1656 */
1657 function wpbc_get_booking_locale() {
1658 return wpbc_get_maybe_reloaded_booking_locale();
1659 }
1660
1661
1662