##// END OF EJS Templates
release: merge back stable branch into default
marcink -
r334:8c44af47 merge default
parent child Browse files
Show More
@@ -0,0 +1,14 b''
1 |RCE| 4.2.1 |RNS|
2 -----------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2016-07-04
8
9 Fixes
10 ^^^^^
11
12 - ui: fixed empty labels caused by missing translation of JS components
13 - login: fixed bad routing URL in comments when user is not logged in.
14 - celery: make sure to run tasks in sync mode if connection to celery is lost.
@@ -0,0 +1,36 b''
1 // # Copyright (C) 2016-2016 RhodeCode GmbH
2 // #
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
6 // #
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19 i18nLog = Logger.get('i18n');
20
21 var _gettext = function (s) {
22 if (_TM.hasOwnProperty(s)) {
23 return _TM[s];
24 }
25 i18nLog.error(
26 'String `' + s + '` was requested but cannot be ' +
27 'found in translation table');
28 return s
29 };
30
31 var _ngettext = function (singular, plural, n) {
32 if (n === 1) {
33 return _gettext(singular)
34 }
35 return _gettext(plural)
36 };
@@ -4,3 +4,4 b' c3fe200198f5aa34cf2e4066df2881a9cefe3704'
4 4 7fd5c850745e2ea821fb4406af5f4bff9b0a7526 v4.1.1
5 5 41c87da28a179953df86061d817bc35533c66dd2 v4.1.2
6 6 baaf9f5bcea3bae0ef12ae20c8b270482e62abb6 v4.2.0
7 32a70c7e56844a825f61df496ee5eaf8c3c4e189 v4.2.1
@@ -19,6 +19,7 b' module.exports = function(grunt) {'
19 19 '<%= dirs.js.src %>/mousetrap.js',
20 20 '<%= dirs.js.src %>/moment.js',
21 21 '<%= dirs.js.src %>/appenlight-client-0.4.1.min.js',
22 '<%= dirs.js.src %>/i18n_utils.js',
22 23
23 24 // Plugins
24 25 '<%= dirs.js.src %>/plugins/jquery.pjax.js',
@@ -9,6 +9,7 b' Release Notes'
9 9 .. toctree::
10 10 :maxdepth: 1
11 11
12 release-notes-4.2.1.rst
12 13 release-notes-4.2.0.rst
13 14 release-notes-4.1.2.rst
14 15 release-notes-4.1.1.rst
@@ -1,33 +1,42 b''
1 1 // translate select2 components
2 2 select2Locales = {
3 3 formatLoadMore: function(pageNumber) {
4 return _TM["Loading more results..."];
4 return _gettext("Loading more results...");
5 5 },
6 6 formatSearching: function() {
7 return _TM["Searching..."];
7 return _gettext("Searching...");
8 8 },
9 9 formatNoMatches: function() {
10 return _TM["No matches found"];
10 return _gettext("No matches found");
11 11 },
12 12 formatAjaxError: function(jqXHR, textStatus, errorThrown) {
13 return _TM["Loading failed"];
13 return _gettext("Loading failed");
14 14 },
15 15 formatMatches: function(matches) {
16 16 if (matches === 1) {
17 return _TM["One result is available, press enter to select it."];
17 return _gettext("One result is available, press enter to select it.");
18 18 }
19 return _TM["{0} results are available, use up and down arrow keys to navigate."].format(matches);
19 return _gettext("{0} results are available, use up and down arrow keys to navigate.").format(matches);
20 20 },
21 21 formatInputTooShort: function(input, min) {
22 22 var n = min - input.length;
23 return "Please enter {0} or more character".format(n) + (n === 1 ? "" : "s");
23 if (n === 1) {
24 return _gettext("Please enter {0} or more character").format(n);
25 }
26 return _gettext("Please enter {0} or more characters").format(n);
24 27 },
25 28 formatInputTooLong: function(input, max) {
26 29 var n = input.length - max;
27 return "Please delete {0} character".format(n) + (n === 1 ? "" : "s");
30 if (n === 1) {
31 return _gettext("Please delete {0} character").format(n);
32 }
33 return _gettext("Please delete {0} characters").format(n);
28 34 },
29 35 formatSelectionTooBig: function(limit) {
30 return "You can only select {0} item".format(limit) + (limit === 1 ? "" : "s");
36 if (limit === 1) {
37 return _gettext("You can only select {0} item").format(limit);
38 }
39 return _gettext("You can only select {0} items").format(limit);
31 40 }
32 41 };
33 42
@@ -84,7 +84,7 b''
84 84 return typeof response === 'string' ? $.parseJSON(response) : response;
85 85 },
86 86 showNoSuggestionNotice: false,
87 noSuggestionNotice: _TM['No results'],
87 noSuggestionNotice: _gettext('No results'),
88 88 orientation: 'bottom',
89 89 forceFixPosition: false,
90 90 replaceOnArrowKey: true
@@ -10,21 +10,6 b' var AgeModule = (function () {'
10 10 var show_suffix = show_suffix || true;
11 11 var short_format = short_format || false;
12 12
13 // alias for backward compat
14 var _ = function(s) {
15 if (_TM.hasOwnProperty(s)) {
16 return _TM[s];
17 }
18 return s
19 };
20
21 var ungettext = function (singular, plural, n) {
22 if (n === 1){
23 return _(singular)
24 }
25 return _(plural)
26 };
27
28 13 var _get_relative_delta = function(now, prevdate) {
29 14
30 15 var duration = moment.duration(moment(now).diff(prevdate));
@@ -121,12 +106,12 b' var AgeModule = (function () {'
121 106
122 107 } else {
123 108 var fmt_funcs = {
124 'year': function(d) {return ungettext('{0} year', '{0} years', d).format(d)},
125 'month': function(d) {return ungettext('{0} month', '{0} months', d).format(d)},
126 'day': function(d) {return ungettext('{0} day', '{0} days', d).format(d)},
127 'hour': function(d) {return ungettext('{0} hour', '{0} hours', d).format(d)},
128 'minute': function(d) {return ungettext('{0} min', '{0} min', d).format(d)},
129 'second': function(d) {return ungettext('{0} sec', '{0} sec', d).format(d)}
109 'year': function(d) {return _ngettext('{0} year', '{0} years', d).format(d)},
110 'month': function(d) {return _ngettext('{0} month', '{0} months', d).format(d)},
111 'day': function(d) {return _ngettext('{0} day', '{0} days', d).format(d)},
112 'hour': function(d) {return _ngettext('{0} hour', '{0} hours', d).format(d)},
113 'minute': function(d) {return _ngettext('{0} min', '{0} min', d).format(d)},
114 'second': function(d) {return _ngettext('{0} sec', '{0} sec', d).format(d)}
130 115 }
131 116
132 117 }
@@ -146,7 +131,7 b' var AgeModule = (function () {'
146 131 var _val = fmt_funcs[part](value);
147 132 if (future) {
148 133 if (show_suffix) {
149 return _('in {0}').format(_val)
134 return _gettext('in {0}').format(_val)
150 135 } else {
151 136 return _val
152 137 }
@@ -154,7 +139,7 b' var AgeModule = (function () {'
154 139 }
155 140 else {
156 141 if (show_suffix) {
157 return _('{0} ago').format(_val)
142 return _gettext('{0} ago').format(_val)
158 143 } else {
159 144 return _val
160 145 }
@@ -166,17 +151,17 b' var AgeModule = (function () {'
166 151 if (short_format) {
167 152 var datetime_tmpl = '{0}, {1}';
168 153 if (show_suffix) {
169 datetime_tmpl = _('{0}, {1} ago');
154 datetime_tmpl = _gettext('{0}, {1} ago');
170 155 if (future) {
171 datetime_tmpl = _('in {0}, {1}');
156 datetime_tmpl = _gettext('in {0}, {1}');
172 157 }
173 158 }
174 159 } else {
175 var datetime_tmpl = _('{0} and {1}');
160 var datetime_tmpl = _gettext('{0} and {1}');
176 161 if (show_suffix) {
177 datetime_tmpl = _('{0} and {1} ago');
162 datetime_tmpl = _gettext('{0} and {1} ago');
178 163 if (future) {
179 datetime_tmpl = _('in {0} and {1}')
164 datetime_tmpl = _gettext('in {0} and {1}')
180 165 }
181 166 }
182 167 }
@@ -186,7 +171,7 b' var AgeModule = (function () {'
186 171 i += 1;
187 172 }
188 173
189 return _('just now')
174 return _gettext('just now')
190 175
191 176 },
192 177 createTimeComponent: function(dateTime, text) {
@@ -24,15 +24,6 b' if (typeof console == "undefined" || typ'
24 24 console = { log: function() {} }
25 25 }
26 26
27
28 // alias for backward compat
29 var _tm = function(s) {
30 if (_TM.hasOwnProperty(s)) {
31 return _TM[s];
32 }
33 return s
34 };
35
36 27 // TODO: move the following function to submodules
37 28
38 29 /**
@@ -148,7 +139,7 b' var showRepoStats = function(target, dat'
148 139
149 140 var td2 = document.createElement('td');
150 141 var trending_language = document.createElement('div');
151 var nr_files = obj.count +" "+ (obj.count === 1 ? _tm('file'): _tm('files'));
142 var nr_files = obj.count +" "+ _ngettext('file', 'files', obj.count);
152 143
153 144 trending_language.title = key + " " + nr_files;
154 145
@@ -168,7 +159,7 b' var showRepoStats = function(target, dat'
168 159 lnk = document.createElement('a');
169 160
170 161 lnk.href = '#';
171 lnk.innerHTML = _tm('Show more');
162 lnk.innerHTML = _ngettext('Show more');
172 163 lnk.id = 'code_stats_show_more';
173 164 td.appendChild(lnk);
174 165
@@ -366,7 +366,7 b' var initCommentBoxCodeMirror = function('
366 366 var actions = [
367 367 {
368 368 text: "approve",
369 displayText: _TM['Set status to Approved'],
369 displayText: _gettext('Set status to Approved'),
370 370 hint: function(CodeMirror, data, completion) {
371 371 CodeMirror.replaceRange("", completion.from || data.from,
372 372 completion.to || data.to, "complete");
@@ -384,7 +384,7 b' var initCommentBoxCodeMirror = function('
384 384 },
385 385 {
386 386 text: "reject",
387 displayText: _TM['Set status to Rejected'],
387 displayText: _gettext('Set status to Rejected'),
388 388 hint: function(CodeMirror, data, completion) {
389 389 CodeMirror.replaceRange("", completion.from || data.from,
390 390 completion.to || data.to, "complete");
@@ -240,7 +240,7 b' var deleteComment = function(comment_id)'
240 240 };
241 241
242 242 var createInlineAddButton = function(tr){
243 var label = _TM['Add another comment'];
243 var label = _gettext('Add another comment');
244 244 var html_el = document.createElement('div');
245 245 $(html_el).addClass('add-comment');
246 246 html_el.innerHTML = '<span class="btn btn-secondary">{0}</span>'.format(label);
@@ -458,7 +458,7 b' var CommentForm = (function() {'
458 458 };
459 459
460 460 $(this.submitForm).find(this.statusChange).select2({
461 placeholder: _TM['Status Review'],
461 placeholder: _gettext('Status Review'),
462 462 formatResult: formatResult,
463 463 formatSelection: formatSelection,
464 464 containerCssClass: "drop-menu status_box_menu",
@@ -472,7 +472,7 b' var CommentForm = (function() {'
472 472 $(self.submitButton).prop('disabled', false);
473 473 }
474 474 //todo, fix this name
475 var placeholderText = _TM['Comment text will be set automatically based on currently selected status ({0}) ...'].format(status);
475 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
476 476 self.cm.setOption('placeholder', placeholderText);
477 477 })
478 478 };
@@ -586,7 +586,7 b' var CommentForm = (function() {'
586 586 }
587 587 $(this.submitButton).prop('disabled', submitState);
588 588 if (submitEvent) {
589 $(this.submitButton).val(_TM['Submitting...']);
589 $(this.submitButton).val(_gettext('Submitting...'));
590 590 } else {
591 591 $(this.submitButton).val(this.submitButtonText);
592 592 }
@@ -636,7 +636,7 b' var CommentForm = (function() {'
636 636 self.setActionButtonsDisabled(true);
637 637
638 638 $(self.previewBoxSelector).addClass('unloaded');
639 $(self.previewBoxSelector).html(_TM['Loading ...']);
639 $(self.previewBoxSelector).html(_gettext('Loading ...'));
640 640 $(self.editContainer).hide();
641 641 $(self.previewContainer).show();
642 642
@@ -147,9 +147,9 b' var fileBrowserListeners = function(node'
147 147 if(results.length > limit){
148 148 var truncated_count = results.length - matches_max;
149 149 if (truncated_count === 1) {
150 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _TM['truncated result']));
150 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated result')));
151 151 } else {
152 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _TM['truncated results']));
152 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated results')));
153 153 }
154 154 }
155 155 }
@@ -158,7 +158,7 b' var fileBrowserListeners = function(node'
158 158 $('#tbody_filtered').show();
159 159
160 160 if (match.length === 0){
161 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_TM['No matching files']));
161 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_gettext('No matching files')));
162 162 }
163 163 $('#tbody_filtered').html(match.join(""));
164 164 }
@@ -293,7 +293,7 b' var getSelectionLink = function(e) {'
293 293 anchor = '#L'+ranges[0]+'-'+ranges[1];
294 294 var link = document.createElement('a');
295 295 link.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
296 link.innerHTML = _TM['Selection link'];
296 link.innerHTML = _gettext('Selection link');
297 297 hl_div.appendChild(link);
298 298 $('#codeblock').append(hl_div);
299 299
@@ -23,8 +23,8 b' var onSuccessFollow = function(target){'
23 23 if(f.hasClass('follow')){
24 24 f.removeClass('follow');
25 25 f.addClass('following');
26 f.attr('title', _TM['Stop following this repository']);
27 $(f).html(_TM['Unfollow']);
26 f.attr('title', _gettext('Stop following this repository'));
27 $(f).html(_gettext('Unfollow'));
28 28 if(f_cnt.length){
29 29 var cnt = Number(f_cnt.html())+1;
30 30 f_cnt.html(cnt);
@@ -33,8 +33,8 b' var onSuccessFollow = function(target){'
33 33 else{
34 34 f.removeClass('following');
35 35 f.addClass('follow');
36 f.attr('title', _TM['Start following this repository']);
37 $(f).html(_TM['Follow']);
36 f.attr('title', _gettext('Start following this repository'));
37 $(f).html(_gettext('Follow'));
38 38 if(f_cnt.length){
39 39 var cnt = Number(f_cnt.html())-1;
40 40 f_cnt.html(cnt);
@@ -116,7 +116,7 b' var show_changeset_tooltip = function(){'
116 116 }
117 117 if(rid && !$(target).hasClass('tooltip')){
118 118 $(target).attr('id', ttid);
119 $(target).attr('title', _TM['loading ...']);
119 $(target).attr('title', _gettext('loading ...'));
120 120 TTIP.main.set_listeners(target);
121 121 TTIP.main.show_tip(e, target);
122 122 var url = pyroutes.url('changeset_info', {"repo_name":repo_name, "revision": rid});
@@ -101,7 +101,7 b''
101 101 elems.splice(elems.indexOf(plugin_id), 1);
102 102 auth_plugins_input.val(elems.join(','));
103 103 $(cur_button).removeClass('btn-success');
104 cur_button.innerHTML = _TM['disabled'];
104 cur_button.innerHTML = _gettext('disabled');
105 105 }
106 106 else{
107 107 if(elems.indexOf(plugin_id) == -1){
@@ -109,7 +109,7 b''
109 109 }
110 110 auth_plugins_input.val(elems.join(','));
111 111 $(cur_button).addClass('btn-success');
112 cur_button.innerHTML = _TM['enabled'];
112 cur_button.innerHTML = _gettext('enabled');
113 113 }
114 114 });
115 115 </script>
@@ -42,8 +42,8 b''
42 42 var api = datatable.api();
43 43 var total = api.page.info().recordsDisplay;
44 44 var active = datatable.fnGetFilteredData();
45
46 $('#user_count').text(_TM["{0} active out of {1} users"].format(active, total));
45 var _text = _gettext("{0} active out of {1} users").format(active, total);
46 $('#user_count').text(_text);
47 47 };
48 48
49 49 // custom filter that filters by username OR email
@@ -228,9 +228,9 b''
228 228 open_new_pull_request.hide();
229 229 } else {
230 230 if (selected_changes == 1) {
231 open_new_pull_request.html(_TM['Open new pull request for selected commit']);
231 open_new_pull_request.html(_gettext('Open new pull request for selected commit'));
232 232 } else if (selected_changes == 0) {
233 open_new_pull_request.html(_TM['Open new pull request']);
233 open_new_pull_request.html(_gettext('Open new pull request'));
234 234 }
235 235 open_new_pull_request.show();
236 236 }
@@ -244,8 +244,8 b''
244 244 'revision': revStart+'...'+revEnd});
245 245
246 246 var link = (revStart == revEnd)
247 ? _TM['Show selected commit __S']
248 : _TM['Show selected commits __S ... __E'];
247 ? _gettext('Show selected commit __S')
248 : _gettext('Show selected commits __S ... __E');
249 249
250 250 link = link.replace('__S', revStart.substr(0,6));
251 251 link = link.replace('__E', revEnd.substr(0,6));
@@ -151,7 +151,7 b''
151 151 ${h.form('', class_='inline-form comment-form-login', method='get')}
152 152 <div class="pull-left">
153 153 <div class="comment-help pull-right">
154 ${_('You need to be logged in to comment.')} <a href="${h.url('login_home',came_from=h.url.current())}">${_('Login now')}</a>
154 ${_('You need to be logged in to comment.')} <a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a>
155 155 </div>
156 156 </div>
157 157 <div class="comment-button pull-right">
@@ -96,7 +96,7 b''
96 96 });
97 97 //push the typed in changeset
98 98 data.results.push({
99 'text': _TM['specify commit'],
99 'text': _gettext('specify commit'),
100 100 'children': [{
101 101 'id': query.term,
102 102 'text': query.term,
@@ -836,7 +836,7 b''
836 836 };
837 837 var previewbox = $('#preview-box');
838 838 previewbox.addClass('unloaded');
839 previewbox.html(_TM['Loading ...']);
839 previewbox.html(_gettext('Loading ...'));
840 840 $('#edit-container').hide();
841 841 $('#preview-container').show();
842 842
@@ -233,7 +233,7 b''
233 233 {'repo_name': templateContext.repo_name,
234 234 'revision': state.rev, 'f_path': path, 'limit': 6});
235 235 $('#file_history_container').show();
236 $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_TM['Loading ...']));
236 $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...')));
237 237
238 238 $.pjax({
239 239 url: url,
@@ -212,7 +212,7 b''
212 212 var _text = myCodeMirror.getValue();
213 213 var _renderer = possible_renderer || DEFAULT_RENDERER;
214 214 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
215 $('#editor_preview').html(_TM['Loading ...']);
215 $('#editor_preview').html(_gettext('Loading ...'));
216 216 var url = pyroutes.url('changeset_comment_preview', {'repo_name': '${c.repo_name}'});
217 217
218 218 ajaxPOST(url, post_data, function(o){
@@ -173,7 +173,7 b''
173 173 var _text = myCodeMirror.getValue();
174 174 var _renderer = possible_renderer || DEFAULT_RENDERER;
175 175 var post_data = {'text': _text, 'renderer': _renderer, 'csrf_token': CSRF_TOKEN};
176 $('#editor_preview').html(_TM['Loading ...']);
176 $('#editor_preview').html(_gettext('Loading ...'));
177 177 var url = pyroutes.url('changeset_comment_preview', {'repo_name': '${c.repo_name}'});
178 178
179 179 ajaxPOST(url, post_data, function(o){
@@ -546,7 +546,7 b''
546 546
547 547 $('#update_commits').on('click', function(e){
548 548 var isDisabled = !$(e.currentTarget).attr('disabled');
549 $(e.currentTarget).text(_TM['Updating...']);
549 $(e.currentTarget).text(_gettext('Updating...'));
550 550 $(e.currentTarget).attr('disabled', 'disabled');
551 551 if(isDisabled){
552 552 updateCommits("${c.repo_name}", "${c.pull_request.pull_request_id}");
@@ -17,7 +17,10 b' output_file = rhodecode/i18n/rhodecode.p'
17 17 msgid-bugs-address = marcin@rhodecode.com
18 18 copyright-holder = RhodeCode GmbH
19 19 no-wrap = true
20 keywords = lazy_ugettext
20 keywords =
21 lazy_ugettext
22 _ngettext
23 _gettext
21 24
22 25 [init_catalog]
23 26 domain = rhodecode
@@ -207,6 +207,7 b' setup('
207 207 message_extractors={
208 208 'rhodecode': [
209 209 ('**.py', 'python', None),
210 ('**.js', 'javascript', None),
210 211 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
211 212 ('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
212 213 ('public/**', 'ignore', None),
General Comments 0
You need to be logged in to leave comments. Login now