TranslatePress – Translate Multilingual sites - Version 1.4.0

Version Description

  • Added Enfold compatibility by increasing the template_include hook priority
  • Add the costa rica flag
  • Speed improvements by optimizing the full_trim function
  • Added compatibility for WooCommerce Invoices plugins
  • Fixed querying for dynamic strings in Translation Editor not bringing up translations for all languages
  • Fixed notice when gettext table is empty
  • Added function to display strings with bad encoding in Translation Editor
Download this release

Release Info

Developer madalin.ungureanu
Plugin Icon 128x128 TranslatePress – Translate Multilingual sites
Version 1.4.0
Comparing to
See all releases

Code changes from version 1.3.9 to 1.4.0

assets/css/trp-preview-iframe-style.css CHANGED
@@ -122,3 +122,33 @@ translate-press{
122
  .trp-icon.trp-split.trp-active-icon, .trp-icon.trp-split.trp-active-icon:hover{
123
  display: inline;
124
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  .trp-icon.trp-split.trp-active-icon, .trp-icon.trp-split.trp-active-icon:hover{
123
  display: inline;
124
  }
125
+
126
+ .trp-editor-notices{
127
+ font-family: inherit;
128
+ font-size: 13px;
129
+ font-style: inherit;
130
+ font-weight: inherit;
131
+ position:relative;
132
+ z-index: 99999;
133
+ width: 100%;
134
+ max-height: 200px;
135
+ overflow-y: auto;
136
+ background: #f1f1f1;
137
+ overflow-x: hidden;
138
+ }
139
+
140
+ .trp-notice{
141
+ background: #fff;
142
+ border-left: 4px solid #fff;
143
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
144
+ margin: 15px;
145
+ padding: 12px;
146
+ }
147
+
148
+ .trp-notice-warning {
149
+ border-left-color: #ffb900;
150
+ }
151
+
152
+ .trp-bad-encoded-strings-list{
153
+ padding-left: 15px;
154
+ }
assets/images/flags/es_CR.png ADDED
Binary file
assets/js/trp-translate-dom-changes.js CHANGED
@@ -17,12 +17,17 @@ function TRP_Translator(){
17
  * Ajax request to get translations for strings
18
  */
19
  this.ajax_get_translation = function( strings_to_query, url ) {
 
 
 
 
20
  jQuery.ajax({
21
  url: url,
22
  type: 'post',
23
  dataType: 'json',
24
  data: {
25
  action: 'trp_get_translations',
 
26
  security: trp_localized_text['gettranslationsnonce'],
27
  language: language_to_query,
28
  original_language: original_language,
@@ -68,26 +73,24 @@ function TRP_Translator(){
68
  */
69
  this.update_strings = function( response, strings_to_query ) {
70
  if ( response != null && response[language_to_query] != null ){
71
- var strings_to_store = {};
72
  for ( var j in strings_to_query ) {
73
  var queried_string = strings_to_query[j];
74
  var translation_found = false;
75
  var initial_value = queried_string.original;
76
  for( var i in response[language_to_query] ) {
77
- if ( typeof strings_to_store[language_to_query] == 'undefined' ){
78
- strings_to_store[language_to_query] = {};
79
- }
80
  var response_string = response[language_to_query][i];
81
  if (response_string.original.trim() == queried_string.original.trim()) {
82
- strings_to_store[language_to_query][j] = {};
83
- strings_to_store[language_to_query][j].id = response[language_to_query][i].id;
84
- strings_to_store[language_to_query][j].original = response[language_to_query][i].original;
85
- strings_to_store[language_to_query][j].translated = response[language_to_query][i].translated;
86
- strings_to_store[language_to_query][j].status = response[language_to_query][i].status;
87
- strings_to_store[language_to_query][j].jquery_object = jQuery( queried_string.node ).parent( 'translate-press' );
 
88
  if ( typeof parent.trpEditor !== 'undefined' ) {
89
- strings_to_store[language_to_query][j].jquery_object.attr('data-trp-translate-id', response[language_to_query][i].id);
90
- strings_to_store[language_to_query][j].jquery_object.attr('data-trp-node-type', 'Dynamic Added Strings');
91
  }
92
 
93
  if (response_string.translated != '' && language_to_query == current_language ) {
@@ -107,7 +110,8 @@ function TRP_Translator(){
107
  }
108
  // this should always be outside the for loop
109
  if ( typeof parent.trpEditor !== 'undefined' ) {
110
- parent.trpEditor.populate_strings( strings_to_store );
 
111
  if ( parent.trpEditor.trp_lister != null ) {
112
  parent.trpEditor.trp_lister.reload_list();
113
  }
17
  * Ajax request to get translations for strings
18
  */
19
  this.ajax_get_translation = function( strings_to_query, url ) {
20
+ var all_languages_true_false = 'false';
21
+ if ( typeof parent.trpEditor !== 'undefined' ) {
22
+ all_languages_true_false = 'true';
23
+ }
24
  jQuery.ajax({
25
  url: url,
26
  type: 'post',
27
  dataType: 'json',
28
  data: {
29
  action: 'trp_get_translations',
30
+ all_languages: all_languages_true_false,
31
  security: trp_localized_text['gettranslationsnonce'],
32
  language: language_to_query,
33
  original_language: original_language,
73
  */
74
  this.update_strings = function( response, strings_to_query ) {
75
  if ( response != null && response[language_to_query] != null ){
76
+ var dictionary = {};
77
  for ( var j in strings_to_query ) {
78
  var queried_string = strings_to_query[j];
79
  var translation_found = false;
80
  var initial_value = queried_string.original;
81
  for( var i in response[language_to_query] ) {
 
 
 
82
  var response_string = response[language_to_query][i];
83
  if (response_string.original.trim() == queried_string.original.trim()) {
84
+ // We use j instead of i index because the strings_to_query can contain duplicates and response cannot. We need duplicates to refer to different jQuery objects where the same string appears in different places on the page.
85
+ dictionary[j] = {};
86
+ dictionary[j].id = response[language_to_query][i].id;
87
+ dictionary[j].original = response[language_to_query][i].original;
88
+ dictionary[j].translated = response[language_to_query][i].translated;
89
+ dictionary[j].status = response[language_to_query][i].status;
90
+ dictionary[j].jquery_object = jQuery( queried_string.node ).parent( 'translate-press' );
91
  if ( typeof parent.trpEditor !== 'undefined' ) {
92
+ dictionary[j].jquery_object.attr('data-trp-translate-id', response[language_to_query][i].id);
93
+ dictionary[j].jquery_object.attr('data-trp-node-type', 'Dynamic Added Strings');
94
  }
95
 
96
  if (response_string.translated != '' && language_to_query == current_language ) {
110
  }
111
  // this should always be outside the for loop
112
  if ( typeof parent.trpEditor !== 'undefined' ) {
113
+ response[language_to_query] = dictionary;
114
+ parent.trpEditor.populate_strings( response );
115
  if ( parent.trpEditor.trp_lister != null ) {
116
  parent.trpEditor.trp_lister.reload_list();
117
  }
class-translate-press.php CHANGED
@@ -17,6 +17,7 @@ class TRP_Translate_Press{
17
  protected $url_converter;
18
  protected $languages;
19
  protected $slug_manager;
 
20
  public static $translate_press = null;
21
 
22
  /**
@@ -40,7 +41,7 @@ class TRP_Translate_Press{
40
  define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
41
  define( 'TRP_PLUGIN_BASE', plugin_basename( __DIR__ . '/index.php' ) );
42
  define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' );
43
- define( 'TRP_PLUGIN_VERSION', '1.3.9' );
44
 
45
  wp_cache_add_non_persistent_groups(array('trp'));
46
 
@@ -76,6 +77,7 @@ class TRP_Translate_Press{
76
  require_once TRP_PLUGIN_DIR . 'includes/class-query.php';
77
  require_once TRP_PLUGIN_DIR . 'includes/class-url-converter.php';
78
  require_once TRP_PLUGIN_DIR . 'includes/class-uri.php';
 
79
  require_once TRP_PLUGIN_DIR . 'includes/class-plugin-notices.php';
80
  require_once TRP_PLUGIN_DIR . 'includes/functions.php';
81
  require_once TRP_PLUGIN_DIR . 'assets/lib/simplehtmldom/simple_html_dom.php';
@@ -96,6 +98,7 @@ class TRP_Translate_Press{
96
  $this->machine_translator = new TRP_Machine_Translator( $this->settings->get_settings() );
97
  $this->translation_manager = new TRP_Translation_Manager( $this->settings->get_settings() );
98
  $this->notifications = new TRP_Trigger_Plugin_Notifications();
 
99
  }
100
 
101
  /**
@@ -119,6 +122,7 @@ class TRP_Translate_Press{
119
  $this->loader->add_action( 'wp_ajax_trp_save_translations', $this->translation_manager, 'save_translations' );
120
  $this->loader->add_action( 'wp_ajax_trp_create_translation_block', $this->translation_manager, 'create_translation_block' );
121
  $this->loader->add_action( 'init', $this->translation_manager, 'split_translation_block' );
 
122
 
123
 
124
  $this->loader->add_action( 'wp_ajax_trp_process_js_strings_in_translation_editor', $this->translation_render, 'process_js_strings_in_translation_editor' );
@@ -128,6 +132,9 @@ class TRP_Translate_Press{
128
 
129
  $this->loader->add_action( 'wp_ajax_trp_publish_language', $this->translation_manager, 'publish_language' );
130
 
 
 
 
131
  }
132
 
133
  /**
@@ -160,7 +167,7 @@ class TRP_Translate_Press{
160
 
161
 
162
  $this->loader->add_action( 'trp_head', $this->translation_manager, 'enqueue_scripts_and_styles' );
163
- $this->loader->add_filter( 'template_include', $this->translation_manager, 'translation_editor', 9999 );
164
  $this->loader->add_action( 'wp_enqueue_scripts', $this->translation_manager, 'enqueue_preview_scripts_and_styles' );
165
  $this->loader->add_action( 'admin_bar_menu', $this->translation_manager, 'add_shortcut_to_translation_editor', 90, 1 );
166
  $this->loader->add_action( 'admin_head', $this->translation_manager, 'add_styling_to_admin_bar_button', 10 );
@@ -194,7 +201,7 @@ class TRP_Translate_Press{
194
  $this->loader->add_filter( 'sanitize_title', $this->translation_manager, 'trp_sanitize_title', 1, 3 );
195
 
196
  /* define an update hook here */
197
- $this->loader->add_action( 'plugins_loaded', $this->query, 'check_for_necessary_updates', 10 );
198
 
199
  $this->loader->add_filter( 'trp_language_name', $this->languages, 'beautify_language_name', 10, 4 );
200
  $this->loader->add_filter( 'trp_languages', $this->languages, 'reorder_languages', 10, 2 );
17
  protected $url_converter;
18
  protected $languages;
19
  protected $slug_manager;
20
+ protected $upgrade;
21
  public static $translate_press = null;
22
 
23
  /**
41
  define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
42
  define( 'TRP_PLUGIN_BASE', plugin_basename( __DIR__ . '/index.php' ) );
43
  define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' );
44
+ define( 'TRP_PLUGIN_VERSION', '1.4.0' );
45
 
46
  wp_cache_add_non_persistent_groups(array('trp'));
47
 
77
  require_once TRP_PLUGIN_DIR . 'includes/class-query.php';
78
  require_once TRP_PLUGIN_DIR . 'includes/class-url-converter.php';
79
  require_once TRP_PLUGIN_DIR . 'includes/class-uri.php';
80
+ require_once TRP_PLUGIN_DIR . 'includes/class-upgrade.php';
81
  require_once TRP_PLUGIN_DIR . 'includes/class-plugin-notices.php';
82
  require_once TRP_PLUGIN_DIR . 'includes/functions.php';
83
  require_once TRP_PLUGIN_DIR . 'assets/lib/simplehtmldom/simple_html_dom.php';
98
  $this->machine_translator = new TRP_Machine_Translator( $this->settings->get_settings() );
99
  $this->translation_manager = new TRP_Translation_Manager( $this->settings->get_settings() );
100
  $this->notifications = new TRP_Trigger_Plugin_Notifications();
101
+ $this->upgrade = new TRP_Upgrade( $this->settings->get_settings() );
102
  }
103
 
104
  /**
122
  $this->loader->add_action( 'wp_ajax_trp_save_translations', $this->translation_manager, 'save_translations' );
123
  $this->loader->add_action( 'wp_ajax_trp_create_translation_block', $this->translation_manager, 'create_translation_block' );
124
  $this->loader->add_action( 'init', $this->translation_manager, 'split_translation_block' );
125
+ $this->loader->add_filter( 'trp_get_existing_translations', $this->translation_manager, 'display_possible_db_errors', 20, 3 );
126
 
127
 
128
  $this->loader->add_action( 'wp_ajax_trp_process_js_strings_in_translation_editor', $this->translation_render, 'process_js_strings_in_translation_editor' );
132
 
133
  $this->loader->add_action( 'wp_ajax_trp_publish_language', $this->translation_manager, 'publish_language' );
134
 
135
+ $this->loader->add_action( 'admin_menu', $this->upgrade, 'register_menu_page' );
136
+ $this->loader->add_action( 'admin_init', $this->upgrade, 'show_admin_notice' );
137
+
138
  }
139
 
140
  /**
167
 
168
 
169
  $this->loader->add_action( 'trp_head', $this->translation_manager, 'enqueue_scripts_and_styles' );
170
+ $this->loader->add_filter( 'template_include', $this->translation_manager, 'translation_editor', 99999 );
171
  $this->loader->add_action( 'wp_enqueue_scripts', $this->translation_manager, 'enqueue_preview_scripts_and_styles' );
172
  $this->loader->add_action( 'admin_bar_menu', $this->translation_manager, 'add_shortcut_to_translation_editor', 90, 1 );
173
  $this->loader->add_action( 'admin_head', $this->translation_manager, 'add_styling_to_admin_bar_button', 10 );
201
  $this->loader->add_filter( 'sanitize_title', $this->translation_manager, 'trp_sanitize_title', 1, 3 );
202
 
203
  /* define an update hook here */
204
+ $this->loader->add_action( 'plugins_loaded', $this->upgrade, 'check_for_necessary_updates', 10 );
205
 
206
  $this->loader->add_filter( 'trp_language_name', $this->languages, 'beautify_language_name', 10, 4 );
207
  $this->loader->add_filter( 'trp_languages', $this->languages, 'reorder_languages', 10, 2 );
includes/class-query.php CHANGED
@@ -31,20 +31,6 @@ class TRP_Query{
31
  $this->settings = $settings;
32
  }
33
 
34
- /**
35
- * Trim unwanted characters from string.
36
- *
37
- * @param string $string String to trim.
38
- * @return string Trimmed string.
39
- */
40
- protected function full_trim( $string ) {
41
- $trp = TRP_Translate_Press::get_trp_instance();
42
- if ( ! $this->translation_render ) {
43
- $this->translation_render = $trp->get_component( 'translation_render' );
44
- }
45
-
46
- return $this->translation_render->full_trim( $string );
47
- }
48
 
49
  /**
50
  * Return an array of all the active translation blocks
@@ -83,13 +69,13 @@ class TRP_Query{
83
  $values = array();
84
  foreach( $strings_array as $string ){
85
  $placeholders[] = '%s';
86
- $values[] = $this->full_trim( $string );
87
  }
88
 
89
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
90
  $prepared_query = $this->db->prepare( $query, $values );
91
  $dictionary = $this->db->get_results( $prepared_query, OBJECT_K );
92
- return apply_filters( 'trp_get_existing_translations', $dictionary, $prepared_query );
93
  }
94
 
95
  /**
@@ -228,31 +214,6 @@ class TRP_Query{
228
  }
229
  }
230
 
231
- /**
232
- * When changing plugin version, call certain database upgrade functions.
233
- *
234
- */
235
- public function check_for_necessary_updates(){
236
- $stored_database_version = get_option('trp_plugin_version');
237
- if( empty($stored_database_version) || version_compare( TRP_PLUGIN_VERSION, $stored_database_version, '>' ) ){
238
- $this->check_if_gettext_tables_exist();
239
- $this->check_for_block_type_column();
240
- }
241
-
242
- update_option( 'trp_plugin_version', TRP_PLUGIN_VERSION );
243
- }
244
-
245
- /**
246
- * Iterates over all languages to call gettext table checking
247
- */
248
- public function check_if_gettext_tables_exist(){
249
- if( !empty( $this->settings['translation-languages'] ) ){
250
- foreach( $this->settings['translation-languages'] as $site_language_code ){
251
- $this->check_gettext_table($site_language_code);
252
- }
253
- }
254
- }
255
-
256
  /**
257
  * Add block_type column to dictionary tables, if it doesn't exist.
258
  *
@@ -306,18 +267,20 @@ class TRP_Query{
306
  /**
307
  * Insert translations and new strings in DB.
308
  *
309
- * @param array $new_strings Array of strings for which we do not have a translation. Only inserts original.
310
- * @param array $update_strings Array of arrays, each containing an entry to update.
311
- * @param string $language_code Language code of table where it should be inserted.
312
- */
313
- public function insert_strings( $new_strings, $update_strings, $language_code, $block_type = self::BLOCK_TYPE_REGULAR_STRING ){
314
- if ( $block_type == null ){
315
- $block_type = self::BLOCK_TYPE_REGULAR_STRING;
316
- }
317
- if ( count( $new_strings ) == 0 && count( $update_strings ) == 0 ){
318
- return;
319
- }
320
- $query = "INSERT INTO `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` ( id, original, translated, status, block_type ) VALUES ";
 
 
321
 
322
  $values = array();
323
  $place_holders = array();
@@ -325,20 +288,19 @@ class TRP_Query{
325
 
326
  foreach ( $new_strings as $string ) {
327
  array_push( $values, NULL, $string, NULL, self::NOT_TRANSLATED, $block_type );
328
- $place_holders[] = "( '%d', '%s', '%s', '%d', '%d')";
329
  }
330
  foreach ( $update_strings as $string ) {
331
  if ( ! isset( $string['block_type'] ) ){
332
  $string['block_type'] = self::BLOCK_TYPE_REGULAR_STRING;
333
  }
334
  array_push( $values, $string['id'], $string['original'], $string['translated'], $string['status'], $string['block_type'] );
335
- $place_holders[] = "( '%d', '%s', '%s', '%d', '%d')";
336
  }
 
337
 
338
- $on_duplicate = ' ON DUPLICATE KEY UPDATE translated=VALUES(translated), status=VALUES(status), block_type=VALUES(block_type)';
339
-
340
- $query .= implode(', ', $place_holders);
341
- $query .= $on_duplicate;
342
 
343
  // you cannot insert multiple rows at once using insert() method.
344
  // but by using prepare you cannot insert NULL values.
@@ -419,7 +381,7 @@ class TRP_Query{
419
  $values = array();
420
  foreach( $original_strings as $string ){
421
  $placeholders[] = '%s';
422
- $values[] = $this->full_trim( $string );
423
  }
424
 
425
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
@@ -446,12 +408,11 @@ class TRP_Query{
446
  $values = array();
447
  foreach( $strings_array as $string ){
448
  $placeholders[] = '%s';
449
- $values[] = $this->full_trim( $string );
450
  }
451
 
452
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
453
  $dictionary = $this->db->get_results( $this->db->prepare( $query, $values ), OBJECT_K );
454
-
455
  return $dictionary;
456
  }
457
 
@@ -512,7 +473,7 @@ class TRP_Query{
512
  $values = array();
513
  foreach ($original_array as $string) {
514
  $placeholders[] = '%s';
515
- $values[] = $this->full_trim($string);
516
  }
517
 
518
  $query1 = "original IN ( " . implode(", ", $placeholders) . " )";
@@ -580,7 +541,7 @@ class TRP_Query{
580
  $values = array();
581
  foreach( $original_array as $string ){
582
  $placeholders[] = '%s';
583
- $values[] = $this->full_trim( $string );
584
  }
585
 
586
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
@@ -610,7 +571,7 @@ class TRP_Query{
610
  $placeholders = array();
611
  foreach( $original_array as $string ){
612
  $placeholders[] = '%s';
613
- $values[] = $this->full_trim( $string );
614
  }
615
  }
616
 
@@ -680,4 +641,85 @@ class TRP_Query{
680
  $last_id = $this->db->get_var("SELECT MAX(id) FROM " . $table_name );
681
  return $last_id;
682
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
  }
31
  $this->settings = $settings;
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  /**
36
  * Return an array of all the active translation blocks
69
  $values = array();
70
  foreach( $strings_array as $string ){
71
  $placeholders[] = '%s';
72
+ $values[] = $string;
73
  }
74
 
75
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
76
  $prepared_query = $this->db->prepare( $query, $values );
77
  $dictionary = $this->db->get_results( $prepared_query, OBJECT_K );
78
+ return apply_filters( 'trp_get_existing_translations', $dictionary, $prepared_query, $strings_array );
79
  }
80
 
81
  /**
214
  }
215
  }
216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  /**
218
  * Add block_type column to dictionary tables, if it doesn't exist.
219
  *
267
  /**
268
  * Insert translations and new strings in DB.
269
  *
270
+ * @param array $new_strings Array of strings for which we do not have a translation. Only inserts original.
271
+ * @param array $update_strings Array of arrays, each containing an entry to update.
272
+ * @param string $language_code Language code of table where it should be inserted.
273
+ * @param int $block_type
274
+ * @param string $on_duplicate
275
+ */
276
+ public function insert_strings( $new_strings, $update_strings, $language_code, $block_type = self::BLOCK_TYPE_REGULAR_STRING ) {
277
+ if ( $block_type == null ) {
278
+ $block_type = self::BLOCK_TYPE_REGULAR_STRING;
279
+ }
280
+ if ( count( $new_strings ) == 0 && count( $update_strings ) == 0 ) {
281
+ return;
282
+ }
283
+ $query = "INSERT INTO `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` ( id, original, translated, status, block_type ) VALUES ";
284
 
285
  $values = array();
286
  $place_holders = array();
288
 
289
  foreach ( $new_strings as $string ) {
290
  array_push( $values, NULL, $string, NULL, self::NOT_TRANSLATED, $block_type );
291
+ $place_holders[] = "('%d','%s','%s','%d','%d')";
292
  }
293
  foreach ( $update_strings as $string ) {
294
  if ( ! isset( $string['block_type'] ) ){
295
  $string['block_type'] = self::BLOCK_TYPE_REGULAR_STRING;
296
  }
297
  array_push( $values, $string['id'], $string['original'], $string['translated'], $string['status'], $string['block_type'] );
298
+ $place_holders[] = "('%d','%s','%s','%d','%d')";
299
  }
300
+ $query .= implode( ', ', $place_holders );
301
 
302
+ $on_duplicate = ' ON DUPLICATE KEY UPDATE translated=VALUES(translated), status=VALUES(status), block_type=VALUES(block_type)';
303
+ $query .= $on_duplicate;
 
 
304
 
305
  // you cannot insert multiple rows at once using insert() method.
306
  // but by using prepare you cannot insert NULL values.
381
  $values = array();
382
  foreach( $original_strings as $string ){
383
  $placeholders[] = '%s';
384
+ $values[] = $string;
385
  }
386
 
387
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
408
  $values = array();
409
  foreach( $strings_array as $string ){
410
  $placeholders[] = '%s';
411
+ $values[] = $string;
412
  }
413
 
414
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
415
  $dictionary = $this->db->get_results( $this->db->prepare( $query, $values ), OBJECT_K );
 
416
  return $dictionary;
417
  }
418
 
473
  $values = array();
474
  foreach ($original_array as $string) {
475
  $placeholders[] = '%s';
476
+ $values[] = $string;
477
  }
478
 
479
  $query1 = "original IN ( " . implode(", ", $placeholders) . " )";
541
  $values = array();
542
  foreach( $original_array as $string ){
543
  $placeholders[] = '%s';
544
+ $values[] = trp_full_trim( $string );
545
  }
546
 
547
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
571
  $placeholders = array();
572
  foreach( $original_array as $string ){
573
  $placeholders[] = '%s';
574
+ $values[] = trp_full_trim( $string );
575
  }
576
  }
577
 
641
  $last_id = $this->db->get_var("SELECT MAX(id) FROM " . $table_name );
642
  return $last_id;
643
  }
644
+
645
+ /**
646
+ * Returns a selection of rows from a specific location.
647
+ * Only id and original are selected.
648
+ *
649
+ * Ex. if $inferior_limit = 400 and $batch_size = 10
650
+ * You will get rows 401 to 411
651
+ *
652
+ * @param $language_code
653
+ * @param $inferior_limit
654
+ * @param $batch_size
655
+ *
656
+ * @return array|null|object
657
+ */
658
+ public function get_rows_from_location( $language_code, $inferior_limit, $batch_size, $columns_to_retrieve ) {
659
+ $columns_query_part = '';
660
+ foreach ( $columns_to_retrieve as $column ) {
661
+ $columns_query_part .= $column . ',';
662
+ }
663
+ $columns_query_part = rtrim( $columns_query_part, ',' );
664
+ $query = "SELECT " . $columns_query_part . " FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE status != " . self::NOT_TRANSLATED . " ORDER BY id LIMIT " . $inferior_limit . ", " . $batch_size;
665
+ $dictionary = $this->db->get_results( $query, ARRAY_A );
666
+ return $dictionary;
667
+ }
668
+
669
+ /**
670
+ * Update non-gettext strings in DB
671
+ *
672
+ * @param array $update_strings Array of strings to update
673
+ * @param string $language_code Language code
674
+ * @param array $columns_to_update Array with the name of columns to update id, original, translated, status, block_type
675
+ * @param string $placeholders_query_part For query on all columns '%d', '%s', '%s', '%d', '%d'
676
+ */
677
+ public function update_strings( $update_strings, $language_code, $columns_to_update, $placeholders ) {
678
+ if ( count( $update_strings ) == 0 ) {
679
+ return;
680
+ }
681
+
682
+ $columns_query_part = '';
683
+ foreach ( $columns_to_update as $column ) {
684
+ $columns_query_part .= $column . ',';
685
+ }
686
+ $columns_query_part = rtrim( $columns_query_part, ',' );
687
+
688
+ $query = "INSERT INTO `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` ( " . $columns_query_part . " ) VALUES ";
689
+
690
+ $values = array();
691
+ $place_holders = array();
692
+
693
+ $placeholders_query_part = '(';
694
+ foreach ( $placeholders as $placeholder ) {
695
+ $placeholders_query_part .= "'" . $placeholder . "',";
696
+ }
697
+ $placeholders_query_part = rtrim( $placeholders_query_part, ',' );
698
+ $placeholders_query_part .= ')';
699
+
700
+ foreach ( $update_strings as $string ) {
701
+ foreach( $columns_to_update as $column ) {
702
+ array_push( $values, $string[$column] );
703
+ }
704
+ $place_holders[] = $placeholders_query_part;
705
+ }
706
+
707
+ $on_duplicate = ' ON DUPLICATE KEY UPDATE ';
708
+ foreach ( $columns_to_update as $column ) {
709
+ if ( $column == 'id' ){
710
+ continue;
711
+ }
712
+ $on_duplicate .= $column . '=VALUES(' . $column . '),';
713
+ }
714
+ $query .= implode( ', ', $place_holders );
715
+
716
+ $on_duplicate = rtrim( $on_duplicate, ',' );
717
+ $query .= $on_duplicate;
718
+
719
+ // you cannot insert multiple rows at once using insert() method.
720
+ // but by using prepare you cannot insert NULL values.
721
+
722
+ $prepared_query = $this->db->prepare($query . ' ', $values);
723
+ $this->db->query( $prepared_query );
724
+ }
725
  }
includes/class-settings.php CHANGED
@@ -69,7 +69,6 @@ class TRP_Settings{
69
  add_options_page( 'TranslatePress', 'TranslatePress', apply_filters( 'trp_settings_capability', 'manage_options' ), 'translate-press', array( $this, 'settings_page_content' ) );
70
  add_submenu_page( 'TRPHidden', 'TranslatePress Addons', 'TRPHidden', 'manage_options', 'trp_addons_page', array($this, 'addons_page_content') );
71
  add_submenu_page( 'TRPHidden', 'TranslatePress Test Google API Key', 'TRPHidden', 'manage_options', 'trp_test_google_key_page', array($this, 'test_google_key_page_content') );
72
- add_submenu_page( 'TRPHidden', 'TranslatePress Remove Duplicate Rows', 'TRPHidden', 'manage_options', 'trp_remove_duplicate_rows', array($this, 'trp_remove_duplicate_rows') );
73
  }
74
 
75
  /**
@@ -102,114 +101,6 @@ class TRP_Settings{
102
  require_once TRP_PLUGIN_DIR . 'partials/test-google-key-settings-page.php';
103
  }
104
 
105
- /**
106
- * Remove duplicate rows from DB for trp_dictionary tables.
107
- * Removes untranslated strings if there is a translated version.
108
- *
109
- * Iterates over languages. Each language is iterated in batches of 10 000
110
- */
111
- public function trp_remove_duplicate_rows(){
112
- if ( ! current_user_can( 'manage_options' ) ){
113
- return;
114
- }
115
- // prepare page structure
116
- require_once TRP_PLUGIN_DIR . 'partials/trp-remove-duplicate-rows.php';
117
-
118
- if ( empty( $_GET['trp_rm_duplicates'] ) ){
119
- // iteration not started
120
- return;
121
- }
122
- if ( $_GET['trp_rm_duplicates'] === 'done' ){
123
- // iteration finished
124
- echo __('Done.', 'translatepress-multilingual' ) . '<br><br><a href="' . site_url('wp-admin/options-general.php?page=translate-press') . '"> <input type="button" value="' . __('Back to TranslatePress Settings page', 'translatepress-multilingual' ) . '" class="button-primary"></a>';
125
- return;
126
- }
127
- $nonce = wp_verify_nonce( $_GET['trp_rm_nonce'], 'tpremoveduplicaterows' );
128
- if ( $nonce === false ){
129
- echo __('Invalid nonce.', 'translatepress-multilingual' ) . '<br><br><a href="' . site_url('wp-admin/options-general.php?page=translate-press') . '"> <input type="button" value="' . __('Back to TranslatePress Settings page', 'translatepress-multilingual' ) . '" class="button-primary"></a>';
130
- return;
131
- }
132
-
133
- $next_get_batch = 1;
134
- $batch_size = apply_filters( 'trp_rm_duplicate_batch_size', 10000 );
135
- if ( !empty( $_GET['trp_rm_batch_size'] ) && (int) $_GET['trp_rm_batch'] > 0 ){
136
- $batch_size = (int) $_GET['trp_rm_batch_size'];
137
- }
138
- if ( in_array( $_GET['trp_rm_duplicates'], $this->settings['translation-languages'] ) ) {
139
- // language code found in array
140
- $language_code = $_GET['trp_rm_duplicates'];
141
- // skip default language since it doesn't have a table
142
- if ( $language_code != $this->settings['default-language'] ) {
143
- if ( ! $this->trp_query ) {
144
- $trp = TRP_Translate_Press::get_trp_instance();
145
- /* @var TRP_Query */
146
- $this->trp_query = $trp->get_component( 'query' );
147
- }
148
- $table_name = $this->trp_query->get_table_name( $language_code );
149
- echo '<div>' . sprintf( __( 'Querying table <strong>%s</strong>', 'translatepress-multilingual' ), $table_name ) . '</div>';
150
-
151
- $last_id = $this->trp_query->get_last_id( $table_name );
152
- if ( !empty( $_GET['trp_rm_batch'] ) && (int) $_GET['trp_rm_batch'] > 0 ) {
153
- $get_batch = (int)$_GET['trp_rm_batch'];
154
- }else{
155
- $get_batch = 1;
156
- }
157
- $batch = $batch_size * $get_batch;
158
-
159
- /* Execute this query only for string with ID < $batch. This ensures that the query is fast.
160
- * Deleting duplicate rows for the first 20k rows might take too long.
161
- * As a solution we are deleting the duplicates of the first 10k rows ( 1 to 10 000),
162
- * then delete duplicates of the first 20k rows( 1 to 20 000, not 10 000 to 20 000 because we there could still be duplicates).
163
- * Same goes for higher numbers.
164
- */
165
- $result1 = $this->trp_query->remove_duplicate_rows_in_dictionary_table( $language_code, $batch );
166
- $result2 = 0;
167
- if ( $batch > $last_id ){
168
- // execute this query only when we do not have any more duplicate rows
169
- $result2 = $this->trp_query->remove_untranslated_strings_if_translation_available( $language_code );
170
- }else{
171
- $next_get_batch = $get_batch + 1;
172
- }
173
-
174
- if ( ( $result1 === false ) || ( $result2 === false ) ) {
175
- // if query outputted error do not continue iteration
176
- return;
177
- }else{
178
- $result = $result1 + $result2;
179
- echo '<div>' . sprintf( __( '%s duplicates removed', 'translatepress-multilingual' ), $result ) . '</div>';
180
- }
181
- }
182
- if ( $next_get_batch == 1 ) {
183
- // finished with the current language
184
- $index = array_search( $language_code, $this->settings['translation-languages'] );
185
- if ( isset ( $this->settings['translation-languages'][ $index + 1 ] ) ) {
186
- // next language code in array
187
- $next_language = $this->settings['translation-languages'][ $index + 1 ];
188
- } else {
189
- // finish iteration due to completing all the translation languages
190
- $next_language = 'done';
191
- }
192
- }else{
193
- $next_language = $language_code;
194
- }
195
- }else{
196
- // finish iteration due to incorrect translation language
197
- $next_language = 'done';
198
- }
199
-
200
- // construct and redirect to next url
201
- $url = add_query_arg( array(
202
- 'page' => 'trp_remove_duplicate_rows',
203
- 'trp_rm_duplicates' => $next_language,
204
- 'trp_rm_batch' => $next_get_batch,
205
- 'trp_rm_batch_size' => $batch_size,
206
- 'trp_rm_nonce' => wp_create_nonce('tpremoveduplicaterows')
207
- ), site_url('wp-admin/admin.php') );
208
- echo "<meta http-equiv='refresh' content='0; url={$url}' />";
209
- echo "<br> " . __( 'If the page does not redirect automatically', 'translatepress-multilingual' ) . " <a href='$url' >" . __( 'click here', 'translatepress-multilingual' ) . ".</a>";
210
- exit;
211
- }
212
-
213
  /**
214
  * Register settings option.
215
  */
69
  add_options_page( 'TranslatePress', 'TranslatePress', apply_filters( 'trp_settings_capability', 'manage_options' ), 'translate-press', array( $this, 'settings_page_content' ) );
70
  add_submenu_page( 'TRPHidden', 'TranslatePress Addons', 'TRPHidden', 'manage_options', 'trp_addons_page', array($this, 'addons_page_content') );
71
  add_submenu_page( 'TRPHidden', 'TranslatePress Test Google API Key', 'TRPHidden', 'manage_options', 'trp_test_google_key_page', array($this, 'test_google_key_page_content') );
 
72
  }
73
 
74
  /**
101
  require_once TRP_PLUGIN_DIR . 'partials/test-google-key-settings-page.php';
102
  }
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  /**
105
  * Register settings option.
106
  */
includes/class-translation-manager.php CHANGED
@@ -181,7 +181,7 @@ class TRP_Translation_Manager{
181
  if ( isset( $string->id ) && is_numeric( $string->id ) ) {
182
  $id_array[$key] = (int)$string->id;
183
  } else if ( isset( $string->original ) ) {
184
- $original_array[$key] = trp_sanitize_string( $string->original );
185
  }
186
  }
187
 
@@ -396,7 +396,7 @@ class TRP_Translation_Manager{
396
  }
397
  array_push($update_strings[ $language ], array(
398
  'id' => (int)$string->id,
399
- 'original' => trp_sanitize_string( $string->original ),
400
  'translated' => trp_sanitize_string( $string->translated ),
401
  'status' => (int)$string->status,
402
  'block_type' => (int)$string->block_type
@@ -513,7 +513,7 @@ class TRP_Translation_Manager{
513
  }
514
  $ajax_translated_string_list = $strings->$language;
515
  foreach( $ajax_translated_string_list as $ajax_key => $ajax_string ) {
516
- if ( trp_sanitize_string( $ajax_string->original ) == $dictionary_string->original ) {
517
  if ( $ajax_string->translated != '' ) {
518
  $dictionaries[ $language ][ $dictionary_string_key ]->translated = trp_sanitize_string( $ajax_string->translated );
519
  $dictionaries[ $language ][ $dictionary_string_key ]->status = (int) $ajax_string->status;
@@ -705,13 +705,14 @@ class TRP_Translation_Manager{
705
  }
706
 
707
  $strings = $this->trp_query->get_all_gettext_strings($TRP_LANGUAGE);
708
- if (!empty($strings))
709
- $trp_translated_gettext_texts = $strings;
710
 
711
- foreach( $trp_translated_gettext_texts as $key => $value ){
712
- $trp_strings[$value['domain'] . '::' . $value['original']] = $value;
 
 
713
  }
714
- $trp_translated_gettext_texts = $trp_strings;
715
  }
716
  }
717
 
@@ -1212,5 +1213,77 @@ class TRP_Translation_Manager{
1212
  }
1213
  }
1214
  }
1215
-
1216
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  if ( isset( $string->id ) && is_numeric( $string->id ) ) {
182
  $id_array[$key] = (int)$string->id;
183
  } else if ( isset( $string->original ) ) {
184
+ $original_array[$key] = trp_full_trim( trp_sanitize_string( $string->original ) );
185
  }
186
  }
187
 
396
  }
397
  array_push($update_strings[ $language ], array(
398
  'id' => (int)$string->id,
399
+ 'original' => trp_full_trim( trp_sanitize_string( $string->original ) ),
400
  'translated' => trp_sanitize_string( $string->translated ),
401
  'status' => (int)$string->status,
402
  'block_type' => (int)$string->block_type
513
  }
514
  $ajax_translated_string_list = $strings->$language;
515
  foreach( $ajax_translated_string_list as $ajax_key => $ajax_string ) {
516
+ if ( trp_full_trim( trp_sanitize_string( $ajax_string->original ) ) == $dictionary_string->original ) {
517
  if ( $ajax_string->translated != '' ) {
518
  $dictionaries[ $language ][ $dictionary_string_key ]->translated = trp_sanitize_string( $ajax_string->translated );
519
  $dictionaries[ $language ][ $dictionary_string_key ]->status = (int) $ajax_string->status;
705
  }
706
 
707
  $strings = $this->trp_query->get_all_gettext_strings($TRP_LANGUAGE);
708
+ if ( !empty( $strings ) ) {
709
+ $trp_translated_gettext_texts = $strings;
710
 
711
+ foreach ( $trp_translated_gettext_texts as $key => $value ) {
712
+ $trp_strings[ $value['domain'] . '::' . $value['original'] ] = $value;
713
+ }
714
+ $trp_translated_gettext_texts = $trp_strings;
715
  }
 
716
  }
717
  }
718
 
1213
  }
1214
  }
1215
  }
1216
+
1217
+ /**
1218
+ * Return true if the string contains characters which are not allowed in the query
1219
+ *
1220
+ * Only valid for utf8.
1221
+ * Function is an extract of strip_invalid_text() function from wp-includes/wp-db.php
1222
+ *
1223
+ * @param $string
1224
+ *
1225
+ * @return bool
1226
+ */
1227
+ public function has_bad_characters( $string ) {
1228
+ $regex = '/
1229
+ (
1230
+ (?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
1231
+ | [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
1232
+ | \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
1233
+ | [\xE1-\xEC][\x80-\xBF]{2}
1234
+ | \xED[\x80-\x9F][\x80-\xBF]
1235
+ | [\xEE-\xEF][\x80-\xBF]{2}';
1236
+
1237
+ $regex .= '
1238
+ | \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
1239
+ | [\xF1-\xF3][\x80-\xBF]{3}
1240
+ | \xF4[\x80-\x8F][\x80-\xBF]{2}
1241
+ ';
1242
+
1243
+
1244
+ $regex .= '){1,40} # ...one or more times
1245
+ )
1246
+ | . # anything else
1247
+ /x';
1248
+ $stripped_string = preg_replace( $regex, '$1', $string );
1249
+
1250
+ if ( $stripped_string === $string ){
1251
+ return false;
1252
+ }else {
1253
+ return true;
1254
+ }
1255
+ }
1256
+
1257
+ /**
1258
+ * Records a series of strings which may have encoding issues
1259
+ *
1260
+ * Does not alter dictionary.
1261
+ *
1262
+ * @param $dictionary
1263
+ * @param $prepared_query
1264
+ * @param $strings_array
1265
+ *
1266
+ * @return mixed
1267
+ */
1268
+ public function display_possible_db_errors( $dictionary, $prepared_query, $strings_array ){
1269
+ global $trp_editor_notices;
1270
+ if ( trp_is_translation_editor( 'preview' ) && is_array( $dictionary ) && count( $dictionary ) === 0 ){
1271
+ if ( $this->has_bad_characters( $prepared_query ) ) {
1272
+ $html = "<div class='trp-notice trp-notice-warning'><p class='trp-bad-encoded-strings'>" . __( '<strong>Warning:</strong> Some strings have possibly incorrectly encoded characters. This may result in breaking the queries, rendering the page untranslated in live mode. Consider revising the following strings or their method of outputting.', 'translatepress-multilingual' ) . "</p>";
1273
+ $html .= "<ul class='trp-bad-encoded-strings-list'>";
1274
+ foreach( $strings_array as $string ){
1275
+ if ( $this->has_bad_characters( $string ) ){
1276
+ $html .= "<li>" . $string . "</li>";
1277
+ }
1278
+ }
1279
+ $html .= "</ul></div>";
1280
+
1281
+ $trp_editor_notices .= $html;
1282
+ }
1283
+ }
1284
+
1285
+ // no modifications to the dictionary
1286
+ return $dictionary;
1287
+ }
1288
+
1289
+ }
includes/class-translation-render.php CHANGED
@@ -89,40 +89,17 @@ class TRP_Translation_Render{
89
  return false;
90
  }
91
 
92
- /**
93
- * Trim strings.
94
- *
95
- * @param string $string Raw string.
96
- * @return string Trimmed string.
97
- */
98
- public function full_trim( $string ) {
99
- /* Make sure you update full_trim function from trp-ajax too*/
100
-
101
- /* Apparently the � char in the trim function turns some strings in an empty string so they can't be translated but I don't really know if we should remove it completely
102
- Removed chr( 194 ) . chr( 160 ) because it altered some special characters (¿¡)
103
- Also removed \xA0 (the same as chr(160) for altering special characters */
104
- //$word = trim($word," \t\n\r\0\x0B\xA0�".chr( 194 ) . chr( 160 ) );
105
-
106
- /* Solution to replace the chr(194).chr(160) from trim function, in order to escape the whitespace character ( \xc2\xa0 ), an old bug that couldn't be replicated anymore. */
107
- $prefix = "\xc2\xa0";
108
- $prefix_length = strlen($prefix);
109
- do{
110
- $previous_iteration_string = $string;
111
- $string = trim( $string," \t\n\r\0\x0B");
112
- if ( substr( $string, 0, $prefix_length ) == $prefix ) {
113
- $string = substr( $string, $prefix_length );
114
- }
115
- if ( substr( $string, - $prefix_length, $prefix_length ) == $prefix ) {
116
- $string = substr( $string, 0, - $prefix_length );
117
- }
118
- }while( $string != $previous_iteration_string );
119
-
120
- if ( strip_tags( $string ) == "" || trim ($string, " \t\n\r\0\x0B\xA0�.,/`~!@#\$€£%^&*():;-_=+[]{}\\|?/<>1234567890'\"" ) == '' ){
121
- $string = '';
122
- }
123
-
124
- return $string;
125
- }
126
 
127
  /**
128
  * Preview mode string category name for give node type.
@@ -237,7 +214,7 @@ class TRP_Translation_Render{
237
  * @return string
238
  */
239
  public function trim_translation_block( $string ){
240
- return preg_replace('/\s+/', ' ', strip_tags( html_entity_decode( htmlspecialchars_decode( $this->full_trim( $string ), ENT_QUOTES ) ) ));
241
  }
242
 
243
  /**
@@ -284,6 +261,7 @@ class TRP_Translation_Render{
284
  * @return string Translated HTML page.
285
  */
286
  public function translate_page( $output ){
 
287
 
288
  /* replace our special tags so we have valid html */
289
  $output = str_replace('#!trpst#', '<', $output);
@@ -367,8 +345,10 @@ class TRP_Translation_Render{
367
  if ( ! $this->translation_manager ) {
368
  $this->translation_manager = $trp->get_component( 'translation_manager' );
369
  }
 
370
  if ( $translate_normal_strings ) {
371
  $all_existing_translation_blocks = $this->trp_query->get_all_translation_blocks( $language_code );
 
372
  // trim every translation block original now, to avoid over-calling trim function later
373
  foreach ( $all_existing_translation_blocks as $key => $existing_tb ) {
374
  $all_existing_translation_blocks[ $key ]->trimmed_original = $this->trim_translation_block( $all_existing_translation_blocks[ $key ]->original );
@@ -398,7 +378,7 @@ class TRP_Translation_Render{
398
  if( $row->nodetype !== 5 && $row->nodetype !== 3 )//add all tags that are not root or text, text nodes can't have attributes
399
  $trp_attr_rows[] = $row;
400
 
401
- if ( $translate_normal_strings ) {
402
  $translation_block = $this->find_translation_block( $row, $all_existing_translation_blocks, $merge_rules );
403
  if ( $translation_block ) {
404
  $existing_classes = $row->getAttribute( 'class' );
@@ -507,33 +487,35 @@ class TRP_Translation_Render{
507
  }
508
  }
509
  foreach ( $html->find('.translation-block') as $k => $row ){
510
- if( $this->full_trim($row->outertext)!=""
 
511
  && $row->parent()->tag!="script"
512
  && $row->parent()->tag!="style"
513
- && !is_numeric($this->full_trim($row->outertext))
514
- && !preg_match('/^\d+%$/',$this->full_trim($row->outertext))
515
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
516
  && $row->parent()->tag != 'title'
517
  && strpos($row->outertext,'[vc_') === false )
518
  {
519
- array_push( $translateable_strings, $this->full_trim( $row->innertext ) );
520
  array_push( $nodes, array('node' => $row, 'type' => 'block'));
521
  }
522
  }
523
 
524
  foreach ( $html->find('text') as $k => $row ){
525
- if( $this->full_trim($row->outertext)!=""
 
526
  && $row->parent()->tag!="script"
527
  && $row->parent()->tag!="style"
528
- && !is_numeric($this->full_trim($row->outertext))
529
- && !preg_match('/^\d+%$/',$this->full_trim($row->outertext))
530
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
531
  && !$this->has_ancestor_class( $row, 'translation-block')
532
  && $row->parent()->tag != 'title'
533
  && strpos($row->outertext,'[vc_') === false )
534
  {
535
  // $translateable_strings array needs to be in sync in $nodes array
536
- array_push( $translateable_strings, $this->full_trim( $row->outertext ) );
537
  if( $row->parent()->tag == 'button') {
538
  array_push($nodes, array('node' => $row, 'type' => 'button'));
539
  }
@@ -548,9 +530,10 @@ class TRP_Translation_Render{
548
  }
549
 
550
  foreach ( $html->find('input[type=\'submit\'],input[type=\'button\']') as $k => $row ){
551
- if( $this->full_trim($row->value)!=""
552
- && !is_numeric($this->full_trim($row->value))
553
- && !preg_match('/^\d+%$/',$this->full_trim($row->value))
 
554
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
555
  && !$this->has_ancestor_class( $row, 'translation-block') )
556
  {
@@ -559,9 +542,10 @@ class TRP_Translation_Render{
559
  }
560
  }
561
  foreach ( $html->find('input[type=\'text\'],input[type=\'password\'],input[type=\'search\'],input[type=\'email\'],input:not([type]),textarea') as $k => $row ){
562
- if( $this->full_trim($row->placeholder)!=""
563
- && !is_numeric($this->full_trim($row->placeholder))
564
- && !preg_match('/^\d+%$/',$this->full_trim($row->placeholder))
 
565
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
566
  && !$this->has_ancestor_class( $row, 'translation-block') )
567
  {
@@ -733,7 +717,14 @@ class TRP_Translation_Render{
733
  $link->href = str_replace('#TRPLINKPROCESSED', '', $link->href);
734
  }
735
 
736
- return $html->save();
 
 
 
 
 
 
 
737
  }
738
 
739
  /**
@@ -901,7 +892,7 @@ class TRP_Translation_Render{
901
  //strings existing in database,
902
 
903
  if ( isset( $dictionary[$string]->translated ) ){
904
- $translated_strings[$i] = $dictionary[$this->full_trim($string)]->translated;
905
  }else{
906
  $new_strings[$i] = $translateable_strings[$i];
907
  }
89
  return false;
90
  }
91
 
92
+ /**
93
+ * Trim strings.
94
+ * This function is kept for backwards compatibility for earlier versions of SEO Pack Add-on
95
+ *
96
+ * @deprecated
97
+ * @param string $string Raw string.
98
+ * @return string Trimmed string.
99
+ */
100
+ public function full_trim( $string ) {
101
+ return trp_full_trim( $string );
102
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
  /**
105
  * Preview mode string category name for give node type.
214
  * @return string
215
  */
216
  public function trim_translation_block( $string ){
217
+ return preg_replace('/\s+/', ' ', strip_tags( html_entity_decode( htmlspecialchars_decode( trp_full_trim( $string ), ENT_QUOTES ) ) ));
218
  }
219
 
220
  /**
261
  * @return string Translated HTML page.
262
  */
263
  public function translate_page( $output ){
264
+ global $trp_editor_notices;
265
 
266
  /* replace our special tags so we have valid html */
267
  $output = str_replace('#!trpst#', '<', $output);
345
  if ( ! $this->translation_manager ) {
346
  $this->translation_manager = $trp->get_component( 'translation_manager' );
347
  }
348
+ $count_translation_blocks = 0;
349
  if ( $translate_normal_strings ) {
350
  $all_existing_translation_blocks = $this->trp_query->get_all_translation_blocks( $language_code );
351
+ $count_translation_blocks = count( $all_existing_translation_blocks );
352
  // trim every translation block original now, to avoid over-calling trim function later
353
  foreach ( $all_existing_translation_blocks as $key => $existing_tb ) {
354
  $all_existing_translation_blocks[ $key ]->trimmed_original = $this->trim_translation_block( $all_existing_translation_blocks[ $key ]->original );
378
  if( $row->nodetype !== 5 && $row->nodetype !== 3 )//add all tags that are not root or text, text nodes can't have attributes
379
  $trp_attr_rows[] = $row;
380
 
381
+ if ( $translate_normal_strings && $count_translation_blocks > 0 ) {
382
  $translation_block = $this->find_translation_block( $row, $all_existing_translation_blocks, $merge_rules );
383
  if ( $translation_block ) {
384
  $existing_classes = $row->getAttribute( 'class' );
487
  }
488
  }
489
  foreach ( $html->find('.translation-block') as $k => $row ){
490
+ $trimmed_string = trp_full_trim($row->innertext);
491
+ if( $trimmed_string!=""
492
  && $row->parent()->tag!="script"
493
  && $row->parent()->tag!="style"
494
+ && !is_numeric($trimmed_string)
495
+ && !preg_match('/^\d+%$/',$trimmed_string)
496
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
497
  && $row->parent()->tag != 'title'
498
  && strpos($row->outertext,'[vc_') === false )
499
  {
500
+ array_push( $translateable_strings, $trimmed_string );
501
  array_push( $nodes, array('node' => $row, 'type' => 'block'));
502
  }
503
  }
504
 
505
  foreach ( $html->find('text') as $k => $row ){
506
+ $trimmed_string = trp_full_trim($row->outertext);
507
+ if( $trimmed_string!=""
508
  && $row->parent()->tag!="script"
509
  && $row->parent()->tag!="style"
510
+ && !is_numeric($trimmed_string)
511
+ && !preg_match('/^\d+%$/',$trimmed_string)
512
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
513
  && !$this->has_ancestor_class( $row, 'translation-block')
514
  && $row->parent()->tag != 'title'
515
  && strpos($row->outertext,'[vc_') === false )
516
  {
517
  // $translateable_strings array needs to be in sync in $nodes array
518
+ array_push( $translateable_strings, $trimmed_string );
519
  if( $row->parent()->tag == 'button') {
520
  array_push($nodes, array('node' => $row, 'type' => 'button'));
521
  }
530
  }
531
 
532
  foreach ( $html->find('input[type=\'submit\'],input[type=\'button\']') as $k => $row ){
533
+ $trimmed_string = trp_full_trim($row->value);
534
+ if( $trimmed_string!=""
535
+ && !is_numeric($trimmed_string)
536
+ && !preg_match('/^\d+%$/',$trimmed_string)
537
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
538
  && !$this->has_ancestor_class( $row, 'translation-block') )
539
  {
542
  }
543
  }
544
  foreach ( $html->find('input[type=\'text\'],input[type=\'password\'],input[type=\'search\'],input[type=\'email\'],input:not([type]),textarea') as $k => $row ){
545
+ $trimmed_string = trp_full_trim($row->placeholder);
546
+ if( $trimmed_string!=""
547
+ && !is_numeric($trimmed_string)
548
+ && !preg_match('/^\d+%$/',$trimmed_string)
549
  && !$this->has_ancestor_attribute( $row, $no_translate_attribute )
550
  && !$this->has_ancestor_class( $row, 'translation-block') )
551
  {
717
  $link->href = str_replace('#TRPLINKPROCESSED', '', $link->href);
718
  }
719
 
720
+ // Append an html table containing the errors
721
+ $trp_editor_notices = apply_filters( 'trp_editor_notices', $trp_editor_notices );
722
+ if ( trp_is_translation_editor('preview') && $trp_editor_notices != '' ){
723
+ $body = $html->find('body', 0 );
724
+ $body->innertext = '<div data-no-translation class="trp-editor-notices">' . $trp_editor_notices . "</div>" . $body->innertext;
725
+ }
726
+
727
+ return $html->save();
728
  }
729
 
730
  /**
892
  //strings existing in database,
893
 
894
  if ( isset( $dictionary[$string]->translated ) ){
895
+ $translated_strings[$i] = $dictionary[$string]->translated;
896
  }else{
897
  $new_strings[$i] = $translateable_strings[$i];
898
  }
includes/class-upgrade.php ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class TRP_Upgrade
5
+ *
6
+ * When changing plugin version, do the necessary checks and database upgrades.
7
+ */
8
+ class TRP_Upgrade {
9
+
10
+ protected $settings;
11
+ /* @var TRP_Query */
12
+ protected $trp_query;
13
+
14
+ /**
15
+ * TRP_Upgrade constructor.
16
+ *
17
+ * @param $settings
18
+ */
19
+ public function __construct( $settings ){
20
+ $this->settings = $settings;
21
+ }
22
+
23
+ /**
24
+ * Register Settings subpage for TranslatePress
25
+ */
26
+ public function register_menu_page(){
27
+ add_submenu_page( 'TRPHidden', 'TranslatePress Remove Duplicate Rows', 'TRPHidden', 'manage_options', 'trp_remove_duplicate_rows', array($this, 'trp_remove_duplicate_rows') );
28
+ add_submenu_page( 'TRPHidden', 'TranslatePress Update Database', 'TRPHidden', 'manage_options', 'trp_update_database', array( $this, 'trp_full_trim_originals' ) );
29
+ }
30
+
31
+ /**
32
+ * When changing plugin version, call certain database upgrade functions.
33
+ *
34
+ */
35
+ public function check_for_necessary_updates(){
36
+ $trp = TRP_Translate_Press::get_trp_instance();
37
+ if( ! $this->trp_query ) {
38
+ $this->trp_query = $trp->get_component( 'query' );
39
+ }
40
+ $stored_database_version = get_option('trp_plugin_version');
41
+ if( empty($stored_database_version) || version_compare( TRP_PLUGIN_VERSION, $stored_database_version, '>' ) ){
42
+ $this->check_if_gettext_tables_exist();
43
+ $this->trp_query->check_for_block_type_column();
44
+ $this->check_for_full_trim_originals( $stored_database_version );
45
+ }
46
+
47
+ update_option( 'trp_plugin_version', TRP_PLUGIN_VERSION );
48
+ }
49
+
50
+ /**
51
+ * Iterates over all languages to call gettext table checking
52
+ */
53
+ public function check_if_gettext_tables_exist(){
54
+ $trp = TRP_Translate_Press::get_trp_instance();
55
+ if( ! $this->trp_query ) {
56
+ $this->trp_query = $trp->get_component( 'query' );
57
+ }
58
+ if( !empty( $this->settings['translation-languages'] ) ){
59
+ foreach( $this->settings['translation-languages'] as $site_language_code ){
60
+ $this->trp_query->check_gettext_table($site_language_code);
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Sets an option to know that an upgrade is needed
67
+ */
68
+ public function check_for_full_trim_originals( $stored_database_version ){
69
+ if ( version_compare( '1.4.0', $stored_database_version, '>' ) ){
70
+ update_option( 'trp_updated_database_full_trim_originals_140', 'no' );
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Show admin notice about updating database
76
+ */
77
+ public function show_admin_notice(){
78
+ $option = get_option( 'trp_updated_database_full_trim_originals_140', 'is not set' );
79
+ // show admin notice if option is set to false AND we are not on the update database page
80
+ if ( $option === 'no' && !( isset( $_GET[ 'page'] ) && $_GET['page'] == 'trp_update_database' ) ){
81
+ add_action( 'admin_notices', array( $this, 'admin_notice_update_database_full_trim' ) );
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Print admin notice message
87
+ */
88
+ public function admin_notice_update_database_full_trim() {
89
+ $url = add_query_arg( array(
90
+ 'page' => 'trp_update_database',
91
+ ), site_url('wp-admin/admin.php') );
92
+
93
+ // maybe change notice color to blue #28B1FF
94
+ $html = '<div id="message" class="updated">';
95
+ $html .= '<p><strong>' . esc_html__( 'TranslatePress data update', 'translatepress-multilingual' ) . '</strong> &#8211; ' . esc_html__( 'We need to update your translations database to the latest version.', 'translatepress-multilingual' ) . '</p>';
96
+ $html .= '<p class="submit"><a href="' . esc_url( $url ) . '" class="button-primary">' . esc_html__( 'Run the updater', 'translatepress-multilingual' ) . '</a></p>';
97
+ $html .= '</div>';
98
+ echo $html;
99
+ }
100
+
101
+ /**
102
+ * Remove duplicate rows from DB for trp_dictionary tables.
103
+ * Removes untranslated strings if there is a translated version.
104
+ *
105
+ * Iterates over languages. Each language is iterated in batches of 10 000
106
+ *
107
+ * Not accessible from anywhere else
108
+ * http://example.com/wp-admin/admin.php?page=trp_remove_duplicate_rows
109
+ */
110
+ public function trp_full_trim_originals(){
111
+ $start_time = microtime(true);
112
+ if ( ! current_user_can( 'manage_options' ) ){
113
+ return;
114
+ }
115
+ // prepare page structure
116
+ require_once TRP_PLUGIN_DIR . 'partials/trp-update-database.php';
117
+
118
+ if ( empty( $_GET['trp_updb_lang'] ) ){
119
+ // iteration not started
120
+ return;
121
+ }
122
+ if ( $_GET['trp_updb_lang'] === 'done' ){
123
+ // iteration finished
124
+ $this->print_queried_tables();
125
+ echo __( '<p><strong>Successfully updated database!</strong></p>', 'translatepress-multilingual' ) . '<br><a href="' . site_url( 'wp-admin/options-general.php?page=translate-press' ) . '"> <input type="button" value="' . __( 'Back to TranslatePress Settings page', 'translatepress-multilingual' ) . '" class="button-primary"></a>';
126
+ return;
127
+ }
128
+ $nonce = wp_verify_nonce( $_GET['trp_updb_nonce'], 'tpupdatedatabase' );
129
+ if ( $nonce === false ){
130
+ echo __('Invalid nonce.', 'translatepress-multilingual' ) . '<br><br><a href="' . site_url('wp-admin/options-general.php?page=translate-press') . '"> <input type="button" value="' . __('Back to TranslatePress Settings page', 'translatepress-multilingual' ) . '" class="button-primary"></a>';
131
+ return;
132
+ }
133
+
134
+ $next_get_batch = 0;
135
+ $batch_size = apply_filters( 'trp_updb_batch_size', 200 );
136
+ if ( !empty( $_GET['trp_updb_batch_size'] ) && (int) $_GET['trp_updb_batch'] >= 0 ){
137
+ $batch_size = (int) $_GET['trp_updb_batch_size'];
138
+ }
139
+ if ( in_array( $_GET['trp_updb_lang'], $this->settings['translation-languages'] ) ) {
140
+ // language code found in array
141
+ $language_code = $_GET['trp_updb_lang'];
142
+ // skip default language since it doesn't have a table
143
+ $finished_with_language = true;
144
+ if ( $language_code != $this->settings['default-language'] ) {
145
+ if ( ! $this->trp_query ) {
146
+ $trp = TRP_Translate_Press::get_trp_instance();
147
+ /* @var TRP_Query */
148
+ $this->trp_query = $trp->get_component( 'query' );
149
+ }
150
+
151
+ if ( !empty( $_GET['trp_updb_batch'] ) && (int) $_GET['trp_updb_batch'] > 0 ) {
152
+ $get_batch = (int)$_GET['trp_updb_batch'];
153
+ }else{
154
+ $get_batch = 0;
155
+ }
156
+
157
+ $this->print_queried_tables( $language_code );
158
+
159
+ $start_time = microtime(true);
160
+ $duration = 0;
161
+ while( $duration < 2 ){
162
+ $inferior_limit = $batch_size * $get_batch;
163
+ $finished_with_language = $this->execute_full_trim( $language_code, $inferior_limit, $batch_size );
164
+ if ( $finished_with_language ) {
165
+ break;
166
+ }else {
167
+ $get_batch = $get_batch + 1;
168
+ }
169
+ $stop_time = microtime( true );
170
+ $duration = $stop_time - $start_time;
171
+ }
172
+ if ( ! $finished_with_language ) {
173
+ $next_get_batch = $get_batch + 1;
174
+ }
175
+ }
176
+
177
+ if ( $finished_with_language ) {
178
+ // finished with the current language
179
+ $index = array_search( $language_code, $this->settings['translation-languages'] );
180
+ if ( isset ( $this->settings['translation-languages'][ $index + 1 ] ) ) {
181
+ // next language code in array
182
+ $next_language = $this->settings['translation-languages'][ $index + 1 ];
183
+ } else {
184
+ // finish iteration due to completing all the translation languages
185
+ $next_language = 'done';
186
+ // this will stop showing the admin notice
187
+ update_option( 'trp_updated_database_full_trim_originals_140', 'yes' );
188
+ }
189
+ }else{
190
+ $next_language = $language_code;
191
+ }
192
+ }else{
193
+ // finish iteration due to incorrect translation language
194
+ $next_language = 'done';
195
+ }
196
+
197
+ // construct and redirect to next url
198
+ $url = add_query_arg( array(
199
+ 'page' => 'trp_update_database',
200
+ 'trp_updb_lang' => $next_language,
201
+ 'trp_updb_batch' => $next_get_batch,
202
+ 'trp_updb_batch_size' => $batch_size,
203
+ 'trp_updb_nonce' => wp_create_nonce('tpupdatedatabase')
204
+ ), site_url('wp-admin/admin.php') );
205
+ echo "<meta http-equiv='refresh' content='0; url={$url}' />";
206
+ echo "<br> " . __( 'If the page does not redirect automatically', 'translatepress-multilingual' ) . " <a href='$url' >" . __( 'click here', 'translatepress-multilingual' ) . ".</a>";
207
+ exit;
208
+ }
209
+
210
+ /**
211
+ * Prints all the tables in the translation languages array until the current language with Done.
212
+ *
213
+ * If current language is given, do not print Done for it.
214
+ *
215
+ * @param bool | string $current_language_code
216
+ */
217
+ public function print_queried_tables( $current_language_code = false ){
218
+ if ( ! $this->trp_query ) {
219
+ $trp = TRP_Translate_Press::get_trp_instance();
220
+ /* @var TRP_Query */
221
+ $this->trp_query = $trp->get_component( 'query' );
222
+ }
223
+ foreach ( $this->settings['translation-languages'] as $language_code ){
224
+ if ( $language_code == $this->settings['default-language'] ){
225
+ continue;
226
+ }
227
+ $table_name = $this->trp_query->get_table_name( $language_code );
228
+ $html = '<div>' . sprintf( __( 'Querying table <strong>%s</strong>... ', 'translatepress-multilingual' ), $table_name );
229
+ if ( $language_code != $current_language_code ) {
230
+ $html .= __( 'Done.', 'translatepress-multilingual' );
231
+ }
232
+ $html .= '</div>';
233
+ echo $html;
234
+ if ( $language_code == $current_language_code ) {
235
+ break;
236
+ }
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Get all originals from the table, trim them and update originals back into table
242
+ *
243
+ * @param string $language_code Language code of the table
244
+ * @param int $inferior_limit Omit first X rows
245
+ * @param int $batch_size How many rows to query
246
+ *
247
+ * @return bool
248
+ */
249
+ public function execute_full_trim( $language_code, $inferior_limit, $batch_size ){
250
+ if ( ! $this->trp_query ) {
251
+ $trp = TRP_Translate_Press::get_trp_instance();
252
+ /* @var TRP_Query */
253
+ $this->trp_query = $trp->get_component( 'query' );
254
+ }
255
+ $strings = $this->trp_query->get_rows_from_location( $language_code, $inferior_limit, $batch_size, array( 'id', 'original' ) );
256
+ if ( count( $strings ) == 0 ) {
257
+ return true;
258
+ }
259
+ foreach( $strings as $key => $string ){
260
+ $strings[$key]['original'] = trp_full_trim( $strings[$key]['original'] );
261
+ }
262
+
263
+ // overwrite original only
264
+ $this->trp_query->update_strings( $strings, $language_code, array( 'id', 'original' ), array( '%d', '%s' ) );
265
+ return false;
266
+ }
267
+
268
+ /**
269
+ * Remove duplicate rows from DB for trp_dictionary tables.
270
+ * Removes untranslated strings if there is a translated version.
271
+ *
272
+ * Iterates over languages. Each language is iterated in batches of 10 000
273
+ *
274
+ * Not accessible from anywhere else
275
+ * http://example.com/wp-admin/admin.php?page=trp_remove_duplicate_rows
276
+ */
277
+ public function trp_remove_duplicate_rows(){
278
+ if ( ! current_user_can( 'manage_options' ) ){
279
+ return;
280
+ }
281
+ // prepare page structure
282
+ require_once TRP_PLUGIN_DIR . 'partials/trp-remove-duplicate-rows.php';
283
+
284
+ if ( empty( $_GET['trp_rm_duplicates'] ) ){
285
+ // iteration not started
286
+ return;
287
+ }
288
+ if ( $_GET['trp_rm_duplicates'] === 'done' ){
289
+ // iteration finished
290
+ echo __('Done.', 'translatepress-multilingual' ) . '<br><br><a href="' . site_url('wp-admin/options-general.php?page=translate-press') . '"> <input type="button" value="' . __('Back to TranslatePress Settings page', 'translatepress-multilingual' ) . '" class="button-primary"></a>';
291
+ return;
292
+ }
293
+ $nonce = wp_verify_nonce( $_GET['trp_rm_nonce'], 'tpremoveduplicaterows' );
294
+ if ( $nonce === false ){
295
+ echo __('Invalid nonce.', 'translatepress-multilingual' ) . '<br><br><a href="' . site_url('wp-admin/options-general.php?page=translate-press') . '"> <input type="button" value="' . __('Back to TranslatePress Settings page', 'translatepress-multilingual' ) . '" class="button-primary"></a>';
296
+ return;
297
+ }
298
+
299
+ $next_get_batch = 1;
300
+ $batch_size = apply_filters( 'trp_rm_duplicate_batch_size', 10000 );
301
+ if ( !empty( $_GET['trp_rm_batch_size'] ) && (int) $_GET['trp_rm_batch'] > 0 ){
302
+ $batch_size = (int) $_GET['trp_rm_batch_size'];
303
+ }
304
+ if ( in_array( $_GET['trp_rm_duplicates'], $this->settings['translation-languages'] ) ) {
305
+ // language code found in array
306
+ $language_code = $_GET['trp_rm_duplicates'];
307
+ // skip default language since it doesn't have a table
308
+ if ( $language_code != $this->settings['default-language'] ) {
309
+ if ( ! $this->trp_query ) {
310
+ $trp = TRP_Translate_Press::get_trp_instance();
311
+ /* @var TRP_Query */
312
+ $this->trp_query = $trp->get_component( 'query' );
313
+ }
314
+ $table_name = $this->trp_query->get_table_name( $language_code );
315
+ echo '<div>' . sprintf( __( 'Querying table <strong>%s</strong>', 'translatepress-multilingual' ), $table_name ) . '</div>';
316
+
317
+ $last_id = $this->trp_query->get_last_id( $table_name );
318
+ if ( !empty( $_GET['trp_rm_batch'] ) && (int) $_GET['trp_rm_batch'] > 0 ) {
319
+ $get_batch = (int)$_GET['trp_rm_batch'];
320
+ }else{
321
+ $get_batch = 1;
322
+ }
323
+ $batch = $batch_size * $get_batch;
324
+
325
+ /* Execute this query only for string with ID < $batch. This ensures that the query is fast.
326
+ * Deleting duplicate rows for the first 20k rows might take too long.
327
+ * As a solution we are deleting the duplicates of the first 10k rows ( 1 to 10 000),
328
+ * then delete duplicates of the first 20k rows( 1 to 20 000, not 10 000 to 20 000 because we there could still be duplicates).
329
+ * Same goes for higher numbers.
330
+ */
331
+ $result1 = $this->trp_query->remove_duplicate_rows_in_dictionary_table( $language_code, $batch );
332
+ $result2 = 0;
333
+ if ( $batch > $last_id ){
334
+ // execute this query only when we do not have any more duplicate rows
335
+ $result2 = $this->trp_query->remove_untranslated_strings_if_translation_available( $language_code );
336
+ }else{
337
+ $next_get_batch = $get_batch + 1;
338
+ }
339
+
340
+ if ( ( $result1 === false ) || ( $result2 === false ) ) {
341
+ // if query outputted error do not continue iteration
342
+ return;
343
+ }else{
344
+ $result = $result1 + $result2;
345
+ echo '<div>' . sprintf( __( '%s duplicates removed', 'translatepress-multilingual' ), $result ) . '</div>';
346
+ }
347
+ }
348
+ if ( $next_get_batch == 1 ) {
349
+ // finished with the current language
350
+ $index = array_search( $language_code, $this->settings['translation-languages'] );
351
+ if ( isset ( $this->settings['translation-languages'][ $index + 1 ] ) ) {
352
+ // next language code in array
353
+ $next_language = $this->settings['translation-languages'][ $index + 1 ];
354
+ } else {
355
+ // finish iteration due to completing all the translation languages
356
+ $next_language = 'done';
357
+ }
358
+ }else{
359
+ $next_language = $language_code;
360
+ }
361
+ }else{
362
+ // finish iteration due to incorrect translation language
363
+ $next_language = 'done';
364
+ }
365
+
366
+ // construct and redirect to next url
367
+ $url = add_query_arg( array(
368
+ 'page' => 'trp_remove_duplicate_rows',
369
+ 'trp_rm_duplicates' => $next_language,
370
+ 'trp_rm_batch' => $next_get_batch,
371
+ 'trp_rm_batch_size' => $batch_size,
372
+ 'trp_rm_nonce' => wp_create_nonce('tpremoveduplicaterows')
373
+ ), site_url('wp-admin/admin.php') );
374
+ echo "<meta http-equiv='refresh' content='0; url={$url}' />";
375
+ echo "<br> " . __( 'If the page does not redirect automatically', 'translatepress-multilingual' ) . " <a href='$url' >" . __( 'click here', 'translatepress-multilingual' ) . ".</a>";
376
+ exit;
377
+ }
378
+ }
includes/functions.php CHANGED
@@ -164,6 +164,43 @@ function trp_sanitize_string( $filtered ){
164
  return $filtered;
165
  }
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
  /**
169
  * function that checks if $_REQUEST['trp-edit-translation'] is set or if it has a certain value
@@ -582,4 +619,21 @@ function trp_bulk_debug($debug = false, $logger = array()){
582
  error_log("$key : " . str_repeat(' ', $key_length - strlen($key)) . $value);
583
  }
584
  error_log('---------------------------------------------------------');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  }
164
  return $filtered;
165
  }
166
 
167
+ /**
168
+ * Trim strings.
169
+ *
170
+ * @param string $string Raw string.
171
+ * @return string Trimmed string.
172
+ */
173
+ function trp_full_trim( $string ) {
174
+ /* Make sure you update full_trim function from trp-ajax too*/
175
+
176
+ /* Apparently the � char in the trim function turns some strings in an empty string so they can't be translated but I don't really know if we should remove it completely
177
+ Removed chr( 194 ) . chr( 160 ) because it altered some special characters (¿¡)
178
+ Also removed \xA0 (the same as chr(160) for altering special characters */
179
+ //$word = trim($word," \t\n\r\0\x0B\xA0�".chr( 194 ) . chr( 160 ) );
180
+
181
+ /* Solution to replace the chr(194).chr(160) from trim function, in order to escape the whitespace character ( \xc2\xa0 ), an old bug that couldn't be replicated anymore. */
182
+ /* Trim nbsp the same way as the whitespace (chr194 chr160) above */
183
+ $prefixes = array( "\xc2\xa0", "&nbsp;" );
184
+ do{
185
+ $previous_iteration_string = $string;
186
+ $string = trim($string, " \t\n\r\0\x0B");
187
+ foreach( $prefixes as $prefix ) {
188
+ $prefix_length = strlen($prefix);
189
+ if (substr($string, 0, $prefix_length) == $prefix) {
190
+ $string = substr($string, $prefix_length);
191
+ }
192
+ if (substr($string, -$prefix_length, $prefix_length) == $prefix) {
193
+ $string = substr($string, 0, -$prefix_length);
194
+ }
195
+ }
196
+ }while( $string != $previous_iteration_string );
197
+
198
+ if ( strip_tags( $string ) == "" || trim ($string, " \t\n\r\0\x0B\xA0�.,/`~!@#\$€£%^&*():;-_=+[]{}\\|?/<>1234567890'\"" ) == '' ){
199
+ $string = '';
200
+ }
201
+
202
+ return $string;
203
+ }
204
 
205
  /**
206
  * function that checks if $_REQUEST['trp-edit-translation'] is set or if it has a certain value
619
  error_log("$key : " . str_repeat(' ', $key_length - strlen($key)) . $value);
620
  }
621
  error_log('---------------------------------------------------------');
622
+ }
623
+
624
+ /**
625
+ * Compatibility with WooCommerce PDF Invoices & Packing Slips
626
+ * https://wordpress.org/plugins/woocommerce-pdf-invoices-packing-slips/
627
+ *
628
+ * @since 1.4.0
629
+ *
630
+ * @param string $html
631
+ * @param object $instance
632
+ */
633
+
634
+ add_filter( 'wpo_wcpdf_get_html', 'trp_woo_pdf_invoices_and_packing_slips_compatibility', 10, 2);
635
+ function trp_woo_pdf_invoices_and_packing_slips_compatibility($html, $instance){
636
+ $html = str_replace('#!trpst#', '<', $html);
637
+ $html = str_replace('#!trpen#', '>', $html);
638
+ return $html;
639
  }
includes/trp-ajax.php CHANGED
@@ -144,26 +144,29 @@ class TRP_Ajax{
144
  * @return string Trimmed string.
145
  */
146
  protected function full_trim( $string ) {
147
- /* Make sure you update full_trim function from translation-render too*/
148
-
149
- /* Apparently the � char in the trim function turns some strings in an empty string so they can't be translated but I don't really know if we should remove it completely
150
- Removed chr( 194 ) . chr( 160 ) because it altered some special characters (¿¡)
151
- Also removed \xA0 (the same as chr(160) for altering special characters */
152
- //$word = trim($word," \t\n\r\0\x0B\xA0�".chr( 194 ) . chr( 160 ) );
153
-
154
- /* Solution to replace the chr(194).chr(160) from trim function, in order to escape the whitespace character ( \xc2\xa0 ), an old bug that couldn't be replicated anymore. */
155
- $prefix = "\xc2\xa0";
156
- $prefix_length = strlen($prefix);
157
- do{
158
- $previous_iteration_string = $string;
159
- $string = trim( $string," \t\n\r\0\x0B");
160
- if ( substr( $string, 0, $prefix_length ) == $prefix ) {
161
- $string = substr( $string, $prefix_length );
162
- }
163
- if ( substr( $string, - $prefix_length, $prefix_length ) == $prefix ) {
164
- $string = substr( $string, 0, - $prefix_length );
165
- }
166
- }while( $string != $previous_iteration_string );
 
 
 
167
 
168
  if ( strip_tags( $string ) == "" || trim ($string, " \t\n\r\0\x0B\xA0�.,/`~!@#\$€£%^&*():;-_=+[]{}\\|?/<>1234567890'\"" ) == '' ){
169
  $string = '';
144
  * @return string Trimmed string.
145
  */
146
  protected function full_trim( $string ) {
147
+ /* Make sure you update full_trim function from translatepress/includes/functions.php too*/
148
+
149
+ /* Apparently the � char in the trim function turns some strings in an empty string so they can't be translated but I don't really know if we should remove it completely
150
+ Removed chr( 194 ) . chr( 160 ) because it altered some special characters (¿¡)
151
+ Also removed \xA0 (the same as chr(160) for altering special characters */
152
+ //$word = trim($word," \t\n\r\0\x0B\xA0�".chr( 194 ) . chr( 160 ) );
153
+
154
+ /* Solution to replace the chr(194).chr(160) from trim function, in order to escape the whitespace character ( \xc2\xa0 ), an old bug that couldn't be replicated anymore. */
155
+ /* Trim nbsp the same way as the whitespace (chr194 chr160) above */
156
+ $prefixes = array( "\xc2\xa0", "&nbsp;" );
157
+ do{
158
+ $previous_iteration_string = $string;
159
+ $string = trim($string, " \t\n\r\0\x0B");
160
+ foreach( $prefixes as $prefix ) {
161
+ $prefix_length = strlen($prefix);
162
+ if (substr($string, 0, $prefix_length) == $prefix) {
163
+ $string = substr($string, $prefix_length);
164
+ }
165
+ if (substr($string, -$prefix_length, $prefix_length) == $prefix) {
166
+ $string = substr($string, 0, -$prefix_length);
167
+ }
168
+ }
169
+ }while( $string != $previous_iteration_string );
170
 
171
  if ( strip_tags( $string ) == "" || trim ($string, " \t\n\r\0\x0B\xA0�.,/`~!@#\$€£%^&*():;-_=+[]{}\\|?/<>1234567890'\"" ) == '' ){
172
  $string = '';
index.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: TranslatePress - Multilingual
4
  Plugin URI: https://translatepress.com/
5
  Description: Experience a better way of translating your WordPress site, with full support for WooCommerce and site builders.
6
- Version: 1.3.9
7
  Author: Cozmoslabs, Razvan Mocanu, Madalin Ungureanu, Cristophor Hurduban
8
  Author URI: https://cozmoslabs.com/
9
  Text Domain: translatepress-multilingual
3
  Plugin Name: TranslatePress - Multilingual
4
  Plugin URI: https://translatepress.com/
5
  Description: Experience a better way of translating your WordPress site, with full support for WooCommerce and site builders.
6
+ Version: 1.4.0
7
  Author: Cozmoslabs, Razvan Mocanu, Madalin Ungureanu, Cristophor Hurduban
8
  Author URI: https://cozmoslabs.com/
9
  Text Domain: translatepress-multilingual
languages/translatepress-multilingual.catalog.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php __("", "translatepress-multilingual"); ?>
2
  <?php __("Error! Duplicate Url slug values.", "translatepress-multilingual"); ?>
3
  <?php __("Limit this menu item to the following languages", "translatepress-multilingual"); ?>
 
4
  <?php __("The Yoast SEO Sitemaps will now contain the default language slug: example.com/en/sitemap_index.xml <br/> This works perfectly, just take it into account when you submit the sitemap to Google.", "translatepress-multilingual"); ?>
5
  <?php __("First by browser language, then IP address (recommended)", "translatepress-multilingual"); ?>
6
  <?php __("First by IP address, then browser language", "translatepress-multilingual"); ?>
@@ -14,7 +15,6 @@
14
  <?php __("Deactivate License", "translatepress-multilingual"); ?>
15
  <?php __("Method of language detection", "translatepress-multilingual"); ?>
16
  <?php __("Select how the language should be detected for first time visitors.<br>The visitor's last displayed language will be remembered through cookies.", "translatepress-multilingual"); ?>
17
- <?php __("All Languages", "translatepress-multilingual"); ?>
18
  <?php __("Language", "translatepress-multilingual"); ?>
19
  <?php __("Code", "translatepress-multilingual"); ?>
20
  <?php __("Slug", "translatepress-multilingual"); ?>
@@ -32,13 +32,6 @@
32
  <?php __("Flags with Full Language Names", "translatepress-multilingual"); ?>
33
  <?php __("Flags with Short Language Names", "translatepress-multilingual"); ?>
34
  <?php __("Only Flags", "translatepress-multilingual"); ?>
35
- <?php __("Done.", "translatepress-multilingual"); ?>
36
- <?php __("Back to TranslatePress Settings page", "translatepress-multilingual"); ?>
37
- <?php __("Invalid nonce.", "translatepress-multilingual"); ?>
38
- <?php __("Querying table <strong>%s</strong>", "translatepress-multilingual"); ?>
39
- <?php __("%s duplicates removed", "translatepress-multilingual"); ?>
40
- <?php __("If the page does not redirect automatically", "translatepress-multilingual"); ?>
41
- <?php __("click here", "translatepress-multilingual"); ?>
42
  <?php __("Current Language", "translatepress-multilingual"); ?>
43
  <?php __("General", "translatepress-multilingual"); ?>
44
  <?php __("Translate Site", "translatepress-multilingual"); ?>
@@ -56,6 +49,7 @@
56
  <?php __("Dynamic Added Strings", "translatepress-multilingual"); ?>
57
  <?php __("Translate Page", "translatepress-multilingual"); ?>
58
  <?php __("Security check", "translatepress-multilingual"); ?>
 
59
  <?php __("Description", "translatepress-multilingual"); ?>
60
  <?php __("OG Title", "translatepress-multilingual"); ?>
61
  <?php __("OG Site Name", "translatepress-multilingual"); ?>
@@ -64,6 +58,18 @@
64
  <?php __("Twitter Description", "translatepress-multilingual"); ?>
65
  <?php __("Post Slug", "translatepress-multilingual"); ?>
66
  <?php __("Page Title", "translatepress-multilingual"); ?>
 
 
 
 
 
 
 
 
 
 
 
 
67
  <?php __("<strong>TranslatePress</strong> requires <strong><a href=\"http://php.net/manual/en/book.mbstring.php\">Multibyte String PHP library</a></strong>. Please contact your server administrator to install it on your server.", "translatepress-multilingual"); ?>
68
  <?php __("Select the language you wish to make your website available in.", "translatepress-multilingual"); ?>
69
  <?php __("To add <strong>more then two languages</strong> and support for SEO Title, Description, Slug and more check out <a href=\"%s\" class=\"button button-primary\" target=\"_blank\" title=\"TranslatePress Pro\">TranslatePress PRO</a>", "translatepress-multilingual"); ?>
@@ -138,6 +144,9 @@
138
  <?php __("Batch size", "translatepress-multilingual"); ?>
139
  <?php __("The number of rows to check at once.<br>Choosing a smaller number helps solve the 502 error \"Page took too long to respond\" on large databases.<br>May take several minutes depending on the database size.", "translatepress-multilingual"); ?>
140
  <?php __("Remove duplicate rows", "translatepress-multilingual"); ?>
 
 
 
141
  <?php __(" TranslatePress Settings", "translatepress-multilingual"); ?>
142
  <?php __("Translator", "translatepress-multilingual"); ?>
143
  <?php __("Allow this user to translate the website.", "translatepress-multilingual"); ?>
1
  <?php __("", "translatepress-multilingual"); ?>
2
  <?php __("Error! Duplicate Url slug values.", "translatepress-multilingual"); ?>
3
  <?php __("Limit this menu item to the following languages", "translatepress-multilingual"); ?>
4
+ <?php __("All Languages", "translatepress-multilingual"); ?>
5
  <?php __("The Yoast SEO Sitemaps will now contain the default language slug: example.com/en/sitemap_index.xml <br/> This works perfectly, just take it into account when you submit the sitemap to Google.", "translatepress-multilingual"); ?>
6
  <?php __("First by browser language, then IP address (recommended)", "translatepress-multilingual"); ?>
7
  <?php __("First by IP address, then browser language", "translatepress-multilingual"); ?>
15
  <?php __("Deactivate License", "translatepress-multilingual"); ?>
16
  <?php __("Method of language detection", "translatepress-multilingual"); ?>
17
  <?php __("Select how the language should be detected for first time visitors.<br>The visitor's last displayed language will be remembered through cookies.", "translatepress-multilingual"); ?>
 
18
  <?php __("Language", "translatepress-multilingual"); ?>
19
  <?php __("Code", "translatepress-multilingual"); ?>
20
  <?php __("Slug", "translatepress-multilingual"); ?>
32
  <?php __("Flags with Full Language Names", "translatepress-multilingual"); ?>
33
  <?php __("Flags with Short Language Names", "translatepress-multilingual"); ?>
34
  <?php __("Only Flags", "translatepress-multilingual"); ?>
 
 
 
 
 
 
 
35
  <?php __("Current Language", "translatepress-multilingual"); ?>
36
  <?php __("General", "translatepress-multilingual"); ?>
37
  <?php __("Translate Site", "translatepress-multilingual"); ?>
49
  <?php __("Dynamic Added Strings", "translatepress-multilingual"); ?>
50
  <?php __("Translate Page", "translatepress-multilingual"); ?>
51
  <?php __("Security check", "translatepress-multilingual"); ?>
52
+ <?php __("<strong>Warning:</strong> Some strings have possibly incorrectly encoded characters. This may result in breaking the queries, rendering the page untranslated in live mode. Consider revising the following strings or their method of outputting.", "translatepress-multilingual"); ?>
53
  <?php __("Description", "translatepress-multilingual"); ?>
54
  <?php __("OG Title", "translatepress-multilingual"); ?>
55
  <?php __("OG Site Name", "translatepress-multilingual"); ?>
58
  <?php __("Twitter Description", "translatepress-multilingual"); ?>
59
  <?php __("Post Slug", "translatepress-multilingual"); ?>
60
  <?php __("Page Title", "translatepress-multilingual"); ?>
61
+ <?php __("TranslatePress data update", "translatepress-multilingual"); ?>
62
+ <?php __("We need to update your translations database to the latest version.", "translatepress-multilingual"); ?>
63
+ <?php __("Run the updater", "translatepress-multilingual"); ?>
64
+ <?php __("<p><strong>Successfully updated database!</strong></p>", "translatepress-multilingual"); ?>
65
+ <?php __("Back to TranslatePress Settings page", "translatepress-multilingual"); ?>
66
+ <?php __("Invalid nonce.", "translatepress-multilingual"); ?>
67
+ <?php __("If the page does not redirect automatically", "translatepress-multilingual"); ?>
68
+ <?php __("click here", "translatepress-multilingual"); ?>
69
+ <?php __("Querying table <strong>%s</strong>... ", "translatepress-multilingual"); ?>
70
+ <?php __("Done.", "translatepress-multilingual"); ?>
71
+ <?php __("Querying table <strong>%s</strong>", "translatepress-multilingual"); ?>
72
+ <?php __("%s duplicates removed", "translatepress-multilingual"); ?>
73
  <?php __("<strong>TranslatePress</strong> requires <strong><a href=\"http://php.net/manual/en/book.mbstring.php\">Multibyte String PHP library</a></strong>. Please contact your server administrator to install it on your server.", "translatepress-multilingual"); ?>
74
  <?php __("Select the language you wish to make your website available in.", "translatepress-multilingual"); ?>
75
  <?php __("To add <strong>more then two languages</strong> and support for SEO Title, Description, Slug and more check out <a href=\"%s\" class=\"button button-primary\" target=\"_blank\" title=\"TranslatePress Pro\">TranslatePress PRO</a>", "translatepress-multilingual"); ?>
144
  <?php __("Batch size", "translatepress-multilingual"); ?>
145
  <?php __("The number of rows to check at once.<br>Choosing a smaller number helps solve the 502 error \"Page took too long to respond\" on large databases.<br>May take several minutes depending on the database size.", "translatepress-multilingual"); ?>
146
  <?php __("Remove duplicate rows", "translatepress-multilingual"); ?>
147
+ <?php __("Update TranslatePress tables", "translatepress-multilingual"); ?>
148
+ <?php __("<p><strong>IMPORTANT NOTE: Before performing this action it is strongly recommended to backup the database first.</strong></p>", "translatepress-multilingual"); ?>
149
+ <?php __("Update database", "translatepress-multilingual"); ?>
150
  <?php __(" TranslatePress Settings", "translatepress-multilingual"); ?>
151
  <?php __("Translator", "translatepress-multilingual"); ?>
152
  <?php __("Allow this user to translate the website.", "translatepress-multilingual"); ?>
languages/translatepress-multilingual.pot CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2018 TranslatePress Multilingual
2
  # This file is distributed under the same license as the TranslatePress Multilingual package.
3
  msgid ""
4
  msgstr ""
@@ -13,70 +13,70 @@ msgstr ""
13
  "X-Poedit-SourceCharset: UTF-8\n"
14
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
 
16
- #: ../tp-add-on-extra-languages/class-extra-languages.php:57, ../translatepress/includes/class-settings.php:416
17
  msgid "Error! Duplicate Url slug values."
18
  msgstr ""
19
 
20
- #: class-navigation-based-on-language.php:85
21
  msgid "Limit this menu item to the following languages"
22
  msgstr ""
23
 
 
 
 
 
24
  #: ../tp-add-on-seo-pack/class-seo-pack.php:160
25
  msgid "The Yoast SEO Sitemaps will now contain the default language slug: example.com/en/sitemap_index.xml <br/> This works perfectly, just take it into account when you submit the sitemap to Google."
26
  msgstr ""
27
 
28
- #: ../tp-add-on-automatic-language-detection/includes/class-ald-settings.php:37
29
  msgid "First by browser language, then IP address (recommended)"
30
  msgstr ""
31
 
32
- #: ../tp-add-on-automatic-language-detection/includes/class-ald-settings.php:38
33
  msgid "First by IP address, then browser language"
34
  msgstr ""
35
 
36
- #: ../tp-add-on-automatic-language-detection/includes/class-ald-settings.php:39
37
  msgid "Only by browser language"
38
  msgstr ""
39
 
40
- #: ../tp-add-on-automatic-language-detection/includes/class-ald-settings.php:40
41
  msgid "Only by IP address"
42
  msgstr ""
43
 
44
- #: ../tp-add-on-automatic-language-detection/includes/class-ald-settings.php:110
45
  msgid "<div class=\"warning\">WARNING. Cannot determine your language preference based on your current IP.<br>This is most likely because the website is on a local environment.</div>"
46
  msgstr ""
47
 
48
- #: ../tp-add-on-automatic-language-detection/partials/license-settings-page.php:4, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:4, ../tp-add-on-extra-languages/partials/license-settings-page.php:4, partials/license-settings-page.php:4, ../tp-add-on-seo-pack/partials/license-settings-page.php:4, ../translatepress/partials/addons-settings-page.php:3, ../translatepress/partials/main-settings-page.php:5, ../translatepress/partials/test-google-key-settings-page.php:10, ../translatepress/partials/trp-remove-duplicate-rows.php:3, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:4
49
  msgid "TranslatePress Settings"
50
  msgstr ""
51
 
52
- #: ../tp-add-on-automatic-language-detection/partials/license-settings-page.php:10, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:10, ../tp-add-on-extra-languages/partials/license-settings-page.php:10, partials/license-settings-page.php:10, ../tp-add-on-seo-pack/partials/license-settings-page.php:10, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:10
53
  msgid "License Key"
54
  msgstr ""
55
 
56
- #: ../tp-add-on-automatic-language-detection/partials/license-settings-page.php:15, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:15, ../tp-add-on-extra-languages/partials/license-settings-page.php:15, partials/license-settings-page.php:15, ../tp-add-on-seo-pack/partials/license-settings-page.php:15, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:15
57
  msgid "Enter your license key."
58
  msgstr ""
59
 
60
- #: ../tp-add-on-automatic-language-detection/partials/license-settings-page.php:22, ../tp-add-on-automatic-language-detection/partials/license-settings-page.php:31, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:22, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:31, ../tp-add-on-extra-languages/partials/license-settings-page.php:22, ../tp-add-on-extra-languages/partials/license-settings-page.php:31, partials/license-settings-page.php:22, partials/license-settings-page.php:31, ../tp-add-on-seo-pack/partials/license-settings-page.php:22, ../tp-add-on-seo-pack/partials/license-settings-page.php:31, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:22, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:31
61
  msgid "Activate License"
62
  msgstr ""
63
 
64
- #: ../tp-add-on-automatic-language-detection/partials/license-settings-page.php:28, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:28, ../tp-add-on-extra-languages/partials/license-settings-page.php:28, partials/license-settings-page.php:28, ../tp-add-on-seo-pack/partials/license-settings-page.php:28, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:28
65
  msgid "Deactivate License"
66
  msgstr ""
67
 
68
- #: ../tp-add-on-automatic-language-detection/partials/settings-option.php:2
69
  msgid "Method of language detection"
70
  msgstr ""
71
 
72
- #: ../tp-add-on-automatic-language-detection/partials/settings-option.php:14
73
  msgid "Select how the language should be detected for first time visitors.<br>The visitor's last displayed language will be remembered through cookies."
74
  msgstr ""
75
 
76
- #: ../tp-add-on-extra-languages/partials/language-selector-pro.php:2, ../translatepress/partials/main-settings-language-selector.php:2
77
- msgid "All Languages"
78
- msgstr ""
79
-
80
  #: ../tp-add-on-extra-languages/partials/language-selector-pro.php:7, ../translatepress/partials/main-settings-language-selector.php:7
81
  msgid "Language"
82
  msgstr ""
@@ -145,59 +145,31 @@ msgstr ""
145
  msgid "Only Flags"
146
  msgstr ""
147
 
148
- #: ../translatepress/includes/class-settings.php:124
149
- msgid "Done."
150
- msgstr ""
151
-
152
- #: ../translatepress/includes/class-settings.php:124, ../translatepress/includes/class-settings.php:129
153
- msgid "Back to TranslatePress Settings page"
154
- msgstr ""
155
-
156
- #: ../translatepress/includes/class-settings.php:129
157
- msgid "Invalid nonce."
158
- msgstr ""
159
-
160
- #: ../translatepress/includes/class-settings.php:149
161
- msgid "Querying table <strong>%s</strong>"
162
- msgstr ""
163
-
164
- #: ../translatepress/includes/class-settings.php:179
165
- msgid "%s duplicates removed"
166
- msgstr ""
167
-
168
- #: ../translatepress/includes/class-settings.php:209
169
- msgid "If the page does not redirect automatically"
170
- msgstr ""
171
-
172
- #: ../translatepress/includes/class-settings.php:209
173
- msgid "click here"
174
- msgstr ""
175
-
176
- #: ../translatepress/includes/class-settings.php:452
177
  msgid "Current Language"
178
  msgstr ""
179
 
180
- #: ../translatepress/includes/class-settings.php:493
181
  msgid "General"
182
  msgstr ""
183
 
184
- #: ../translatepress/includes/class-settings.php:498, ../translatepress/includes/class-translation-manager.php:617
185
  msgid "Translate Site"
186
  msgstr ""
187
 
188
- #: ../translatepress/includes/class-settings.php:506
189
  msgid "License"
190
  msgstr ""
191
 
192
- #: ../translatepress/includes/class-settings.php:512
193
  msgid "Addons"
194
  msgstr ""
195
 
196
- #: ../translatepress/includes/class-settings.php:537, ../translatepress/includes/class-translation-manager.php:648
197
  msgid "Settings"
198
  msgstr ""
199
 
200
- #: ../translatepress/includes/class-settings.php:541
201
  msgid "Pro Features"
202
  msgstr ""
203
 
@@ -237,43 +209,95 @@ msgstr ""
237
  msgid "Translate Page"
238
  msgstr ""
239
 
240
- #: ../translatepress/includes/class-translation-manager.php:1197
241
  msgid "Security check"
242
  msgstr ""
243
 
244
- #: ../translatepress/includes/class-translation-render.php:166
 
 
 
 
245
  msgid "Description"
246
  msgstr ""
247
 
248
- #: ../translatepress/includes/class-translation-render.php:172
249
  msgid "OG Title"
250
  msgstr ""
251
 
252
- #: ../translatepress/includes/class-translation-render.php:178
253
  msgid "OG Site Name"
254
  msgstr ""
255
 
256
- #: ../translatepress/includes/class-translation-render.php:184
257
  msgid "OG Description"
258
  msgstr ""
259
 
260
- #: ../translatepress/includes/class-translation-render.php:190
261
  msgid "Twitter Title"
262
  msgstr ""
263
 
264
- #: ../translatepress/includes/class-translation-render.php:196
265
  msgid "Twitter Description"
266
  msgstr ""
267
 
268
- #: ../translatepress/includes/class-translation-render.php:202
269
  msgid "Post Slug"
270
  msgstr ""
271
 
272
- #: ../translatepress/includes/class-translation-render.php:206
273
  msgid "Page Title"
274
  msgstr ""
275
 
276
- #: ../translatepress/includes/functions.php:216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  msgid "<strong>TranslatePress</strong> requires <strong><a href=\"http://php.net/manual/en/book.mbstring.php\">Multibyte String PHP library</a></strong>. Please contact your server administrator to install it on your server."
278
  msgstr ""
279
 
@@ -553,7 +577,7 @@ msgstr ""
553
  msgid "<strong>IMPORTANT NOTE: Before performing this action it is strongly recommended to backup the database first.</strong><br><br>This feature can be used to cleanup duplicate entries in TranslatePress trp_dictionary tables. Such duplicates can appear in exceptional situations of unexpected behavior."
554
  msgstr ""
555
 
556
- #: ../translatepress/partials/trp-remove-duplicate-rows.php:12
557
  msgid ""
558
  "IMPORTANT: It is strongly recommended to backup the database first!\n"
559
  "Are you sure you want to continue?"
@@ -571,6 +595,18 @@ msgstr ""
571
  msgid "Remove duplicate rows"
572
  msgstr ""
573
 
 
 
 
 
 
 
 
 
 
 
 
 
574
  #: ../trp-add-on-translator-accounts-add-on/includes/class-translator-accounts.php:119
575
  msgid " TranslatePress Settings"
576
  msgstr ""
1
+ # Copyright (C) 2019 TranslatePress Multilingual
2
  # This file is distributed under the same license as the TranslatePress Multilingual package.
3
  msgid ""
4
  msgstr ""
13
  "X-Poedit-SourceCharset: UTF-8\n"
14
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
15
 
16
+ #: ../tp-add-on-extra-languages/class-extra-languages.php:57, ../translatepress/includes/class-settings.php:307
17
  msgid "Error! Duplicate Url slug values."
18
  msgstr ""
19
 
20
+ #: ../tp-add-on-navigation-based-on-language/class-navigation-based-on-language.php:86
21
  msgid "Limit this menu item to the following languages"
22
  msgstr ""
23
 
24
+ #: ../tp-add-on-navigation-based-on-language/class-navigation-based-on-language.php:92, ../tp-add-on-extra-languages/partials/language-selector-pro.php:2, ../translatepress/partials/main-settings-language-selector.php:2
25
+ msgid "All Languages"
26
+ msgstr ""
27
+
28
  #: ../tp-add-on-seo-pack/class-seo-pack.php:160
29
  msgid "The Yoast SEO Sitemaps will now contain the default language slug: example.com/en/sitemap_index.xml <br/> This works perfectly, just take it into account when you submit the sitemap to Google."
30
  msgstr ""
31
 
32
+ #: includes/class-ald-settings.php:37
33
  msgid "First by browser language, then IP address (recommended)"
34
  msgstr ""
35
 
36
+ #: includes/class-ald-settings.php:38
37
  msgid "First by IP address, then browser language"
38
  msgstr ""
39
 
40
+ #: includes/class-ald-settings.php:39
41
  msgid "Only by browser language"
42
  msgstr ""
43
 
44
+ #: includes/class-ald-settings.php:40
45
  msgid "Only by IP address"
46
  msgstr ""
47
 
48
+ #: includes/class-ald-settings.php:110
49
  msgid "<div class=\"warning\">WARNING. Cannot determine your language preference based on your current IP.<br>This is most likely because the website is on a local environment.</div>"
50
  msgstr ""
51
 
52
+ #: partials/license-settings-page.php:4, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:4, ../tp-add-on-extra-languages/partials/license-settings-page.php:4, ../tp-add-on-navigation-based-on-language/partials/license-settings-page.php:4, ../tp-add-on-seo-pack/partials/license-settings-page.php:4, ../translatepress/partials/addons-settings-page.php:3, ../translatepress/partials/main-settings-page.php:5, ../translatepress/partials/test-google-key-settings-page.php:10, ../translatepress/partials/trp-remove-duplicate-rows.php:3, ../translatepress/partials/trp-update-database.php:3, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:4
53
  msgid "TranslatePress Settings"
54
  msgstr ""
55
 
56
+ #: partials/license-settings-page.php:10, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:10, ../tp-add-on-extra-languages/partials/license-settings-page.php:10, ../tp-add-on-navigation-based-on-language/partials/license-settings-page.php:10, ../tp-add-on-seo-pack/partials/license-settings-page.php:10, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:10
57
  msgid "License Key"
58
  msgstr ""
59
 
60
+ #: partials/license-settings-page.php:15, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:15, ../tp-add-on-extra-languages/partials/license-settings-page.php:15, ../tp-add-on-navigation-based-on-language/partials/license-settings-page.php:15, ../tp-add-on-seo-pack/partials/license-settings-page.php:15, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:15
61
  msgid "Enter your license key."
62
  msgstr ""
63
 
64
+ #: partials/license-settings-page.php:22, partials/license-settings-page.php:31, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:22, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:31, ../tp-add-on-extra-languages/partials/license-settings-page.php:22, ../tp-add-on-extra-languages/partials/license-settings-page.php:31, ../tp-add-on-navigation-based-on-language/partials/license-settings-page.php:22, ../tp-add-on-navigation-based-on-language/partials/license-settings-page.php:31, ../tp-add-on-seo-pack/partials/license-settings-page.php:22, ../tp-add-on-seo-pack/partials/license-settings-page.php:31, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:22, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:31
65
  msgid "Activate License"
66
  msgstr ""
67
 
68
+ #: partials/license-settings-page.php:28, ../tp-add-on-browse-as-other-roles/partials/license-settings-page.php:28, ../tp-add-on-extra-languages/partials/license-settings-page.php:28, ../tp-add-on-navigation-based-on-language/partials/license-settings-page.php:28, ../tp-add-on-seo-pack/partials/license-settings-page.php:28, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:28
69
  msgid "Deactivate License"
70
  msgstr ""
71
 
72
+ #: partials/settings-option.php:2
73
  msgid "Method of language detection"
74
  msgstr ""
75
 
76
+ #: partials/settings-option.php:14
77
  msgid "Select how the language should be detected for first time visitors.<br>The visitor's last displayed language will be remembered through cookies."
78
  msgstr ""
79
 
 
 
 
 
80
  #: ../tp-add-on-extra-languages/partials/language-selector-pro.php:7, ../translatepress/partials/main-settings-language-selector.php:7
81
  msgid "Language"
82
  msgstr ""
145
  msgid "Only Flags"
146
  msgstr ""
147
 
148
+ #: ../translatepress/includes/class-settings.php:343
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  msgid "Current Language"
150
  msgstr ""
151
 
152
+ #: ../translatepress/includes/class-settings.php:384
153
  msgid "General"
154
  msgstr ""
155
 
156
+ #: ../translatepress/includes/class-settings.php:389, ../translatepress/includes/class-translation-manager.php:617
157
  msgid "Translate Site"
158
  msgstr ""
159
 
160
+ #: ../translatepress/includes/class-settings.php:397
161
  msgid "License"
162
  msgstr ""
163
 
164
+ #: ../translatepress/includes/class-settings.php:403
165
  msgid "Addons"
166
  msgstr ""
167
 
168
+ #: ../translatepress/includes/class-settings.php:428, ../translatepress/includes/class-translation-manager.php:648
169
  msgid "Settings"
170
  msgstr ""
171
 
172
+ #: ../translatepress/includes/class-settings.php:432
173
  msgid "Pro Features"
174
  msgstr ""
175
 
209
  msgid "Translate Page"
210
  msgstr ""
211
 
212
+ #: ../translatepress/includes/class-translation-manager.php:1198
213
  msgid "Security check"
214
  msgstr ""
215
 
216
+ #: ../translatepress/includes/class-translation-manager.php:1272
217
+ msgid "<strong>Warning:</strong> Some strings have possibly incorrectly encoded characters. This may result in breaking the queries, rendering the page untranslated in live mode. Consider revising the following strings or their method of outputting."
218
+ msgstr ""
219
+
220
+ #: ../translatepress/includes/class-translation-render.php:143
221
  msgid "Description"
222
  msgstr ""
223
 
224
+ #: ../translatepress/includes/class-translation-render.php:149
225
  msgid "OG Title"
226
  msgstr ""
227
 
228
+ #: ../translatepress/includes/class-translation-render.php:155
229
  msgid "OG Site Name"
230
  msgstr ""
231
 
232
+ #: ../translatepress/includes/class-translation-render.php:161
233
  msgid "OG Description"
234
  msgstr ""
235
 
236
+ #: ../translatepress/includes/class-translation-render.php:167
237
  msgid "Twitter Title"
238
  msgstr ""
239
 
240
+ #: ../translatepress/includes/class-translation-render.php:173
241
  msgid "Twitter Description"
242
  msgstr ""
243
 
244
+ #: ../translatepress/includes/class-translation-render.php:179
245
  msgid "Post Slug"
246
  msgstr ""
247
 
248
+ #: ../translatepress/includes/class-translation-render.php:183
249
  msgid "Page Title"
250
  msgstr ""
251
 
252
+ #: ../translatepress/includes/class-upgrade.php:95
253
+ msgid "TranslatePress data update"
254
+ msgstr ""
255
+
256
+ #: ../translatepress/includes/class-upgrade.php:95
257
+ msgid "We need to update your translations database to the latest version."
258
+ msgstr ""
259
+
260
+ #: ../translatepress/includes/class-upgrade.php:96
261
+ msgid "Run the updater"
262
+ msgstr ""
263
+
264
+ #: ../translatepress/includes/class-upgrade.php:125
265
+ msgid "<p><strong>Successfully updated database!</strong></p>"
266
+ msgstr ""
267
+
268
+ #: ../translatepress/includes/class-upgrade.php:125, ../translatepress/includes/class-upgrade.php:130, ../translatepress/includes/class-upgrade.php:290, ../translatepress/includes/class-upgrade.php:295
269
+ msgid "Back to TranslatePress Settings page"
270
+ msgstr ""
271
+
272
+ #: ../translatepress/includes/class-upgrade.php:130, ../translatepress/includes/class-upgrade.php:295
273
+ msgid "Invalid nonce."
274
+ msgstr ""
275
+
276
+ #: ../translatepress/includes/class-upgrade.php:206, ../translatepress/includes/class-upgrade.php:375
277
+ msgid "If the page does not redirect automatically"
278
+ msgstr ""
279
+
280
+ #: ../translatepress/includes/class-upgrade.php:206, ../translatepress/includes/class-upgrade.php:375
281
+ msgid "click here"
282
+ msgstr ""
283
+
284
+ #: ../translatepress/includes/class-upgrade.php:228
285
+ msgid "Querying table <strong>%s</strong>... "
286
+ msgstr ""
287
+
288
+ #: ../translatepress/includes/class-upgrade.php:230, ../translatepress/includes/class-upgrade.php:290
289
+ msgid "Done."
290
+ msgstr ""
291
+
292
+ #: ../translatepress/includes/class-upgrade.php:315
293
+ msgid "Querying table <strong>%s</strong>"
294
+ msgstr ""
295
+
296
+ #: ../translatepress/includes/class-upgrade.php:345
297
+ msgid "%s duplicates removed"
298
+ msgstr ""
299
+
300
+ #: ../translatepress/includes/functions.php:253
301
  msgid "<strong>TranslatePress</strong> requires <strong><a href=\"http://php.net/manual/en/book.mbstring.php\">Multibyte String PHP library</a></strong>. Please contact your server administrator to install it on your server."
302
  msgstr ""
303
 
577
  msgid "<strong>IMPORTANT NOTE: Before performing this action it is strongly recommended to backup the database first.</strong><br><br>This feature can be used to cleanup duplicate entries in TranslatePress trp_dictionary tables. Such duplicates can appear in exceptional situations of unexpected behavior."
578
  msgstr ""
579
 
580
+ #: ../translatepress/partials/trp-remove-duplicate-rows.php:12, ../translatepress/partials/trp-update-database.php:12
581
  msgid ""
582
  "IMPORTANT: It is strongly recommended to backup the database first!\n"
583
  "Are you sure you want to continue?"
595
  msgid "Remove duplicate rows"
596
  msgstr ""
597
 
598
+ #: ../translatepress/partials/trp-update-database.php:7
599
+ msgid "Update TranslatePress tables"
600
+ msgstr ""
601
+
602
+ #: ../translatepress/partials/trp-update-database.php:10
603
+ msgid "<p><strong>IMPORTANT NOTE: Before performing this action it is strongly recommended to backup the database first.</strong></p>"
604
+ msgstr ""
605
+
606
+ #: ../translatepress/partials/trp-update-database.php:18
607
+ msgid "Update database"
608
+ msgstr ""
609
+
610
  #: ../trp-add-on-translator-accounts-add-on/includes/class-translator-accounts.php:119
611
  msgid " TranslatePress Settings"
612
  msgstr ""
partials/trp-update-database.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="trp-addons-page" class="wrap">
2
+
3
+ <h1> <?php _e( 'TranslatePress Settings', 'translatepress-multilingual' );?></h1>
4
+
5
+ <div class="grid feat-header">
6
+ <div class="grid-cell">
7
+ <h2><?php _e('Update TranslatePress tables', 'translatepress-multilingual' );?> </h2>
8
+ <?php if ( empty( $_GET['trp_updb_lang'] ) ){ ?>
9
+ <div>
10
+ <?php _e( '<p><strong>IMPORTANT NOTE: Before performing this action it is strongly recommended to backup the database first.</strong></p>', 'translatepress-multilingual' )?>
11
+ </div>
12
+ <form onsubmit="return confirm('<?php _e( 'IMPORTANT: It is strongly recommended to backup the database first!\nAre you sure you want to continue?', 'translatepress-multilingual' ) ?>');">
13
+ <input type="hidden" name="trp_updb_nonce" value="<?php echo wp_create_nonce('tpupdatedatabase')?>">
14
+ <input type="hidden" name="page" value="trp_update_database">
15
+ <input type="hidden" name="trp_updb_batch" value="0">
16
+ <input type="hidden" name="trp_updb_batch_size" value="200">
17
+ <input type="hidden" name="trp_updb_lang" value="<?php echo $this->settings['translation-languages'][0]?>">
18
+ <input type="submit" class="button-primary" value="<?php _e( 'Update database', 'translatepress-multilingual' ); ?>">
19
+ </form>
20
+ <?php } ?>
21
+
22
+ </div>
23
+ </div>
24
+
25
+ </div>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: cozmoslabs, razvan.mo, madalin.ungureanu, cristophor
3
  Donate link: https://www.cozmoslabs.com/
4
  Tags: translate, translation, multilingual, automatic translation, bilingual, front-end translation, google translate, language
5
  Requires at least: 3.1.0
6
- Tested up to: 5.0.1
7
- Stable tag: 1.3.9
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -124,6 +124,16 @@ For more information please check out [TranslatePress - Multilingual plugin docu
124
  6. Menu Language Switcher
125
 
126
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
127
  = 1.3.9 =
128
  * Fixed some issues with url translations
129
  * Speed improvements
3
  Donate link: https://www.cozmoslabs.com/
4
  Tags: translate, translation, multilingual, automatic translation, bilingual, front-end translation, google translate, language
5
  Requires at least: 3.1.0
6
+ Tested up to: 5.0.3
7
+ Stable tag: 1.4.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
124
  6. Menu Language Switcher
125
 
126
  == Changelog ==
127
+ = 1.4.0 =
128
+ * Added Enfold compatibility by increasing the template_include hook priority
129
+ * Add the costa rica flag
130
+ * Speed improvements by optimizing the full_trim function
131
+ * Added compatibility for WooCommerce Invoices plugins
132
+ * Fixed querying for dynamic strings in Translation Editor not bringing up translations for all languages
133
+ * Fixed notice when gettext table is empty
134
+ * Added function to display strings with bad encoding in Translation Editor
135
+
136
+
137
  = 1.3.9 =
138
  * Fixed some issues with url translations
139
  * Speed improvements