JS string formatting parameter substitution.

This changes the string usage pattern from:
r.strings.stringname to r.strings('stringname', parameters).
This commit is contained in:
Max Goodman
2012-10-28 00:25:37 -07:00
parent 3788b971ad
commit 261583095f
10 changed files with 57 additions and 21 deletions

View File

@@ -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"(?<!%)%\w|(?<!%)%\(\w+\)[^s]")
def _check_formatting_specifiers(self, key, string):
if not isinstance(string, str):
return
if self.invalid_formatting_specifier_re.search(string):
raise ValueError("Invalid string formatting specifier:"
" strings[%r]" % key)
def get_content(self):
from pylons.i18n import get_lang
from r2.lib import strings, translation
@@ -220,6 +229,7 @@ class StringsSource(DataSource):
if self.keys is not None:
for key in self.keys:
data[key] = strings.strings[key]
self._check_formatting_specifiers(key, data[key])
else:
data = dict(strings.strings)
@@ -232,7 +242,7 @@ class StringsSource(DataSource):
class LocalizedModule(Module):
"""A module that is localized with r2.lib.strings.
References to `r.strings.<string>` are parsed out of the module source.
References to `r.strings(<string>)` 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",

View File

@@ -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"),

View File

@@ -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 () {

View File

@@ -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()
}

View File

@@ -193,7 +193,7 @@ r.ui.LoginForm.prototype = $.extend(new r.ui.Form(), {
if (xhr.status == 0 && r.config.currentOrigin != r.config.https_endpoint) {
$('<p>').append(
$('<a>')
.text(r.strings.login_fallback_msg)
.text(r.strings('login_fallback_msg'))
.attr('href', r.config.https_endpoint + '/login')
).appendTo(this.$el.find('.status'))
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -8,9 +8,9 @@ r.traffic = {
addSubredditSelector: function () {
$('<form>').append(
$('<fieldset>').append(
$('<legend>').text(r.strings.view_subreddit_traffic),
$('<legend>').text(r.strings('view_subreddit_traffic')),
$('<input type="text" id="srname">'),
$('<input type="submit">').attr('value', r.strings.go)
$('<input type="submit">').attr('value', r.strings('go'))
)
).submit(r.traffic._onSubredditSelected)
.prependTo('.traffic-tables-side')

View File

@@ -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)
}
})

View File

@@ -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]
})
}
}