TranslatePress – Translate Multilingual sites - Version 1.2.2

Version Description

  • Added Translation Block feature in which you can translate multiple html elements together
  • Improvement: make it possible for the SEO Addon to automatically translate page slugs using Google Translate
  • Fix: using the shortcode language switcher added #trpprocessurl to the end of the url
  • Fix: changing languages from a secondary language gave 404 page when the page slug was translated
  • Fix: submitting a form from one page to another directed the user to the default language. Now if Force Custom Language Links is enabled the user gets directed to the correct url
Download this release

Release Info

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

Code changes from version 1.2.1 to 1.2.2

assets/css/trp-preview-iframe-style.css CHANGED
@@ -2,7 +2,7 @@
2
  String editor button
3
  */
4
 
5
- span.trp-edit-translation {
6
  width: 30px !important;
7
  height: 30px !important;
8
  display: inline-block;
@@ -27,14 +27,13 @@ span.trp-edit-translation {
27
  -moz-box-sizing: border-box;
28
  box-sizing: border-box;
29
  padding: 3px;
30
- text-shadow: 0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799;
31
  }
32
 
33
- span.trp-edit-translation:hover {
34
  background: #008ec2!important;
35
  }
36
 
37
- span.trp-edit-translation svg {
38
  fill: #fff;
39
  min-width: 20px;
40
  min-height: 20px;
@@ -51,19 +50,19 @@ span.trp-edit-translation svg {
51
  outline: 2px solid #e2e4e7;
52
  }
53
 
54
- *[data-trpgettextoriginal] span.trp-edit-translation, .trpgettext-wrap span.trp-edit-translation{
55
  background: #00ba3f !important;
56
  }
57
 
58
- *[data-trpgettextoriginal] *[data-trp-translate-id] span.trp-edit-translation{
59
  background: #0085ba!important;
60
  }
61
 
62
- *[data-trpgettextoriginal] span.trp-edit-translation:hover, .trpgettext-wrap span.trp-edit-translation:hover{
63
  background: #00ce44 !important;
64
  }
65
 
66
- *[data-trpgettextoriginal] *[data-trp-translate-id] span.trp-edit-translation:hover{
67
  background: #008ec2!important;
68
  }
69
 
@@ -77,10 +76,49 @@ translate-press{
77
  -webkit-transform: translate3d(0,0,0);
78
  }
79
 
80
- .trp-overflow-transform-fixer span.trp-edit-translation{
81
  position:fixed;
82
  }
83
 
84
- .trp-overflow-inside-fixer span.trp-edit-translation{
85
  margin-left:0 !important;
86
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  String editor button
3
  */
4
 
5
+ .trp-icon {
6
  width: 30px !important;
7
  height: 30px !important;
8
  display: inline-block;
27
  -moz-box-sizing: border-box;
28
  box-sizing: border-box;
29
  padding: 3px;
 
30
  }
31
 
32
+ .trp-icon:hover {
33
  background: #008ec2!important;
34
  }
35
 
36
+ .trp-icon svg {
37
  fill: #fff;
38
  min-width: 20px;
39
  min-height: 20px;
50
  outline: 2px solid #e2e4e7;
51
  }
52
 
53
+ *[data-trpgettextoriginal] .trp-icon, .trpgettext-wrap .trp-icon{
54
  background: #00ba3f !important;
55
  }
56
 
57
+ *[data-trpgettextoriginal] *[data-trp-translate-id] .trp-icon{
58
  background: #0085ba!important;
59
  }
60
 
61
+ *[data-trpgettextoriginal] .trp-icon:hover, .trpgettext-wrap .trp-icon:hover{
62
  background: #00ce44 !important;
63
  }
64
 
65
+ *[data-trpgettextoriginal] *[data-trp-translate-id] .trp-icon:hover{
66
  background: #008ec2!important;
67
  }
68
 
76
  -webkit-transform: translate3d(0,0,0);
77
  }
78
 
79
+ .trp-overflow-transform-fixer trp-edit.trp-edit-translation{
80
  position:fixed;
81
  }
82
 
83
+ .trp-overflow-inside-fixer trp-edit.trp-edit-translation{
84
  margin-left:0 !important;
85
+ }
86
+
87
+
88
+ /*
89
+ * Merge icon
90
+ */
91
+
92
+ .trp-icon.trp-merge{
93
+ display: none;
94
+ margin-left: -60px !important;
95
+ background: #3CB371!important;
96
+ }
97
+
98
+ .trp-icon.trp-merge:hover {
99
+ display: none;
100
+ background: #40bf79!important;
101
+ }
102
+
103
+ .trp-icon.trp-merge.trp-active-icon, .trp-icon.trp-merge.trp-active-icon:hover{
104
+ display: inline;
105
+ }
106
+
107
+ /*
108
+ * Split icon
109
+ */
110
+
111
+ .trp-icon.trp-split{
112
+ display: none;
113
+ margin-left: -60px !important;
114
+ background: #ffa500!important;
115
+ }
116
+
117
+ .trp-icon.trp-split:hover {
118
+ display: none;
119
+ background: #ffae19!important;
120
+ }
121
+
122
+ .trp-icon.trp-split.trp-active-icon, .trp-icon.trp-split.trp-active-icon:hover{
123
+ display: inline;
124
+ }
assets/js/trp-editor-script.js CHANGED
@@ -2,12 +2,14 @@
2
  * Handle Editor interface
3
  */
4
  function TRP_Editor(){
 
5
  var _this = this;
6
  this.preview_iframe = null;
7
  var strings;
8
  var dictionaries;
9
  var default_language;
10
  var TRP_TRANSLATION_ID = 'data-trp-translate-id';
 
11
  this.original_textarea = jQuery( '#trp-original' );
12
  var loading_animation = jQuery( '#trp-string-saved-ajax-loader' );
13
  var translation_saved = jQuery( '#trp-translation-saved' );
@@ -163,6 +165,7 @@ function TRP_Editor(){
163
  dataType: 'json',
164
  data: {
165
  action: 'trp_get_translations',
 
166
  language: trp_on_screen_language,
167
  strings: JSON.stringify( strings_to_query ),
168
  all_languages: 'true'
@@ -215,10 +218,11 @@ function TRP_Editor(){
215
  * @param index
216
  */
217
  this.edit_strings = function ( trp_string, index ){
218
- if ( _this.change_tracker.check_unsaved_changes() ) {
219
  return;
220
  }
221
- _this.original_textarea.val( trp_string.original );
 
222
  for ( var key in translated_textareas ){
223
  var translated = '';
224
  var id = '';
@@ -248,12 +252,22 @@ function TRP_Editor(){
248
  var strings_to_save = {};
249
  var modified = false;
250
  var original = _this.original_textarea.val();
 
251
  var action = 'trp_save_translations';
252
  if ( original != "" ) {
253
  for ( var key in translated_textareas ) {
254
  var translated = translated_textareas[key].val();
255
- var string = dictionaries[key].get_string_by_original(original);
256
- if ( string.slug == true ){
 
 
 
 
 
 
 
 
 
257
  action = 'trp_save_slug_translation';
258
  }
259
  if ( string.translated != translated ) {
@@ -261,12 +275,11 @@ function TRP_Editor(){
261
  if (strings_to_save[key] == undefined) {
262
  strings_to_save[key] = [];
263
  }
264
- var id = translated_textareas[key].attr( TRP_TRANSLATION_ID );
265
  var status = 2;
266
  if (translated.trim() == '') {
267
  status = 0;
268
  }
269
- strings_to_save[key].push({id: id, original: original, translated: translated, status: status});
270
  }
271
  }
272
  }
@@ -288,11 +301,12 @@ function TRP_Editor(){
288
  return dictionaries;
289
  };
290
 
 
291
  /**
292
  * Ajax request with translation to be stored.
293
  *
294
  * @param strings_to_save Strings to save in database.
295
- * @param action 'trp_save_translations' | 'trp_save_slug_translation'.
296
  */
297
  this.ajax_save_strings = function ( strings_to_save, action ){
298
  jQuery.ajax({
@@ -301,12 +315,18 @@ function TRP_Editor(){
301
  dataType: 'json',
302
  data: {
303
  action: action,
304
- strings: JSON.stringify( strings_to_save )
 
 
 
305
  },
306
  success: function (response) {
307
- _this.populate_strings( strings_to_save );
 
 
 
 
308
  _this.saved_translation_ui();
309
-
310
  },
311
  error: function(errorThrown){
312
  loading_animation.toggle();
@@ -315,6 +335,202 @@ function TRP_Editor(){
315
  });
316
  };
317
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  /**
319
  * Show UI for translation being saved.
320
  */
@@ -446,7 +662,7 @@ function TRP_Editor(){
446
  jQuery( '.trp-toggle-languages span' ).on( 'click', _this.toggle_languages );
447
  jQuery( '#trp-previous' ).on( 'click', function(e){
448
  e.preventDefault();
449
- if ( _this.change_tracker.check_unsaved_changes() ) {
450
  return;
451
  }
452
  prev_option_value = jQuery( 'option:selected', _this.jquery_string_selector ).prevAll('option').first().attr('value');
@@ -456,7 +672,7 @@ function TRP_Editor(){
456
  });
457
  jQuery( '#trp-next' ).on( 'click', function(e){
458
  e.preventDefault();
459
- if ( _this.change_tracker.check_unsaved_changes() ) {
460
  return;
461
  }
462
  next_option_value = jQuery('option:selected', _this.jquery_string_selector).nextAll('option').first().attr('value');
@@ -488,7 +704,7 @@ function TRP_Editor(){
488
 
489
  /* when we have unsaved changes prevent the strings dropdown from opening so we do not have a disconnect between the textareas and the dropdown */
490
  _this.jquery_string_selector.on('select2:opening', function (e) {
491
- if ( trpEditor.change_tracker.check_unsaved_changes() ) {
492
  e.preventDefault();
493
  }
494
  });
@@ -498,7 +714,7 @@ function TRP_Editor(){
498
  * Remove pencil icon from preview window.
499
  */
500
  this.remove_pencil_icon = function(){
501
- jQuery( '#trp-preview-iframe').contents().find( '.trp-edit-translation' ).remove();
502
  };
503
 
504
  /**
@@ -586,6 +802,7 @@ function TRP_Dictionary( language_code ){
586
  ( _this.strings[s].jquery_object != null && strings_object[i].jquery_object == null ) ||
587
  ( strings_object[i].jquery_object ==_this.strings[s].jquery_object )
588
  )
 
589
  ) {
590
  strings_object[i].set = true;
591
  _this.strings[s].set_string( strings_object[i] );
@@ -604,6 +821,20 @@ function TRP_Dictionary( language_code ){
604
 
605
  };
606
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  /**
608
  * Concatenate given strings with the existing list.
609
  *
@@ -613,6 +844,20 @@ function TRP_Dictionary( language_code ){
613
  _this.strings = _this.strings.concat( new_strings );
614
  };
615
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
  /**
617
  * Return a TRP_String entry for the given original.
618
  *
@@ -689,7 +934,7 @@ function TRP_String( language, array_index ){
689
  this.original = null;
690
  this.translated = null;
691
  this.status = null;
692
- this.node_type = 'Dynamic Added Strings';
693
  this.node_description = '';
694
  this.jquery_object = null;
695
  this.language = language;
@@ -716,18 +961,26 @@ function TRP_String( language, array_index ){
716
  };
717
 
718
  /**
719
- * Return given text converted to html.
720
- *
721
- * Useful for decoding special characters into displayable form.
722
  *
723
- * @param html
724
- * @returns {*}
725
  */
726
- function decode_html( html ) {
727
- var txt = document.createElement( "textarea" );
728
- txt.innerHTML = html;
729
- return txt.value;
730
- }
 
 
 
 
 
 
 
 
 
 
731
 
732
  /**
733
  * Update string information. Also updates in page if available.
@@ -737,10 +990,30 @@ function TRP_String( language, array_index ){
737
  this.set_string = function ( new_settings ){
738
  _this.id = ( new_settings.hasOwnProperty ( 'id' ) ) ? new_settings.id : _this.id;
739
  _this.original = ( new_settings.hasOwnProperty ( 'original' ) ) ? new_settings.original : _this.original;
740
- _this.original = decode_html( _this.original );
741
  _this.jquery_object = ( new_settings.hasOwnProperty ( 'jquery_object' ) ) ? new_settings.jquery_object : _this.jquery_object;
 
 
 
 
 
 
 
 
 
 
 
 
 
742
 
743
- if ( _this.jquery_object ){
 
 
 
 
 
 
 
 
744
  if ( trp_language == trp_on_screen_language ) {
745
  var text_to_set = null;
746
  if (new_settings.hasOwnProperty('translated') && new_settings.translated != _this.translated) {
@@ -750,19 +1023,7 @@ function TRP_String( language, array_index ){
750
  text_to_set = _this.original;
751
  }
752
  _this.wrap_special_html_elements();
753
- if (text_to_set) {
754
- var initial_value = _this.jquery_object.text();
755
- text_to_set = initial_value.replace(initial_value.trim(), text_to_set);
756
- if ( _this.jquery_object.attr( 'data-trp-attr' ) ){
757
- _this.jquery_object.children().attr( _this.jquery_object.attr('data-trp-attr'), text_to_set );
758
- }else if( _this.jquery_object.attr( 'data-trp-button' ) ){
759
- _this.jquery_object.children('button').text(text_to_set);
760
- }else {
761
- if (_this.jquery_object.text().trim() !== text_to_set.trim() ){
762
- _this.jquery_object.html( text_to_set );
763
- }
764
- }
765
- }
766
  }
767
 
768
  _this.jquery_object.on( 'mouseenter', '', _this.highlight );
@@ -794,26 +1055,42 @@ function TRP_String( language, array_index ){
794
  }
795
  };
796
 
 
797
  /**
798
  * Show the pencil and border the viewable string in Preview window.
799
  */
800
  this.highlight = function (e){
801
  e.stopPropagation();
 
 
 
 
 
 
 
 
 
 
802
  if ( ! trpEditor.edit_translation_button ){
803
- _this.jquery_object.prepend( '<span class="trp-edit-translation"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6z"></path></svg></span>' );
804
- trpEditor.edit_translation_button = _this.jquery_object.children('.trp-edit-translation');
805
  }else{
806
  _this.wrap_special_html_elements();
807
  trpEditor.maybe_overflow_fix(trpEditor.edit_translation_button);
808
- _this.jquery_object.prepend(trpEditor.edit_translation_button);
 
 
 
 
 
809
  }
810
 
811
- trpEditor.make_sure_pencil_icon_is_inside_view( _this.jquery_object[0] );
812
 
813
  trpEditor.edit_translation_button.off( 'click' );
814
  trpEditor.edit_translation_button.on( 'click', function(e){
815
  e.preventDefault();
816
- if ( trpEditor.change_tracker.check_unsaved_changes() ) {
817
  return;
818
  }
819
 
@@ -828,9 +1105,22 @@ function TRP_String( language, array_index ){
828
  }else{
829
  trpEditor.jquery_string_selector.trigger('trpSelectorNotChanged');
830
  }
 
 
 
 
 
 
 
 
 
 
 
831
  });
 
 
 
832
 
833
- jQuery( this ).addClass( 'trp-highlight' );
834
  };
835
 
836
  /**
@@ -865,7 +1155,7 @@ function TRP_String( language, array_index ){
865
  if ( _this.jquery_object.attr( 'name' ) == 'trp-slug' ){
866
  _this.slug = true;
867
  _this.slug_post_id = _this.jquery_object.attr( 'post-id' );
868
- _this.original = _this.jquery_object.attr( 'content' );
869
  }
870
  }else{
871
  _this.original = _this.jquery_object.text();
@@ -930,9 +1220,15 @@ function TRP_Lister( current_dictionary ) {
930
  jQuery( "#trp-gettext-strings-optgroup", jquery_string_selector ).prevAll(":not(.default-option)").remove();
931
  /* add the normal strings before the trp-gettext-strings-optgroup optiongroup so it doesn't matter which ajax finishes first */
932
  for ( var category in category_array ){
 
 
 
933
  jQuery( "#trp-gettext-strings-optgroup", jquery_string_selector ).before( jQuery( '<optgroup></optgroup>' ).attr( 'label', _this.format_category_name( category ) ) );
934
  for ( var i in category_array[category] ) {
935
- var original = category_array[category][i].original;
 
 
 
936
  var description = '';
937
  if ( category_array[category][i].node_description != undefined && category_array[category][i].node_description != '' ){
938
  description = '(' + category_array[category][i].node_description + ')';
@@ -961,6 +1257,17 @@ function TRP_Lister( current_dictionary ) {
961
  _this.set_cached_option();
962
  };
963
 
 
 
 
 
 
 
 
 
 
 
 
964
  /**
965
  * Cut the length of text displayed in string dropdown list.
966
  */
@@ -970,7 +1277,7 @@ function TRP_Lister( current_dictionary ) {
970
  suspension_dots = '';
971
  }
972
 
973
- return original.substring(0, 90) + suspension_dots ;
974
  };
975
 
976
  /**
@@ -986,7 +1293,7 @@ function TRP_Lister( current_dictionary ) {
986
  this.set_textareas_with_gettext = function( string_id ){
987
 
988
  /* don't do anything if there is an unsaved change */
989
- if ( trpEditor.change_tracker.check_unsaved_changes() ) {
990
  return;
991
  }
992
 
@@ -1027,7 +1334,7 @@ function TRP_Lister( current_dictionary ) {
1027
  };
1028
 
1029
  this.set_texts_select_to_gettext = function( jquery_object ){
1030
- if ( trpEditor.change_tracker.check_unsaved_changes() ) {
1031
  return;
1032
  }
1033
  string_id = jquery_object.attr('data-trpgettextoriginal');
@@ -1222,6 +1529,7 @@ jQuery(function(){
1222
  dataType: 'json',
1223
  data: {
1224
  action: 'trp_gettext_get_translations',
 
1225
  language: trp_language,
1226
  gettext_string_ids: JSON.stringify( gettext_string_ids )
1227
  },
@@ -1247,9 +1555,9 @@ jQuery(function(){
1247
  gettext_string = this;
1248
 
1249
  if ( ! trpEditor.edit_translation_button ){
1250
- trpEditor.edit_translation_button = jQuery( '<span class="trp-edit-translation"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M13.89 3.39l2.71 2.72c.46.46.42 1.24.03 1.64l-8.01 8.02-5.56 1.16 1.16-5.58s7.6-7.63 7.99-8.03c.39-.39 1.22-.39 1.68.07zm-2.73 2.79l-5.59 5.61 1.11 1.11 5.54-5.65zm-2.97 8.23l5.58-5.6-1.07-1.08-5.59 5.6z"></path></svg></span>' );
1251
  }
1252
-
1253
  trpEditor.maybe_overflow_fix(trpEditor.edit_translation_button);
1254
 
1255
  if ( jQuery(this).attr( 'type' ) == 'submit' || jQuery(this).attr( 'type' ) == 'button' || jQuery(this).attr('type') == 'search' ) {
@@ -1263,6 +1571,8 @@ jQuery(function(){
1263
  trpEditor.make_sure_pencil_icon_is_inside_view ( jQuery(this)[0] );
1264
  trpEditor.edit_translation_button.off( 'click' );
1265
  trpEditor.edit_translation_button.on( 'click', function(e){
 
 
1266
  e.preventDefault();
1267
  e.stopPropagation();
1268
  trp_lister.set_texts_select_to_gettext( jQuery(gettext_string) );
@@ -1324,6 +1634,7 @@ jQuery(function(){
1324
  dataType: 'json',
1325
  data: {
1326
  action: 'trp_gettext_save_translations',
 
1327
  gettext_strings: JSON.stringify( strings_to_save )
1328
  },
1329
  success: function (response) {
@@ -1364,3 +1675,16 @@ jQuery( function(){
1364
  });
1365
 
1366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  * Handle Editor interface
3
  */
4
  function TRP_Editor(){
5
+ trp_action_button_html = '<trp-span><trp-merge title="' + trp_localized_text['merge'] + '" class="trp-icon trp-merge dashicons dashicons-arrow-up-alt"></trp-merge><trp-split title="' + trp_localized_text['split'] + '" class="trp-icon trp-split dashicons dashicons-arrow-down-alt"></trp-split><trp-edit title="' + trp_localized_text['edit'] + '" class="trp-icon trp-edit-translation dashicons dashicons-edit"></trp-edit></trp-span>';
6
  var _this = this;
7
  this.preview_iframe = null;
8
  var strings;
9
  var dictionaries;
10
  var default_language;
11
  var TRP_TRANSLATION_ID = 'data-trp-translate-id';
12
+ var TRP_BLOCK_TYPE = 'data-trp-block-type';
13
  this.original_textarea = jQuery( '#trp-original' );
14
  var loading_animation = jQuery( '#trp-string-saved-ajax-loader' );
15
  var translation_saved = jQuery( '#trp-translation-saved' );
165
  dataType: 'json',
166
  data: {
167
  action: 'trp_get_translations',
168
+ security: trp_localized_text['gettranslationsnonce'],
169
  language: trp_on_screen_language,
170
  strings: JSON.stringify( strings_to_query ),
171
  all_languages: 'true'
218
  * @param index
219
  */
220
  this.edit_strings = function ( trp_string, index ){
221
+ if ( _this.change_tracker == null || _this.change_tracker.check_unsaved_changes() ) {
222
  return;
223
  }
224
+ _this.original_textarea.val( decode_html( trp_string.original ) );
225
+ _this.original_textarea.attr( TRP_BLOCK_TYPE, trp_string.block_type );
226
  for ( var key in translated_textareas ){
227
  var translated = '';
228
  var id = '';
252
  var strings_to_save = {};
253
  var modified = false;
254
  var original = _this.original_textarea.val();
255
+ var block_type = _this.original_textarea.attr( TRP_BLOCK_TYPE );
256
  var action = 'trp_save_translations';
257
  if ( original != "" ) {
258
  for ( var key in translated_textareas ) {
259
  var translated = translated_textareas[key].val();
260
+ var id = translated_textareas[key].attr( TRP_TRANSLATION_ID );
261
+ var string = {};
262
+ if ( id == 'trp_creating_translation_block' ){
263
+ string.translated = 'trp_creating_translation_block';
264
+ string.slug = false;
265
+ block_type = 1;
266
+ action = 'trp_create_translation_block';
267
+ }else {
268
+ string = dictionaries[key].get_string_by_original(original);
269
+ }
270
+ if (string.slug == true) {
271
  action = 'trp_save_slug_translation';
272
  }
273
  if ( string.translated != translated ) {
275
  if (strings_to_save[key] == undefined) {
276
  strings_to_save[key] = [];
277
  }
 
278
  var status = 2;
279
  if (translated.trim() == '') {
280
  status = 0;
281
  }
282
+ strings_to_save[key].push({id: id, original: original, translated: translated, status: status, block_type: block_type});
283
  }
284
  }
285
  }
301
  return dictionaries;
302
  };
303
 
304
+
305
  /**
306
  * Ajax request with translation to be stored.
307
  *
308
  * @param strings_to_save Strings to save in database.
309
+ * @param action 'trp_save_translations' | 'trp_save_slug_translation' | 'trp_get_translations'
310
  */
311
  this.ajax_save_strings = function ( strings_to_save, action ){
312
  jQuery.ajax({
315
  dataType: 'json',
316
  data: {
317
  action: action,
318
+ security: trp_localized_text['savestringsnonce'],
319
+ language: trp_on_screen_language,
320
+ strings: JSON.stringify( strings_to_save ),
321
+ all_languages: 'true'
322
  },
323
  success: function (response) {
324
+ if ( action == 'trp_create_translation_block' ){
325
+ _this.populate_translation_block_strings( response );
326
+ }else {
327
+ _this.populate_strings(strings_to_save);
328
+ }
329
  _this.saved_translation_ui();
 
330
  },
331
  error: function(errorThrown){
332
  loading_animation.toggle();
335
  });
336
  };
337
 
338
+ /**
339
+ * Call populate strings on response
340
+ *
341
+ * Remove individual strings composing the translation blocks
342
+ * Reload list
343
+ * Removes the highlight of the translation block
344
+ *
345
+ * @param response
346
+ */
347
+ this.populate_translation_block_strings = function( response ){
348
+ // remove individual strings composing the translation blocks
349
+ trpEditor.preview_iframe.contents().find('.trp-create-translation-block [data-trp-translate-id]').each( function(){
350
+ dictionaries[trp_on_screen_language].remove_strings_with_id_from_translation_block( jQuery( this ).attr( TRP_TRANSLATION_ID ) );
351
+ });
352
+ _this.populate_strings( response );
353
+ _this.trp_lister.reload_list();
354
+
355
+ // remove highlighting of possibly highlighted new translation block
356
+ trpEditor.preview_iframe.contents().find('.trp-create-translation-block').removeClass('trp-highlight trp-create-translation-block');
357
+ };
358
+
359
+ /*
360
+ * Construct a string version for the top_parents_array
361
+ */
362
+ this.get_parent_block = function ( jquery_object ){
363
+ if ( typeof trp_merge_rules.top_parents_selector == 'undefined' ) {
364
+ var t = 0;
365
+ var top_parents_string = trp_merge_rules.top_parents[t];
366
+ while (t + 1 < trp_merge_rules.top_parents.length) {
367
+ t = t + 1;
368
+ top_parents_string = top_parents_string + ', ' + trp_merge_rules.top_parents[t];
369
+ }
370
+ trp_merge_rules.top_parents_selector = top_parents_string;
371
+ }
372
+
373
+ return jquery_object.closest( trp_merge_rules.top_parents_selector );
374
+ };
375
+
376
+ /**
377
+ * Return 'merge', 'split' or 'none' for the jquery_object received based on rules.
378
+ */
379
+ this.decide_if_merge_or_split = function ( trp_string_to_merge ){
380
+
381
+ if ( typeof trp_merge_rules == 'undefined' ) {
382
+ return 'none';
383
+ }
384
+
385
+ // if string is an active translation block
386
+ if ( trp_string_to_merge.block_type == 1 ){
387
+ return 'split';
388
+ }
389
+
390
+ var jquery_object = trp_string_to_merge.jquery_object;
391
+ // check if object is of correct type
392
+ for ( var s in trp_merge_rules.self_object_type ) {
393
+ if ( jquery_object.is( trp_merge_rules.self_object_type[s] ) ) {
394
+ if ( typeof trp_merge_rules.top_parents != 'undefined' && trp_merge_rules.top_parents.length > 0 ) {
395
+ // closest element which is of type like
396
+ var block_parent = _this.get_parent_block(jquery_object);
397
+ if ( block_parent.length > 0 ){
398
+ for ( var sl in trp_merge_rules.self_object_type ) {
399
+ mergeable_children_count = block_parent.find( trp_merge_rules.self_object_type[sl] ).length;
400
+ if ( mergeable_children_count > 1 ) {
401
+ for( var i in trp_merge_rules.incompatible_siblings ){
402
+ var incompatible_children = block_parent.find( trp_merge_rules.incompatible_siblings[i] ).length;
403
+ if ( incompatible_children > 0 ) {
404
+ return 'none';
405
+ }
406
+ }
407
+ return 'merge';
408
+ }
409
+ }
410
+ }
411
+ }
412
+ }
413
+ }
414
+ return 'none';
415
+ };
416
+
417
+ /*
418
+ * Strips all the html added by TP Editor to return a vanilla html.
419
+ *
420
+ * Returns original language even if in TP Editor is in secondary language preview.
421
+ */
422
+ this.strip_editor_meta_data = function ( parent ) {
423
+ var clone = parent.clone();
424
+ if ( trp_language == trp_on_screen_language ){
425
+ // editor is not in original language
426
+ clone.find('['+TRP_TRANSLATION_ID+']').each( function(){
427
+ var trp_string = dictionaries[trp_on_screen_language].get_string_by_id( jQuery( this ).attr( TRP_TRANSLATION_ID ) );
428
+ if ( trp_string.status != 0 ) {
429
+ jQuery( this ).html( jQuery( this ).text().replace( trp_string.translated, trp_string.original ) );
430
+ }
431
+ });
432
+ }
433
+
434
+ clone.find('trp-span').remove();
435
+ clone.find('translate-press, trp-wrap, trp-highlight').contents().unwrap();
436
+
437
+ var replace_attributes = ['href', 'target'];
438
+ var arrayLength = replace_attributes.length;
439
+ for (var i = 0; i < arrayLength; i++) {
440
+ var attribute = replace_attributes[i];
441
+ clone.find('[data-trp-original-' + attribute + ']').each(function () {
442
+ jQuery(this).attr( attribute, jQuery(this).attr('data-trp-original-' + attribute));
443
+ jQuery(this).removeAttr('data-trp-original-' + attribute );
444
+ });
445
+ }
446
+
447
+ var remove_attributes = ['data-trp-translate-id', 'data-trp-node-type', 'data-trp-placeholder', 'data-trp-node-description', 'data-trp-unpreviewable' ];
448
+ arrayLength = remove_attributes.length;
449
+ for (var i = 0; i < arrayLength; i++) {
450
+ var attribute = remove_attributes[i];
451
+ clone.find('[' + attribute + ']').removeAttr( attribute );
452
+ }
453
+
454
+ stripped_html = clone.html();
455
+ return stripped_html.replace('&nbsp;', "\u00a0");
456
+ };
457
+
458
+ /*
459
+ * Brings translation block in sidebar for saving
460
+ *
461
+ * @param trp_string_to_merge TRP_String from which to extract parent block.
462
+ */
463
+ this.prepare_merging = function( trp_string_to_merge ){
464
+ // check again
465
+ if ( _this.decide_if_merge_or_split( trp_string_to_merge ) != 'merge' ) {
466
+ return;
467
+ }
468
+
469
+ var parent = _this.get_parent_block( trp_string_to_merge.jquery_object );
470
+ var maybe_deprecated_id = parent.attr( 'data-trp-translate-id-deprecated' );
471
+ var trp_deprecated_string = null;
472
+ if ( maybe_deprecated_id != '' ){
473
+ trp_deprecated_string = dictionaries[trp_on_screen_language].get_string_by_id( maybe_deprecated_id );
474
+ }
475
+ trpEditor.preview_iframe.find( "[" + TRP_TRANSLATION_ID + "='trp_creating_translation_block']" ).removeAttr( TRP_TRANSLATION_ID );
476
+ parent.attr( TRP_TRANSLATION_ID, 'trp_creating_translation_block' );
477
+ parent.find('.trp-highlight').removeClass( 'trp-highlight' );
478
+ parent.addClass( 'trp-highlight trp-create-translation-block' );
479
+
480
+ _this.original_textarea.val( _this.strip_editor_meta_data( parent ) );
481
+ for ( var key in translated_textareas ){
482
+ if ( trp_deprecated_string == null ) {
483
+ translated_textareas[key].val('');
484
+ }else{
485
+ var trp_string = dictionaries[key].get_string_by_original( trp_deprecated_string.original );
486
+ translated_textareas[key].val( trp_string.translated );
487
+ }
488
+ translated_textareas[key].attr( TRP_TRANSLATION_ID, 'trp_creating_translation_block' );
489
+ }
490
+ };
491
+
492
+ /**
493
+ * Submit a form with the action of splitting received translation block
494
+ *
495
+ * @param trp_string_to_split
496
+ */
497
+ this.split_translation_block = function( trp_string_to_split ){
498
+ // check again
499
+ if ( _this.decide_if_merge_or_split( trp_string_to_split ) != 'split' ) {
500
+ return;
501
+ }
502
+ var split = confirm( trp_localized_text['areyousuresplittb'] );
503
+ if ( split == false ){
504
+ return;
505
+ }
506
+ var tb_to_split = [ trp_string_to_split.original ];
507
+
508
+ var form = document.createElement('form');
509
+ form.setAttribute('method', 'POST');
510
+ form.setAttribute('action', window.location.href );
511
+
512
+ var action = document.createElement('input');
513
+ action.setAttribute('type', 'hidden');
514
+ action.setAttribute('name', 'action');
515
+ action.setAttribute('value', 'trp_split_translation_block');
516
+ form.appendChild(action);
517
+
518
+ var security = document.createElement('input');
519
+ security.setAttribute('type', 'hidden');
520
+ security.setAttribute('name', 'security');
521
+ security.setAttribute('value', trp_localized_text['splittbnonce']);
522
+ form.appendChild(security);
523
+
524
+ var strings = document.createElement('input');
525
+ strings.setAttribute('type', 'hidden');
526
+ strings.setAttribute('name', 'strings');
527
+ strings.setAttribute('value', JSON.stringify( tb_to_split ));
528
+ form.appendChild(strings);
529
+
530
+ document.body.appendChild(form);
531
+ form.submit();
532
+ };
533
+
534
  /**
535
  * Show UI for translation being saved.
536
  */
662
  jQuery( '.trp-toggle-languages span' ).on( 'click', _this.toggle_languages );
663
  jQuery( '#trp-previous' ).on( 'click', function(e){
664
  e.preventDefault();
665
+ if ( _this.change_tracker == null || _this.change_tracker.check_unsaved_changes() ) {
666
  return;
667
  }
668
  prev_option_value = jQuery( 'option:selected', _this.jquery_string_selector ).prevAll('option').first().attr('value');
672
  });
673
  jQuery( '#trp-next' ).on( 'click', function(e){
674
  e.preventDefault();
675
+ if ( _this.change_tracker == null || _this.change_tracker.check_unsaved_changes() ) {
676
  return;
677
  }
678
  next_option_value = jQuery('option:selected', _this.jquery_string_selector).nextAll('option').first().attr('value');
704
 
705
  /* when we have unsaved changes prevent the strings dropdown from opening so we do not have a disconnect between the textareas and the dropdown */
706
  _this.jquery_string_selector.on('select2:opening', function (e) {
707
+ if ( trpEditor.change_tracker == null || trpEditor.change_tracker.check_unsaved_changes() ) {
708
  e.preventDefault();
709
  }
710
  });
714
  * Remove pencil icon from preview window.
715
  */
716
  this.remove_pencil_icon = function(){
717
+ jQuery( '#trp-preview-iframe').contents().find( 'trp-span' ).remove();
718
  };
719
 
720
  /**
802
  ( _this.strings[s].jquery_object != null && strings_object[i].jquery_object == null ) ||
803
  ( strings_object[i].jquery_object ==_this.strings[s].jquery_object )
804
  )
805
+ && _this.strings[s].block_type != 2
806
  ) {
807
  strings_object[i].set = true;
808
  _this.strings[s].set_string( strings_object[i] );
821
 
822
  };
823
 
824
+ /**
825
+ * Remove trp_strings which match the id from this dictionary and has ancestor a newly created translation block
826
+ *
827
+ * @param id
828
+ */
829
+ this.remove_strings_with_id_from_translation_block = function ( id ){
830
+ for ( var i in _this.strings ) {
831
+ if (_this.strings[i].id == id && _this.strings[i].jquery_object.parents( '.trp-create-translation-block' ).length > 0 ){
832
+ //remove from array
833
+ delete( _this.strings[i] );
834
+ }
835
+ }
836
+ };
837
+
838
  /**
839
  * Concatenate given strings with the existing list.
840
  *
844
  _this.strings = _this.strings.concat( new_strings );
845
  };
846
 
847
+ /**
848
+ * Return a TRP_String entry for the given id.
849
+ *
850
+ * @param id
851
+ */
852
+ this.get_string_by_id = function( id ){
853
+ for ( var i in _this.strings ) {
854
+ if (_this.strings[i].id == id) {
855
+ return _this.strings[i];
856
+ }
857
+ }
858
+ return null;
859
+ };
860
+
861
  /**
862
  * Return a TRP_String entry for the given original.
863
  *
934
  this.original = null;
935
  this.translated = null;
936
  this.status = null;
937
+ this.node_type = trp_localized_text['dynamicstrings'];
938
  this.node_description = '';
939
  this.jquery_object = null;
940
  this.language = language;
961
  };
962
 
963
  /**
964
+ * Replace existing text from iframe with specified string
 
 
965
  *
966
+ * @param text_to_set
967
+ * @param jquery_object
968
  */
969
+ this.set_text_in_iframe = function( text_to_set, jquery_object ){
970
+ if (text_to_set) {
971
+ var initial_value = jquery_object.text();
972
+ text_to_set = initial_value.replace(initial_value.trim(), text_to_set);
973
+ if ( jquery_object.attr( 'data-trp-attr' ) ){
974
+ jquery_object.children().attr( jquery_object.attr('data-trp-attr'), text_to_set );
975
+ }else if( jquery_object.attr( 'data-trp-button' ) ){
976
+ jquery_object.children('button').text(text_to_set);
977
+ }else {
978
+ if (jquery_object.text().trim() !== text_to_set.trim() ){
979
+ jquery_object.html( text_to_set );
980
+ }
981
+ }
982
+ }
983
+ };
984
 
985
  /**
986
  * Update string information. Also updates in page if available.
990
  this.set_string = function ( new_settings ){
991
  _this.id = ( new_settings.hasOwnProperty ( 'id' ) ) ? new_settings.id : _this.id;
992
  _this.original = ( new_settings.hasOwnProperty ( 'original' ) ) ? new_settings.original : _this.original;
 
993
  _this.jquery_object = ( new_settings.hasOwnProperty ( 'jquery_object' ) ) ? new_settings.jquery_object : _this.jquery_object;
994
+ _this.block_type = ( new_settings.hasOwnProperty ( 'block_type' ) ) ? new_settings.block_type : _this.block_type;
995
+ if ( _this.block_type == 1 ){
996
+ _this.node_description = trp_localized_text['translationblock'];
997
+ }
998
+
999
+ if ( new_settings.hasOwnProperty ( 'new_translation_block' ) && new_settings.new_translation_block == true && _this.language == trp_on_screen_language ){
1000
+ _this.jquery_object = trpEditor.preview_iframe.find( "[" + TRP_TRANSLATION_ID + "='trp_creating_translation_block']" );
1001
+ _this.jquery_object.attr( TRP_TRANSLATION_ID, _this.id );
1002
+ _this.jquery_object = trpEditor.preview_iframe.find( "[" + TRP_TRANSLATION_ID + "='" + _this.id + "'" );
1003
+
1004
+ _this.jquery_object.addClass('translation-block');
1005
+ _this.node_type = trp_localized_text['stringlist'];
1006
+ _this.jquery_object.attr( TRP_NODE_TYPE, _this.node_type );
1007
 
1008
+ _this.node_type = trp_localized_text['stringlist'];
1009
+ if ( trp_language != trp_on_screen_language ) {
1010
+ _this.set_text_in_iframe( _this.original, _this.jquery_object );
1011
+ }else{
1012
+ _this.set_text_in_iframe( _this.translated, _this.jquery_object );
1013
+ }
1014
+ }
1015
+
1016
+ if ( _this.jquery_object && _this.block_type != 2 ) {
1017
  if ( trp_language == trp_on_screen_language ) {
1018
  var text_to_set = null;
1019
  if (new_settings.hasOwnProperty('translated') && new_settings.translated != _this.translated) {
1023
  text_to_set = _this.original;
1024
  }
1025
  _this.wrap_special_html_elements();
1026
+ _this.set_text_in_iframe( text_to_set, _this.jquery_object );
 
 
 
 
 
 
 
 
 
 
 
 
1027
  }
1028
 
1029
  _this.jquery_object.on( 'mouseenter', '', _this.highlight );
1055
  }
1056
  };
1057
 
1058
+
1059
  /**
1060
  * Show the pencil and border the viewable string in Preview window.
1061
  */
1062
  this.highlight = function (e){
1063
  e.stopPropagation();
1064
+ var this_jquery_object;
1065
+ var tb_parent = _this.jquery_object.parents( '.trp-create-translation-block' );
1066
+ if ( tb_parent.length > 0 ){
1067
+ this_jquery_object = tb_parent.first();
1068
+ }else{
1069
+ this_jquery_object = _this.jquery_object;
1070
+ }
1071
+
1072
+ trpEditor.remove_pencil_icon();
1073
+
1074
  if ( ! trpEditor.edit_translation_button ){
1075
+ this_jquery_object.prepend( trp_action_button_html );
1076
+ trpEditor.edit_translation_button = this_jquery_object.children('trp-span');
1077
  }else{
1078
  _this.wrap_special_html_elements();
1079
  trpEditor.maybe_overflow_fix(trpEditor.edit_translation_button);
1080
+ this_jquery_object.prepend(trpEditor.edit_translation_button);
1081
+ }
1082
+ trpEditor.edit_translation_button.children( ).removeClass( 'trp-active-icon' );
1083
+ var merge_or_split = trpEditor.decide_if_merge_or_split( _this );
1084
+ if ( merge_or_split != 'none' ) {
1085
+ trpEditor.edit_translation_button.children('trp-' + merge_or_split ).addClass( 'trp-active-icon' );
1086
  }
1087
 
1088
+ trpEditor.make_sure_pencil_icon_is_inside_view( this_jquery_object[0] );
1089
 
1090
  trpEditor.edit_translation_button.off( 'click' );
1091
  trpEditor.edit_translation_button.on( 'click', function(e){
1092
  e.preventDefault();
1093
+ if ( trpEditor.change_tracker == null || trpEditor.change_tracker.check_unsaved_changes() ) {
1094
  return;
1095
  }
1096
 
1105
  }else{
1106
  trpEditor.jquery_string_selector.trigger('trpSelectorNotChanged');
1107
  }
1108
+
1109
+ if( jQuery( e.target ).closest( 'trp-split' ).length > 0 ){
1110
+ trpEditor.split_translation_block( _this );
1111
+ }
1112
+ // remove highlighting of possibly highlighted new translation block
1113
+ trpEditor.preview_iframe.contents().find('.trp-highlight.trp-create-translation-block').removeClass('trp-highlight trp-create-translation-block');
1114
+ if( jQuery( e.target ).closest( 'trp-merge' ).length > 0 ){
1115
+ trpEditor.prepare_merging( _this );
1116
+ }
1117
+
1118
+
1119
  });
1120
+ if ( tb_parent.length == 0 ) {
1121
+ jQuery(this).addClass('trp-highlight');
1122
+ }
1123
 
 
1124
  };
1125
 
1126
  /**
1155
  if ( _this.jquery_object.attr( 'name' ) == 'trp-slug' ){
1156
  _this.slug = true;
1157
  _this.slug_post_id = _this.jquery_object.attr( 'post-id' );
1158
+ _this.original = _this.jquery_object.attr( 'original' );
1159
  }
1160
  }else{
1161
  _this.original = _this.jquery_object.text();
1220
  jQuery( "#trp-gettext-strings-optgroup", jquery_string_selector ).prevAll(":not(.default-option)").remove();
1221
  /* add the normal strings before the trp-gettext-strings-optgroup optiongroup so it doesn't matter which ajax finishes first */
1222
  for ( var category in category_array ){
1223
+ if ( category == 'undefined' ){
1224
+ continue;
1225
+ }
1226
  jQuery( "#trp-gettext-strings-optgroup", jquery_string_selector ).before( jQuery( '<optgroup></optgroup>' ).attr( 'label', _this.format_category_name( category ) ) );
1227
  for ( var i in category_array[category] ) {
1228
+ if ( category_array[category][i].block_type == 2 ){
1229
+ continue;
1230
+ }
1231
+ var original = decode_html( category_array[category][i].original );
1232
  var description = '';
1233
  if ( category_array[category][i].node_description != undefined && category_array[category][i].node_description != '' ){
1234
  description = '(' + category_array[category][i].node_description + ')';
1257
  _this.set_cached_option();
1258
  };
1259
 
1260
+ /**
1261
+ * Escape tags for a given string
1262
+ *
1263
+ * @param string
1264
+ */
1265
+ this.escape_html = function ( string ){
1266
+ var escape = document.createElement('textarea');
1267
+ escape.textContent = string;
1268
+ return escape.innerHTML;
1269
+ };
1270
+
1271
  /**
1272
  * Cut the length of text displayed in string dropdown list.
1273
  */
1277
  suspension_dots = '';
1278
  }
1279
 
1280
+ return _this.escape_html( original.substring(0, 90) ) + suspension_dots ;
1281
  };
1282
 
1283
  /**
1293
  this.set_textareas_with_gettext = function( string_id ){
1294
 
1295
  /* don't do anything if there is an unsaved change */
1296
+ if ( trpEditor.change_tracker == null || trpEditor.change_tracker.check_unsaved_changes() ) {
1297
  return;
1298
  }
1299
 
1334
  };
1335
 
1336
  this.set_texts_select_to_gettext = function( jquery_object ){
1337
+ if ( trpEditor.change_tracker == null || trpEditor.change_tracker.check_unsaved_changes() ) {
1338
  return;
1339
  }
1340
  string_id = jquery_object.attr('data-trpgettextoriginal');
1529
  dataType: 'json',
1530
  data: {
1531
  action: 'trp_gettext_get_translations',
1532
+ security: trp_localized_text['gettextgettranslationsnonce'],
1533
  language: trp_language,
1534
  gettext_string_ids: JSON.stringify( gettext_string_ids )
1535
  },
1555
  gettext_string = this;
1556
 
1557
  if ( ! trpEditor.edit_translation_button ){
1558
+ trpEditor.edit_translation_button = jQuery( trp_action_button_html );
1559
  }
1560
+ trpEditor.edit_translation_button.children( ).removeClass( 'trp-active-icon' );
1561
  trpEditor.maybe_overflow_fix(trpEditor.edit_translation_button);
1562
 
1563
  if ( jQuery(this).attr( 'type' ) == 'submit' || jQuery(this).attr( 'type' ) == 'button' || jQuery(this).attr('type') == 'search' ) {
1571
  trpEditor.make_sure_pencil_icon_is_inside_view ( jQuery(this)[0] );
1572
  trpEditor.edit_translation_button.off( 'click' );
1573
  trpEditor.edit_translation_button.on( 'click', function(e){
1574
+ // remove highlighting of possibly highlighted new translation block
1575
+ trpEditor.preview_iframe.contents().find('.trp-highlight.trp-create-translation-block').removeClass('trp-highlight trp-create-translation-block');
1576
  e.preventDefault();
1577
  e.stopPropagation();
1578
  trp_lister.set_texts_select_to_gettext( jQuery(gettext_string) );
1634
  dataType: 'json',
1635
  data: {
1636
  action: 'trp_gettext_save_translations',
1637
+ security: trp_localized_text['gettextsavetranslationsnonce'],
1638
  gettext_strings: JSON.stringify( strings_to_save )
1639
  },
1640
  success: function (response) {
1675
  });
1676
 
1677
 
1678
+ /**
1679
+ * Return given text converted to html.
1680
+ *
1681
+ * Useful for decoding special characters into displayable form.
1682
+ *
1683
+ * @param html
1684
+ * @returns {*}
1685
+ */
1686
+ function decode_html( html ) {
1687
+ var txt = document.createElement( "textarea" );
1688
+ txt.innerHTML = html;
1689
+ return txt.value;
1690
+ }
assets/js/trp-iframe-preview-script.js CHANGED
@@ -10,8 +10,10 @@ function TRP_Iframe_Preview(){
10
  */
11
  this.initialize = function() {
12
  jQuery('a').each(function () {
13
- // target parent brakes from the iframe so we're removing it entirely
14
- jQuery(this).removeAttr('target');
 
 
15
 
16
  if( typeof this.href != "undefined" && this.href != '' ) {
17
  if (this.action != '' && this.href.indexOf('void(0)') === -1) {
10
  */
11
  this.initialize = function() {
12
  jQuery('a').each(function () {
13
+ // target parent brakes from the iframe so we're changing to self.
14
+ // We cannot remove it because we need it in Translation blocks
15
+ jQuery(this).attr('data-trp-original-target', jQuery(this).attr('target') );
16
+ jQuery(this).attr('target', '_self');
17
 
18
  if( typeof this.href != "undefined" && this.href != '' ) {
19
  if (this.action != '' && this.href.indexOf('void(0)') === -1) {
assets/js/trp-translate-dom-changes.js CHANGED
@@ -24,6 +24,7 @@ function TRP_Translator(){
24
  data: {
25
  action: 'trp_get_translations',
26
  async: false,
 
27
  language: language_to_query,
28
  original_language: original_language,
29
  strings: JSON.stringify( strings_to_query )
@@ -59,7 +60,7 @@ function TRP_Translator(){
59
  var txt = document.createElement( "textarea" );
60
  txt.innerHTML = html;
61
  return txt.value;
62
- }
63
 
64
  /**
65
  * Replace original strings with translations if found.
@@ -106,7 +107,9 @@ function TRP_Translator(){
106
  // this should always be outside the for loop
107
  if ( typeof parent.trpEditor !== 'undefined' ) {
108
  parent.trpEditor.populate_strings( strings_to_store );
109
- parent.trpEditor.trp_lister.reload_list();
 
 
110
  }
111
  }else{
112
  for ( var j in strings_to_query ) {
24
  data: {
25
  action: 'trp_get_translations',
26
  async: false,
27
+ security: trp_localized_text['gettranslationsnonce'],
28
  language: language_to_query,
29
  original_language: original_language,
30
  strings: JSON.stringify( strings_to_query )
60
  var txt = document.createElement( "textarea" );
61
  txt.innerHTML = html;
62
  return txt.value;
63
+ };
64
 
65
  /**
66
  * Replace original strings with translations if found.
107
  // this should always be outside the for loop
108
  if ( typeof parent.trpEditor !== 'undefined' ) {
109
  parent.trpEditor.populate_strings( strings_to_store );
110
+ if ( parent.trpEditor.trp_lister != null ) {
111
+ parent.trpEditor.trp_lister.reload_list();
112
+ }
113
  }
114
  }else{
115
  for ( var j in strings_to_query ) {
class-translate-press.php CHANGED
@@ -39,7 +39,7 @@ class TRP_Translate_Press{
39
  define( 'TRP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
40
  define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
41
  define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' );
42
- define( 'TRP_PLUGIN_VERSION', '1.2.1' );
43
 
44
  $this->load_dependencies();
45
  $this->initialize_components();
@@ -112,6 +112,9 @@ class TRP_Translate_Press{
112
 
113
  $this->loader->add_action( 'wp_ajax_trp_get_translations', $this->translation_manager, 'get_translations' );
114
  $this->loader->add_action( 'wp_ajax_trp_save_translations', $this->translation_manager, 'save_translations' );
 
 
 
115
 
116
  $this->loader->add_action( 'wp_ajax_trp_process_js_strings_in_translation_editor', $this->translation_render, 'process_js_strings_in_translation_editor' );
117
 
@@ -179,7 +182,7 @@ class TRP_Translate_Press{
179
  $this->loader->add_filter( 'date_i18n', $this->translation_manager, 'handle_date_i18n_function_for_gettext', 1, 4 );
180
 
181
  /* define an update hook here */
182
- $this->loader->add_action( 'plugins_loaded', $this->query, 'check_for_necessary_updates' );
183
 
184
  $this->loader->add_filter( 'trp_language_name', $this->languages, 'beautify_language_name', 10, 3 );
185
 
39
  define( 'TRP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
40
  define( 'TRP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
41
  define( 'TRP_PLUGIN_SLUG', 'translatepress-multilingual' );
42
+ define( 'TRP_PLUGIN_VERSION', '1.2.2' );
43
 
44
  $this->load_dependencies();
45
  $this->initialize_components();
112
 
113
  $this->loader->add_action( 'wp_ajax_trp_get_translations', $this->translation_manager, 'get_translations' );
114
  $this->loader->add_action( 'wp_ajax_trp_save_translations', $this->translation_manager, 'save_translations' );
115
+ $this->loader->add_action( 'wp_ajax_trp_create_translation_block', $this->translation_manager, 'create_translation_block' );
116
+ $this->loader->add_action( 'init', $this->translation_manager, 'split_translation_block' );
117
+
118
 
119
  $this->loader->add_action( 'wp_ajax_trp_process_js_strings_in_translation_editor', $this->translation_render, 'process_js_strings_in_translation_editor' );
120
 
182
  $this->loader->add_filter( 'date_i18n', $this->translation_manager, 'handle_date_i18n_function_for_gettext', 1, 4 );
183
 
184
  /* define an update hook here */
185
+ $this->loader->add_action( 'plugins_loaded', $this->query, 'check_for_necessary_updates', 10 );
186
 
187
  $this->loader->add_filter( 'trp_language_name', $this->languages, 'beautify_language_name', 10, 3 );
188
 
includes/class-plugin-notices.php CHANGED
@@ -284,6 +284,16 @@ class TRP_Trigger_Plugin_Notifications{
284
  $notifications->add_notification($notification_id, $message, 'trp-notice trp-narrow notice notice-info', true, array('translate-press'));
285
  }
286
 
 
 
 
 
 
 
 
 
 
 
287
  }
288
 
289
  }
284
  $notifications->add_notification($notification_id, $message, 'trp-notice trp-narrow notice notice-info', true, array('translate-press'));
285
  }
286
 
287
+
288
+ /* this must be unique */
289
+ $notification_id = 'trp_new_feature_translation_block';
290
+
291
+ $message = '<p style="padding-right:30px;">' . __('You can now translate several strings at once by merging them together. Find out more about these translation blocks in <a href="https://translatepress.com/docs/translation-editor/#translation-blocks" >our documentation.</a>.' , 'translatepress-multilingual' ) . '</p>';
292
+ //make sure to use the trp_dismiss_admin_notification arg
293
+ $message .= '<a href="' . add_query_arg(array('trp_dismiss_admin_notification' => $notification_id)) . '" type="button" class="notice-dismiss"><span class="screen-reader-text">' . __('Dismiss this notice.', 'translatepress-multilingual') . '</span></a>';
294
+
295
+ $notifications->add_notification($notification_id, $message, 'trp-notice trp-narrow notice notice-info', true, array('translate-press'));
296
+
297
  }
298
 
299
  }
includes/class-query.php CHANGED
@@ -17,6 +17,10 @@ class TRP_Query{
17
  const MACHINE_TRANSLATED = 1;
18
  const HUMAN_REVIEWED = 2;
19
 
 
 
 
 
20
  /**
21
  * TRP_Query constructor.
22
  * @param $settings
@@ -24,7 +28,7 @@ class TRP_Query{
24
  public function __construct( $settings ){
25
  global $wpdb;
26
  $this->db = $wpdb;
27
- $this->settings =$settings;
28
  }
29
 
30
  /**
@@ -42,6 +46,19 @@ class TRP_Query{
42
  return $this->translation_render->full_trim( $string );
43
  }
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  /**
46
  * Returns the translations for the provided strings.
47
  *
@@ -51,11 +68,16 @@ class TRP_Query{
51
  * @param string $language_code Language code to query for.
52
  * @return object Associative Array of objects with translations where key is original string.
53
  */
54
- public function get_existing_translations( $strings_array, $language_code ){
55
  if ( !is_array( $strings_array ) || count ( $strings_array ) == 0 ){
56
  return array();
57
  }
58
- $query = "SELECT original,translated FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE status != " . self::NOT_TRANSLATED . " AND original IN ";
 
 
 
 
 
59
 
60
  $placeholders = array();
61
  $values = array();
@@ -96,7 +118,34 @@ class TRP_Query{
96
  return self::HUMAN_REVIEWED;
97
  }
98
 
99
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  * Check if table for specific language exists.
101
  *
102
  * If the table does not exists it is created.
@@ -113,7 +162,8 @@ class TRP_Query{
113
  id bigint(20) AUTO_INCREMENT NOT NULL PRIMARY KEY,
114
  original longtext NOT NULL,
115
  translated longtext,
116
- status int(20),
 
117
  UNIQUE KEY id (id) )
118
  $charset_collate;";
119
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
@@ -121,9 +171,40 @@ class TRP_Query{
121
 
122
  $sql_index = "CREATE INDEX index_name ON `" . $table_name . "` (original(100));";
123
  $this->db->query( $sql_index );
124
- }
 
 
 
 
 
125
  }
126
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  public function check_gettext_table( $language_code ){
128
  $table_name = sanitize_text_field( $this->get_gettext_table_name($language_code) );
129
  if ( $this->db->get_var( "SHOW TABLES LIKE '$table_name'" ) != $table_name ) {
@@ -146,14 +227,23 @@ class TRP_Query{
146
  }
147
  }
148
 
 
 
 
 
149
  public function check_for_necessary_updates(){
150
  $stored_database_version = get_option('trp_plugin_version');
151
  if( empty($stored_database_version) || version_compare( TRP_PLUGIN_VERSION, $stored_database_version, '>' ) ){
152
  $this->check_if_gettext_tables_exist();
 
153
  }
 
154
  update_option( 'trp_plugin_version', TRP_PLUGIN_VERSION );
155
  }
156
 
 
 
 
157
  public function check_if_gettext_tables_exist(){
158
  if( !empty( $this->settings['translation-languages'] ) ){
159
  foreach( $this->settings['translation-languages'] as $site_language_code ){
@@ -162,6 +252,56 @@ class TRP_Query{
162
  }
163
  }
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  /**
166
  * Insert translations and new strings in DB.
167
  *
@@ -169,26 +309,32 @@ class TRP_Query{
169
  * @param array $update_strings Array of arrays, each containing an entry to update.
170
  * @param string $language_code Language code of table where it should be inserted.
171
  */
172
- public function insert_strings( $new_strings, $update_strings, $language_code ){
 
 
 
173
  if ( count( $new_strings ) == 0 && count( $update_strings ) == 0 ){
174
  return;
175
  }
176
- $query = "INSERT INTO `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` ( id, original, translated, status ) VALUES ";
177
 
178
  $values = array();
179
  $place_holders = array();
180
  $new_strings = array_unique( $new_strings );
181
 
182
  foreach ( $new_strings as $string ) {
183
- array_push( $values, NULL, $string, NULL, self::NOT_TRANSLATED );
184
- $place_holders[] = "( '%d', '%s', '%s', '%d')";
185
  }
186
  foreach ( $update_strings as $string ) {
187
- array_push( $values, $string['id'], $string['original'], $string['translated'], $string['status'] );
188
- $place_holders[] = "( '%d', '%s', '%s', '%d')";
 
 
 
189
  }
190
 
191
- $on_duplicate = ' ON DUPLICATE KEY UPDATE translated=VALUES(translated), status=VALUES(status)';
192
 
193
  $query .= implode(', ', $place_holders);
194
  $query .= $on_duplicate;
@@ -262,7 +408,7 @@ class TRP_Query{
262
  * @param string $language_code Language code to query for.
263
  * @return object Associative Array of objects with translations where key is original string.
264
  */
265
- public function get_string_ids( $original_strings, $language_code ){
266
  if ( !is_array( $original_strings ) || count ( $original_strings ) == 0 ){
267
  return array();
268
  }
@@ -276,7 +422,7 @@ class TRP_Query{
276
  }
277
 
278
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
279
- $dictionary = $this->db->get_results( $this->db->prepare( $query, $values ), OBJECT_K );
280
  return $dictionary;
281
  }
282
 
@@ -316,10 +462,18 @@ class TRP_Query{
316
  * @return string Table name.
317
  */
318
  protected function get_table_name( $language_code, $default_language = null ){
319
- if ( $default_language != null ) {
320
- $this->settings['default-language'] = $default_language;
321
  }
322
- return $this->db->prefix . 'trp_dictionary_' . strtolower( $this->settings['default-language'] ) . '_'. strtolower( $language_code );
 
 
 
 
 
 
 
 
323
  }
324
 
325
  public function get_all_gettext_strings( $language_code ){
@@ -347,9 +501,9 @@ class TRP_Query{
347
  * @param string $language_code Language code of table.
348
  * @return object Associative Array of objects with translations where key is id.
349
  */
350
- public function get_string_rows( $id_array, $original_array, $language_code ){
351
 
352
- $select_query = "SELECT id, original, translated, status FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE ";
353
 
354
  $prepared_query1 = '';
355
  if ( is_array( $original_array ) && count ( $original_array ) > 0 ) {
@@ -393,7 +547,7 @@ class TRP_Query{
393
  }
394
 
395
 
396
- $dictionary = $this->db->get_results( $query, OBJECT_K );
397
  return $dictionary;
398
  }
399
 
@@ -433,4 +587,35 @@ class TRP_Query{
433
  return $dictionary;
434
  }
435
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  }
17
  const MACHINE_TRANSLATED = 1;
18
  const HUMAN_REVIEWED = 2;
19
 
20
+ const BLOCK_TYPE_REGULAR_STRING = 0;
21
+ const BLOCK_TYPE_ACTIVE = 1;
22
+ const BLOCK_TYPE_DEPRECATED = 2;
23
+
24
  /**
25
  * TRP_Query constructor.
26
  * @param $settings
28
  public function __construct( $settings ){
29
  global $wpdb;
30
  $this->db = $wpdb;
31
+ $this->settings = $settings;
32
  }
33
 
34
  /**
46
  return $this->translation_render->full_trim( $string );
47
  }
48
 
49
+ /**
50
+ * Return an array of all the active translation blocks
51
+ *
52
+ * @param $language_code
53
+ *
54
+ * @return array|null|object
55
+ */
56
+ public function get_all_translation_blocks( $language_code ){
57
+ $query = "SELECT original, id, block_type, status FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE block_type = " . self::BLOCK_TYPE_ACTIVE . " OR block_type = " . self::BLOCK_TYPE_DEPRECATED;
58
+ $dictionary = $this->db->get_results( $query, OBJECT_K );
59
+ return $dictionary;
60
+ }
61
+
62
  /**
63
  * Returns the translations for the provided strings.
64
  *
68
  * @param string $language_code Language code to query for.
69
  * @return object Associative Array of objects with translations where key is original string.
70
  */
71
+ public function get_existing_translations( $strings_array, $language_code, $block_type = null ){
72
  if ( !is_array( $strings_array ) || count ( $strings_array ) == 0 ){
73
  return array();
74
  }
75
+ if ( $block_type == null ){
76
+ $and_block_type = "";
77
+ }else {
78
+ $and_block_type = " AND block_type = " . $block_type;
79
+ }
80
+ $query = "SELECT original,translated FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE status != " . self::NOT_TRANSLATED . $and_block_type . " AND original IN ";
81
 
82
  $placeholders = array();
83
  $values = array();
118
  return self::HUMAN_REVIEWED;
119
  }
120
 
121
+ /**
122
+ * Return constant used for individual strings, not part of a translation block
123
+ *
124
+ * @return int
125
+ */
126
+ public function get_constant_block_type_regular_string(){
127
+ return self::BLOCK_TYPE_REGULAR_STRING;
128
+ }
129
+
130
+ /**
131
+ * Return constant used for a translation block
132
+ *
133
+ * @return int
134
+ */
135
+ public function get_constant_block_type_active(){
136
+ return self::BLOCK_TYPE_ACTIVE;
137
+ }
138
+
139
+ /**
140
+ * Return constant used for a translation block, no longer in use (i.e. after being split )
141
+ *
142
+ * @return int
143
+ */
144
+ public function get_constant_block_type_deprecated(){
145
+ return self::BLOCK_TYPE_DEPRECATED;
146
+ }
147
+
148
+ /**
149
  * Check if table for specific language exists.
150
  *
151
  * If the table does not exists it is created.
162
  id bigint(20) AUTO_INCREMENT NOT NULL PRIMARY KEY,
163
  original longtext NOT NULL,
164
  translated longtext,
165
+ status int(20) DEFAULT " . $this::NOT_TRANSLATED .",
166
+ block_type int(20) DEFAULT " . $this::BLOCK_TYPE_REGULAR_STRING .",
167
  UNIQUE KEY id (id) )
168
  $charset_collate;";
169
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
171
 
172
  $sql_index = "CREATE INDEX index_name ON `" . $table_name . "` (original(100));";
173
  $this->db->query( $sql_index );
174
+
175
+ //syncronize all translation blocks.
176
+ $this->copy_all_translation_blocks_into_table( $default_language, $language_code );
177
+ }else{
178
+ $this->check_for_block_type_column( $language_code, $default_language );
179
+ }
180
  }
181
+
182
+ public function copy_all_translation_blocks_into_table( $default_language, $language_code ){
183
+ $all_table_names = $this->get_all_table_names( $default_language, array( $language_code ) );
184
+ if ( count( $all_table_names ) > 0 ){
185
+ $source_table_name = $all_table_names[0];
186
+
187
+ // copy translation blocks from table name of this language
188
+ $source_language = apply_filters( 'trp_source_language_translation_blocks', '', $default_language, $language_code );
189
+ if ( $source_language != '' ){
190
+ $source_table_name = $this->get_table_name( $source_language, $default_language );
191
+ }
192
+
193
+ $destination_table_name = $this->get_table_name( $language_code, $default_language );
194
+
195
+ // get all tb from $source_table_name and copy to $destination_table_name
196
+ $sql = 'INSERT INTO `' . $destination_table_name . '` SELECT NULL, original, "", ' . $this::NOT_TRANSLATED . ', block_type FROM `' . $source_table_name . '` WHERE block_type = ' . self::BLOCK_TYPE_ACTIVE . ' OR block_type = ' . self::BLOCK_TYPE_DEPRECATED;
197
+ $this->db->query( $sql );
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Check if gettext table for specific language exists.
203
+ *
204
+ * If the table does not exists it is created.
205
+ *
206
+ * @param string $language_code
207
+ */
208
  public function check_gettext_table( $language_code ){
209
  $table_name = sanitize_text_field( $this->get_gettext_table_name($language_code) );
210
  if ( $this->db->get_var( "SHOW TABLES LIKE '$table_name'" ) != $table_name ) {
227
  }
228
  }
229
 
230
+ /**
231
+ * When changing plugin version, call certain database upgrade functions.
232
+ *
233
+ */
234
  public function check_for_necessary_updates(){
235
  $stored_database_version = get_option('trp_plugin_version');
236
  if( empty($stored_database_version) || version_compare( TRP_PLUGIN_VERSION, $stored_database_version, '>' ) ){
237
  $this->check_if_gettext_tables_exist();
238
+ $this->check_for_block_type_column();
239
  }
240
+
241
  update_option( 'trp_plugin_version', TRP_PLUGIN_VERSION );
242
  }
243
 
244
+ /**
245
+ * Iterates over all languages to call gettext table checking
246
+ */
247
  public function check_if_gettext_tables_exist(){
248
  if( !empty( $this->settings['translation-languages'] ) ){
249
  foreach( $this->settings['translation-languages'] as $site_language_code ){
252
  }
253
  }
254
 
255
+ /**
256
+ * Add block_type column to dictionary tables, if it doesn't exist.
257
+ *
258
+ * Affects all existing tables, including deactivated languages
259
+ *
260
+ * @param null $language_code
261
+ * @param null $default_language
262
+ */
263
+ public function check_for_block_type_column( $language_code = null, $default_language = null ){
264
+ if ( $default_language == null ){
265
+ $default_language = $this->settings['default-language'];
266
+ }
267
+
268
+ if ( $language_code ){
269
+ // check only this language
270
+ $array_of_table_names = array( $this->get_table_name( $language_code, $default_language ) );
271
+ }else {
272
+ // check all languages, including deactivated ones
273
+ $array_of_table_names = $this->get_all_table_names( $default_language, array() );
274
+ }
275
+
276
+ foreach( $array_of_table_names as $table_name ){
277
+ if ( ! $this->table_column_exists( $table_name, 'block_type' ) ) {
278
+ $this->db->query("ALTER TABLE " . $table_name . " ADD block_type INT(20) DEFAULT " . $this::BLOCK_TYPE_REGULAR_STRING );
279
+ }
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Returns true if a database table column exists. Otherwise returns false.
285
+ *
286
+ * @link http://stackoverflow.com/a/5943905/2489248
287
+ * @global wpdb $wpdb
288
+ *
289
+ * @param string $table_name Name of table we will check for column existence.
290
+ * @param string $column_name Name of column we are checking for.
291
+ *
292
+ * @return boolean True if column exists. Else returns false.
293
+ */
294
+ public function table_column_exists( $table_name, $column_name ) {
295
+ $column = $this->db->get_results( $this->db->prepare(
296
+ "SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = %s ",
297
+ DB_NAME, $table_name, $column_name
298
+ ) );
299
+ if ( ! empty( $column ) ) {
300
+ return true;
301
+ }
302
+ return false;
303
+ }
304
+
305
  /**
306
  * Insert translations and new strings in DB.
307
  *
309
  * @param array $update_strings Array of arrays, each containing an entry to update.
310
  * @param string $language_code Language code of table where it should be inserted.
311
  */
312
+ public function insert_strings( $new_strings, $update_strings, $language_code, $block_type = self::BLOCK_TYPE_REGULAR_STRING ){
313
+ if ( $block_type == null ){
314
+ $block_type = self::BLOCK_TYPE_REGULAR_STRING;
315
+ }
316
  if ( count( $new_strings ) == 0 && count( $update_strings ) == 0 ){
317
  return;
318
  }
319
+ $query = "INSERT INTO `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` ( id, original, translated, status, block_type ) VALUES ";
320
 
321
  $values = array();
322
  $place_holders = array();
323
  $new_strings = array_unique( $new_strings );
324
 
325
  foreach ( $new_strings as $string ) {
326
+ array_push( $values, NULL, $string, NULL, self::NOT_TRANSLATED, $block_type );
327
+ $place_holders[] = "( '%d', '%s', '%s', '%d', '%d')";
328
  }
329
  foreach ( $update_strings as $string ) {
330
+ if ( ! isset( $string['block_type'] ) ){
331
+ $string['block_type'] = self::BLOCK_TYPE_REGULAR_STRING;
332
+ }
333
+ array_push( $values, $string['id'], $string['original'], $string['translated'], $string['status'], $string['block_type'] );
334
+ $place_holders[] = "( '%d', '%s', '%s', '%d', '%d')";
335
  }
336
 
337
+ $on_duplicate = ' ON DUPLICATE KEY UPDATE translated=VALUES(translated), status=VALUES(status), block_type=VALUES(block_type)';
338
 
339
  $query .= implode(', ', $place_holders);
340
  $query .= $on_duplicate;
408
  * @param string $language_code Language code to query for.
409
  * @return object Associative Array of objects with translations where key is original string.
410
  */
411
+ public function get_string_ids( $original_strings, $language_code, $output = OBJECT_K ){
412
  if ( !is_array( $original_strings ) || count ( $original_strings ) == 0 ){
413
  return array();
414
  }
422
  }
423
 
424
  $query .= "( " . implode ( ", ", $placeholders ) . " )";
425
+ $dictionary = $this->db->get_results( $this->db->prepare( $query, $values ), $output );
426
  return $dictionary;
427
  }
428
 
462
  * @return string Table name.
463
  */
464
  protected function get_table_name( $language_code, $default_language = null ){
465
+ if ( $default_language == null ) {
466
+ $default_language = $this->settings['default-language'];
467
  }
468
+ return $this->db->prefix . 'trp_dictionary_' . strtolower( $default_language ) . '_'. strtolower( $language_code );
469
+ }
470
+
471
+ public function get_language_code_from_table_name( $table_name, $default_language = null ){
472
+ if ( $default_language == null ) {
473
+ $default_language = $this->settings['default-language'];
474
+ }
475
+ $language_code = str_replace($this->db->prefix . 'trp_dictionary_' . strtolower( $default_language ) . '_', '', $table_name );
476
+ return $language_code;
477
  }
478
 
479
  public function get_all_gettext_strings( $language_code ){
501
  * @param string $language_code Language code of table.
502
  * @return object Associative Array of objects with translations where key is id.
503
  */
504
+ public function get_string_rows( $id_array, $original_array, $language_code, $output = OBJECT_K ){
505
 
506
+ $select_query = "SELECT id, original, translated, status, block_type FROM `" . sanitize_text_field( $this->get_table_name( $language_code ) ) . "` WHERE ";
507
 
508
  $prepared_query1 = '';
509
  if ( is_array( $original_array ) && count ( $original_array ) > 0 ) {
547
  }
548
 
549
 
550
+ $dictionary = $this->db->get_results( $query, $output );
551
  return $dictionary;
552
  }
553
 
587
  return $dictionary;
588
  }
589
 
590
+ public function get_all_table_names ( $original_language, $exception_translation_languages = array() ){
591
+ foreach ( $exception_translation_languages as $key => $language ){
592
+ $exception_translation_languages[$key] = $this->get_table_name( $language, $original_language );
593
+ }
594
+ $return_tables = array();
595
+ $table_name = $this->get_table_name( '' );
596
+ $table_names = $this->db->get_results( "SHOW TABLES LIKE '$table_name%'", ARRAY_N );
597
+ foreach ( $table_names as $table_name ){
598
+ if ( isset( $table_name[0]) && ! in_array( $table_name[0], $exception_translation_languages ) ) {
599
+ $return_tables[] = $table_name[0];
600
+ }
601
+ }
602
+ return $return_tables;
603
+ }
604
+
605
+ public function update_translation_blocks_by_original( $table_names, $original_array, $block_type ) {
606
+
607
+ $values = array();
608
+ foreach( $table_names as $table_name ){
609
+ $placeholders = array();
610
+ foreach( $original_array as $string ){
611
+ $placeholders[] = '%s';
612
+ $values[] = $this->full_trim( $string );
613
+ }
614
+ }
615
+
616
+ $placeholders = "( " . implode ( ", ", $placeholders ) . " )";
617
+ $query = 'UPDATE `' . implode( $table_names, '`, `' ) . '` SET `' . implode( $table_names, '`.block_type=' . $block_type . ', `' ) . '`.block_type=' . $block_type . ' WHERE `' . implode( $table_names, '`.original IN ' . $placeholders . ' AND `' ) . '`.original IN ' . $placeholders ;
618
+
619
+ return $this->db->query( $this->db->prepare( $query, $values ) );
620
+ }
621
  }
includes/class-translation-manager.php CHANGED
@@ -7,7 +7,9 @@
7
  */
8
  class TRP_Translation_Manager{
9
  protected $settings;
 
10
  protected $translation_render;
 
11
  protected $trp_query;
12
  protected $machine_translator;
13
  protected $slug_manager;
@@ -62,6 +64,35 @@ class TRP_Translation_Manager{
62
  return TRP_PLUGIN_DIR . 'partials/translation-manager.php' ;
63
  }
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  /**
66
  * Enqueue scripts and styles for translation Editor parent window.
67
  */
@@ -70,6 +101,10 @@ class TRP_Translation_Manager{
70
  wp_enqueue_script( 'trp-select2-lib-js', TRP_PLUGIN_URL . 'assets/lib/select2-lib/dist/js/select2.min.js', array( 'jquery' ), TRP_PLUGIN_VERSION );
71
 
72
  wp_enqueue_script( 'trp-translation-manager-script', TRP_PLUGIN_URL . 'assets/js/trp-editor-script.js', array(), TRP_PLUGIN_VERSION );
 
 
 
 
73
  wp_enqueue_style( 'trp-translation-manager-style', TRP_PLUGIN_URL . 'assets/css/trp-editor-style.css', array('buttons'), TRP_PLUGIN_VERSION );
74
 
75
  wp_enqueue_script( 'trp-translation-overlay', TRP_PLUGIN_URL . 'assets/js/trp-editor-overlay.js', array(), TRP_PLUGIN_VERSION );
@@ -86,7 +121,7 @@ class TRP_Translation_Manager{
86
  public function enqueue_preview_scripts_and_styles(){
87
  if ( $this->conditions_met( 'preview' ) ) {
88
  wp_enqueue_script( 'trp-translation-manager-preview-script', TRP_PLUGIN_URL . 'assets/js/trp-iframe-preview-script.js', array('jquery'), TRP_PLUGIN_VERSION );
89
- wp_enqueue_style('trp-preview-iframe-style', TRP_PLUGIN_URL . 'assets/css/trp-preview-iframe-style.css', array(), TRP_PLUGIN_VERSION );
90
  }
91
  }
92
 
@@ -97,8 +132,16 @@ class TRP_Translation_Manager{
97
  */
98
  public function add_slug_as_meta_tag() {
99
  global $post;
100
- if ( isset( $post->ID ) && !empty( $post->ID ) && isset( $post->post_name ) && !empty( $post->post_name ) && $this->conditions_met( 'preview' ) && !is_home() && !is_front_page() && !is_archive() && !is_search() ) {
101
- echo '<meta name="trp-slug" content="' . $post->post_name. '" post-id="' . $post->ID . '"/>' . "\n";
 
 
 
 
 
 
 
 
102
  }
103
 
104
  }
@@ -114,12 +157,105 @@ class TRP_Translation_Manager{
114
  protected function extract_original_strings( $strings, $original_array, $id_array ){
115
  if ( count( $strings ) > 0 ) {
116
  foreach ($id_array as $id) {
117
- $original_array[] = $strings[$id]->original;
 
 
118
  }
119
  }
120
  return array_values( $original_array );
121
  }
122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  /**
124
  * Returns translations based on original strings and ids.
125
  *
@@ -128,89 +264,18 @@ class TRP_Translation_Manager{
128
  */
129
  public function get_translations() {
130
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
131
- if ( isset( $_POST['action'] ) && $_POST['action'] === 'trp_get_translations' && !empty( $_POST['strings'] ) && !empty( $_POST['language'] ) && in_array( $_POST['language'], $this->settings['translation-languages'] ) ) {
132
- $strings = json_decode(stripslashes($_POST['strings']));
133
- if ( is_array( $strings ) ) {
134
- $id_array = array();
135
- $original_array = array();
136
- $dictionaries = array();
137
- $slug_info = false;
138
- foreach ( $strings as $key => $string ) {
139
- if ( isset( $string->slug ) && $string->slug === true ){
140
- $slug_info = array(
141
- 'post_id' => (int)$string->slug_post_id,
142
- 'id' => (int)$string->id,
143
- 'original' => sanitize_text_field( $string->original ) );
144
- continue;
145
- }
146
- if ( isset( $string->id ) && is_numeric( $string->id ) ) {
147
- $id_array[$key] = (int)$string->id;
148
- } else if ( isset( $string->original ) ) {
149
- $original_array[$key] = sanitize_text_field( $string->original );
150
- }
151
- }
152
-
153
- $current_language = sanitize_text_field( $_POST['language'] );
154
-
155
- $trp = TRP_Translate_Press::get_trp_instance();
156
- if ( ! $this->trp_query ) {
157
- $this->trp_query = $trp->get_component( 'query' );
158
- }
159
- if ( ! $this->slug_manager ) {
160
- $this->slug_manager = $trp->get_component('slug_manager');
161
- }
162
- if ( ! $this->translation_render ) {
163
- $this->translation_render = $trp->get_component('translation_render');
164
- }
165
-
166
- // necessary in order to obtain all the original strings
167
- if ( $this->settings['default-language'] != $current_language ) {
168
- if ( current_user_can ( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
169
- $this->translation_render->process_strings($original_array, $current_language);
170
- }
171
- $dictionaries[$current_language] = $this->trp_query->get_string_rows( $id_array, $original_array, $current_language );
172
- if ( $slug_info !== false ) {
173
- $dictionaries[$current_language][$slug_info['id']] = array(
174
- 'id' => $slug_info['id'],
175
- 'original' => $slug_info['original'],
176
- 'translated' => apply_filters( 'trp_translate_slug', $slug_info['original'], $slug_info['post_id'], $current_language ),
177
- );
178
- }
179
-
180
- }else{
181
- $dictionaries[$current_language] = array();
182
- }
183
-
184
- if ( isset( $_POST['all_languages'] ) && $_POST['all_languages'] === 'true' ) {
185
- foreach ($this->settings['translation-languages'] as $language) {
186
- if ($language == $this->settings['default-language']) {
187
- $dictionaries[$language]['default-language'] = true;
188
- continue;
189
- }
190
-
191
- if ($language == $current_language) {
192
- continue;
193
- }
194
- if (empty($original_strings)) {
195
- $original_strings = $this->extract_original_strings($dictionaries[$current_language], $original_array, $id_array);
196
- }
197
- if (current_user_can(apply_filters( 'trp_translating_capability', 'manage_options' ))) {
198
- $this->translation_render->process_strings($original_strings, $language);
199
- }
200
- $dictionaries[$language] = $this->trp_query->get_string_rows(array(), $original_strings, $language);
201
- if ( $slug_info !== false ) {
202
- $dictionaries[$language][0] = array(
203
- 'id' => 0,
204
- 'original' => $slug_info['original'],
205
- 'translated' => apply_filters( 'trp_translate_slug', $slug_info['original'], $slug_info['post_id'], $language ),
206
- );
207
- }
208
- }
209
- }
210
-
211
  echo trp_safe_json_encode( $dictionaries );
212
  }
213
-
214
  }
215
  }
216
 
@@ -219,9 +284,9 @@ class TRP_Translation_Manager{
219
 
220
  public function gettext_get_translations(){
221
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
222
- if (isset($_POST['action']) && $_POST['action'] === 'trp_gettext_get_translations' && !empty($_POST['gettext_string_ids']) && !empty($_POST['language']) && in_array($_POST['language'], $this->settings['translation-languages'])) {
223
-
224
- if (!empty($_POST['gettext_string_ids']))
225
  $gettext_string_ids = json_decode(stripslashes($_POST['gettext_string_ids']));
226
  else
227
  $gettext_string_ids = array();
@@ -314,42 +379,63 @@ class TRP_Translation_Manager{
314
  }
315
  }
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  /**
318
  * Save translations from ajax post.
319
  *
320
  * Hooked to wp_ajax_trp_save_translations.
321
  */
322
  public function save_translations(){
323
-
324
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX && current_user_can( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
 
325
  if ( isset( $_POST['action'] ) && $_POST['action'] === 'trp_save_translations' && !empty( $_POST['strings'] ) ) {
326
  $strings = json_decode(stripslashes($_POST['strings']));
327
- $update_strings = array();
328
- foreach ( $strings as $language => $language_strings ) {
329
- if ( in_array( $language, $this->settings['translation-languages'] ) && $language != $this->settings['default-language'] ) {
330
- foreach( $language_strings as $string ) {
331
- if ( isset( $string->id ) && is_numeric( $string->id ) ) {
332
- $update_strings[ $language ] = array();
333
- array_push($update_strings[ $language ], array(
334
- 'id' => (int)$string->id,
335
- 'original' => sanitize_text_field($string->original),
336
- 'translated' => preg_replace( '/<script\b[^>]*>(.*?)<\/script>/is', '', $string->translated ),
337
- 'status' => (int)$string->status
338
- ));
339
-
340
- }
341
- }
342
- }
343
- }
344
-
345
- if ( ! $this->trp_query ) {
346
- $trp = TRP_Translate_Press::get_trp_instance();
347
- $this->trp_query = $trp->get_component( 'query' );
348
- }
349
-
350
- foreach( $update_strings as $language => $update_string_array ) {
351
- $this->trp_query->insert_strings( array(), $update_string_array, $language );
352
- }
353
  }
354
  }
355
 
@@ -359,6 +445,7 @@ class TRP_Translation_Manager{
359
  public function gettext_save_translations(){
360
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX && current_user_can( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
361
  if (isset($_POST['action']) && $_POST['action'] === 'trp_gettext_save_translations' && !empty($_POST['gettext_strings'])) {
 
362
  $strings = json_decode(stripslashes($_POST['gettext_strings']));
363
  $update_strings = array();
364
  foreach ( $strings as $language => $language_strings ) {
@@ -368,8 +455,8 @@ class TRP_Translation_Manager{
368
  $update_strings[ $language ] = array();
369
  array_push($update_strings[ $language ], array(
370
  'id' => (int)$string->id,
371
- 'original' => sanitize_text_field($string->original),
372
- 'translated' => preg_replace( '/<script\b[^>]*>(.*?)<\/script>/is', '', $string->translated ),
373
  'domain' => sanitize_text_field( $string->domain ),
374
  'status' => (int)$string->status
375
  ));
@@ -391,6 +478,134 @@ class TRP_Translation_Manager{
391
  die();
392
  }
393
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
  /**
395
  * Display button to enter translation Editor in admin bar
396
  *
@@ -616,7 +831,7 @@ class TRP_Translation_Manager{
616
  $found_in_db = true;
617
  /* update the db if a translation appeared in the po file later */
618
  if( empty( $trp_translated_gettext_text['translated'] ) && $translation != $text ) {
619
- $this->trp_query->update_gettext_strings( array( array( 'id' => $db_id, 'original' => $text, 'translated' => $translation, 'domain' => $domain), 'status' => TRP_Query::HUMAN_REVIEWED ), get_locale() );
620
  }
621
 
622
  break;
@@ -643,7 +858,7 @@ class TRP_Translation_Manager{
643
  foreach( $trp_translated_gettext_texts as $trp_translated_gettext_text ){
644
  if( $trp_translated_gettext_text['id'] == $db_id ){
645
  if( $trp_translated_gettext_text['translated'] == '' ){
646
- $trp_gettext_strings_for_machine_translation[] = array( 'id' => $db_id, 'original' => $text, 'translated' => '', 'domain' => $domain, 'status' => TRP_Query::MACHINE_TRANSLATED );
647
  }
648
  break;
649
  }
7
  */
8
  class TRP_Translation_Manager{
9
  protected $settings;
10
+ /** @var TRP_Translation_Render */
11
  protected $translation_render;
12
+ /** @var TRP_Query */
13
  protected $trp_query;
14
  protected $machine_translator;
15
  protected $slug_manager;
64
  return TRP_PLUGIN_DIR . 'partials/translation-manager.php' ;
65
  }
66
 
67
+ public function get_merge_rules(){
68
+ $localized_text = $this->localized_text();
69
+ $merge_rules = array (
70
+ 'top_parents' => array( 'p', 'div', 'li', 'ol', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7', 'body', 'footer', 'article', 'main', 'iframe', 'section', 'figure', 'figcaption' ),
71
+ 'self_object_type' => array( 'translate-press' ),
72
+ 'incompatible_siblings' => array( '[data-trpgettextoriginal]', '[data-trp-node-type="' . $localized_text['dynamicstrings'] . '"]' )
73
+ );
74
+ return apply_filters( 'trp_merge_rules', $merge_rules );
75
+ }
76
+
77
+ public function localized_text(){
78
+ $text = array(
79
+ 'edit' => __( 'Translate', 'translatepress-multilingual' ),
80
+ 'merge' => __( 'Translate entire block element', 'translatepress-multilingual' ),
81
+ 'split' => __( 'Split block to translate strings individually', 'translatepress-multilingual' ),
82
+ 'translationblock' => __( 'Translation block', 'translatepress-multilingual' ),
83
+ 'areyousuresplittb' => __( 'Are you sure you want to split this phrase into smaller pieces?', 'translatepress-multilingual' ),
84
+ 'metainformation' => __( 'Meta Information', 'translatepress-multilingual' ),
85
+ 'stringlist' => __( 'String List', 'translatepress-multilingual' ),
86
+ 'dynamicstrings' => __( 'Dynamic Added Strings', 'translatepress-multilingual' ),
87
+ 'gettranslationsnonce' => __( wp_create_nonce('get_translations'), 'translatepress-multilingual' ),
88
+ 'savestringsnonce' => __( wp_create_nonce('save_translations'), 'translatepress-multilingual' ),
89
+ 'splittbnonce' => __( wp_create_nonce('split_translation_block'), 'translatepress-multilingual' ),
90
+ 'gettextgettranslationsnonce' => __( wp_create_nonce('gettext_get_translations'), 'translatepress-multilingual' ),
91
+ 'gettextsavetranslationsnonce' => __( wp_create_nonce('gettext_save_translations'), 'translatepress-multilingual' ),
92
+ );
93
+ return $text;
94
+ }
95
+
96
  /**
97
  * Enqueue scripts and styles for translation Editor parent window.
98
  */
101
  wp_enqueue_script( 'trp-select2-lib-js', TRP_PLUGIN_URL . 'assets/lib/select2-lib/dist/js/select2.min.js', array( 'jquery' ), TRP_PLUGIN_VERSION );
102
 
103
  wp_enqueue_script( 'trp-translation-manager-script', TRP_PLUGIN_URL . 'assets/js/trp-editor-script.js', array(), TRP_PLUGIN_VERSION );
104
+ $trp_merge_rules = $this->get_merge_rules();
105
+ wp_localize_script('trp-translation-manager-script', 'trp_merge_rules', $trp_merge_rules);
106
+ $localized_text = $this->localized_text();
107
+ wp_localize_script('trp-translation-manager-script', 'trp_localized_text', $localized_text );
108
  wp_enqueue_style( 'trp-translation-manager-style', TRP_PLUGIN_URL . 'assets/css/trp-editor-style.css', array('buttons'), TRP_PLUGIN_VERSION );
109
 
110
  wp_enqueue_script( 'trp-translation-overlay', TRP_PLUGIN_URL . 'assets/js/trp-editor-overlay.js', array(), TRP_PLUGIN_VERSION );
121
  public function enqueue_preview_scripts_and_styles(){
122
  if ( $this->conditions_met( 'preview' ) ) {
123
  wp_enqueue_script( 'trp-translation-manager-preview-script', TRP_PLUGIN_URL . 'assets/js/trp-iframe-preview-script.js', array('jquery'), TRP_PLUGIN_VERSION );
124
+ wp_enqueue_style('trp-preview-iframe-style', TRP_PLUGIN_URL . 'assets/css/trp-preview-iframe-style.css', array('dashicons'), TRP_PLUGIN_VERSION );
125
  }
126
  }
127
 
132
  */
133
  public function add_slug_as_meta_tag() {
134
  global $post;
135
+ // we need this further down when generating slug translations
136
+ global $trp_backup_post_id;
137
+ if( isset( $post->ID ) && !empty( $post->ID ) && !is_home() && !is_front_page() && !is_archive() && !is_search() ){
138
+ $trp_backup_post_id = $post->ID;
139
+ } else {
140
+ $trp_backup_post_id = 0;
141
+ }
142
+
143
+ if ( isset( $post->ID ) && !empty( $post->ID ) && isset( $post->post_name ) && !empty( $post->post_name ) && !is_home() && !is_front_page() && !is_archive() && !is_search() ) {
144
+ echo '<meta name="trp-slug" original="' . $post->post_name. '" content="' . $post->post_name. '" post-id="' . $post->ID . '"/>' . "\n";
145
  }
146
 
147
  }
157
  protected function extract_original_strings( $strings, $original_array, $id_array ){
158
  if ( count( $strings ) > 0 ) {
159
  foreach ($id_array as $id) {
160
+ if ( is_object( $strings[$id] ) ){
161
+ $original_array[] = $strings[ $id ]->original;
162
+ }
163
  }
164
  }
165
  return array_values( $original_array );
166
  }
167
 
168
+ /**
169
+ * Return dictionary with translated strings.
170
+ *
171
+ * @param $strings
172
+ * @param null $block_type
173
+ *
174
+ * @return array
175
+ */
176
+ protected function get_translation_for_strings( $strings, $block_type = null ){
177
+ $id_array = array();
178
+ $original_array = array();
179
+ $dictionaries = array();
180
+ $slug_info = false;
181
+ foreach ( $strings as $key => $string ) {
182
+ if ( isset( $string->slug ) && $string->slug === true ){
183
+ $slug_info = array(
184
+ 'post_id' => (int)$string->slug_post_id,
185
+ 'id' => (int)$string->id,
186
+ 'original' => sanitize_text_field( $string->original ) );
187
+ continue;
188
+ }
189
+ if ( isset( $string->id ) && is_numeric( $string->id ) ) {
190
+ $id_array[$key] = (int)$string->id;
191
+ } else if ( isset( $string->original ) ) {
192
+ $original_array[$key] = trp_sanitize_string( $string->original );
193
+ }
194
+ }
195
+
196
+ $current_language = sanitize_text_field( $_POST['language'] );
197
+
198
+ $trp = TRP_Translate_Press::get_trp_instance();
199
+ if ( ! $this->trp_query ) {
200
+ $this->trp_query = $trp->get_component( 'query' );
201
+ }
202
+ if ( ! $this->slug_manager ) {
203
+ $this->slug_manager = $trp->get_component('slug_manager');
204
+ }
205
+ if ( ! $this->translation_render ) {
206
+ $this->translation_render = $trp->get_component('translation_render');
207
+ }
208
+
209
+ // necessary in order to obtain all the original strings
210
+ if ( $this->settings['default-language'] != $current_language ) {
211
+ if ( current_user_can ( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
212
+ $this->translation_render->process_strings($original_array, $current_language, $block_type);
213
+ }
214
+ $dictionaries[$current_language] = $this->trp_query->get_string_rows( $id_array, $original_array, $current_language );
215
+ if ( $slug_info !== false ) {
216
+ $dictionaries[$current_language][$slug_info['id']] = array(
217
+ 'id' => $slug_info['id'],
218
+ 'original' => $slug_info['original'],
219
+ 'translated' => apply_filters( 'trp_translate_slug', $slug_info['original'], $slug_info['post_id'], $current_language ),
220
+ );
221
+ }
222
+
223
+ }else{
224
+ $dictionaries[$current_language] = array();
225
+ }
226
+
227
+ if ( isset( $_POST['all_languages'] ) && $_POST['all_languages'] === 'true' ) {
228
+ foreach ($this->settings['translation-languages'] as $language) {
229
+ if ($language == $this->settings['default-language']) {
230
+ $dictionaries[$language]['default-language'] = true;
231
+ continue;
232
+ }
233
+
234
+ if ($language == $current_language) {
235
+ continue;
236
+ }
237
+ if (empty($original_strings)) {
238
+ $original_strings = $this->extract_original_strings($dictionaries[$current_language], $original_array, $id_array);
239
+ }
240
+ if (current_user_can(apply_filters( 'trp_translating_capability', 'manage_options' ))) {
241
+ $this->translation_render->process_strings($original_strings, $language, $block_type);
242
+ }
243
+ $dictionaries[$language] = $this->trp_query->get_string_rows(array(), $original_strings, $language);
244
+ if ( $slug_info !== false ) {
245
+ $dictionaries[$language][0] = array(
246
+ 'id' => 0,
247
+ 'original' => $slug_info['original'],
248
+ 'translated' => apply_filters( 'trp_translate_slug', $slug_info['original'], $slug_info['post_id'], $language ),
249
+ );
250
+ }
251
+ }
252
+ }
253
+
254
+ return $dictionaries;
255
+ }
256
+
257
+
258
+
259
  /**
260
  * Returns translations based on original strings and ids.
261
  *
264
  */
265
  public function get_translations() {
266
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
267
+ check_ajax_referer( 'get_translations', 'security' );
268
+ if ( isset( $_POST['action'] ) && $_POST['action'] === 'trp_get_translations' && !empty( $_POST['strings'] ) && !empty( $_POST['language'] ) && in_array( $_POST['language'], $this->settings['translation-languages'] ) ) {
269
+ $strings = json_decode(stripslashes($_POST['strings']));
270
+ if ( is_array( $strings ) ) {
271
+ if (!$this->trp_query) {
272
+ $trp = TRP_Translate_Press::get_trp_instance();
273
+ $this->trp_query = $trp->get_component('query');
274
+ }
275
+ $block_type = $this->trp_query->get_constant_block_type_regular_string();
276
+ $dictionaries = $this->get_translation_for_strings( $strings, $block_type );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  echo trp_safe_json_encode( $dictionaries );
278
  }
 
279
  }
280
  }
281
 
284
 
285
  public function gettext_get_translations(){
286
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
287
+ if (isset($_POST['action']) && $_POST['action'] === 'trp_gettext_get_translations' && !empty($_POST['gettext_string_ids']) && !empty($_POST['language']) && in_array($_POST['language'], $this->settings['translation-languages'])) {
288
+ check_ajax_referer( 'gettext_get_translations', 'security' );
289
+ if (!empty($_POST['gettext_string_ids']))
290
  $gettext_string_ids = json_decode(stripslashes($_POST['gettext_string_ids']));
291
  else
292
  $gettext_string_ids = array();
379
  }
380
  }
381
 
382
+ /**
383
+ * Save translations in DB for the strings
384
+ *
385
+ * @param $strings
386
+ * @param null $block_type
387
+ */
388
+ protected function save_translations_of_strings( $strings, $block_type = null ){
389
+ if ( !$block_type ){
390
+ if (!$this->trp_query) {
391
+ $trp = TRP_Translate_Press::get_trp_instance();
392
+ $this->trp_query = $trp->get_component('query');
393
+ }
394
+ $block_type = $this->trp_query->get_constant_block_type_regular_string();
395
+ }
396
+ $update_strings = array();
397
+ foreach ( $strings as $language => $language_strings ) {
398
+ if ( in_array( $language, $this->settings['translation-languages'] ) && $language != $this->settings['default-language'] ) {
399
+ foreach( $language_strings as $string ) {
400
+ if ( isset( $string->id ) && is_numeric( $string->id ) ) {
401
+ $update_strings[ $language ] = array();
402
+ if ( ! isset( $string->block_type ) ){
403
+ $string->block_type = $block_type;
404
+ }
405
+ array_push($update_strings[ $language ], array(
406
+ 'id' => (int)$string->id,
407
+ 'original' => trp_sanitize_string( $string->original ),
408
+ 'translated' => trp_sanitize_string( $string->translated ),
409
+ 'status' => (int)$string->status,
410
+ 'block_type' => (int)$string->block_type
411
+ ));
412
+
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ if ( ! $this->trp_query ) {
419
+ $trp = TRP_Translate_Press::get_trp_instance();
420
+ $this->trp_query = $trp->get_component( 'query' );
421
+ }
422
+
423
+ foreach( $update_strings as $language => $update_string_array ) {
424
+ $this->trp_query->insert_strings( array(), $update_string_array, $language, $block_type );
425
+ }
426
+ }
427
+
428
  /**
429
  * Save translations from ajax post.
430
  *
431
  * Hooked to wp_ajax_trp_save_translations.
432
  */
433
  public function save_translations(){
 
434
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX && current_user_can( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
435
+ check_ajax_referer( 'save_translations', 'security' );
436
  if ( isset( $_POST['action'] ) && $_POST['action'] === 'trp_save_translations' && !empty( $_POST['strings'] ) ) {
437
  $strings = json_decode(stripslashes($_POST['strings']));
438
+ $this->save_translations_of_strings( $strings );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
439
  }
440
  }
441
 
445
  public function gettext_save_translations(){
446
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX && current_user_can( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
447
  if (isset($_POST['action']) && $_POST['action'] === 'trp_gettext_save_translations' && !empty($_POST['gettext_strings'])) {
448
+ check_ajax_referer( 'gettext_save_translations', 'security' );
449
  $strings = json_decode(stripslashes($_POST['gettext_strings']));
450
  $update_strings = array();
451
  foreach ( $strings as $language => $language_strings ) {
455
  $update_strings[ $language ] = array();
456
  array_push($update_strings[ $language ], array(
457
  'id' => (int)$string->id,
458
+ 'original' => trp_sanitize_string( $string->original ),
459
+ 'translated' => trp_sanitize_string( $string->translated ),
460
  'domain' => sanitize_text_field( $string->domain ),
461
  'status' => (int)$string->status
462
  ));
478
  die();
479
  }
480
 
481
+ /**
482
+ * Set translation block to active.
483
+ *
484
+ * Creates TB is not exists. Adds auto translation if one is not provided.
485
+ * Supports handling multiple translation blocks
486
+ */
487
+ public function create_translation_block(){
488
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX && current_user_can( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
489
+ check_ajax_referer( 'save_translations', 'security' );
490
+ if ( isset( $_POST['action'] ) && $_POST['action'] === 'trp_create_translation_block' && !empty( $_POST['strings'] ) && !empty( $_POST['language'] ) && in_array( $_POST['language'], $this->settings['translation-languages'] ) ) {
491
+ $strings = json_decode( stripslashes( $_POST['strings'] ) );
492
+ if ( isset ( $this->settings['translation-languages']) ){
493
+ $trp = TRP_Translate_Press::get_trp_instance();
494
+ if (!$this->trp_query) {
495
+ $this->trp_query = $trp->get_component('query');
496
+ }
497
+ if (!$this->translation_render) {
498
+ $this->translation_render = $trp->get_component('translation_render');
499
+ }
500
+
501
+ $active_block_type = $this->trp_query->get_constant_block_type_active();
502
+ foreach( $this->settings['translation-languages'] as $language ){
503
+ if ( $language != $this->settings['default-language'] ){
504
+ $dictionaries = $this->get_translation_for_strings( $strings->$language, $active_block_type );
505
+ break;
506
+ }
507
+ }
508
+
509
+ /*
510
+ * Merging the dictionary received from get_translation_for_strings (which contains ID and possibly automatic translations) with
511
+ * ajax translated (which can contain manual translations)
512
+ */
513
+ $originals_array_constructed = false;
514
+ $originals = array();
515
+ if ( isset( $dictionaries ) ){
516
+ foreach ( $dictionaries as $language => $dictionary ){
517
+ foreach( $dictionary as $dictionary_string_key => $dictionary_string ){
518
+ if ( !isset ($strings->$language) ){
519
+ continue;
520
+ }
521
+ $ajax_translated_string_list = $strings->$language;
522
+ foreach( $ajax_translated_string_list as $ajax_key => $ajax_string ) {
523
+ if ( trp_sanitize_string( $ajax_string->original ) == $dictionary_string->original ) {
524
+ if ( $ajax_string->translated != '' ) {
525
+ $dictionaries[ $language ][ $dictionary_string_key ]->translated = trp_sanitize_string( $ajax_string->translated );
526
+ $dictionaries[ $language ][ $dictionary_string_key ]->status = (int) $ajax_string->status;
527
+ }
528
+ $dictionaries[ $language ][ $dictionary_string_key ]->block_type = (int) $ajax_string->block_type;
529
+ }
530
+ $dictionaries[ $language ][ $dictionary_string_key ]->new_translation_block = true;
531
+ }
532
+
533
+ if( !$originals_array_constructed ){
534
+ $originals[] = $dictionary_string->original;
535
+ }
536
+ }
537
+ $originals_array_constructed = true;
538
+ }
539
+ $this->save_translations_of_strings( $dictionaries, $active_block_type );
540
+
541
+ // update deactivated languages
542
+ $copy_of_originals = $originals;
543
+ if ( $originals_array_constructed ){
544
+ $table_names = $this->trp_query->get_all_table_names( $this->settings['default-language'], $this->settings['translation-languages'] );
545
+ if ( count( $table_names ) > 0 ){
546
+ foreach( $table_names as $table_name ) {
547
+ $originals = $copy_of_originals;
548
+ $language = $this->trp_query->get_language_code_from_table_name( $table_name );
549
+ $existing_dictionary = $this->trp_query->get_string_rows( array(), $originals, $language, ARRAY_A );
550
+ foreach ( $existing_dictionary as $string_key => $string ){
551
+ foreach ( $originals as $original_key => $original ){
552
+ if ( $string['original'] == $original ){
553
+ unset( $originals[$original_key] );
554
+ }
555
+ }
556
+ $existing_dictionary[$string_key]['block_type'] = $active_block_type;
557
+ $originals = array_values( $originals );
558
+ }
559
+ $this->trp_query->insert_strings( $originals, $existing_dictionary, $language, $active_block_type );
560
+ }
561
+
562
+ }
563
+ }
564
+
565
+ echo trp_safe_json_encode( $dictionaries );
566
+ }
567
+ }
568
+
569
+ }
570
+ }
571
+ die();
572
+ }
573
+
574
+ /**
575
+ * Set translation block to deprecated
576
+ *
577
+ * Can handle splitting multiple blocks.
578
+ *
579
+ * @return mixed|string|void
580
+ */
581
+ public function split_translation_block() {
582
+ if ( current_user_can( apply_filters( 'trp_translating_capability', 'manage_options' ) ) ) {
583
+ if ( isset( $_POST['action'] ) && $_POST['action'] === 'trp_split_translation_block' && ! empty( $_POST['strings'] ) ) {
584
+ check_ajax_referer( 'split_translation_block', 'security' );
585
+ $raw_original_array = json_decode( stripslashes( $_POST['strings'] ) );
586
+ $trp = TRP_Translate_Press::get_trp_instance();
587
+ if ( ! $this->trp_query ) {
588
+ $this->trp_query = $trp->get_component( 'query' );
589
+ }
590
+ $deprecated_block_type = $this->trp_query->get_constant_block_type_deprecated();
591
+ $originals = array();
592
+ foreach( $raw_original_array as $original ){
593
+ $originals[] = trp_sanitize_string( $original );
594
+ }
595
+
596
+ // even inactive languages ( not in $this->settings['translation-languages'] array ) will be updated
597
+ $all_languages_table_names = $this->trp_query->get_all_table_names( $this->settings['default-language'], array() );
598
+ $rows_affected = $this->trp_query->update_translation_blocks_by_original( $all_languages_table_names, $originals, $deprecated_block_type );
599
+ if ( $rows_affected == 0 ){
600
+ // do updates individually if it fails
601
+ foreach ( $all_languages_table_names as $table_name ){
602
+ $this->trp_query->update_translation_blocks_by_original( array( $table_name ), $originals, $deprecated_block_type );
603
+ }
604
+ }
605
+ }
606
+ }
607
+ }
608
+
609
  /**
610
  * Display button to enter translation Editor in admin bar
611
  *
831
  $found_in_db = true;
832
  /* update the db if a translation appeared in the po file later */
833
  if( empty( $trp_translated_gettext_text['translated'] ) && $translation != $text ) {
834
+ $this->trp_query->update_gettext_strings( array( array( 'id' => $db_id, 'original' => $text, 'translated' => $translation, 'domain' => $domain), 'status' => $this->trp_query->get_constant_human_reviewed() ), get_locale() );
835
  }
836
 
837
  break;
858
  foreach( $trp_translated_gettext_texts as $trp_translated_gettext_text ){
859
  if( $trp_translated_gettext_text['id'] == $db_id ){
860
  if( $trp_translated_gettext_text['translated'] == '' ){
861
+ $trp_gettext_strings_for_machine_translation[] = array( 'id' => $db_id, 'original' => $text, 'translated' => '', 'domain' => $domain, 'status' => $this->trp_query->get_constant_machine_translated() );
862
  }
863
  break;
864
  }
includes/class-translation-render.php CHANGED
@@ -10,6 +10,8 @@ class TRP_Translation_Render{
10
  protected $machine_translator;
11
  protected $trp_query;
12
  protected $url_converter;
 
 
13
 
14
  /**
15
  * TRP_Translation_Render constructor.
@@ -129,8 +131,14 @@ class TRP_Translation_Render{
129
  * @return string Category name.
130
  */
131
  protected function get_node_type_category( $current_node_type ){
 
 
 
 
 
 
132
  $node_type_categories = apply_filters( 'trp_node_type_categories', array(
133
- __( 'Meta Information', 'translatepress-multilingual' ) => array( 'meta_desc', 'post_slug', 'page_title' ),
134
  ));
135
 
136
  foreach( $node_type_categories as $category_name => $node_types ){
@@ -139,8 +147,7 @@ class TRP_Translation_Render{
139
  }
140
  }
141
 
142
- return __( 'String List', 'translatepress-multilingual' );
143
-
144
  }
145
 
146
  /**
@@ -219,6 +226,43 @@ class TRP_Translation_Render{
219
 
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  /**
223
  * Finding translateable strings and replacing with translations.
224
  *
@@ -230,7 +274,7 @@ class TRP_Translation_Render{
230
  public function translate_page( $output ){
231
  $output = apply_filters('trp_before_translate_content', $output);
232
 
233
- if ( strlen( $output ) < 1 ){
234
  return $output;
235
  }
236
 
@@ -240,12 +284,13 @@ class TRP_Translation_Render{
240
  return $output;
241
  }
242
 
 
243
 
244
  /* if there is an ajax request and we have a json response we need to parse it and only translate the nodes that contain html */
245
  if( TRP_Translation_Manager::is_ajax_on_frontend() ) {
246
 
247
  /* if it's one of our own ajax calls don't do nothing */
248
- if( !empty( $_REQUEST['action'] ) && strpos( $_REQUEST['action'], 'trp_' ) === 0 ){
249
  return $output;
250
  }
251
 
@@ -293,6 +338,16 @@ class TRP_Translation_Render{
293
  $translateable_strings = array();
294
  $nodes = array();
295
 
 
 
 
 
 
 
 
 
 
 
296
  $html = trp_str_get_html($output, true, true, TRP_DEFAULT_TARGET_CHARSET, false, TRP_DEFAULT_BR_TEXT, TRP_DEFAULT_SPAN_TEXT);
297
 
298
  /**
@@ -314,6 +369,31 @@ class TRP_Translation_Render{
314
  }
315
  else{
316
  $trp_attr_rows[] = $row;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  }
318
  }
319
 
@@ -392,7 +472,6 @@ class TRP_Translation_Render{
392
  $row->setAttribute( $no_translate_attribute, '' );
393
  }
394
  }
395
-
396
  foreach ( $html->find('.translation-block') as $k => $row ){
397
  if( $this->full_trim($row->outertext)!=""
398
  && $row->parent()->tag!="script"
@@ -457,14 +536,10 @@ class TRP_Translation_Render{
457
  $translateable_strings = $translateable_information['translateable_strings'];
458
  $nodes = $translateable_information['nodes'];
459
 
460
- if ( ! $this->trp_query ) {
461
- $trp = TRP_Translate_Press::get_trp_instance();
462
- $this->trp_query = $trp->get_component( 'query' );
463
- }
464
-
465
  $translated_strings = $this->process_strings( $translateable_strings, $language_code );
466
 
467
- $preview_mode = isset( $_REQUEST['trp-edit-translation'] ) && $_REQUEST['trp-edit-translation'] == 'preview';
 
468
  if ( $preview_mode ) {
469
  $translated_string_ids = $this->trp_query->get_string_ids($translateable_strings, $language_code);
470
  }
@@ -562,12 +637,20 @@ class TRP_Translation_Render{
562
  $this->url_converter = $trp->get_component('url_converter');
563
  }
564
 
 
 
 
 
565
  // force custom links to have the correct language
566
  foreach( $html->find('a[href!="#"]') as $a_href) {
567
  $url = $a_href->href;
568
  $is_external_link = $this->is_external_link( $url );
569
  $is_admin_link = $this->is_admin_link($url);
570
 
 
 
 
 
571
  if ( $this->settings['force-language-to-custom-links'] == 'yes' && !$is_external_link && $this->url_converter->get_lang_from_url_string( $url ) == null && !$is_admin_link && strpos($url, '#TRPLINKPROCESSED') === false ){
572
  $a_href->href = apply_filters( 'trp_force_custom_links', $this->url_converter->get_url_for_language( $TRP_LANGUAGE, $url ), $url, $TRP_LANGUAGE, $a_href );
573
  $url = $a_href->href;
@@ -583,9 +666,28 @@ class TRP_Translation_Render{
583
  // pass the current language in forms where the action does not contain the language
584
  // based on this we're filtering wp_redirect to include the proper URL when returning to the current page.
585
  foreach ( $html->find('form') as $k => $row ){
 
586
  $row->innertext .= apply_filters( 'trp_form_inputs', '<input type="hidden" name="trp-form-language" value="'. $this->settings['url-slugs'][$TRP_LANGUAGE] .'"/>', $TRP_LANGUAGE, $this->settings['url-slugs'][$TRP_LANGUAGE] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  }
588
 
 
 
 
589
 
590
  return $html->save();
591
  }
@@ -667,7 +769,7 @@ class TRP_Translation_Render{
667
  * @param $language_code
668
  * @return array
669
  */
670
- public function process_strings( $translateable_strings, $language_code ){
671
  $translated_strings = array();
672
 
673
  if ( ! $this->trp_query ) {
@@ -681,7 +783,7 @@ class TRP_Translation_Render{
681
  foreach( $translateable_strings as $i => $string ){
682
  //strings existing in database,
683
 
684
- if ( isset( $dictionary[$this->full_trim($string)]->translated ) ){
685
  $translated_strings[$i] = $dictionary[$this->full_trim($string)]->translated;
686
  }else{
687
  $new_strings[$i] = $translateable_strings[$i];
@@ -710,8 +812,8 @@ class TRP_Translation_Render{
710
  // we have a translation
711
  array_push ( $update_strings, array(
712
  'id' => $untranslated_list[$string]->id,
713
- 'original' => sanitize_text_field($untranslated_list[$string]->original),
714
- 'translated' => sanitize_text_field($machine_strings[$i]),
715
  'status' => $this->trp_query->get_constant_machine_translated() ) );
716
  $translated_strings[$i] = $machine_strings[$i];
717
  }
@@ -729,14 +831,14 @@ class TRP_Translation_Render{
729
  array_push ( $update_strings, array(
730
  'id' => NULL,
731
  'original' => $new_strings[$i],
732
- 'translated' => sanitize_text_field($machine_strings[$i]),
733
  'status' => $this->trp_query->get_constant_machine_translated() ) );
734
  unset($new_strings[$i]);
735
  }
736
  }
737
  }
738
 
739
- $this->trp_query->insert_strings( $new_strings, $update_strings, $language_code );
740
 
741
  return $translated_strings;
742
  }
@@ -815,6 +917,12 @@ class TRP_Translation_Render{
815
  }
816
  wp_enqueue_script('trp-dynamic-translator', TRP_PLUGIN_URL . 'assets/js/trp-translate-dom-changes.js', array('jquery', 'trp-language-switcher'), TRP_PLUGIN_VERSION );
817
  wp_localize_script('trp-dynamic-translator', 'trp_data', $trp_data);
 
 
 
 
 
 
818
  }
819
  }
820
 
@@ -878,7 +986,7 @@ class TRP_Translation_Render{
878
  * @since 1.0.8
879
  */
880
  public function force_preview_on_url_in_ajax( $output ){
881
- if ( TRP_Translation_Manager::is_ajax_on_frontend() && isset( $_REQUEST['trp-edit-translation'] ) && $_REQUEST['trp-edit-translation'] === 'preview' ) {
882
  $result = json_decode($output, TRUE);
883
  if ( json_last_error() === JSON_ERROR_NONE) {
884
  array_walk_recursive($result, array($this, 'callback_add_preview_arg'));
10
  protected $machine_translator;
11
  protected $trp_query;
12
  protected $url_converter;
13
+ /* @var TRP_Translation_Manager */
14
+ protected $translation_manager;
15
 
16
  /**
17
  * TRP_Translation_Render constructor.
131
  * @return string Category name.
132
  */
133
  protected function get_node_type_category( $current_node_type ){
134
+ $trp = TRP_Translate_Press::get_trp_instance();
135
+ if ( ! $this->translation_manager ) {
136
+ $this->translation_manager = $trp->get_component( 'translation_manager' );
137
+ }
138
+ $localized_text = $this->translation_manager->localized_text();
139
+
140
  $node_type_categories = apply_filters( 'trp_node_type_categories', array(
141
+ $localized_text['metainformation'] => array( 'meta_desc', 'post_slug', 'page_title' ),
142
  ));
143
 
144
  foreach( $node_type_categories as $category_name => $node_types ){
147
  }
148
  }
149
 
150
+ return $localized_text['stringlist'];
 
151
  }
152
 
153
  /**
226
 
227
  }
228
 
229
+ /**
230
+ * Specific trim made for translation block string
231
+ *
232
+ * Problem especially for nbsp; which gets saved like that in DB. Then, in translation-render, the string arrives with nbsp; rendered to actual space character.
233
+ * Used before inserting in db, and when trying to match on translation-render.
234
+ *
235
+ * @param $string
236
+ *
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
+ /**
244
+ * Return translation block if matches any existing translation block from db
245
+ *
246
+ * Return null if not found
247
+ *
248
+ * @param $row
249
+ * @param $all_existing_translation_blocks
250
+ * @param $merge_rules
251
+ *
252
+ * @return bool
253
+ */
254
+ public function find_translation_block( $row, $all_existing_translation_blocks, $merge_rules ){
255
+ if ( in_array( $row->tag, $merge_rules['top_parents'] ) ){
256
+ $trimmed_inner_text = $this->trim_translation_block( $row->innertext );
257
+ foreach( $all_existing_translation_blocks as $existing_translation_block ){
258
+ if ( $this->trim_translation_block( $existing_translation_block->original ) == $trimmed_inner_text ){
259
+ return $existing_translation_block;
260
+ }
261
+ }
262
+ }
263
+ return null;
264
+ }
265
+
266
  /**
267
  * Finding translateable strings and replacing with translations.
268
  *
274
  public function translate_page( $output ){
275
  $output = apply_filters('trp_before_translate_content', $output);
276
 
277
+ if ( strlen( $output ) < 1 || $output == false ){
278
  return $output;
279
  }
280
 
284
  return $output;
285
  }
286
 
287
+ $preview_mode = isset( $_REQUEST['trp-edit-translation'] ) && $_REQUEST['trp-edit-translation'] == 'preview';
288
 
289
  /* if there is an ajax request and we have a json response we need to parse it and only translate the nodes that contain html */
290
  if( TRP_Translation_Manager::is_ajax_on_frontend() ) {
291
 
292
  /* if it's one of our own ajax calls don't do nothing */
293
+ if( !empty( $_REQUEST['action'] ) && strpos( $_REQUEST['action'], 'trp_' ) === 0 && $_REQUEST['action'] != 'trp_split_translation_block' ){
294
  return $output;
295
  }
296
 
338
  $translateable_strings = array();
339
  $nodes = array();
340
 
341
+ $trp = TRP_Translate_Press::get_trp_instance();
342
+ if ( ! $this->trp_query ) {
343
+ $this->trp_query = $trp->get_component( 'query' );
344
+ }
345
+ if ( ! $this->translation_manager ) {
346
+ $this->translation_manager = $trp->get_component( 'translation_manager' );
347
+ }
348
+ $all_existing_translation_blocks = $this->trp_query->get_all_translation_blocks( $language_code );
349
+ $merge_rules = $this->translation_manager->get_merge_rules();
350
+
351
  $html = trp_str_get_html($output, true, true, TRP_DEFAULT_TARGET_CHARSET, false, TRP_DEFAULT_BR_TEXT, TRP_DEFAULT_SPAN_TEXT);
352
 
353
  /**
369
  }
370
  else{
371
  $trp_attr_rows[] = $row;
372
+
373
+ $translation_block = $this->find_translation_block( $row, $all_existing_translation_blocks, $merge_rules );
374
+ if ( $translation_block ){
375
+ $existing_classes = $row->getAttribute( 'class' );
376
+ if ( $translation_block->block_type == 1 ) {
377
+ $found_inner_translation_block = false;
378
+ foreach( $row->children() as $child ){
379
+ if ( $this->find_translation_block( $child, array( $translation_block ), $merge_rules ) != null ){
380
+ $found_inner_translation_block = true;
381
+ break;
382
+ }
383
+ }
384
+ if ( !$found_inner_translation_block ) {
385
+ // make sure we find it later exactly the way it is in DB
386
+ $row->innertext = $translation_block->original;
387
+ $row->setAttribute( 'class', $existing_classes . ' translation-block' );
388
+ }
389
+ }else if ( $preview_mode && $translation_block->block_type == 2 && $translation_block->status != 0 ) {
390
+ // refactor to not do this for each
391
+ $row->setAttribute( 'data-trp-translate-id', $translation_block->id );
392
+ $row->setAttribute( 'data-trp-translate-id-deprecated', $translation_block->id );
393
+ $row->setAttribute( 'class', $existing_classes . 'trp-deprecated-tb' );
394
+ }
395
+ }
396
+
397
  }
398
  }
399
 
472
  $row->setAttribute( $no_translate_attribute, '' );
473
  }
474
  }
 
475
  foreach ( $html->find('.translation-block') as $k => $row ){
476
  if( $this->full_trim($row->outertext)!=""
477
  && $row->parent()->tag!="script"
536
  $translateable_strings = $translateable_information['translateable_strings'];
537
  $nodes = $translateable_information['nodes'];
538
 
 
 
 
 
 
539
  $translated_strings = $this->process_strings( $translateable_strings, $language_code );
540
 
541
+ do_action('trp_translateable_information', $translateable_information, $translated_strings, $language_code);
542
+
543
  if ( $preview_mode ) {
544
  $translated_string_ids = $this->trp_query->get_string_ids($translateable_strings, $language_code);
545
  }
637
  $this->url_converter = $trp->get_component('url_converter');
638
  }
639
 
640
+ // We need to save here in order to access the translated links too.
641
+ $html = $html->save();
642
+ $html = trp_str_get_html($html, true, true, TRP_DEFAULT_TARGET_CHARSET, false, TRP_DEFAULT_BR_TEXT, TRP_DEFAULT_SPAN_TEXT);
643
+
644
  // force custom links to have the correct language
645
  foreach( $html->find('a[href!="#"]') as $a_href) {
646
  $url = $a_href->href;
647
  $is_external_link = $this->is_external_link( $url );
648
  $is_admin_link = $this->is_admin_link($url);
649
 
650
+ if( $preview_mode && ! $is_external_link ){
651
+ $a_href->setAttribute( 'data-trp-original-href', $url );
652
+ }
653
+
654
  if ( $this->settings['force-language-to-custom-links'] == 'yes' && !$is_external_link && $this->url_converter->get_lang_from_url_string( $url ) == null && !$is_admin_link && strpos($url, '#TRPLINKPROCESSED') === false ){
655
  $a_href->href = apply_filters( 'trp_force_custom_links', $this->url_converter->get_url_for_language( $TRP_LANGUAGE, $url ), $url, $TRP_LANGUAGE, $a_href );
656
  $url = $a_href->href;
666
  // pass the current language in forms where the action does not contain the language
667
  // based on this we're filtering wp_redirect to include the proper URL when returning to the current page.
668
  foreach ( $html->find('form') as $k => $row ){
669
+ $row->setAttribute( 'data-trp-original-action', $row->action );
670
  $row->innertext .= apply_filters( 'trp_form_inputs', '<input type="hidden" name="trp-form-language" value="'. $this->settings['url-slugs'][$TRP_LANGUAGE] .'"/>', $TRP_LANGUAGE, $this->settings['url-slugs'][$TRP_LANGUAGE] );
671
+ $form_action = $row->action;
672
+
673
+ $is_external_link = $this->is_external_link( $form_action );
674
+ $is_admin_link = $this->is_admin_link($form_action );
675
+
676
+ if ( !empty($form_action)
677
+ && $this->settings['force-language-to-custom-links'] == 'yes'
678
+ && !$is_external_link
679
+ && $this->url_converter->get_lang_from_url_string( $form_action ) == null
680
+ && !$is_admin_link
681
+ && strpos($url, '#TRPLINKPROCESSED') === false)
682
+ {
683
+ $row->action = $this->url_converter->get_url_for_language( $TRP_LANGUAGE, $form_action );
684
+ }
685
+ $row->action = str_replace('#TRPLINKPROCESSED', '', $row->action);
686
  }
687
 
688
+ foreach ( $html->find('link') as $link ){
689
+ $link->href = str_replace('#TRPLINKPROCESSED', '', $link->href);
690
+ }
691
 
692
  return $html->save();
693
  }
769
  * @param $language_code
770
  * @return array
771
  */
772
+ public function process_strings( $translateable_strings, $language_code, $block_type = null ){
773
  $translated_strings = array();
774
 
775
  if ( ! $this->trp_query ) {
783
  foreach( $translateable_strings as $i => $string ){
784
  //strings existing in database,
785
 
786
+ if ( isset( $dictionary[$string]->translated ) ){
787
  $translated_strings[$i] = $dictionary[$this->full_trim($string)]->translated;
788
  }else{
789
  $new_strings[$i] = $translateable_strings[$i];
812
  // we have a translation
813
  array_push ( $update_strings, array(
814
  'id' => $untranslated_list[$string]->id,
815
+ 'original' => trp_sanitize_string($untranslated_list[$string]->original),
816
+ 'translated' => trp_sanitize_string($machine_strings[$i]),
817
  'status' => $this->trp_query->get_constant_machine_translated() ) );
818
  $translated_strings[$i] = $machine_strings[$i];
819
  }
831
  array_push ( $update_strings, array(
832
  'id' => NULL,
833
  'original' => $new_strings[$i],
834
+ 'translated' => trp_sanitize_string($machine_strings[$i]),
835
  'status' => $this->trp_query->get_constant_machine_translated() ) );
836
  unset($new_strings[$i]);
837
  }
838
  }
839
  }
840
 
841
+ $this->trp_query->insert_strings( $new_strings, $update_strings, $language_code, $block_type );
842
 
843
  return $translated_strings;
844
  }
917
  }
918
  wp_enqueue_script('trp-dynamic-translator', TRP_PLUGIN_URL . 'assets/js/trp-translate-dom-changes.js', array('jquery', 'trp-language-switcher'), TRP_PLUGIN_VERSION );
919
  wp_localize_script('trp-dynamic-translator', 'trp_data', $trp_data);
920
+ $trp = TRP_Translate_Press::get_trp_instance();
921
+ if ( ! $this->translation_manager ) {
922
+ $this->translation_manager = $trp->get_component( 'translation_manager' );
923
+ }
924
+ $localized_text = $this->translation_manager->localized_text();
925
+ wp_localize_script('trp-dynamic-translator', 'trp_localized_text', $localized_text );
926
  }
927
  }
928
 
986
  * @since 1.0.8
987
  */
988
  public function force_preview_on_url_in_ajax( $output ){
989
+ if ( TRP_Translation_Manager::is_ajax_on_frontend() && isset( $_REQUEST['trp-edit-translation'] ) && $_REQUEST['trp-edit-translation'] === 'preview' && $output != false ) {
990
  $result = json_decode($output, TRUE);
991
  if ( json_last_error() === JSON_ERROR_NONE) {
992
  array_walk_recursive($result, array($this, 'callback_add_preview_arg'));
includes/class-url-converter.php CHANGED
@@ -73,9 +73,9 @@ class TRP_Url_Converter {
73
 
74
  $url_slug = $this->get_url_slug( $TRP_LANGUAGE );
75
  $abs_home = $this->get_abs_home();
76
- $new_url = trailingslashit( $abs_home ) . $url_slug;
77
  if ( ! empty( $path ) ){
78
- $new_url .= '/' . ltrim( $path, '/' );
79
  }
80
 
81
  return apply_filters( 'trp_home_url', $new_url, $abs_home, $TRP_LANGUAGE, $path, $url );
@@ -166,6 +166,7 @@ class TRP_Url_Converter {
166
  */
167
  public function get_url_for_language ( $language = null, $url = null, $trp_link_is_processed = '#TRPLINKPROCESSED') {
168
  global $TRP_LANGUAGE;
 
169
  $new_url = '';
170
 
171
  // we're appending $trp_link_is_processed string to the end of each processed link so we don't process them again in the render class.
@@ -186,14 +187,21 @@ class TRP_Url_Converter {
186
  $language = $TRP_LANGUAGE;
187
  }
188
 
 
189
  if( empty( $url ) ) {
190
  $url = $this->cur_page_url();
 
191
  }
192
 
193
- $post_id = url_to_postid($url);
194
  if( $post_id ){
195
  $TRP_LANGUAGE = $language;
196
  $new_url = get_permalink( $post_id );
 
 
 
 
 
 
197
  $TRP_LANGUAGE = $trp_language_copy;
198
  } else {
199
  // If no $post_id is set we simply replace the current language root with the new language root.
73
 
74
  $url_slug = $this->get_url_slug( $TRP_LANGUAGE );
75
  $abs_home = $this->get_abs_home();
76
+ $new_url = trailingslashit( trailingslashit( $abs_home ) . $url_slug );
77
  if ( ! empty( $path ) ){
78
+ $new_url .= ltrim( $path, '/' );
79
  }
80
 
81
  return apply_filters( 'trp_home_url', $new_url, $abs_home, $TRP_LANGUAGE, $path, $url );
166
  */
167
  public function get_url_for_language ( $language = null, $url = null, $trp_link_is_processed = '#TRPLINKPROCESSED') {
168
  global $TRP_LANGUAGE;
169
+ global $trp_backup_post_id;
170
  $new_url = '';
171
 
172
  // we're appending $trp_link_is_processed string to the end of each processed link so we don't process them again in the render class.
187
  $language = $TRP_LANGUAGE;
188
  }
189
 
190
+ $post_id = url_to_postid( $url );
191
  if( empty( $url ) ) {
192
  $url = $this->cur_page_url();
193
+ $post_id = ( url_to_postid( $url ) ) ? ( url_to_postid( $url ) ) : ( $trp_backup_post_id );
194
  }
195
 
 
196
  if( $post_id ){
197
  $TRP_LANGUAGE = $language;
198
  $new_url = get_permalink( $post_id );
199
+
200
+ $pass_arguments = parse_url($url);
201
+ if(isset($pass_arguments['query'])){
202
+ $new_url = trailingslashit($new_url) . '?' . $pass_arguments['query'];
203
+ }
204
+
205
  $TRP_LANGUAGE = $trp_language_copy;
206
  } else {
207
  // If no $post_id is set we simply replace the current language root with the new language root.
includes/functions.php CHANGED
@@ -126,4 +126,31 @@ function trp_add_affiliate_id_to_link( $link ){
126
  }
127
 
128
  return esc_url( $link );
129
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
 
128
  return esc_url( $link );
129
+ }
130
+
131
+ /**
132
+ * Function that makes string safe for display.
133
+ *
134
+ * Can be used on original or translated string.
135
+ * Removes any unwanted html code from the string.
136
+ * Do not confuse with trim.
137
+ */
138
+ function trp_sanitize_string( $filtered ){
139
+ $filtered = preg_replace( '/<script\b[^>]*>(.*?)<\/script>/is', '', $filtered );
140
+
141
+ $filtered = preg_replace( '/[\r\n\t ]+/', ' ', $filtered );
142
+ $filtered = trim( $filtered );
143
+
144
+ $found = false;
145
+ while ( preg_match('/%[a-f0-9]{2}/i', $filtered, $match) ) {
146
+ $filtered = str_replace($match[0], '', $filtered);
147
+ $found = true;
148
+ }
149
+
150
+ if ( $found ) {
151
+ // Strip out the whitespace that may now exist after removing the octets.
152
+ $filtered = trim( preg_replace('/ +/', ' ', $filtered) );
153
+ }
154
+
155
+ return $filtered;
156
+ }
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.2.1
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.2.2
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
@@ -17,6 +17,7 @@
17
  <?php __("Select the languages you wish to make your website available in.", "translatepress-multilingual"); ?>
18
  <?php __("You are not using a permalink structure! Please <a href=\"%s\">enable</a> one or install our <a href=\"%s\">\"Language by GET parameter\"</a> addon so TranslatePress can function properly.", "translatepress-multilingual"); ?>
19
  <?php __("Dismiss this notice.", "translatepress-multilingual"); ?>
 
20
  <?php __("Full Language Names", "translatepress-multilingual"); ?>
21
  <?php __("Short Language Names", "translatepress-multilingual"); ?>
22
  <?php __("Flags with Full Language Names", "translatepress-multilingual"); ?>
@@ -27,11 +28,17 @@
27
  <?php __("Translate Site", "translatepress-multilingual"); ?>
28
  <?php __("License", "translatepress-multilingual"); ?>
29
  <?php __("Addons", "translatepress-multilingual"); ?>
 
 
 
 
 
 
 
 
30
  <?php __("Translate Page", "translatepress-multilingual"); ?>
31
  <?php __("Settings", "translatepress-multilingual"); ?>
32
  <?php __("Security check", "translatepress-multilingual"); ?>
33
- <?php __("Meta Information", "translatepress-multilingual"); ?>
34
- <?php __("String List", "translatepress-multilingual"); ?>
35
  <?php __("Description", "translatepress-multilingual"); ?>
36
  <?php __("OG Title", "translatepress-multilingual"); ?>
37
  <?php __("OG Site Name", "translatepress-multilingual"); ?>
17
  <?php __("Select the languages you wish to make your website available in.", "translatepress-multilingual"); ?>
18
  <?php __("You are not using a permalink structure! Please <a href=\"%s\">enable</a> one or install our <a href=\"%s\">\"Language by GET parameter\"</a> addon so TranslatePress can function properly.", "translatepress-multilingual"); ?>
19
  <?php __("Dismiss this notice.", "translatepress-multilingual"); ?>
20
+ <?php __("You can now translate several strings at once by merging them together. Find out more about these translation blocks in <a href=\"https://translatepress.com/docs/translation-editor/#translation-blocks\" >our documentation.</a>.", "translatepress-multilingual"); ?>
21
  <?php __("Full Language Names", "translatepress-multilingual"); ?>
22
  <?php __("Short Language Names", "translatepress-multilingual"); ?>
23
  <?php __("Flags with Full Language Names", "translatepress-multilingual"); ?>
28
  <?php __("Translate Site", "translatepress-multilingual"); ?>
29
  <?php __("License", "translatepress-multilingual"); ?>
30
  <?php __("Addons", "translatepress-multilingual"); ?>
31
+ <?php __("Translate", "translatepress-multilingual"); ?>
32
+ <?php __("Translate entire block element", "translatepress-multilingual"); ?>
33
+ <?php __("Split block to translate strings individually", "translatepress-multilingual"); ?>
34
+ <?php __("Translation block", "translatepress-multilingual"); ?>
35
+ <?php __("Are you sure you want to split this phrase into smaller pieces?", "translatepress-multilingual"); ?>
36
+ <?php __("Meta Information", "translatepress-multilingual"); ?>
37
+ <?php __("String List", "translatepress-multilingual"); ?>
38
+ <?php __("Dynamic Added Strings", "translatepress-multilingual"); ?>
39
  <?php __("Translate Page", "translatepress-multilingual"); ?>
40
  <?php __("Settings", "translatepress-multilingual"); ?>
41
  <?php __("Security check", "translatepress-multilingual"); ?>
 
 
42
  <?php __("Description", "translatepress-multilingual"); ?>
43
  <?php __("OG Title", "translatepress-multilingual"); ?>
44
  <?php __("OG Site Name", "translatepress-multilingual"); ?>
languages/translatepress-multilingual.pot CHANGED
@@ -21,23 +21,23 @@ msgstr ""
21
  msgid "Limit this menu item to the following languages"
22
  msgstr ""
23
 
24
- #: ../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:17, partials/license-settings-page.php:4
25
  msgid "TranslatePress Settings"
26
  msgstr ""
27
 
28
- #: ../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, partials/license-settings-page.php:10
29
  msgid "License Key"
30
  msgstr ""
31
 
32
- #: ../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, partials/license-settings-page.php:15
33
  msgid "Enter your license key."
34
  msgstr ""
35
 
36
- #: ../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, partials/license-settings-page.php:22, partials/license-settings-page.php:31
37
  msgid "Activate License"
38
  msgstr ""
39
 
40
- #: ../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, partials/license-settings-page.php:28
41
  msgid "Deactivate License"
42
  msgstr ""
43
 
@@ -81,10 +81,14 @@ msgstr ""
81
  msgid "You are not using a permalink structure! Please <a href=\"%s\">enable</a> one or install our <a href=\"%s\">\"Language by GET parameter\"</a> addon so TranslatePress can function properly."
82
  msgstr ""
83
 
84
- #: ../translatepress/includes/class-plugin-notices.php:282
85
  msgid "Dismiss this notice."
86
  msgstr ""
87
 
 
 
 
 
88
  #: ../translatepress/includes/class-settings.php:25
89
  msgid "Full Language Names"
90
  msgstr ""
@@ -113,7 +117,7 @@ msgstr ""
113
  msgid "General"
114
  msgstr ""
115
 
116
- #: ../translatepress/includes/class-settings.php:397, ../translatepress/includes/class-translation-manager.php:409
117
  msgid "Translate Site"
118
  msgstr ""
119
 
@@ -125,55 +129,82 @@ msgstr ""
125
  msgid "Addons"
126
  msgstr ""
127
 
128
- #: ../translatepress/includes/class-translation-manager.php:421
129
- msgid "Translate Page"
130
  msgstr ""
131
 
132
- #: ../translatepress/includes/class-translation-manager.php:440
133
- msgid "Settings"
134
  msgstr ""
135
 
136
- #: ../translatepress/includes/class-translation-manager.php:880
137
- msgid "Security check"
138
  msgstr ""
139
 
140
- #: ../translatepress/includes/class-translation-render.php:133
 
 
 
 
 
 
 
 
141
  msgid "Meta Information"
142
  msgstr ""
143
 
144
- #: ../translatepress/includes/class-translation-render.php:142
145
  msgid "String List"
146
  msgstr ""
147
 
148
- #: ../translatepress/includes/class-translation-render.php:159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  msgid "Description"
150
  msgstr ""
151
 
152
- #: ../translatepress/includes/class-translation-render.php:165
153
  msgid "OG Title"
154
  msgstr ""
155
 
156
- #: ../translatepress/includes/class-translation-render.php:171
157
  msgid "OG Site Name"
158
  msgstr ""
159
 
160
- #: ../translatepress/includes/class-translation-render.php:177
161
  msgid "OG Description"
162
  msgstr ""
163
 
164
- #: ../translatepress/includes/class-translation-render.php:183
165
  msgid "Twitter Title"
166
  msgstr ""
167
 
168
- #: ../translatepress/includes/class-translation-render.php:189
169
  msgid "Twitter Description"
170
  msgstr ""
171
 
172
- #: ../translatepress/includes/class-translation-render.php:195
173
  msgid "Post Slug"
174
  msgstr ""
175
 
176
- #: ../translatepress/includes/class-translation-render.php:199
177
  msgid "Page Title"
178
  msgstr ""
179
 
@@ -409,14 +440,14 @@ msgstr ""
409
  msgid "Learn More"
410
  msgstr ""
411
 
412
- #: includes/class-translator-accounts.php:119
413
  msgid " TranslatePress Settings"
414
  msgstr ""
415
 
416
- #: includes/class-translator-accounts.php:123, includes/class-translator-accounts.php:124
417
  msgid "Translator"
418
  msgstr ""
419
 
420
- #: includes/class-translator-accounts.php:128
421
  msgid "Allow this user to translate the website."
422
  msgstr ""
21
  msgid "Limit this menu item to the following languages"
22
  msgstr ""
23
 
24
+ #: ../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, 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:17, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:4
25
  msgid "TranslatePress Settings"
26
  msgstr ""
27
 
28
+ #: ../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, partials/license-settings-page.php:10, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:10
29
  msgid "License Key"
30
  msgstr ""
31
 
32
+ #: ../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, partials/license-settings-page.php:15, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:15
33
  msgid "Enter your license key."
34
  msgstr ""
35
 
36
+ #: ../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, partials/license-settings-page.php:22, 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
37
  msgid "Activate License"
38
  msgstr ""
39
 
40
+ #: ../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, partials/license-settings-page.php:28, ../trp-add-on-translator-accounts-add-on/partials/license-settings-page.php:28
41
  msgid "Deactivate License"
42
  msgstr ""
43
 
81
  msgid "You are not using a permalink structure! Please <a href=\"%s\">enable</a> one or install our <a href=\"%s\">\"Language by GET parameter\"</a> addon so TranslatePress can function properly."
82
  msgstr ""
83
 
84
+ #: ../translatepress/includes/class-plugin-notices.php:282, ../translatepress/includes/class-plugin-notices.php:293
85
  msgid "Dismiss this notice."
86
  msgstr ""
87
 
88
+ #: ../translatepress/includes/class-plugin-notices.php:291
89
+ msgid "You can now translate several strings at once by merging them together. Find out more about these translation blocks in <a href=\"https://translatepress.com/docs/translation-editor/#translation-blocks\" >our documentation.</a>."
90
+ msgstr ""
91
+
92
  #: ../translatepress/includes/class-settings.php:25
93
  msgid "Full Language Names"
94
  msgstr ""
117
  msgid "General"
118
  msgstr ""
119
 
120
+ #: ../translatepress/includes/class-settings.php:397, ../translatepress/includes/class-translation-manager.php:624
121
  msgid "Translate Site"
122
  msgstr ""
123
 
129
  msgid "Addons"
130
  msgstr ""
131
 
132
+ #: ../translatepress/includes/class-translation-manager.php:79
133
+ msgid "Translate"
134
  msgstr ""
135
 
136
+ #: ../translatepress/includes/class-translation-manager.php:80
137
+ msgid "Translate entire block element"
138
  msgstr ""
139
 
140
+ #: ../translatepress/includes/class-translation-manager.php:81
141
+ msgid "Split block to translate strings individually"
142
  msgstr ""
143
 
144
+ #: ../translatepress/includes/class-translation-manager.php:82
145
+ msgid "Translation block"
146
+ msgstr ""
147
+
148
+ #: ../translatepress/includes/class-translation-manager.php:83
149
+ msgid "Are you sure you want to split this phrase into smaller pieces?"
150
+ msgstr ""
151
+
152
+ #: ../translatepress/includes/class-translation-manager.php:84
153
  msgid "Meta Information"
154
  msgstr ""
155
 
156
+ #: ../translatepress/includes/class-translation-manager.php:85
157
  msgid "String List"
158
  msgstr ""
159
 
160
+ #: ../translatepress/includes/class-translation-manager.php:86
161
+ msgid "Dynamic Added Strings"
162
+ msgstr ""
163
+
164
+ #: ../translatepress/includes/class-translation-manager.php:87, ../translatepress/includes/class-translation-manager.php:88, ../translatepress/includes/class-translation-manager.php:89, ../translatepress/includes/class-translation-manager.php:90, ../translatepress/includes/class-translation-manager.php:91
165
+ msgstr ""
166
+
167
+ #: ../translatepress/includes/class-translation-manager.php:636
168
+ msgid "Translate Page"
169
+ msgstr ""
170
+
171
+ #: ../translatepress/includes/class-translation-manager.php:655
172
+ msgid "Settings"
173
+ msgstr ""
174
+
175
+ #: ../translatepress/includes/class-translation-manager.php:1095
176
+ msgid "Security check"
177
+ msgstr ""
178
+
179
+ #: ../translatepress/includes/class-translation-render.php:166
180
  msgid "Description"
181
  msgstr ""
182
 
183
+ #: ../translatepress/includes/class-translation-render.php:172
184
  msgid "OG Title"
185
  msgstr ""
186
 
187
+ #: ../translatepress/includes/class-translation-render.php:178
188
  msgid "OG Site Name"
189
  msgstr ""
190
 
191
+ #: ../translatepress/includes/class-translation-render.php:184
192
  msgid "OG Description"
193
  msgstr ""
194
 
195
+ #: ../translatepress/includes/class-translation-render.php:190
196
  msgid "Twitter Title"
197
  msgstr ""
198
 
199
+ #: ../translatepress/includes/class-translation-render.php:196
200
  msgid "Twitter Description"
201
  msgstr ""
202
 
203
+ #: ../translatepress/includes/class-translation-render.php:202
204
  msgid "Post Slug"
205
  msgstr ""
206
 
207
+ #: ../translatepress/includes/class-translation-render.php:206
208
  msgid "Page Title"
209
  msgstr ""
210
 
440
  msgid "Learn More"
441
  msgstr ""
442
 
443
+ #: ../trp-add-on-translator-accounts-add-on/includes/class-translator-accounts.php:119
444
  msgid " TranslatePress Settings"
445
  msgstr ""
446
 
447
+ #: ../trp-add-on-translator-accounts-add-on/includes/class-translator-accounts.php:123, ../trp-add-on-translator-accounts-add-on/includes/class-translator-accounts.php:124
448
  msgid "Translator"
449
  msgstr ""
450
 
451
+ #: ../trp-add-on-translator-accounts-add-on/includes/class-translator-accounts.php:128
452
  msgid "Allow this user to translate the website."
453
  msgstr ""
readme.txt CHANGED
@@ -4,7 +4,7 @@ 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: 4.9.5
7
- Stable tag: 1.2.1
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -28,11 +28,13 @@ https://www.youtube.com/watch?v=pUlYisvBm8g
28
  * Support for both manual and automatic translation (via Google Translate)
29
  * Ability to translate dynamic strings (gettext) added by WordPress, plugins and themes.
30
  * Integrates with Google Translate, allowing you to set up Automatic Translation using your own Google API key.
31
- * Translate larger html blocks using the css class **translation-block**. `<p class="translation-block">Translate <em>everything</em> inside</p>`
 
32
  * Place language switchers anywhere using shortcode **[language-switcher]**, WP menu item or as a floating dropdown.
33
  * Editorial control allowing you to publish your language only when all your translations are done
34
  * Conditional display content shortcode based on language [trp_language language="en_US"] English content only [/trp_language]
35
  * Possibility to edit gettext strings from themes and plugins from english to english, without adding another language. Basically a string-replace functionality.
 
36
 
37
  Note: this plugin uses the Google Translation API to translate the strings on your site. This feature can be enabled or disabled according to your preferences.
38
 
@@ -115,6 +117,13 @@ For more information please check out [TranslatePress documentation](https://tra
115
  6. Menu Language Switcher
116
 
117
  == Changelog ==
 
 
 
 
 
 
 
118
  = 1.2.1 =
119
  * Extra css for the floater images so they don't brake the line in certain themes
120
  * Fixed compatibility issue with Woocommerce cart widget
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: 4.9.5
7
+ Stable tag: 1.2.2
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
28
  * Support for both manual and automatic translation (via Google Translate)
29
  * Ability to translate dynamic strings (gettext) added by WordPress, plugins and themes.
30
  * Integrates with Google Translate, allowing you to set up Automatic Translation using your own Google API key.
31
+ * Translate larger html blocks by merging strings into translation blocks.
32
+ * Select specific html blocks for translation using the css class **translation-block**. `<p class="translation-block">Translate <em>everything</em> inside</p>`
33
  * Place language switchers anywhere using shortcode **[language-switcher]**, WP menu item or as a floating dropdown.
34
  * Editorial control allowing you to publish your language only when all your translations are done
35
  * Conditional display content shortcode based on language [trp_language language="en_US"] English content only [/trp_language]
36
  * Possibility to edit gettext strings from themes and plugins from english to english, without adding another language. Basically a string-replace functionality.
37
+ * Translation Block feature in which you can translate multiple html elements together
38
 
39
  Note: this plugin uses the Google Translation API to translate the strings on your site. This feature can be enabled or disabled according to your preferences.
40
 
117
  6. Menu Language Switcher
118
 
119
  == Changelog ==
120
+ = 1.2.2 =
121
+ * Added Translation Block feature in which you can translate multiple html elements together
122
+ * Improvement: make it possible for the SEO Addon to automatically translate page slugs using Google Translate
123
+ * Fix: using the shortcode language switcher added #trpprocessurl to the end of the url
124
+ * Fix: changing languages from a secondary language gave 404 page when the page slug was translated
125
+ * Fix: submitting a form from one page to another directed the user to the default language. Now if Force Custom Language Links is enabled the user gets directed to the correct url
126
+
127
  = 1.2.1 =
128
  * Extra css for the floater images so they don't brake the line in certain themes
129
  * Fixed compatibility issue with Woocommerce cart widget