Skip to content
This repository has been archived by the owner on Jun 18, 2020. It is now read-only.

Commit

Permalink
#9428 Internationalizes the notebook and adds a localization to Brazi…
Browse files Browse the repository at this point in the history
…lian Portuguese.
  • Loading branch information
lcmaquino committed Jul 5, 2010
1 parent 2ff328b commit a11b6f6
Show file tree
Hide file tree
Showing 70 changed files with 7,645 additions and 712 deletions.
2 changes: 2 additions & 0 deletions .hgignore
@@ -1,4 +1,6 @@
# Boring file regexps:
\.scssc$
\.sassc$
\.git$
\.hi$
\.mtl$
Expand Down
2 changes: 1 addition & 1 deletion MANIFEST.in
Expand Up @@ -3,4 +3,4 @@ recursive-include sass *
prune sass/src/.sass-cache
include *.txt Makefile MANIFEST.in .hgignore .hgtags sdist spkg-dist SPKG.txt go
recursive-include .hg *
global-exclude *.pyc *.pyo *.orig *.rej *~ \#* *\#
global-exclude *.pyc *.pyo *.orig *.rej *~ \#* *\# *.sassc *.scssc
25 changes: 25 additions & 0 deletions SPKG.txt
Expand Up @@ -42,6 +42,12 @@ GPLv2+
in setup.py. Dependencies of dependencies need not be put in setup.py, but
need to be put in ./spkg-dist.
* The Selenium tests pass (optional, for now).
* The localization file ``sagenb.pot`` is up-to-date .
* Run ``pybabel extract -F /path/to/babel.cfg /path/to/project
-o /path/to/sagenb.po`` (get pybabel with ``easy_install
pybabel``).
* Copy the headers from the existing ``sagenb.pot``.
* Replace ``sagenb.pot`` with ``sagenb.po``.

Then,

Expand All @@ -54,6 +60,25 @@ GPLv2+

* Stylesheets (CSS): see sass/readme.txt.

* To add a locale to an existing install:

* Create a new locale, or download one from
`http://wiki.sagemath.org/i18n`_:

* To create a new locale:

* Edit and save a copy of ``sagenb.pot``
using your favorite text editor or POEdit (http://poedit.net)

* (Recommended) Post the new locale to
`http://wiki.sagemath.org/i18n`_

* Compile your copy via ``msgfmt sagenb.pot -o sagenb.mo``

* Copy ``sagenb.mo`` to ``sagenb/locale/xx_YY/LC_MESSAGES/``,
where xx_YY is a locale code (en_US, pt_BR, en_UK, etc.)


== Changelog ==

* For an accurate log of changes, run "hg log" in src/sagenb.
19 changes: 14 additions & 5 deletions flask_version/admin.py
@@ -1,6 +1,8 @@
import os
from flask import Module, url_for, render_template, request, session, redirect, g, current_app
from decorators import login_required, admin_required, with_lock
from flaskext.babel import Babel, gettext, ngettext, lazy_gettext
_ = gettext

admin = Module('flask_version.admin')

Expand Down Expand Up @@ -62,25 +64,32 @@ def add_user():
error='username_taken', username_input=username, **template_dict)
g.notebook.user_manager().add_user(username, password, '', force=True)

#XXX: i18n
return current_app.message('The temporary password for the new user <em>%s</em> is <em>%s</em>' %
(username, password), '/adduser',
title=u'New User')
message = gettext('The temporary password for the new user <em>%(username)s</em> is <em>%(password)s</em>',
username=username, password=password)
return current_app.message(message='/adduser', title=_('New User'))
else:
return render_template(os.path.join('html', 'settings', 'admin_add_user.html'),
**template_dict)

@admin.route('/notebooksettings')
@admin.route('/notebooksettings', methods=['GET', 'POST'])
@admin_required
@with_lock
def notebook_settings():
updated = {}
if 'form' in request.values:
updated = g.notebook.conf().update_from_form(request.values)

#Make changes to the default language used
if 'default_language' in request.values:
from flaskext.babel import refresh
refresh()
current_app.config['BABEL_DEFAULT_LOCALE'] = request.values['default_language']

template_dict = {}
template_dict['auto_table'] = g.notebook.conf().html_table(updated)
template_dict['admin'] = g.notebook.user_manager().user(g.username).is_admin()
template_dict['username'] = g.username

return render_template(os.path.join('html', 'settings', 'notebook_settings.html'),
**template_dict)

13 changes: 7 additions & 6 deletions flask_version/authentication.py
Expand Up @@ -2,6 +2,8 @@
import random
from flask import Module, url_for, render_template, request, session, redirect, g, current_app
from decorators import with_lock
from flaskext.babel import gettext, ngettext, lazy_gettext
_ = gettext

authentication = Module('flask_version.authentication')

Expand Down Expand Up @@ -246,24 +248,23 @@ def register():
@with_lock
def confirm():
if not g.notebook.conf()['email']:
return current_app.message('The confirmation system is nlot active.')
return current_app.message(_('The confirmation system is not active.'))
key = int(request.values.get('key', '-1'))

#XXX: i18n
invalid_confirm_key = """\
invalid_confirm_key = _("""\
<h1>Invalid confirmation key</h1>
<p>You are reporting a confirmation key that has not been assigned by this
server. Please <a href="/register">register</a> with the server.</p>
"""
""")
try:
username = waiting[key]
user = g.notebook.user(username)
user.set_email_confirmation(True)
except KeyError:
return current_app.message(invalid_confirm_key, '/register')
success = """<h1>Email address confirmed for user %s</h1>""" % username #XXX: i18n
success = _("""<h1>Email address confirmed for user %(username)s</h1>""", username=username)
del waiting[key]
return current_app.message(success, title='Email Confirmed') #XXX: i18n
return current_app.message(success, title=_('Email Confirmed'))

@authentication.route('/forgotpass')
@with_lock
Expand Down
33 changes: 26 additions & 7 deletions flask_version/base.py
Expand Up @@ -8,6 +8,9 @@
from flaskext.autoindex import AutoIndex
SRC = os.path.join(os.environ['SAGE_ROOT'], 'devel', 'sage', 'sage')
from flaskext.openid import OpenID
from flaskext.babel import Babel, gettext, ngettext, lazy_gettext, get_locale
from sagenb.misc.misc import SAGENB_ROOT, DATA, SAGE_DOC, translations_path

oid = OpenID()

class SageNBFlask(Flask):
Expand All @@ -17,7 +20,8 @@ def __init__(self, *args, **kwds):
self.startup_token = kwds.pop('startup_token', None)
Flask.__init__(self, *args, **kwds)

from sagenb.misc.misc import DATA
self.root_path = SAGENB_ROOT

self.add_static_path('/css', os.path.join(DATA, "sage", "css"))
self.add_static_path('/images', os.path.join(DATA, "sage", "images"))
self.add_static_path('/javascript/sage', os.path.join(DATA, "sage", "js"))
Expand All @@ -32,7 +36,6 @@ def __init__(self, *args, **kwds):
# Doc #
#######
#These "should" be in doc.py
from sagenb.misc.misc import SAGE_DOC
DOC = os.path.join(SAGE_DOC, 'output', 'html', 'en')
self.add_static_path('/pdf', os.path.join(SAGE_DOC, 'output', 'pdf'))
self.add_static_path('/doc/static', DOC)
Expand Down Expand Up @@ -126,6 +129,14 @@ def main_js():
response.headers['Content-Type'] = 'text/javascript; charset=utf-8'
return response

@base.route('/javascript/sage/localization.js')
def localization_js():
print "localization.js"
response = make_response(render_template(os.path.join('js/localization.js')))
response.headers['Content-Type'] = 'text/javascript; charset=utf-8'
return response


@base.route('/javascript/sage/jsmath.js')
def jsmath_js():
from sagenb.misc.misc import jsmath_macros
Expand Down Expand Up @@ -173,7 +184,7 @@ def history():
@login_required
@with_lock
def live_history():
W = g.notebook.create_new_worksheet_from_history('Log', g.username, 100)
W = g.notebook.create_new_worksheet_from_history(gettext('Log'), g.username, 100)
from worksheet import url_for_worksheet
return redirect(url_for_worksheet(W))

Expand All @@ -183,7 +194,6 @@ def live_history():
@base.route('/favicon.ico')
def favicon():
from flask.helpers import send_file
from sagenb.misc.misc import DATA
return send_file(os.path.join(DATA, 'sage', 'images', 'favicon.ico'))

@base.route('/loginoid', methods=['POST', 'GET'])
Expand Down Expand Up @@ -323,6 +333,13 @@ def create_app(path_to_notebook, *args, **kwds):
def set_notebook_object():
g.notebook = notebook

####################################
# create Babel translation manager #
####################################
babel = Babel(app, default_locale=notebook.conf()['default_language'],
default_timezone='UTC',
date_formats=None, configure_jinja=True)

########################
# Register the modules #
########################
Expand Down Expand Up @@ -357,9 +374,11 @@ def autoindex(path='.'):
if os.path.isfile(filename):
from cgi import escape
src = escape(open(filename).read().decode('utf-8','ignore'))
if os.path.splitext(filename)[1] in \
['.py','.c','.cc','.h','.hh','.pyx','.pyd']:
return render_template(os.path.join('html', 'source_code.html'), src_filename=path, src=src, username = g.username)
if (os.path.splitext(filename)[1] in
['.py','.c','.cc','.h','.hh','.pyx','.pyd']):
return render_template(os.path.join('html', 'source_code.html'),
src_filename=path,
src=src, username = g.username)
return src
return idx.render_autoindex(path)

Expand Down
6 changes: 4 additions & 2 deletions flask_version/decorators.py
@@ -1,5 +1,8 @@
from functools import wraps
from flask import Flask, url_for, render_template, request, session, redirect, g
from flaskext.babel import Babel, gettext, ngettext, lazy_gettext
_ = gettext

from threading import Lock
global_lock = Lock()

Expand All @@ -23,8 +26,7 @@ def admin_required(f):
@wraps(f)
def wrapper(*args, **kwds):
if not g.notebook.user_manager().user_is_admin(g.username):
#XXX: i18n
app.message("You do not have permission to access this location")
app.message(_("You do not have permission to access this location"))
return f(*args, **kwds)

return wrapper
Expand Down
2 changes: 0 additions & 2 deletions flask_version/settings.py
Expand Up @@ -74,5 +74,3 @@ def settings_page():

return render_template(os.path.join('html', 'settings', 'account_settings.html'), **td)



29 changes: 13 additions & 16 deletions flask_version/worksheet.py
Expand Up @@ -3,6 +3,8 @@
from flask import Module, url_for, render_template, request, session, redirect, g, current_app
from decorators import login_required, with_lock
from collections import defaultdict
from flaskext.babel import Babel, gettext, ngettext, lazy_gettext
_ = gettext

ws = Module('flask_version.worksheet')
worksheet_locks = defaultdict(threading.Lock)
Expand All @@ -15,7 +17,7 @@ def wrapper(username, id, **kwds):
try:
worksheet = kwds['worksheet'] = g.notebook.get_worksheet_with_filename(worksheet_filename)
except KeyError:
return current_app.message("You do not have permission to access this worksheet") #XXX: i18n
return current_app.message(_("You do not have permission to access this worksheet"))

with worksheet_locks[worksheet]:
owner = worksheet.owner()
Expand All @@ -24,7 +26,7 @@ def wrapper(username, id, **kwds):
if not worksheet.is_published():
if (not g.username in worksheet.collaborators() and
not g.notebook.user_manager().user_is_admin(g.username)):
return current_app.message("You do not have permission to access this worksheet") #XXX: i18n
return current_app.message(_("You do not have permission to access this worksheet"))

if not worksheet.is_published():
worksheet.set_active(g.username)
Expand Down Expand Up @@ -64,7 +66,7 @@ def get_cell_id():
@login_required
@with_lock
def new_worksheet():
W = g.notebook.create_new_worksheet("Untitled", g.username)
W = g.notebook.create_new_worksheet(gettext("Untitled"), g.username)
return redirect(url_for_worksheet(W))

@ws.route('/home/<username>/<id>/')
Expand Down Expand Up @@ -558,7 +560,7 @@ def worksheet_datafile(worksheet):
if request.values.get('action', '') == 'delete':
path = os.path.join(dir, filename)
os.unlink(path)
return current_app.message("Successfully deleted '%s'"%filename) #XXX: i18n
return current_app.message(_("Successfully deleted '%(filename)s'", filename=filename))
else:
return g.notebook.html_download_or_delete_datafile(worksheet, g.username, filename)

Expand All @@ -583,7 +585,7 @@ def worksheet_link_datafile(worksheet):
target = os.path.abspath(os.path.join(
target_ws.data_directory(), data_filename))
if target_ws.owner() != g.username and not target_ws.is_collaborator(g.username):
return current_app.message("illegal link attempt!") #XXX: i18n
return current_app.message(_("illegal link attempt!"))
os.system('ln "%s" "%s"'%(src, target))
return redirect(worksheet_link_datafile.url_for(worksheet, name=data_filename))
#return redirect(url_for_worksheet(target_ws) + '/datafile?name=%s'%data_filename) #XXX: Can we not hardcode this?
Expand All @@ -599,21 +601,18 @@ def worksheet_do_upload_data(worksheet):
worksheet_url = url_for_worksheet(worksheet)
upload_url = worksheet_upload_data.url_for(worksheet)

#XXX: i18n
backlinks = """ Return to <a href="%s" title="Upload or create a data file in a wide range of formats"><strong>Upload or Create Data File</strong></a> or <a href="%s" title="Interactively use the worksheet"><strong>%s</strong></a>.""" % (upload_url, worksheet_url, worksheet.name())
backlinks = _(""" Return to <a href="%(upload_url)s" title="Upload or create a data file in a wide range of formats"><strong>Upload or Create Data File</strong></a> or <a href="%(worksheet_url)s" title="Interactively use the worksheet"><strong>%(worksheet_name)s</strong></a>.""", upload_url=upload_url, worksheet_url=worksheet_url, worksheet_name=worksheet.name())


if 'file' not in request.files:
#XXX: i18n
return current_app.message('Error uploading file (missing field "file").%s' % backlinks, worksheet_url)
return current_app.message(_('Error uploading file (missing field "file"). %(backlinks)s', backlinks=backlinks), worksheet_url)
else:
file = request.files['file']

text_fields = ['url', 'new', 'name']
for field in text_fields:
if field not in request.values:
#XXX: i18n
return current_app.message('Error uploading file (missing %s arg).%s' % (field, backlinks), worksheet_url)
return current_app.message(_('Error uploading file (missing %(field)s arg).%(backlinks)s', field=field, backlinks=backlinks), worksheet_url)


name = request.values.get('name', '').strip()
Expand All @@ -626,15 +625,13 @@ def worksheet_do_upload_data(worksheet):
name = secure_filename(name)

if not name:
#XXX: i18n
return current_app.message('Error uploading file (missing filename).%s' % backlinks, worksheet_url)
return current_app.message(_('Error uploading file (missing filename).%(backlinks)s', backlinks=backlinks), worksheet_url)

#XXX: disk access
dest = os.path.join(worksheet.data_directory(), name)
if os.path.exists(dest):
if not os.path.isfile(dest):
#XXX: i18n
return current_app.message('Suspicious filename "%s" encountered uploading file.%s' % (name, backlinks), worksheet_url)
return current_app.message(_('Suspicious filename "%(filename)s" encountered uploading file.%(backlinks)s', filename=filename, backlinks=backlinks), worksheet_url)
os.unlink(dest)


Expand Down Expand Up @@ -821,7 +818,7 @@ def extract_title(html_page):
h = html_page.lower()
i = h.find('<title>')
if i == -1:
return "Untitled"
return gettext("Untitled")
j = h.find('</title>')
return html_page[i + len('<title>') : j]

Expand Down

0 comments on commit a11b6f6

Please sign in to comment.