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 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); } 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 name="enddate", value="${thing.enddate}" - minDateSrc="#startdate" initfuncname="init_enddate"> + minDateSrc="startdate" initfuncname="init_enddate"> function(elem) { update_bid(elem); } 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() -