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

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

parents 19550a3b 16fab270
...@@ -70,6 +70,8 @@ ...@@ -70,6 +70,8 @@
{% trans "Alt+M - Shows machine translation tab"%}<br /> {% trans "Alt+M - Shows machine translation tab"%}<br />
{% trans "Alt+N - Shows nearby strings tab"%}<br /> {% trans "Alt+N - Shows nearby strings tab"%}<br />
{% trans "Alt+S - Shows search 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> "></i>
</span><h4 class="panel-title">{% if unit.translation.is_template %}{% trans "Editing source string" %}{% else %}{% trans "Translate" %}{% endif %}</h4></div> </span><h4 class="panel-title">{% if unit.translation.is_template %}{% trans "Editing source string" %}{% else %}{% trans "Translate" %}{% endif %}</h4></div>
<div class="panel-body"> <div class="panel-body">
...@@ -107,7 +109,7 @@ ...@@ -107,7 +109,7 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endwith %} {% 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> </div>
{% endif %} {% endif %}
{% endif %} {% endif %}
......
...@@ -180,7 +180,7 @@ function processMachineTranslation(data, textStatus, jqXHR) { ...@@ -180,7 +180,7 @@ function processMachineTranslation(data, textStatus, jqXHR) {
newRow.append($('<td/>').text(el.source)); newRow.append($('<td/>').text(el.source));
newRow.append($('<td/>').text(el.service)); newRow.append($('<td/>').text(el.service));
/* Translators: Verb for copy operation */ /* 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'); var $machineTranslations = $('#machine-translations');
$machineTranslations.children('tr').each(function (idx) { $machineTranslations.children('tr').each(function (idx) {
if ($(this).data('quality') < el.quality && !done) { if ($(this).data('quality') < el.quality && !done) {
...@@ -197,6 +197,28 @@ function processMachineTranslation(data, textStatus, jqXHR) { ...@@ -197,6 +197,28 @@ function processMachineTranslation(data, textStatus, jqXHR) {
$('.translation-editor').val(text).trigger('autosize.resize'); $('.translation-editor').val(text).trigger('autosize.resize');
$('#id_fuzzy').prop('checked', true); $('#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 { } else {
var msg = interpolate( var msg = interpolate(
gettext('The request for machine translation using %s has failed:'), gettext('The request for machine translation using %s has failed:'),
...@@ -522,6 +544,8 @@ $(function () { ...@@ -522,6 +544,8 @@ $(function () {
Mousetrap.bindGlobal('alt+pagedown', function(e) {window.location = $('#button-next').attr('href'); return false;}); 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+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+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( Mousetrap.bindGlobal(
['ctrl+shift+enter', 'command+shift+enter'], ['ctrl+shift+enter', 'command+shift+enter'],
function(e) {$('input[name="fuzzy"]').prop('checked', false); return submitForm(e);} function(e) {$('input[name="fuzzy"]').prop('checked', false); return submitForm(e);}
...@@ -576,6 +600,27 @@ $(function () { ...@@ -576,6 +600,27 @@ $(function () {
$this.tooltip('destroy'); $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 */ /* Check link clicking */
$document.on('click', '.check [data-toggle="tab"]', function (e) { $document.on('click', '.check [data-toggle="tab"]', function (e) {
var href = $(this).attr('href'); var href = $(this).attr('href');
...@@ -591,6 +636,37 @@ $(function () { ...@@ -591,6 +636,37 @@ $(function () {
e.preventDefault(); 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 */ /* Widgets selector */
$('.select-tab').on('change', function (e) { $('.select-tab').on('change', function (e) {
$(this).parent().find('.tab-pane').removeClass('active'); $(this).parent().find('.tab-pane').removeClass('active');
......
...@@ -128,6 +128,12 @@ textarea#id_comment { ...@@ -128,6 +128,12 @@ textarea#id_comment {
.check .close { .check .close {
top: -5px; top: -5px;
} }
.hlcheck {
border: 1px dotted #AEB7CF;
background-color: #E0EAF1;
display: inline-block;
cursor: pointer;
}
.hlmatch { .hlmatch {
background-color: #eb3; background-color: #eb3;
} }
......
...@@ -133,6 +133,14 @@ class Check(object): ...@@ -133,6 +133,14 @@ class Check(object):
return weblate.get_doc_url('user/checks', self.doc_id) 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): class TargetCheck(Check):
''' '''
Basic class for target checks. Basic class for target checks.
......
...@@ -205,6 +205,14 @@ class BaseFormatCheck(TargetCheck): ...@@ -205,6 +205,14 @@ class BaseFormatCheck(TargetCheck):
''' '''
return False 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): class PythonFormatCheck(BaseFormatCheck):
''' '''
......
...@@ -66,6 +66,14 @@ class BBCodeCheck(TargetCheck): ...@@ -66,6 +66,14 @@ class BBCodeCheck(TargetCheck):
return src_tags != tgt_tags 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): class XMLTagsCheck(TargetCheck):
''' '''
...@@ -105,3 +113,17 @@ class XMLTagsCheck(TargetCheck): ...@@ -105,3 +113,17 @@ class XMLTagsCheck(TargetCheck):
# Compare tags # Compare tags
return source_tags != target_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): ...@@ -80,11 +80,37 @@ def fmt_whitespace(value):
SPACE_TAB.format(_('Tab character')) SPACE_TAB.format(_('Tab character'))
) )
return value 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') @register.inclusion_tag('format-translation.html')
def format_translation(value, language, diff=None, search_match=None, 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. Nicely formats translation text possibly handling plurals or diff.
""" """
...@@ -109,6 +135,7 @@ def format_translation(value, language, diff=None, search_match=None, ...@@ -109,6 +135,7 @@ def format_translation(value, language, diff=None, search_match=None,
parts = [] parts = []
for idx, value in enumerate(plurals): for idx, value in enumerate(plurals):
highlights = fmt_check_highlights(value, checks)
# HTML escape # HTML escape
value = escape(force_text(value)) value = escape(force_text(value))
...@@ -118,6 +145,17 @@ def format_translation(value, language, diff=None, search_match=None, ...@@ -118,6 +145,17 @@ def format_translation(value, language, diff=None, search_match=None,
diffvalue = escape(force_text(diff[idx])) diffvalue = escape(force_text(diff[idx]))
value = html_diff(diffvalue, value) 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 # Format search term
if search_match: if search_match:
# Since the search ignored case, we need to highlight any # 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