PluginProbe
Booking Calendar / 11.1
Booking Calendar v11.1
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.1, at core/wpbc-translation.php

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