Changeset 3420034
- Timestamp:
- 12/15/2025 11:26:52 AM (2 months ago)
- Location:
- translatepress-multilingual
- Files:
-
- 40 edited
- 1 copied
-
tags/3.0.6 (copied) (copied from translatepress-multilingual/trunk)
-
tags/3.0.6/assets/js/trp-frontend-compatibility.js (modified) (1 diff)
-
tags/3.0.6/assets/js/trp-frontend-language-switcher.js (modified) (2 diffs)
-
tags/3.0.6/assets/js/trp-translate-dom-changes.js (modified) (1 diff)
-
tags/3.0.6/changelog.txt (modified) (1 diff)
-
tags/3.0.6/class-translate-press.php (modified) (3 diffs)
-
tags/3.0.6/includes/advanced-settings/do-not-translate-certain-paths.php (modified) (1 diff)
-
tags/3.0.6/includes/class-language-switcher-v2.php (modified) (1 diff)
-
tags/3.0.6/includes/class-languages.php (modified) (2 diffs)
-
tags/3.0.6/includes/class-machine-translator.php (modified) (1 diff)
-
tags/3.0.6/includes/class-settings.php (modified) (1 diff)
-
tags/3.0.6/includes/class-translation-render.php (modified) (4 diffs)
-
tags/3.0.6/includes/class-woocommerce-emails.php (modified) (6 diffs)
-
tags/3.0.6/includes/compatibility-functions.php (modified) (1 diff)
-
tags/3.0.6/includes/external-functions.php (modified) (1 diff)
-
tags/3.0.6/includes/functions.php (modified) (2 diffs)
-
tags/3.0.6/includes/gettext/class-gettext-manager.php (modified) (2 diffs)
-
tags/3.0.6/includes/queries/class-query.php (modified) (2 diffs)
-
tags/3.0.6/index.php (modified) (2 diffs)
-
tags/3.0.6/languages/translatepress-multilingual.pot (modified) (4 diffs)
-
tags/3.0.6/readme.txt (modified) (2 diffs)
-
trunk/assets/js/trp-frontend-compatibility.js (modified) (1 diff)
-
trunk/assets/js/trp-frontend-language-switcher.js (modified) (2 diffs)
-
trunk/assets/js/trp-translate-dom-changes.js (modified) (1 diff)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/class-translate-press.php (modified) (3 diffs)
-
trunk/includes/advanced-settings/do-not-translate-certain-paths.php (modified) (1 diff)
-
trunk/includes/class-language-switcher-v2.php (modified) (1 diff)
-
trunk/includes/class-languages.php (modified) (2 diffs)
-
trunk/includes/class-machine-translator.php (modified) (1 diff)
-
trunk/includes/class-settings.php (modified) (1 diff)
-
trunk/includes/class-translation-render.php (modified) (4 diffs)
-
trunk/includes/class-woocommerce-emails.php (modified) (6 diffs)
-
trunk/includes/compatibility-functions.php (modified) (1 diff)
-
trunk/includes/external-functions.php (modified) (1 diff)
-
trunk/includes/functions.php (modified) (2 diffs)
-
trunk/includes/gettext/class-gettext-manager.php (modified) (2 diffs)
-
trunk/includes/queries/class-query.php (modified) (2 diffs)
-
trunk/index.php (modified) (2 diffs)
-
trunk/languages/translatepress-multilingual.pot (modified) (4 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
translatepress-multilingual/tags/3.0.6/assets/js/trp-frontend-compatibility.js
r3288239 r3420034 3 3 4 4 // clear WooCommerce cart fragments when switching language 5 var trp_language_switcher_urls = document.querySelectorAll(".trp-language-switcher-container a:not(.trp-ls-disabled-language) ");5 var trp_language_switcher_urls = document.querySelectorAll(".trp-language-switcher-container a:not(.trp-ls-disabled-language), .trp-language-item:not(.trp-language-item__current)"); 6 6 7 7 for (i = 0; i < trp_language_switcher_urls.length; i++) { -
translatepress-multilingual/tags/3.0.6/assets/js/trp-frontend-language-switcher.js
r3389452 r3420034 35 35 } 36 36 37 /** 38 * Returns true if the list has a non-zero transition duration (for any property). 39 * We use this to decide whether to rely on `transitionend` or fall back to sync behavior. 40 */ 41 _hasAnimatedTransition() { 42 if (!this.list) return false; 43 44 const cs = getComputedStyle(this.list); 45 const durationsRaw = cs.transitionDuration || ''; 46 47 if (!durationsRaw) return false; 48 49 const durations = durationsRaw 50 .split(',') 51 .map(str => parseFloat(str) || 0); 52 53 return durations.some(d => d > 0); 54 } 55 37 56 collapse() { 38 57 this.list.hidden = true; … … 66 85 } 67 86 68 setOpen(open, { source = null } = {}) { 69 if (!this.root || !this.list || open === this.isOpen) return; 70 71 // Honor reduced motion: skip the transition entirely (still class-driven) 87 setOpen( open, { source = null } = {} ) { 88 if ( !this.root || !this.list || open === this.isOpen ) return; 89 72 90 const prefersReduced = window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches; 91 const hasTransition = !prefersReduced && this._hasAnimatedTransition(); 73 92 74 93 this.isOpen = open; 75 94 76 if (open) { 77 // Prepare: must be visible for CSS transition to run 95 // No transitions (0s duration) OR reduced motion: do everything synchronously, 96 if ( !hasTransition ) { 97 if ( open ) { 98 this.list.hidden = false; 99 this.list.removeAttribute( 'inert' ); 100 this.setExpanded( true ); 101 102 this._pendingFocusOnOpen = ( source?.type === 'keydown' ); 103 if ( this._pendingFocusOnOpen ) { 104 this._pendingFocusOnOpen = false; 105 const first = this.list.querySelector( 106 '[role="option"], a, button, [tabindex]:not([tabindex="-1"])' 107 ); 108 first?.focus?.({ preventScroll: true }); 109 } 110 } else { 111 this.setExpanded( false ); 112 this.list.hidden = true; 113 this.list.setAttribute( 'inert', '' ); 114 this._pendingFocusOnOpen = false; 115 } 116 return; 117 } 118 119 // Animated path: rely on transitionend to remove .is-transitioning 120 if ( open ) { 121 // Must be visible for CSS transition to run 78 122 this.list.hidden = false; 79 this.list.removeAttribute('inert'); 80 81 if (prefersReduced) { 82 this.root.classList.remove('is-transitioning'); 83 this.setExpanded(true); 84 } else { 85 this.root.classList.add('is-transitioning'); 86 // Next frame so the browser registers the pre-open (max-height:0) state 87 requestAnimationFrame(() => this.setExpanded(true)); 88 } 89 90 // keyboard open should move focus after transition completes 91 this._pendingFocusOnOpen = (source?.type === 'keydown'); 92 123 this.list.removeAttribute( 'inert' ); 124 125 this._pendingFocusOnOpen = ( source?.type === 'keydown' ); 126 127 this.root.classList.add( 'is-transitioning' ); 128 // Next frame so browser registers pre-open (max-height: 0) state 129 requestAnimationFrame( () => this.setExpanded( true ) ); 93 130 } else { 94 if (prefersReduced){ 95 this.root.classList.add( 'is-transitioning' ); 96 } 97 98 this.setExpanded(false); 131 this.root.classList.add( 'is-transitioning' ); 132 this.setExpanded( false ); 99 133 } 100 134 } -
translatepress-multilingual/tags/3.0.6/assets/js/trp-translate-dom-changes.js
r3288239 r3420034 468 468 469 469 // create an observer instance 470 observer = new MutationObserver( _this.detect_new_strings_callback ); 470 if ( trp_data['showdynamiccontentbeforetranslation'] === true ){ 471 observer = new MutationObserver(mutations => { 472 setTimeout(() => _this.detect_new_strings_callback(mutations), 0); 473 }); 474 } 475 476 else { 477 observer = observer = new MutationObserver(_this.detect_new_strings_callback) 478 } 471 479 472 480 _this.resume_observer(); -
translatepress-multilingual/tags/3.0.6/changelog.txt
r3403492 r3420034 1 = 3.0.5 = 2 * Fixed CSS for Black Friday offer from admin notice 3 4 = 3.0.4 = 5 * Added 39 more languages including Irish, Maltese and Sicilian 6 * Added support for Latin American Spanish automatic translation in TranslatePress AI 7 * Added support for Divi search in secondary language 8 * Added support for exact match search in String Translation by placing the string in quotes: "example" 9 * Allow schema.org data to be translated 10 * Fixed Regular String Translation search so filtered languages also match terms appearing in the middle of translated strings, not only at the start 11 * Prevent automatic translation of strings that are 0 or 1 characters long or strings that are punctuation only 12 * Change background hover color for transparent preset in order to improve contrast of language switcher 13 * Fixed two missing spaces in floating switcher HTML markup 14 * Fix PHP warning with empty domain for gettext with context 15 * Fixed edge case error "call to a member function is_available() on null" 16 * Moved the "Automatically Translate Slug" setting to be first in line 17 * Extended the license message for item_name_mismatch to provide more context 18 * Improved text information next to the default language 19 1 20 = 3.0.3 = 2 21 * Fixed an issue introduced in the previous update that occurred when using Google Translate as the translation engine -
translatepress-multilingual/tags/3.0.6/class-translate-press.php
r3403492 r3420034 68 68 */ 69 69 public function __construct() { 70 // Early bind to break recursion loop caused by calling get_trp_instance during construction 71 if ( self::$translate_press === null ) { 72 self::$translate_press = $this; 73 } 74 70 75 define( 'TRP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 71 76 define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); 72 77 define( 'TRP_PLUGIN_BASE', plugin_basename( __DIR__ . '/index.php' ) ); 73 78 define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' ); 74 define( 'TRP_PLUGIN_VERSION', '3.0. 5' );79 define( 'TRP_PLUGIN_VERSION', '3.0.6' ); 75 80 76 81 wp_cache_add_non_persistent_groups(array('trp')); … … 103 108 require_once TRP_PLUGIN_DIR . 'includes/class-editor-api-regular-strings.php'; 104 109 require_once TRP_PLUGIN_DIR . 'includes/class-editor-api-gettext-strings.php'; 105 require_once TRP_PLUGIN_DIR . 'includes/class-translation-manager.php';106 110 require_once TRP_PLUGIN_DIR . 'includes/class-hooks-loader.php'; 107 111 require_once TRP_PLUGIN_DIR . 'includes/class-languages.php'; … … 180 184 $this->query = new TRP_Query( $this->settings->get_settings() ); 181 185 $this->machine_translator_logger = new TRP_Machine_Translator_Logger( $this->settings->get_settings() ); 186 $this->machine_translator = new TRP_Machine_Translator( $this->settings->get_settings() ); // Will be overwritten in init_machine_translation with the actual machine translator class. Use this as replacement until then. 182 187 $this->translation_manager = new TRP_Translation_Manager( $this->settings->get_settings() ); 183 188 $this->editor_api_regular_strings = new TRP_Editor_Api_Regular_Strings( $this->settings->get_settings() ); -
translatepress-multilingual/tags/3.0.6/includes/advanced-settings/do-not-translate-certain-paths.php
r3328103 r3420034 490 490 return $excluded; 491 491 } 492 493 /** 494 * Check if the current URL is excluded from translation based on the 495 * "Do not translate certain paths" / "Translate only certain paths" setting. 496 * 497 * Takes into account: 498 * - site installed in subdirectory 499 * - "Use a subdirectory for the default language" 500 * - {{home}} mapping 501 * - both "exclude" and "include" modes 502 * 503 * @return bool True if the current URL should be treated as excluded from translation. 504 */ 505 function trp_dntcp_is_current_url_excluded() { 506 if ( is_admin() ) { 507 return false; 508 } 509 510 $settings = get_option( 'trp_settings', false ); 511 $advanced_settings = get_option( 'trp_advanced_settings', false ); 512 513 // No configuration -> nothing is excluded. 514 if ( empty( $advanced_settings ) 515 || ! isset( $advanced_settings['translateable_content'] ) 516 || empty( $advanced_settings['translateable_content']['paths'] ) 517 || empty( $advanced_settings['translateable_content']['option'] ) ) { 518 return false; 519 } 520 521 $mode = $advanced_settings['translateable_content']['option']; // 'exclude' or 'include' 522 $paths = trp_dntcp_get_paths(); 523 524 // Build current slug in the same way as trp_exclude_include_paths_to_run_on() 525 $trp = TRP_Translate_Press::get_trp_instance(); 526 $url_converter = $trp->get_component( 'url_converter' ); 527 528 $current_lang = $url_converter->get_lang_from_url_string( $url_converter->cur_page_url() ); 529 if ( empty( $current_lang ) && isset( $settings['default-language'] ) ) { 530 $current_lang = $settings['default-language']; 531 } 532 533 $site_url_components = parse_url( get_home_url() ); 534 $current_slug = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( $_SERVER['REQUEST_URI'] ) : ''; 535 536 // Remove site_url path for installs in subdirectories (e.g. http://localhost/wordpress) 537 if ( isset( $site_url_components['path'] ) && $site_url_components['path'] !== '' ) { 538 $current_slug = str_replace( trim( $site_url_components['path'] ), '', $current_slug ); 539 } 540 541 // Take into account subdirectory for the default language or other languages. 542 // This mirrors the logic used in trp_exclude_include_paths_to_run_on(). 543 if ( isset( $settings['add-subdirectory-to-default-language'] ) 544 && $settings['add-subdirectory-to-default-language'] === 'yes' 545 && ! empty( $current_lang ) 546 && isset( $settings['url-slugs'][ $current_lang ] ) ) { 547 548 $replace = '\/' . $settings['url-slugs'][ $current_lang ]; 549 $current_slug = preg_replace( "/$replace/i", '', ltrim( $current_slug, '/' ), 1 ); 550 } 551 552 $array_slugs = array(); 553 trp_test_current_slug( $current_slug, $array_slugs ); 554 555 $matched = trp_return_exclude_include_url( $paths, $current_slug, $array_slugs ); 556 557 // In "exclude" mode: listed paths are excluded. 558 if ( $mode === 'exclude' ) 559 return (bool) $matched; 560 561 // In "include" mode: ONLY listed paths are translatable; all others are excluded 562 if ( $mode === 'include' ) 563 return !$matched; 564 565 return false; 566 } -
translatepress-multilingual/tags/3.0.6/includes/class-language-switcher-v2.php
r3389452 r3420034 130 130 131 131 $allow = apply_filters('trp_allow_language_redirect', true, $needed_lang, $this->url_converter->cur_page_url()); 132 if (!$allow) return; 132 133 if ( !$allow || trp_dntcp_is_current_url_excluded() ) 134 return; 133 135 134 136 $missing_in_url = ($lang_from_url === null); -
translatepress-multilingual/tags/3.0.6/includes/class-languages.php
r3398116 r3420034 41 41 */ 42 42 public function change_locale( $locale ){ 43 44 if ( $this->is_string_translation_request_for_different_language() ){45 $trp_ajax_language = (isset($_POST['trp_ajax_language']) ) ? sanitize_text_field( $_POST['trp_ajax_language'] ) : '';46 if ( !$this->settings ){47 $trp = TRP_Translate_Press::get_trp_instance();48 $trp_settings = $trp->get_component( 'settings' );49 $this->settings = $trp_settings->get_settings();50 }51 if ( $trp_ajax_language && in_array( $trp_ajax_language, $this->settings['translation-languages'] ) ){52 return $trp_ajax_language;53 }54 }55 56 43 if ( $this->is_admin_request === null ){ 57 44 $trp = TRP_Translate_Press::get_trp_instance(); … … 70 57 return $locale; 71 58 } 72 73 public function is_string_translation_request_for_different_language(){74 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {75 $action = 'trp_string_translation_get_missing_gettext_strings';76 if ( isset( $_POST['action'] ) && $_POST['action'] === $action ) {77 return true;78 }79 }80 return false;81 }82 59 83 60 /** -
translatepress-multilingual/tags/3.0.6/includes/class-machine-translator.php
r3398116 r3420034 48 48 * @return bool 49 49 */ 50 public function is_available( $languages = array() ){ 51 if( !empty( $this->settings['trp_machine_translation_settings']['machine-translation'] ) && 52 $this->settings['trp_machine_translation_settings']['machine-translation'] == 'yes' 53 ) { 54 if ( empty( $languages ) ){ 55 // can be used to simply know if machine translation is available 50 public function is_available( $languages = array() ) { 51 /** 52 * Return false in case it was directly called from parent and not from a derived class (DeepL / Google / TPAI) 53 * Calling this method on the parent class means it was called too early and machine translation is not available at this point 54 */ 55 if ( get_class( $this ) === __CLASS__ ) 56 return false; 57 58 $settings = $this->settings['trp_machine_translation_settings'] ?? array(); 59 $enabled = ( $settings['machine-translation'] ?? '' ) === 'yes'; 60 $is_available = false; 61 62 if ( $enabled ) { 63 $engine = $settings['translation-engine'] ?? null; 64 65 if ( $engine === 'deepl' && get_option( 'trp_license_status' ) !== 'valid' ) { 66 $is_available = false; 67 } elseif ( empty( $languages ) ) { 56 68 $is_available = true; 57 } 58 59 // If the license is invalid and the translation engine is DeepL,return false 60 $license_status = get_option( 'trp_license_status' ); 61 if ( $license_status !== 'valid' && isset( $this->settings['trp_machine_translation_settings']['translation-engine'] ) && $this->settings['trp_machine_translation_settings']['translation-engine'] === 'deepl' ) { 62 $is_available = false; 63 } 64 65 $is_available = $this->check_languages_availability($languages); 66 67 }else { 68 $is_available = false; 69 } 70 71 return apply_filters('trp_machine_translator_is_available', $is_available); 69 } else { 70 $is_available = $this->check_languages_availability( $languages ); 71 } 72 } 73 74 return apply_filters( 'trp_machine_translator_is_available', $is_available, $languages, $settings ); 72 75 } 73 76 -
translatepress-multilingual/tags/3.0.6/includes/class-settings.php
r3377320 r3420034 329 329 330 330 unset($settings['translation-languages-formality']); 331 332 $trp = TRP_Translate_Press::get_trp_instance(); 333 $language_switcher_tab = $trp->get_component('language_switcher_tab'); 334 335 if ( !$language_switcher_tab->is_legacy_enabled() && count( $settings['publish-languages'] ) > 2 ) { 336 $ls_settings = $language_switcher_tab->get_initial_config(); 337 $new_ls_settings = $ls_settings; 338 339 $new_ls_settings['floater']['oppositeLanguage'] = false; 340 $new_ls_settings['shortcode']['oppositeLanguage'] = false; 341 342 if ( $new_ls_settings !== $ls_settings ){ 343 update_option( 'trp_language_switcher_settings', $new_ls_settings ); 344 } 345 } 331 346 332 347 // check for duplicates in url slugs -
translatepress-multilingual/tags/3.0.6/includes/class-translation-render.php
r3398116 r3420034 1020 1020 $translated_strings_manual = array(); 1021 1021 foreach ( $translateable_strings_manual as $i => $string_manual ) { 1022 if ( isset( $translated_strings_manual_dictionary[ $string_manual ]->translated ) ) {1022 if ( isset( $translated_strings_manual_dictionary[ $string_manual ]->translated ) && !empty( $translated_strings_manual_dictionary[ $string_manual ]->translated )) { 1023 1023 $translated_strings_manual[$i] = $translated_strings_manual_dictionary[ $string_manual ]->translated; 1024 1024 } … … 1686 1686 1687 1687 foreach ( $translateable_strings as $i => $string ) { 1688 1688 if ( isset( $dictionary[ $string ]->translated ) && empty( $dictionary[ $string ]->translated ) ) { 1689 /* If we have an empty string with a status != NOT TRANSLATED, it's possible we are dealing with 1690 * an intentional thing. After Automatic translation, a text can be translated with unallowed html 1691 * thus being stored in DB as empty string with status = MACHINE TRANSLATED. By doing continue; we avoid 1692 * re-autotranslating over and over again. 1693 */ 1694 continue; 1695 } 1689 1696 // prevent accidentally machine translated strings from db such as for src to be displayed 1690 1697 $skip_string = in_array( $string, $skip_machine_translating_strings ); … … 1763 1770 1764 1771 if ( !isset($translated_strings[$i]) && isset( $machine_strings[$string] ) ) { 1765 $translated_strings[$i] = $machine_strings[$string]; 1772 $sanitized_machine_string = trp_sanitize_string( $machine_strings[$string] ); 1773 if ( !empty( $sanitized_machine_string ) ){ 1774 // Unallowed HTML can be turned into empty string. Show original text instead 1775 $translated_strings[$i] = $sanitized_machine_string; 1776 } 1766 1777 } 1767 1778 … … 2080 2091 * @return array 2081 2092 */ 2082 public function wp_mail_filter( $args ) {2083 if ( ! is_array( $args ) ){2093 public function wp_mail_filter( $args ) { 2094 if ( ! is_array( $args ) ) { 2084 2095 return $args; 2085 2096 } 2086 2097 2087 $whitelisted_shortcodes = apply_filters( 'trp_whitelisted_shortcodes_for_wp_mail', [ 'trp_language', 'language-include', 'language-exclude' ] ); 2088 2089 if ( array_key_exists( 'subject', $args ) ){ 2090 $args['subject'] = $this->translate_page( trp_do_these_shortcodes( $args['subject'], $whitelisted_shortcodes ) ); 2091 } 2092 2093 if ( array_key_exists( 'message', $args ) ){ 2094 $args['message'] = $this->translate_page( trp_do_these_shortcodes( $args['message'], $whitelisted_shortcodes ) ); 2095 } 2098 if ( empty( $args['to'] ) ) { 2099 return $args; 2100 } 2101 2102 global $TRP_LANGUAGE; 2103 2104 $initial_language = $TRP_LANGUAGE; 2105 2106 $recipient = $args['to']; 2107 2108 // Normalize $recipient to a single email string (first recipient only - that's the main one) 2109 if ( is_array( $recipient ) ) { 2110 $first = reset( $recipient ); 2111 $recipient = is_string( $first ) ? $first : ''; 2112 } 2113 2114 $recipient = (string) $recipient; 2115 2116 // Keep only the first comma-separated entry if multiple are present in the string 2117 $recipient = trim( strtok( $recipient, ',' ) ); 2118 2119 if ( $recipient !== '' ) { 2120 trp_switch_to_preffered_language( $recipient ); 2121 } 2122 2123 $whitelisted_shortcodes = apply_filters( 2124 'trp_whitelisted_shortcodes_for_wp_mail', 2125 array( 'trp_language', 'language-include', 'language-exclude' ) 2126 ); 2127 2128 if ( array_key_exists( 'subject', $args ) ) { 2129 $args['subject'] = $this->translate_page( 2130 trp_do_these_shortcodes( $args['subject'], $whitelisted_shortcodes ) 2131 ); 2132 } 2133 2134 if ( array_key_exists( 'message', $args ) ) { 2135 $args['message'] = $this->translate_page( 2136 trp_do_these_shortcodes( $args['message'], $whitelisted_shortcodes ) 2137 ); 2138 } 2139 2140 // Switch back to the language used initially 2141 $TRP_LANGUAGE = $initial_language; 2096 2142 2097 2143 return $args; -
translatepress-multilingual/tags/3.0.6/includes/class-woocommerce-emails.php
r3398116 r3420034 187 187 } 188 188 189 $trp_settings = TRP_Translate_Press::get_trp_instance()->get_component( 'settings' ); 190 $settings = $trp_settings->get_settings(); 191 192 $default_language = $settings["default-language"]; 193 189 194 /** 190 195 * At this point in the execution, $wc_email->get_recipient() returns null and throws a PHP warning inside WooCommerce /woocommerce/includes/emails/class-wc-email.php … … 224 229 $registered_user = get_user_by( 'email', $recipients[0] ); 225 230 if( $registered_user ){ 226 // If language is set to site default, user object won't have a locale set. Fallback to WPLANG. In case WPLANG is not set either, fallback to trp_language231 // If language is set to site default, user object won't have a locale set. Fallback to WPLANG. In case WPLANG is not set either, fallback to default language 227 232 if ( !empty( $registered_user->locale ) ){ 228 233 $language = $registered_user->locale; 229 234 } else { 230 $language = get_option( 'WPLANG' ) ?? get_user_meta( $registered_user->ID, 'trp_language', true ); 235 $wplang = get_option( 'WPLANG' ); 236 $language = !empty( $wplang ) ? $wplang : $default_language; 231 237 } 232 238 } else { … … 243 249 trp_switch_language( $language ); 244 250 245 WC()->load_plugin_textdomain(); 246 247 $this->bootstrap_trp_gettext_for_email_language( $language ); 251 add_filter( 'trp_allow_gettext_write', '__return_true' ); 252 253 $this->reload_woocommerce_textdomain(); 254 255 $this->bootstrap_trp_gettext_for_emails(); 248 256 249 257 // calls necessary because the default additional_content field of an email is localized before this point and stored in a variable in the previous locale … … 264 272 265 273 trp_restore_language(); 266 WC()->load_plugin_textdomain();274 $this->reload_woocommerce_textdomain(); 267 275 268 276 return false; … … 289 297 * gettext translations stored in TranslatePress are applied correctly. 290 298 */ 291 private function bootstrap_trp_gettext_for_email _language( $language) {299 private function bootstrap_trp_gettext_for_emails() { 292 300 $trp = TRP_Translate_Press::get_trp_instance(); 293 301 $gettext_manager = $trp->get_component( 'gettext_manager' ); … … 308 316 } 309 317 318 function reload_woocommerce_textdomain() { 319 $domain = 'woocommerce'; 320 321 $locale = apply_filters( 'plugin_locale', get_locale(), $domain ); 322 323 $custom_translation_path = WP_LANG_DIR . '/woocommerce/woocommerce-' . $locale . '.mo'; 324 $global_translation_path = WP_LANG_DIR . '/plugins/woocommerce-' . $locale . '.mo'; 325 $bundled_translation_path = trailingslashit( WC()->plugin_path() ) . 'i18n/languages/woocommerce-' . $locale . '.mo'; 326 327 unload_textdomain( $domain ); 328 329 // Custom file present: mimic WC 330 if ( is_readable( $custom_translation_path ) ) { 331 load_textdomain( $domain, $custom_translation_path ); 332 333 if ( is_readable( $global_translation_path ) ) { 334 load_textdomain( $domain, $global_translation_path ); 335 } 336 337 return true; 338 } 339 340 if ( is_readable( $global_translation_path ) ) { 341 load_textdomain( $domain, $global_translation_path ); 342 return true; 343 } 344 345 if ( is_readable( $bundled_translation_path ) ) { 346 load_textdomain( $domain, $bundled_translation_path ); 347 return true; 348 } 349 350 return false; 351 } 352 310 353 } -
translatepress-multilingual/tags/3.0.6/includes/compatibility-functions.php
r3398116 r3420034 2709 2709 2710 2710 /** 2711 * Override the wrap_with_post_id condition for Divi 2712 * 2713 * Divi doesn't use the main loop in the traditional way, so we need to override 2714 * the condition that checks for in_the_loop and is_main_query. 2715 * 2716 * @param bool $return Whether to bypass the wrap condition 2717 * @return bool 2718 */ 2719 add_filter('trp_wrap_with_post_id_overrule', 'trp_divi_override_wrap_condition', 10); 2720 function trp_divi_override_wrap_condition($return) { 2721 // Check if Divi is the active theme 2722 if (function_exists('et_setup_theme')) { 2723 // Return false to bypass the in_the_loop check 2724 return false; 2725 } 2726 return $return; 2727 } 2711 * Add trp-post-container wrapper to Divi module outputs 2712 * TP is not adding any trp-post-container except here. 2713 * 2714 * @param string $output The module HTML output 2715 * @param string $render_slug The module slug (e.g., 'et_pb_text', 'et_pb_post_title') 2716 * @param object $module The module object 2717 * @return string Modified output with trp-post-container wrapper 2718 */ 2719 add_filter('et_module_shortcode_output', 'trp_divi_wrap_module_with_post_id', 10, 3); 2720 2721 function trp_divi_wrap_module_with_post_id($output, $render_slug, $module) { 2722 global $post, $TRP_LANGUAGE; 2723 2724 // Check if we have a valid post ID 2725 if (empty($post->ID)) { 2726 return $output; 2727 } 2728 2729 // Get TranslatePress settings 2730 $trp = TRP_Translate_Press::get_trp_instance(); 2731 $trp_settings = $trp->get_component('settings'); 2732 $settings = $trp_settings->get_settings(); 2733 2734 // Only wrap on non-default language 2735 if ($TRP_LANGUAGE !== $settings['default-language']) { 2736 // Only wrap modules that typically contain translatable text content 2737 $modules_to_wrap = apply_filters('trp_divi_modules_to_wrap', array( 2738 'et_pb_text', 2739 'et_pb_post_title', 2740 'et_pb_post_content', 2741 'et_pb_blurb', 2742 'et_pb_cta', 2743 'et_pb_accordion', 2744 'et_pb_toggle', 2745 'et_pb_tabs', 2746 'et_pb_testimonial', 2747 'et_pb_pricing_tables', 2748 'et_pb_number_counter', 2749 'et_pb_countdown_timer' 2750 )); 2751 2752 if (in_array($render_slug, $modules_to_wrap)) { 2753 $output = "<trp-post-container data-trp-post-id='" . $post->ID . "'>" . $output . "</trp-post-container>"; 2754 } 2755 } 2756 2757 return $output; 2758 } -
translatepress-multilingual/tags/3.0.6/includes/external-functions.php
r3288239 r3420034 64 64 } 65 65 66 if ( strip_tags( $string ) === '' || trim ($string, $filter_string) === '' ){ 67 $string = ''; 68 } 66 if ( strip_tags( $string ) === '' || trim( $string, $filter_string ) === '' ) { 67 // Needs decoding otherwise some strings with special characters won't get detected. 68 // Example in Hebrew: אוכל ותרבות 69 // Placed inside the "if" to avoid calling html_entity_decode so often as this is a very used function 70 $decoded_string = html_entity_decode( $string ); 71 if ( trim( $decoded_string, $filter_string ) === '' ) { 72 $string = ''; 73 } 74 } 69 75 return $string; 70 76 } -
translatepress-multilingual/tags/3.0.6/includes/functions.php
r3349766 r3420034 274 274 return $string; 275 275 276 if (seems_utf8($string)) { 276 $seems_utf = ( function_exists( 'wp_is_valid_utf8' ) ) ? wp_is_valid_utf8( $string ) : seems_utf8( $string ); 277 278 if ( $seems_utf ) { 277 279 $chars = array( 278 280 // Decompositions for Latin-1 Supplement … … 821 823 822 824 /** 825 * Switch to a user's preferred language based on the recipient email. 826 * 827 * For managerial users (admin-like roles), prefer user->locale with fallback 828 * to WPLANG, then trp_language. 829 * 830 * For non-managerial users, prefer trp_language, with fallback to locale, then WPLANG. 831 * 832 * @param string $email 833 * @return void 834 */ 835 function trp_switch_to_preffered_language( $email ) { 836 $email = trim( (string) $email ); 837 838 if ( $email === '' ) 839 return; 840 841 $user = get_user_by( 'email', $email ); 842 843 if ( ! ( $user instanceof WP_User ) ) 844 return; 845 846 $user_roles = is_array( $user->roles ) ? $user->roles : array(); 847 848 $trp_settings = TRP_Translate_Press::get_trp_instance()->get_component( 'settings' ); 849 $settings = $trp_settings->get_settings(); 850 851 $default_language = $settings["default-language"]; 852 853 /** 854 * Roles considered "managerial" for email language purposes. 855 * 856 * @param string[] $roles 857 */ 858 $managerial_roles = apply_filters( 859 'trp_managerial_roles_for_email_language', 860 [ 'administrator', 'editor', 'shop_manager' ] 861 ); 862 863 $is_managerial = !empty( array_intersect( $managerial_roles, $user_roles ) ); 864 865 if ( $is_managerial ) { 866 // Managerial: prefer locale, then WPLANG, then default_language 867 if ( !empty( $user->locale ) ) { 868 $language = $user->locale; 869 } else { 870 $wplang = get_option( 'WPLANG' ); 871 $language = !empty( $wplang ) ? $wplang : $default_language; 872 } 873 } else { 874 // Non-managerial: prefer trp_language. 875 $language = get_user_meta( $user->ID, 'trp_language', true ); 876 877 if ( empty( $language ) ) { 878 if ( !empty( $user->locale ) ) { 879 $language = $user->locale; 880 } else { 881 $wplang = get_option( 'WPLANG' ); 882 $language = !empty( $wplang ) ? $wplang : $default_language; 883 } 884 } 885 } 886 887 if ( empty( $language ) ) 888 return; 889 890 trp_switch_language( $language ); 891 } 892 893 /** 823 894 * Return $TRP_LANGUAGE as plugin locale 824 895 * -
translatepress-multilingual/tags/3.0.6/includes/gettext/class-gettext-manager.php
r3374439 r3420034 488 488 */ 489 489 public function add_missing_language_file_translations( $dictionary, $language ) { 490 491 $trp_plural_forms = $this->get_gettext_component( 'plural_forms' ); 490 // Ensure translation files are loaded with the correct locale 491 $locale = determine_locale(); 492 $switched = switch_to_locale( $language ); 493 494 // This means that the language is not supported by WordPress. Either a custom language or a language that we support but WordPress does not. 495 if ( !$switched && $language !== $locale ) 496 return; 497 498 $trp_plural_forms = $this->get_gettext_component( 'plural_forms' ); 492 499 if ( ! $this->trp_query ) { 493 500 $trp = TRP_Translate_Press::get_trp_instance(); … … 611 618 $gettext_insert_update->insert_gettext_strings($insert_gettext_strings, $language); 612 619 $gettext_insert_update->update_gettext_strings($update_gettext_strings, $language, array('translated', 'id', 'status')); 620 621 if ( $switched ) 622 restore_previous_locale(); 613 623 } 614 624 } -
translatepress-multilingual/tags/3.0.6/includes/queries/class-query.php
r3288239 r3420034 97 97 $and_block_type = " AND block_type = " . $block_type; 98 98 } 99 $query = "SELECT original,translated, status FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE status != " . self::NOT_TRANSLATED . $and_block_type . " AND translated <>'' AND original IN "; 99 100 /* Do not add a condition for "translated <> '' because this would cause re-autotranslating. */ 101 $query = "SELECT original,translated, status FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE status != " . self::NOT_TRANSLATED . $and_block_type . " AND original IN "; 100 102 101 103 $placeholders = array(); … … 108 110 $query .= "( " . implode ( ", ", $placeholders ) . " )"; 109 111 $prepared_query = $this->db->prepare( $query, $values ); 110 $dictionary = $this->db->get_results( $prepared_query, OBJECT_K ); 111 112 $results = $this->db->get_results( $prepared_query, OBJECT ); 113 114 if ( !empty( $results ) && is_array( $results ) ) { 115 // There are edge cases where we have 2 results for the same original: 116 // one with translated as empty string, one with non-empty translation. Keep the one with translation. 117 $dictionary = []; 118 foreach ( $results as $row ) { 119 $key = $row->original; 120 121 // If this key has never been added, simply add it 122 if ( !isset( $dictionary[ $key ] ) ) { 123 $dictionary[ $key ] = $row; 124 continue; 125 } 126 127 // If current stored entry has empty 'translated' 128 // and this new row has non-empty 'translated', replace it 129 if ( 130 empty( $dictionary[ $key ]->translated ) && 131 !empty( $row->translated ) 132 ) { 133 $dictionary[ $key ] = $row; 134 } 135 136 // Otherwise do nothing — we keep the existing "better" record 137 } 138 } else { 139 $dictionary = $results; 140 } 112 141 113 142 -
translatepress-multilingual/tags/3.0.6/index.php
r3403492 r3420034 4 4 Plugin URI: https://translatepress.com/ 5 5 Description: Experience a better way of translating your WordPress site using a visual front-end translation editor, with full support for WooCommerce and site builders. 6 Version: 3.0. 56 Version: 3.0.6 7 7 Author: Cozmoslabs, Razvan Mocanu, Madalin Ungureanu, Cristophor Hurduban 8 8 Author URI: https://cozmoslabs.com/ … … 11 11 License: GPL2 12 12 WC requires at least: 2.5.0 13 WC tested up to: 10. 3.513 WC tested up to: 10.4.2 14 14 15 15 == Copyright == -
translatepress-multilingual/tags/3.0.6/languages/translatepress-multilingual.pot
r3403492 r3420034 7 7 "Content-Type: text/plain; charset=UTF-8\n" 8 8 "Content-Transfer-Encoding: 8bit\n" 9 "POT-Creation-Date: 2025-1 1-26 15:19+0000\n"9 "POT-Creation-Date: 2025-12-15 11:13+0000\n" 10 10 "X-Poedit-Basepath: ..\n" 11 11 "X-Poedit-KeywordsList: __;_e;_ex:1,2c;_n:1,2;_n_noop:1,2;_nx:1,2,4c;_nx_noop:1,2,3c;_x:1,2c;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c\n" … … 319 319 msgstr "" 320 320 321 #: includes/class-language-switcher-v2.php:7 18321 #: includes/class-language-switcher-v2.php:720 322 322 msgid "Change language to %s" 323 323 msgstr "" … … 347 347 msgstr "" 348 348 349 #: includes/class-machine-translator.php:15 4, includes/google-translate/class-google-translate-v2-machine-translator.php:200349 #: includes/class-machine-translator.php:157, includes/google-translate/class-google-translate-v2-machine-translator.php:200 350 350 msgid "Please enter your Google Translate key." 351 351 msgstr "" 352 352 353 #: includes/class-machine-translator.php:1 69, add-ons-pro/deepl/includes/class-deepl-machine-translator.php:365353 #: includes/class-machine-translator.php:172, add-ons-pro/deepl/includes/class-deepl-machine-translator.php:365 354 354 msgid "Please enter your DeepL API key." 355 355 msgstr "" … … 567 567 msgstr "" 568 568 569 #: includes/class-settings.php:4 71569 #: includes/class-settings.php:486 570 570 msgid "Language codes can contain only A-Z a-z 0-9 - _ characters. Check your language codes in TranslatePress General Settings." 571 571 msgstr "" 572 572 573 #: includes/class-settings.php:5 34573 #: includes/class-settings.php:549 574 574 msgid "Error! Duplicate URL slug values." 575 575 msgstr "" 576 576 577 #: includes/class-settings.php:5 35577 #: includes/class-settings.php:550 578 578 msgid "You cannot select two languages that have the same <a href=\"https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\" target=\"_blank\">iso code</a> but different formalities because doing so will lead to duplicate <a href=\"https://developers.google.com/search/docs/specialty/international/localized-versions\" target=\"_blank\">hreflang tags</a>." 579 579 msgstr "" 580 580 581 #: includes/class-settings.php:5 36581 #: includes/class-settings.php:551 582 582 msgid "Duplicate language detected.<br>Each language can only be added once to ensure accurate translation management.<br> Please change the duplicate language entry and try again. " 583 583 msgstr "" 584 584 585 #: includes/class-settings.php: 593585 #: includes/class-settings.php:608 586 586 msgid "Current Language" 587 587 msgstr "" 588 588 589 #: includes/class-settings.php: 599589 #: includes/class-settings.php:614 590 590 msgid "Opposite Language" 591 591 msgstr "" 592 592 593 #: includes/class-settings.php:6 39593 #: includes/class-settings.php:654 594 594 msgid "General" 595 595 msgstr "" 596 596 597 #: includes/class-settings.php:6 44, includes/class-translation-manager.php:540, add-ons-pro/translator-accounts/includes/class-translator-accounts.php:156597 #: includes/class-settings.php:659, includes/class-translation-manager.php:540, add-ons-pro/translator-accounts/includes/class-translator-accounts.php:156 598 598 msgid "Translate Site" 599 599 msgstr "" 600 600 601 #: includes/class-settings.php:6 49601 #: includes/class-settings.php:664 602 602 msgid "Addons" 603 603 msgstr "" 604 604 605 #: includes/class-settings.php:6 57605 #: includes/class-settings.php:672 606 606 msgid "License" 607 607 msgstr "" 608 608 609 #: includes/class-settings.php:7 01, includes/class-translation-manager.php:572609 #: includes/class-settings.php:716, includes/class-translation-manager.php:572 610 610 msgid "Settings" 611 611 msgstr "" 612 612 613 #: includes/class-settings.php:7 15, partials/license-settings-page.php:29, includes/onboarding/class-autotranslation.php:169, includes/onboarding/class-license.php:131613 #: includes/class-settings.php:730, partials/license-settings-page.php:29, includes/onboarding/class-autotranslation.php:169, includes/onboarding/class-license.php:131 614 614 msgid "Activate License" 615 615 msgstr "" 616 616 617 #: includes/class-settings.php:7 07617 #: includes/class-settings.php:722 618 618 msgid "Pro Features" 619 619 msgstr "" -
translatepress-multilingual/tags/3.0.6/readme.txt
r3403492 r3420034 4 4 Tags: translate, translation, multilingual, automatic translation, bilingual, front-end translation, google translate, language 5 5 Requires at least: 3.1.0 6 Tested up to: 6. 8.36 Tested up to: 6.9 7 7 Requires PHP: 7.4 8 Stable tag: 3.0. 58 Stable tag: 3.0.6 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 143 143 144 144 == Changelog == 145 = 3.0.5 = 146 * Fixed CSS for Black Friday offer from admin notice 147 148 = 3.0.4 = 149 * Added 39 more languages including Irish, Maltese and Sicilian 150 * Added support for Latin American Spanish automatic translation in TranslatePress AI 151 * Added support for Divi search in secondary language 152 * Added support for exact match search in String Translation by placing the string in quotes: "example" 153 * Allow schema.org data to be translated 154 * Fixed Regular String Translation search so filtered languages also match terms appearing in the middle of translated strings, not only at the start 155 * Prevent automatic translation of strings that are 0 or 1 characters long or strings that are punctuation only 156 * Change background hover color for transparent preset in order to improve contrast of language switcher 157 * Fixed two missing spaces in floating switcher HTML markup 158 * Fix PHP warning with empty domain for gettext with context 159 * Fixed edge case error "call to a member function is_available() on null" 160 * Moved the "Automatically Translate Slug" setting to be first in line 161 * Extended the license message for item_name_mismatch to provide more context 162 * Improved text information next to the default language 163 145 = 3.0.6 = 146 * Extended support for Divi search in secondary languages 147 * Fixed redirect loop bug with excluded paths from translation 148 * Fixed incorrect gettext resolution in string translation when the site locale differed from the default TranslatePress language, which caused untranslated gettext entries to be populated using translations from the wrong locale 149 * Fixed edge case of retranslating the same text multiple times 150 * Fixed not detecting texts containing only certain special characters 151 * Fixed bug where mini cart menu widget doesn't respect language change 152 * Fixed edge case error "Call to a member function is_available() on null" 153 * Send emails in recipient's preferred language, in case the recipient is a user 154 * Improved INP by deferring dynamic translation detection when original content can be shown first 155 * Fixed a bug where the floating language switcher was not displaying all languages (if more than 10 were added and animations disabled) 156 * Disable language switcher show opposite language settings in case more than 2 languages are active 157 * Fixed deprecated notice for seems_utf8 function on WP 6.9 164 158 165 159 = Older versions = -
translatepress-multilingual/trunk/assets/js/trp-frontend-compatibility.js
r3288239 r3420034 3 3 4 4 // clear WooCommerce cart fragments when switching language 5 var trp_language_switcher_urls = document.querySelectorAll(".trp-language-switcher-container a:not(.trp-ls-disabled-language) ");5 var trp_language_switcher_urls = document.querySelectorAll(".trp-language-switcher-container a:not(.trp-ls-disabled-language), .trp-language-item:not(.trp-language-item__current)"); 6 6 7 7 for (i = 0; i < trp_language_switcher_urls.length; i++) { -
translatepress-multilingual/trunk/assets/js/trp-frontend-language-switcher.js
r3389452 r3420034 35 35 } 36 36 37 /** 38 * Returns true if the list has a non-zero transition duration (for any property). 39 * We use this to decide whether to rely on `transitionend` or fall back to sync behavior. 40 */ 41 _hasAnimatedTransition() { 42 if (!this.list) return false; 43 44 const cs = getComputedStyle(this.list); 45 const durationsRaw = cs.transitionDuration || ''; 46 47 if (!durationsRaw) return false; 48 49 const durations = durationsRaw 50 .split(',') 51 .map(str => parseFloat(str) || 0); 52 53 return durations.some(d => d > 0); 54 } 55 37 56 collapse() { 38 57 this.list.hidden = true; … … 66 85 } 67 86 68 setOpen(open, { source = null } = {}) { 69 if (!this.root || !this.list || open === this.isOpen) return; 70 71 // Honor reduced motion: skip the transition entirely (still class-driven) 87 setOpen( open, { source = null } = {} ) { 88 if ( !this.root || !this.list || open === this.isOpen ) return; 89 72 90 const prefersReduced = window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches; 91 const hasTransition = !prefersReduced && this._hasAnimatedTransition(); 73 92 74 93 this.isOpen = open; 75 94 76 if (open) { 77 // Prepare: must be visible for CSS transition to run 95 // No transitions (0s duration) OR reduced motion: do everything synchronously, 96 if ( !hasTransition ) { 97 if ( open ) { 98 this.list.hidden = false; 99 this.list.removeAttribute( 'inert' ); 100 this.setExpanded( true ); 101 102 this._pendingFocusOnOpen = ( source?.type === 'keydown' ); 103 if ( this._pendingFocusOnOpen ) { 104 this._pendingFocusOnOpen = false; 105 const first = this.list.querySelector( 106 '[role="option"], a, button, [tabindex]:not([tabindex="-1"])' 107 ); 108 first?.focus?.({ preventScroll: true }); 109 } 110 } else { 111 this.setExpanded( false ); 112 this.list.hidden = true; 113 this.list.setAttribute( 'inert', '' ); 114 this._pendingFocusOnOpen = false; 115 } 116 return; 117 } 118 119 // Animated path: rely on transitionend to remove .is-transitioning 120 if ( open ) { 121 // Must be visible for CSS transition to run 78 122 this.list.hidden = false; 79 this.list.removeAttribute('inert'); 80 81 if (prefersReduced) { 82 this.root.classList.remove('is-transitioning'); 83 this.setExpanded(true); 84 } else { 85 this.root.classList.add('is-transitioning'); 86 // Next frame so the browser registers the pre-open (max-height:0) state 87 requestAnimationFrame(() => this.setExpanded(true)); 88 } 89 90 // keyboard open should move focus after transition completes 91 this._pendingFocusOnOpen = (source?.type === 'keydown'); 92 123 this.list.removeAttribute( 'inert' ); 124 125 this._pendingFocusOnOpen = ( source?.type === 'keydown' ); 126 127 this.root.classList.add( 'is-transitioning' ); 128 // Next frame so browser registers pre-open (max-height: 0) state 129 requestAnimationFrame( () => this.setExpanded( true ) ); 93 130 } else { 94 if (prefersReduced){ 95 this.root.classList.add( 'is-transitioning' ); 96 } 97 98 this.setExpanded(false); 131 this.root.classList.add( 'is-transitioning' ); 132 this.setExpanded( false ); 99 133 } 100 134 } -
translatepress-multilingual/trunk/assets/js/trp-translate-dom-changes.js
r3288239 r3420034 468 468 469 469 // create an observer instance 470 observer = new MutationObserver( _this.detect_new_strings_callback ); 470 if ( trp_data['showdynamiccontentbeforetranslation'] === true ){ 471 observer = new MutationObserver(mutations => { 472 setTimeout(() => _this.detect_new_strings_callback(mutations), 0); 473 }); 474 } 475 476 else { 477 observer = observer = new MutationObserver(_this.detect_new_strings_callback) 478 } 471 479 472 480 _this.resume_observer(); -
translatepress-multilingual/trunk/changelog.txt
r3403492 r3420034 1 = 3.0.5 = 2 * Fixed CSS for Black Friday offer from admin notice 3 4 = 3.0.4 = 5 * Added 39 more languages including Irish, Maltese and Sicilian 6 * Added support for Latin American Spanish automatic translation in TranslatePress AI 7 * Added support for Divi search in secondary language 8 * Added support for exact match search in String Translation by placing the string in quotes: "example" 9 * Allow schema.org data to be translated 10 * Fixed Regular String Translation search so filtered languages also match terms appearing in the middle of translated strings, not only at the start 11 * Prevent automatic translation of strings that are 0 or 1 characters long or strings that are punctuation only 12 * Change background hover color for transparent preset in order to improve contrast of language switcher 13 * Fixed two missing spaces in floating switcher HTML markup 14 * Fix PHP warning with empty domain for gettext with context 15 * Fixed edge case error "call to a member function is_available() on null" 16 * Moved the "Automatically Translate Slug" setting to be first in line 17 * Extended the license message for item_name_mismatch to provide more context 18 * Improved text information next to the default language 19 1 20 = 3.0.3 = 2 21 * Fixed an issue introduced in the previous update that occurred when using Google Translate as the translation engine -
translatepress-multilingual/trunk/class-translate-press.php
r3403492 r3420034 68 68 */ 69 69 public function __construct() { 70 // Early bind to break recursion loop caused by calling get_trp_instance during construction 71 if ( self::$translate_press === null ) { 72 self::$translate_press = $this; 73 } 74 70 75 define( 'TRP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 71 76 define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); 72 77 define( 'TRP_PLUGIN_BASE', plugin_basename( __DIR__ . '/index.php' ) ); 73 78 define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' ); 74 define( 'TRP_PLUGIN_VERSION', '3.0. 5' );79 define( 'TRP_PLUGIN_VERSION', '3.0.6' ); 75 80 76 81 wp_cache_add_non_persistent_groups(array('trp')); … … 103 108 require_once TRP_PLUGIN_DIR . 'includes/class-editor-api-regular-strings.php'; 104 109 require_once TRP_PLUGIN_DIR . 'includes/class-editor-api-gettext-strings.php'; 105 require_once TRP_PLUGIN_DIR . 'includes/class-translation-manager.php';106 110 require_once TRP_PLUGIN_DIR . 'includes/class-hooks-loader.php'; 107 111 require_once TRP_PLUGIN_DIR . 'includes/class-languages.php'; … … 180 184 $this->query = new TRP_Query( $this->settings->get_settings() ); 181 185 $this->machine_translator_logger = new TRP_Machine_Translator_Logger( $this->settings->get_settings() ); 186 $this->machine_translator = new TRP_Machine_Translator( $this->settings->get_settings() ); // Will be overwritten in init_machine_translation with the actual machine translator class. Use this as replacement until then. 182 187 $this->translation_manager = new TRP_Translation_Manager( $this->settings->get_settings() ); 183 188 $this->editor_api_regular_strings = new TRP_Editor_Api_Regular_Strings( $this->settings->get_settings() ); -
translatepress-multilingual/trunk/includes/advanced-settings/do-not-translate-certain-paths.php
r3328103 r3420034 490 490 return $excluded; 491 491 } 492 493 /** 494 * Check if the current URL is excluded from translation based on the 495 * "Do not translate certain paths" / "Translate only certain paths" setting. 496 * 497 * Takes into account: 498 * - site installed in subdirectory 499 * - "Use a subdirectory for the default language" 500 * - {{home}} mapping 501 * - both "exclude" and "include" modes 502 * 503 * @return bool True if the current URL should be treated as excluded from translation. 504 */ 505 function trp_dntcp_is_current_url_excluded() { 506 if ( is_admin() ) { 507 return false; 508 } 509 510 $settings = get_option( 'trp_settings', false ); 511 $advanced_settings = get_option( 'trp_advanced_settings', false ); 512 513 // No configuration -> nothing is excluded. 514 if ( empty( $advanced_settings ) 515 || ! isset( $advanced_settings['translateable_content'] ) 516 || empty( $advanced_settings['translateable_content']['paths'] ) 517 || empty( $advanced_settings['translateable_content']['option'] ) ) { 518 return false; 519 } 520 521 $mode = $advanced_settings['translateable_content']['option']; // 'exclude' or 'include' 522 $paths = trp_dntcp_get_paths(); 523 524 // Build current slug in the same way as trp_exclude_include_paths_to_run_on() 525 $trp = TRP_Translate_Press::get_trp_instance(); 526 $url_converter = $trp->get_component( 'url_converter' ); 527 528 $current_lang = $url_converter->get_lang_from_url_string( $url_converter->cur_page_url() ); 529 if ( empty( $current_lang ) && isset( $settings['default-language'] ) ) { 530 $current_lang = $settings['default-language']; 531 } 532 533 $site_url_components = parse_url( get_home_url() ); 534 $current_slug = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( $_SERVER['REQUEST_URI'] ) : ''; 535 536 // Remove site_url path for installs in subdirectories (e.g. http://localhost/wordpress) 537 if ( isset( $site_url_components['path'] ) && $site_url_components['path'] !== '' ) { 538 $current_slug = str_replace( trim( $site_url_components['path'] ), '', $current_slug ); 539 } 540 541 // Take into account subdirectory for the default language or other languages. 542 // This mirrors the logic used in trp_exclude_include_paths_to_run_on(). 543 if ( isset( $settings['add-subdirectory-to-default-language'] ) 544 && $settings['add-subdirectory-to-default-language'] === 'yes' 545 && ! empty( $current_lang ) 546 && isset( $settings['url-slugs'][ $current_lang ] ) ) { 547 548 $replace = '\/' . $settings['url-slugs'][ $current_lang ]; 549 $current_slug = preg_replace( "/$replace/i", '', ltrim( $current_slug, '/' ), 1 ); 550 } 551 552 $array_slugs = array(); 553 trp_test_current_slug( $current_slug, $array_slugs ); 554 555 $matched = trp_return_exclude_include_url( $paths, $current_slug, $array_slugs ); 556 557 // In "exclude" mode: listed paths are excluded. 558 if ( $mode === 'exclude' ) 559 return (bool) $matched; 560 561 // In "include" mode: ONLY listed paths are translatable; all others are excluded 562 if ( $mode === 'include' ) 563 return !$matched; 564 565 return false; 566 } -
translatepress-multilingual/trunk/includes/class-language-switcher-v2.php
r3389452 r3420034 130 130 131 131 $allow = apply_filters('trp_allow_language_redirect', true, $needed_lang, $this->url_converter->cur_page_url()); 132 if (!$allow) return; 132 133 if ( !$allow || trp_dntcp_is_current_url_excluded() ) 134 return; 133 135 134 136 $missing_in_url = ($lang_from_url === null); -
translatepress-multilingual/trunk/includes/class-languages.php
r3398116 r3420034 41 41 */ 42 42 public function change_locale( $locale ){ 43 44 if ( $this->is_string_translation_request_for_different_language() ){45 $trp_ajax_language = (isset($_POST['trp_ajax_language']) ) ? sanitize_text_field( $_POST['trp_ajax_language'] ) : '';46 if ( !$this->settings ){47 $trp = TRP_Translate_Press::get_trp_instance();48 $trp_settings = $trp->get_component( 'settings' );49 $this->settings = $trp_settings->get_settings();50 }51 if ( $trp_ajax_language && in_array( $trp_ajax_language, $this->settings['translation-languages'] ) ){52 return $trp_ajax_language;53 }54 }55 56 43 if ( $this->is_admin_request === null ){ 57 44 $trp = TRP_Translate_Press::get_trp_instance(); … … 70 57 return $locale; 71 58 } 72 73 public function is_string_translation_request_for_different_language(){74 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {75 $action = 'trp_string_translation_get_missing_gettext_strings';76 if ( isset( $_POST['action'] ) && $_POST['action'] === $action ) {77 return true;78 }79 }80 return false;81 }82 59 83 60 /** -
translatepress-multilingual/trunk/includes/class-machine-translator.php
r3398116 r3420034 48 48 * @return bool 49 49 */ 50 public function is_available( $languages = array() ){ 51 if( !empty( $this->settings['trp_machine_translation_settings']['machine-translation'] ) && 52 $this->settings['trp_machine_translation_settings']['machine-translation'] == 'yes' 53 ) { 54 if ( empty( $languages ) ){ 55 // can be used to simply know if machine translation is available 50 public function is_available( $languages = array() ) { 51 /** 52 * Return false in case it was directly called from parent and not from a derived class (DeepL / Google / TPAI) 53 * Calling this method on the parent class means it was called too early and machine translation is not available at this point 54 */ 55 if ( get_class( $this ) === __CLASS__ ) 56 return false; 57 58 $settings = $this->settings['trp_machine_translation_settings'] ?? array(); 59 $enabled = ( $settings['machine-translation'] ?? '' ) === 'yes'; 60 $is_available = false; 61 62 if ( $enabled ) { 63 $engine = $settings['translation-engine'] ?? null; 64 65 if ( $engine === 'deepl' && get_option( 'trp_license_status' ) !== 'valid' ) { 66 $is_available = false; 67 } elseif ( empty( $languages ) ) { 56 68 $is_available = true; 57 } 58 59 // If the license is invalid and the translation engine is DeepL,return false 60 $license_status = get_option( 'trp_license_status' ); 61 if ( $license_status !== 'valid' && isset( $this->settings['trp_machine_translation_settings']['translation-engine'] ) && $this->settings['trp_machine_translation_settings']['translation-engine'] === 'deepl' ) { 62 $is_available = false; 63 } 64 65 $is_available = $this->check_languages_availability($languages); 66 67 }else { 68 $is_available = false; 69 } 70 71 return apply_filters('trp_machine_translator_is_available', $is_available); 69 } else { 70 $is_available = $this->check_languages_availability( $languages ); 71 } 72 } 73 74 return apply_filters( 'trp_machine_translator_is_available', $is_available, $languages, $settings ); 72 75 } 73 76 -
translatepress-multilingual/trunk/includes/class-settings.php
r3377320 r3420034 329 329 330 330 unset($settings['translation-languages-formality']); 331 332 $trp = TRP_Translate_Press::get_trp_instance(); 333 $language_switcher_tab = $trp->get_component('language_switcher_tab'); 334 335 if ( !$language_switcher_tab->is_legacy_enabled() && count( $settings['publish-languages'] ) > 2 ) { 336 $ls_settings = $language_switcher_tab->get_initial_config(); 337 $new_ls_settings = $ls_settings; 338 339 $new_ls_settings['floater']['oppositeLanguage'] = false; 340 $new_ls_settings['shortcode']['oppositeLanguage'] = false; 341 342 if ( $new_ls_settings !== $ls_settings ){ 343 update_option( 'trp_language_switcher_settings', $new_ls_settings ); 344 } 345 } 331 346 332 347 // check for duplicates in url slugs -
translatepress-multilingual/trunk/includes/class-translation-render.php
r3398116 r3420034 1020 1020 $translated_strings_manual = array(); 1021 1021 foreach ( $translateable_strings_manual as $i => $string_manual ) { 1022 if ( isset( $translated_strings_manual_dictionary[ $string_manual ]->translated ) ) {1022 if ( isset( $translated_strings_manual_dictionary[ $string_manual ]->translated ) && !empty( $translated_strings_manual_dictionary[ $string_manual ]->translated )) { 1023 1023 $translated_strings_manual[$i] = $translated_strings_manual_dictionary[ $string_manual ]->translated; 1024 1024 } … … 1686 1686 1687 1687 foreach ( $translateable_strings as $i => $string ) { 1688 1688 if ( isset( $dictionary[ $string ]->translated ) && empty( $dictionary[ $string ]->translated ) ) { 1689 /* If we have an empty string with a status != NOT TRANSLATED, it's possible we are dealing with 1690 * an intentional thing. After Automatic translation, a text can be translated with unallowed html 1691 * thus being stored in DB as empty string with status = MACHINE TRANSLATED. By doing continue; we avoid 1692 * re-autotranslating over and over again. 1693 */ 1694 continue; 1695 } 1689 1696 // prevent accidentally machine translated strings from db such as for src to be displayed 1690 1697 $skip_string = in_array( $string, $skip_machine_translating_strings ); … … 1763 1770 1764 1771 if ( !isset($translated_strings[$i]) && isset( $machine_strings[$string] ) ) { 1765 $translated_strings[$i] = $machine_strings[$string]; 1772 $sanitized_machine_string = trp_sanitize_string( $machine_strings[$string] ); 1773 if ( !empty( $sanitized_machine_string ) ){ 1774 // Unallowed HTML can be turned into empty string. Show original text instead 1775 $translated_strings[$i] = $sanitized_machine_string; 1776 } 1766 1777 } 1767 1778 … … 2080 2091 * @return array 2081 2092 */ 2082 public function wp_mail_filter( $args ) {2083 if ( ! is_array( $args ) ){2093 public function wp_mail_filter( $args ) { 2094 if ( ! is_array( $args ) ) { 2084 2095 return $args; 2085 2096 } 2086 2097 2087 $whitelisted_shortcodes = apply_filters( 'trp_whitelisted_shortcodes_for_wp_mail', [ 'trp_language', 'language-include', 'language-exclude' ] ); 2088 2089 if ( array_key_exists( 'subject', $args ) ){ 2090 $args['subject'] = $this->translate_page( trp_do_these_shortcodes( $args['subject'], $whitelisted_shortcodes ) ); 2091 } 2092 2093 if ( array_key_exists( 'message', $args ) ){ 2094 $args['message'] = $this->translate_page( trp_do_these_shortcodes( $args['message'], $whitelisted_shortcodes ) ); 2095 } 2098 if ( empty( $args['to'] ) ) { 2099 return $args; 2100 } 2101 2102 global $TRP_LANGUAGE; 2103 2104 $initial_language = $TRP_LANGUAGE; 2105 2106 $recipient = $args['to']; 2107 2108 // Normalize $recipient to a single email string (first recipient only - that's the main one) 2109 if ( is_array( $recipient ) ) { 2110 $first = reset( $recipient ); 2111 $recipient = is_string( $first ) ? $first : ''; 2112 } 2113 2114 $recipient = (string) $recipient; 2115 2116 // Keep only the first comma-separated entry if multiple are present in the string 2117 $recipient = trim( strtok( $recipient, ',' ) ); 2118 2119 if ( $recipient !== '' ) { 2120 trp_switch_to_preffered_language( $recipient ); 2121 } 2122 2123 $whitelisted_shortcodes = apply_filters( 2124 'trp_whitelisted_shortcodes_for_wp_mail', 2125 array( 'trp_language', 'language-include', 'language-exclude' ) 2126 ); 2127 2128 if ( array_key_exists( 'subject', $args ) ) { 2129 $args['subject'] = $this->translate_page( 2130 trp_do_these_shortcodes( $args['subject'], $whitelisted_shortcodes ) 2131 ); 2132 } 2133 2134 if ( array_key_exists( 'message', $args ) ) { 2135 $args['message'] = $this->translate_page( 2136 trp_do_these_shortcodes( $args['message'], $whitelisted_shortcodes ) 2137 ); 2138 } 2139 2140 // Switch back to the language used initially 2141 $TRP_LANGUAGE = $initial_language; 2096 2142 2097 2143 return $args; -
translatepress-multilingual/trunk/includes/class-woocommerce-emails.php
r3398116 r3420034 187 187 } 188 188 189 $trp_settings = TRP_Translate_Press::get_trp_instance()->get_component( 'settings' ); 190 $settings = $trp_settings->get_settings(); 191 192 $default_language = $settings["default-language"]; 193 189 194 /** 190 195 * At this point in the execution, $wc_email->get_recipient() returns null and throws a PHP warning inside WooCommerce /woocommerce/includes/emails/class-wc-email.php … … 224 229 $registered_user = get_user_by( 'email', $recipients[0] ); 225 230 if( $registered_user ){ 226 // If language is set to site default, user object won't have a locale set. Fallback to WPLANG. In case WPLANG is not set either, fallback to trp_language231 // If language is set to site default, user object won't have a locale set. Fallback to WPLANG. In case WPLANG is not set either, fallback to default language 227 232 if ( !empty( $registered_user->locale ) ){ 228 233 $language = $registered_user->locale; 229 234 } else { 230 $language = get_option( 'WPLANG' ) ?? get_user_meta( $registered_user->ID, 'trp_language', true ); 235 $wplang = get_option( 'WPLANG' ); 236 $language = !empty( $wplang ) ? $wplang : $default_language; 231 237 } 232 238 } else { … … 243 249 trp_switch_language( $language ); 244 250 245 WC()->load_plugin_textdomain(); 246 247 $this->bootstrap_trp_gettext_for_email_language( $language ); 251 add_filter( 'trp_allow_gettext_write', '__return_true' ); 252 253 $this->reload_woocommerce_textdomain(); 254 255 $this->bootstrap_trp_gettext_for_emails(); 248 256 249 257 // calls necessary because the default additional_content field of an email is localized before this point and stored in a variable in the previous locale … … 264 272 265 273 trp_restore_language(); 266 WC()->load_plugin_textdomain();274 $this->reload_woocommerce_textdomain(); 267 275 268 276 return false; … … 289 297 * gettext translations stored in TranslatePress are applied correctly. 290 298 */ 291 private function bootstrap_trp_gettext_for_email _language( $language) {299 private function bootstrap_trp_gettext_for_emails() { 292 300 $trp = TRP_Translate_Press::get_trp_instance(); 293 301 $gettext_manager = $trp->get_component( 'gettext_manager' ); … … 308 316 } 309 317 318 function reload_woocommerce_textdomain() { 319 $domain = 'woocommerce'; 320 321 $locale = apply_filters( 'plugin_locale', get_locale(), $domain ); 322 323 $custom_translation_path = WP_LANG_DIR . '/woocommerce/woocommerce-' . $locale . '.mo'; 324 $global_translation_path = WP_LANG_DIR . '/plugins/woocommerce-' . $locale . '.mo'; 325 $bundled_translation_path = trailingslashit( WC()->plugin_path() ) . 'i18n/languages/woocommerce-' . $locale . '.mo'; 326 327 unload_textdomain( $domain ); 328 329 // Custom file present: mimic WC 330 if ( is_readable( $custom_translation_path ) ) { 331 load_textdomain( $domain, $custom_translation_path ); 332 333 if ( is_readable( $global_translation_path ) ) { 334 load_textdomain( $domain, $global_translation_path ); 335 } 336 337 return true; 338 } 339 340 if ( is_readable( $global_translation_path ) ) { 341 load_textdomain( $domain, $global_translation_path ); 342 return true; 343 } 344 345 if ( is_readable( $bundled_translation_path ) ) { 346 load_textdomain( $domain, $bundled_translation_path ); 347 return true; 348 } 349 350 return false; 351 } 352 310 353 } -
translatepress-multilingual/trunk/includes/compatibility-functions.php
r3398116 r3420034 2709 2709 2710 2710 /** 2711 * Override the wrap_with_post_id condition for Divi 2712 * 2713 * Divi doesn't use the main loop in the traditional way, so we need to override 2714 * the condition that checks for in_the_loop and is_main_query. 2715 * 2716 * @param bool $return Whether to bypass the wrap condition 2717 * @return bool 2718 */ 2719 add_filter('trp_wrap_with_post_id_overrule', 'trp_divi_override_wrap_condition', 10); 2720 function trp_divi_override_wrap_condition($return) { 2721 // Check if Divi is the active theme 2722 if (function_exists('et_setup_theme')) { 2723 // Return false to bypass the in_the_loop check 2724 return false; 2725 } 2726 return $return; 2727 } 2711 * Add trp-post-container wrapper to Divi module outputs 2712 * TP is not adding any trp-post-container except here. 2713 * 2714 * @param string $output The module HTML output 2715 * @param string $render_slug The module slug (e.g., 'et_pb_text', 'et_pb_post_title') 2716 * @param object $module The module object 2717 * @return string Modified output with trp-post-container wrapper 2718 */ 2719 add_filter('et_module_shortcode_output', 'trp_divi_wrap_module_with_post_id', 10, 3); 2720 2721 function trp_divi_wrap_module_with_post_id($output, $render_slug, $module) { 2722 global $post, $TRP_LANGUAGE; 2723 2724 // Check if we have a valid post ID 2725 if (empty($post->ID)) { 2726 return $output; 2727 } 2728 2729 // Get TranslatePress settings 2730 $trp = TRP_Translate_Press::get_trp_instance(); 2731 $trp_settings = $trp->get_component('settings'); 2732 $settings = $trp_settings->get_settings(); 2733 2734 // Only wrap on non-default language 2735 if ($TRP_LANGUAGE !== $settings['default-language']) { 2736 // Only wrap modules that typically contain translatable text content 2737 $modules_to_wrap = apply_filters('trp_divi_modules_to_wrap', array( 2738 'et_pb_text', 2739 'et_pb_post_title', 2740 'et_pb_post_content', 2741 'et_pb_blurb', 2742 'et_pb_cta', 2743 'et_pb_accordion', 2744 'et_pb_toggle', 2745 'et_pb_tabs', 2746 'et_pb_testimonial', 2747 'et_pb_pricing_tables', 2748 'et_pb_number_counter', 2749 'et_pb_countdown_timer' 2750 )); 2751 2752 if (in_array($render_slug, $modules_to_wrap)) { 2753 $output = "<trp-post-container data-trp-post-id='" . $post->ID . "'>" . $output . "</trp-post-container>"; 2754 } 2755 } 2756 2757 return $output; 2758 } -
translatepress-multilingual/trunk/includes/external-functions.php
r3288239 r3420034 64 64 } 65 65 66 if ( strip_tags( $string ) === '' || trim ($string, $filter_string) === '' ){ 67 $string = ''; 68 } 66 if ( strip_tags( $string ) === '' || trim( $string, $filter_string ) === '' ) { 67 // Needs decoding otherwise some strings with special characters won't get detected. 68 // Example in Hebrew: אוכל ותרבות 69 // Placed inside the "if" to avoid calling html_entity_decode so often as this is a very used function 70 $decoded_string = html_entity_decode( $string ); 71 if ( trim( $decoded_string, $filter_string ) === '' ) { 72 $string = ''; 73 } 74 } 69 75 return $string; 70 76 } -
translatepress-multilingual/trunk/includes/functions.php
r3349766 r3420034 274 274 return $string; 275 275 276 if (seems_utf8($string)) { 276 $seems_utf = ( function_exists( 'wp_is_valid_utf8' ) ) ? wp_is_valid_utf8( $string ) : seems_utf8( $string ); 277 278 if ( $seems_utf ) { 277 279 $chars = array( 278 280 // Decompositions for Latin-1 Supplement … … 821 823 822 824 /** 825 * Switch to a user's preferred language based on the recipient email. 826 * 827 * For managerial users (admin-like roles), prefer user->locale with fallback 828 * to WPLANG, then trp_language. 829 * 830 * For non-managerial users, prefer trp_language, with fallback to locale, then WPLANG. 831 * 832 * @param string $email 833 * @return void 834 */ 835 function trp_switch_to_preffered_language( $email ) { 836 $email = trim( (string) $email ); 837 838 if ( $email === '' ) 839 return; 840 841 $user = get_user_by( 'email', $email ); 842 843 if ( ! ( $user instanceof WP_User ) ) 844 return; 845 846 $user_roles = is_array( $user->roles ) ? $user->roles : array(); 847 848 $trp_settings = TRP_Translate_Press::get_trp_instance()->get_component( 'settings' ); 849 $settings = $trp_settings->get_settings(); 850 851 $default_language = $settings["default-language"]; 852 853 /** 854 * Roles considered "managerial" for email language purposes. 855 * 856 * @param string[] $roles 857 */ 858 $managerial_roles = apply_filters( 859 'trp_managerial_roles_for_email_language', 860 [ 'administrator', 'editor', 'shop_manager' ] 861 ); 862 863 $is_managerial = !empty( array_intersect( $managerial_roles, $user_roles ) ); 864 865 if ( $is_managerial ) { 866 // Managerial: prefer locale, then WPLANG, then default_language 867 if ( !empty( $user->locale ) ) { 868 $language = $user->locale; 869 } else { 870 $wplang = get_option( 'WPLANG' ); 871 $language = !empty( $wplang ) ? $wplang : $default_language; 872 } 873 } else { 874 // Non-managerial: prefer trp_language. 875 $language = get_user_meta( $user->ID, 'trp_language', true ); 876 877 if ( empty( $language ) ) { 878 if ( !empty( $user->locale ) ) { 879 $language = $user->locale; 880 } else { 881 $wplang = get_option( 'WPLANG' ); 882 $language = !empty( $wplang ) ? $wplang : $default_language; 883 } 884 } 885 } 886 887 if ( empty( $language ) ) 888 return; 889 890 trp_switch_language( $language ); 891 } 892 893 /** 823 894 * Return $TRP_LANGUAGE as plugin locale 824 895 * -
translatepress-multilingual/trunk/includes/gettext/class-gettext-manager.php
r3374439 r3420034 488 488 */ 489 489 public function add_missing_language_file_translations( $dictionary, $language ) { 490 491 $trp_plural_forms = $this->get_gettext_component( 'plural_forms' ); 490 // Ensure translation files are loaded with the correct locale 491 $locale = determine_locale(); 492 $switched = switch_to_locale( $language ); 493 494 // This means that the language is not supported by WordPress. Either a custom language or a language that we support but WordPress does not. 495 if ( !$switched && $language !== $locale ) 496 return; 497 498 $trp_plural_forms = $this->get_gettext_component( 'plural_forms' ); 492 499 if ( ! $this->trp_query ) { 493 500 $trp = TRP_Translate_Press::get_trp_instance(); … … 611 618 $gettext_insert_update->insert_gettext_strings($insert_gettext_strings, $language); 612 619 $gettext_insert_update->update_gettext_strings($update_gettext_strings, $language, array('translated', 'id', 'status')); 620 621 if ( $switched ) 622 restore_previous_locale(); 613 623 } 614 624 } -
translatepress-multilingual/trunk/includes/queries/class-query.php
r3288239 r3420034 97 97 $and_block_type = " AND block_type = " . $block_type; 98 98 } 99 $query = "SELECT original,translated, status FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE status != " . self::NOT_TRANSLATED . $and_block_type . " AND translated <>'' AND original IN "; 99 100 /* Do not add a condition for "translated <> '' because this would cause re-autotranslating. */ 101 $query = "SELECT original,translated, status FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE status != " . self::NOT_TRANSLATED . $and_block_type . " AND original IN "; 100 102 101 103 $placeholders = array(); … … 108 110 $query .= "( " . implode ( ", ", $placeholders ) . " )"; 109 111 $prepared_query = $this->db->prepare( $query, $values ); 110 $dictionary = $this->db->get_results( $prepared_query, OBJECT_K ); 111 112 $results = $this->db->get_results( $prepared_query, OBJECT ); 113 114 if ( !empty( $results ) && is_array( $results ) ) { 115 // There are edge cases where we have 2 results for the same original: 116 // one with translated as empty string, one with non-empty translation. Keep the one with translation. 117 $dictionary = []; 118 foreach ( $results as $row ) { 119 $key = $row->original; 120 121 // If this key has never been added, simply add it 122 if ( !isset( $dictionary[ $key ] ) ) { 123 $dictionary[ $key ] = $row; 124 continue; 125 } 126 127 // If current stored entry has empty 'translated' 128 // and this new row has non-empty 'translated', replace it 129 if ( 130 empty( $dictionary[ $key ]->translated ) && 131 !empty( $row->translated ) 132 ) { 133 $dictionary[ $key ] = $row; 134 } 135 136 // Otherwise do nothing — we keep the existing "better" record 137 } 138 } else { 139 $dictionary = $results; 140 } 112 141 113 142 -
translatepress-multilingual/trunk/index.php
r3403492 r3420034 4 4 Plugin URI: https://translatepress.com/ 5 5 Description: Experience a better way of translating your WordPress site using a visual front-end translation editor, with full support for WooCommerce and site builders. 6 Version: 3.0. 56 Version: 3.0.6 7 7 Author: Cozmoslabs, Razvan Mocanu, Madalin Ungureanu, Cristophor Hurduban 8 8 Author URI: https://cozmoslabs.com/ … … 11 11 License: GPL2 12 12 WC requires at least: 2.5.0 13 WC tested up to: 10. 3.513 WC tested up to: 10.4.2 14 14 15 15 == Copyright == -
translatepress-multilingual/trunk/languages/translatepress-multilingual.pot
r3403492 r3420034 7 7 "Content-Type: text/plain; charset=UTF-8\n" 8 8 "Content-Transfer-Encoding: 8bit\n" 9 "POT-Creation-Date: 2025-1 1-26 15:19+0000\n"9 "POT-Creation-Date: 2025-12-15 11:13+0000\n" 10 10 "X-Poedit-Basepath: ..\n" 11 11 "X-Poedit-KeywordsList: __;_e;_ex:1,2c;_n:1,2;_n_noop:1,2;_nx:1,2,4c;_nx_noop:1,2,3c;_x:1,2c;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c\n" … … 319 319 msgstr "" 320 320 321 #: includes/class-language-switcher-v2.php:7 18321 #: includes/class-language-switcher-v2.php:720 322 322 msgid "Change language to %s" 323 323 msgstr "" … … 347 347 msgstr "" 348 348 349 #: includes/class-machine-translator.php:15 4, includes/google-translate/class-google-translate-v2-machine-translator.php:200349 #: includes/class-machine-translator.php:157, includes/google-translate/class-google-translate-v2-machine-translator.php:200 350 350 msgid "Please enter your Google Translate key." 351 351 msgstr "" 352 352 353 #: includes/class-machine-translator.php:1 69, add-ons-pro/deepl/includes/class-deepl-machine-translator.php:365353 #: includes/class-machine-translator.php:172, add-ons-pro/deepl/includes/class-deepl-machine-translator.php:365 354 354 msgid "Please enter your DeepL API key." 355 355 msgstr "" … … 567 567 msgstr "" 568 568 569 #: includes/class-settings.php:4 71569 #: includes/class-settings.php:486 570 570 msgid "Language codes can contain only A-Z a-z 0-9 - _ characters. Check your language codes in TranslatePress General Settings." 571 571 msgstr "" 572 572 573 #: includes/class-settings.php:5 34573 #: includes/class-settings.php:549 574 574 msgid "Error! Duplicate URL slug values." 575 575 msgstr "" 576 576 577 #: includes/class-settings.php:5 35577 #: includes/class-settings.php:550 578 578 msgid "You cannot select two languages that have the same <a href=\"https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\" target=\"_blank\">iso code</a> but different formalities because doing so will lead to duplicate <a href=\"https://developers.google.com/search/docs/specialty/international/localized-versions\" target=\"_blank\">hreflang tags</a>." 579 579 msgstr "" 580 580 581 #: includes/class-settings.php:5 36581 #: includes/class-settings.php:551 582 582 msgid "Duplicate language detected.<br>Each language can only be added once to ensure accurate translation management.<br> Please change the duplicate language entry and try again. " 583 583 msgstr "" 584 584 585 #: includes/class-settings.php: 593585 #: includes/class-settings.php:608 586 586 msgid "Current Language" 587 587 msgstr "" 588 588 589 #: includes/class-settings.php: 599589 #: includes/class-settings.php:614 590 590 msgid "Opposite Language" 591 591 msgstr "" 592 592 593 #: includes/class-settings.php:6 39593 #: includes/class-settings.php:654 594 594 msgid "General" 595 595 msgstr "" 596 596 597 #: includes/class-settings.php:6 44, includes/class-translation-manager.php:540, add-ons-pro/translator-accounts/includes/class-translator-accounts.php:156597 #: includes/class-settings.php:659, includes/class-translation-manager.php:540, add-ons-pro/translator-accounts/includes/class-translator-accounts.php:156 598 598 msgid "Translate Site" 599 599 msgstr "" 600 600 601 #: includes/class-settings.php:6 49601 #: includes/class-settings.php:664 602 602 msgid "Addons" 603 603 msgstr "" 604 604 605 #: includes/class-settings.php:6 57605 #: includes/class-settings.php:672 606 606 msgid "License" 607 607 msgstr "" 608 608 609 #: includes/class-settings.php:7 01, includes/class-translation-manager.php:572609 #: includes/class-settings.php:716, includes/class-translation-manager.php:572 610 610 msgid "Settings" 611 611 msgstr "" 612 612 613 #: includes/class-settings.php:7 15, partials/license-settings-page.php:29, includes/onboarding/class-autotranslation.php:169, includes/onboarding/class-license.php:131613 #: includes/class-settings.php:730, partials/license-settings-page.php:29, includes/onboarding/class-autotranslation.php:169, includes/onboarding/class-license.php:131 614 614 msgid "Activate License" 615 615 msgstr "" 616 616 617 #: includes/class-settings.php:7 07617 #: includes/class-settings.php:722 618 618 msgid "Pro Features" 619 619 msgstr "" -
translatepress-multilingual/trunk/readme.txt
r3403492 r3420034 4 4 Tags: translate, translation, multilingual, automatic translation, bilingual, front-end translation, google translate, language 5 5 Requires at least: 3.1.0 6 Tested up to: 6. 8.36 Tested up to: 6.9 7 7 Requires PHP: 7.4 8 Stable tag: 3.0. 58 Stable tag: 3.0.6 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 143 143 144 144 == Changelog == 145 = 3.0.5 = 146 * Fixed CSS for Black Friday offer from admin notice 147 148 = 3.0.4 = 149 * Added 39 more languages including Irish, Maltese and Sicilian 150 * Added support for Latin American Spanish automatic translation in TranslatePress AI 151 * Added support for Divi search in secondary language 152 * Added support for exact match search in String Translation by placing the string in quotes: "example" 153 * Allow schema.org data to be translated 154 * Fixed Regular String Translation search so filtered languages also match terms appearing in the middle of translated strings, not only at the start 155 * Prevent automatic translation of strings that are 0 or 1 characters long or strings that are punctuation only 156 * Change background hover color for transparent preset in order to improve contrast of language switcher 157 * Fixed two missing spaces in floating switcher HTML markup 158 * Fix PHP warning with empty domain for gettext with context 159 * Fixed edge case error "call to a member function is_available() on null" 160 * Moved the "Automatically Translate Slug" setting to be first in line 161 * Extended the license message for item_name_mismatch to provide more context 162 * Improved text information next to the default language 163 145 = 3.0.6 = 146 * Extended support for Divi search in secondary languages 147 * Fixed redirect loop bug with excluded paths from translation 148 * Fixed incorrect gettext resolution in string translation when the site locale differed from the default TranslatePress language, which caused untranslated gettext entries to be populated using translations from the wrong locale 149 * Fixed edge case of retranslating the same text multiple times 150 * Fixed not detecting texts containing only certain special characters 151 * Fixed bug where mini cart menu widget doesn't respect language change 152 * Fixed edge case error "Call to a member function is_available() on null" 153 * Send emails in recipient's preferred language, in case the recipient is a user 154 * Improved INP by deferring dynamic translation detection when original content can be shown first 155 * Fixed a bug where the floating language switcher was not displaying all languages (if more than 10 were added and animations disabled) 156 * Disable language switcher show opposite language settings in case more than 2 languages are active 157 * Fixed deprecated notice for seems_utf8 function on WP 6.9 164 158 165 159 = Older versions =
Note: See TracChangeset
for help on using the changeset viewer.