release: merge back stable branch into default

This commit is contained in:
Marcin Kuzminski 2016-07-04 12:38:32 +02:00
commit 83b9fcd4da
25 changed files with 123 additions and 82 deletions

View file

@ -19,6 +19,7 @@ module.exports = function(grunt) {
'<%= dirs.js.src %>/mousetrap.js',
'<%= dirs.js.src %>/moment.js',
'<%= dirs.js.src %>/appenlight-client-0.4.1.min.js',
'<%= dirs.js.src %>/i18n_utils.js',
// Plugins
'<%= dirs.js.src %>/plugins/jquery.pjax.js',

View file

@ -0,0 +1,14 @@
|RCE| 4.2.1 |RNS|
-----------------
Release Date
^^^^^^^^^^^^
- 2016-07-04
Fixes
^^^^^
- ui: fixed empty labels caused by missing translation of JS components
- login: fixed bad routing URL in comments when user is not logged in.
- celery: make sure to run tasks in sync mode if connection to celery is lost.

View file

@ -9,6 +9,7 @@ Release Notes
.. toctree::
:maxdepth: 1
release-notes-4.2.1.rst
release-notes-4.2.0.rst
release-notes-4.1.2.rst
release-notes-4.1.1.rst

View file

@ -1,33 +1,42 @@
// translate select2 components
select2Locales = {
formatLoadMore: function(pageNumber) {
return _TM["Loading more results..."];
return _gettext("Loading more results...");
},
formatSearching: function() {
return _TM["Searching..."];
return _gettext("Searching...");
},
formatNoMatches: function() {
return _TM["No matches found"];
return _gettext("No matches found");
},
formatAjaxError: function(jqXHR, textStatus, errorThrown) {
return _TM["Loading failed"];
return _gettext("Loading failed");
},
formatMatches: function(matches) {
if (matches === 1) {
return _TM["One result is available, press enter to select it."];
return _gettext("One result is available, press enter to select it.");
}
return _TM["{0} results are available, use up and down arrow keys to navigate."].format(matches);
return _gettext("{0} results are available, use up and down arrow keys to navigate.").format(matches);
},
formatInputTooShort: function(input, min) {
var n = min - input.length;
return "Please enter {0} or more character".format(n) + (n === 1 ? "" : "s");
if (n === 1) {
return _gettext("Please enter {0} or more character").format(n);
}
return _gettext("Please enter {0} or more characters").format(n);
},
formatInputTooLong: function(input, max) {
var n = input.length - max;
return "Please delete {0} character".format(n) + (n === 1 ? "" : "s");
if (n === 1) {
return _gettext("Please delete {0} character").format(n);
}
return _gettext("Please delete {0} characters").format(n);
},
formatSelectionTooBig: function(limit) {
return "You can only select {0} item".format(limit) + (limit === 1 ? "" : "s");
if (limit === 1) {
return _gettext("You can only select {0} item").format(limit);
}
return _gettext("You can only select {0} items").format(limit);
}
};

View file

@ -0,0 +1,36 @@
// # Copyright (C) 2016-2016 RhodeCode GmbH
// #
// # This program is free software: you can redistribute it and/or modify
// # it under the terms of the GNU Affero General Public License, version 3
// # (only), as published by the Free Software Foundation.
// #
// # This program is distributed in the hope that it will be useful,
// # but WITHOUT ANY WARRANTY; without even the implied warranty of
// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// # GNU General Public License for more details.
// #
// # You should have received a copy of the GNU Affero General Public License
// # along with this program. If not, see <http://www.gnu.org/licenses/>.
// #
// # This program is dual-licensed. If you wish to learn more about the
// # RhodeCode Enterprise Edition, including its added features, Support services,
// # and proprietary license terms, please see https://rhodecode.com/licenses/
i18nLog = Logger.get('i18n');
var _gettext = function (s) {
if (_TM.hasOwnProperty(s)) {
return _TM[s];
}
i18nLog.error(
'String `' + s + '` was requested but cannot be ' +
'found in translation table');
return s
};
var _ngettext = function (singular, plural, n) {
if (n === 1) {
return _gettext(singular)
}
return _gettext(plural)
};

View file

@ -84,7 +84,7 @@
return typeof response === 'string' ? $.parseJSON(response) : response;
},
showNoSuggestionNotice: false,
noSuggestionNotice: _TM['No results'],
noSuggestionNotice: _gettext('No results'),
orientation: 'bottom',
forceFixPosition: false,
replaceOnArrowKey: true

View file

@ -10,21 +10,6 @@ var AgeModule = (function () {
var show_suffix = show_suffix || true;
var short_format = short_format || false;
// alias for backward compat
var _ = function(s) {
if (_TM.hasOwnProperty(s)) {
return _TM[s];
}
return s
};
var ungettext = function (singular, plural, n) {
if (n === 1){
return _(singular)
}
return _(plural)
};
var _get_relative_delta = function(now, prevdate) {
var duration = moment.duration(moment(now).diff(prevdate));
@ -121,12 +106,12 @@ var AgeModule = (function () {
} else {
var fmt_funcs = {
'year': function(d) {return ungettext('{0} year', '{0} years', d).format(d)},
'month': function(d) {return ungettext('{0} month', '{0} months', d).format(d)},
'day': function(d) {return ungettext('{0} day', '{0} days', d).format(d)},
'hour': function(d) {return ungettext('{0} hour', '{0} hours', d).format(d)},
'minute': function(d) {return ungettext('{0} min', '{0} min', d).format(d)},
'second': function(d) {return ungettext('{0} sec', '{0} sec', d).format(d)}
'year': function(d) {return _ngettext('{0} year', '{0} years', d).format(d)},
'month': function(d) {return _ngettext('{0} month', '{0} months', d).format(d)},
'day': function(d) {return _ngettext('{0} day', '{0} days', d).format(d)},
'hour': function(d) {return _ngettext('{0} hour', '{0} hours', d).format(d)},
'minute': function(d) {return _ngettext('{0} min', '{0} min', d).format(d)},
'second': function(d) {return _ngettext('{0} sec', '{0} sec', d).format(d)}
}
}
@ -146,7 +131,7 @@ var AgeModule = (function () {
var _val = fmt_funcs[part](value);
if (future) {
if (show_suffix) {
return _('in {0}').format(_val)
return _gettext('in {0}').format(_val)
} else {
return _val
}
@ -154,7 +139,7 @@ var AgeModule = (function () {
}
else {
if (show_suffix) {
return _('{0} ago').format(_val)
return _gettext('{0} ago').format(_val)
} else {
return _val
}
@ -166,17 +151,17 @@ var AgeModule = (function () {
if (short_format) {
var datetime_tmpl = '{0}, {1}';
if (show_suffix) {
datetime_tmpl = _('{0}, {1} ago');
datetime_tmpl = _gettext('{0}, {1} ago');
if (future) {
datetime_tmpl = _('in {0}, {1}');
datetime_tmpl = _gettext('in {0}, {1}');
}
}
} else {
var datetime_tmpl = _('{0} and {1}');
var datetime_tmpl = _gettext('{0} and {1}');
if (show_suffix) {
datetime_tmpl = _('{0} and {1} ago');
datetime_tmpl = _gettext('{0} and {1} ago');
if (future) {
datetime_tmpl = _('in {0} and {1}')
datetime_tmpl = _gettext('in {0} and {1}')
}
}
}
@ -186,7 +171,7 @@ var AgeModule = (function () {
i += 1;
}
return _('just now')
return _gettext('just now')
},
createTimeComponent: function(dateTime, text) {

View file

@ -24,15 +24,6 @@ if (typeof console == "undefined" || typeof console.log == "undefined"){
console = { log: function() {} }
}
// alias for backward compat
var _tm = function(s) {
if (_TM.hasOwnProperty(s)) {
return _TM[s];
}
return s
};
// TODO: move the following function to submodules
/**
@ -148,7 +139,7 @@ var showRepoStats = function(target, data){
var td2 = document.createElement('td');
var trending_language = document.createElement('div');
var nr_files = obj.count +" "+ (obj.count === 1 ? _tm('file'): _tm('files'));
var nr_files = obj.count +" "+ _ngettext('file', 'files', obj.count);
trending_language.title = key + " " + nr_files;
@ -168,7 +159,7 @@ var showRepoStats = function(target, data){
lnk = document.createElement('a');
lnk.href = '#';
lnk.innerHTML = _tm('Show more');
lnk.innerHTML = _ngettext('Show more');
lnk.id = 'code_stats_show_more';
td.appendChild(lnk);

View file

@ -366,7 +366,7 @@ var initCommentBoxCodeMirror = function(textAreaId, triggerActions){
var actions = [
{
text: "approve",
displayText: _TM['Set status to Approved'],
displayText: _gettext('Set status to Approved'),
hint: function(CodeMirror, data, completion) {
CodeMirror.replaceRange("", completion.from || data.from,
completion.to || data.to, "complete");
@ -384,7 +384,7 @@ var initCommentBoxCodeMirror = function(textAreaId, triggerActions){
},
{
text: "reject",
displayText: _TM['Set status to Rejected'],
displayText: _gettext('Set status to Rejected'),
hint: function(CodeMirror, data, completion) {
CodeMirror.replaceRange("", completion.from || data.from,
completion.to || data.to, "complete");

View file

@ -240,7 +240,7 @@ var deleteComment = function(comment_id) {
};
var createInlineAddButton = function(tr){
var label = _TM['Add another comment'];
var label = _gettext('Add another comment');
var html_el = document.createElement('div');
$(html_el).addClass('add-comment');
html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label);
@ -458,7 +458,7 @@ var CommentForm = (function() {
};
$(this.submitForm).find(this.statusChange).select2({
placeholder: _TM['Status Review'],
placeholder: _gettext('Status Review'),
formatResult: formatResult,
formatSelection: formatSelection,
containerCssClass: "drop-menu status_box_menu",
@ -472,7 +472,7 @@ var CommentForm = (function() {
$(self.submitButton).prop('disabled', false);
}
//todo, fix this name
var placeholderText = _TM['Comment text will be set automatically based on currently selected status ({0}) ...'].format(status);
var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
self.cm.setOption('placeholder', placeholderText);
})
};
@ -586,7 +586,7 @@ var CommentForm = (function() {
}
$(this.submitButton).prop('disabled', submitState);
if (submitEvent) {
$(this.submitButton).val(_TM['Submitting...']);
$(this.submitButton).val(_gettext('Submitting...'));
} else {
$(this.submitButton).val(this.submitButtonText);
}
@ -636,7 +636,7 @@ var CommentForm = (function() {
self.setActionButtonsDisabled(true);
$(self.previewBoxSelector).addClass('unloaded');
$(self.previewBoxSelector).html(_TM['Loading ...']);
$(self.previewBoxSelector).html(_gettext('Loading ...'));
$(self.editContainer).hide();
$(self.previewContainer).show();

View file

@ -147,9 +147,9 @@ var fileBrowserListeners = function(node_list_url, url_base){
if(results.length > limit){
var truncated_count = results.length - matches_max;
if (truncated_count === 1) {
match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _TM['truncated result']));
match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated result')));
} else {
match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _TM['truncated results']));
match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated results')));
}
}
}
@ -158,7 +158,7 @@ var fileBrowserListeners = function(node_list_url, url_base){
$('#tbody_filtered').show();
if (match.length === 0){
match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_gettext('No matching files')));
}
$('#tbody_filtered').html(match.join(""));
}
@ -293,7 +293,7 @@ var getSelectionLink = function(e) {
anchor = '#L'+ranges[0]+'-'+ranges[1];
var link = document.createElement('a');
link.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
link.innerHTML = _TM['Selection link'];
link.innerHTML = _gettext('Selection link');
hl_div.appendChild(link);
$('#codeblock').append(hl_div);

View file

@ -23,8 +23,8 @@ var onSuccessFollow = function(target){
if(f.hasClass('follow')){
f.removeClass('follow');
f.addClass('following');
f.attr('title', _TM['Stop following this repository']);
$(f).html(_TM['Unfollow']);
f.attr('title', _gettext('Stop following this repository'));
$(f).html(_gettext('Unfollow'));
if(f_cnt.length){
var cnt = Number(f_cnt.html())+1;
f_cnt.html(cnt);
@ -33,8 +33,8 @@ var onSuccessFollow = function(target){
else{
f.removeClass('following');
f.addClass('follow');
f.attr('title', _TM['Start following this repository']);
$(f).html(_TM['Follow']);
f.attr('title', _gettext('Start following this repository'));
$(f).html(_gettext('Follow'));
if(f_cnt.length){
var cnt = Number(f_cnt.html())-1;
f_cnt.html(cnt);

View file

@ -116,7 +116,7 @@ var show_changeset_tooltip = function(){
}
if(rid && !$(target).hasClass('tooltip')){
$(target).attr('id', ttid);
$(target).attr('title', _TM['loading ...']);
$(target).attr('title', _gettext('loading ...'));
TTIP.main.set_listeners(target);
TTIP.main.show_tip(e, target);
var url = pyroutes.url('changeset_info', {"repo_name":repo_name, "revision": rid});

View file

@ -101,7 +101,7 @@
elems.splice(elems.indexOf(plugin_id), 1);
auth_plugins_input.val(elems.join(','));
$(cur_button).removeClass('btn-success');
cur_button.innerHTML = _TM['disabled'];
cur_button.innerHTML = _gettext('disabled');
}
else{
if(elems.indexOf(plugin_id) == -1){
@ -109,7 +109,7 @@
}
auth_plugins_input.val(elems.join(','));
$(cur_button).addClass('btn-success');
cur_button.innerHTML = _TM['enabled'];
cur_button.innerHTML = _gettext('enabled');
}
});
</script>

View file

@ -42,8 +42,8 @@ $(document).ready(function() {
var api = datatable.api();
var total = api.page.info().recordsDisplay;
var active = datatable.fnGetFilteredData();
$('#user_count').text(_TM["{0} active out of {1} users"].format(active, total));
var _text = _gettext("{0} active out of {1} users").format(active, total);
$('#user_count').text(_text);
};
// custom filter that filters by username OR email

View file

@ -228,9 +228,9 @@
open_new_pull_request.hide();
} else {
if (selected_changes == 1) {
open_new_pull_request.html(_TM['Open new pull request for selected commit']);
open_new_pull_request.html(_gettext('Open new pull request for selected commit'));
} else if (selected_changes == 0) {
open_new_pull_request.html(_TM['Open new pull request']);
open_new_pull_request.html(_gettext('Open new pull request'));
}
open_new_pull_request.show();
}
@ -244,8 +244,8 @@
'revision': revStart+'...'+revEnd});
var link = (revStart == revEnd)
? _TM['Show selected commit __S']
: _TM['Show selected commits __S ... __E'];
? _gettext('Show selected commit __S')
: _gettext('Show selected commits __S ... __E');
link = link.replace('__S', revStart.substr(0,6));
link = link.replace('__E', revEnd.substr(0,6));

View file

@ -151,7 +151,7 @@
${h.form('', class_='inline-form comment-form-login', method='get')}
<div class="pull-left">
<div class="comment-help pull-right">
${_('You need to be logged in to comment.')} <a href="${h.url('login_home',came_from=h.url.current())}">${_('Login now')}</a>
${_('You need to be logged in to comment.')} <a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a>
</div>
</div>
<div class="comment-button pull-right">

View file

@ -96,7 +96,7 @@
});
//push the typed in changeset
data.results.push({
'text': _TM['specify commit'],
'text': _gettext('specify commit'),
'children': [{
'id': query.term,
'text': query.term,

View file

@ -836,7 +836,7 @@ $(document).ready(function() {
};
var previewbox = $('#preview-box');
previewbox.addClass('unloaded');
previewbox.html(_TM['Loading ...']);
previewbox.html(_gettext('Loading ...'));
$('#edit-container').hide();
$('#preview-container').show();

View file

@ -233,7 +233,7 @@
{'repo_name': templateContext.repo_name,
'revision': state.rev, 'f_path': path, 'limit': 6});
$('#file_history_container').show();
$('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_TM['Loading ...']));
$('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...')));
$.pjax({
url: url,

View file

@ -212,7 +212,7 @@
var _text = myCodeMirror.getValue();
var _renderer = possible_renderer || DEFAULT_RENDERER;
var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
$('#editor_preview').html(_TM['Loading ...']);
$('#editor_preview').html(_gettext('Loading ...'));
var url = pyroutes.url('changeset_comment_preview', {'repo_name': '${c.repo_name}'});
ajaxPOST(url, post_data, function(o){

View file

@ -173,7 +173,7 @@ $(document).ready(function(){
var _text = myCodeMirror.getValue();
var _renderer = possible_renderer || DEFAULT_RENDERER;
var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
$('#editor_preview').html(_TM['Loading ...']);
$('#editor_preview').html(_gettext('Loading ...'));
var url = pyroutes.url('changeset_comment_preview', {'repo_name': '${c.repo_name}'});
ajaxPOST(url, post_data, function(o){

View file

@ -546,7 +546,7 @@
$('#update_commits').on('click', function(e){
var isDisabled = !$(e.currentTarget).attr('disabled');
$(e.currentTarget).text(_TM['Updating...']);
$(e.currentTarget).text(_gettext('Updating...'));
$(e.currentTarget).attr('disabled', 'disabled');
if(isDisabled){
updateCommits("${c.repo_name}", "${c.pull_request.pull_request_id}");

View file

@ -17,7 +17,10 @@ output_file = rhodecode/i18n/rhodecode.pot
msgid-bugs-address = marcin@rhodecode.com
copyright-holder = RhodeCode GmbH
no-wrap = true
keywords = lazy_ugettext
keywords =
lazy_ugettext
_ngettext
_gettext
[init_catalog]
domain = rhodecode

View file

@ -207,6 +207,7 @@ setup(
message_extractors={
'rhodecode': [
('**.py', 'python', None),
('**.js', 'javascript', None),
('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
('public/**', 'ignore', None),