From 0335afa8836ba2c5129de94b65d863b732ec2b50 Mon Sep 17 00:00:00 2001 From: Sai Vineet Date: Wed, 6 Jan 2016 18:13:45 +0530 Subject: [PATCH 01/21] Make suggestions optional --- assets/js/translator.js | 37 +++++++++++++++++++++++++++++++++++++ config.conf.example | 6 ++++++ 2 files changed, 43 insertions(+) diff --git a/assets/js/translator.js b/assets/js/translator.js index 6067e4678..281411f0a 100644 --- a/assets/js/translator.js +++ b/assets/js/translator.js @@ -491,6 +491,43 @@ function translateText() { if(data.responseStatus === HTTP_OK_CODE) { $('#translatedText').html(data.responseData.translatedText); $('#translatedText').removeClass('notAvailable text-danger'); + + $('#translatedText').attr('pristineText', data.responseData.translatedText); + + if(config.SUGGESTIONS.enabled === 'True') { + $('#translatedText').html( + $('#translatedText').html().replace( + /(\*\S+|\@\S+|\#\S+)/g, + '$1')); + } + $('#translatedTextClone').html( + $('#translatedText').attr('pristineText')); + + $('.wordSuggestPop').click(function() { + $('.wordSuggestPop').removeAttr('id'); + $('.wordSuggestPopInline').removeAttr('id'); + $(this).attr('id', 'wordGettingSuggested'); + + $('#translatedTextClone').html( + $('#translatedTextClone').html().replace( + /(\*\S+|\@\S+|\#\S+)/g, + '$1')); + + $('.wordSuggestPopInline').click(function() { + $('.wordSuggestPop').removeAttr('id'); + $('.wordSuggestPopInline').removeAttr('id'); + $(this).attr('id', 'wordGettingSuggested'); + + $('#suggestionTargetWord').html($(this).text()); + $('#suggestedWordInput').val(''); + }); + + console.log(dynamicLocalizations['Suggest_Sentence']); + $('#suggestSentenceContainer').html( + dynamicLocalizations['Suggest_Sentence'].replace('{{targetWordCode}}', '')) + $('#suggestionTargetWord').html($(this).text()); + $('#wordSuggestModal').modal(); + }); } else { translationNotAvailable(); diff --git a/config.conf.example b/config.conf.example index 3465b1265..6821b9960 100644 --- a/config.conf.example +++ b/config.conf.example @@ -24,3 +24,9 @@ AVAILABLE_LOCALES_CACHE_EXPIRY = 24 # Localisation replacement strings, see assets/strings/*.json for usage: [REPLACEMENTS] maintainer = Apertium + +[SUGGESTIONS] +ENABLED = True +RECAPTCHA_SITE_KEY = None +CONTEXT_WRAP = 5 + From 311126f52f333805331c85bae646db371d53a140 Mon Sep 17 00:00:00 2001 From: Sai Vineet Date: Sun, 17 Jan 2016 16:23:45 +0530 Subject: [PATCH 02/21] Fixes for suggestions --- assets/js/translator.js | 2 +- read-conf.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/assets/js/translator.js b/assets/js/translator.js index 281411f0a..71fa73b7c 100644 --- a/assets/js/translator.js +++ b/assets/js/translator.js @@ -494,7 +494,7 @@ function translateText() { $('#translatedText').attr('pristineText', data.responseData.translatedText); - if(config.SUGGESTIONS.enabled === 'True') { + if(config.SUGGESTIONS.enabled) { $('#translatedText').html( $('#translatedText').html().replace( /(\*\S+|\@\S+|\#\S+)/g, diff --git a/read-conf.py b/read-conf.py index ba71cabcf..8d9edb2b2 100755 --- a/read-conf.py +++ b/read-conf.py @@ -52,6 +52,12 @@ def load_conf(filename): 'AVAILABLE_LOCALES_CACHE_EXPIRY' : conf_APY.getint('AVAILABLE_LOCALES_CACHE_EXPIRY', fallback=24), 'REPLACEMENTS' : {k: v for k, v in conf['REPLACEMENTS'].items()}, + + 'SUGGESTIONS' : { + 'enabled': conf['SUGGESTIONS'].getboolean('ENABLED'), + 'recaptcha_site_key': conf['SUGGESTIONS'].get('RECAPTCHA_SITE_KEY'), + 'context_wrap': conf['SUGGESTIONS'].get('CONTEXT_WRAP') + }, } check_config(conf, result) return result From 03b19653b5349725422597504bed5bf2d2b9702d Mon Sep 17 00:00:00 2001 From: Kira Date: Mon, 6 Jun 2016 14:56:35 +0200 Subject: [PATCH 03/21] captcha reset added and right wrap context fixed --- assets/js/translator.js | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/assets/js/translator.js b/assets/js/translator.js index 71fa73b7c..41e33a34c 100644 --- a/assets/js/translator.js +++ b/assets/js/translator.js @@ -199,6 +199,87 @@ if(modeEnabled('translation')) { $('a#fileDownload').fadeOut('fast'); }); + $('#translatedText').css('height', $('#originalText').css('height')); + $('#suggestBtn').click(function() { + var fromWord = $('#suggestionTargetWord').html(); + var toWord = $('#suggestedWordInput').val(); + var recaptchaResponse = grecaptcha.getResponse(); + + if(toWord.length === 0) { + $('#suggestedWordInput').tooltip('destroy'); + $('#suggestedWordInput').tooltip({ + 'title': 'Suggestion cannot be empty.', + 'trigger': 'manual', + 'placement': 'bottom' + }); + $('#suggestedWordInput').tooltip('show') + setTimeout(function() { + $('#suggestedWordInput').tooltip('hide'); + $('#suggestedWordInput').tooltip('destroy'); + }, 3000); + + return; + } + + // Obtaining context, (± config.SUGGESTIONS.context_wrap) words + // fallback to complete text if this fails. + var hashedWord = fromWord.hashCode() + fromWord + fromWord.hashCode(); + $('#wordGettingSuggested').text(hashedWord); + + var splitted = $('#translatedText').text().split(' '); + $('#wordGettingSuggested').text(fromWord) + + var targetIndex = splitted.indexOf(hashedWord); + var wrapLength = parseInt(config.SUGGESTIONS.context_wrap); + var begin, end; + begin = (targetIndex > wrapLength)? (targetIndex-wrapLength): 0; + end = (splitted.length-targetIndex-1 > wrapLength)? (targetIndex+wrapLength+1): splitted.length; + + var context = splitted.slice(begin, end).join(' ').replace(hashedWord, fromWord); + if (!context) { + context = $('#translatedText').attr('pristineText'); + } + + $.ajax({ + url: config.APY_URL + '/suggest', + type: 'POST', + beforeSend: ajaxSend, + data: { + 'langpair': curSrcLang + '|' + curDstLang, + 'word': fromWord, + 'newWord': toWord, + 'context': context, + 'g-recaptcha-response': recaptchaResponse + }, + success: function (data) { + // console.log(data); + $('#suggestedWordInput').tooltip('hide'); + $('#suggestedWordInput').tooltip('destroy'); + $('#suggestedWordInput').val(''); + + $('#wordSuggestModal').modal('hide'); + }, + error: function (data) { + data = $.parseJSON(data.responseText); + $('#suggestedWordInput').tooltip('destroy'); + $('#suggestedWordInput').tooltip({ + 'title': (data['explanation'] ? data['explanation'] : 'An error occurred'), + 'trigger': 'manual', + 'placement': 'bottom' + }); + $('#suggestedWordInput').tooltip('show') + setTimeout(function() { + $('#suggestedWordInput').tooltip('hide'); + $('#suggestedWordInput').tooltip('destroy'); + }, 3000); + }, + complete: function(){ + ajaxComplete + grecaptcha.reset(); + } + }); + }); + $('body').on('dragover', function (ev) { ev.preventDefault(); return false; From 843dda6cf2f565adf1e4e100b2ff3e509e7ea057 Mon Sep 17 00:00:00 2001 From: Kira Date: Tue, 14 Jun 2016 11:45:11 +0200 Subject: [PATCH 04/21] Bugfix (*/@/# deleted from suggestion form) and style fixes --- assets/js/translator.js | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/assets/js/translator.js b/assets/js/translator.js index 41e33a34c..0524aad9d 100644 --- a/assets/js/translator.js +++ b/assets/js/translator.js @@ -232,8 +232,8 @@ if(modeEnabled('translation')) { var targetIndex = splitted.indexOf(hashedWord); var wrapLength = parseInt(config.SUGGESTIONS.context_wrap); var begin, end; - begin = (targetIndex > wrapLength)? (targetIndex-wrapLength): 0; - end = (splitted.length-targetIndex-1 > wrapLength)? (targetIndex+wrapLength+1): splitted.length; + begin = (targetIndex > wrapLength) ? (targetIndex - wrapLength) : 0; + end = (splitted.length - targetIndex - 1 > wrapLength) ? (targetIndex + wrapLength + 1) : splitted.length; var context = splitted.slice(begin, end).join(' ').replace(hashedWord, fromWord); if (!context) { @@ -252,7 +252,6 @@ if(modeEnabled('translation')) { 'g-recaptcha-response': recaptchaResponse }, success: function (data) { - // console.log(data); $('#suggestedWordInput').tooltip('hide'); $('#suggestedWordInput').tooltip('destroy'); $('#suggestedWordInput').val(''); @@ -273,10 +272,10 @@ if(modeEnabled('translation')) { $('#suggestedWordInput').tooltip('destroy'); }, 3000); }, - complete: function(){ - ajaxComplete - grecaptcha.reset(); - } + complete: function(){ + ajaxComplete + grecaptcha.reset(); + } }); }); @@ -577,9 +576,7 @@ function translateText() { if(config.SUGGESTIONS.enabled) { $('#translatedText').html( - $('#translatedText').html().replace( - /(\*\S+|\@\S+|\#\S+)/g, - '$1')); + $('#translatedText').html().replace(/(\*|\@|\#)(\S+)/g, '$2')); } $('#translatedTextClone').html( $('#translatedText').attr('pristineText')); @@ -590,23 +587,20 @@ function translateText() { $(this).attr('id', 'wordGettingSuggested'); $('#translatedTextClone').html( - $('#translatedTextClone').html().replace( - /(\*\S+|\@\S+|\#\S+)/g, - '$1')); + $('#translatedTextClone').html().replace(/(\*|\@|\#)(\S+)/g, '$2')); $('.wordSuggestPopInline').click(function() { $('.wordSuggestPop').removeAttr('id'); $('.wordSuggestPopInline').removeAttr('id'); $(this).attr('id', 'wordGettingSuggested'); - $('#suggestionTargetWord').html($(this).text()); + $('#suggestionTargetWord').html($(this).text().replace(/(\*|\@|\#)/g, '')); $('#suggestedWordInput').val(''); }); - console.log(dynamicLocalizations['Suggest_Sentence']); $('#suggestSentenceContainer').html( dynamicLocalizations['Suggest_Sentence'].replace('{{targetWordCode}}', '')) - $('#suggestionTargetWord').html($(this).text()); + $('#suggestionTargetWord').html($(this).text().replace(/(\*|\@|\#)/g, '')); $('#wordSuggestModal').modal(); }); } From d22834e1b7de08d54e9044609a304458ccba1059 Mon Sep 17 00:00:00 2001 From: Kira Date: Sun, 26 Jun 2016 13:43:55 +0200 Subject: [PATCH 05/21] Empty the suggestedWordInput --- assets/js/translator.js | 6 ++++++ index.html.in | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/assets/js/translator.js b/assets/js/translator.js index 0524aad9d..73197b7d5 100644 --- a/assets/js/translator.js +++ b/assets/js/translator.js @@ -200,6 +200,9 @@ if(modeEnabled('translation')) { }); $('#translatedText').css('height', $('#originalText').css('height')); + $('#suggestCloseBtn').click(function() { + $('#suggestedWordInput').val(''); + }); $('#suggestBtn').click(function() { var fromWord = $('#suggestionTargetWord').html(); var toWord = $('#suggestedWordInput').val(); @@ -578,6 +581,7 @@ function translateText() { $('#translatedText').html( $('#translatedText').html().replace(/(\*|\@|\#)(\S+)/g, '$2')); } + $('#translatedTextClone').html( $('#translatedText').attr('pristineText')); @@ -596,11 +600,13 @@ function translateText() { $('#suggestionTargetWord').html($(this).text().replace(/(\*|\@|\#)/g, '')); $('#suggestedWordInput').val(''); + }); $('#suggestSentenceContainer').html( dynamicLocalizations['Suggest_Sentence'].replace('{{targetWordCode}}', '')) $('#suggestionTargetWord').html($(this).text().replace(/(\*|\@|\#)/g, '')); + $('#wordSuggestModal').modal(); }); } diff --git a/index.html.in b/index.html.in index fa55e04be..5e18fd369 100644 --- a/index.html.in +++ b/index.html.in @@ -519,6 +519,32 @@ + +
From dcfb36891fbc9a2bf824c8cf33e12146f18c9d1b Mon Sep 17 00:00:00 2001 From: Kira Date: Sun, 26 Jun 2016 16:01:05 +0200 Subject: [PATCH 06/21] ReCaptcha widget localization --- assets/js/localization.js | 45 ++++++++++++++++++++++++++++++++++++++- assets/js/translator.js | 34 ++++++++++++++++++++++++++--- assets/strings/eng.json | 4 ++++ assets/strings/rus.json | 4 ++++ index.html.in | 6 +++--- 5 files changed, 86 insertions(+), 7 deletions(-) diff --git a/assets/js/localization.js b/assets/js/localization.js index faa5bec73..5b3654efc 100644 --- a/assets/js/localization.js +++ b/assets/js/localization.js @@ -11,9 +11,16 @@ var dynamicLocalizations = { 'detected': 'detected', 'File_Too_Large': 'File is too large!', 'Format_Not_Supported': 'Format not supported!', - 'Download_File': 'Download {{fileName}}' + 'Download_File': 'Download {{fileName}}', + 'Suggest_Sentence': 'How would you suggest we translate {{targetWordCode}}?', + 'Suggest_Title': 'Improve Apertium\'s translation', + 'Suggest_Placeholder': 'New word' }; +var localizeRecaptcha = ['ar', 'af', 'am', 'hy', 'az', 'eu', 'bn', 'bg', 'ca', 'zh-HK', 'zh-CN', 'zh-TW', 'hr', 'cs', 'da', 'nl', 'en-GB', 'en', 'et', 'fil', 'fi', 'fr', 'fr-CA', 'gl', 'ka', 'de', 'de-AT', 'de-CH', 'el', 'gu', 'iw', 'hi', 'hu', 'is', 'id', 'it', 'ja', 'kn', 'ko', 'lo', 'lv', 'lt', 'ms', 'ml', 'mr', 'mn', 'no', 'fa', 'pl', 'pt', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sr', 'si', 'sk', 'sl', 'es', 'es-419', 'sw', 'sv', 'ta', 'te', 'th', 'tr', 'uk', 'ur', 'vi', 'zu']; + +var localizeRecaptchaAlternative = {'zh': 'zh-TW', 'hrv': 'hr', 'srp': 'sr', 'msa': 'ms', 'cy': 'en', 'ga': 'en', 'gv': 'en', 'gd': 'en', 'rn': 'en', 'lg': 'en', 'mt': 'en', 'sq': 'fr', 'br': 'fr', 'se': 'no', 'eo': 'en', 'fo': 'da', 'ia': 'en', 'xh': 'af', 'mfe': 'fr', 'nb': 'no', 'nn': 'no', 'uz': 'ru', 'rm': 'en', 'tg': 'ru', 'ba': 'ru', 'be': 'ru', 'os': 'ru', 'kum': 'ru', 'ky': 'ru', 'mk': 'en', 'tt': 'ru', 'kk': 'ru', 'he': 'en', 'ne': 'hi', 'as': 'hi', 'pa': 'ur', 'mrj': 'ru', 'myv': 'ru', 'oc': 'es', 'cv': 'ru', 'arg': 'es', 'ast': 'es', 'hbs': 'en', 'bos':'en', 'nog': 'ru', 'sah': 'ru', 'uig': 'zh-TW', 'tyv': 'ru'}; + var localizedHTML = false; /* exported getLangByCode */ @@ -52,10 +59,46 @@ $(document).ready(function () { }); $('.localeSelect').change(function () { + locale = $(this).val(); sendEvent('localization', 'localize', locale); localizeEverything(false); persistChoices('localization'); + + var localLang = iso639Codes[locale]; + var newSrc = currentSrc + 'en'; + var backoff = false; + + for (var i = 0; i < localizeRecaptcha.length; i++) { + if (localLang == localizeRecaptcha[i]) { + newSrc = currentSrc + localLang; + backoff = false; + break + } + else { + backoff = true; + } + } + + if (backoff == true) { + newSrc = currentSrc + localizeRecaptchaAlternative[localLang]; + } + + var head= document.getElementsByTagName('head')[0]; + $('#recapscript').remove(); + + var script = document.createElement('script'); + script.src = newSrc; + script.id = 'recapscript'; + script.async = true; + script.defer = true; + $('#suggestRecaptcha').html(''); + head.appendChild(script); + + var placeholder = dynamicLocalizations['Suggest_Placeholder']; + $('#suggestedWordInput').removeAttr('placeholder'); + $('#suggestedWordInput').attr('placeholder', placeholder); + }); function localizeEverything(stringsFresh) { diff --git a/assets/js/translator.js b/assets/js/translator.js index 73197b7d5..f4cf1a2ea 100644 --- a/assets/js/translator.js +++ b/assets/js/translator.js @@ -4,6 +4,7 @@ var curSrcLang, curDstLang; var recentSrcLangs = [], recentDstLangs = []; var droppedFile; var textTranslateRequest; +var currentSrc = "https://www.google.com/recaptcha/api.js?onload=recaptchaRenderCallback&render=explicit&hl="; var TEXTAREA_AUTO_RESIZE_MINIMUM_WIDTH = 768, UPLOAD_FILE_SIZE_LIMIT = 32E6, @@ -17,6 +18,29 @@ if(modeEnabled('translation')) { $(document).ready(function () { synchronizeTextareaHeights(); + var localLang = iso639Codes[$('.localeSelect').val()]; + var newSrc = currentSrc + 'en'; + var backoff = false; + + for(var i = 0; i < localizeRecaptcha.length; i++) { + if (localLang == localizeRecaptcha[i]) { + newSrc = currentSrc + localLang; + backoff = false; + break + } + else { + backoff = true; + } + } + + if (backoff) { + newSrc = currentSrc + localizeRecaptchaAlternative[localLang]; + } + + $('#recapscript').attr('src', newSrc); + $('#recapscript').attr('async', ''); + $('#recapscript').attr('defer', ''); + $('#srcLanguages').on('click', '.languageName:not(.text-muted)', function () { curSrcLang = $(this).attr('data-code'); handleNewCurrentLang(curSrcLang, recentSrcLangs, 'srcLang'); @@ -202,6 +226,7 @@ if(modeEnabled('translation')) { $('#translatedText').css('height', $('#originalText').css('height')); $('#suggestCloseBtn').click(function() { $('#suggestedWordInput').val(''); + grecaptcha.reset(); }); $('#suggestBtn').click(function() { var fromWord = $('#suggestionTargetWord').html(); @@ -578,8 +603,11 @@ function translateText() { $('#translatedText').attr('pristineText', data.responseData.translatedText); if(config.SUGGESTIONS.enabled) { - $('#translatedText').html( - $('#translatedText').html().replace(/(\*|\@|\#)(\S+)/g, '$2')); + var localizedTitle = dynamicLocalizations['Suggest_Title']; + var placeholder = dynamicLocalizations['Suggest_Placeholder']; + $('#suggestedWordInput').attr('placeholder', placeholder); + $('#translatedText').html( + $('#translatedText').html().replace(/(\*|\@|\#)(\S+)/g, '$2')); } $('#translatedTextClone').html( @@ -591,7 +619,7 @@ function translateText() { $(this).attr('id', 'wordGettingSuggested'); $('#translatedTextClone').html( - $('#translatedTextClone').html().replace(/(\*|\@|\#)(\S+)/g, '$2')); + $('#translatedTextClone').html().replace(/(\*|\@|\#)(\S+)/g, '$2')); $('.wordSuggestPopInline').click(function() { $('.wordSuggestPop').removeAttr('id'); diff --git a/assets/strings/eng.json b/assets/strings/eng.json index 06222913d..6f3973c73 100644 --- a/assets/strings/eng.json +++ b/assets/strings/eng.json @@ -52,6 +52,10 @@ "Download": "Download", "Contact": "Contact", "Documentation": "Documentation", + "Suggest_Title": "Improve Apertium's translation", + "Suggest_Button": "Suggest", + "Suggest_Sentence": "How would you suggest we translate {{targetWordCode}}?", + "Suggest_Placeholder": "New Word", "About_Apertium": "About Apertium", "What_Is_Apertium": "

Apertium is a free/open-source machine translation platform, initially aimed at related-language pairs but expanded to deal with more divergent language pairs (such as English-Catalan). The platform provides

  1. a language-independent machine translation engine
  2. tools to manage the linguistic data necessary to build a machine translation system for a given language pair and
  3. linguistic data for a growing number of language pairs.

Apertium welcomes new developers: if you think you can improve the engine or the tools, or develop linguistic data for us, do not hesitate to contact us.

", "Documentation_Para": "Documentation can be found on our Wiki under the Documentation sub-page. We have published various conference papers and journal articles, a list of which may be found on the Wiki under Publications.", diff --git a/assets/strings/rus.json b/assets/strings/rus.json index 2e25a0c93..667b485b3 100644 --- a/assets/strings/rus.json +++ b/assets/strings/rus.json @@ -53,6 +53,10 @@ "About": "Об Apertium", "Download": "Загрузки", "Contact": "Связаться с разработчиками", + "Suggest_Title": "Предложить улучшенный перевод Apertium", + "Suggest_Button": "Предложить перевод", + "Suggest_Sentence": "Как лучше перевести {{targetWordCode}}?", + "Suggest_Placeholder": "Новое слово", "Documentation": "Документация", "About_Apertium": "Об Apertium", "What_Is_Apertium": "

Apertium это открытая платформа машинного перевода, изначально созданная для связанных языковых пар, но теперь она поддерживает даже такие необычные пары, как анлийский-каталанский. Платформа предоставляет

  1. независимый от языка машинный переводчик
  2. инструменты для сбора лингвистических данных для машинного перевода и
  3. лингвистические данные для большого количества языковых пар.

Apertium приветствует новых разработчиков: если Вы можете улучшить движок машинного перевода или инструменты, или собрать лингвистические данные для нас, свяжитесь с нами.

", diff --git a/index.html.in b/index.html.in index 5e18fd369..c5c544ce5 100644 --- a/index.html.in +++ b/index.html.in @@ -56,6 +56,7 @@ button#translateDoc { display: none; } + @@ -531,10 +532,9 @@

-
- +
-
+
- @@ -143,12 +145,7 @@
@@ -167,12 +164,7 @@
@@ -183,11 +175,11 @@
- - + +
-
+
@@ -277,7 +268,7 @@
- +
@@ -311,7 +302,7 @@
- +
@@ -344,7 +335,7 @@
- + APy @@ -367,7 +358,7 @@

               
- +
@@ -388,7 +379,7 @@ Notice a mistake? Help us improve Apertium!
-
@@ -439,12 +430,12 @@
@@ -452,17 +443,17 @@
@@ -548,7 +539,7 @@

diff --git a/interfaces/jquery.js.flow b/interfaces/jquery.js.flow deleted file mode 100644 index d2fcfd143..000000000 --- a/interfaces/jquery.js.flow +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable max-len, no-unused-vars */ - -// Stub interface, since jsonp leads to so many errors with the full -// https://github.com/marudor/flowInterfaces/blob/master/packages/iflow-jquery/index.js.flow - -declare module "jQuery" { - declare function $(element: any): any; -} - -declare var jQuery: jQuery; -declare var $: jQuery; diff --git a/tools/localise-html.py b/tools/localise-html.py index 6dc3f35da..a72a9543b 100755 --- a/tools/localise-html.py +++ b/tools/localise-html.py @@ -47,7 +47,7 @@ def handle_starttag(self, tag, attrs): """This is where html's dir attribute is set to ltr or rtl""" if tag == "html": text = self.get_starttag_text() - self.p('