diff --git a/.gitignore b/.gitignore
index c0a2c74e6..7c97ee279 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@ r2/r2/public/static/sprite*.png
r2/r2/lib/_normalized_hot.c
r2/r2/lib/mr_tools/_mr_tools.c
r2/r2/lib/db/_sorts.c
+r2/r2/lib/rand_strings.py
r2/r2/lib/sgm.c
r2/r2/lib/utils/_utils.c
r2/r2/lib/wrapped.c
diff --git a/r2/Makefile b/r2/Makefile
index 93201e671..2aac9549f 100644
--- a/r2/Makefile
+++ b/r2/Makefile
@@ -48,6 +48,9 @@ UPDATE_NAMES = $(PYTHON) $(package)/lib/static.py
# files against the primary production.ini
PRIVATEREPOS = $(shell $(PYTHON) -c 'exec "try: import r2admin; print r2admin.__path__[0]\nexcept:pass"')
+# If reddit-i18n repo is found, use that for r2.pot generation
+I18NPATH = $(shell $(PYTHON) -c 'exec "try: import reddit_i18n; print reddit_i18n.__path__[0]\nexcept ImportError: print \"r2/i18n\""')
+
#------
JSTARGETS = $(foreach js, $(js_targets) $(localized_js_targets), $(static_dir)/$(js))
@@ -80,7 +83,7 @@ endif
all: pyx static names $(INIS)
-.PHONY: pyx js css rtl static names clean clean_static clean_pyx all
+.PHONY: pyx js css rtl static names i18n clean clean_static clean_pyx all
$(NAMES): $(JSTARGETS) $(CSSTARGETS) $(RTLCSS) $(SPRITES)
$(UPDATE_NAMES) $(NAMES) $(NAMED)
@@ -121,8 +124,14 @@ rtl: $(RTLCSS)
names: $(NAMES)
+# Not part of 'all' target as it doesn't need to be run for the site to work,
+# only when r2.pot needs updating
+i18n:
+ paster run run.ini r2/lib/strings.py -c "print_rand_strings()" > r2/lib/rand_strings.py
+ python setup.py extract_messages -o $(I18NPATH)/r2.pot
+
clean: clean_static clean_pyx
- rm -f $(INIS)
+ rm -f $(INIS) r2/lib/rand_strings.py
clean_pyx:
rm -f $(PYXSO_FILES) $(PYXC_FILES)
diff --git a/r2/r2/controllers/error.py b/r2/r2/controllers/error.py
index 19d63ba9c..ab2f3e792 100644
--- a/r2/r2/controllers/error.py
+++ b/r2/r2/controllers/error.py
@@ -53,7 +53,7 @@ NUM_FAILIENS = 3
redditbroke = \
'''
- Reddit broke!
+ reddit broke!
@@ -88,6 +88,9 @@ class ErrorController(RedditController):
ErrorDocuments middleware in your config/middleware.py file.
"""
allowed_render_styles = ('html', 'xml', 'js', 'embed', '', "compact", 'api')
+ # List of admins to blame (skip the first admin, "reddit")
+ # If list is empty, just blame "an admin"
+ admins = g.admins[1:] or ["an admin"]
def __before__(self):
try:
c.error_page = True
@@ -163,6 +166,7 @@ class ErrorController(RedditController):
code = 404
srname = request.GET.get('srname', '')
takedown = request.GET.get('takedown', "")
+
if srname:
c.site = Subreddit._by_name(srname)
if c.render_style not in self.allowed_render_styles:
@@ -178,7 +182,8 @@ class ErrorController(RedditController):
elif code == 403:
return self.send403()
elif code == 500:
- return redditbroke % (rand.randint(1,NUM_FAILIENS), rand_strings.sadmessages)
+ randmin = {'admin': rand.choice(self.admins)}
+ return redditbroke % (rand.randint(1,NUM_FAILIENS), rand_strings.sadmessages % randmin)
elif code == 503:
return self.send503()
elif code == 304:
diff --git a/r2/r2/lib/strings.py b/r2/r2/lib/strings.py
index 80f42cdae..fc7e76224 100644
--- a/r2/r2/lib/strings.py
+++ b/r2/r2/lib/strings.py
@@ -27,7 +27,7 @@ random strings which can be different in each language, though the
hooks to the UI are the same.
"""
-import helpers as h
+import r2.lib.helpers as h
from pylons import g
from pylons.i18n import _, ungettext
import random, locale
@@ -379,3 +379,9 @@ rand_strings = RandomStringManager()
rand_strings.add('sadmessages', "Funny 500 page message", 10)
rand_strings.add('create_reddit', "Reason to create a reddit", 20)
+
+
+def print_rand_strings():
+ for name, rand_string in rand_strings:
+ for string in rand_string:
+ print "_('" + string + "')"
diff --git a/r2/r2/templates/promotelinkform.html b/r2/r2/templates/promotelinkform.html
index c61eda6ce..c13092c65 100644
--- a/r2/r2/templates/promotelinkform.html
+++ b/r2/r2/templates/promotelinkform.html
@@ -39,6 +39,10 @@ ${unsafe(js.use('sponsored'))}
+## Create a datepicker for a form. min/maxDateSrc are the id of the
+## element containing the min/max date - the '#' is added automatically
+## here (as a workaround for babel message extraction not handling it
+## properly if passed in when the function is called
<%def name="datepicker(name, value, minDateSrc = '', maxDateSrc ='', initfuncname = '', min_date_offset=0)">
@@ -101,7 +105,7 @@ ${unsafe(js.use('sponsored'))}
%>
<%self:datepicker name="startdate", value="${thing.startdate}"
- minDateSrc="#date-min" initfuncname="init_startdate">
+ minDateSrc="date-min" initfuncname="init_startdate">
function(elem) {
var other = $("#enddate");
if(dateFromInput("#startdate") >= dateFromInput("#enddate")) {
@@ -116,7 +120,7 @@ ${unsafe(js.use('sponsored'))}
%self:datepicker>
-
<%self:datepicker name="enddate", value="${thing.enddate}"
- minDateSrc="#startdate" initfuncname="init_enddate" min_date_offset="86400000">
+ minDateSrc="startdate" initfuncname="init_enddate" min_date_offset="86400000">
function(elem) { update_bid(elem); }
%self:datepicker>
diff --git a/r2/r2/templates/roadblocks.html b/r2/r2/templates/roadblocks.html
index 3e3b58335..5902a81da 100644
--- a/r2/r2/templates/roadblocks.html
+++ b/r2/r2/templates/roadblocks.html
@@ -48,7 +48,7 @@ ${unsafe(js.use('sponsored'))}
${error_field("BAD_FUTURE_DATE", "enddate", "div")}
${error_field("BAD_DATE_RANGE", "enddate", "div")}
<%p:datepicker name="startdate", value="${thing.startdate}"
- minDateSrc="#date-min" initfuncname="init_startdate">
+ minDateSrc="date-min" initfuncname="init_startdate">
function(elem) {
var other = $("#enddate");
if(dateFromInput("#startdate") >= dateFromInput("#enddate")) {
@@ -63,7 +63,7 @@ ${unsafe(js.use('sponsored'))}
%p:datepicker>
-
<%p:datepicker name="enddate", value="${thing.enddate}"
- minDateSrc="#startdate" initfuncname="init_enddate">
+ minDateSrc="startdate" initfuncname="init_enddate">
function(elem) { update_bid(elem); }
%p:datepicker>
diff --git a/r2/translation.py b/r2/translation.py
deleted file mode 100644
index 9bca7870f..000000000
--- a/r2/translation.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# The contents of this file are subject to the Common Public Attribution
-# License Version 1.0. (the "License"); you may not use this file except in
-# compliance with the License. You may obtain a copy of the License at
-# http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
-# License Version 1.1, but Sections 14 and 15 have been added to cover use of
-# software over a computer network and provide for limited attribution for the
-# Original Developer. In addition, Exhibit A has been modified to be consistent
-# with Exhibit B.
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-# the specific language governing rights and limitations under the License.
-#
-# The Original Code is Reddit.
-#
-# The Original Developer is the Initial Developer. The Initial Developer of the
-# Original Code is CondeNet, Inc.
-#
-# All portions of the code written by CondeNet are Copyright (c) 2006-2010
-# CondeNet, Inc. All Rights Reserved.
-################################################################################
-from distutils.cmd import Command
-from babel.messages.frontend import new_catalog as _new_catalog, \
- extract_messages as _extract_messages
-from distutils.cmd import Command
-from distutils.errors import DistutilsOptionError
-from babel import Locale
-import os, shutil, re
-
-
-
-class extract_messages(_extract_messages):
- def initialize_options(self):
- _extract_messages.initialize_options(self)
- self.output_file = 'r2/i18n/r2.pot'
- self.mapping_file = 'babel.cfg'
-
-class new_catalog(_new_catalog):
- def initialize_options(self):
- _new_catalog.initialize_options(self)
- self.output_dir = 'r2/i18n'
- self.input_file = 'r2/i18n/r2.pot'
- self.domain = 'r2'
-
- def finalize_options(self):
- _new_catalog.finalize_options(self)
- if os.path.exists(self.output_file):
- file2 = self.output_file + "-sav"
- print " --> backing up existing PO file to '%s'" % file2
- shutil.copyfile(self.output_file, file2)
-
-class commit_translation(Command):
- description = 'Turns PO into MO files'
- user_options = [('locale=', 'l',
- 'locale for the new localized catalog'), ]
-
- def initialize_options(self):
- self.locale = None
- self.output_dir = 'r2/i18n'
- self.domain = 'r2'
- self.string = '_what_'
-
- def finalize_options(self):
- if not self.locale:
- raise DistutilsOptionError('you must provide a locale for the '
- 'catalog')
-
- self.input_file = os.path.join(self.output_dir, self.locale,
- 'LC_MESSAGES', self.domain + '.po')
- self.output_file = os.path.join(self.output_dir, self.locale,
- 'LC_MESSAGES', self.domain + '.mo')
- def run(self):
- cmd = 'msgfmt -o "%s" "%s"' % (self.output_file, self.input_file)
- handle = os.popen(cmd)
- print handle.read(),
- handle.close()
-
-class test_translation(new_catalog):
- description = 'makes a mock-up PO and MO file for testing and sets to en'
- user_options = [('locale=', 'l',
- 'locale for the new localized catalog'),
- ('string=', 's',
- 'global string substitution on translation'),
- ]
-
- def initialize_options(self):
- new_catalog.initialize_options(self)
- self.locale = 'en'
- self.string = '_what_'
-
- def finalize_options(self):
- self.output_file = os.path.join(self.output_dir, self.locale,
- 'LC_MESSAGES', self.domain + '.po')
- self.output_file_mo = os.path.join(self.output_dir, self.locale,
- 'LC_MESSAGES', self.domain + '.mo')
-
- if not os.path.exists(os.path.dirname(self.output_file)):
- os.makedirs(os.path.dirname(self.output_file))
-
- self._locale = Locale.parse('en')
- self._locale.language = self.locale
-
- def run(self):
- new_catalog.run(self)
- handle = open(self.output_file)
- res = ''
- counter = 0
- formatting_string = False
- for line in handle:
- if not ('""' in line):
- strlen = len(re.findall(r"\S+", line)) - 1
- if "%" in line:
- formatting_string = re.findall(r"%\S+", line)
- strlen -= len(formatting_string)
- formatting_string = (', '.join(formatting_string)).strip('"')
- if '""' in line and not("msgid" in line):
- strlen = 1 if strlen < 1 else strlen
- string = ' '.join([self.string for x in range(0, strlen)])
- if formatting_string:
- string = '%s [%s]' %(string, formatting_string)
- formatting_string = ''
- string = '"%s"' % string
- res += line if counter < 1 else line.replace('""', string)
- counter += 1
- elif line.startswith('"Last-Translator:'):
- res += line.replace("FULL NAME", "Babel Phish")
- else:
- res += line
- handle.close()
- handle = open(self.output_file, 'w')
- handle.write(res)
- handle.close()
- cmd = 'msgfmt -o "%s" "%s"' % (self.output_file_mo, self.output_file)
- handle = os.popen(cmd)
- print "converting to MO file..."
- print handle.read(),
- handle.close()
-