Commit ee46f523 authored by Serge S. Koval's avatar Serge S. Koval

Added localization support through Flask-Babel.

parent cf4179ad
- Core - Core
- View Site button? - View Site button?
- Localization
- Model Admin - Model Admin
- Ability to sort by fields that are not visible? - Reduce number of parameters passed to list view
- List display callables - Checkboxes and mass operations
- Form Fields
- Override field class by field name
- Verify how boolean field is rendered
- Filters - Filters
- Custom filters for date fields? - Custom filters for date fields?
- Checkboxes and mass operations - Ability to sort by fields that are not visible?
- List display callables?
- SQLA Model Admin - SQLA Model Admin
- Many2Many support - Many2Many support
- Verify if it is working properly - Verify if it is working properly
...@@ -17,8 +16,7 @@ ...@@ -17,8 +16,7 @@
- Header title - Header title
- Mass-delete functionality - Mass-delete functionality
- File size restriction - File size restriction
- Localization
- Unit tests - Unit tests
- Form generation tests - Form generation tests
- Documentation - Documentation
- Add all new stuff - Add all new stuff
\ No newline at end of file
from flask import _request_ctx_stack
def _gettext(string, **variables):
return string % variables
def _ngettext(singular, plural, num, **variables):
return (singular if num == 1 else plural) % variables
def _lazy_gettext(string, **variables):
return string % variables
# Wrap flask-babel API
try:
from flask.ext import babel
def _is_babel_on():
ctx = _request_ctx_stack.top
if ctx is None:
return False
return hasattr(ctx, 'babel_locale')
def gettext(string, **variables):
if not _is_babel_on():
return _gettext(string, **variables)
return babel.gettext(string, **variables)
def ngettext(singular, plural, num, **variables):
if not _is_babel_on():
return _ngettext(singular, plural, num, **variables)
return babel.ngettext(singular, plural, num, **variables)
def lazy_gettext(string, **variables):
from speaklater import make_lazy_string
return make_lazy_string(gettext, string, **variables)
except ImportError:
gettext = _gettext
ngettext = _ngettext
lazy_gettext = _lazy_gettext
...@@ -3,6 +3,8 @@ from re import sub ...@@ -3,6 +3,8 @@ from re import sub
from flask import Blueprint, render_template, url_for, abort from flask import Blueprint, render_template, url_for, abort
from flask.ext.adminex import babel
def expose(url='/', methods=('GET',)): def expose(url='/', methods=('GET',)):
""" """
...@@ -159,6 +161,11 @@ class BaseView(object): ...@@ -159,6 +161,11 @@ class BaseView(object):
# Store self as admin_view # Store self as admin_view
kwargs['admin_view'] = self kwargs['admin_view'] = self
# Provide i18n support even if flask-babel is not installed
# or enabled.
kwargs['_gettext'] = babel.gettext
kwargs['_ngettext'] = babel.ngettext
return render_template(template, **kwargs) return render_template(template, **kwargs)
def _prettify_name(self, name): def _prettify_name(self, name):
...@@ -260,9 +267,6 @@ class MenuItem(object): ...@@ -260,9 +267,6 @@ class MenuItem(object):
def get_children(self): def get_children(self):
return [c for c in self._children if c.is_accessible()] return [c for c in self._children if c.is_accessible()]
def __repr__(self):
return 'MenuItem %s (%s)' % (self.name, repr(self._children))
class Admin(object): class Admin(object):
""" """
......
...@@ -7,11 +7,12 @@ import shutil ...@@ -7,11 +7,12 @@ import shutil
from operator import itemgetter from operator import itemgetter
from flask import flash, url_for, redirect, abort, request
from werkzeug import secure_filename from werkzeug import secure_filename
from flask import flash, url_for, redirect, abort, request
from flask.ext.adminex.base import BaseView, expose from flask.ext.adminex.base import BaseView, expose
from flask.ext.adminex.babel import gettext, lazy_gettext
from flask.ext.adminex import form from flask.ext.adminex import form
from flask.ext import wtf from flask.ext import wtf
...@@ -28,7 +29,7 @@ class NameForm(form.BaseForm): ...@@ -28,7 +29,7 @@ class NameForm(form.BaseForm):
def validate_name(self, field): def validate_name(self, field):
if not self.regexp.match(field.data): if not self.regexp.match(field.data):
raise wtf.ValidationError('Invalid directory name') raise wtf.ValidationError(gettext('Invalid directory name'))
class UploadForm(form.BaseForm): class UploadForm(form.BaseForm):
...@@ -36,7 +37,7 @@ class UploadForm(form.BaseForm): ...@@ -36,7 +37,7 @@ class UploadForm(form.BaseForm):
File upload form. Works with FileAdmin instance to check if it is allowed File upload form. Works with FileAdmin instance to check if it is allowed
to upload file with given extension. to upload file with given extension.
""" """
upload = wtf.FileField('File to upload') upload = wtf.FileField(lazy_gettext('File to upload'))
def __init__(self, admin): def __init__(self, admin):
self.admin = admin self.admin = admin
...@@ -45,12 +46,12 @@ class UploadForm(form.BaseForm): ...@@ -45,12 +46,12 @@ class UploadForm(form.BaseForm):
def validate_upload(self, field): def validate_upload(self, field):
if not self.upload.has_file(): if not self.upload.has_file():
raise wtf.ValidationError('File required.') raise wtf.ValidationError(gettext('File required.'))
filename = self.upload.data.filename filename = self.upload.data.filename
if not self.admin.is_file_allowed(filename): if not self.admin.is_file_allowed(filename):
raise wtf.ValidationError('Invalid file type.') raise wtf.ValidationError(gettext('Invalid file type.'))
class FileAdmin(BaseView): class FileAdmin(BaseView):
...@@ -331,7 +332,7 @@ class FileAdmin(BaseView): ...@@ -331,7 +332,7 @@ class FileAdmin(BaseView):
base_path, directory, path = self._normalize_path(path) base_path, directory, path = self._normalize_path(path)
if not self.can_upload: if not self.can_upload:
flash('File uploading is disabled.', 'error') flash(gettext('File uploading is disabled.'), 'error')
return redirect(self._get_dir_url('.index', path)) return redirect(self._get_dir_url('.index', path))
form = UploadForm(self) form = UploadForm(self)
...@@ -340,14 +341,14 @@ class FileAdmin(BaseView): ...@@ -340,14 +341,14 @@ class FileAdmin(BaseView):
secure_filename(form.upload.data.filename)) secure_filename(form.upload.data.filename))
if op.exists(filename): if op.exists(filename):
flash('File "%s" already exists.' % form.upload.data.filename, flash(gettext('File "%(name)s" already exists.', name=form.upload.data.filename),
'error') 'error')
else: else:
try: try:
self.save_file(filename, form.upload.data) self.save_file(filename, form.upload.data)
return redirect(self._get_dir_url('.index', path)) return redirect(self._get_dir_url('.index', path))
except Exception, ex: except Exception, ex:
flash('Failed to save file: %s' % ex) flash(gettext('Failed to save file: %(error)s', error=ex))
return self.render(self.upload_template, form=form) return self.render(self.upload_template, form=form)
...@@ -366,7 +367,7 @@ class FileAdmin(BaseView): ...@@ -366,7 +367,7 @@ class FileAdmin(BaseView):
dir_url = self._get_dir_url('.index', path) dir_url = self._get_dir_url('.index', path)
if not self.can_mkdir: if not self.can_mkdir:
flash('Directory creation is disabled.', 'error') flash(gettext('Directory creation is disabled.'), 'error')
return redirect(dir_url) return redirect(dir_url)
form = NameForm(request.form) form = NameForm(request.form)
...@@ -376,7 +377,7 @@ class FileAdmin(BaseView): ...@@ -376,7 +377,7 @@ class FileAdmin(BaseView):
os.mkdir(op.join(directory, form.name.data)) os.mkdir(op.join(directory, form.name.data))
return redirect(dir_url) return redirect(dir_url)
except Exception, ex: except Exception, ex:
flash('Failed to create directory: %s' % ex, 'error') flash(gettext('Failed to create directory: %(error)s', ex), 'error')
return self.render(self.mkdir_template, return self.render(self.mkdir_template,
form=form, form=form,
...@@ -398,25 +399,25 @@ class FileAdmin(BaseView): ...@@ -398,25 +399,25 @@ class FileAdmin(BaseView):
return_url = self._get_dir_url('.index', op.dirname(path)) return_url = self._get_dir_url('.index', op.dirname(path))
if not self.can_delete: if not self.can_delete:
flash('Deletion is disabled.') flash(gettext('Deletion is disabled.'))
return redirect(return_url) return redirect(return_url)
if op.isdir(full_path): if op.isdir(full_path):
if not self.can_delete_dirs: if not self.can_delete_dirs:
flash('Directory deletion is disabled.') flash(gettext('Directory deletion is disabled.'))
return redirect(return_url) return redirect(return_url)
try: try:
shutil.rmtree(full_path) shutil.rmtree(full_path)
flash('Directory "%s" was successfully deleted.' % path) flash(gettext('Directory "%s" was successfully deleted.' % path))
except Exception, ex: except Exception, ex:
flash('Failed to delete directory: %s' % ex, 'error') flash(gettext('Failed to delete directory: %(error)s', error=ex), 'error')
else: else:
try: try:
os.remove(full_path) os.remove(full_path)
flash('File "%s" was successfully deleted.' % path) flash(gettext('File "%(name)s" was successfully deleted.', name=path))
except Exception, ex: except Exception, ex:
flash('Failed to delete file: %s' % ex, 'error') flash(gettext('Failed to delete file: %(name)s', name=ex), 'error')
return redirect(return_url) return redirect(return_url)
...@@ -435,11 +436,11 @@ class FileAdmin(BaseView): ...@@ -435,11 +436,11 @@ class FileAdmin(BaseView):
return_url = self._get_dir_url('.index', op.dirname(path)) return_url = self._get_dir_url('.index', op.dirname(path))
if not self.can_rename: if not self.can_rename:
flash('Renaming is disabled.') flash(gettext('Renaming is disabled.'))
return redirect(return_url) return redirect(return_url)
if not op.exists(full_path): if not op.exists(full_path):
flash('Path does not exist.') flash(gettext('Path does not exist.'))
return redirect(return_url) return redirect(return_url)
form = NameForm(request.form, name=op.basename(path)) form = NameForm(request.form, name=op.basename(path))
...@@ -449,11 +450,11 @@ class FileAdmin(BaseView): ...@@ -449,11 +450,11 @@ class FileAdmin(BaseView):
filename = secure_filename(form.name.data) filename = secure_filename(form.name.data)
os.rename(full_path, op.join(dir_base, filename)) os.rename(full_path, op.join(dir_base, filename))
flash('Successfully renamed "%s" to "%s"' % ( flash(gettext('Successfully renamed "%(src)s" to "%(dst)s"',
op.basename(path), src=op.basename(path),
filename)) dst=filename))
except Exception, ex: except Exception, ex:
flash('Failed to rename: %s' % ex, 'error') flash(gettext('Failed to rename: %(error)s', error=ex), 'error')
return redirect(return_url) return redirect(return_url)
......
from flask.ext.babel import gettext
from flask.ext.adminex.model import filters from flask.ext.adminex.model import filters
from flask.ext.adminex.ext.sqlamodel import tools from flask.ext.adminex.ext.sqlamodel import tools
...@@ -30,7 +32,7 @@ class FilterEqual(BaseSQLAFilter): ...@@ -30,7 +32,7 @@ class FilterEqual(BaseSQLAFilter):
return query.filter(self.column == value) return query.filter(self.column == value)
def operation(self): def operation(self):
return 'equals' return gettext('equals')
class FilterNotEqual(BaseSQLAFilter): class FilterNotEqual(BaseSQLAFilter):
...@@ -38,7 +40,7 @@ class FilterNotEqual(BaseSQLAFilter): ...@@ -38,7 +40,7 @@ class FilterNotEqual(BaseSQLAFilter):
return query.filter(self.column != value) return query.filter(self.column != value)
def operation(self): def operation(self):
return 'not equal' return gettext('not equal')
class FilterLike(BaseSQLAFilter): class FilterLike(BaseSQLAFilter):
...@@ -47,7 +49,7 @@ class FilterLike(BaseSQLAFilter): ...@@ -47,7 +49,7 @@ class FilterLike(BaseSQLAFilter):
return query.filter(self.column.ilike(stmt)) return query.filter(self.column.ilike(stmt))
def operation(self): def operation(self):
return 'like' return gettext('contains')
class FilterNotLike(BaseSQLAFilter): class FilterNotLike(BaseSQLAFilter):
...@@ -56,7 +58,7 @@ class FilterNotLike(BaseSQLAFilter): ...@@ -56,7 +58,7 @@ class FilterNotLike(BaseSQLAFilter):
return query.filter(~self.column.ilike(stmt)) return query.filter(~self.column.ilike(stmt))
def operation(self): def operation(self):
return 'not like' return gettext('not contains')
class FilterGreater(BaseSQLAFilter): class FilterGreater(BaseSQLAFilter):
...@@ -64,7 +66,7 @@ class FilterGreater(BaseSQLAFilter): ...@@ -64,7 +66,7 @@ class FilterGreater(BaseSQLAFilter):
return query.filter(self.column > value) return query.filter(self.column > value)
def operation(self): def operation(self):
return 'greater than' return gettext('greater than')
class FilterSmaller(BaseSQLAFilter): class FilterSmaller(BaseSQLAFilter):
...@@ -72,7 +74,7 @@ class FilterSmaller(BaseSQLAFilter): ...@@ -72,7 +74,7 @@ class FilterSmaller(BaseSQLAFilter):
return query.filter(self.column < value) return query.filter(self.column < value)
def operation(self): def operation(self):
return 'smaller than' return gettext('smaller than')
# Customized type filters # Customized type filters
......
...@@ -6,6 +6,7 @@ from sqlalchemy import or_ ...@@ -6,6 +6,7 @@ from sqlalchemy import or_
from wtforms.ext.sqlalchemy.orm import model_form from wtforms.ext.sqlalchemy.orm import model_form
from flask import flash from flask import flash
from flask.ext.babel import gettext
from flask.ext.adminex.form import BaseForm from flask.ext.adminex.form import BaseForm
from flask.ext.adminex.model import BaseModelView from flask.ext.adminex.model import BaseModelView
...@@ -500,7 +501,7 @@ class ModelView(BaseModelView): ...@@ -500,7 +501,7 @@ class ModelView(BaseModelView):
self.session.commit() self.session.commit()
return True return True
except Exception, ex: except Exception, ex:
flash('Failed to create model. ' + str(ex), 'error') flash(gettext('Failed to create model. %(error)s', error=str(ex)), 'error')
return False return False
def update_model(self, form, model): def update_model(self, form, model):
...@@ -515,7 +516,7 @@ class ModelView(BaseModelView): ...@@ -515,7 +516,7 @@ class ModelView(BaseModelView):
self.session.commit() self.session.commit()
return True return True
except Exception, ex: except Exception, ex:
flash('Failed to update model. ' + str(ex), 'error') flash(gettext('Failed to update model. %(error)s', error=str(ex)), 'error')
return False return False
def delete_model(self, model): def delete_model(self, model):
...@@ -530,5 +531,5 @@ class ModelView(BaseModelView): ...@@ -530,5 +531,5 @@ class ModelView(BaseModelView):
self.session.commit() self.session.commit()
return True return True
except Exception, ex: except Exception, ex:
flash('Failed to delete model. ' + str(ex), 'error') flash(gettext('Failed to delete model. %(error)s', error=str(ex)), 'error')
return False return False
...@@ -4,6 +4,8 @@ import datetime ...@@ -4,6 +4,8 @@ import datetime
from flask.ext import wtf from flask.ext import wtf
from wtforms import fields, widgets from wtforms import fields, widgets
from flask.ext.adminex.babel import gettext
class BaseForm(wtf.Form): class BaseForm(wtf.Form):
""" """
...@@ -76,7 +78,7 @@ class TimeField(fields.Field): ...@@ -76,7 +78,7 @@ class TimeField(fields.Field):
except ValueError: except ValueError:
pass pass
raise ValueError('Invalid time format') raise ValueError(gettext('Invalid time format'))
class ChosenSelectWidget(widgets.Select): class ChosenSelectWidget(widgets.Select):
......
from flask import request, url_for, redirect, flash from flask import request, url_for, redirect, flash
from flask.ext.babel import gettext
from flask.ext.adminex.base import BaseView, expose from flask.ext.adminex.base import BaseView, expose
from flask.ext.adminex.model import filters from flask.ext.adminex.model import filters
...@@ -737,7 +739,7 @@ class BaseModelView(BaseView): ...@@ -737,7 +739,7 @@ class BaseModelView(BaseView):
if form.validate_on_submit(): if form.validate_on_submit():
if self.create_model(form): if self.create_model(form):
if '_add_another' in request.form: if '_add_another' in request.form:
flash('Model was successfully created.') flash(gettext('Model was successfully created.'))
return redirect(url_for('.create_view', url=return_url)) return redirect(url_for('.create_view', url=return_url))
else: else:
return redirect(return_url) return redirect(return_url)
......
from flask.ext.babel import lazy_gettext
class BaseFilter(object): class BaseFilter(object):
""" """
Base filter class. Base filter class.
...@@ -76,7 +79,8 @@ class BaseBooleanFilter(BaseFilter): ...@@ -76,7 +79,8 @@ class BaseBooleanFilter(BaseFilter):
""" """
def __init__(self, name, data_type=None): def __init__(self, name, data_type=None):
super(BaseBooleanFilter, self).__init__(name, super(BaseBooleanFilter, self).__init__(name,
(('1', 'Yes'), ('0', 'No')), (('1', lazy_gettext('Yes')),
('0', lazy_gettext('No'))),
data_type) data_type)
def validate(self, value): def validate(self, value):
......
{% extends 'admin/master.html' %} {% extends 'admin/master.html' %}
{% import 'admin/lib.html' as lib %} {% import 'admin/lib.html' as lib with context %}
{% block body %} {% block body %}
{{ lib.render_form(form, dir_url) }} {{ lib.render_form(form, dir_url) }}
......
{% extends 'admin/master.html' %} {% extends 'admin/master.html' %}
{% import 'admin/lib.html' as lib %} {% import 'admin/lib.html' as lib with context %}
{% block body %} {% block body %}
<ul class="breadcrumb"> <ul class="breadcrumb">
<li> <li>
<a href="{{ get_dir_url('.index', path=None) }}">Root</a> <a href="{{ get_dir_url('.index', path=None) }}">{{ _gettext('Root') }}</a>
</li> </li>
{% for name, path in breadcrumbs[:-1] %} {% for name, path in breadcrumbs[:-1] %}
<li> <li>
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
{% if name != '..' and admin_view.can_delete_dirs %} {% if name != '..' and admin_view.can_delete_dirs %}
<form class="icon" method="POST" action="{{ url_for('.delete') }}"> <form class="icon" method="POST" action="{{ url_for('.delete') }}">
<input type="hidden" name="path" value="{{ path }}"></input> <input type="hidden" name="path" value="{{ path }}"></input>
<button onclick="return confirm('Are you sure you want to delete \'{{ name }}\' recursively?')"> <button onclick="return confirm('{{ _gettext('Are you sure you want to delete \\\'%(name)s\\\' recursively?', name=name) }}')">
<i class="icon-remove"></i> <i class="icon-remove"></i>
</button> </button>
</form> </form>
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
{% else %} {% else %}
<form class="icon" method="POST" action="{{ url_for('.delete') }}"> <form class="icon" method="POST" action="{{ url_for('.delete') }}">
<input type="hidden" name="path" value="{{ path }}"></input> <input type="hidden" name="path" value="{{ path }}"></input>
<button onclick="return confirm('Are you sure you want to delete \'{{ name }}\'?')"> <button onclick="return confirm('{{ _gettext('Are you sure you want to delete \\\'%(name)s\\\'?', name=name) }}')">
<i class="icon-remove"></i> <i class="icon-remove"></i>
</button> </button>
</form> </form>
...@@ -72,9 +72,9 @@ ...@@ -72,9 +72,9 @@
{% endfor %} {% endfor %}
</table> </table>
{% if admin_view.can_upload %} {% if admin_view.can_upload %}
<a class="btn btn-primary btn-large" href="{{ get_dir_url('.upload', path=dir_path) }}">Upload File</a> <a class="btn btn-primary btn-large" href="{{ get_dir_url('.upload', path=dir_path) }}">{{ _gettext('Upload File') }}</a>
{% endif %} {% endif %}
{% if admin_view.can_mkdir %} {% if admin_view.can_mkdir %}
<a class="btn btn-primary btn-large" href="{{ get_dir_url('.mkdir', path=dir_path) }}">Create Directory</a> <a class="btn btn-primary btn-large" href="{{ get_dir_url('.mkdir', path=dir_path) }}">{{ _gettext('Create Directory') }}</a>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% extends 'admin/master.html' %} {% extends 'admin/master.html' %}
{% import 'admin/lib.html' as lib %} {% import 'admin/lib.html' as lib with context %}
{% block body %} {% block body %}
<h3>Please provide new name for <i>{{ name }}</i></h3> <h3>{{ _gettext('Please provide new name for %(name)s', name=name) }}</h3>
{{ lib.render_form(form, dir_url) }} {{ lib.render_form(form, dir_url) }}
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -107,7 +107,7 @@ ...@@ -107,7 +107,7 @@
{{ extra }} {{ extra }}
{% endif %} {% endif %}
{% if cancel_url %} {% if cancel_url %}
<a href="{{ cancel_url }}" class="btn btn-large">Cancel</a> <a href="{{ cancel_url }}" class="btn btn-large">{{ _gettext('Cancel') }}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>
......
{% extends 'admin/master.html' %} {% extends 'admin/master.html' %}
{% import 'admin/lib.html' as lib %} {% import 'admin/lib.html' as lib with context %}
{% block head %} {% block head %}
<link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet"> <link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet">
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
{% block body %} {% block body %}
{% macro extra() %} {% macro extra() %}
<input name="_add_another" type="submit" class="btn btn-primary btn-large" value="Save and Add" /> <input name="_add_another" type="submit" class="btn btn-primary btn-large" value="{{ _gettext('Save and Add') }}" />
{% endmacro %} {% endmacro %}
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<a href="{{ return_url }}">List</a> <a href="{{ return_url }}">List</a>
</li> </li>
<li class="active"> <li class="active">
<a href="#">Create</a> <a href="#">{{ _gettext('Create') }}</a>
</li> </li>
</ul> </ul>
{{ lib.render_form(form, return_url, extra()) }} {{ lib.render_form(form, return_url, extra()) }}
......
{% extends 'admin/master.html' %} {% extends 'admin/master.html' %}
{% import 'admin/lib.html' as lib %} {% import 'admin/lib.html' as lib with context %}
{% block head %} {% block head %}
<link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet"> <link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet">
......
{% extends 'admin/master.html' %} {% extends 'admin/master.html' %}
{% import 'admin/lib.html' as lib %} {% import 'admin/lib.html' as lib with context %}
{% block head %} {% block head %}
<link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet"> <link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet">
...@@ -9,18 +9,18 @@ ...@@ -9,18 +9,18 @@
{% block body %} {% block body %}
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <li class="active">
<a href="#">List ({{ count }})</a> <a href="#">{{ _gettext('List') }} ({{ count }})</a>
</li> </li>
{% if admin_view.can_create %} {% if admin_view.can_create %}
<li> <li>
<a href="{{ url_for('.create_view', url=return_url) }}">Create</a> <a href="{{ url_for('.create_view', url=return_url) }}">{{ _gettext('Create') }}</a>
</li> </li>
{% endif %} {% endif %}
{% if filter_groups %} {% if filter_groups %}
<li class="dropdown"> <li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> <a class="dropdown-toggle" data-toggle="dropdown" href="#">
Add Filter<b class="caret"></b> {{ _gettext('Add Filter') }}<b class="caret"></b>
</a> </a>
<ul class="dropdown-menu field-filters"> <ul class="dropdown-menu field-filters">
{% for k in filter_groups %} {% for k in filter_groups %}
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
{% if sort_desc %} {% if sort_desc %}
<input type="hidden" name="desc" value="{{ sort_desc }}"></input> <input type="hidden" name="desc" value="{{ sort_desc }}"></input>
{% endif %} {% endif %}
<input type="text" name="search" value="{{ search or '' }}" class="search-query span2" placeholder="Search"></input> <input type="text" name="search" value="{{ search or '' }}" class="search-query span2" placeholder="{{ _gettext('Search') }}"></input>
{% if search %} {% if search %}
<a href="{{ clear_search_url }}" class="clear"> <a href="{{ clear_search_url }}" class="clear">
<i class="icon-remove"></i> <i class="icon-remove"></i>
...@@ -54,9 +54,9 @@ ...@@ -54,9 +54,9 @@
{% if filter_groups %} {% if filter_groups %}
<form id="filter_form" method="GET" action="{{ return_url }}"> <form id="filter_form" method="GET" action="{{ return_url }}">
<div class="pull-right"> <div class="pull-right">
<button type="submit" class="btn btn-primary" style="display: none">Apply</button> <button type="submit" class="btn btn-primary" style="display: none">{{ _gettext('Apply') }}</button>
{% if active_filters %} {% if active_filters %}
<a href="{{ clear_search_url }}" class="btn">Reset Filters</a> <a href="{{ clear_search_url }}" class="btn">{{ _gettext('Reset Filters') }}</a>
{% endif %} {% endif %}
</div> </div>
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
{%- for i, flt in enumerate(active_filters) -%} {%- for i, flt in enumerate(active_filters) -%}
<div class="filter-row"> <div class="filter-row">
{% set filter = admin_view._filters[flt[0]] %} {% set filter = admin_view._filters[flt[0]] %}
<a href="#" class="btn remove-filter" title="Remove Filter"> <a href="#" class="btn remove-filter" title="{{ _gettext('Remove Filter') }}">
{{ filters[flt[0]] }} {{ filters[flt[0]] }}
</a><select class="filter-op" data-role="chosen"> </a><select class="filter-op" data-role="chosen">
{% for op in admin_view._filter_dict[filter.name] %} {% for op in admin_view._filter_dict[filter.name] %}
...@@ -125,7 +125,7 @@ ...@@ -125,7 +125,7 @@
{%- endif -%} {%- endif -%}
{%- if admin_view.can_delete -%} {%- if admin_view.can_delete -%}
<form class="icon" method="POST" action="{{ url_for('.delete_view', id=get_pk_value(row), url=return_url) }}"> <form class="icon" method="POST" action="{{ url_for('.delete_view', id=get_pk_value(row), url=return_url) }}">
<button onclick="return confirm('You sure you want to delete this item?')"> <button onclick="return confirm('{{ _gettext('You sure you want to delete this item?') }}');">
<i class="icon-remove"></i> <i class="icon-remove"></i>
</button> </button>
</form> </form>
......
...@@ -182,7 +182,6 @@ def test_submenu(): ...@@ -182,7 +182,6 @@ def test_submenu():
eq_(admin._menu[1].is_accessible(), False) eq_(admin._menu[1].is_accessible(), False)
eq_(len(admin._menu[1].get_children()), 1) eq_(len(admin._menu[1].get_children()), 1)
ok_(repr(admin._menu[1]).startswith('MenuItem '))
def test_delayed_init(): def test_delayed_init():
......
...@@ -217,8 +217,8 @@ def test_column_filters(): ...@@ -217,8 +217,8 @@ def test_column_filters():
eq_(view._filter_dict, {'Test1': [(0, 'equals'), eq_(view._filter_dict, {'Test1': [(0, 'equals'),
(1, 'not equal'), (1, 'not equal'),
(2, 'like'), (2, 'contains'),
(3, 'not like')]}) (3, 'not contains')]})
db.session.add(Model1('model1')) db.session.add(Model1('model1'))
db.session.add(Model1('model2')) db.session.add(Model1('model2'))
......
...@@ -18,7 +18,7 @@ setup( ...@@ -18,7 +18,7 @@ setup(
platforms='any', platforms='any',
install_requires=[ install_requires=[
'Flask>=0.7', 'Flask>=0.7',
'Flask-WTF>=0.6', 'Flask-WTF>=0.6'
], ],
tests_require=[ tests_require=[
'nose>=1.0' 'nose>=1.0'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment