ajax-cat 1.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -1
- data/Gemfile.lock +4 -3
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/ajax-cat.gemspec +10 -5
- data/ajax-cat_old.ini.json +15 -0
- data/lib/ajax-cat.rb +5 -0
- data/lib/ajax-cat/ajax_cat_server.rb +39 -16
- data/lib/ajax-cat/pairs.rb +3 -1
- data/lib/ajax-cat/public/AjaxCatList.coffee +11 -3
- data/lib/ajax-cat/public/AjaxCatTranslation.coffee +36 -12
- data/lib/ajax-cat/public/Suggestions.coffee +12 -3
- data/lib/ajax-cat/public/TranslationTable.coffee +20 -1
- data/lib/ajax-cat/public/Utils.coffee +16 -0
- data/lib/ajax-cat/public/ajax-cat.js +111 -16
- data/lib/ajax-cat/public/cookie.js +72 -0
- data/lib/ajax-cat/public/index.html +1 -1
- data/lib/ajax-cat/public/translation.html +13 -7
- data/lib/ajax-cat/request/suggestion.rb +12 -2
- data/lib/ajax-cat/views/admin.erb +65 -16
- data/lib/ajax-cat/views/experiment.erb +62 -7
- data/test/unit/test_suggestion_request.rb +18 -6
- metadata +39 -26
@@ -44,3 +44,19 @@ class Utils
|
|
44
44
|
|
45
45
|
@trim: (text) =>
|
46
46
|
return text.replace(/^\s+|\s+$/g, "")
|
47
|
+
|
48
|
+
@edit_distance: (source, target) ->
|
49
|
+
a = []
|
50
|
+
for i in [0..source.length]
|
51
|
+
a[i] = new Array(target.length + 1)
|
52
|
+
a[i][0] = i
|
53
|
+
a[0] = [0..target.length]
|
54
|
+
|
55
|
+
for i in [1..source.length]
|
56
|
+
for j in [1..target.length]
|
57
|
+
substitute_cost = a[i - 1][j - 1]
|
58
|
+
substitute_cost += 1 if (source.charAt(i - 1) != target.charAt(j - 1))
|
59
|
+
a[i][j] = Math.min(substitute_cost, a[i-1][j] + 1, a[i][j-1] + 1)
|
60
|
+
return a[source.length][target.length]
|
61
|
+
|
62
|
+
|
@@ -40,6 +40,7 @@ AjaxCatList = (function() {
|
|
40
40
|
alert("Write your email, please.");
|
41
41
|
return;
|
42
42
|
}
|
43
|
+
$.cookie("email", email);
|
43
44
|
return $.ajax("/admin/get_experiment", {
|
44
45
|
data: {
|
45
46
|
email: email,
|
@@ -48,7 +49,7 @@ AjaxCatList = (function() {
|
|
48
49
|
success: function(data) {
|
49
50
|
var id;
|
50
51
|
data = JSON.parse(data);
|
51
|
-
id = _this.add_translation(data.
|
52
|
+
id = _this.add_translation(JSON.parse(data.sentences), "EXPERIMENT #" + data.task_id + ", " + data.email, data.pair, data.task_id, data.email, data);
|
52
53
|
return window.location = "/translation.html#" + id;
|
53
54
|
},
|
54
55
|
error: function() {
|
@@ -60,6 +61,7 @@ AjaxCatList = (function() {
|
|
60
61
|
AjaxCatList.prototype.new_experiment_translation = function() {
|
61
62
|
var _this = this;
|
62
63
|
$("#new-experiment-pair").html("");
|
64
|
+
$("#new-experiment-email").val($.cookie("email"));
|
63
65
|
return $.ajax("/api/info", {
|
64
66
|
success: function(data) {
|
65
67
|
var p, _i, _len, _ref;
|
@@ -138,7 +140,7 @@ AjaxCatList = (function() {
|
|
138
140
|
return this.show_translations();
|
139
141
|
};
|
140
142
|
|
141
|
-
AjaxCatList.prototype.add_translation = function(text, name, pair, task_id, email) {
|
143
|
+
AjaxCatList.prototype.add_translation = function(text, name, pair, task_id, email, experiment_data) {
|
142
144
|
var doc, docs;
|
143
145
|
if (task_id == null) task_id = false;
|
144
146
|
if (email == null) email = false;
|
@@ -153,7 +155,12 @@ AjaxCatList = (function() {
|
|
153
155
|
doc.pair = pair;
|
154
156
|
doc.email = email;
|
155
157
|
doc.task_id = task_id;
|
156
|
-
|
158
|
+
if (jQuery.isArray(text)) {
|
159
|
+
doc.source = text;
|
160
|
+
doc.options = JSON.parse(experiment_data.options);
|
161
|
+
} else {
|
162
|
+
doc.source = Utils.split_source(text);
|
163
|
+
}
|
157
164
|
doc.target = new Array(doc.source.length);
|
158
165
|
docs.push(doc.id);
|
159
166
|
localStorage.setItem('ac-data', JSON.stringify(docs));
|
@@ -169,6 +176,10 @@ AjaxCatTranslation = (function() {
|
|
169
176
|
|
170
177
|
AjaxCatTranslation.prototype.cur_position = false;
|
171
178
|
|
179
|
+
AjaxCatTranslation.prototype.experiment = false;
|
180
|
+
|
181
|
+
AjaxCatTranslation.prototype.param_suggestion = true;
|
182
|
+
|
172
183
|
function AjaxCatTranslation() {
|
173
184
|
this.add_words = __bind(this.add_words, this);
|
174
185
|
this.change_position = __bind(this.change_position, this);
|
@@ -179,6 +190,7 @@ AjaxCatTranslation = (function() {
|
|
179
190
|
this.resize = __bind(this.resize, this);
|
180
191
|
this.log = __bind(this.log, this);
|
181
192
|
this.prepare_test = __bind(this.prepare_test, this);
|
193
|
+
this.change_experiment_sentence = __bind(this.change_experiment_sentence, this);
|
182
194
|
this.time = __bind(this.time, this);
|
183
195
|
var data, i, s, t, _i, _j, _len, _len2, _ref, _ref2,
|
184
196
|
_this = this;
|
@@ -235,16 +247,16 @@ AjaxCatTranslation = (function() {
|
|
235
247
|
return setTimeout(this.time, 10);
|
236
248
|
};
|
237
249
|
|
238
|
-
AjaxCatTranslation.prototype.
|
250
|
+
AjaxCatTranslation.prototype.change_experiment_sentence = function() {
|
239
251
|
var _this = this;
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
$("#send-experiment").click(function() {
|
252
|
+
if (this.cur_position + 1 < this.doc.source.length) {
|
253
|
+
return this.change_position(this.cur_position + 1);
|
254
|
+
} else {
|
244
255
|
$("#send-experiment").hide();
|
245
256
|
return $.ajax("/admin/save_experiment", {
|
246
257
|
data: {
|
247
|
-
|
258
|
+
"log_id": this.doc.task_id,
|
259
|
+
log: JSON.stringify(this.doc)
|
248
260
|
},
|
249
261
|
type: "post",
|
250
262
|
success: function() {
|
@@ -255,6 +267,20 @@ AjaxCatTranslation = (function() {
|
|
255
267
|
return alert("Could not save experiment.");
|
256
268
|
}
|
257
269
|
});
|
270
|
+
}
|
271
|
+
};
|
272
|
+
|
273
|
+
AjaxCatTranslation.prototype.prepare_test = function() {
|
274
|
+
var _this = this;
|
275
|
+
AjaxCatList.delete_document(this.hash);
|
276
|
+
this.experiment = true;
|
277
|
+
$("#save").hide();
|
278
|
+
$("#experiment-settings").show();
|
279
|
+
$("#top-translations").hide();
|
280
|
+
$("#bottom-translations").hide();
|
281
|
+
$("#send-experiment").show();
|
282
|
+
$("#send-experiment").click(function() {
|
283
|
+
return _this.change_experiment_sentence();
|
258
284
|
});
|
259
285
|
this.doc.log = [];
|
260
286
|
this.time();
|
@@ -273,7 +299,10 @@ AjaxCatTranslation = (function() {
|
|
273
299
|
};
|
274
300
|
if (type) new_log.type = type;
|
275
301
|
if (param) new_log.param = param;
|
276
|
-
this.doc.log.
|
302
|
+
if (this.doc.log[this.cur_position] === void 0) {
|
303
|
+
this.doc.log[this.cur_position] = [];
|
304
|
+
}
|
305
|
+
this.doc.log[this.cur_position].push(new_log);
|
277
306
|
return $("#log").append(JSON.stringify(new_log) + "<br>");
|
278
307
|
};
|
279
308
|
|
@@ -357,6 +386,7 @@ AjaxCatTranslation = (function() {
|
|
357
386
|
|
358
387
|
AjaxCatTranslation.prototype.load_translation_table = function(sentence) {
|
359
388
|
var _this = this;
|
389
|
+
if (this.table_request) this.table_request.abort();
|
360
390
|
sentence = Utils.tokenize(sentence);
|
361
391
|
if (sentence.match(/^[\ \t]*$/)) {
|
362
392
|
$("#translation-table-container").html("");
|
@@ -364,7 +394,7 @@ AjaxCatTranslation = (function() {
|
|
364
394
|
return;
|
365
395
|
}
|
366
396
|
$("#translation-table-container").text("");
|
367
|
-
return $.ajax("/api/table", {
|
397
|
+
return this.table_request = $.ajax("/api/table", {
|
368
398
|
data: {
|
369
399
|
pair: this.pair,
|
370
400
|
q: sentence
|
@@ -379,6 +409,18 @@ AjaxCatTranslation = (function() {
|
|
379
409
|
};
|
380
410
|
|
381
411
|
AjaxCatTranslation.prototype.change_position = function(position) {
|
412
|
+
if (this.experiment) {
|
413
|
+
if (!((position === 0 && this.cur_position === false) || (this.cur_position + 1 === position))) {
|
414
|
+
return;
|
415
|
+
}
|
416
|
+
this.param_suggestion = this.doc.options[position].suggestion;
|
417
|
+
$("#suggestion-panel-is-on").text(this.param_suggestion);
|
418
|
+
$("#translated-status").text("translating sentence " + (position + 1) + " out of " + this.doc.source.length);
|
419
|
+
if ((position + 1) === this.doc.source.length) {
|
420
|
+
$("#send-experiment").text("Finish experiment");
|
421
|
+
}
|
422
|
+
}
|
423
|
+
this.suggestions.clear();
|
382
424
|
if (this.cur_position !== false) this.save_target();
|
383
425
|
$("#source-top").children().slice(0, position).show();
|
384
426
|
$("#source-top").children().slice(position, this.length).hide();
|
@@ -453,6 +495,7 @@ Suggestions = (function() {
|
|
453
495
|
}
|
454
496
|
|
455
497
|
Suggestions.prototype.clear = function() {
|
498
|
+
if (this.suggestion_request) this.suggestion_request.abort();
|
456
499
|
$(".ac-suggestion").text("");
|
457
500
|
$(".ac-suggestion").removeClass('suggestion-enabled');
|
458
501
|
return $(".ac-suggestion").removeClass('suggestion-active');
|
@@ -462,11 +505,12 @@ Suggestions = (function() {
|
|
462
505
|
var covered, sentence, translated,
|
463
506
|
_this = this;
|
464
507
|
this.clear();
|
508
|
+
if (!this.translation.param_suggestion) return;
|
465
509
|
sentence = $("#source-sentence").text();
|
466
510
|
sentence = Utils.tokenize(sentence);
|
467
511
|
translated = Utils.tokenize($("#source-target").text());
|
468
512
|
covered = this.translation.table.covered_vector();
|
469
|
-
return $.ajax("/api/suggestion", {
|
513
|
+
return this.suggestion_request = $.ajax("/api/suggestion", {
|
470
514
|
data: {
|
471
515
|
pair: this.translation.pair,
|
472
516
|
q: Utils.tokenize(sentence),
|
@@ -482,11 +526,13 @@ Suggestions = (function() {
|
|
482
526
|
};
|
483
527
|
|
484
528
|
Suggestions.prototype.take_suggestion = function() {
|
485
|
-
var text;
|
529
|
+
var from, text, to;
|
486
530
|
if (this.get_position() === false) return;
|
487
531
|
text = $(".suggestion-active span").text();
|
532
|
+
from = $(".suggestion-active").data('from');
|
533
|
+
to = $(".suggestion-active").data('to');
|
488
534
|
this.translation.add_words(text);
|
489
|
-
return this.translation.table.
|
535
|
+
return this.translation.table.mark_interval(from, to);
|
490
536
|
};
|
491
537
|
|
492
538
|
Suggestions.prototype.process_suggestions = function(data) {
|
@@ -498,7 +544,9 @@ Suggestions = (function() {
|
|
498
544
|
suggestion = _ref[_i];
|
499
545
|
translation = $("#target-sentence").val();
|
500
546
|
el = $(".ac-suggestion").slice(i, i + 1);
|
501
|
-
el.html("" + translation + " <span>" + suggestion + "</span>");
|
547
|
+
el.html("" + translation + " <span>" + suggestion.text + "</span>");
|
548
|
+
el.data('from', suggestion.from);
|
549
|
+
el.data('to', suggestion.to);
|
502
550
|
el.addClass('suggestion-enabled');
|
503
551
|
_results.push(i += 1);
|
504
552
|
}
|
@@ -550,6 +598,7 @@ TranslationTable = (function() {
|
|
550
598
|
this.unmark_position = __bind(this.unmark_position, this);
|
551
599
|
this.mark_position = __bind(this.mark_position, this);
|
552
600
|
this.mark_interval = __bind(this.mark_interval, this);
|
601
|
+
this.mark_words_OLD = __bind(this.mark_words_OLD, this);
|
553
602
|
this.mark_words = __bind(this.mark_words, this);
|
554
603
|
this.position_marked = __bind(this.position_marked, this);
|
555
604
|
this.get_row = __bind(this.get_row, this);
|
@@ -643,8 +692,32 @@ TranslationTable = (function() {
|
|
643
692
|
return false;
|
644
693
|
};
|
645
694
|
|
646
|
-
TranslationTable.prototype.mark_words = function(
|
695
|
+
TranslationTable.prototype.mark_words = function(word) {
|
696
|
+
var best_element, best_result, el, element_text, maximal_acceptable_distance, result, _i, _len, _ref;
|
697
|
+
word = Utils.trim(word);
|
698
|
+
best_result = 10000;
|
699
|
+
best_element = null;
|
700
|
+
maximal_acceptable_distance = 1;
|
701
|
+
if (word.length < 5) maximal_acceptable_distance = 0;
|
702
|
+
if (word.length > 10) maximal_acceptable_distance = 2;
|
703
|
+
_ref = $(".ac-word div");
|
704
|
+
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
705
|
+
el = _ref[_i];
|
706
|
+
element_text = Utils.trim($(el).text());
|
707
|
+
result = Utils.edit_distance(word, element_text);
|
708
|
+
if (result < best_result) {
|
709
|
+
best_result = result;
|
710
|
+
best_element = $(el);
|
711
|
+
}
|
712
|
+
}
|
713
|
+
if (best_element !== null && best_result <= maximal_acceptable_distance) {
|
714
|
+
return this.mark_interval(best_element.data('position-from'), best_element.data('position-to'));
|
715
|
+
}
|
716
|
+
};
|
717
|
+
|
718
|
+
TranslationTable.prototype.mark_words_OLD = function(words) {
|
647
719
|
var el, el_text, _i, _len, _ref;
|
720
|
+
console.log("MARKING WORDS: " + words);
|
648
721
|
words = "" + words + " ";
|
649
722
|
_ref = $(".ac-word div");
|
650
723
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
@@ -761,6 +834,28 @@ Utils = (function() {
|
|
761
834
|
return text.replace(/^\s+|\s+$/g, "");
|
762
835
|
};
|
763
836
|
|
837
|
+
Utils.edit_distance = function(source, target) {
|
838
|
+
var a, i, j, substitute_cost, _i, _ref, _ref2, _ref3, _ref4, _results;
|
839
|
+
a = [];
|
840
|
+
for (i = 0, _ref = source.length; 0 <= _ref ? i <= _ref : i >= _ref; 0 <= _ref ? i++ : i--) {
|
841
|
+
a[i] = new Array(target.length + 1);
|
842
|
+
a[i][0] = i;
|
843
|
+
}
|
844
|
+
a[0] = (function() {
|
845
|
+
_results = [];
|
846
|
+
for (var _i = 0, _ref2 = target.length; 0 <= _ref2 ? _i <= _ref2 : _i >= _ref2; 0 <= _ref2 ? _i++ : _i--){ _results.push(_i); }
|
847
|
+
return _results;
|
848
|
+
}).apply(this);
|
849
|
+
for (i = 1, _ref3 = source.length; 1 <= _ref3 ? i <= _ref3 : i >= _ref3; 1 <= _ref3 ? i++ : i--) {
|
850
|
+
for (j = 1, _ref4 = target.length; 1 <= _ref4 ? j <= _ref4 : j >= _ref4; 1 <= _ref4 ? j++ : j--) {
|
851
|
+
substitute_cost = a[i - 1][j - 1];
|
852
|
+
if (source.charAt(i - 1) !== target.charAt(j - 1)) substitute_cost += 1;
|
853
|
+
a[i][j] = Math.min(substitute_cost, a[i - 1][j] + 1, a[i][j - 1] + 1);
|
854
|
+
}
|
855
|
+
}
|
856
|
+
return a[source.length][target.length];
|
857
|
+
};
|
858
|
+
|
764
859
|
return Utils;
|
765
860
|
|
766
861
|
}).call(this);
|
@@ -0,0 +1,72 @@
|
|
1
|
+
/*jshint eqnull:true */
|
2
|
+
/*!
|
3
|
+
* jQuery Cookie Plugin v1.2
|
4
|
+
* https://github.com/carhartl/jquery-cookie
|
5
|
+
*
|
6
|
+
* Copyright 2011, Klaus Hartl
|
7
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
8
|
+
* http://www.opensource.org/licenses/mit-license.php
|
9
|
+
* http://www.opensource.org/licenses/GPL-2.0
|
10
|
+
*/
|
11
|
+
(function ($, document, undefined) {
|
12
|
+
|
13
|
+
var pluses = /\+/g;
|
14
|
+
|
15
|
+
function raw(s) {
|
16
|
+
return s;
|
17
|
+
}
|
18
|
+
|
19
|
+
function decoded(s) {
|
20
|
+
return decodeURIComponent(s.replace(pluses, ' '));
|
21
|
+
}
|
22
|
+
|
23
|
+
$.cookie = function (key, value, options) {
|
24
|
+
|
25
|
+
// key and at least value given, set cookie...
|
26
|
+
if (value !== undefined && !/Object/.test(Object.prototype.toString.call(value))) {
|
27
|
+
options = $.extend({}, $.cookie.defaults, options);
|
28
|
+
|
29
|
+
if (value === null) {
|
30
|
+
options.expires = -1;
|
31
|
+
}
|
32
|
+
|
33
|
+
if (typeof options.expires === 'number') {
|
34
|
+
var days = options.expires, t = options.expires = new Date();
|
35
|
+
t.setDate(t.getDate() + days);
|
36
|
+
}
|
37
|
+
|
38
|
+
value = String(value);
|
39
|
+
|
40
|
+
return (document.cookie = [
|
41
|
+
encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
|
42
|
+
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
43
|
+
options.path ? '; path=' + options.path : '',
|
44
|
+
options.domain ? '; domain=' + options.domain : '',
|
45
|
+
options.secure ? '; secure' : ''
|
46
|
+
].join(''));
|
47
|
+
}
|
48
|
+
|
49
|
+
// key and possibly options given, get cookie...
|
50
|
+
options = value || $.cookie.defaults || {};
|
51
|
+
var decode = options.raw ? raw : decoded;
|
52
|
+
var cookies = document.cookie.split('; ');
|
53
|
+
for (var i = 0, parts; (parts = cookies[i] && cookies[i].split('=')); i++) {
|
54
|
+
if (decode(parts.shift()) === key) {
|
55
|
+
return decode(parts.join('='));
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
return null;
|
60
|
+
};
|
61
|
+
|
62
|
+
$.cookie.defaults = {};
|
63
|
+
|
64
|
+
$.removeCookie = function (key, options) {
|
65
|
+
if ($.cookie(key, options) !== null) {
|
66
|
+
$.cookie(key, null, options);
|
67
|
+
return true;
|
68
|
+
}
|
69
|
+
return false;
|
70
|
+
};
|
71
|
+
|
72
|
+
})(jQuery, document);
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<link rel="stylesheet" type="text/css" href="/bootstrap.css" />
|
7
7
|
<link rel="stylesheet" type="text/css" href="/style.css" />
|
8
8
|
<script src="/jquery.js"></script>
|
9
|
-
<script src="/
|
9
|
+
<script src="/cookie.js"></script>
|
10
10
|
<script src="/bootstrap.js"></script>
|
11
11
|
<script src="/ajax-cat.js"></script>
|
12
12
|
<script src="/index.js"></script>
|
@@ -30,9 +30,6 @@
|
|
30
30
|
<li><a href="#about" id="preview">Preview</a></li>
|
31
31
|
</ul>
|
32
32
|
<p class="pull-right">
|
33
|
-
<button class="btn btn-info" id="send-experiment">
|
34
|
-
Send experiment results
|
35
|
-
</button>
|
36
33
|
<button class="btn btn-info" id="save">
|
37
34
|
Save into browser
|
38
35
|
</button>
|
@@ -47,10 +44,13 @@
|
|
47
44
|
<div class="container-fluid">
|
48
45
|
<div class="row-fluid">
|
49
46
|
<h1>Translations</h1>
|
50
|
-
<span id="time"></span>
|
47
|
+
<h2><span id="translated-status"></span> <span id="time"></span></h2>
|
48
|
+
<button class="btn btn-info btn-large" id="send-experiment">
|
49
|
+
Next sentence >
|
50
|
+
</button>
|
51
51
|
|
52
52
|
<table class=" table-bordered table-condensed" id="translation">
|
53
|
-
<tr>
|
53
|
+
<tr id="top-translations">
|
54
54
|
<td width="50%" id="source-top"></td>
|
55
55
|
<td width="50%" id="target-top"></td>
|
56
56
|
</tr>
|
@@ -62,7 +62,7 @@
|
|
62
62
|
<div id="translation-table-container"></div>
|
63
63
|
</td>
|
64
64
|
</tr>
|
65
|
-
<tr>
|
65
|
+
<tr id="bottom-translations">
|
66
66
|
<td id="source-bottom"></td>
|
67
67
|
<td id="target-bottom"></td>
|
68
68
|
</tr>
|
@@ -70,7 +70,13 @@
|
|
70
70
|
|
71
71
|
</div><!--/row-->
|
72
72
|
|
73
|
-
<div id="
|
73
|
+
<div id="experiment-settings" style="display: none;">
|
74
|
+
<h2>Current experiment settings</h2>
|
75
|
+
<table class="table">
|
76
|
+
<tr><th>Suggestion panel:</th><td id="suggestion-panel-is-on"></td></tr>
|
77
|
+
</table>
|
78
|
+
</div>
|
79
|
+
<div id="log" style="display: none;"></div>
|
74
80
|
|
75
81
|
<hr>
|
76
82
|
|
@@ -13,6 +13,7 @@ module AjaxCat
|
|
13
13
|
@translated = translated
|
14
14
|
@translated_length = tokenize(translated).length
|
15
15
|
@suggestions = []
|
16
|
+
@suggested_phrases = []
|
16
17
|
end
|
17
18
|
|
18
19
|
def prepare_moses_request
|
@@ -28,8 +29,17 @@ module AjaxCat
|
|
28
29
|
def process_line(line)
|
29
30
|
words = line.split(" ||| ")[1].strip.split(" ")
|
30
31
|
if @suggestions.length < @@rows
|
31
|
-
|
32
|
-
|
32
|
+
alignment = line.split(" ||| ")[4].strip.split(" ").first
|
33
|
+
phrase = Phrase.new(words, alignment)
|
34
|
+
suggestion = {
|
35
|
+
"text" => phrase.words,
|
36
|
+
"from" => phrase.from,
|
37
|
+
"to" => phrase.to
|
38
|
+
}
|
39
|
+
if not @suggested_phrases.member?(suggestion['text'])
|
40
|
+
@suggested_phrases.push(suggestion['text'])
|
41
|
+
@suggestions.push(suggestion)
|
42
|
+
end
|
33
43
|
end
|
34
44
|
end
|
35
45
|
|