Automatic Translate Addon For Loco Translate - Version 1.4.1

Version Description

Download this release

Release Info

Developer Narinder singh
Plugin Icon 128x128 Automatic Translate Addon For Loco Translate
Version 1.4.1
Comparing to
See all releases

Code changes from version 1.3.2 to 1.4.1

assets/css/atlt-admin-feedback-notice.css CHANGED
@@ -47,4 +47,4 @@
47
  #atlt-dialog .atlt-ok.button{
48
  margin: 0 auto;
49
  display: block;
50
- }
47
  #atlt-dialog .atlt-ok.button{
48
  margin: 0 auto;
49
  display: block;
50
+ }
assets/images/preloader.gif ADDED
Binary file
assets/js/loco-js-editor.js DELETED
@@ -1,915 +0,0 @@
1
- /**
2
- * Script for PO file editor pages
3
- */
4
- !function( window, $ ){
5
- var TotalCharacters=0;
6
- var HtmlStrings = 0;
7
- var requestChars=0;
8
- let event = document.createEvent('event');
9
- event.initEvent('atlt_translated');
10
- // custom popup message box
11
- let popup_html = '<div id="atlt-dialog-container"><div style="display:none;" id="atlt-dialog" title="Automatic Translation Progress"><p><span class="translated-label">Translated</span> <span class="translated-text">0%</span></p><div class="atlt-progress-bar-track"><div class="atlt-progress-bar-value"></div></div><div class="atlt-final-message"></div><button style="display:none;" class="atlt-ok button button-primary">OK</button></div></div>';
12
-
13
- $("body").append( popup_html );
14
-
15
- $('#atlt-dialog .atlt-ok.button').on('click',function(){
16
- // hide dialog container by finding main parent DOM
17
- $("#atlt-dialog").parent('.ui-dialog').hide();
18
- });
19
-
20
- var loco = window.locoScope,
21
- conf = window.locoConf,
22
- syncParams = null,
23
- saveParams = null,
24
-
25
-
26
- // UI translation
27
- translator = loco.l10n,
28
- sprintf = loco.string.sprintf,
29
-
30
- // PO file data
31
- locale = conf.locale,
32
- messages = loco.po.init( locale ).wrap( conf.powrap ),
33
- template = ! locale,
34
-
35
- // form containing action buttons
36
- elForm = document.getElementById('loco-actions'),
37
- filePath = conf.popath,
38
- syncPath = conf.potpath,
39
-
40
- // file system connect when file is locked
41
- elFilesys = document.getElementById('loco-fs'),
42
- fsConnect = elFilesys && loco.fs.init( elFilesys ),
43
-
44
- // prevent all write operations if readonly mode
45
- readonly = conf.readonly,
46
- editable = ! readonly,
47
-
48
- // Editor components
49
- editor,
50
- saveButton,
51
- innerDiv = document.getElementById('loco-editor-inner');
52
-
53
- /**
54
- *
55
- */
56
- function doSyncAction( callback ){
57
- function onSuccess( result ){
58
- var info = [],
59
- doc = messages,
60
- exp = result.po,
61
- src = result.pot,
62
- pot = loco.po.init().load( exp ),
63
- done = doc.merge( pot ),
64
- nadd = done.add.length,
65
- ndel = done.del.length,
66
- t = translator;
67
- // reload even if unchanged, cos indexes could be off
68
- editor.load( doc );
69
- // Show summary
70
- if( nadd || ndel ){
71
- if( src ){
72
- // Translators: Where %s is the name of the POT template file. Message appears after sync
73
- info.push( sprintf( t._('Merged from %s'), src ) );
74
- }
75
- else {
76
- // Translators: Message appears after sync operation
77
- info.push( t._('Merged from source code') );
78
- }
79
- // Translators: Summary of new strings after running in-editor Sync
80
- nadd && info.push( sprintf( t._n('1 new string added','%s new strings added', nadd ), nadd ) );
81
- // Translators: Summary of existing strings that no longer exist after running in-editor Sync
82
- ndel && info.push( sprintf( t._n('1 obsolete string removed','%s obsolete strings removed', ndel ), ndel ) );
83
- // editor thinks it's saved, but we want the UI to appear otherwise
84
- $(innerDiv).trigger('poUnsaved',[]);
85
- updateStatus();
86
- // debug info in lieu of proper merge confirmation:
87
- window.console && debugMerge( console, done );
88
- }
89
- else if( src ){
90
- // Translators: Message appears after sync operation when nothing has changed. %s refers to a POT file.
91
- info.push( sprintf( t._('Already up to date with %s'), src ) );
92
- }
93
- else {
94
- // Translators: Message appears after sync operation when nothing has changed
95
- info.push( t._('Already up to date with source code') );
96
- }
97
- loco.notices.success( info.join('. ') );
98
- $(innerDiv).trigger('poMerge',[result]);
99
- // done sync
100
- callback && callback();
101
- }
102
- loco.ajax.post( 'sync', syncParams, onSuccess, callback );
103
- }
104
-
105
- function debugMerge( console, result ){
106
- var i = -1, t = result.add.length;
107
- while( ++i < t ){
108
- console.log(' + '+result.add[i].source() );
109
- }
110
- i = -1, t = result.del.length;
111
- while( ++i < t ){
112
- console.log(' - '+result.del[i].source() );
113
- }
114
- }
115
-
116
- /**
117
- * Post full editor contents to "posave" endpoint
118
- */
119
- function doSaveAction( callback ){
120
- function onSuccess( result ){
121
- callback && callback();
122
- editor.save( true );
123
- // Update saved time update
124
- $('#loco-po-modified').text( result.datetime||'[datetime error]' );
125
- }
126
- saveParams.locale = String( messages.locale() || '' );
127
- if( fsConnect ){
128
- fsConnect.applyCreds( saveParams );
129
- }
130
- // adding PO source last for easier debugging in network inspector
131
- saveParams.data = String( messages );
132
- loco.ajax.post( 'save', saveParams, onSuccess, callback );
133
- }
134
-
135
-
136
- function saveIfDirty(){
137
- editor.dirty && doSaveAction();
138
- }
139
-
140
-
141
-
142
- function onUnloadWarning(){
143
- // Translators: Warning appears when user tries to refresh or navigate away when editor work is unsaved
144
- return translator._("Your changes will be lost if you continue without saving");
145
- }
146
-
147
-
148
-
149
- function registerSaveButton( button ){
150
- saveButton = button;
151
- // enables and disable according to save/unsave events
152
- editor
153
- .on('poUnsaved', function(){
154
- enable();
155
- $(button).addClass( 'button-primary loco-flagged' );
156
- } )
157
- .on('poSave', function(){
158
- disable();
159
- $(button).removeClass( 'button-primary loco-flagged' );
160
- } )
161
- ;
162
- function disable(){
163
- button.disabled = true;
164
- }
165
- function enable(){
166
- button.disabled = false;
167
- }
168
- function think(){
169
- disable();
170
- $(button).addClass('loco-loading');
171
- }
172
- function unthink(){
173
- enable();
174
- $(button).removeClass('loco-loading');
175
- }
176
- saveParams = $.extend( { path: filePath }, conf.project||{} );
177
-
178
- $(button).click( function(event){
179
- event.preventDefault();
180
- think();
181
- doSaveAction( unthink );
182
- return false;
183
- } );
184
- return true;
185
- };
186
-
187
-
188
-
189
- function registerSyncButton( button ){
190
- var project = conf.project;
191
- if( project ){
192
- function disable(){
193
- button.disabled = true;
194
- }
195
- function enable(){
196
- button.disabled = false;
197
- }
198
- function think(){
199
- disable();
200
- $(button).addClass('loco-loading');
201
- }
202
- function unthink(){
203
- enable();
204
- $(button).removeClass('loco-loading');
205
- }
206
- // Only permit sync when document is saved
207
- editor
208
- .on('poUnsaved', function(){
209
- disable();
210
- } )
211
- .on('poSave', function(){
212
- enable();
213
- } )
214
- ;
215
- // params for sync end point
216
- syncParams = {
217
- bundle: project.bundle,
218
- domain: project.domain,
219
- type: template ? 'pot' : 'po',
220
- sync: syncPath||''
221
- };
222
- // enable syncing on button click
223
- $(button)
224
- .click( function(event){
225
- event.preventDefault();
226
- think();
227
- doSyncAction( unthink );
228
- return false;
229
- } )
230
- //.attr('title', syncPath ? sprintf( translator._('Update from %s'), syncPath ) : translator._('Update from source code') )
231
- ;
232
- enable();
233
- }
234
- return true;
235
- }
236
-
237
-
238
-
239
- function registerFuzzyButton( button ){
240
- var toggled = false,
241
- enabled = false
242
- ;
243
- function redraw( message, state ){
244
- // fuzziness only makes sense when top-level string is translated
245
- var allowed = message && message.translated(0) || false;
246
- if( enabled !== allowed ){
247
- button.disabled = ! allowed;
248
- enabled = allowed;
249
- }
250
- // toggle on/off according to new fuzziness
251
- if( state !== toggled ){
252
- $(button)[ state ? 'addClass' : 'removeClass' ]('inverted');
253
- toggled = state;
254
- }
255
- }
256
- // state changes depending on whether an asset is selected and is fuzzy
257
- editor
258
- .on('poSelected', function( event, message ){
259
- redraw( message, message && message.fuzzy() || false );
260
- } )
261
- .on( 'poEmpty', function( event, blank, message, pluralIndex ){
262
- if( 0 === pluralIndex && blank === enabled ){
263
- redraw( message, toggled );
264
- }
265
- } )
266
- .on( 'poFuzzy', function( event, message, newState ){
267
- redraw( message, newState );
268
- } )
269
- ;
270
- // click toggles current state
271
- $(button).click( function( event ){
272
- event.preventDefault();
273
- editor.fuzzy( ! editor.fuzzy() );
274
- return false;
275
- } );
276
- return true;
277
- };
278
-
279
-
280
-
281
- function registerRevertButton( button ){
282
- // No need for revert when document is saved
283
- editor
284
- .on('poUnsaved', function(){
285
- button.disabled = false;
286
- } )
287
- .on('poSave', function(){
288
- button.disabled = true;
289
- } )
290
- ;
291
- // handling unsaved state prompt with onbeforeunload, see below
292
- $(button).click( function( event ){
293
- event.preventDefault();
294
- location.reload();
295
- return false;
296
- } );
297
- return true;
298
- };
299
-
300
- function registerInvisiblesButton( button ){
301
- var $button = $(button);
302
- button.disabled = false;
303
- editor.on('poInvs', function( event, state ){
304
- $button[ state ? 'addClass' : 'removeClass' ]('inverted');
305
- });
306
- $button.click( function( event ){
307
- event.preventDefault();
308
- editor.setInvs( ! editor.getInvs() );
309
- return false;
310
- } );
311
- locoScope.tooltip.init($button);
312
- return true;
313
- }
314
-
315
- function registerCodeviewButton( button ){
316
- var $button = $(button);
317
- button.disabled = false;
318
- $button.click( function(event){
319
- event.preventDefault();
320
- var state = ! editor.getMono();
321
- editor.setMono( state );
322
- $button[ state ? 'addClass' : 'removeClass' ]('inverted');
323
- return false;
324
- } );
325
- locoScope.tooltip.init($button);
326
- return true;
327
- };
328
-
329
- function registerAddButton( button ){
330
- button.disabled = false;
331
- $(button).click( function( event ){
332
- event.preventDefault();
333
- // Need a placeholder guaranteed to be unique for new items
334
- var i = 1, baseid, msgid, regex = /(\d+)$/;
335
- msgid = baseid = 'New message';
336
- while( messages.get( msgid ) ){
337
- i = regex.exec(msgid) ? Math.max(i,RegExp.$1) : i;
338
- msgid = baseid+' '+( ++i );
339
- }
340
- editor.add( msgid );
341
- return false;
342
- } );
343
- return true;
344
- };
345
-
346
- function registerDelButton( button ){
347
- button.disabled = false;
348
- $(button).click( function(event){
349
- event.preventDefault();
350
- editor.del();
351
- return false;
352
- } );
353
- return true;
354
- };
355
-
356
- function registerDownloadButton( button, id ){
357
- button.disabled = false;
358
- $(button).click( function( event ){
359
- var form = button.form,
360
- path = filePath;
361
- // swap out path
362
- if( 'binary' === id ){
363
- path = path.replace(/\.po$/,'.mo');
364
- }
365
- form.path.value = path;
366
- form.source.value = messages.toString();
367
- // allow form to submit
368
- return true;
369
- } );
370
- return true;
371
- }
372
-
373
-
374
- // event handler that stops dead
375
- function noop( event ){
376
- event.preventDefault();
377
- return false;
378
- }
379
-
380
-
381
- /*/ dummy function for enabling buttons that do nothing (or do something inherently)
382
- function registerNoopButton( button ){
383
- return true;
384
- }*/
385
-
386
-
387
-
388
- /**
389
- * Update status message above editor.
390
- * This is dynamic version of PHP Loco_gettext_Metadata::getProgressSummary
391
- * TODO implement progress bar, not just text.
392
- */
393
- function updateStatus(){
394
- var t = translator,
395
- stats = editor.stats(),
396
- total = stats.t,
397
- fuzzy = stats.f,
398
- empty = stats.u,
399
- // Translators: Shows total string count at top of editor
400
- stext = sprintf( t._n('1 string','%s strings',total ), total.format(0) ),
401
- extra = [];
402
- if( locale ){
403
- // Translators: Shows percentage translated at top of editor
404
- stext = sprintf( t._('%s%% translated'), stats.p.replace('%','') ) +', '+ stext;
405
- // Translators: Shows number of fuzzy strings at top of editor
406
- fuzzy && extra.push( sprintf( t._('%s fuzzy'), fuzzy.format(0) ) );
407
- // Translators: Shows number of untranslated strings at top of editor
408
- empty && extra.push( sprintf( t._('%s untranslated'), empty.format(0) ) );
409
- if( extra.length ){
410
- stext += ' ('+extra.join(', ')+')';
411
- }
412
- }
413
- $('#loco-po-status').text( stext );
414
- if( typeof window.locoEditorStats == 'undefined'){
415
- window.locoEditorStats = {totalWords:stats.t, totalTranslated:stats.p} ;
416
- }else{
417
- window.locoEditorStats.totalWords = stats.t;
418
- window.locoEditorStats.totalTranslated = stats.p;
419
- }
420
-
421
- }
422
-
423
-
424
-
425
- /**
426
- * Enable text filtering
427
- */
428
- function initSearchFilter( elSearch ){
429
- editor.searchable( loco.fulltext.init() );
430
- // prep search text field
431
- elSearch.disabled = false;
432
- elSearch.value = '';
433
- function showValidFilter( numFound ){
434
- $(elSearch.parentNode)[ numFound || null == numFound ? 'removeClass' : 'addClass' ]('invalid');
435
- }
436
- var listener = loco.watchtext( elSearch, function( value ){
437
- var numFound = editor.filter( value, true );
438
- showValidFilter( numFound );
439
- } );
440
- editor
441
- .on( 'poFilter', function( event, value, numFound ){
442
- listener.val( value||'' );
443
- showValidFilter( numFound );
444
- } )
445
- .on( 'poMerge', function( event, result ){
446
- var value = listener.val();
447
- value && editor.filter( value );
448
- } )
449
- ;
450
- }
451
-
452
-
453
-
454
- // resize function fits editor to screen, accounting for headroom and touching bottom of screen.
455
- var resize = function(){
456
- function top( el, ancestor ){
457
- var y = el.offsetTop||0;
458
- while( ( el = el.offsetParent ) && el !== ancestor ){
459
- y += el.offsetTop||0;
460
- }
461
- return y;
462
- }
463
- var fixHeight,
464
- minHeight = parseInt($(innerDiv).css('min-height')||0)
465
- ;
466
- return function(){
467
- var padBottom = 20,
468
- topBanner = top( innerDiv, document.body ),
469
- winHeight = window.innerHeight,
470
- setHeight = Math.max( minHeight, winHeight - topBanner - padBottom )
471
- ;
472
- if( fixHeight !== setHeight ){
473
- innerDiv.style.height = String(setHeight)+'px';
474
- fixHeight = setHeight;
475
- }
476
- };
477
- }();
478
-
479
- // ensure outer resize is handled before editor's internal resize
480
- resize();
481
- $(window).resize( resize );
482
-
483
- // initialize editor
484
- innerDiv.innerHTML = '';
485
- editor = loco.po.ed
486
- .init( innerDiv )
487
- .localise( translator )
488
- ;
489
- loco.po.kbd
490
- .init( editor )
491
- .add( 'save', saveIfDirty )
492
- .enable('copy','clear','enter','next','prev','fuzzy','save','invis')
493
- ;
494
-
495
- // initialize toolbar button actions
496
- var buttons = {
497
- // help: registerNoopButton,
498
- save: editable && registerSaveButton,
499
- sync: editable && registerSyncButton,
500
- revert: registerRevertButton,
501
- // editor mode togglers
502
- invs: registerInvisiblesButton,
503
- code: registerCodeviewButton,
504
- // downloads / post-throughs
505
- source: registerDownloadButton,
506
- binary: template ? null : registerDownloadButton
507
- };
508
- // POT only
509
- if( template ){
510
- buttons.add = editable && registerAddButton;
511
- buttons.del = editable && registerDelButton;
512
- }
513
- // PO only
514
- else {
515
- buttons.fuzzy = registerFuzzyButton;
516
- };
517
- $('#loco-toolbar').find('button').each( function(i,el){
518
- var id = el.getAttribute('data-loco'), register = buttons[id];
519
- register && register(el,id) || $(el).hide();
520
- } );
521
-
522
- // disable submit on dummy form
523
- $(elForm).submit( noop );
524
-
525
- // enable text filtering
526
- initSearchFilter( document.getElementById('loco-search') );
527
-
528
- // editor event behaviours
529
- editor
530
- .on('poUnsaved', function(){
531
- window.onbeforeunload = onUnloadWarning;
532
- } )
533
- .on('poSave', function(){
534
- updateStatus();
535
- window.onbeforeunload = null;
536
- } )
537
- .on( 'poUpdate', updateStatus );
538
- ;
539
-
540
- // load raw message data
541
- messages.load( conf.podata );
542
-
543
- // ready to render editor
544
- editor.load( messages );
545
-
546
- // locale should be cast to full object once set in editor
547
- if( locale = editor.targetLocale ){
548
- locale.isRTL() && $(innerDiv).addClass('trg-rtl');
549
- }
550
- // enable template mode when no target locale
551
- else {
552
- editor.unlock();
553
- }
554
-
555
-
556
- /*
557
- |--------------------------------------------------------------------------
558
- | Auto Translator Custom Code
559
- |--------------------------------------------------------------------------
560
- */
561
- //encode URL query string
562
- function createEncodedString(allStringText){
563
- const queryString=allStringText.map((item)=>{
564
- return "&text="+ encodeURIComponent(item.source);
565
- }).join(",");
566
-
567
- return queryString;
568
- }
569
-
570
- function validLicenseKey(licenseKey){
571
- return licenseKey;
572
- }
573
-
574
- // auto traslator button in editor
575
- function addAutoTranslationBtn(){
576
- if($("#loco-toolbar").find("#cool-auto-translate-btn").length>0){
577
- $("#loco-toolbar").find("#cool-auto-translate-btn").remove();
578
- }
579
- const disabledBtn='<fieldset><button title="Buy PRO." id="cool-auto-translate-btn" disabled class="button has-icon icon-translate">Auto Translate</button><div style="max-width:320px; display:inline-block;margin-top: 4px;"><span style="font-size:12px;display:inline-block;margin-left:8px;">You have exceeded free translation limit. In order to extend the limit - <a target="_blank" style="font-size:14px;display:inline-block;margin-left:8px;" target="_blank" href="https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/">Buy Premium License</a></span></div></fieldset>';
580
- const apiKey=ATLT["api_key"]["atlt_api-key"];
581
- const userType=ATLT["info"].type;
582
- const allowed=ATLT["info"].allowed;
583
- const today=ATLT["info"].today;
584
- const total=ATLT["info"].total;
585
- if( ATLT == '' || ATLT["api_key"] == '' || apiKey=='' ){
586
- $("#loco-toolbar").find("#loco-actions")
587
- .append('<fieldset><button title="Add API key to enable this feature." id="cool-auto-translate-btn" disabled class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="https://tech.yandex.com/translate/">Get Free API Key</a></fieldset>');
588
- return;
589
- }else if( allowed=="no" && userType=='free'){
590
- $("#loco-toolbar").find("#loco-actions")
591
- .append(disabledBtn);
592
- return;
593
- }else if(today!==undefined && parseInt(today)>300000 && userType=='free'){
594
- $("#loco-toolbar").find("#loco-actions")
595
- .append(disabledBtn);
596
- return;
597
- }else if(total!==undefined && parseInt(total)>10000000
598
- && userType=='free'){
599
- $("#loco-toolbar").find("#loco-actions")
600
- .append(disabledBtn);
601
- return;
602
- }else if( window.locoEditorStats.totalTranslated != "100%" && window.locoEditorStats.totalWords > 0 ){
603
- if(userType=='pro' && validLicenseKey(ATLT["info"]["licenseKey"])){
604
- $("#loco-toolbar").find("#loco-actions")
605
- .append('<fieldset><button id="cool-auto-translate-btn" class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="http://translate.yandex.com/">Powered by Yandex.Translate</a></fieldset>');
606
- }else{
607
- if(today==undefined){
608
- var todayChars=100000;
609
- }else{
610
- var todayChars=100000-parseInt(today);
611
- }
612
- var totalChars=3000000-parseInt(total);
613
- var freeBtn='<fieldset><button data-today-limit="'+todayChars+'" data-total-limit="'+totalChars+'" id="cool-auto-translate-btn" class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="http://translate.yandex.com/">Powered by Yandex.Translate</a></fieldset>';
614
- $("#loco-toolbar").find("#loco-actions").append(freeBtn);
615
- }
616
- } else if( window.locoEditorStats.totalWords == 0){
617
- return;
618
- } else {
619
- $("#loco-toolbar").find("#loco-actions")
620
- .append('<fieldset><button id="cool-auto-translate-btn" class="button has-icon icon-translate" disabled>Translated</button></fieldset>');
621
- }
622
- }
623
- $(document).ready(function(){
624
- const locoRawData=conf.podata;
625
- if(locoRawData!=undefined && locoRawData.length>0 ){
626
- // called auto traslate button
627
- addAutoTranslationBtn();
628
- }
629
- // main translate handler
630
- let dataObj = {};
631
- $(document)
632
- // Bind translate function to translate button
633
- .on("click", "#cool-auto-translate-btn", function() {
634
- var thisBtn=$(this);
635
- var todayLimit= thisBtn.data('today-limit');
636
- var totalLimit= thisBtn.data('total-limit');
637
- // const targetLang=conf.locale.lang;
638
- const apiKey = ATLT["api_key"]["atlt_api-key"];
639
-
640
- if(locoRawData!=undefined && locoRawData.length>0 && apiKey!='' ){
641
- let untranslatedAllString=locoRawData.filter((item,index)=>{
642
- // if(item.target===undefined || item.target=="" && savedIndex<=90){
643
- if( (item.target===undefined || item.target=="") && (item.source).includes('</') == false && (item.source).includes('/>') == false && (item.source).includes('#') == false ){
644
- return true;
645
- }else{
646
- HtmlStrings++;
647
- }
648
- });
649
- // remove links from string
650
- let untranslatedTextArr=untranslatedAllString.filter((item,index)=>{
651
- if(ValidURL(item.source)){
652
- return false;
653
- }else{
654
- return true;
655
- }
656
- });
657
-
658
- if (untranslatedTextArr !== null) {
659
- var countChars=0;
660
- untranslatedTextArr.map(function(index){
661
- countChars +=index.source.length;
662
- });
663
-
664
- if(countChars>parseInt(todayLimit)){
665
- alert('Your translation string are larger then available free limit.In order to extend limit Buy Pro license key');
666
- }else{
667
- thisBtn.text('...Translating');
668
-
669
- dataObj = {
670
- textToTranslateArr:untranslatedTextArr,
671
- thisBtn:$(this),
672
- };
673
-
674
- window.locoEditorStats.dataObj = dataObj;
675
- jQuery(document).trigger('atlt_translated');
676
-
677
- // load raw message data
678
-
679
- } //
680
-
681
- } // else close
682
- }
683
-
684
- });
685
-
686
- });
687
-
688
- jQuery(document).on('atlt_translated',function(){
689
- let textToTranslate = window.locoEditorStats.dataObj.textToTranslateArr
690
- let totalTranslated = window.locoEditorStats.totalTranslated
691
- const apiKey = ATLT["api_key"]["atlt_api-key"];
692
- const nonce=ATLT["nonce"];
693
- const saveBtn=$('[data-loco="save"]');
694
- const orignalstringArr=conf.podata;
695
- const targetLang=conf['locale']["lang"];
696
- let indexRequest = 50;
697
- if( ATLT.api_key['atlt_index-per-request'] != "" && typeof ATLT.api_key['atlt_index-per-request'] != "undefined" ){
698
- indexRequest = ATLT.api_key['atlt_index-per-request'];
699
- }
700
-
701
- if( typeof textToTranslate == "object" && textToTranslate.length >= 1 ){
702
- let translationO = {
703
- textToTranslateArr:textToTranslate.slice(indexRequest),
704
- thisBtn:window.locoEditorStats.dataObj.thisBtn,
705
- };
706
- window.locoEditorStats.dataObj = translationO;
707
-
708
- // partial data request
709
- let data = {
710
- sourceLang:'en',
711
- targetLang:targetLang,
712
- textToTranslateArr:textToTranslate.slice(0,indexRequest),
713
- orginalArr:orignalstringArr,
714
- apiKey:apiKey,
715
- thisBtn:window.locoEditorStats.dataObj.thisBtn,
716
- saveBtn:saveBtn,
717
- nonce:nonce
718
- };
719
-
720
- textToTranslate.slice(0,indexRequest).map(function(value,index){
721
- TotalCharacters += (value.source).length;
722
- requestChars+=(value.source).length;
723
- })
724
-
725
- $('#atlt-dialog').dialog({width:320});
726
-
727
- atlt_translate(data);
728
- }else if( HtmlStrings >= 1){
729
- alert('Remaining HTML strings can not be auto translate!');
730
- window.location.reload();
731
- }
732
- })
733
-
734
- // Translate
735
- function atlt_translate(data) {
736
-
737
- atlt_ajax_translation_request(data, "POST").success(function(
738
- resp
739
- ) {
740
- const json_resp = JSON.parse(resp);
741
- if( json_resp == false ){
742
- alert('Unable to make request to the server at the moment. Try again later.');
743
- }else if( typeof json_resp['code'] === undefined || json_resp['code'] != 200 ){
744
- let error = '';
745
- switch(json_resp['code']){
746
- case 401:
747
- error = 'Yendex API Key is invalid!';
748
- break;
749
- case 402:
750
- error = 'Provided Yendex API Key has been blocked!';
751
- break;
752
- case 404:
753
- error = 'Exceeded the daily limit for Yendex API on the amount of translated text.';
754
- break;
755
- case 422:
756
- error = 'The text cannot be translated by Yendex API.';
757
- break;
758
- case 501:
759
- error = 'Yendex API does not support the specified translation direction.';
760
- break;
761
- default:
762
- error = json_resp['message'];
763
- }
764
- if( error != '' && (data.textToTranslateArr).length != 0 ){
765
- $('#atlt-dialog .atlt-final-message').html("<strong>"+error+"</strong>");
766
- $('#atlt-dialog .atlt-ok.button').show();
767
- data.thisBtn.text('Translation');
768
- data.thisBtn.attr('disabled','disabled');
769
- }
770
- return;
771
- }
772
-
773
- let totalTranslated = window.locoEditorStats.totalTranslated;
774
-
775
- var response = json_resp['text'];
776
-
777
- if(response!==undefined){
778
- for(i=0;i< response.length;i++){
779
- var text = response[i];
780
- if( data.textToTranslateArr[i] === undefined ){
781
- break;
782
- }
783
- data.textToTranslateArr[i].target = text ;
784
-
785
- }
786
- }
787
- var mergeTranslatedText = atlt_arrayUnique(data['textToTranslateArr'].concat(data['orginalArr']) ),
788
- textForTranslation = data['textToTranslateArr'],
789
- Emptytargets = []
790
- for(var x=0; x<textForTranslation.length;++x){
791
- if(textForTranslation[x].target !='' ){
792
- Emptytargets[x]=textForTranslation[x].source;
793
- }
794
- }
795
-
796
- messages = loco.po.init( locale ).wrap( conf.powrap );
797
- // ready to render editor
798
- messages.load(mergeTranslatedText);
799
-
800
- // editor event behaviours
801
- editor
802
- .on('poUnsaved', function(){
803
- window.onbeforeunload = onUnloadWarning;
804
- } )
805
- .on('poSave', function(){
806
- updateStatus();
807
- window.onbeforeunload = null;
808
- } )
809
- .on( 'poUpdate', updateStatus );
810
-
811
- // ready to render editor
812
- editor.load(messages);
813
- data.saveBtn.addClass( 'button-primary loco-flagged' ).removeAttr("disabled");
814
- updateStatus();
815
- requestChars=0;
816
- // update progress bar
817
- $('#atlt-dialog .translated-label').text('Translated');
818
- $('#atlt-dialog .translated-text').text(window.locoEditorStats.totalTranslated);
819
-
820
- $('#atlt-dialog .atlt-progress-bar-value').width(window.locoEditorStats.totalTranslated);
821
-
822
- if(json_resp['stats']['time_saved']!==undefined){
823
- var saved_time_msg = '<br/><br/><span style="border: 3px solid #14b75d;display: inline-block;padding: 3px;">Wahooo! You have saved your <strong>'+json_resp['stats']['time_saved']+'</strong> via auto translating '+parseInt(json_resp['stats']['totalChars'])+ ' characters using <strong><a href="https://wordpress.org/support/plugin/automatic-translator-addon-for-loco-translate/reviews/#new-post" target="_new">Loco Automatic Translate Addon</a></strong>.</span><br/><br/>';
824
- }
825
-
826
- switch( window.locoEditorStats.totalTranslated ){
827
- case "0%":
828
- $('#atlt-dialog .translated-label').text('Translating...');
829
- $('#atlt-dialog .translated-text').text('');
830
- break;
831
- case "100%":
832
- data.thisBtn.text('Translated');
833
- data.thisBtn.attr('disabled','disabled');
834
- // change cursor to 'default' state
835
- $('#atlt-dialog .atlt-final-message').html("<strong style='font-size:18px;display:inline-block;margin:5px auto;'>Translation Complete!</strong><br/>(Close this popup & Click <strong>Save</strong>)"+saved_time_msg);
836
- $('#atlt-dialog .atlt-ok.button').show();
837
- return;
838
- break;
839
- }
840
-
841
- // run through DOM and mark *(STAR) for newly translated
842
- for(var x=0;x<=Emptytargets.length;x++){
843
- var source = Emptytargets[x];
844
- jQuery("#po-list-tbody div[for='po-list-col-source'] div").filter(function(index){
845
- return jQuery(this).text() == source
846
- }).addClass('po-unsaved');
847
- }
848
-
849
- if( (window.locoEditorStats.dataObj.textToTranslateArr).length == 0){
850
- data.thisBtn.text('Translated');
851
- data.thisBtn.attr('disabled','disabled');
852
- // change cursor to 'default' state
853
- $('#atlt-dialog .atlt-final-message').html("<strong style='font-size:18px;display:inline-block;margin:5px auto;'>Translation Complete!</strong><br/>(Close this popup & Click <strong>Save</strong>)<br/><br/>Text with HTML content can not be translated."+saved_time_msg);
854
- $('#atlt-dialog .atlt-ok.button').show();
855
- return;
856
- }
857
-
858
- jQuery(document).trigger('atlt_translated');
859
- });
860
- }
861
-
862
- function atlt_arrayUnique(array) {
863
- var a = array.concat();
864
- for(var i=0; i<a.length; ++i) {
865
- for(var j=i+1; j<a.length; ++j) {
866
- if(a[i] === a[j])
867
- a.splice(j--, 1);
868
- }
869
- }
870
-
871
- return a;
872
- }
873
-
874
- function ValidURL(str) {
875
- var pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
876
- if(!pattern.test(str)) {
877
- return false;
878
- } else {
879
- return true;
880
- }
881
- }
882
- function atlt_ajax_translation_request(data,type){
883
-
884
- const newArr=data.textToTranslateArr.map((item)=>{
885
- if( typeof item.source!= 'undefined'){
886
- //return obj='['+item.source+']';
887
- return obj= encodeURI( item.source );
888
- }
889
- });
890
- return jQuery.ajax({
891
- url: ajaxurl,
892
- type:'POST',
893
- data: {'action':'atlt_translation',
894
- 'sourceLan':data.sourceLang,
895
- 'targetLan':data.targetLang,
896
- 'totalCharacters': TotalCharacters,
897
- 'requestChars':requestChars,
898
- 'nonce':data.nonce,
899
- 'data':newArr
900
- },
901
- done:function(res){
902
- console.log(res)
903
- }
904
-
905
- });
906
- }
907
-
908
- // ok, editor ready
909
- updateStatus();
910
-
911
- // clean up
912
- //delete window.locoConf;
913
- //conf = buttons = null;
914
-
915
- }( window, jQuery );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/loco-js-editor.min.js CHANGED
@@ -1 +1 @@
1
- !function(window,$){var TotalCharacters=0,HtmlStrings=0,requestChars=0;let event;document.createEvent("event").initEvent("atlt_translated");let popup_html='<div id="atlt-dialog-container"><div style="display:none;" id="atlt-dialog" title="Automatic Translation Progress"><p><span class="translated-label">Translated</span> <span class="translated-text">0%</span></p><div class="atlt-progress-bar-track"><div class="atlt-progress-bar-value"></div></div><div class="atlt-final-message"></div><button style="display:none;" class="atlt-ok button button-primary">OK</button></div></div>';$("body").append(popup_html),$("#atlt-dialog .atlt-ok.button").on("click",(function(){$("#atlt-dialog").parent(".ui-dialog").hide()}));var loco=window.locoScope,conf=window.locoConf,syncParams=null,saveParams=null,translator=loco.l10n,sprintf=loco.string.sprintf,locale=conf.locale,messages=loco.po.init(locale).wrap(conf.powrap),template=!locale,elForm=document.getElementById("loco-actions"),filePath=conf.popath,syncPath=conf.potpath,elFilesys=document.getElementById("loco-fs"),fsConnect=elFilesys&&loco.fs.init(elFilesys),readonly,editable=!conf.readonly,editor,saveButton,innerDiv=document.getElementById("loco-editor-inner");function doSyncAction(callback){function onSuccess(result){var info=[],doc=messages,exp=result.po,src=result.pot,pot=loco.po.init().load(exp),done=doc.merge(pot),nadd=done.add.length,ndel=done.del.length,t=translator;editor.load(doc),nadd||ndel?(src?info.push(sprintf(t._("Merged from %s"),src)):info.push(t._("Merged from source code")),nadd&&info.push(sprintf(t._n("1 new string added","%s new strings added",nadd),nadd)),ndel&&info.push(sprintf(t._n("1 obsolete string removed","%s obsolete strings removed",ndel),ndel)),$(innerDiv).trigger("poUnsaved",[]),updateStatus(),window.console&&debugMerge(console,done)):src?info.push(sprintf(t._("Already up to date with %s"),src)):info.push(t._("Already up to date with source code")),loco.notices.success(info.join(". ")),$(innerDiv).trigger("poMerge",[result]),callback&&callback()}loco.ajax.post("sync",syncParams,onSuccess,callback)}function debugMerge(console,result){for(var i=-1,t=result.add.length;++i<t;)console.log(" + "+result.add[i].source());for(i=-1,t=result.del.length;++i<t;)console.log(" - "+result.del[i].source())}function doSaveAction(callback){function onSuccess(result){callback&&callback(),editor.save(!0),$("#loco-po-modified").text(result.datetime||"[datetime error]")}saveParams.locale=String(messages.locale()||""),fsConnect&&fsConnect.applyCreds(saveParams),saveParams.data=String(messages),loco.ajax.post("save",saveParams,onSuccess,callback)}function saveIfDirty(){editor.dirty&&doSaveAction()}function onUnloadWarning(){return translator._("Your changes will be lost if you continue without saving")}function registerSaveButton(button){function disable(){button.disabled=!0}function enable(){button.disabled=!1}function think(){disable(),$(button).addClass("loco-loading")}function unthink(){enable(),$(button).removeClass("loco-loading")}return saveButton=button,editor.on("poUnsaved",(function(){enable(),$(button).addClass("button-primary loco-flagged")})).on("poSave",(function(){disable(),$(button).removeClass("button-primary loco-flagged")})),saveParams=$.extend({path:filePath},conf.project||{}),$(button).click((function(event){return event.preventDefault(),think(),doSaveAction(unthink),!1})),!0}function registerSyncButton(button){var project=conf.project;if(project){function disable(){button.disabled=!0}function enable(){button.disabled=!1}function think(){disable(),$(button).addClass("loco-loading")}function unthink(){enable(),$(button).removeClass("loco-loading")}editor.on("poUnsaved",(function(){disable()})).on("poSave",(function(){enable()})),syncParams={bundle:project.bundle,domain:project.domain,type:template?"pot":"po",sync:syncPath||""},$(button).click((function(event){return event.preventDefault(),think(),doSyncAction(unthink),!1})),enable()}return!0}function registerFuzzyButton(button){var toggled=!1,enabled=!1;function redraw(message,state){var allowed=message&&message.translated(0)||!1;enabled!==allowed&&(button.disabled=!allowed,enabled=allowed),state!==toggled&&($(button)[state?"addClass":"removeClass"]("inverted"),toggled=state)}return editor.on("poSelected",(function(event,message){redraw(message,message&&message.fuzzy()||!1)})).on("poEmpty",(function(event,blank,message,pluralIndex){0===pluralIndex&&blank===enabled&&redraw(message,toggled)})).on("poFuzzy",(function(event,message,newState){redraw(message,newState)})),$(button).click((function(event){return event.preventDefault(),editor.fuzzy(!editor.fuzzy()),!1})),!0}function registerRevertButton(button){return editor.on("poUnsaved",(function(){button.disabled=!1})).on("poSave",(function(){button.disabled=!0})),$(button).click((function(event){return event.preventDefault(),location.reload(),!1})),!0}function registerInvisiblesButton(button){var $button=$(button);return button.disabled=!1,editor.on("poInvs",(function(event,state){$button[state?"addClass":"removeClass"]("inverted")})),$button.click((function(event){return event.preventDefault(),editor.setInvs(!editor.getInvs()),!1})),locoScope.tooltip.init($button),!0}function registerCodeviewButton(button){var $button=$(button);return button.disabled=!1,$button.click((function(event){event.preventDefault();var state=!editor.getMono();return editor.setMono(state),$button[state?"addClass":"removeClass"]("inverted"),!1})),locoScope.tooltip.init($button),!0}function registerAddButton(button){return button.disabled=!1,$(button).click((function(event){event.preventDefault();var i=1,baseid,msgid,regex=/(\d+)$/;for(msgid=baseid="New message";messages.get(msgid);)i=regex.exec(msgid)?Math.max(i,RegExp.$1):i,msgid=baseid+" "+ ++i;return editor.add(msgid),!1})),!0}function registerDelButton(button){return button.disabled=!1,$(button).click((function(event){return event.preventDefault(),editor.del(),!1})),!0}function registerDownloadButton(button,id){return button.disabled=!1,$(button).click((function(event){var form=button.form,path=filePath;return"binary"===id&&(path=path.replace(/\.po$/,".mo")),form.path.value=path,form.source.value=messages.toString(),!0})),!0}function noop(event){return event.preventDefault(),!1}function updateStatus(){var t=translator,stats=editor.stats(),total=stats.t,fuzzy=stats.f,empty=stats.u,stext=sprintf(t._n("1 string","%s strings",total),total.format(0)),extra=[];locale&&(stext=sprintf(t._("%s%% translated"),stats.p.replace("%",""))+", "+stext,fuzzy&&extra.push(sprintf(t._("%s fuzzy"),fuzzy.format(0))),empty&&extra.push(sprintf(t._("%s untranslated"),empty.format(0))),extra.length&&(stext+=" ("+extra.join(", ")+")")),$("#loco-po-status").text(stext),void 0===window.locoEditorStats?window.locoEditorStats={totalWords:stats.t,totalTranslated:stats.p}:(window.locoEditorStats.totalWords=stats.t,window.locoEditorStats.totalTranslated=stats.p)}function initSearchFilter(elSearch){function showValidFilter(numFound){$(elSearch.parentNode)[numFound||null==numFound?"removeClass":"addClass"]("invalid")}editor.searchable(loco.fulltext.init()),elSearch.disabled=!1,elSearch.value="";var listener=loco.watchtext(elSearch,(function(value){var numFound;showValidFilter(editor.filter(value,!0))}));editor.on("poFilter",(function(event,value,numFound){listener.val(value||""),showValidFilter(numFound)})).on("poMerge",(function(event,result){var value=listener.val();value&&editor.filter(value)}))}var resize=function(){function top(el,ancestor){for(var y=el.offsetTop||0;(el=el.offsetParent)&&el!==ancestor;)y+=el.offsetTop||0;return y}var fixHeight,minHeight=parseInt($(innerDiv).css("min-height")||0);return function(){var padBottom=20,topBanner=top(innerDiv,document.body),winHeight=window.innerHeight,setHeight=Math.max(minHeight,winHeight-topBanner-20);fixHeight!==setHeight&&(innerDiv.style.height=String(setHeight)+"px",fixHeight=setHeight)}}();resize(),$(window).resize(resize),innerDiv.innerHTML="",editor=loco.po.ed.init(innerDiv).localise(translator),loco.po.kbd.init(editor).add("save",saveIfDirty).enable("copy","clear","enter","next","prev","fuzzy","save","invis");var buttons={save:editable&&registerSaveButton,sync:editable&&registerSyncButton,revert:registerRevertButton,invs:registerInvisiblesButton,code:registerCodeviewButton,source:registerDownloadButton,binary:template?null:registerDownloadButton};function createEncodedString(allStringText){const queryString=allStringText.map(item=>"&text="+encodeURIComponent(item.source)).join(",");return queryString}function validLicenseKey(licenseKey){return licenseKey}function addAutoTranslationBtn(){$("#loco-toolbar").find("#cool-auto-translate-btn").length>0&&$("#loco-toolbar").find("#cool-auto-translate-btn").remove();const disabledBtn='<fieldset><button title="Buy PRO." id="cool-auto-translate-btn" disabled class="button has-icon icon-translate">Auto Translate</button><div style="max-width:320px; display:inline-block;margin-top: 4px;"><span style="font-size:12px;display:inline-block;margin-left:8px;">You have exceeded free translation limit. In order to extend the limit - <a target="_blank" style="font-size:14px;display:inline-block;margin-left:8px;" target="_blank" href="https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/">Buy Premium License</a></span></div></fieldset>',apiKey=ATLT.api_key["atlt_api-key"],userType=ATLT.info.type,allowed=ATLT.info.allowed,today=ATLT.info.today,total=ATLT.info.total;if(""!=ATLT&&""!=ATLT.api_key&&""!=apiKey)if("no"!=allowed||"free"!=userType)if(void 0!==today&&parseInt(today)>3e5&&"free"==userType)$("#loco-toolbar").find("#loco-actions").append(disabledBtn);else if(void 0!==total&&parseInt(total)>1e7&&"free"==userType)$("#loco-toolbar").find("#loco-actions").append(disabledBtn);else if("100%"!=window.locoEditorStats.totalTranslated&&window.locoEditorStats.totalWords>0)if("pro"==userType&&validLicenseKey(ATLT.info.licenseKey))$("#loco-toolbar").find("#loco-actions").append('<fieldset><button id="cool-auto-translate-btn" class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="http://translate.yandex.com/">Powered by Yandex.Translate</a></fieldset>');else{if(null==today)var todayChars=1e5;else var todayChars=1e5-parseInt(today);var totalChars,freeBtn='<fieldset><button data-today-limit="'+todayChars+'" data-total-limit="'+(3e6-parseInt(total))+'" id="cool-auto-translate-btn" class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="http://translate.yandex.com/">Powered by Yandex.Translate</a></fieldset>';$("#loco-toolbar").find("#loco-actions").append(freeBtn)}else{if(0==window.locoEditorStats.totalWords)return;$("#loco-toolbar").find("#loco-actions").append('<fieldset><button id="cool-auto-translate-btn" class="button has-icon icon-translate" disabled>Translated</button></fieldset>')}else $("#loco-toolbar").find("#loco-actions").append(disabledBtn);else $("#loco-toolbar").find("#loco-actions").append('<fieldset><button title="Add API key to enable this feature." id="cool-auto-translate-btn" disabled class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="https://tech.yandex.com/translate/">Get Free API Key</a></fieldset>')}function atlt_translate(data){atlt_ajax_translation_request(data,"POST").success((function(resp){const json_resp=JSON.parse(resp);if(0==json_resp)alert("Unable to make request to the server at the moment. Try again later.");else if(void 0===typeof json_resp.code||200!=json_resp.code){let error="";switch(json_resp.code){case 401:error="Yendex API Key is invalid!";break;case 402:error="Provided Yendex API Key has been blocked!";break;case 404:error="Exceeded the daily limit for Yendex API on the amount of translated text.";break;case 422:error="The text cannot be translated by Yendex API.";break;case 501:error="Yendex API does not support the specified translation direction.";break;default:error=json_resp.message}return void(""!=error&&0!=data.textToTranslateArr.length&&($("#atlt-dialog .atlt-final-message").html("<strong>"+error+"</strong>"),$("#atlt-dialog .atlt-ok.button").show(),data.thisBtn.text("Translation"),data.thisBtn.attr("disabled","disabled")))}let totalTranslated=window.locoEditorStats.totalTranslated;var response=json_resp.text;if(void 0!==response)for(i=0;i<response.length;i++){var text=response[i];if(void 0===data.textToTranslateArr[i])break;data.textToTranslateArr[i].target=text}for(var mergeTranslatedText=atlt_arrayUnique(data.textToTranslateArr.concat(data.orginalArr)),textForTranslation=data.textToTranslateArr,Emptytargets=[],x=0;x<textForTranslation.length;++x)""!=textForTranslation[x].target&&(Emptytargets[x]=textForTranslation[x].source);if((messages=loco.po.init(locale).wrap(conf.powrap)).load(mergeTranslatedText),editor.on("poUnsaved",(function(){window.onbeforeunload=onUnloadWarning})).on("poSave",(function(){updateStatus(),window.onbeforeunload=null})).on("poUpdate",updateStatus),editor.load(messages),data.saveBtn.addClass("button-primary loco-flagged").removeAttr("disabled"),updateStatus(),requestChars=0,$("#atlt-dialog .translated-label").text("Translated"),$("#atlt-dialog .translated-text").text(window.locoEditorStats.totalTranslated),$("#atlt-dialog .atlt-progress-bar-value").width(window.locoEditorStats.totalTranslated),void 0!==json_resp.stats.time_saved)var saved_time_msg='<br/><br/><span style="border: 3px solid #14b75d;display: inline-block;padding: 3px;">Wahooo! You have saved your <strong>'+json_resp.stats.time_saved+"</strong> via auto translating "+parseInt(json_resp.stats.totalChars)+' characters using <strong><a href="https://wordpress.org/support/plugin/automatic-translator-addon-for-loco-translate/reviews/#new-post" target="_new">Loco Automatic Translate Addon</a></strong>.</span><br/><br/>';switch(window.locoEditorStats.totalTranslated){case"0%":$("#atlt-dialog .translated-label").text("Translating..."),$("#atlt-dialog .translated-text").text("");break;case"100%":return data.thisBtn.text("Translated"),data.thisBtn.attr("disabled","disabled"),$("#atlt-dialog .atlt-final-message").html("<strong style='font-size:18px;display:inline-block;margin:5px auto;'>Translation Complete!</strong><br/>(Close this popup & Click <strong>Save</strong>)"+saved_time_msg),void $("#atlt-dialog .atlt-ok.button").show()}for(var x=0;x<=Emptytargets.length;x++){var source=Emptytargets[x];jQuery("#po-list-tbody div[for='po-list-col-source'] div").filter((function(index){return jQuery(this).text()==source})).addClass("po-unsaved")}if(0==window.locoEditorStats.dataObj.textToTranslateArr.length)return data.thisBtn.text("Translated"),data.thisBtn.attr("disabled","disabled"),$("#atlt-dialog .atlt-final-message").html("<strong style='font-size:18px;display:inline-block;margin:5px auto;'>Translation Complete!</strong><br/>(Close this popup & Click <strong>Save</strong>)<br/><br/>Text with HTML content can not be translated."+saved_time_msg),void $("#atlt-dialog .atlt-ok.button").show();jQuery(document).trigger("atlt_translated")}))}function atlt_arrayUnique(array){for(var a=array.concat(),i=0;i<a.length;++i)for(var j=i+1;j<a.length;++j)a[i]===a[j]&&a.splice(j--,1);return a}function ValidURL(str){var pattern;return!!/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/.test(str)}function atlt_ajax_translation_request(data,type){const newArr=data.textToTranslateArr.map(item=>{if(void 0!==item.source)return obj=encodeURI(item.source)});return jQuery.ajax({url:ajaxurl,type:"POST",data:{action:"atlt_translation",sourceLan:data.sourceLang,targetLan:data.targetLang,totalCharacters:TotalCharacters,requestChars:requestChars,nonce:data.nonce,data:newArr},done:function(res){console.log(res)}})}template?(buttons.add=editable&&registerAddButton,buttons.del=editable&&registerDelButton):buttons.fuzzy=registerFuzzyButton,$("#loco-toolbar").find("button").each((function(i,el){var id=el.getAttribute("data-loco"),register=buttons[id];register&&register(el,id)||$(el).hide()})),$(elForm).submit(noop),initSearchFilter(document.getElementById("loco-search")),editor.on("poUnsaved",(function(){window.onbeforeunload=onUnloadWarning})).on("poSave",(function(){updateStatus(),window.onbeforeunload=null})).on("poUpdate",updateStatus),messages.load(conf.podata),editor.load(messages),(locale=editor.targetLocale)?locale.isRTL()&&$(innerDiv).addClass("trg-rtl"):editor.unlock(),$(document).ready((function(){const locoRawData=conf.podata;null!=locoRawData&&locoRawData.length>0&&addAutoTranslationBtn();let dataObj={};$(document).on("click","#cool-auto-translate-btn",(function(){var thisBtn=$(this),todayLimit=thisBtn.data("today-limit"),totalLimit=thisBtn.data("total-limit");const apiKey=ATLT.api_key["atlt_api-key"];if(null!=locoRawData&&locoRawData.length>0&&""!=apiKey){let untranslatedAllString,untranslatedTextArr=locoRawData.filter((item,index)=>{if((void 0===item.target||""==item.target)&&0==item.source.includes("</")&&0==item.source.includes("/>")&&0==item.source.includes("#"))return!0;HtmlStrings++}).filter((item,index)=>!ValidURL(item.source));if(null!==untranslatedTextArr){var countChars=0;untranslatedTextArr.map((function(index){countChars+=index.source.length})),countChars>parseInt(todayLimit)?alert("Your translation string are larger then available free limit.In order to extend limit Buy Pro license key"):(thisBtn.text("...Translating"),dataObj={textToTranslateArr:untranslatedTextArr,thisBtn:$(this)},window.locoEditorStats.dataObj=dataObj,jQuery(document).trigger("atlt_translated"))}}}))})),jQuery(document).on("atlt_translated",(function(){let textToTranslate=window.locoEditorStats.dataObj.textToTranslateArr,totalTranslated=window.locoEditorStats.totalTranslated;const apiKey=ATLT.api_key["atlt_api-key"],nonce=ATLT.nonce,saveBtn=$('[data-loco="save"]'),orignalstringArr=conf.podata,targetLang=conf.locale.lang;let indexRequest=50;if(""!=ATLT.api_key["atlt_index-per-request"]&&void 0!==ATLT.api_key["atlt_index-per-request"]&&(indexRequest=ATLT.api_key["atlt_index-per-request"]),"object"==typeof textToTranslate&&textToTranslate.length>=1){let translationO={textToTranslateArr:textToTranslate.slice(indexRequest),thisBtn:window.locoEditorStats.dataObj.thisBtn};window.locoEditorStats.dataObj=translationO;let data={sourceLang:"en",targetLang:targetLang,textToTranslateArr:textToTranslate.slice(0,indexRequest),orginalArr:orignalstringArr,apiKey:apiKey,thisBtn:window.locoEditorStats.dataObj.thisBtn,saveBtn:saveBtn,nonce:nonce};textToTranslate.slice(0,indexRequest).map((function(value,index){TotalCharacters+=value.source.length,requestChars+=value.source.length})),$("#atlt-dialog").dialog({width:320}),atlt_translate(data)}else HtmlStrings>=1&&(alert("Remaining HTML strings can not be auto translate!"),window.location.reload())})),updateStatus()}(window,jQuery);
1
+ !function(t,e){var a=0,o=0;document.createEvent("event").initEvent("atlt_translated"),function(){let t=extradata.preloader_path;const a=ATLT.info.type;let o="",n="",l="";"free"==a&&(o="disabled",n="html-disabled",l='<span class="atlt-pro-feature"><a href="https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/" target="_blank" style="color:red;font-weight:bold;" title="Only For Pro Users">PRO Only</a></span>');let r=`<div id="atlt-dialog-container">\n <div style="display:none;" id="atlt-dialog" title="Automatic Translation Progress">\n ${`<div class="atlt-settings">\n <form id="atlt-settings-form" method="post" action="#">\n <strong class="atlt-heading">Select Content Type</strong>\n <div class="inputGroup">\n <input class="inputEle" type="radio" id="typeplain" checked="true" name="translationtype" value="plain">\n <label for="typeplain">Translate Plain Text Strings</label>\n </div><div class="inputGroup ${n}">\n <input class="inputEle" type="radio" id="typehtml" name="translationtype" value="html" ${o}>\n <label for="typehtml">Translate HTML Strings (Beta) ${l}<br/><small style="display:inline-block;margin-left:24px;margin-top:8px;">(<a href="https://locotranslate.com/html-translation-languages-list/" target="_blank">List of languages with HTML support</a>)</small></label>\n </div>\n <br/>\n <fieldset><input type="submit" class="button has-icon icon-translate" value="Start Translation" id="cool-auto-translate-start">\n <img style="display:none;margin-left:10px;margin-top:-3px;" id="atlt_preloader" src="${t}">\n </fieldset>\n </form>\n </div>`}\n <p><span class="translated-label">Translated</span>\n <span class="translated-text">0%</span></p>\n <div class="atlt-progress-bar-track">\n <div class="atlt-progress-bar-value">\n </div></div>\n <div class="atlt-final-message"></div>\n <button style="display:none;" class="atlt-ok button button-primary">OK</button>\n </div></div>`;e("body").append(r)}(),e("#atlt-dialog .atlt-ok.button").on("click",function(){localStorage.removeItem("unSavedString"),e("#atlt-dialog").parent(".ui-dialog").hide()});var n,l=t.locoScope,r=t.locoConf,s=null,d=null,c=l.l10n,u=l.string.sprintf,p=r.locale,f=l.po.init(p).wrap(r.powrap),g=!p,b=document.getElementById("loco-actions"),v=r.popath,h=r.potpath,m=document.getElementById("loco-fs"),y=m&&l.fs.init(m),T=!r.readonly,x=document.getElementById("loco-editor-inner");function S(t){d.locale=String(f.locale()||""),y&&y.applyCreds(d),d.data=String(f),l.ajax.post("save",d,function(a){t&&t(),n.save(!0),e("#loco-po-modified").text(a.datetime||"[datetime error]")},t)}function k(){return c._("Your changes will be lost if you continue without saving")}function A(t,a){return t.disabled=!1,e(t).click(function(e){var o=t.form,n=v;return"binary"===a&&(n=n.replace(/\.po$/,".mo")),o.path.value=n,o.source.value=f.toString(),!0}),!0}function _(){var a=c,o=n.stats(),l=o.t,r=o.f,i=o.u,s=u(a._n("1 string","%s strings",l),l.format(0)),d=[];p&&(s=u(a._("%s%% translated"),o.p.replace("%",""))+", "+s,r&&d.push(u(a._("%s fuzzy"),r.format(0))),i&&d.push(u(a._("%s untranslated"),i.format(0))),d.length&&(s+=" ("+d.join(", ")+")")),e("#loco-po-status").text(s),void 0===t.locoEditorStats?t.locoEditorStats={totalWords:o.t,totalTranslated:o.p}:(t.locoEditorStats.totalWords=o.t,t.locoEditorStats.totalTranslated=o.p)}var w=function(){var a,o=parseInt(e(x).css("min-height")||0);return function(){var e=function(t,e){for(var a=t.offsetTop||0;(t=t.offsetParent)&&t!==e;)a+=t.offsetTop||0;return a}(x,document.body),n=t.innerHeight,l=Math.max(o,n-e-20);a!==l&&(x.style.height=String(l)+"px",a=l)}}();w(),e(t).resize(w),x.innerHTML="",n=l.po.ed.init(x).localise(c),l.po.kbd.init(n).add("save",function(){n.dirty&&S()}).enable("copy","clear","enter","next","prev","fuzzy","save","invis");var E={save:T&&function(t){function a(){t.disabled=!0}function o(){t.disabled=!1}function l(){o(),e(t).removeClass("loco-loading")}return t,n.on("poUnsaved",function(){o(),e(t).addClass("button-primary loco-flagged")}).on("poSave",function(){a(),e(t).removeClass("button-primary loco-flagged")}),d=e.extend({path:v},r.project||{}),e(t).click(function(o){return o.preventDefault(),a(),e(t).addClass("loco-loading"),S(l),!1}),!0},sync:T&&function(a){var o=r.project;if(o){function i(){a.disabled=!0}function d(){a.disabled=!1}function p(){d(),e(a).removeClass("loco-loading")}n.on("poUnsaved",function(){i()}).on("poSave",function(){d()}),s={bundle:o.bundle,domain:o.domain,type:g?"pot":"po",sync:h||""},e(a).click(function(o){var r;return o.preventDefault(),i(),e(a).addClass("loco-loading"),r=p,l.ajax.post("sync",s,function(a){var o=[],i=f,s=a.po,d=a.pot,p=l.po.init().load(s),g=i.merge(p),b=g.add.length,v=g.del.length,h=c;n.load(i),b||v?(d?o.push(u(h._("Merged from %s"),d)):o.push(h._("Merged from source code")),b&&o.push(u(h._n("1 new string added","%s new strings added",b),b)),v&&o.push(u(h._n("1 obsolete string removed","%s obsolete strings removed",v),v)),e(x).trigger("poUnsaved",[]),_(),t.console&&function(t,e){for(var a=-1,o=e.add.length;++a<o;)t.log(" + "+e.add[a].source());for(a=-1,o=e.del.length;++a<o;)t.log(" - "+e.del[a].source())}(console,g)):d?o.push(u(h._("Already up to date with %s"),d)):o.push(h._("Already up to date with source code")),l.notices.success(o.join(". ")),e(x).trigger("poMerge",[a]),r&&r()},r),!1}),d()}return!0},revert:function(t){return n.on("poUnsaved",function(){t.disabled=!1}).on("poSave",function(){t.disabled=!0}),e(t).click(function(t){return t.preventDefault(),location.reload(),!1}),!0},invs:function(t){var a=e(t);return t.disabled=!1,n.on("poInvs",function(t,e){a[e?"addClass":"removeClass"]("inverted")}),a.click(function(t){return t.preventDefault(),n.setInvs(!n.getInvs()),!1}),locoScope.tooltip.init(a),!0},code:function(t){var a=e(t);return t.disabled=!1,a.click(function(t){t.preventDefault();var e=!n.getMono();return n.setMono(e),a[e?"addClass":"removeClass"]("inverted"),!1}),locoScope.tooltip.init(a),!0},source:A,binary:g?null:A};function j(t){return!!/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/.test(t)}function C(t){return void 0!==t&&/<(?=.*? .*?\/ ?>|br|hr|input|!--|wbr)[a-z]+.*?>|<([a-z]+).*?<\/\1>/i.test(t)}g?(E.add=T&&function(t){return t.disabled=!1,e(t).click(function(t){t.preventDefault();var e,a=1,o=/(\d+)$/;for(e="New message";f.get(e);)a=o.exec(e)?Math.max(a,RegExp.$1):a,e="New message "+ ++a;return n.add(e),!1}),!0},E.del=T&&function(t){return t.disabled=!1,e(t).click(function(t){return t.preventDefault(),n.del(),!1}),!0}):E.fuzzy=function(t){var a=!1,o=!1;function l(n,l){var r=n&&n.translated(0)||!1;o!==r&&(t.disabled=!r,o=r),l!==a&&(e(t)[l?"addClass":"removeClass"]("inverted"),a=l)}return n.on("poSelected",function(t,e){l(e,e&&e.fuzzy()||!1)}).on("poEmpty",function(t,e,n,r){0===r&&e===o&&l(n,a)}).on("poFuzzy",function(t,e,a){l(e,a)}),e(t).click(function(t){return t.preventDefault(),n.fuzzy(!n.fuzzy()),!1}),!0},e("#loco-toolbar").find("button").each(function(t,a){var o=a.getAttribute("data-loco"),n=E[o];n&&n(a,o)||e(a).hide()}),e(b).submit(function(t){return t.preventDefault(),!1}),function(t){function a(a){e(t.parentNode)[a||null==a?"removeClass":"addClass"]("invalid")}n.searchable(l.fulltext.init()),t.disabled=!1,t.value="";var o=l.watchtext(t,function(t){a(n.filter(t,!0))});n.on("poFilter",function(t,e,n){o.val(e||""),a(n)}).on("poMerge",function(t,e){var a=o.val();a&&n.filter(a)})}(document.getElementById("loco-search")),n.on("poUnsaved",function(){t.onbeforeunload=k}).on("poSave",function(){_(),t.onbeforeunload=null}).on("poUpdate",_),f.load(r.podata),n.load(f),(p=n.targetLocale)?p.isRTL()&&e(x).addClass("trg-rtl"):n.unlock(),e(document).ready(function(){const a=r.podata;null!=a&&a.length>0&&function(){e("#loco-toolbar").find("#cool-auto-translate-btn").length>0&&e("#loco-toolbar").find("#cool-auto-translate-btn").remove();const a='<fieldset><button title="Buy PRO." id="cool-auto-translate-btn" disabled class="button has-icon icon-translate">Auto Translate</button><div style="max-width:320px; display:inline-block;margin-top: 4px;"><span style="font-size:12px;display:inline-block;margin-left:8px;">You have exceeded free translation limit. In order to extend the limit - <a target="_blank" style="font-size:14px;display:inline-block;margin-left:8px;" target="_blank" href="https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/">Buy Premium License</a></span></div></fieldset>',o=ATLT.api_key["atlt_api-key"],n=ATLT.info.type,l=ATLT.info.allowed,r=ATLT.info.today,i=ATLT.info.total;if(""==ATLT||""==ATLT.api_key||""==o)return void e("#loco-toolbar").find("#loco-actions").append('<fieldset><button title="Add API key to enable this feature." id="cool-auto-translate-btn" disabled class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="https://tech.yandex.com/translate/">Get Free API Key</a></fieldset>');if("no"==l&&"free"==n)return void e("#loco-toolbar").find("#loco-actions").append(a);if(void 0!==r&&parseInt(r)>3e5&&"free"==n)return void e("#loco-toolbar").find("#loco-actions").append(a);if(void 0!==i&&parseInt(i)>1e6&&"free"==n)return void e("#loco-toolbar").find("#loco-actions").append(a);if("100%"!=t.locoEditorStats.totalTranslated&&t.locoEditorStats.totalWords>0)if("pro"==n&&ATLT.info.licenseKey)e("#loco-toolbar").find("#loco-actions").append('<fieldset><button id="cool-auto-translate-btn" class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="http://translate.yandex.com/">Powered by Yandex.Translate</a></fieldset>');else{if(null==r)var s=3e5;else var s=3e5-parseInt(r);var d=1e6-parseInt(i),c='<fieldset><button data-today-limit="'+s+'" data-total-limit="'+d+'" id="cool-auto-translate-btn" class="button has-icon icon-translate">Auto Translate</button> <a style="font-size:9px;display:block;margin-left:8px;" target="_blank" href="http://translate.yandex.com/">Powered by Yandex.Translate</a></fieldset>';e("#loco-toolbar").find("#loco-actions").append(c)}else{if(0==t.locoEditorStats.totalWords)return;e("#loco-toolbar").find("#loco-actions").append('<fieldset><button id="cool-auto-translate-btn" class="button has-icon icon-translate" disabled>Translated</button></fieldset>')}}(),e(document).on("click","#cool-auto-translate-btn",function(){e("#atlt-dialog").dialog({width:320,height:300})}),e("#atlt-settings-form").submit(function(o){o.preventDefault();let n=e("input[name='translationtype']:checked").val(),l=e("#cool-auto-translate-btn");var r=e("#cool-auto-translate-start"),i=l.data("today-limit");l.data("total-limit");const s=ATLT.api_key["atlt_api-key"];if(null!=a&&a.length>0&&""!=s){let o=[],s=[],c=[];c=a,s=a.filter((t,e)=>{if(void 0===t.target||""==t.target&&""!=t.source&&void 0!==t.source)return!j(t.source)&&(!function(t){return void 0!==t&&/[{}[]/g.test(t)}(t.source)&&(!!C(t.source)||!!function(t){return void 0!==t&&/[!@#$%^&*(),?":|<>]/g.test(t)}(t.source)))}),o=a.filter((t,e)=>{if((void 0===t.target||""==t.target)&&""!=t.source)return!C(t.source)&&!j(t.source)&&(!function(t){return void 0!==t&&/[@#^&*{}|<>]/g.test(t)}(t.source)&&1!=t.source.includes("#"))});var d=0;if("plain"==n?null!==o&&o.map(function(t){d+=t.source.length}):null!==s&&o.map(function(t){d+=t.length}),null!==s||null!==o)if(d>parseInt(i))alert("Your translation string are larger then available free limit.In order to extend limit Buy Pro license key");else{if("plain"==n){if(0==o.length)return e("#atlt-dialog").parent(".ui-dialog").hide(),l.attr("disabled","disabled"),alert("You have no untransalted strings"),void t.location.reload();dataObj={textToTranslateArr:o,thisBtn:e(this),strType:"plain"}}else{if(0==s.length)return e("#atlt-dialog").parent(".ui-dialog").hide(),l.attr("disabled","disabled"),alert("You have no untransalted HTML strings"),void t.location.reload();dataObj={textToTranslateArr:s,thisBtn:e(this),strType:"html"}}dataObj.orgStrArr=c,r.val("Translating..."),l.text("Translating.."),e("#atlt_preloader").show(),t.locoEditorStats.dataObj=dataObj,jQuery(document).trigger("atlt_translated")}}})}),jQuery(document).on("atlt_translated",function(){let s=t.locoEditorStats.dataObj.textToTranslateArr;t.locoEditorStats.totalTranslated;const d=ATLT.api_key["atlt_api-key"],c=ATLT.nonce,u=e('[data-loco="save"]'),g=t.locoEditorStats.dataObj.orgStrArr,b=r.locale.lang;let v=50;if(""!=ATLT.api_key["atlt_index-per-request"]&&void 0!==ATLT.api_key["atlt_index-per-request"]&&(v=ATLT.api_key["atlt_index-per-request"]),"object"==typeof s&&s.length>=1){let h={textToTranslateArr:s.slice(v),thisBtn:t.locoEditorStats.dataObj.thisBtn,strType:t.locoEditorStats.dataObj.strType,orgStrArr:t.locoEditorStats.dataObj.orgStrArr};t.locoEditorStats.dataObj=h;let m={sourceLang:"en",targetLang:b,textToTranslateArr:s.slice(0,v),orginalArr:g,apiKey:d,thisBtn:t.locoEditorStats.dataObj.thisBtn,strType:t.locoEditorStats.dataObj.strType,saveBtn:u,nonce:c};s.slice(0,v).map(function(t,e){a+=t.source.length,o+=t.source.length}),function(s){(function(t,e){let n=[];n=t.textToTranslateArr.map(t=>{if(void 0!==t.source)return t.source});const l=JSON.stringify(n);return jQuery.ajax({url:ajaxurl,type:"POST",data:{action:"atlt_translation",sourceLan:t.sourceLang,targetLan:t.targetLang,totalCharacters:a,requestChars:o,nonce:t.nonce,strType:t.strType,data:l},done:function(t){console.log(t)}})})(s).success(function(a){const d=JSON.parse(a);if(0==d)s.thisBtn.hide("slow"),e("#cool-auto-translate-btn").attr("disabled","disabled"),e("#cool-auto-translate-btn").text("Translation").attr("disabled","disabled"),alert("Unable to make request to the server at the moment. Try again later.");else if(void 0===typeof d.code||200!=d.code){let t="";switch(d.code){case 401:t="Yendex API Key is invalid!";break;case 402:t="Provided Yendex API Key has been blocked!";break;case 404:t="Exceeded the daily limit for Yendex API on the amount of translated text.";break;case 422:t="The text cannot be translated by Yendex API.";break;case 501:t="Yendex API does not support the specified translation direction.";break;default:t=d.message}return void(""!=t&&0!=s.textToTranslateArr.length&&(e("#atlt-dialog .atlt-final-message").html("<strong>"+t+"</strong>"),e("#atlt-dialog .atlt-ok.button").show(),s.thisBtn.val("Translation"),e("#cool-auto-translate-btn").text("Translation").attr("disabled","disabled"),s.thisBtn.attr("disabled","disabled")))}t.locoEditorStats.totalTranslated;var c=d.text;if(void 0!==c)for(i=0;i<c.length;i++){var u=c[i];if(void 0===s.textToTranslateArr[i])break;s.textToTranslateArr[i].target=u}let g=s.textToTranslateArr;var b=function(t){for(var e=t.concat(),a=0;a<e.length;++a)for(var o=a+1;o<e.length;++o)e[a]===e[o]&&e.splice(o--,1);return e}(g.concat(s.orginalArr));let v,h=[];for(var m=0;m<g.length;++m)""!=g[m].target&&(h[m]=g[m].source);var y=(v=localStorage.getItem("unSavedString")?JSON.parse(localStorage.getItem("unSavedString")):[]).concat(h);if(localStorage.setItem("unSavedString",JSON.stringify(y)),(f=l.po.init(p).wrap(r.powrap)).load(b),n.on("poUnsaved",function(){t.onbeforeunload=k}).on("poSave",function(){_(),t.onbeforeunload=null}).on("poUpdate",_),n.load(f),s.saveBtn.addClass("button-primary loco-flagged").removeAttr("disabled"),_(),function(){const t=JSON.parse(localStorage.getItem("unSavedString"));console.log(t);for(var e=0;e<=t.length;e++){var a=t[e];jQuery("#po-list-tbody div[for='po-list-col-source'] div").filter(function(t){return jQuery(this).text()==a}).addClass("po-unsaved")}}(),o=0,e("#atlt-dialog .translated-label").text("Translated"),e("#atlt-dialog .translated-text").text(t.locoEditorStats.totalTranslated),e("#atlt-dialog .atlt-progress-bar-value").width(t.locoEditorStats.totalTranslated),void 0!==d&&void 0!==d.stats.time_saved)var T='<br/><br/><span style="border: 3px solid #14b75d;display: inline-block;padding: 3px;">Wahooo! You have saved your <strong>'+d.stats.time_saved+"</strong> via auto translating "+parseInt(d.stats.totalChars)+' characters using <strong><a href="https://wordpress.org/support/plugin/automatic-translator-addon-for-loco-translate/reviews/#new-post" target="_new">Loco Automatic Translate Addon</a></strong>.</span><br/><br/>';switch(t.locoEditorStats.totalTranslated){case"0%":e("#atlt-dialog .translated-label").text("Translating..."),e("#atlt-dialog .translated-text").text("");break;case"100%":return s.thisBtn.text("Translated"),s.thisBtn.attr("disabled","disabled").hide("slow"),e("#cool-auto-translate-btn").text("Translated - SAVE NOW").attr("disabled","disabled"),e("#atlt-dialog .atlt-final-message").html("<strong style='font-size:18px;display:inline-block;margin:5px auto;'>Translation Complete!</strong><br/>(Close this popup & Click <strong>Save</strong>)"+T),void e("#atlt-dialog .atlt-ok.button").show()}e("#cool-auto-translate-btn").text("Translated");for(var m=0;m<=h.length;m++){var x=h[m];jQuery("#po-list-tbody div[for='po-list-col-source'] div").filter(function(t){return jQuery(this).text()==x}).addClass("po-unsaved")}if(0==t.locoEditorStats.dataObj.textToTranslateArr.length)return s.thisBtn.text("Translated"),e("#atlt_preloader").hide(),s.thisBtn.attr("disabled","disabled").hide("slow"),e("#cool-auto-translate-btn").text("Translated - SAVE NOW").attr("disabled","disabled"),e("#atlt-dialog .atlt-final-message").html("<strong style='font-size:18px;display:inline-block;margin:5px auto;'>Translation Complete!</strong><br/>(Close this popup & Click <strong>Save</strong>)."+T),void e("#atlt-dialog .atlt-ok.button").show();jQuery(document).trigger("atlt_translated")})}(m)}}),_()}(window,jQuery);
automatic-translator-addon-for-loco-translate.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  Plugin Name:Loco Automatic Translate Addon
4
  Description:Auto language translator add-on for Loco Translate plugin to translate plugins and themes translation files into any language via fully automatic machine translations via Yendex Translate API.
5
- Version:1.3.2
6
  License:GPL2
7
  Text Domain:atlt
8
  Domain Path:languages
@@ -13,7 +13,7 @@ namespace LocoAutoTranslateAddon;
13
  use LocoAutoTranslateAddon\Helpers\Helpers;
14
  /**
15
  * @package Loco Automatic Translate Addon
16
- * @version 1.3
17
  */
18
  if (!defined('ABSPATH')) {
19
  die('WordPress Environment Not Found!');
@@ -22,11 +22,10 @@ if (!defined('ABSPATH')) {
22
  define('ATLT_FILE', __FILE__);
23
  define('ATLT_URL', plugin_dir_url(ATLT_FILE));
24
  define('ATLT_PATH', plugin_dir_path(ATLT_FILE));
25
- define('ATLT_VERSION', '1.3.2');
26
 
27
  class LocoAutoTranslate
28
  {
29
-
30
  public function __construct()
31
  {
32
  register_activation_hook( ATLT_FILE, array( $this, 'atlt_activate' ) );
@@ -34,16 +33,13 @@ class LocoAutoTranslate
34
  add_action('plugins_loaded', array($this, 'atlt_check_required_loco_plugin'));
35
  /*** Template Setting Page Link inside Plugins List */
36
  add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this,'atlt_settings_page_link'));
37
-
38
  add_action( 'admin_enqueue_scripts', array( $this, 'atlt_enqueue_scripts') );
39
- add_action('wp_ajax_atlt_translation', array($this, 'atlt_translate_words'), 100);
40
  add_action('init',array($this,'checkStatus'));
41
-
42
  add_action('plugins_loaded', array($this,'include_files'));
43
-
44
  }
45
 
46
-
47
  /**
48
  * create 'settings' link in plugins page
49
  */
@@ -66,7 +62,6 @@ class LocoAutoTranslate
66
  if ( is_admin() ) {
67
  include_once ATLT_PATH . "includes/ReviewNotice/class.review-notice.php";
68
  new ALTLReviewNotice\ALTLReviewNotice();
69
-
70
  include_once ATLT_PATH . 'includes/Feedback/class.feedback-form.php';
71
  new FeedbackForm\FeedbackForm();
72
  //require_once ATLT_PATH . "includes/init-api.php";
@@ -76,60 +71,7 @@ class LocoAutoTranslate
76
  public function checkStatus(){
77
  Helpers::checkPeriod();
78
  }
79
- /*
80
- |----------------------------------------------------------------------
81
- | AJAX called to this function for translation
82
- |----------------------------------------------------------------------
83
- */
84
- public function atlt_translate_words()
85
- {
86
- $status=Helpers::atltVerification();
87
- if($status['type']=="free" && $status['allowed']=="no"){
88
- die(json_encode(array('code' => 800, 'message' => 'You have consumed daily limit')));
89
- }
90
- $api_key = Helpers::getAPIkey();
91
- $KEY = $api_key['atlt_api-key'];
92
- $lang = $_REQUEST['sourceLan'] . '-' . $_REQUEST['targetLan'];
93
- $request_chars = $_REQUEST['requestChars'];
94
- $totalChars = $_REQUEST['totalCharacters'];
95
- $nonce=$_REQUEST['nonce'];
96
- if ( ! wp_verify_nonce( $nonce, 'atlt_nonce' ) ) {
97
- die(json_encode(array('code' => 850, 'message' => 'Request Time Out. Please refresh your browser window.')));
98
- } else {
99
- // Do stuff here.
100
- $DATA = $_REQUEST['data'];
101
- if (empty($DATA)) {
102
- die(json_encode(array('code' => 900, 'message' => 'Empty request')));
103
- }
104
- $data = implode('&text=', $DATA );
105
-
106
- $HOST = 'https://translate.yandex.net/api/v1.5/tr.json/translate?key=' . $KEY . '&lang=' . $lang.'&text='.$data;
107
- $response = wp_remote_get($HOST, array('timeout'=>'180'));
108
-
109
- if (is_wp_error($response)) {
110
- return $response; // Bail early
111
- }
112
- $body = wp_remote_retrieve_body($response);
113
- $data = json_decode( $body, true); // convert string into assoc array
114
-
115
- if($data['code']==200){
116
- $today_translated = Helpers::todayTranslated( $request_chars);
117
- $monthly_translated = Helpers::monthlyTranslated( $request_chars);
118
- /** Calculate the total time save on translation */
119
- $session_time_saved = Helpers::atlt_time_saved_on_translation( $totalChars);
120
- $total_time_saved = Helpers::atlt_time_saved_on_translation($totalChars);
121
- $data['stats']=array(
122
- 'todays_translation'=>$today_translated,
123
- 'total_translation'=>$monthly_translated,
124
- 'time_saved'=> $session_time_saved,
125
- 'total_time_saved'=>$total_time_saved,
126
- 'totalChars'=>$totalChars
127
- );
128
- }
129
- die(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
130
- }
131
- }
132
-
133
  /*
134
  |----------------------------------------------------------------------
135
  | check if required "Loco Translate" plugin is active
@@ -191,10 +133,96 @@ class LocoAutoTranslate
191
  $data['nonce']=$nonce;
192
  }
193
  }
 
194
  wp_localize_script('loco-js-editor', 'ATLT', $data);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
  }
 
198
 
199
  /*
200
  |------------------------------------------------------
2
  /*
3
  Plugin Name:Loco Automatic Translate Addon
4
  Description:Auto language translator add-on for Loco Translate plugin to translate plugins and themes translation files into any language via fully automatic machine translations via Yendex Translate API.
5
+ Version:1.4.1
6
  License:GPL2
7
  Text Domain:atlt
8
  Domain Path:languages
13
  use LocoAutoTranslateAddon\Helpers\Helpers;
14
  /**
15
  * @package Loco Automatic Translate Addon
16
+ * @version 1.4.1
17
  */
18
  if (!defined('ABSPATH')) {
19
  die('WordPress Environment Not Found!');
22
  define('ATLT_FILE', __FILE__);
23
  define('ATLT_URL', plugin_dir_url(ATLT_FILE));
24
  define('ATLT_PATH', plugin_dir_path(ATLT_FILE));
25
+ define('ATLT_VERSION', '1.4.1');
26
 
27
  class LocoAutoTranslate
28
  {
 
29
  public function __construct()
30
  {
31
  register_activation_hook( ATLT_FILE, array( $this, 'atlt_activate' ) );
33
  add_action('plugins_loaded', array($this, 'atlt_check_required_loco_plugin'));
34
  /*** Template Setting Page Link inside Plugins List */
35
  add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this,'atlt_settings_page_link'));
 
36
  add_action( 'admin_enqueue_scripts', array( $this, 'atlt_enqueue_scripts') );
37
+ add_action('wp_ajax_atlt_translation', array($this, 'atlt_translate_string_callback'), 100);
38
  add_action('init',array($this,'checkStatus'));
 
39
  add_action('plugins_loaded', array($this,'include_files'));
40
+ add_action('testRequest',array($this,'testHtmltranslation'));
41
  }
42
 
 
43
  /**
44
  * create 'settings' link in plugins page
45
  */
62
  if ( is_admin() ) {
63
  include_once ATLT_PATH . "includes/ReviewNotice/class.review-notice.php";
64
  new ALTLReviewNotice\ALTLReviewNotice();
 
65
  include_once ATLT_PATH . 'includes/Feedback/class.feedback-form.php';
66
  new FeedbackForm\FeedbackForm();
67
  //require_once ATLT_PATH . "includes/init-api.php";
71
  public function checkStatus(){
72
  Helpers::checkPeriod();
73
  }
74
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  /*
76
  |----------------------------------------------------------------------
77
  | check if required "Loco Translate" plugin is active
133
  $data['nonce']=$nonce;
134
  }
135
  }
136
+ $extraData['preloader_path']=ATLT_URL.'/assets/images/preloader.gif';
137
  wp_localize_script('loco-js-editor', 'ATLT', $data);
138
+ wp_localize_script('loco-js-editor', 'extradata', $extraData);
139
+
140
+ }
141
+
142
+ }
143
+
144
+ /*
145
+ |----------------------------------------------------------------------
146
+ | AJAX called to this function for translation
147
+ |----------------------------------------------------------------------
148
+ */
149
+ public function atlt_translate_string_callback()
150
+ {
151
+ // verify request
152
+ if ( ! wp_verify_nonce($_REQUEST['nonce'], 'atlt_nonce' ) ) {
153
+ die(json_encode(array('code' => 850, 'message' => 'Request Time Out. Please refresh your browser window.')));
154
+ } else {
155
+ // user status
156
+ $status=Helpers::atltVerification();
157
+ if($status['type']=="free" && $status['allowed']=="no"){
158
+ die(json_encode(array('code' => 800, 'message' => 'You have consumed daily limit')));
159
+ }
160
+
161
+ // grab API keys
162
+ $api_key_arr = Helpers::getAPIkey();
163
+ $apiKey = $api_key_arr['atlt_api-key'];
164
+ // get request vars
165
+ if (empty($_REQUEST['data'])) {
166
+ die(json_encode(array('code' => 900, 'message' => 'Empty request')));
167
+ }
168
+
169
+ if(isset($_REQUEST['data'])){
170
+
171
+ $requestData = $_REQUEST['data'];
172
+ $targetLang=$_REQUEST['targetLan'];
173
+ $sourceLang=$_REQUEST['sourceLan'];
174
+ if($targetLang=="nb"){
175
+ $targetLang="no";
176
+ }
177
+ $lang = $sourceLang.'-'.$targetLang;
178
+ $request_chars = $_REQUEST['requestChars'];
179
+ $totalChars = $_REQUEST['totalCharacters'];
180
+ $requestType=$_REQUEST['strType'];
181
+
182
+
183
+ // create query string
184
+ $queryString='';
185
+ $stringArr= json_decode(stripslashes($requestData),true);
186
+ if(is_array($stringArr)){
187
+ foreach($stringArr as $str){
188
+ $queryString.='&text='.urlencode($str);
189
+ }
190
+ }
191
+ // build query
192
+ $buildReqURL='';
193
+ $buildReqURL.='https://translate.yandex.net/api/v1.5/tr.json/translate';
194
+ $buildReqURL.='?key=' . $apiKey . '&lang=' . $lang.'&format='.$requestType;
195
+ $buildReqURL.=$queryString;
196
+ // get API response
197
+ $response = wp_remote_get($buildReqURL, array('timeout'=>'180'));
198
+
199
+ if (is_wp_error($response)) {
200
+ return $response; // Bail early
201
  }
202
+ $body = wp_remote_retrieve_body($response);
203
+ $data = json_decode( $body, true); // convert string into assoc array
204
+
205
+ if($data['code']==200){
206
+ // grab translation count data
207
+ $today_translated = Helpers::todayTranslated( $request_chars);
208
+ $monthly_translated = Helpers::monthlyTranslated( $request_chars);
209
+ /** Calculate the total time save on translation */
210
+ $session_time_saved = Helpers::atlt_time_saved_on_translation( $totalChars);
211
+ $total_time_saved = Helpers::atlt_time_saved_on_translation($totalChars);
212
+ // create response array
213
+ $data['stats']=array(
214
+ 'todays_translation'=>$today_translated,
215
+ 'total_translation'=>$monthly_translated,
216
+ 'time_saved'=> $session_time_saved,
217
+ 'total_time_saved'=>$total_time_saved,
218
+ 'totalChars'=>$totalChars
219
+ );
220
+ }
221
+ die(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
222
+ }
223
 
224
  }
225
+ }
226
 
227
  /*
228
  |------------------------------------------------------
includes/Core/class.settings-panel.php CHANGED
@@ -58,7 +58,7 @@ if( !class_exists( 'Settings_Panel' ) ){
58
  {
59
  $month = get_option('atlt_translation_month');
60
  $today = ('atlt_translation_day');
61
-
62
  $total_translation = get_option('atlt_month_translated_chars', 0);
63
  $todays_total_translation = get_option('atlt_perday_translated_chars', 0);
64
  $a_per_day=0;
@@ -123,7 +123,7 @@ if( !class_exists( 'Settings_Panel' ) ){
123
  <th>'.number_format($pro_per_mon).' / Month</th>
124
  </tr>
125
  </table>';
126
-
127
  $settingArr[]=array(
128
  'name' => $this->PREFIX.'api-key',
129
  'id' => $this->PREFIX.'api-key',
@@ -211,7 +211,6 @@ if( !class_exists( 'Settings_Panel' ) ){
211
  public function screenshort(){
212
 
213
  $src = ATLT_URL .'assets/images/screenshot-1.gif';
214
-
215
  $html = '<img src="'.$src.'" width="100%">';
216
 
217
  return $html;
58
  {
59
  $month = get_option('atlt_translation_month');
60
  $today = ('atlt_translation_day');
61
+ // do_action('testRequest');
62
  $total_translation = get_option('atlt_month_translated_chars', 0);
63
  $todays_total_translation = get_option('atlt_perday_translated_chars', 0);
64
  $a_per_day=0;
123
  <th>'.number_format($pro_per_mon).' / Month</th>
124
  </tr>
125
  </table>';
126
+
127
  $settingArr[]=array(
128
  'name' => $this->PREFIX.'api-key',
129
  'id' => $this->PREFIX.'api-key',
211
  public function screenshort(){
212
 
213
  $src = ATLT_URL .'assets/images/screenshot-1.gif';
 
214
  $html = '<img src="'.$src.'" width="100%">';
215
 
216
  return $html;
includes/Register/LocoAutomaticTranslateAddonPro.php CHANGED
@@ -170,6 +170,11 @@ require_once "LocoAutomaticTranslateAddonProBase.php";
170
  <td>Quick Support Via Email<br/><strong>contact@coolplugins.net</strong></td>
171
  <td>WordPress Free Forum Support!<br/><strong>(Support Time: 7 – 10 days)</strong></td>
172
  </tr>
 
 
 
 
 
173
  </table>
174
  <br/>
175
  <h3><a href='https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/' target='_blank'>Buy Premium License Key - <strong>Just $9 / Half Year</strong> or <strong>$15 / Year</strong></a></h3>
170
  <td>Quick Support Via Email<br/><strong>contact@coolplugins.net</strong></td>
171
  <td>WordPress Free Forum Support!<br/><strong>(Support Time: 7 – 10 days)</strong></td>
172
  </tr>
173
+ <tr>
174
+ <td>HTML Support</td>
175
+ <td><strong>Yes</strong></td>
176
+ <td>No</td>
177
+ </tr>
178
  </table>
179
  <br/>
180
  <h3><a href='https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/' target='_blank'>Buy Premium License Key - <strong>Just $9 / Half Year</strong> or <strong>$15 / Year</strong></a></h3>
readme.txt CHANGED
@@ -14,9 +14,9 @@ Automatic language translator add-on for Loco Translate plugin to translate Word
14
 
15
  **Automatic Machine Translator Addon For Loco Translate**
16
 
17
- Install this plugin along with the famous **[Loco Translate](https://wordpress.org/plugins/loco-translate/)** plugin (**900,000+ Active Installations**) and automatically machine translate any WordPress plugin or theme translation files into any language.
18
 
19
- = Loco Addon Features ([LocoTranslate.com](https://locotranslate.com)): =
20
  * One-click translate any plugin or theme all translatable strings.
21
  * You can automatic translate upto **300,000 characters** daily free of cost (you can extend this limit via [premium license key](https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/)).
22
  * Check auto translations inside Loco build-in editor to manually edit any machine translated string.
@@ -27,6 +27,8 @@ Install this plugin along with the famous **[Loco Translate](https://wordpress.o
27
  = FREE v/s Premium License Key: =
28
  * Free License - can automatic transalte **300,000 characters / day** & **1,000,000 characters / month**.
29
  * Premium License - can automatic translate **1,000,000 characters** / day & **10,000,000 characters / month**.
 
 
30
  * Free License Users - can ask for support only via WordPress Support Forum (**Support time:- 7-10 days**).
31
  * Premium License Users - will receive quick support via email - contact@coolplugins.net (**Support time:- 24-48 hours**).
32
  * Buy Premium License - **[$9 / Half Year](https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/)** or **[$15 / Year](https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/)**
@@ -73,6 +75,22 @@ For **premium license** users:- The volume of the text translated: 1,000,000 cha
73
  3. Free License v/s Premium License
74
 
75
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  <strong>Version 1.3.2 | 13 DEC 2019</strong>
77
  <pre>
78
  Added:Integrated URL and link filters in String
14
 
15
  **Automatic Machine Translator Addon For Loco Translate**
16
 
17
+ Install this plugin along with the famous **[Loco Translate](https://wordpress.org/plugins/loco-translate/)** plugin (**1+ Million Active Installations**) and automatically machine translate any WordPress plugin or theme translation files into any language.
18
 
19
+ = Loco Addon Features: =
20
  * One-click translate any plugin or theme all translatable strings.
21
  * You can automatic translate upto **300,000 characters** daily free of cost (you can extend this limit via [premium license key](https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/)).
22
  * Check auto translations inside Loco build-in editor to manually edit any machine translated string.
27
  = FREE v/s Premium License Key: =
28
  * Free License - can automatic transalte **300,000 characters / day** & **1,000,000 characters / month**.
29
  * Premium License - can automatic translate **1,000,000 characters** / day & **10,000,000 characters / month**.
30
+ * Free License - can only automatic translate **plain text strings**.
31
+ * Premium License - can also automatic translate **strings with HTML**.
32
  * Free License Users - can ask for support only via WordPress Support Forum (**Support time:- 7-10 days**).
33
  * Premium License Users - will receive quick support via email - contact@coolplugins.net (**Support time:- 24-48 hours**).
34
  * Buy Premium License - **[$9 / Half Year](https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/)** or **[$15 / Year](https://locotranslate.com/addon/loco-automatic-translate-premium-license-key/)**
75
  3. Free License v/s Premium License
76
 
77
  == Changelog ==
78
+ <strong>Version 1.4.1 | 8 JAN 2020</strong>
79
+ <pre>
80
+ Fixed:Minor JS bug fixes
81
+ </pre>
82
+ <strong>Version 1.4 | 31 DEC 2019</strong>
83
+ <pre>
84
+ Added: Integrated HTML String Translation Feature
85
+ Added: Supported Norwegian and other missing languages
86
+ Added: Integrated Translation settings popup.
87
+ Imporved: Optimized code
88
+ Improved: Updated Preloader
89
+ Fixed: Unsaved string highlighting issue
90
+ Fixed: minor JS issues
91
+ Fixed: Wrong characters calculation bug
92
+
93
+ </pre>
94
  <strong>Version 1.3.2 | 13 DEC 2019</strong>
95
  <pre>
96
  Added:Integrated URL and link filters in String