Commit 402cf17e authored by Michal Čihař's avatar Michal Čihař

Merge remote-tracking branch 'origin/pull/949'

parents 19550a3b 16fab270
......@@ -70,6 +70,8 @@
{% trans "Alt+M - Shows machine translation tab"%}<br />
{% trans "Alt+N - Shows nearby strings tab"%}<br />
{% trans "Alt+S - Shows search tab"%}<br />
{% trans "Alt+V - Fill in with source string"%}<br />
{% trans "Alt+F - Set fuzzy"%}<br />
"></i>
</span><h4 class="panel-title">{% if unit.translation.is_template %}{% trans "Editing source string" %}{% else %}{% trans "Translate" %}{% endif %}</h4></div>
<div class="panel-body">
......@@ -107,7 +109,7 @@
{% endif %}
{% endif %}
{% endwith %}
{% format_translation unit.source unit.translation.subproject.project.source_language search_match=search_query num_plurals=unit.translation.language.nplurals %}
{% format_translation unit.source unit.translation.subproject.project.source_language search_match=search_query num_plurals=unit.translation.language.nplurals checks=unit.checks %}
</div>
{% endif %}
{% endif %}
......
......@@ -180,7 +180,7 @@ function processMachineTranslation(data, textStatus, jqXHR) {
newRow.append($('<td/>').text(el.source));
newRow.append($('<td/>').text(el.service));
/* Translators: Verb for copy operation */
newRow.append($('<td><a class="copymt btn btn-xs btn-default">' + gettext('Copy') + '</a></td>'));
newRow.append($('<td><a class="copymt btn btn-xs btn-default"><span class="mtn text-info"></span>' + gettext('Copy') + '</a><a class="copymts btn btn-xs btn-default">↵</a></td>'));
var $machineTranslations = $('#machine-translations');
$machineTranslations.children('tr').each(function (idx) {
if ($(this).data('quality') < el.quality && !done) {
......@@ -197,6 +197,28 @@ function processMachineTranslation(data, textStatus, jqXHR) {
$('.translation-editor').val(text).trigger('autosize.resize');
$('#id_fuzzy').prop('checked', true);
});
$('a.copymts').button({text: true, icons: { primary: 'ui-icon-copy' }}).click(function () {
var text = $(this).parent().parent().find('.target').text();
$('.translation-editor').val(text).trigger('autosize.resize');
$('#id_fuzzy').prop('checked', false);
submitForm({target:$('.translation-editor')});
});
for(var i=1;i<10;i++){Mousetrap.bindGlobal('ctrl '+i,function() {});}
var $machineTranslations = $('#machine-translations');
$machineTranslations.children('tr').each(function (idx) {
if(idx<9)
{
$(this).find('.mtn').html("<sup title='"+gettext('CTRL then ')+(idx+1)+"'>"+(idx+1))+"</sup>";
Mousetrap.bindGlobal('ctrl '+(idx+1),function(e) {
$($('#machine-translations').children('tr')[idx]).find('a.copymt').click(); return false;});
}
else
{
$(this).find('.mtn').html('');
}
});
} else {
var msg = interpolate(
gettext('The request for machine translation using %s has failed:'),
......@@ -522,6 +544,8 @@ $(function () {
Mousetrap.bindGlobal('alt+pagedown', function(e) {window.location = $('#button-next').attr('href'); return false;});
Mousetrap.bindGlobal('alt+pageup', function(e) {window.location = $('#button-prev').attr('href'); return false;});
Mousetrap.bindGlobal('alt+home', function(e) {window.location = $('#button-first').attr('href'); return false;});
Mousetrap.bindGlobal('alt+v', function(e) {$('.translation-item .copy-text').click(); return false;});
Mousetrap.bindGlobal('alt+f', function(e) {$('input[name="fuzzy"]').prop('checked', true); return false;});
Mousetrap.bindGlobal(
['ctrl+shift+enter', 'command+shift+enter'],
function(e) {$('input[name="fuzzy"]').prop('checked', false); return submitForm(e);}
......@@ -576,6 +600,27 @@ $(function () {
$this.tooltip('destroy');
});
/* Check dismiss shortcuts */
for (var icheck=0;icheck<10;icheck++){Mousetrap.bindGlobal("esc "+ icheck, function(e) { });}
if ($(".check").length>0)
{
$($('.check')[0].parentNode).children(".check").each(function(idx){
var $this = $(this);
if (idx <10)
{
if ($this.find(".nchk").length>0) $this.find(".nchk").html("<sup title="+gettext('ESC then ')+idx+"'>"+idx+"</sup>");
else
$this.append("<span class='nchk text-info' ><sup title='"+gettext('ESC then ')+idx+"'>"+idx+"</sup></span>");
Mousetrap.bindGlobal("esc "+ idx, function(e) { $this.find('.close').click(); return false; });
}
else
{
if ($this.find(".nchk")) $this.find(".nchk").html("");
}
});
}
/* Check link clicking */
$document.on('click', '.check [data-toggle="tab"]', function (e) {
var href = $(this).attr('href');
......@@ -591,6 +636,37 @@ $(function () {
e.preventDefault();
});
/* Copy from source text highlight check */
$('.hlcheck').click(function (e) {
var text = $(this).clone();
text.find(".nchk").remove();
text=text.text();
$('.translation-editor').insertAtCaret($.trim(text)).trigger('autosize.resize');;
e.preventDefault();
});
/* and shortcuts */
var possibleShortcuts=['a','b','d','g','i','j','k','l','o','p','q','t','u','w','x','y'];
for (var icheck=0;icheck<possibleShortcuts.length;icheck++){Mousetrap.bindGlobal("alt+"+possibleShortcuts[icheck], function(e) { });}
if ($(".hlcheck").length>0)
{
$('.hlcheck').each(function(idx){
var $this = $(this);
if (idx <possibleShortcuts.length)
{
if ($this.find(".nchk").length>0) $this.find(".nchk").html("<sup title='ALT+"+possibleShortcuts[idx]+"'>"+possibleShortcuts[idx]+"</sup>");
else
$this.prepend("<span class='nchk text-info' ><sup title='ALT+"+possibleShortcuts[idx]+"'>"+possibleShortcuts[idx]+"</sup></span>");
Mousetrap.bindGlobal("alt+"+possibleShortcuts[idx], function(e) { $this.click(); return false; });
}
else
{
if ($this.find(".nchk")) $this.find(".nchk").html("");
}
});
}
/* Widgets selector */
$('.select-tab').on('change', function (e) {
$(this).parent().find('.tab-pane').removeClass('active');
......
......@@ -128,6 +128,12 @@ textarea#id_comment {
.check .close {
top: -5px;
}
.hlcheck {
border: 1px dotted #AEB7CF;
background-color: #E0EAF1;
display: inline-block;
cursor: pointer;
}
.hlmatch {
background-color: #eb3;
}
......
......@@ -133,6 +133,14 @@ class Check(object):
return weblate.get_doc_url('user/checks', self.doc_id)
def check_highlight(self, source, unit):
'''
Returns parts of the text that match to hightlight them
return is table that contains lists of two elements with
start position of the match and the value of the match
'''
return []
class TargetCheck(Check):
'''
Basic class for target checks.
......
......@@ -205,6 +205,14 @@ class BaseFormatCheck(TargetCheck):
'''
return False
def check_highlight(self, source, unit):
ret = []
match_objects = self.regexp.finditer(source)
for match in match_objects:
if match.start() == match.end():
continue
ret.append((match.start(), match.group()))
return ret
class PythonFormatCheck(BaseFormatCheck):
'''
......
......@@ -66,6 +66,14 @@ class BBCodeCheck(TargetCheck):
return src_tags != tgt_tags
def check_highlight(self, source, unit):
ret = []
match_objects = BBCODE_MATCH.finditer(source)
for match in match_objects:
if match.start() == match.end():
continue
ret.append((match.start(), match.group()))
return ret
class XMLTagsCheck(TargetCheck):
'''
......@@ -105,3 +113,17 @@ class XMLTagsCheck(TargetCheck):
# Compare tags
return source_tags != target_tags
def check_highlight(self, source, unit):
ret = []
match_objects = XML_MATCH.finditer(source)
for match in match_objects:
if match.start() == match.end():
continue
ret.append((match.start(), match.group()))
match_objects = XML_ENTITY_MATCH.finditer(source)
for match in match_objects:
if match.start() == match.end():
continue
ret.append((match.start(), match.group()))
return ret
......@@ -80,11 +80,37 @@ def fmt_whitespace(value):
SPACE_TAB.format(_('Tab character'))
)
return value
def fmt_check_highlights(value, checks):
highlights = None
# Find all checks highlight
if checks:
highlights = []
for check in checks:
highlights += check.check_highlight(value, None)
#Sort by order in string
if highlights:
highlights.sort(key=lambda tup: tup[0])
#remove probelmatics ones (overlapping or one inside another)
for hl_idx in xrange(0, len(highlights)):
if hl_idx >= len(highlights):
break
elref = highlights[hl_idx]
elref_end = elref[0] + len(elref[1])
for hl_idx_next in xrange(hl_idx + 1, len(highlights)):
if hl_idx_next >= len(highlights):
break
eltest = highlights[hl_idx_next]
if eltest[0] >= elref[0] and eltest[0] < elref_end:
highlights.pop(hl_idx_next)
elif eltest[0] > elref_end:
break
#then transform highlights to escaped html
highlights = [(h[0], escape(force_unicode(h[1]))) for h in highlights]
return highlights
@register.inclusion_tag('format-translation.html')
def format_translation(value, language, diff=None, search_match=None,
simple=False, num_plurals=2):
simple=False, num_plurals=2, checks=None):
"""
Nicely formats translation text possibly handling plurals or diff.
"""
......@@ -109,6 +135,7 @@ def format_translation(value, language, diff=None, search_match=None,
parts = []
for idx, value in enumerate(plurals):
highlights = fmt_check_highlights(value, checks)
# HTML escape
value = escape(force_text(value))
......@@ -118,6 +145,17 @@ def format_translation(value, language, diff=None, search_match=None,
diffvalue = escape(force_text(diff[idx]))
value = html_diff(diffvalue, value)
# Create span for checks highlights
if highlights:
start_search = 0
for htext in [h[1] for h in highlights]:
find_highlight = value.find(htext, start_search)
if find_highlight >= 0:
newpart = u'<span class="hlcheck">{0}</span>'.format(htext)
next_part = value[(find_highlight + len(htext)):]
value = value[:find_highlight] + newpart + next_part
start_search = find_highlight + len(newpart)
# Format search term
if search_match:
# Since the search ignored case, we need to highlight any
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment