From 261583095f8e1354eee1899e0fccc92d1ce5ee12 Mon Sep 17 00:00:00 2001 From: Max Goodman Date: Sun, 28 Oct 2012 00:25:37 -0700 Subject: [PATCH] JS string formatting parameter substitution. This changes the string usage pattern from: r.strings.stringname to r.strings('stringname', parameters). --- r2/r2/lib/js.py | 18 +++++++++++++++--- r2/r2/lib/strings.py | 4 ++-- r2/r2/public/static/js/gold.js | 18 +++++++++--------- r2/r2/public/static/js/interestbar.js | 2 +- r2/r2/public/static/js/login.js | 2 +- r2/r2/public/static/js/reddit.js | 4 ++-- r2/r2/public/static/js/strings.js | 14 ++++++++++++++ r2/r2/public/static/js/traffic.js | 4 ++-- r2/r2/public/static/js/ui.js | 2 +- r2/r2/public/static/js/utils.js | 10 ++++++++++ 10 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 r2/r2/public/static/js/strings.js diff --git a/r2/r2/lib/js.py b/r2/r2/lib/js.py index 9445181e4..24f328cd6 100755 --- a/r2/r2/lib/js.py +++ b/r2/r2/lib/js.py @@ -196,7 +196,7 @@ class DataSource(Source): class StringsSource(DataSource): """A virtual source consisting of localized strings from r2.lib.strings.""" - def __init__(self, lang=None, keys=None, wrap="r.strings = {content}"): + def __init__(self, lang=None, keys=None, wrap="r.strings.set({content})"): DataSource.__init__(self, wrap=wrap) self.lang = lang self.keys = keys @@ -208,6 +208,15 @@ class StringsSource(DataSource): return obj.string_dict raise TypeError + invalid_formatting_specifier_re = re.compile(r"(?` are parsed out of the module source. + References to `r.strings()` are parsed out of the module source. A StringsSource is created and included which contains localized versions of the strings referenced in the module. """ @@ -246,7 +256,8 @@ class LocalizedModule(Module): Module.build(self, closure) reddit_source = open(self.path).read() - string_keys = re.findall("r\.strings\.([\w$_]+)", reddit_source) + string_keys = re.findall("r\.strings\(['\"]([\w$_]+)['\"]", reddit_source) + string_keys.append("permissions") print >> sys.stderr, "Creating language-specific files:" for lang, unused in iter_langs(): @@ -318,6 +329,7 @@ module["reddit"] = LocalizedModule("reddit.js", "jquery.reddit.js", "base.js", "utils.js", + "strings.js", "ui.js", "login.js", "analytics.js", diff --git a/r2/r2/lib/strings.py b/r2/r2/lib/strings.py index faa20e875..71c3ecafc 100644 --- a/r2/r2/lib/strings.py +++ b/r2/r2/lib/strings.py @@ -175,8 +175,8 @@ Note: there are a couple of places outside of your subreddit where someone can c go = _("go"), view_subreddit_traffic = _("view subreddit traffic"), - an_error_occurred = _("an error occurred"), - an_error_occurred_friendly = _("an error occurred. please try again later!"), + an_error_occurred = _("an error occurred (status: %(status)s)"), + an_error_occurred_friendly = _("an error occurred. please try again later! (status: %(status)s)"), rate_limit = _("please wait a few seconds and try again."), subscribed_multi = _("multireddit of your subscriptions"), mod_multi = _("multireddit of subreddits you moderate"), diff --git a/r2/r2/public/static/js/gold.js b/r2/r2/public/static/js/gold.js index ab4ea0f69..d2fc9bb13 100644 --- a/r2/r2/public/static/js/gold.js +++ b/r2/r2/public/static/js/gold.js @@ -43,7 +43,7 @@ r.gold = { var form = $('.gold-form.cloneable:first').clone(), authorName = $link.thing().find('.entry .author:first').text(), - message = r.strings.gold_summary_comment_gift.replace('%(recipient)s', authorName), + message = r.strings('gold_summary_comment_gift', {recipient: authorName}), passthroughs = form.find('.passthrough'), cbBaseUrl = form.find('[name="cbbaseurl"]').val() @@ -147,21 +147,21 @@ r.gold = { Stripe.setPublishableKey(publicKey) if (!cardName) { - status.text(r.strings.missing_credit_name) + status.text(r.strings('missing_credit_name')) } else if (!(Stripe.validateCardNumber(cardNumber))) { - status.text(r.strings.bad_credit_number) + status.text(r.strings('bad_credit_number')) } else if (!Stripe.validateExpiry(expiryMonth, expiryYear)) { - status.text(r.strings.bad_credit_expiry) + status.text(r.strings('bad_credit_expiry')) } else if (!Stripe.validateCVC(cardCvc)) { - status.text(r.strings.bad_credit_cvc) + status.text(r.strings('bad_credit_cvc')) } else if (!cardAddress1) { - status.text(r.strings.missing_credit_address) + status.text(r.strings('missing_credit_address')) } else if (!cardCity) { - status.text(r.strings.missing_credit_city) + status.text(r.strings('missing_credit_city')) } else if (!cardState) { - status.text(r.strings.missing_credit_state) + status.text(r.strings('missing_credit_state')) } else if (!cardZip) { - status.text(r.strings.missing_credit_zip) + status.text(r.strings('missing_credit_zip')) } else { var workingTimer = setTimeout(function () { diff --git a/r2/r2/public/static/js/interestbar.js b/r2/r2/public/static/js/interestbar.js index e2fa37ffb..64c8b9e54 100644 --- a/r2/r2/public/static/js/interestbar.js +++ b/r2/r2/public/static/js/interestbar.js @@ -77,7 +77,7 @@ r.ui.InterestBar.prototype = { .removeClass('working') .addClass('error') .find('.error-caption') - .text(r.strings.an_error_occurred_friendly + ' (' + xhr.status + ')') + .text(r.strings('an_error_occurred_friendly', {status: xhr.status})) this.hideResults() } diff --git a/r2/r2/public/static/js/login.js b/r2/r2/public/static/js/login.js index 24a4b5439..a7bed1934 100644 --- a/r2/r2/public/static/js/login.js +++ b/r2/r2/public/static/js/login.js @@ -193,7 +193,7 @@ r.ui.LoginForm.prototype = $.extend(new r.ui.Form(), { if (xhr.status == 0 && r.config.currentOrigin != r.config.https_endpoint) { $('

').append( $('') - .text(r.strings.login_fallback_msg) + .text(r.strings('login_fallback_msg')) .attr('href', r.config.https_endpoint + '/login') ).appendTo(this.$el.find('.status')) } diff --git a/r2/r2/public/static/js/reddit.js b/r2/r2/public/static/js/reddit.js index 323fa56b4..4b3efda83 100644 --- a/r2/r2/public/static/js/reddit.js +++ b/r2/r2/public/static/js/reddit.js @@ -101,9 +101,9 @@ function form_error(form) { return function(req) { var msg if (req == 'ratelimit') { - msg = r.strings.rate_limit + msg = r.strings('rate_limit') } else { - msg = 'an error occurred while posting (status: ' + req.status + ')' + msg = r.strings('an_error_occurred', {status: req.status}) } $(form).find('.status').text(msg) } diff --git a/r2/r2/public/static/js/strings.js b/r2/r2/public/static/js/strings.js new file mode 100644 index 000000000..1222e1cf6 --- /dev/null +++ b/r2/r2/public/static/js/strings.js @@ -0,0 +1,14 @@ +r.strings = function(name, params) { + var string = r.strings.index[name] + if (params) { + return r.utils.pyStrFormat(string, params) + } else { + return string + } +} + +r.strings.index = {} +r.strings.set = function(strings) { + _.extend(r.strings.index, strings) + this.permissions = this.index.permissions +} diff --git a/r2/r2/public/static/js/traffic.js b/r2/r2/public/static/js/traffic.js index 86ff3673c..94c7f8749 100644 --- a/r2/r2/public/static/js/traffic.js +++ b/r2/r2/public/static/js/traffic.js @@ -8,9 +8,9 @@ r.traffic = { addSubredditSelector: function () { $('

').append( $('
').append( - $('').text(r.strings.view_subreddit_traffic), + $('').text(r.strings('view_subreddit_traffic')), $(''), - $('').attr('value', r.strings.go) + $('').attr('value', r.strings('go')) ) ).submit(r.traffic._onSubredditSelected) .prependTo('.traffic-tables-side') diff --git a/r2/r2/public/static/js/ui.js b/r2/r2/public/static/js/ui.js index d16aa2e98..5df92cd46 100644 --- a/r2/r2/public/static/js/ui.js +++ b/r2/r2/public/static/js/ui.js @@ -141,7 +141,7 @@ r.ui.Form.prototype = $.extend(new r.ui.Base(), { }, _handleNetError: function(result, err, xhr) { - this.showStatus(r.strings.an_error_occurred + ' (' + xhr.status + ')', true) + this.showStatus(r.strings('an_error_occurred', {status: xhr.status}), true) } }) diff --git a/r2/r2/public/static/js/utils.js b/r2/r2/public/static/js/utils.js index 030dfb941..1268b0196 100644 --- a/r2/r2/public/static/js/utils.js +++ b/r2/r2/public/static/js/utils.js @@ -36,5 +36,15 @@ r.utils = { params[value.name] = value.value }) return params + }, + + _pyStrFormatRe: /%\((\w+)\)s/, + pyStrFormat: function(format, params) { + return format.replace(this._pyStrFormatRe, function(match, fieldName) { + if (!(fieldName in params)) { + throw 'missing format parameter' + } + return params[fieldName] + }) } }