diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..457923b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.vscode/ +/dbs/ +/doc/ +/eggs/ +/logs/ +python.txt +/webview/node_modules/ +/webview/.vscode/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..62db93e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 hsp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 6929456..341bcb1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,78 @@ -# weibo-analysis-system-master +## weibo-analysis-system +`毕业设计`:微博用户情感分析系统 + +> (2020/02/02)更新,近日有不少童鞋来问我这个项目跑不起的问题,当时水平有点不够,写的确实有点乱,这里简单说明一下项目下下来直接跑起的方法。前提先搞好python环境和vue环境,保证你有一个账户密码连上数据库mysql。 +1、pip install requirements.txt 安装python包 +2、修改mysql数据库的账户密码(weibosystem/ssettings)里面 +3、创建数据库 python manage.py makemigrations python manage.py migrate +4、创建后台xadmin账户python manage.py createsuperuser +5、登录后台,http://localhost:8000/xadmin/SpiderAPI/target/ 在爬虫API里面的爬虫设置,输入一个用户uid + cookie,然后即可开始在首页localhost:8000数据爬虫id爬虫 + +### 1、系统介绍(2019.5.4毕设已完成): + +> extra_apps:xadmin后台管理系统 + +> scrapydserver:Scrapy爬虫 + +> src:django app里面写接口 + +> webview:前端Vue代码 + +> weibosystem:django wsgi/url等配置 + +#### 1、系统技术架构介绍 + +> 前端使用:vue-cli + vue + vuex + axios + +> 后端使用:python + django + xadmin + request + scrapy + scrapyd + snownlp(模型已训练好,但并不是特别准确) + +#### 2、系统功能介绍 + +> ① 输入微博oid,爬取个人微博信息,情感分析处理后并展示(oid获取方式,进入个人微博首页如: https://weibo.com/u/1797112632 ,其中`1797112632`就是oid。)有些用户自定义了域名,右击查看网页源代码,搜索`['oid']`即可找到oid。下图是本系统爬取个人信息界面: + +![个人微博爬虫前端主界面](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/1.png?raw=true) + +![个人微博爬虫前端信息展示](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/3.png?raw=true) + +> ② 输入单条微博id,爬取个人微博信息(获取单条微博id的方式,打开微博客户端,随便找到一条微博,进入微博正文,点击右上角三个点,然后可以看到分享给微信好友,QQ好友等,在下面一栏有收藏等,往右边拖,找到复制链接,复制并粘贴出来。如 https://m.weibo.cn/1769965211/4366947749433348 ,其中`4366947749433348`就是单条微博id。)情感分析处理后并展示。本系统展示单条微博例子如下: + +![单条微博爬虫前端信息展示](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/4.png?raw=true) + +> ③ 输入微博id,或者多个微博id和Cookie启动持续爬虫。前提先运行Scrapyd服务。这个功能使用Scrpay爬虫,然后把数据存到Django的Model中。 + +![多用户爬虫启动](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/7.png?raw=true) + +> ④ 独立出来的文本情感分析API,输入任意一段中文,返回情感分析值,词频,关键词。 + +![独立爬虫API](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/8.png?raw=true) + +> ⑤ 数据库已爬虫的用户,其中持续爬虫模块点击进去就是③中的多用户爬虫,默认设置了组别是1,如需修改进入xadmin后台,修改即可,上面的点击个人账号,点击单条微博,也是进入信息展示界面。点击组别进入的多用户爬虫界面如下图: + +![已爬虫用户](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/2.png?raw=true) + +![多用户爬虫展示](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/5.png?raw=true) + +> ⑥ xadmin后台管理系统 + +![xadmin后台管理系统](https://github.com/Superbsco/weibo-analysis-system/blob/master/pic/6.png?raw=true) + +### 2、系统启动注意事项 + +[参考技术文档](https://github.com/Superbsco/weibo-analysis-system/blob/master/%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3%E8%AF%B4%E6%98%8E.md) + +按照技术文档按照完了之后,workon进入虚拟环境: + +#### 1、数据库自动生成,使用如下命令: + +```python +python manage.py makemigrations +python manage.py migrate +``` + +#### 2、初始化Cookies +爬虫之前一定要先进入xadmin后台,使用数据库自动生成后,xadmin的登录账号密码就没了,参考这里初始化账号:https://blog.csdn.net/a_little_snail/article/details/76984933 , +然后重设Cookie,获取新浪微博Cookie,可参考 https://blog.csdn.net/A_xiao_mili/article/details/77947802 这里。 + + + diff --git a/extra_apps/__init__.py b/extra_apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extra_apps/xadmin/.tx/config b/extra_apps/xadmin/.tx/config new file mode 100644 index 0000000..4a783a2 --- /dev/null +++ b/extra_apps/xadmin/.tx/config @@ -0,0 +1,14 @@ +[main] +host = https://www.transifex.com + +[xadmin-core.django] +file_filter = locale//LC_MESSAGES/django.po +source_file = locale/en/LC_MESSAGES/django.po +source_lang = en +type = PO + +[xadmin-core.djangojs] +file_filter = locale//LC_MESSAGES/djangojs.po +source_file = locale/en/LC_MESSAGES/djangojs.po +source_lang = en +type = PO \ No newline at end of file diff --git a/extra_apps/xadmin/__init__.py b/extra_apps/xadmin/__init__.py new file mode 100644 index 0000000..3e1a052 --- /dev/null +++ b/extra_apps/xadmin/__init__.py @@ -0,0 +1,70 @@ + +VERSION = (0,6,0) + +from xadmin.sites import AdminSite, site + +class Settings(object): + pass + + +def autodiscover(): + """ + Auto-discover INSTALLED_APPS admin.py modules and fail silently when + not present. This forces an import on them to register any admin bits they + may want. + """ + + from importlib import import_module + from django.conf import settings + from django.utils.module_loading import module_has_submodule + from django.apps import apps + + setattr(settings, 'CRISPY_TEMPLATE_PACK', 'bootstrap3') + setattr(settings, 'CRISPY_CLASS_CONVERTERS', { + "textinput": "textinput textInput form-control", + "fileinput": "fileinput fileUpload form-control", + "passwordinput": "textinput textInput form-control", + }) + + from xadmin.views import register_builtin_views + register_builtin_views(site) + + # load xadmin settings from XADMIN_CONF module + try: + xadmin_conf = getattr(settings, 'XADMIN_CONF', 'xadmin_conf.py') + conf_mod = import_module(xadmin_conf) + except Exception: + conf_mod = None + + if conf_mod: + for key in dir(conf_mod): + setting = getattr(conf_mod, key) + try: + if issubclass(setting, Settings): + site.register_settings(setting.__name__, setting) + except Exception: + pass + + from xadmin.plugins import register_builtin_plugins + register_builtin_plugins(site) + + for app_config in apps.get_app_configs(): + mod = import_module(app_config.name) + # Attempt to import the app's admin module. + try: + before_import_registry = site.copy_registry() + import_module('%s.adminx' % app_config.name) + except: + # Reset the model registry to the state before the last import as + # this import will have to reoccur on the next request and this + # could raise NotRegistered and AlreadyRegistered exceptions + # (see #8245). + site.restore_registry(before_import_registry) + + # Decide whether to bubble up this error. If the app just + # doesn't have an admin module, we can ignore the error + # attempting to import it, otherwise we want it to bubble up. + if module_has_submodule(mod, 'adminx'): + raise + +default_app_config = 'xadmin.apps.XAdminConfig' diff --git a/extra_apps/xadmin/__pycache__/__init__.cpython-36.pyc b/extra_apps/xadmin/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..f308809 Binary files /dev/null and b/extra_apps/xadmin/__pycache__/__init__.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/adminx.cpython-36.pyc b/extra_apps/xadmin/__pycache__/adminx.cpython-36.pyc new file mode 100644 index 0000000..01af8a3 Binary files /dev/null and b/extra_apps/xadmin/__pycache__/adminx.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/apps.cpython-36.pyc b/extra_apps/xadmin/__pycache__/apps.cpython-36.pyc new file mode 100644 index 0000000..aaea472 Binary files /dev/null and b/extra_apps/xadmin/__pycache__/apps.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/filters.cpython-36.pyc b/extra_apps/xadmin/__pycache__/filters.cpython-36.pyc new file mode 100644 index 0000000..02531a8 Binary files /dev/null and b/extra_apps/xadmin/__pycache__/filters.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/forms.cpython-36.pyc b/extra_apps/xadmin/__pycache__/forms.cpython-36.pyc new file mode 100644 index 0000000..23153fa Binary files /dev/null and b/extra_apps/xadmin/__pycache__/forms.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/layout.cpython-36.pyc b/extra_apps/xadmin/__pycache__/layout.cpython-36.pyc new file mode 100644 index 0000000..3804027 Binary files /dev/null and b/extra_apps/xadmin/__pycache__/layout.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/models.cpython-36.pyc b/extra_apps/xadmin/__pycache__/models.cpython-36.pyc new file mode 100644 index 0000000..6ba7b77 Binary files /dev/null and b/extra_apps/xadmin/__pycache__/models.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/sites.cpython-36.pyc b/extra_apps/xadmin/__pycache__/sites.cpython-36.pyc new file mode 100644 index 0000000..7134cac Binary files /dev/null and b/extra_apps/xadmin/__pycache__/sites.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/util.cpython-36.pyc b/extra_apps/xadmin/__pycache__/util.cpython-36.pyc new file mode 100644 index 0000000..b74f09e Binary files /dev/null and b/extra_apps/xadmin/__pycache__/util.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/vendors.cpython-36.pyc b/extra_apps/xadmin/__pycache__/vendors.cpython-36.pyc new file mode 100644 index 0000000..267cff3 Binary files /dev/null and b/extra_apps/xadmin/__pycache__/vendors.cpython-36.pyc differ diff --git a/extra_apps/xadmin/__pycache__/widgets.cpython-36.pyc b/extra_apps/xadmin/__pycache__/widgets.cpython-36.pyc new file mode 100644 index 0000000..78db7ea Binary files /dev/null and b/extra_apps/xadmin/__pycache__/widgets.cpython-36.pyc differ diff --git a/extra_apps/xadmin/adminx.py b/extra_apps/xadmin/adminx.py new file mode 100644 index 0000000..e7a66e0 --- /dev/null +++ b/extra_apps/xadmin/adminx.py @@ -0,0 +1,32 @@ +from __future__ import absolute_import +import xadmin +from .models import UserSettings, Log +from xadmin.layout import * + +from django.utils.translation import ugettext_lazy as _, ugettext + +class UserSettingsAdmin(object): + model_icon = 'fa fa-cog' + hidden_menu = True + +xadmin.site.register(UserSettings, UserSettingsAdmin) + +class LogAdmin(object): + + def link(self, instance): + if instance.content_type and instance.object_id and instance.action_flag != 'delete': + admin_url = self.get_admin_url('%s_%s_change' % (instance.content_type.app_label, instance.content_type.model), + instance.object_id) + return "%s" % (admin_url, _('Admin Object')) + else: + return '' + link.short_description = "" + link.allow_tags = True + link.is_column = False + + list_display = ('action_time', 'user', 'ip_addr', '__str__', 'link') + list_filter = ['user', 'action_time'] + search_fields = ['ip_addr', 'message'] + model_icon = 'fa fa-cog' + +xadmin.site.register(Log, LogAdmin) diff --git a/extra_apps/xadmin/apps.py b/extra_apps/xadmin/apps.py new file mode 100644 index 0000000..6bae500 --- /dev/null +++ b/extra_apps/xadmin/apps.py @@ -0,0 +1,15 @@ +from django.apps import AppConfig +from django.core import checks +from django.utils.translation import ugettext_lazy as _ +import xadmin + + +class XAdminConfig(AppConfig): + """Simple AppConfig which does not do automatic discovery.""" + + name = 'xadmin' + verbose_name = _("Administration") + + def ready(self): + self.module.autodiscover() + setattr(xadmin,'site',xadmin.site) diff --git a/extra_apps/xadmin/filters.py b/extra_apps/xadmin/filters.py new file mode 100644 index 0000000..9ab977a --- /dev/null +++ b/extra_apps/xadmin/filters.py @@ -0,0 +1,573 @@ +from __future__ import absolute_import +from django.db import models +from django.core.exceptions import ImproperlyConfigured +from django.utils.encoding import smart_text +from django.utils.translation import ugettext_lazy as _ +from django.utils import timezone +from django.template.loader import get_template +from django.template.context import Context +from django.utils import six +from django.utils.safestring import mark_safe +from django.utils.html import escape, format_html +from django.utils.text import Truncator +from django.core.cache import cache, caches + +from xadmin.views.list import EMPTY_CHANGELIST_VALUE +from xadmin.util import is_related_field, is_related_field2 +import datetime + +FILTER_PREFIX = '_p_' +SEARCH_VAR = '_q_' + +from .util import (get_model_from_relation, + reverse_field_path, get_limit_choices_to_from_path, prepare_lookup_value) + + +class BaseFilter(object): + title = None + template = 'xadmin/filters/list.html' + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + pass + + def __init__(self, request, params, model, admin_view): + self.used_params = {} + self.request = request + self.params = params + self.model = model + self.admin_view = admin_view + + if self.title is None: + raise ImproperlyConfigured( + "The filter '%s' does not specify " + "a 'title'." % self.__class__.__name__) + + def query_string(self, new_params=None, remove=None): + return self.admin_view.get_query_string(new_params, remove) + + def form_params(self): + arr = map(lambda k: FILTER_PREFIX + k, self.used_params.keys()) + if six.PY3: + arr = list(arr) + return self.admin_view.get_form_params(remove=arr) + + def has_output(self): + """ + Returns True if some choices would be output for this filter. + """ + raise NotImplementedError + + @property + def is_used(self): + return len(self.used_params) > 0 + + def do_filte(self, queryset): + """ + Returns the filtered queryset. + """ + raise NotImplementedError + + def get_context(self): + return {'title': self.title, 'spec': self, 'form_params': self.form_params()} + + def __str__(self): + tpl = get_template(self.template) + return mark_safe(tpl.render(context=self.get_context())) + + +class FieldFilterManager(object): + _field_list_filters = [] + _take_priority_index = 0 + + def register(self, list_filter_class, take_priority=False): + if take_priority: + # This is to allow overriding the default filters for certain types + # of fields with some custom filters. The first found in the list + # is used in priority. + self._field_list_filters.insert( + self._take_priority_index, list_filter_class) + self._take_priority_index += 1 + else: + self._field_list_filters.append(list_filter_class) + return list_filter_class + + def create(self, field, request, params, model, admin_view, field_path): + for list_filter_class in self._field_list_filters: + if not list_filter_class.test(field, request, params, model, admin_view, field_path): + continue + return list_filter_class(field, request, params, + model, admin_view, field_path=field_path) + +manager = FieldFilterManager() + + +class FieldFilter(BaseFilter): + + lookup_formats = {} + + def __init__(self, field, request, params, model, admin_view, field_path): + self.field = field + self.field_path = field_path + self.title = getattr(field, 'verbose_name', field_path) + self.context_params = {} + + super(FieldFilter, self).__init__(request, params, model, admin_view) + + for name, format in self.lookup_formats.items(): + p = format % field_path + self.context_params["%s_name" % name] = FILTER_PREFIX + p + if p in params: + value = prepare_lookup_value(p, params.pop(p)) + self.used_params[p] = value + self.context_params["%s_val" % name] = value + else: + self.context_params["%s_val" % name] = '' + + arr = map( + lambda kv: setattr(self, 'lookup_' + kv[0], kv[1]), + self.context_params.items() + ) + if six.PY3: + list(arr) + + def get_context(self): + context = super(FieldFilter, self).get_context() + context.update(self.context_params) + obj = map(lambda k: FILTER_PREFIX + k, self.used_params.keys()) + if six.PY3: + obj = list(obj) + context['remove_url'] = self.query_string({}, obj) + return context + + def has_output(self): + return True + + def do_filte(self, queryset): + return queryset.filter(**self.used_params) + + +class ListFieldFilter(FieldFilter): + template = 'xadmin/filters/list.html' + + def get_context(self): + context = super(ListFieldFilter, self).get_context() + context['choices'] = list(self.choices()) + return context + + +@manager.register +class BooleanFieldListFilter(ListFieldFilter): + lookup_formats = {'exact': '%s__exact', 'isnull': '%s__isnull'} + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return isinstance(field, (models.BooleanField, models.NullBooleanField)) + + def choices(self): + for lookup, title in ( + ('', _('All')), + ('1', _('Yes')), + ('0', _('No')), + ): + yield { + 'selected': ( + self.lookup_exact_val == lookup + and not self.lookup_isnull_val + ), + 'query_string': self.query_string( + {self.lookup_exact_name: lookup}, + [self.lookup_isnull_name], + ), + 'display': title, + } + if isinstance(self.field, models.NullBooleanField): + yield { + 'selected': self.lookup_isnull_val == 'True', + 'query_string': self.query_string( + {self.lookup_isnull_name: 'True'}, + [self.lookup_exact_name], + ), + 'display': _('Unknown'), + } + + +@manager.register +class ChoicesFieldListFilter(ListFieldFilter): + lookup_formats = {'exact': '%s__exact'} + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return bool(field.choices) + + def choices(self): + yield { + 'selected': self.lookup_exact_val is '', + 'query_string': self.query_string({}, [self.lookup_exact_name]), + 'display': _('All') + } + for lookup, title in self.field.flatchoices: + yield { + 'selected': smart_text(lookup) == self.lookup_exact_val, + 'query_string': self.query_string({self.lookup_exact_name: lookup}), + 'display': title, + } + + +@manager.register +class TextFieldListFilter(FieldFilter): + template = 'xadmin/filters/char.html' + lookup_formats = {'in': '%s__in', 'search': '%s__contains'} + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return ( + isinstance(field, models.CharField) + and field.max_length > 20 + or isinstance(field, models.TextField) + ) + + +@manager.register +class NumberFieldListFilter(FieldFilter): + template = 'xadmin/filters/number.html' + lookup_formats = {'equal': '%s__exact', 'lt': '%s__lt', 'gt': '%s__gt', + 'ne': '%s__ne', 'lte': '%s__lte', 'gte': '%s__gte', + } + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return isinstance(field, (models.DecimalField, models.FloatField, models.IntegerField)) + + def do_filte(self, queryset): + params = self.used_params.copy() + ne_key = '%s__ne' % self.field_path + if ne_key in params: + queryset = queryset.exclude( + **{self.field_path: params.pop(ne_key)}) + return queryset.filter(**params) + + +@manager.register +class DateFieldListFilter(ListFieldFilter): + template = 'xadmin/filters/date.html' + lookup_formats = {'since': '%s__gte', 'until': '%s__lt', + 'year': '%s__year', 'month': '%s__month', 'day': '%s__day', + 'isnull': '%s__isnull'} + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return isinstance(field, models.DateField) + + def __init__(self, field, request, params, model, admin_view, field_path): + self.field_generic = '%s__' % field_path + self.date_params = dict([(FILTER_PREFIX + k, v) for k, v in params.items() + if k.startswith(self.field_generic)]) + + super(DateFieldListFilter, self).__init__( + field, request, params, model, admin_view, field_path) + + now = timezone.now() + # When time zone support is enabled, convert "now" to the user's time + # zone so Django's definition of "Today" matches what the user expects. + if now.tzinfo is not None: + current_tz = timezone.get_current_timezone() + now = now.astimezone(current_tz) + if hasattr(current_tz, 'normalize'): + # available for pytz time zones + now = current_tz.normalize(now) + + if isinstance(field, models.DateTimeField): + today = now.replace(hour=0, minute=0, second=0, microsecond=0) + else: # field is a models.DateField + today = now.date() + tomorrow = today + datetime.timedelta(days=1) + + self.links = ( + (_('Any date'), {}), + (_('Has date'), { + self.lookup_isnull_name: False + }), + (_('Has no date'), { + self.lookup_isnull_name: 'True' + }), + (_('Today'), { + self.lookup_since_name: str(today), + self.lookup_until_name: str(tomorrow), + }), + (_('Past 7 days'), { + self.lookup_since_name: str(today - datetime.timedelta(days=7)), + self.lookup_until_name: str(tomorrow), + }), + (_('This month'), { + self.lookup_since_name: str(today.replace(day=1)), + self.lookup_until_name: str(tomorrow), + }), + (_('This year'), { + self.lookup_since_name: str(today.replace(month=1, day=1)), + self.lookup_until_name: str(tomorrow), + }), + ) + + def get_context(self): + context = super(DateFieldListFilter, self).get_context() + context['choice_selected'] = bool(self.lookup_year_val) or bool(self.lookup_month_val) \ + or bool(self.lookup_day_val) + return context + + def choices(self): + for title, param_dict in self.links: + yield { + 'selected': self.date_params == param_dict, + 'query_string': self.query_string( + param_dict, [FILTER_PREFIX + self.field_generic]), + 'display': title, + } + + +@manager.register +class RelatedFieldSearchFilter(FieldFilter): + template = 'xadmin/filters/fk_search.html' + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + if not is_related_field2(field): + return False + related_modeladmin = admin_view.admin_site._registry.get( + get_model_from_relation(field)) + return related_modeladmin and getattr(related_modeladmin, 'relfield_style', None) in ('fk-ajax', 'fk-select') + + def __init__(self, field, request, params, model, model_admin, field_path): + other_model = get_model_from_relation(field) + if hasattr(field, 'remote_field'): + rel_name = field.remote_field.get_related_field().name + else: + rel_name = other_model._meta.pk.name + + self.lookup_formats = {'in': '%%s__%s__in' % rel_name, 'exact': '%%s__%s__exact' % rel_name} + super(RelatedFieldSearchFilter, self).__init__( + field, request, params, model, model_admin, field_path) + + related_modeladmin = self.admin_view.admin_site._registry.get(other_model) + self.relfield_style = related_modeladmin.relfield_style + + if hasattr(field, 'verbose_name'): + self.lookup_title = field.verbose_name + else: + self.lookup_title = other_model._meta.verbose_name + self.title = self.lookup_title + self.search_url = model_admin.get_admin_url('%s_%s_changelist' % ( + other_model._meta.app_label, other_model._meta.model_name)) + self.label = self.label_for_value(other_model, rel_name, self.lookup_exact_val) if self.lookup_exact_val else "" + self.choices = '?' + if field.remote_field.limit_choices_to: + for i in list(field.remote_field.limit_choices_to): + self.choices += "&_p_%s=%s" % (i, field.remote_field.limit_choices_to[i]) + self.choices = format_html(self.choices) + + def label_for_value(self, other_model, rel_name, value): + try: + obj = other_model._default_manager.get(**{rel_name: value}) + return '%s' % escape(Truncator(obj).words(14, truncate='...')) + except (ValueError, other_model.DoesNotExist): + return "" + + def get_context(self): + context = super(RelatedFieldSearchFilter, self).get_context() + context['search_url'] = self.search_url + context['label'] = self.label + context['choices'] = self.choices + context['relfield_style'] = self.relfield_style + return context + + +@manager.register +class RelatedFieldListFilter(ListFieldFilter): + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return is_related_field2(field) + + def __init__(self, field, request, params, model, model_admin, field_path): + other_model = get_model_from_relation(field) + if hasattr(field, 'remote_field'): + rel_name = field.remote_field.get_related_field().name + else: + rel_name = other_model._meta.pk.name + + self.lookup_formats = {'in': '%%s__%s__in' % rel_name, 'exact': '%%s__%s__exact' % + rel_name, 'isnull': '%s__isnull'} + self.lookup_choices = field.get_choices(include_blank=False) + super(RelatedFieldListFilter, self).__init__( + field, request, params, model, model_admin, field_path) + + if hasattr(field, 'verbose_name'): + self.lookup_title = field.verbose_name + else: + self.lookup_title = other_model._meta.verbose_name + self.title = self.lookup_title + + def has_output(self): + if (is_related_field(self.field) + and self.field.field.null or hasattr(self.field, 'remote_field') + and self.field.null): + extra = 1 + else: + extra = 0 + return len(self.lookup_choices) + extra > 1 + + def expected_parameters(self): + return [self.lookup_kwarg, self.lookup_kwarg_isnull] + + def choices(self): + yield { + 'selected': self.lookup_exact_val == '' and not self.lookup_isnull_val, + 'query_string': self.query_string({}, + [self.lookup_exact_name, self.lookup_isnull_name]), + 'display': _('All'), + } + for pk_val, val in self.lookup_choices: + yield { + 'selected': self.lookup_exact_val == smart_text(pk_val), + 'query_string': self.query_string({ + self.lookup_exact_name: pk_val, + }, [self.lookup_isnull_name]), + 'display': val, + } + if (is_related_field(self.field) + and self.field.field.null or hasattr(self.field, 'remote_field') + and self.field.null): + yield { + 'selected': bool(self.lookup_isnull_val), + 'query_string': self.query_string({ + self.lookup_isnull_name: 'True', + }, [self.lookup_exact_name]), + 'display': EMPTY_CHANGELIST_VALUE, + } + + +@manager.register +class MultiSelectFieldListFilter(ListFieldFilter): + """ Delegates the filter to the default filter and ors the results of each + + Lists the distinct values of each field as a checkbox + Uses the default spec for each + + """ + template = 'xadmin/filters/checklist.html' + lookup_formats = {'in': '%s__in'} + cache_config = {'enabled': False, 'key': 'quickfilter_%s', 'timeout': 3600, 'cache': 'default'} + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return True + + def get_cached_choices(self): + if not self.cache_config['enabled']: + return None + c = caches(self.cache_config['cache']) + return c.get(self.cache_config['key'] % self.field_path) + + def set_cached_choices(self, choices): + if not self.cache_config['enabled']: + return + c = caches(self.cache_config['cache']) + return c.set(self.cache_config['key'] % self.field_path, choices) + + def __init__(self, field, request, params, model, model_admin, field_path, field_order_by=None, field_limit=None, sort_key=None, cache_config=None): + super(MultiSelectFieldListFilter, self).__init__(field, request, params, model, model_admin, field_path) + + # Check for it in the cachce + if cache_config is not None and type(cache_config) == dict: + self.cache_config.update(cache_config) + + if self.cache_config['enabled']: + self.field_path = field_path + choices = self.get_cached_choices() + if choices: + self.lookup_choices = choices + return + + # Else rebuild it + queryset = self.admin_view.queryset().exclude(**{"%s__isnull" % field_path: True}).values_list(field_path, flat=True).distinct() + #queryset = self.admin_view.queryset().distinct(field_path).exclude(**{"%s__isnull"%field_path:True}) + + if field_order_by is not None: + # Do a subquery to order the distinct set + queryset = self.admin_view.queryset().filter(id__in=queryset).order_by(field_order_by) + + if field_limit is not None and type(field_limit) == int and queryset.count() > field_limit: + queryset = queryset[:field_limit] + + self.lookup_choices = [str(it) for it in queryset.values_list(field_path, flat=True) if str(it).strip() != ""] + if sort_key is not None: + self.lookup_choices = sorted(self.lookup_choices, key=sort_key) + + if self.cache_config['enabled']: + self.set_cached_choices(self.lookup_choices) + + def choices(self): + self.lookup_in_val = (type(self.lookup_in_val) in (tuple, list)) and self.lookup_in_val or list(self.lookup_in_val) + yield { + 'selected': len(self.lookup_in_val) == 0, + 'query_string': self.query_string({}, [self.lookup_in_name]), + 'display': _('All'), + } + for val in self.lookup_choices: + yield { + 'selected': smart_text(val) in self.lookup_in_val, + 'query_string': self.query_string({self.lookup_in_name: ",".join([val] + self.lookup_in_val), }), + 'remove_query_string': self.query_string({self.lookup_in_name: ",".join([v for v in self.lookup_in_val if v != val]), }), + 'display': val, + } + + +@manager.register +class AllValuesFieldListFilter(ListFieldFilter): + lookup_formats = {'exact': '%s__exact', 'isnull': '%s__isnull'} + + @classmethod + def test(cls, field, request, params, model, admin_view, field_path): + return True + + def __init__(self, field, request, params, model, admin_view, field_path): + parent_model, reverse_path = reverse_field_path(model, field_path) + queryset = parent_model._default_manager.all() + # optional feature: limit choices base on existing relationships + # queryset = queryset.complex_filter( + # {'%s__isnull' % reverse_path: False}) + limit_choices_to = get_limit_choices_to_from_path(model, field_path) + queryset = queryset.filter(limit_choices_to) + + self.lookup_choices = (queryset + .distinct() + .order_by(field.name) + .values_list(field.name, flat=True)) + super(AllValuesFieldListFilter, self).__init__( + field, request, params, model, admin_view, field_path) + + def choices(self): + yield { + 'selected': (self.lookup_exact_val is '' and self.lookup_isnull_val is ''), + 'query_string': self.query_string({}, [self.lookup_exact_name, self.lookup_isnull_name]), + 'display': _('All'), + } + include_none = False + for val in self.lookup_choices: + if val is None: + include_none = True + continue + val = smart_text(val) + yield { + 'selected': self.lookup_exact_val == val, + 'query_string': self.query_string({self.lookup_exact_name: val}, + [self.lookup_isnull_name]), + 'display': val, + } + if include_none: + yield { + 'selected': bool(self.lookup_isnull_val), + 'query_string': self.query_string({self.lookup_isnull_name: 'True'}, + [self.lookup_exact_name]), + 'display': EMPTY_CHANGELIST_VALUE, + } diff --git a/extra_apps/xadmin/forms.py b/extra_apps/xadmin/forms.py new file mode 100644 index 0000000..512de10 --- /dev/null +++ b/extra_apps/xadmin/forms.py @@ -0,0 +1,47 @@ +from django import forms + +from django.contrib.auth import authenticate +from django.contrib.auth.forms import AuthenticationForm + +from django.utils.translation import ugettext_lazy, ugettext as _ + +from django.contrib.auth import get_user_model + +ERROR_MESSAGE = ugettext_lazy("Please enter the correct username and password " + "for a staff account. Note that both fields are case-sensitive.") + + +class AdminAuthenticationForm(AuthenticationForm): + """ + A custom authentication form used in the admin app. + + """ + this_is_the_login_form = forms.BooleanField( + widget=forms.HiddenInput, initial=1, + error_messages={'required': ugettext_lazy("Please log in again, because your session has expired.")}) + + def clean(self): + username = self.cleaned_data.get('username') + password = self.cleaned_data.get('password') + message = ERROR_MESSAGE + + if username and password: + self.user_cache = authenticate( + username=username, password=password) + if self.user_cache is None: + if u'@' in username: + User = get_user_model() + # Mistakenly entered e-mail address instead of username? Look it up. + try: + user = User.objects.get(email=username) + except (User.DoesNotExist, User.MultipleObjectsReturned): + # Nothing to do here, moving along. + pass + else: + if user.check_password(password): + message = _("Your e-mail address is not your username." + " Try '%s' instead.") % user.username + raise forms.ValidationError(message) + elif not self.user_cache.is_active or not self.user_cache.is_staff: + raise forms.ValidationError(message) + return self.cleaned_data diff --git a/extra_apps/xadmin/layout.py b/extra_apps/xadmin/layout.py new file mode 100644 index 0000000..1d3c7a9 --- /dev/null +++ b/extra_apps/xadmin/layout.py @@ -0,0 +1,113 @@ +from crispy_forms.helper import FormHelper +from crispy_forms.layout import * +from crispy_forms.bootstrap import * +from crispy_forms.utils import render_field, flatatt, TEMPLATE_PACK + +from crispy_forms import layout +from crispy_forms import bootstrap + +import math + + +class Fieldset(layout.Fieldset): + template = "xadmin/layout/fieldset.html" + + def __init__(self, legend, *fields, **kwargs): + self.description = kwargs.pop('description', None) + self.collapsed = kwargs.pop('collapsed', None) + super(Fieldset, self).__init__(legend, *fields, **kwargs) + + +class Row(layout.Div): + + def __init__(self, *fields, **kwargs): + css_class = 'form-inline form-group' + new_fields = [self.convert_field(f, len(fields)) for f in fields] + super(Row, self).__init__(css_class=css_class, *new_fields, **kwargs) + + def convert_field(self, f, counts): + col_class = "col-sm-%d" % int(math.ceil(12 / counts)) + if not (isinstance(f, Field) or issubclass(f.__class__, Field)): + f = layout.Field(f) + if f.wrapper_class: + f.wrapper_class += " %s" % col_class + else: + f.wrapper_class = col_class + return f + + +class Col(layout.Column): + + def __init__(self, id, *fields, **kwargs): + css_class = ['column', 'form-column', id, 'col col-sm-%d' % + kwargs.get('span', 6)] + if kwargs.get('horizontal'): + css_class.append('form-horizontal') + super(Col, self).__init__(css_class=' '.join(css_class), * + fields, **kwargs) + + +class Main(layout.Column): + css_class = "column form-column main col col-sm-9 form-horizontal" + + +class Side(layout.Column): + css_class = "column form-column sidebar col col-sm-3" + + +class Container(layout.Div): + css_class = "form-container row clearfix" + + +# Override bootstrap3 +class InputGroup(layout.Field): + + template = "xadmin/layout/input_group.html" + + def __init__(self, field, *args, **kwargs): + self.field = field + self.inputs = list(args) + if '@@' not in args: + self.inputs.append('@@') + + self.input_size = None + css_class = kwargs.get('css_class', '') + if 'input-lg' in css_class: + self.input_size = 'input-lg' + if 'input-sm' in css_class: + self.input_size = 'input-sm' + + super(InputGroup, self).__init__(field, **kwargs) + + def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs): + classes = form.fields[self.field].widget.attrs.get('class', '') + extra_context = { + 'inputs': self.inputs, + 'input_size': self.input_size, + 'classes': classes.replace('form-control', '') + } + if hasattr(self, 'wrapper_class'): + extra_context['wrapper_class'] = self.wrapper_class + + return render_field( + self.field, form, form_style, context, template=self.template, + attrs=self.attrs, template_pack=template_pack, extra_context=extra_context, **kwargs) + + +class PrependedText(InputGroup): + + def __init__(self, field, text, **kwargs): + super(PrependedText, self).__init__(field, text, '@@', **kwargs) + + +class AppendedText(InputGroup): + + def __init__(self, field, text, **kwargs): + super(AppendedText, self).__init__(field, '@@', text, **kwargs) + + +class PrependedAppendedText(InputGroup): + + def __init__(self, field, prepended_text=None, appended_text=None, *args, **kwargs): + super(PrependedAppendedText, self).__init__( + field, prepended_text, '@@', appended_text, **kwargs) diff --git a/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/django.mo new file mode 100644 index 0000000..e594acb Binary files /dev/null and b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/django.po new file mode 100644 index 0000000..65ab472 --- /dev/null +++ b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/django.po @@ -0,0 +1,1454 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# p3n15h34d , 2013 +# Sebastian Morkisch , 2013 +# Azd325 , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-12-19 11:06+0000\n" +"Last-Translator: Sebastian Morkisch \n" +"Language-Team: German (Germany) (http://www.transifex.com/projects/p/xadmin/" +"language/de_DE/)\n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "Alle" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "Ja" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "Nein" + +#: filters.py:175 +msgid "Unknown" +msgstr "Unbekannt" + +#: filters.py:267 +msgid "Any date" +msgstr "Beliebiges Datum" + +#: filters.py:268 +msgid "Has date" +msgstr "Hat ein Datum" + +#: filters.py:271 +msgid "Has no date" +msgstr "Hat kein Datum" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "Heute" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "Letzten 7 Tage" + +#: filters.py:282 +msgid "This month" +msgstr "Diesen Monat" + +#: filters.py:286 +msgid "This year" +msgstr "Dieses Jahr" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" +"Bitte geben Sie den richtigen Benutzernamen und das Kennwort für ein " +"Mitarbeiter Konto an. Beachten Sie die Groß-und Kleinschreibung in den " +"beiden Feldern." + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "Ihre Sitzung ist abgelaufen - bitte melden Sie sich erneut an." + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "Ihre Email ist nicht ihr Benutzername. Probieren sie anstelle %s." + +#: models.py:48 +msgid "Title" +msgstr "Titel" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "Benutzer" + +#: models.py:50 +msgid "Url Name" +msgstr "URL Name" + +#: models.py:52 +msgid "Query String" +msgstr "Abfrage String" + +#: models.py:53 +msgid "Is Shared" +msgstr "Wird geteilt" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "Lesezeichen" + +#: models.py:67 +msgid "Bookmarks" +msgstr "Lesezeichen" + +#: models.py:89 +msgid "Settings Key" +msgstr "Einstellungsschlüssel" + +#: models.py:90 +msgid "Settings Content" +msgstr "Einstellungsinhalt" + +#: models.py:102 +msgid "User Setting" +msgstr "Benutzereinstellung" + +#: models.py:103 +msgid "User Settings" +msgstr "Benutzereinstelllungen" + +#: models.py:108 +msgid "Page" +msgstr "Seite" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "Widget Typ" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "Widget Parameter" + +#: models.py:137 +msgid "User Widget" +msgstr "Benutzer Widget" + +#: models.py:138 +msgid "User Widgets" +msgstr "Benutzer Widgets" + +#: models.py:142 +#, fuzzy +#| msgid "Date/time" +msgid "action time" +msgstr "Datum/Uhrzeit" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +#, fuzzy +#| msgid "Change %s" +msgid "change message" +msgstr "Ändern %s" + +#: models.py:164 +#, fuzzy +#| msgid "log in" +msgid "log entry" +msgstr "einloggen" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, fuzzy, python-format +#| msgid "Change one %(objects_name)s" +#| msgid_plural "Batch change %(counter)s %(objects_name)s" +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "Anpassung von %(objects_name)s" + +#: models.py:180 +#, fuzzy, python-format +#| msgid "Related Objects" +msgid "Deleted \"%(object)s.\"" +msgstr "Abhängige Objekte" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Lösche ausgewählte %(verbose_name_plural)s" + +#: plugins/actions.py:72 +#, fuzzy, python-format +#| msgid "Successfully deleted %(count)d %(items)s." +msgid "Batch delete %(count)d %(items)s." +msgstr "Erfolgreich gelöscht %(count)d %(items)s." + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Erfolgreich gelöscht %(count)d %(items)s." + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "Kann nicht gelöscht werden %(name)s" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "Sind Sie sicher?" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "%(total_count)s ausgewählt" +msgstr[1] "Alle %(total_count)s ausgewählt" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "0 von %(cnt)s ausgewählt" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "Min" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "Max" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "Durchschnitt" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "Summe" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "Anzahl" + +#: plugins/auth.py:21 +#, fuzzy, python-format +msgid "Can add %s" +msgstr "Kann %s betrachten" + +#: plugins/auth.py:22 +#, fuzzy, python-format +msgid "Can change %s" +msgstr "Ändern %s" + +#: plugins/auth.py:23 +#, fuzzy, python-format +msgid "Can edit %s" +msgstr "Kann %s betrachten" + +#: plugins/auth.py:24 +#, fuzzy, python-format +msgid "Can delete %s" +msgstr "Kann nicht gelöscht werden %(name)s" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "Kann %s betrachten" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "Persönliche Informationen" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "Berechtigungen" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "Wichtige Termine" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "Status" + +#: plugins/auth.py:111 +#, fuzzy +msgid "Permission Name" +msgstr "Berechtigungen" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "Passwort ändern" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "Passwort ändern: %s" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "Passwort erfolgreich geändert." + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "Passwort ändern" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "Änderung des Feldes" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "Anpassung aller gewählten %(verbose_name_plural)s" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "Es wurden %(count)d %(items)s erfolgreich geändert." + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "Als Lesezeichen abspeichern" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "Einfaches Diagramm der Modelle anzeigen." + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "%s Diagramme" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +#, fuzzy +msgid "removed" +msgid_plural "removed" +msgstr[0] "Entferne" +msgstr[1] "Entferne" + +#: plugins/comments.py:73 +#, fuzzy +msgid "Remove selected comments" +msgstr "Gelöschte %(name)s wiederherstellen" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "Einzelheiten von %s" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "Eingabe %s" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "" +"%(name)s bezeichnetes Objekt mit dem Primärschlüssel %(key)r existiert nicht." + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "Seite" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "Fehlerhaftes Filtern: %s" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "Vorherige" + +#: plugins/images.py:29 +msgid "Next" +msgstr "Nächste" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "Slideshow" + +#: plugins/images.py:29 +msgid "Download" +msgstr "Download" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "Änderung:" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "Tabelle" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "Thumbnails" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "Haben Sie Ihr Passwort oder den Benutzernamen vergessen?" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "Erstelle %s neu" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "Abhängige Objekte" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "Suche %s" + +#: plugins/relfield.py:67 +#, fuzzy, python-format +#| msgid "Select Date" +msgid "Select %s" +msgstr "Datum wählen" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "Standard" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "Standard Bootstrap Thema" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "Bootstrap2" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "Bootstrap 2.x Thema" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "Hinzufügen %s" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "Erste Version." + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "Version ändern." + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "Version zurückfallen." + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "Version wiederherstellen." + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "Gelöschte %(verbose_name)s." + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "Verlauf" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "Gelöschte %(name)s wiederherstellen" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "Änderungen: %s" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "Es müssen zwei Versionen ausgewählt sein." + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "Bitte wählen Sie zwei unterschiedliche Versionen aus." + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "Aktuell: %s" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "Auf %s zurückfallen" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "Stelle %s wieder her" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "Seite konnte nicht gefunden werden" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" +"Es tut uns leid, aber die angeforderte Seite konnte nicht gefunden werden." + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "Startseite" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "Serverfehler" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "Serverfehler (500)" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "Server Fehler (500)" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"Es ist ein Fehler aufgetreten. Der Siteadmin wurde via E-Mail informiert und " +"wird sich in Kürze um die Behebung des Fehlers kümmern. Wir danken für Ihre " +"Geduld." + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "Passwort erfolgreich zurückgesetzt" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "Ihr Passwort wurde gesetzt. Sie können fortfahren und sich einloggen." + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "Einloggen" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "Geben Sie Ihr neues Passwort ein." + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Bitte geben Sie Ihr neues Passwort zweimal ein, damit die Identität " +"festgestellt werden kann." + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "Passwort ändern" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "Passwort zurücksetzen fehlgeschlagen" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"Der Passwort-zurücksetzen Link war ungültig, weil dieser möglicherweise " +"schon verwendet wurde. Bitte fordern Sie einen neuen Link an." + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" +"Wir haben Ihnen eine E-Mail mit Anweisungen zum Zurücksetzen Ihres " +"Passwortes an die Adresse geschickt, die Sie uns übermittelt haben. Sie " +"sollten sie in Kürze erhalten." + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "Bitte gehen Sie auf folgende Seite und erstellen ein neues Passwort." + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "Ihr Benutzername, falls Sie ihn vergessen sollten:" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "Danke, dass Sie uns besucht haben!" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "Das %(site_name)s Team" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "Passwort zurücksetzen" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" +"Haben Sie Ihr Passwort vergessen? Geben Sie unten Ihre E-Mail Adresse ein " +"und wir werden Ihnen eine Nachricht mit Anweisungen schicken, wie ein Neues " +"erstellt wird." + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "E-Mail Adresse:" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "Passwort zurücksetzen" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"Bitte tragen Sie einen Benutzernamen und Passwort ein. Anschließend können " +"Sie weitere Benutzerinformationen bearbeiten." + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "Bitte geben Sie Benutzernamen und Passwort ein." + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Bitte korrigieren Sie den folgenden Fehler." +msgstr[1] "Bitte korrigieren Sie die folgenden Fehler." + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "Geben Sie Ihr neues Passwort ein." + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" +"Vergeben Sie ein neues Passwort für den Benutzer %(username)s." + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "Willkommen," + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "Abmelden" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "Sie haben nicht die notwendige Berechtigung etwas zu ändern." + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "Themeneinstellungen" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "Suchen" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "Hinzufügen" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "Zurück" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "Nächstes" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "Speichern" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "Bereinige Lesezeichen" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "Keine Lesezeichen" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "Neues Lesezeichen" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "Lesezeichen hinzufügen" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "Lesezeichenname" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "Warte" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "Speichere Lesezeichen" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "Filter" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "Bereinige Filter" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "Klicken Sie hier, um alle Objekte über alle Seiten hinweg auszuwählen." + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "Alles auswählen %(total_count)s %(model_name)s" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "Auswahl abwählen" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "Diagramme" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "Exportieren" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "Export mit Tabellenkopf." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "Exportieren mit Formatierung." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "Komplette Daten exportieren." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "Schließen" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "Layout" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "Säubern" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "Alle %(t)s Sekunden" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "Null" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "Eingabe" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "Auswahldatum" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "YY" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "Jahr" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "MM" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "Monat" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "DD" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "Tag" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "Anwenden" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "Datumsintervall" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "Datum wählen" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "Von" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "Bis" + +#: templates/xadmin/filters/fk_search.html:14 +#, fuzzy +#| msgid "Select Date" +msgid "Select" +msgstr "Datum wählen" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "Entfernen" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "Zahl eingeben" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Mittels %(filter_title)s" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "Verfügbar" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "Klicken um alles auf einmal auszuwählen." + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "Alles auswählen" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "Wähle" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "Entferne" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "Gewählt" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "Klicken um alles Ausgewählte sofort zu löschen." + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "Alles entfernen" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "Alles anzeigen" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "Speichern..." + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "Als neu abspeichern" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "Speichern und neu hinzufügen" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "Speichern und weiter bearbeiten" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "Löschen" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "Mehrere Objekte ändern" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "Anpassung von %(objects_name)s" +msgstr[1] "Anpassung aller %(counter)s %(objects_name)s" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "Mehrere andern" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "Widget hinzufügen" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "Logout erfolgreich" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Danke, dass Sie ein paar nette Minuten hier verbracht haben." + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "Fenster schließen" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "Wieder einloggen" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "Bitte loggen Sie sich ein" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "Benutzername" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "Passwort" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "einloggen" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "Bearbeiten" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "Ja, na klar!" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "Abbruch" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "Mehrere Objekte löschen" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "Delta" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "Datum/Uhrzeit" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "Benutzer" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "Kommentar" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "%(name)s hinzufügen" + +#: templates/xadmin/views/model_list.html:39 +#, fuzzy +msgid "Columns" +msgstr "Spalten" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "Gewähltes wiederherstellen" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "Leere Liste" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "Es gibt keine gelöschten Objekte wiederherzustellen." + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "Delta zwischen %(verbose_name)s" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "Feld" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "Version A" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "Version B" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "Diese Überarbeitung umkehren." + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "Erfolg" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "Schnelles Hinzufügen" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "Widget Optionen" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "Änderungen speichern" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "Django Xadmin" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "Widget ID" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "Widget Titel" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "Html Inhalt" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "Zielmodell" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "" +"Schnellauswahlbutton Widget, zum schnellen Öffnen einer beliebigen Seite." + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "Schnellauswahl Buttons" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "Beliebige Objektliste Widget." + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "Fügen Sie ein beliebiges Modell Objekt Widget hinzu." + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "Armaturentafel" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "%s Armaturentafel" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "" + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "Andere Felder" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "%s Einzelheiten" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, fuzzy, python-format +#| msgid "Change %s" +msgid "Changed %s." +msgstr "Ändern %s" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "%(name)s \"%(obj)s\" wurde erfolgreich hinzugefügt." + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "Sie können es trotzdem nochmals bearbeiten." + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "Sie können unten ein weiteres %s hinzufügen." + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "Ändern %s" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "" + +#: views/form.py:165 +#, fuzzy, python-format +msgid "The %s was changed successfully." +msgstr "Passwort erfolgreich geändert." + +#: views/list.py:199 +msgid "Database error" +msgstr "Datenbankfehler" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "%s Liste" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "Aufsteigend sortieren" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "Absteigend sortieren" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "Sortierung abbrechen" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "Hauptübersicht" + +#: widgets.py:48 +msgid "Now" +msgstr "Jetzt" diff --git a/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..effeda4 Binary files /dev/null and b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..11bd775 --- /dev/null +++ b/extra_apps/xadmin/locale/de_DE/LC_MESSAGES/djangojs.po @@ -0,0 +1,72 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# Azd325 , 2013 +# Azd325 , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: Azd325 \n" +"Language-Team: German (Germany) (http://www.transifex.com/projects/p/xadmin/language/de_DE/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de_DE\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "%(sel)s von %(cnt)s markiert" +msgstr[1] "%(sel)s von %(cnt)s markiert" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "Neues Element" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag Sonntag" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "So Mo Di Mi Do Fr Sa So" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "So Mo Di Mi Do Fr Sa So" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "Januar Februar März April Mai Juni Juli August September Oktober November Dezember" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "Heute" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "%a %d %b %Y %T %Z" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "vorm nachm" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "vorm nachm" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "%T" diff --git a/extra_apps/xadmin/locale/en/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000..46394b0 Binary files /dev/null and b/extra_apps/xadmin/locale/en/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/en/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..8f291d5 --- /dev/null +++ b/extra_apps/xadmin/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,1411 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=1;\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "" + +#: filters.py:175 +msgid "Unknown" +msgstr "" + +#: filters.py:267 +msgid "Any date" +msgstr "" + +#: filters.py:268 +msgid "Has date" +msgstr "" + +#: filters.py:271 +msgid "Has no date" +msgstr "" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "" + +#: filters.py:282 +msgid "This month" +msgstr "" + +#: filters.py:286 +msgid "This year" +msgstr "" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" + +#: models.py:48 +msgid "Title" +msgstr "" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "" + +#: models.py:52 +msgid "Query String" +msgstr "" + +#: models.py:53 +msgid "Is Shared" +msgstr "" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "" + +#: models.py:67 +msgid "Bookmarks" +msgstr "" + +#: models.py:89 +msgid "Settings Key" +msgstr "" + +#: models.py:90 +msgid "Settings Content" +msgstr "" + +#: models.py:102 +msgid "User Setting" +msgstr "" + +#: models.py:103 +msgid "User Settings" +msgstr "" + +#: models.py:108 +msgid "Page" +msgstr "" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "" + +#: models.py:137 +msgid "User Widget" +msgstr "" + +#: models.py:138 +msgid "User Widgets" +msgstr "" + +#: models.py:142 +msgid "action time" +msgstr "" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +msgid "change message" +msgstr "" + +#: models.py:164 +msgid "log entry" +msgstr "" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "" + +#: models.py:180 +#, python-format +msgid "Deleted \"%(object)s.\"" +msgstr "" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/actions.py:72 +#, python-format +msgid "Batch delete %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "" +msgstr[1] "" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "" + +#: plugins/auth.py:21 +#, python-format +msgid "Can add %s" +msgstr "" + +#: plugins/auth.py:22 +#, python-format +msgid "Can change %s" +msgstr "" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, python-format +msgid "Can delete %s" +msgstr "" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "" + +#: plugins/auth.py:111 +msgid "Permission Name" +msgstr "" + +#: plugins/auth.py:167 +#, fuzzy +msgid "Change Password" +msgstr "Changed Password" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "" + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "" + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:73 +msgid "Remove selected comments" +msgstr "" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "" + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "" + +#: plugins/images.py:29 +msgid "Next" +msgstr "" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "" + +#: plugins/images.py:29 +msgid "Download" +msgstr "" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "" + +#: plugins/relfield.py:67 +#, python-format +msgid "Select %s" +msgstr "" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "" + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "" + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "" + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "" + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "" + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "" + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "" + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" +msgstr[1] "" + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "" + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "" + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:14 +msgid "Select" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "" +msgstr[1] "" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "" + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "" + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "" + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "" + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, fuzzy, python-format +msgid "Changed %s." +msgstr "Changed Password" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "" + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "" + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "" + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "" + +#: views/form.py:165 +#, python-format +msgid "The %s was changed successfully." +msgstr "" + +#: views/list.py:199 +msgid "Database error" +msgstr "" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "" + +#: widgets.py:48 +msgid "Now" +msgstr "" diff --git a/extra_apps/xadmin/locale/en/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/en/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..9702706 Binary files /dev/null and b/extra_apps/xadmin/locale/en/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/en/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/en/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..2cbb726 --- /dev/null +++ b/extra_apps/xadmin/locale/en/LC_MESSAGES/djangojs.po @@ -0,0 +1,69 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "" +msgstr[1] "" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November " +"December" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "" diff --git a/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/django.mo new file mode 100644 index 0000000..4044840 Binary files /dev/null and b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/django.po new file mode 100644 index 0000000..62ed011 --- /dev/null +++ b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/django.po @@ -0,0 +1,1556 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# byroncorrales , 2013 +# charlieweb , 2013 +# sacrac , 2013 +# netoxico , 2013 +# abelthf , 2013 +# laoska , 2013 +# VerurteiltKind , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-05-12 18:45+0000\n" +"Last-Translator: sacrac \n" +"Language-Team: Spanish (Mexico) (http://www.transifex.com/projects/p/xadmin/" +"language/es_MX/)\n" +"Language: es_MX\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "Todo" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "Sí" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "No" + +#: filters.py:175 +msgid "Unknown" +msgstr "Desconocido" + +#: filters.py:267 +msgid "Any date" +msgstr "Cualquier fecha" + +#: filters.py:268 +#, fuzzy +msgid "Has date" +msgstr "Cualquier fecha" + +#: filters.py:271 +#, fuzzy +msgid "Has no date" +msgstr "Cualquier fecha" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "Hoy" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "Pasados ​​7 días" + +#: filters.py:282 +msgid "This month" +msgstr "Este mes" + +#: filters.py:286 +msgid "This year" +msgstr "Este año" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" +"Por favor, introduzca el nombre de usuario y contraseña correctos de su " +"cuenta. Note que ambos campos son sensibles a mayúsculas y minúsculas." + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "Por favor, ingrese de nuevo, debido a que su sesión ha caducado." + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" +"Tu dirección de correo no es tu nombre de usuario. Prueba '%s' nuevamente." + +#: models.py:48 +msgid "Title" +msgstr "Titulo" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "Nombre de Url" + +#: models.py:52 +msgid "Query String" +msgstr "Cadena de consulta" + +#: models.py:53 +msgid "Is Shared" +msgstr "Es compartido" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "Marcador" + +#: models.py:67 +msgid "Bookmarks" +msgstr "Marcadores" + +#: models.py:89 +msgid "Settings Key" +msgstr "Configuración llave" + +#: models.py:90 +msgid "Settings Content" +msgstr "Configuración de contenidos" + +#: models.py:102 +msgid "User Setting" +msgstr "Configuración del usuario" + +#: models.py:103 +msgid "User Settings" +msgstr "Configuraciones de los usuarios" + +#: models.py:108 +msgid "Page" +msgstr "Página" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "Tipo de Widget" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "Parametros del Widget" + +#: models.py:137 +msgid "User Widget" +msgstr "Widget del Usuario" + +#: models.py:138 +msgid "User Widgets" +msgstr "Widgets del Usuario" + +#: models.py:142 +#, fuzzy +#| msgid "Date/time" +msgid "action time" +msgstr "Fecha/hora" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +#, fuzzy +#| msgid "Change %s" +msgid "change message" +msgstr "Cambiar %s" + +#: models.py:164 +#, fuzzy +#| msgid "log in" +msgid "log entry" +msgstr "Iniciar sesión" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, fuzzy, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "Cambiar multiples objetos" + +#: models.py:180 +#, fuzzy, python-format +#| msgid "Related Objects" +msgid "Deleted \"%(object)s.\"" +msgstr "Objetos relacionados" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Borrar selección %(verbose_name_plural)s" + +#: plugins/actions.py:72 +#, fuzzy, python-format +#| msgid "Successfully deleted %(count)d %(items)s." +msgid "Batch delete %(count)d %(items)s." +msgstr "Correctamente eliminado %(count)d %(items)s." + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Correctamente eliminado %(count)d %(items)s." + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "No se puede eliminar %(name)s" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "Esta seguro?" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "%(total_count)s seleccionados" +msgstr[1] "Todos los %(total_count)s seleccionados" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "0 de %(cnt)s seleccionado" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" +"Los articulos deben de ser seleccionados en orden para realizar la acción. " +"No existen artículos que han cambiado" + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "Minimo" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "Maximo" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "Promedio" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "Suma" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "Conteo" + +#: plugins/auth.py:21 +#, fuzzy, python-format +msgid "Can add %s" +msgstr "Añadir %s" + +#: plugins/auth.py:22 +#, fuzzy, python-format +msgid "Can change %s" +msgstr "Cambiar %s" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, fuzzy, python-format +msgid "Can delete %s" +msgstr "No se puede eliminar %(name)s" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "Información personal" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "Permisos" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "Fechas importantes" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "Estados" + +#: plugins/auth.py:111 +#, fuzzy +msgid "Permission Name" +msgstr "Permisos" + +#: plugins/auth.py:167 +#, fuzzy +msgid "Change Password" +msgstr "Cambiar Contraseña" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "Cambiar contraseña: %s" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "Contraseña cambiada correctamente" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "Cambiar contraseña" + +#: plugins/batch.py:44 +#, fuzzy +msgid "Change this field" +msgstr "Historial de cambios: %s" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "Cambio de grupo seleccionado %(verbose_name_plural)s" + +#: plugins/batch.py:89 +#, fuzzy, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "Correctamente eliminado %(count)d %(items)s." + +#: plugins/batch.py:138 +#, fuzzy, python-format +msgid "Batch change %s" +msgstr "Cambiar %s" + +#: plugins/bookmark.py:173 +#, fuzzy +msgid "bookmark" +msgstr "Marcador" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" +"Widget de marcador, puede mostrar datos de la lista de favoritos del usuario " +"en el widget." + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "Mostrar simple grafos para los modelos" + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "%s Graficos" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +#, fuzzy +msgid "removed" +msgid_plural "removed" +msgstr[0] "Eliminar" +msgstr[1] "Eliminar" + +#: plugins/comments.py:73 +#, fuzzy +msgid "Remove selected comments" +msgstr "Recuperar borrado %(name)s" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "Detalles de %s" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "Entre %s" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "%(name)s el objeto con la llave primaria %(key)r no existe." + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "Hoja" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "Previo" + +#: plugins/images.py:29 +msgid "Next" +msgstr "Próximo " + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "presentación" + +#: plugins/images.py:29 +msgid "Download" +msgstr "Descargar" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "Cambiar:" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "¿Olvidó su contraseña o nombre de usuario?" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "Objetos relacionados" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "Buscar %s" + +#: plugins/relfield.py:67 +#, fuzzy, python-format +#| msgid "Select Date" +msgid "Select %s" +msgstr "Seleccionar Fecha" + +#: plugins/themes.py:47 +#, fuzzy +msgid "Default" +msgstr "Tema por defecto" + +#: plugins/themes.py:48 +#, fuzzy +msgid "Default bootstrap theme" +msgstr "Tema bootstrap por defecto" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +#, fuzzy +msgid "Bootstrap 2.x theme" +msgstr "Tema bootstrap por defecto" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "Añadir %s" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "Versión inicial." + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "Cambiar la versión." + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "Revertir la versión." + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "Recuperar versión" + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "Borrado %(verbose_name)s." + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "Recuperar" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "Historico" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "Recuperar borrado %(name)s" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "Historial de cambios: %s" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "Debe seleccionar dos versiones." + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "Por favor seleccione dos versiones diferente." + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "Actual: %s" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "Revertir %s" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" +"El %(model)s \"%(name)s\" se revirtió con éxito. Puede editarlo de nuevo a " +"continuación." + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "Recuperar %s" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" +"El %(model)s \"%(name) s\" se recuperó con éxito. Puede editarlo de nuevo a " +"continuación." + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "Pagina no encontrada" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "Lo sentimos pero la pagina que usted solicita no se encuentra." + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "Inicio" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "Error en el servidor" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "Error en el servidor (500)" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "Error en el servidor (500)" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"Ha habido un error. Se nos ha informado a los administradores del sitio a " +"través de un correo electrónico y debe repararse en la breve. Gracias por su " +"paciencia." + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "Restablecimiento de contraseña con éxito" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "Se ha establecido su contraseña. Usted puede acceder ahora mismo." + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "Entrar" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "Escriba la nueva contraseña" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Introduzca su nueva contraseña dos veces para que podamos verificar que la " +"ha escrito correctamente." + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "Cambiar mi contraseña" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "Restablecimiento de contraseña sin éxito" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"El enlace de restablecimiento de contraseña no es válida, posiblemente " +"debido a que ya se ha utilizado. Por favor, solicite un nuevo " +"restablecimiento de contraseña." + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" +"Nosotro te hemos enviado por correo electrónico las instrucciones para " +"configurar la contraseña a la dirección de correo electrónico que ha " +"enviado. Usted debe recibirlo en breve momento." + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Tu has recibido este correo debido a que has solicitado restablecimiento de " +"contraseña para tu cuenta de usuario en %(site_name)s." + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "Por favor ir a la siguiente pagina y selecciona una nueva contraseña" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "Tu usuario, en caso de que lo hayas olvidado" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "Gracias por usar nuestro sitio web!" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "El equipo de %(site_name)s" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "restablecimiento de contraseña" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" +"¿Olvidaste tu contraseña? Escribe tu dirección de e-mail debajo, y le " +"enviaremos un e-mail para el establecimiento de una nueva." + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "Dirección de correo:" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "Cambiar contraseña" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"Primero, ingrese usuario y contraseña. Luego, sera capaz de editar mas " +"opciones de usuario." + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "Ingresa nombre de usuario y contraseña" + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Por favor corrija el error abajo." +msgstr[1] "Por favor corrija los errores abajo." + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "Ingresa una nueva contraseña" + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" +"Introduzca una nueva contraseña para el usuario %(username)s" + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "Bienvenidos," + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "Salir" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "No tiene permiso para editar nada. " + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "Temas" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "Buscar" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "Agregar" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "Paso previo" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "Próximo paso" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "Guardar" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "Limpiar marcadores" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "No hay marcadores" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "Nuevo marcador" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "Guardar actual pagino como Marcador" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "Ingrese titulo de marcador" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "Espera un momento" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "Guardar marcador" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "Filtros" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "Limpiar Filtros" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "" +"Haz clic aquí para seleccionar los objetos a través de todas las páginas" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "Seleccionar todo %(total_count)s %(model_name)s" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "Limpiar seleccion" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "Graficos" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "Exportar" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "Exportar con la cabecera de la tabla." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "Exportar con formato" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "Exportar todos los datos." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "Cerrar" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "Limpiar Refrescar" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, fuzzy, python-format +msgid "Every %(t)s seconds" +msgstr "Por %(t)s segundos" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "Nulo" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "Introducir" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "Elija Fecha" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "año" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "Mes" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "día" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "Aplicar" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "Rangos de fechas" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "Seleccionar Fecha" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "De" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "Para" + +#: templates/xadmin/filters/fk_search.html:14 +#, fuzzy +#| msgid "Select Date" +msgid "Select" +msgstr "Seleccionar Fecha" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "Limpiar" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "Ingrese el numero" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "Por %(filter_title)s" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "Disponible" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "Click para elegir todos" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "Seleccionar todos" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "Elegir" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "Eliminar" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "Preferido" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "Click para remover todos los preferidos" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "Remover todos" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "Mostrar todos" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "Guardar como nuevo" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "Guardar y añadir otro" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "Guardar y continuar editando" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "Borrar" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "Cambiar multiples objetos" + +#: templates/xadmin/views/batch_change_form.html:16 +#, fuzzy, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "Cambiar multiples objetos" +msgstr[1] "Cambiar multiples objetos" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "Cambios multiples" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "Añadir Widget" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"Algo está mal con tu instalación de base de datos. Asegúrese de que las " +"tablas de la bases de datos se han creado apropiadamente, y asegúrese de que " +"la base de datos puede ser leído por el usuario apropiado" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "Salio con éxito " + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Gracias por pasar tiempo de calidad con el sitio web hoy." + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "Cerrar ventana" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "Entrar nuevamente" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "Por favor, inicia sesión" + +#: templates/xadmin/views/login.html:52 +#, fuzzy +msgid "Username" +msgstr "Usuario:" + +#: templates/xadmin/views/login.html:64 +#, fuzzy +msgid "Password" +msgstr "Contraseña:" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "Iniciar sesión" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "Editar." + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" +"Eliminando los %(verbose_name)s '%(escaped_object)s terminaría eliminando " +"objetos relacionados, pero su cuenta no tiene permisos para eliminar los " +"siguientes tipo de objetos:" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" +"Eliminando los %(verbose_name)s '%(escaped_object)s requeriría eliminar los " +"siguientes objetos relacionas protegidos:" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" +"¿Estas seguro de querer eliminar los %(verbose_name)s \"%(escaped_object)s" +"\" ? Todos los siguientes artículos relacionados serán eliminados:" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "Si, estoy seguro" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +#, fuzzy +msgid "Cancel" +msgstr "Cancelar ordenación" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "Eliminar múltiples objetos." + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" +"Eliminando los %(objects_name)s terminaría eliminando objetos relacionados, " +"pero su cuenta no tiene permisos para eliminar los siguientes tipo de " +"objetos:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" +"Eliminando los %(objects_name)s seleccionados terminaria emilinando los " +"siguientes objetos relacionados protegidos:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" +"¿Estas seguro de querer borrar los %(objects_name)s seleccionados? Todos los " +"siguientes objetos y sus artículos relacionados serán eliminados:" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "Differencia" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "Fecha/hora" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "Usuario" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "Comentario" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "Seleccionar diferentes versiones" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" +"Este objeto no tiene un historial de cambios, Es probable que no se haya " +"añadido a través de este sitio de admin.|" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "Agregar %(name)s" + +#: templates/xadmin/views/model_list.html:39 +#, fuzzy +msgid "Columns" +msgstr "Seleccionar columns." + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "Restaurar seleccionados." + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "Lista vacia" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" +"Presione el botón de recuperación abajo para recuperar esta versión del " +"objeto." + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" +"Selecciona una fecha de la lista de abajo para recuperar una versión " +"eliminada de un objeto." + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "No hay objetos eliminados para recuperar." + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "Diferentes %(verbose_name)s" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "Campo" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "Versión A" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "Versión B" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "Revertir a" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "Revertir" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "Revertir %(verbose_name)s" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" +"Presiona el botón revertir de abajo para revertir a esta versión del objeto." + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "Revertir esta revisión" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "Éxito" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" +"Agregado exitosa mente, presiona edit para editar." + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "Agregar rápidamente." + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "Opciones del Widget" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "Guardar cambios" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "Django Xadmin" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "ID del Widget" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "Titulo del Widget" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" +"Contenido html del Widget, puede escribir cualquier contenido del widget." + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "Contenido HTML" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "Modelo objeto" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "botón rapido del widget, abrir rápidamente cualquier página." + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "Botones rapidos" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "Cualquier objeto listado en el widget" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "Añadir cualquier modelo de objeto al Widget." + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "Panel de control" + +#: views/dashboard.py:633 +#, fuzzy, python-format +msgid "%s Dashboard" +msgstr "Panel de control" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "El %(name)s \"%(obj)s\" fue eliminado exitosa mente." + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "Otros campos" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "%s Detalles" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, fuzzy, python-format +#| msgid "Change %s" +msgid "Changed %s." +msgstr "Cambiar %s" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "El %(name)s \"%(obj)s\" fue agregado exitosa mente." + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "Puedes editarlo de nuevo abajo." + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "Puedes agregar otro %s debajo." + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "Cambiar %s" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "El %(name)s \"%(obj)s\" fue editado exitosa mente." + +#: views/form.py:165 +#, fuzzy, python-format +msgid "The %s was changed successfully." +msgstr "El %(name)s \"%(obj)s\" fue editado exitosa mente." + +#: views/list.py:199 +msgid "Database error" +msgstr "Error de base de datos" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "%s Lista" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "Ordenar ascendente mente." + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "Ordenar descendente mente" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "Cancelar ordenación" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "Dashboard principal." + +#: widgets.py:48 +msgid "Now" +msgstr "Ahora" + +#~ msgid "Add Other %s" +#~ msgstr "Añadir otro %s" + +#~ msgid "Recover deleted" +#~ msgstr "Recuperar borrado" + +#~ msgid "Documentation" +#~ msgstr "Documentación" + +#~ msgid "Password change" +#~ msgstr "Cambiar contraseña" + +#~ msgid "Password change successful" +#~ msgstr "Contraseña cambio con exito " + +#~ msgid "Your password was changed." +#~ msgstr "Tu contraseña fue cambiada." + +#~ msgid "" +#~ "Please enter your old password, for security's sake, and then enter your " +#~ "new password twice so we can verify you typed it in correctly." +#~ msgstr "" +#~ "Introduzca su antigua contraseña, por el bien de la seguridad, y luego " +#~ "ingrese su nueva contraseña dos veces para que podamos verificar que la " +#~ "ha escrito correctamente." + +#~ msgid "Old password" +#~ msgstr "Vieja contraseña" + +#~ msgid "New password" +#~ msgstr "Nueva contraseña" + +#~ msgid "Password (again)" +#~ msgstr "Contraseña (nuevamente)" + +#~ msgid "Password reset complete" +#~ msgstr "restablecimiento de contraseña completo" + +#~ msgid "Password reset confirmation" +#~ msgstr "Confirmación de restablecimiento de contraseña" + +#~ msgid "New password:" +#~ msgstr "Nueva contraseña:" + +#~ msgid "Confirm password:" +#~ msgstr "Confirmar contraseña:" + +#~ msgid "Search By" +#~ msgstr "Buscar por" + +#~ msgid "None" +#~ msgstr "Ninguno" + +#~ msgid "Cacnel" +#~ msgstr "Cancelar" diff --git a/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..81c3f49 Binary files /dev/null and b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..ec4f2a6 --- /dev/null +++ b/extra_apps/xadmin/locale/es_MX/LC_MESSAGES/djangojs.po @@ -0,0 +1,76 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# byroncorrales , 2013 +# byroncorrales , 2013 +# sacrac , 2013 +# netoxico , 2013 +# netoxico , 2013 +# sacrac , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: sacrac \n" +"Language-Team: Spanish (Mexico) (http://www.transifex.com/projects/p/xadmin/language/es_MX/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es_MX\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "%(sel)s de %(cnt)s seleccionado." +msgstr[1] "%(sel)s de %(cnt)s seleccionado " + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "Nuevo elemento" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "Domingo Lunes Martes Miércoles Jueves Viernes Sábado Domingo" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "Dom Lun Mar Mié Jue Vie Sáb Dom" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "Do Lu Ma Mi Ju Vi Sá Do" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "Enero Febrero Marzo Abril Mayo Junio ​​Julio Agosto Septiembre Octubre Noviembre Diciembre" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "Ene Feb Mar Abr May Jun Jul Ago Sep Oct Nov Dic" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "Hoy" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "%a %d %b %Y %T %Z" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "AM PM" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "am pm" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "%T" diff --git a/extra_apps/xadmin/locale/eu/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/eu/LC_MESSAGES/django.mo new file mode 100644 index 0000000..f6c51c6 Binary files /dev/null and b/extra_apps/xadmin/locale/eu/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/eu/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/eu/LC_MESSAGES/django.po new file mode 100644 index 0000000..61f5e85 --- /dev/null +++ b/extra_apps/xadmin/locale/eu/LC_MESSAGES/django.po @@ -0,0 +1,1475 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# unaizalakain , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-11-20 10:21+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Basque (http://www.transifex.com/projects/p/xadmin/language/" +"eu/)\n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "Guztia" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "Bai" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "Ez" + +#: filters.py:175 +msgid "Unknown" +msgstr "Ezezaguna" + +#: filters.py:267 +msgid "Any date" +msgstr "Edozein data" + +#: filters.py:268 +msgid "Has date" +msgstr "" + +#: filters.py:271 +msgid "Has no date" +msgstr "" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "Gaur" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "Duela 7 egun" + +#: filters.py:282 +msgid "This month" +msgstr "Hilabete hau" + +#: filters.py:286 +msgid "This year" +msgstr "Urte hau" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" +"Mesedez sartu langile kontu baten erabiltzaile eta pasahitz egokiak. Kontuan " +"hartu bi eremuek maiuskula eta minuskulak bereizten dituztela." + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "Mesedez hasi berriro saioa, zure uneko saioa iraungi da eta." + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" +"Zure e-posta helbidea ez da zure erabiltzaile izena. Horren ordez saiatu " +"'%s'." + +#: models.py:48 +msgid "Title" +msgstr "Izenburua" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "Url Izena" + +#: models.py:52 +msgid "Query String" +msgstr "Kontsulta Katea" + +#: models.py:53 +msgid "Is Shared" +msgstr "Partekatua da." + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "Laster-marketara gehitu" + +#: models.py:67 +msgid "Bookmarks" +msgstr "Laster-markak" + +#: models.py:89 +msgid "Settings Key" +msgstr "Ezarpenen Gakoa" + +#: models.py:90 +msgid "Settings Content" +msgstr "Ezarpenen Edukia" + +#: models.py:102 +msgid "User Setting" +msgstr "Erabiltzaile Ezarpenak" + +#: models.py:103 +msgid "User Settings" +msgstr "Erabiltzaile Ezarpenak" + +#: models.py:108 +msgid "Page" +msgstr "Orrialdea" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "Widget Mota" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "Widget Parametroak" + +#: models.py:137 +msgid "User Widget" +msgstr "Erabiltzaile Widgeta" + +#: models.py:138 +msgid "User Widgets" +msgstr "Erabiltzaile Widgetak" + +#: models.py:142 +#, fuzzy +#| msgid "Date/time" +msgid "action time" +msgstr "Data/ordua" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +#, fuzzy +#| msgid "Change %s" +msgid "change message" +msgstr "Aldaketa %s" + +#: models.py:164 +#, fuzzy +#| msgid "log in" +msgid "log entry" +msgstr "hasi saioa" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "" + +#: models.py:180 +#, fuzzy, python-format +#| msgid "Related Objects" +msgid "Deleted \"%(object)s.\"" +msgstr "Erlazionatutako Objetuak" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Aukeratutako %(verbose_name_plural)s ezabatu" + +#: plugins/actions.py:72 +#, fuzzy, python-format +#| msgid "Successfully deleted %(count)d %(items)s." +msgid "Batch delete %(count)d %(items)s." +msgstr "Aukeratutako %(count)d %(items)s arrakastaz ezabatuak." + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Aukeratutako %(count)d %(items)s arrakastaz ezabatuak." + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "Ezin izan da %(name)s ezabatu" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "Ziur al zaude?" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "%(total_count)s aukeratua" +msgstr[1] "%(total_count)s guztiak aukeratuak" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "%(cnt)stik 0 aukeratuak" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" +"Elementuren bat aukeratzea beharrezkoa da ekintza bat burutzeko. Ez da " +"elementurik aldatu." + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "Min" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "Max" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "Btz-bst" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "Batura" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "Kontaketa" + +#: plugins/auth.py:21 +#, fuzzy, python-format +msgid "Can add %s" +msgstr "%s gehitu" + +#: plugins/auth.py:22 +#, fuzzy, python-format +msgid "Can change %s" +msgstr "Aldaketa %s" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, fuzzy, python-format +msgid "Can delete %s" +msgstr "Ezin izan da %(name)s ezabatu" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "Info pertsonala" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "Baimenak" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "Data garrantzitsuak" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "Egoera" + +#: plugins/auth.py:111 +#, fuzzy +msgid "Permission Name" +msgstr "Baimenak" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "Pasahitza Aldatu" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "Pasahitza aldatu: %s" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "Pasahitza arrakastaz aldatua." + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "Pasahitza aldatu" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "Sorta moduko Aldaketa aukeratua %(verbose_name_plural)s" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "" + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" +"Laster-marken Widgeta, erabiltzailearen laster-marka zerrenda widgetean " +"erakutsi dezake." + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "Erabili modeluen diagrama sinplea." + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "%s Diagrama" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +#, fuzzy +msgid "removed" +msgid_plural "removed" +msgstr[0] "Ezabatu" +msgstr[1] "Ezabatu" + +#: plugins/comments.py:73 +#, fuzzy +msgid "Remove selected comments" +msgstr "Ezabatutako %(name)sa berreskuratu" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "%sren xehetasunak" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "Sartu %s" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "Ez da %(key)r eremua nagusitzat duen %(name)srik." + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "Xafla" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "Aurrekoa" + +#: plugins/images.py:29 +msgid "Next" +msgstr "Hurrengoa" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "Aurkezpena" + +#: plugins/images.py:29 +msgid "Download" +msgstr "Deskargatu" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "Aldatu:" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "Zure pasahitza edo erabiltzailea ahaztu duzu?" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "Erlazionatutako Objetuak" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "Bilatu %s" + +#: plugins/relfield.py:67 +#, fuzzy, python-format +#| msgid "Select Date" +msgid "Select %s" +msgstr "Data Aukeratu" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "%s gehitu" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "Hasierako bertsioa." + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "Bertsioa aldatu." + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "Aurreko bertsiora itzuli." + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "Bertsioa berreskuratu." + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "%(verbose_name)s ezabatua." + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "Berreskuratu" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "Historiala" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "Ezabatutako %(name)sa berreskuratu" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "Historiala aldatu: %s" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "Bi bertsio aukeratu behar dira." + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "Mesedez aukeratu bi bertsio ezberdin." + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "Unekoa: %s" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "%s aurreko bertsiora itzuli" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" +"\"%(name)s\" %(model)sa aurreko bertsiora arrakastaz itzularazi da. Azpian " +"berriro editatu dezakezu." + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "%s berreskuratu" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" +"\"%(name)s\" %(model)sa arrakastaz berreskuratu da. Azpian berriro editatu " +"dezakezu." + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "Orria ez da aurkitu" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "Sentitzen dugu baina eskatutako orria ezin izan da aurkitu." + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "Hasiera" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "Zerbitzariaren errorea" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "Zerbitzariaren errorea (500)" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "Zerbitzariaren errorea " + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"Errore bat egon da. Eposta bidez bidali zaio webgunearen kudeatzaileari eta " +"laister konpondu beharko litzake. Milesker zure pazientziagatik." + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "Pasahitzaren berrezartze arrakastatsua" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "Zure pasahitza ezarria izan da. Orain saioa hasi dezakezu." + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "Sarioa hasi" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "Pasahitz berria idatzi" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Mesedez idatzi zure pasahitz berria bi aldiz ongi idatzi duzun egiaztatzeko." + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "Nire pasahitza aldatu" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "Pasahitzaren berrezartzea gaizki joan da" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"Pasahitzaren berrezartze esteka baliogabea zen, ziur aski iadanik erabilia " +"izan delak. Mesedez, eskatu pasahitzaren berrezartze berri bat." + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" +"Eposta biez zure pasahitza ezartzeko argibideak bidali dizkizugu eman " +"diguzun eposta helbidera. Laister jaso beharko zenituzke." + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"%(site_name)sen zure erabiltzailearen pasahitzaren berrezarpen bat eskatu " +"duzulako ari zera eposta hau jasotzen." + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "Mesedez, joan ondorengo orrira eta pasahitz berri bat aukeratu:" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "Zure erabiltzailea, ahaztu baduzu:" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "Eskerrik asko gunea erabiltzaileagatik!" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "%(site_name)sko taldea" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "Pasahitza berrezarri" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" +"Pasahitza ahaztu duzu? Idatzi zure eposta helbidea behean eta berri bat " +"ezartzeko argibideak bidaliko dizkizugu." + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "Eposta helbidea:" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "Nire pasahitza berrezarri" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"Lehendabizi, erabiltzaile eta pasahitz bat sartu. Ondoren, erabiltzaile " +"aukera gehiago editatzeko gai izango zara." + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "Erabiltzaile eta pasahitz bat sartu." + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Beheko errorea zuzendu mesedez." +msgstr[1] "Beheko erroreak zuzendu mesedez." + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "Zure pasahitz berria sartu." + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" +"%(username)s erabiltzailearentzat pasahitz berri bat sartu." + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "Ongietorri," + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "Saioa amaitu" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "Ez daukazu ezer editatzeko baimenik." + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "Itsura-gaiak" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "Bilatu" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "Gehitu" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "Aurr pausua" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "Ondo pausua" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "Gorde" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "Laster-markak Garbitu" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "Ez dago Laster-markarik" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "Laster-marka Berria" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "Uneko orria Laster-marka bezala gorde" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "Laster-markaren izenburua idatzi" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "Itxoiten" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "Laster-marka gorde" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "Filtroak" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "Filtroak garbitu" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "Klikatu hemen orrialde guztiko objetuak aukeratzeko" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "Aukeratu %(total_count)s %(model_name)sak" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "Aukeraketa garbitu" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "Diagramak" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "Esportatu" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "Esportatu taularen goiburuarekin." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "Formatuarekin esportatu." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "Data guztiak esportatu." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "Itxi" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "Garbitu Freskatzea" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "Null" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "Sartu" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "Aukeraketa Data" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "urtea" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "hilabetea" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "eguna" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "Aplikatu" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "Data Tartea" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "Data Aukeratu" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "Nork" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "Nori" + +#: templates/xadmin/filters/fk_search.html:14 +#, fuzzy +#| msgid "Select Date" +msgid "Select" +msgstr "Data Aukeratu" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "Garbitu" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "Zenbakia Sartu" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "%(filter_title)sgatik" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "Eskuragarri" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "Klikatu guztia aukeratzeko." + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "Guztia aukeratu" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "Aukeratu" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "Ezabatu" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "Aukeratua" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "Klikatu aukeraketa guztia ezabatzeko" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "Guztia ezabatu" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "Guztia erakutsi" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "Berri bezala gorde" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "Gorde eta beste bat gehitu" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "Gorde eta editatzen jarraitu" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "Ezabatu" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "Objetu anitz aldatu" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "" +msgstr[1] "" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "Bizpahiru Aldatu" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "Widgeta Gehitu" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"Zerbait txarto dago zure datubasearen instalazioarekin. Ziurtatu beharrezko " +"datubase taulak sortuak izan direla eta datubasea erabiltzaile egokiak " +"irakurri dezakela." + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "Saioa Arrakastaz Amaitua" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Eskerrikasko Web gunean zure denbora sartzeagatik." + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "Lehioa Itxi" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "Saioa hasi berriro" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "Hasi Saioa mesedez" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "hasi saioa" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "Editatu" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" +"'%(escaped_object)s' %(verbose_name)sa ezabatzeak erlazionatutako beste " +"objetu batzuk ezabatuzko lituzke baina zure kontuak ez dauzka ondorengo " +"objetu motak ezabatzeko baimenik:" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" +"'%(escaped_object)s' %(verbose_name)sa ezabatzeak ondorengo babestutako " +"erlazionatutako objetuak ezabatuko lituzke:" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" +"Ziur al zaude \"%(escaped_object)s\" %(verbose_name)sa ezabatu nahi duzula? " +"Ondorengo erlazionatutako objetuak ezabatuko lirateke:" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "Bai, ziur nago" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "Bizpahiru objetu ezabatu" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" +"Aukeratutako %(objects_name)s objetua ezabatzeak erlazionatutako objetuak " +"ezabatuko lituzke, baina zure kontuak ez dauzka ondorengo objetu motak " +"ezabatzeko baimenik:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" +"Aukeratutako %(objects_name)s objetua ezabatzeak ondorengo objetuak " +"ezabatuko lituzke:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" +"Ziur zaude aukeratutako %(objects_name)s ezabatu nahi duzula? Ondorengo " +"objetuak eta haiekin erlazionatuta daudenak ezabatuak izango dira:" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "Diferentzia" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "Data/ordua" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "Erabiltzailea" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "Iruzkina" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "Aukeratutako Bertsioen Ezberdintasunak" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" +"Objetu honek ez dauka aldaketa historialik. Ziurrenik ez zen kudeaketa gune " +"honen bitartez gehitua izango." + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "%(name)s gehitu" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "Aukeratutakoa berrezarri" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "Zerrenda hustu" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" +"Sakatu beheko berreskuratze botoia objetuaren bertsio hau berreskuratzeko." + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" +"Aukeratu beheko zerrendatik data bat objetu baten ezabatutako bertsioa " +"berreskuratzeko." + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "Ez dago berreskuratu daitekeen ezabatutako objeturik." + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "%(verbose_name)s ezberdintasunak" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "Eremua" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "A bertsioa" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "B bertsioa" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "Hona itzularazi" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "Itzularazi" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "%(verbose_name)s itzularazi" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "Beheko itzularatze botoia sakatu objetua bertsio hontara itzultzeko." + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "Bertsio hau itzularazi" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "Arrakasta" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" +"Gehitze arrakastatsua, klikatu editatu editatzeko." + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "Gehitze Azkarra" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "Widget Aukerak" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "Aldaketak gorde" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "Django Xadmin" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "Widget IDa" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "Widget Izenburua" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "Html Eduki Widgeta, edozein html eduki idatzi daiteke widgetan." + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "Html Edukia" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "Helburu den Modelua" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "Botoi azkarra Widgeta, edozein orri azkar ireki." + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "Botoi Azkarrak" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "Edozein Objetu zerrenda Widgeta." + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "Edozein objetu gehitu Widgeta." + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "Arbela" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "\"%(obj)s\" %(name)sa arrakastaz ezabatua izan da." + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "Beste Eremuak" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "%s Xehetasunak" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, fuzzy, python-format +#| msgid "Change %s" +msgid "Changed %s." +msgstr "Aldaketa %s" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "\"%(obj)s\" %(name)sa arrakastaz gehitua izan da." + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "Behean editatu dezakezu berriro." + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "Behean beste %s bat gehitu dezakezu." + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "Aldaketa %s" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "\"%(obj)s\" %(name)sa arrakastaz gehitua izan da." + +#: views/form.py:165 +#, fuzzy, python-format +msgid "The %s was changed successfully." +msgstr "\"%(obj)s\" %(name)sa arrakastaz gehitua izan da." + +#: views/list.py:199 +msgid "Database error" +msgstr "Datubase errorea" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "%s Zerrenda" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "GOR Ordenatu" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "BEH Ordenatu" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "Ezeztatu Ordenaketa" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "Arbela Nagusia" + +#: widgets.py:48 +msgid "Now" +msgstr "Orain" diff --git a/extra_apps/xadmin/locale/eu/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/eu/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..601a8bd Binary files /dev/null and b/extra_apps/xadmin/locale/eu/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/eu/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/eu/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..609c60f --- /dev/null +++ b/extra_apps/xadmin/locale/eu/LC_MESSAGES/djangojs.po @@ -0,0 +1,71 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# unaizalakain , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: unaizalakain \n" +"Language-Team: Basque (http://www.transifex.com/projects/p/xadmin/language/eu/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: eu\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "%(cnt)stik %(sel)s aukeratua" +msgstr[1] "%(cnt)stik %(sel)s aukeratuak" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "Elementu Berria" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "Igandea Astelehena Asteartea Asteazkena Osteguna Ostirala Larunbata Igandea" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "Iga Atl Atr Atz Otg Otr Lar Iga" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "Ig At Ar Az Og Or La Ig" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "Urtarrila Otsaila Martxoa Apirila Maiatza Ekaina Uztaila Abuztua Iraila Urria Azaroa Abendua" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "Urt Ots Mar Api Mai Eka Uzt Abu Ira Urr Aza Abe" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "Gaur" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "%a %d %b %Y %T %Z" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "AM PM" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "am pm" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "%T" diff --git a/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/django.mo new file mode 100644 index 0000000..434b645 Binary files /dev/null and b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/django.po new file mode 100644 index 0000000..1cc66c5 --- /dev/null +++ b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/django.po @@ -0,0 +1,1403 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-11-20 10:21+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Indonesian (Indonesia) (http://www.transifex.com/projects/p/" +"xadmin/language/id_ID/)\n" +"Language: id_ID\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "" + +#: filters.py:175 +msgid "Unknown" +msgstr "" + +#: filters.py:267 +msgid "Any date" +msgstr "" + +#: filters.py:268 +msgid "Has date" +msgstr "" + +#: filters.py:271 +msgid "Has no date" +msgstr "" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "" + +#: filters.py:282 +msgid "This month" +msgstr "" + +#: filters.py:286 +msgid "This year" +msgstr "" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" + +#: models.py:48 +msgid "Title" +msgstr "" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "" + +#: models.py:52 +msgid "Query String" +msgstr "" + +#: models.py:53 +msgid "Is Shared" +msgstr "" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "" + +#: models.py:67 +msgid "Bookmarks" +msgstr "" + +#: models.py:89 +msgid "Settings Key" +msgstr "" + +#: models.py:90 +msgid "Settings Content" +msgstr "" + +#: models.py:102 +msgid "User Setting" +msgstr "" + +#: models.py:103 +msgid "User Settings" +msgstr "" + +#: models.py:108 +msgid "Page" +msgstr "" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "" + +#: models.py:137 +msgid "User Widget" +msgstr "" + +#: models.py:138 +msgid "User Widgets" +msgstr "" + +#: models.py:142 +msgid "action time" +msgstr "" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +msgid "change message" +msgstr "" + +#: models.py:164 +msgid "log entry" +msgstr "" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "" + +#: models.py:180 +#, python-format +msgid "Deleted \"%(object)s.\"" +msgstr "" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/actions.py:72 +#, python-format +msgid "Batch delete %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "" + +#: plugins/auth.py:21 +#, python-format +msgid "Can add %s" +msgstr "" + +#: plugins/auth.py:22 +#, python-format +msgid "Can change %s" +msgstr "" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, python-format +msgid "Can delete %s" +msgstr "" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "" + +#: plugins/auth.py:111 +msgid "Permission Name" +msgstr "" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "" + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "" + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "" + +#: plugins/comments.py:73 +msgid "Remove selected comments" +msgstr "" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "" + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "" + +#: plugins/images.py:29 +msgid "Next" +msgstr "" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "" + +#: plugins/images.py:29 +msgid "Download" +msgstr "" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "" + +#: plugins/relfield.py:67 +#, python-format +msgid "Select %s" +msgstr "" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "" + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "" + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "" + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "" + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "" + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "" + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "" + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "" + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "" + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:14 +msgid "Select" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "" + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "" + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "" + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "" + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, python-format +msgid "Changed %s." +msgstr "" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "" + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "" + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "" + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "" + +#: views/form.py:165 +#, python-format +msgid "The %s was changed successfully." +msgstr "" + +#: views/list.py:199 +msgid "Database error" +msgstr "" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "" + +#: widgets.py:48 +msgid "Now" +msgstr "" diff --git a/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..225de83 Binary files /dev/null and b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..9136f01 --- /dev/null +++ b/extra_apps/xadmin/locale/id_ID/LC_MESSAGES/djangojs.po @@ -0,0 +1,69 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Indonesian (Indonesia) (http://www.transifex.com/projects/p/xadmin/language/id_ID/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: id_ID\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "" diff --git a/extra_apps/xadmin/locale/ja/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/ja/LC_MESSAGES/django.mo new file mode 100644 index 0000000..42bffc0 Binary files /dev/null and b/extra_apps/xadmin/locale/ja/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/ja/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/ja/LC_MESSAGES/django.po new file mode 100644 index 0000000..1d716b0 --- /dev/null +++ b/extra_apps/xadmin/locale/ja/LC_MESSAGES/django.po @@ -0,0 +1,1403 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-11-20 10:21+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Japanese (http://www.transifex.com/projects/p/xadmin/language/" +"ja/)\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "" + +#: filters.py:175 +msgid "Unknown" +msgstr "" + +#: filters.py:267 +msgid "Any date" +msgstr "" + +#: filters.py:268 +msgid "Has date" +msgstr "" + +#: filters.py:271 +msgid "Has no date" +msgstr "" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "" + +#: filters.py:282 +msgid "This month" +msgstr "" + +#: filters.py:286 +msgid "This year" +msgstr "" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" + +#: models.py:48 +msgid "Title" +msgstr "" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "" + +#: models.py:52 +msgid "Query String" +msgstr "" + +#: models.py:53 +msgid "Is Shared" +msgstr "" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "" + +#: models.py:67 +msgid "Bookmarks" +msgstr "" + +#: models.py:89 +msgid "Settings Key" +msgstr "" + +#: models.py:90 +msgid "Settings Content" +msgstr "" + +#: models.py:102 +msgid "User Setting" +msgstr "" + +#: models.py:103 +msgid "User Settings" +msgstr "" + +#: models.py:108 +msgid "Page" +msgstr "" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "" + +#: models.py:137 +msgid "User Widget" +msgstr "" + +#: models.py:138 +msgid "User Widgets" +msgstr "" + +#: models.py:142 +msgid "action time" +msgstr "" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +msgid "change message" +msgstr "" + +#: models.py:164 +msgid "log entry" +msgstr "" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "" + +#: models.py:180 +#, python-format +msgid "Deleted \"%(object)s.\"" +msgstr "" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/actions.py:72 +#, python-format +msgid "Batch delete %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "" + +#: plugins/auth.py:21 +#, python-format +msgid "Can add %s" +msgstr "" + +#: plugins/auth.py:22 +#, python-format +msgid "Can change %s" +msgstr "" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, python-format +msgid "Can delete %s" +msgstr "" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "" + +#: plugins/auth.py:111 +msgid "Permission Name" +msgstr "" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "" + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "" + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "" + +#: plugins/comments.py:73 +msgid "Remove selected comments" +msgstr "" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "" + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "" + +#: plugins/images.py:29 +msgid "Next" +msgstr "" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "" + +#: plugins/images.py:29 +msgid "Download" +msgstr "" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "" + +#: plugins/relfield.py:67 +#, python-format +msgid "Select %s" +msgstr "" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "" + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "" + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "" + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "" + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "" + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "" + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "" + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "" + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "" + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:14 +msgid "Select" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "" + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "" + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "" + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "" + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, python-format +msgid "Changed %s." +msgstr "" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "" + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "" + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "" + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "" + +#: views/form.py:165 +#, python-format +msgid "The %s was changed successfully." +msgstr "" + +#: views/list.py:199 +msgid "Database error" +msgstr "" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "" + +#: widgets.py:48 +msgid "Now" +msgstr "" diff --git a/extra_apps/xadmin/locale/ja/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/ja/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..e0da039 Binary files /dev/null and b/extra_apps/xadmin/locale/ja/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/ja/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/ja/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..dc0c9c2 --- /dev/null +++ b/extra_apps/xadmin/locale/ja/LC_MESSAGES/djangojs.po @@ -0,0 +1,69 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Japanese (http://www.transifex.com/projects/p/xadmin/language/ja/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ja\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "" diff --git a/extra_apps/xadmin/locale/lt/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/lt/LC_MESSAGES/django.mo new file mode 100644 index 0000000..7a23b22 Binary files /dev/null and b/extra_apps/xadmin/locale/lt/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/lt/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/lt/LC_MESSAGES/django.po new file mode 100644 index 0000000..1e7dcbf --- /dev/null +++ b/extra_apps/xadmin/locale/lt/LC_MESSAGES/django.po @@ -0,0 +1,1418 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-11-20 10:21+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Lithuanian (http://www.transifex.com/projects/p/xadmin/" +"language/lt/)\n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" +"%100<10 || n%100>=20) ? 1 : 2);\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "" + +#: filters.py:175 +msgid "Unknown" +msgstr "" + +#: filters.py:267 +msgid "Any date" +msgstr "" + +#: filters.py:268 +msgid "Has date" +msgstr "" + +#: filters.py:271 +msgid "Has no date" +msgstr "" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "" + +#: filters.py:282 +msgid "This month" +msgstr "" + +#: filters.py:286 +msgid "This year" +msgstr "" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" + +#: models.py:48 +msgid "Title" +msgstr "" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "" + +#: models.py:52 +msgid "Query String" +msgstr "" + +#: models.py:53 +msgid "Is Shared" +msgstr "" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "" + +#: models.py:67 +msgid "Bookmarks" +msgstr "" + +#: models.py:89 +msgid "Settings Key" +msgstr "" + +#: models.py:90 +msgid "Settings Content" +msgstr "" + +#: models.py:102 +msgid "User Setting" +msgstr "" + +#: models.py:103 +msgid "User Settings" +msgstr "" + +#: models.py:108 +msgid "Page" +msgstr "" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "" + +#: models.py:137 +msgid "User Widget" +msgstr "" + +#: models.py:138 +msgid "User Widgets" +msgstr "" + +#: models.py:142 +msgid "action time" +msgstr "" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +msgid "change message" +msgstr "" + +#: models.py:164 +msgid "log entry" +msgstr "" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "" + +#: models.py:180 +#, python-format +msgid "Deleted \"%(object)s.\"" +msgstr "" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/actions.py:72 +#, python-format +msgid "Batch delete %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "" + +#: plugins/auth.py:21 +#, python-format +msgid "Can add %s" +msgstr "" + +#: plugins/auth.py:22 +#, python-format +msgid "Can change %s" +msgstr "" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, python-format +msgid "Can delete %s" +msgstr "" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "" + +#: plugins/auth.py:111 +msgid "Permission Name" +msgstr "" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "" + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "" + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/comments.py:73 +msgid "Remove selected comments" +msgstr "" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "" + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "" + +#: plugins/images.py:29 +msgid "Next" +msgstr "" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "" + +#: plugins/images.py:29 +msgid "Download" +msgstr "" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "" + +#: plugins/relfield.py:67 +#, python-format +msgid "Select %s" +msgstr "" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "" + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "" + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "" + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "" + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "" + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "" + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "" + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "" + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "" + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:14 +msgid "Select" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "" + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "" + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "" + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "" + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, python-format +msgid "Changed %s." +msgstr "" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "" + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "" + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "" + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "" + +#: views/form.py:165 +#, python-format +msgid "The %s was changed successfully." +msgstr "" + +#: views/list.py:199 +msgid "Database error" +msgstr "" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "" + +#: widgets.py:48 +msgid "Now" +msgstr "" diff --git a/extra_apps/xadmin/locale/lt/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/lt/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..6b387a7 Binary files /dev/null and b/extra_apps/xadmin/locale/lt/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/lt/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/lt/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..6e691a6 --- /dev/null +++ b/extra_apps/xadmin/locale/lt/LC_MESSAGES/djangojs.po @@ -0,0 +1,71 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Lithuanian (http://www.transifex.com/projects/p/xadmin/language/lt/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: lt\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "" diff --git a/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/django.mo new file mode 100644 index 0000000..f197a00 Binary files /dev/null and b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/django.po new file mode 100644 index 0000000..b783286 --- /dev/null +++ b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/django.po @@ -0,0 +1,1410 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-11-20 10:21+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/" +"xadmin/language/nl_NL/)\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "" + +#: filters.py:175 +msgid "Unknown" +msgstr "" + +#: filters.py:267 +msgid "Any date" +msgstr "" + +#: filters.py:268 +msgid "Has date" +msgstr "" + +#: filters.py:271 +msgid "Has no date" +msgstr "" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "" + +#: filters.py:282 +msgid "This month" +msgstr "" + +#: filters.py:286 +msgid "This year" +msgstr "" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" + +#: models.py:48 +msgid "Title" +msgstr "" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "" + +#: models.py:52 +msgid "Query String" +msgstr "" + +#: models.py:53 +msgid "Is Shared" +msgstr "" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "" + +#: models.py:67 +msgid "Bookmarks" +msgstr "" + +#: models.py:89 +msgid "Settings Key" +msgstr "" + +#: models.py:90 +msgid "Settings Content" +msgstr "" + +#: models.py:102 +msgid "User Setting" +msgstr "" + +#: models.py:103 +msgid "User Settings" +msgstr "" + +#: models.py:108 +msgid "Page" +msgstr "" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "" + +#: models.py:137 +msgid "User Widget" +msgstr "" + +#: models.py:138 +msgid "User Widgets" +msgstr "" + +#: models.py:142 +msgid "action time" +msgstr "" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +msgid "change message" +msgstr "" + +#: models.py:164 +msgid "log entry" +msgstr "" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "" + +#: models.py:180 +#, python-format +msgid "Deleted \"%(object)s.\"" +msgstr "" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/actions.py:72 +#, python-format +msgid "Batch delete %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "" + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "" +msgstr[1] "" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "" + +#: plugins/auth.py:21 +#, python-format +msgid "Can add %s" +msgstr "" + +#: plugins/auth.py:22 +#, python-format +msgid "Can change %s" +msgstr "" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, python-format +msgid "Can delete %s" +msgstr "" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "" + +#: plugins/auth.py:111 +msgid "Permission Name" +msgstr "" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "" + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "" + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:73 +msgid "Remove selected comments" +msgstr "" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "" + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "" + +#: plugins/images.py:29 +msgid "Next" +msgstr "" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "" + +#: plugins/images.py:29 +msgid "Download" +msgstr "" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "" + +#: plugins/relfield.py:67 +#, python-format +msgid "Select %s" +msgstr "" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "" + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "" + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "" + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "" + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "" + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "" + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "" + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" +msgstr[1] "" + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "" + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "" + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:14 +msgid "Select" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "" +msgstr[1] "" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "" + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "" + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "" + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "" + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, python-format +msgid "Changed %s." +msgstr "" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "" + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "" + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "" + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "" + +#: views/form.py:165 +#, python-format +msgid "The %s was changed successfully." +msgstr "" + +#: views/list.py:199 +msgid "Database error" +msgstr "" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "" + +#: widgets.py:48 +msgid "Now" +msgstr "" diff --git a/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..7783a99 Binary files /dev/null and b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..4edf57c --- /dev/null +++ b/extra_apps/xadmin/locale/nl_NL/LC_MESSAGES/djangojs.po @@ -0,0 +1,70 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/xadmin/language/nl_NL/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: nl_NL\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "" +msgstr[1] "" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "" diff --git a/extra_apps/xadmin/locale/pl/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000..c9b8381 Binary files /dev/null and b/extra_apps/xadmin/locale/pl/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/pl/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000..5f5751b --- /dev/null +++ b/extra_apps/xadmin/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,1481 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django-xadmin\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2014-08-12 21:08+0100\n" +"Last-Translator: Michał Szpadzik \n" +"Language-Team: Polish translators \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 1.5.4\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "Wszystko" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "Tak" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "Nie" + +#: filters.py:175 +msgid "Unknown" +msgstr "Nieznany" + +#: filters.py:267 +msgid "Any date" +msgstr "Dowolna data" + +#: filters.py:268 +msgid "Has date" +msgstr "Ma datę" + +#: filters.py:271 +msgid "Has no date" +msgstr "Nie ma daty" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "Dzisiaj" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "Ostatnie 7 dni" + +#: filters.py:282 +msgid "This month" +msgstr "Ten miesiąc" + +#: filters.py:286 +msgid "This year" +msgstr "Ten rok" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" +"Proszę wpisz prawidłową nazwę użytkownika i hasło do konta. Pamiętaj, że oba " +"pola są wrażliwe na wielkość znaków." + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "Proszę, zaloguj się ponownie, ponieważ Twoja sesja wygasła." + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" +"Twój adres e-mail nie jest Twoją nazwą użytkownika. Zamiast tego spróbuj " +"'%s'." + +#: models.py:48 +msgid "Title" +msgstr "Tytuł" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "użytkownik" + +#: models.py:50 +msgid "Url Name" +msgstr "Nazwa Url" + +#: models.py:52 +msgid "Query String" +msgstr "Tekst wyszukiwania" + +#: models.py:53 +msgid "Is Shared" +msgstr "Jest współdzielony" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "Zakładka" + +#: models.py:67 +msgid "Bookmarks" +msgstr "Zakładki" + +#: models.py:89 +msgid "Settings Key" +msgstr "Klucz ustawień" + +#: models.py:90 +msgid "Settings Content" +msgstr "Treść ustawień" + +#: models.py:102 +msgid "User Setting" +msgstr "Ustawienie użytkownika" + +#: models.py:103 +msgid "User Settings" +msgstr "Ustawienia użytkownika" + +#: models.py:108 +msgid "Page" +msgstr "Strona" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "Typ Widgetu" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "Parametry Widgetu" + +#: models.py:137 +msgid "User Widget" +msgstr "Widget użytkownika" + +#: models.py:138 +msgid "User Widgets" +msgstr "Widgety użytkownika" + +#: models.py:142 +#, fuzzy +#| msgid "Date/time" +msgid "action time" +msgstr "Data/czas" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +#, fuzzy +#| msgid "Change %s" +msgid "change message" +msgstr "Zmień %s" + +#: models.py:164 +#, fuzzy +#| msgid "log in" +msgid "log entry" +msgstr "zaloguj się" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, fuzzy, python-format +#| msgid "Change one %(objects_name)s" +#| msgid_plural "Batch change %(counter)s %(objects_name)s" +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "Zmień %(objects_name)s" + +#: models.py:180 +#, fuzzy, python-format +#| msgid "Related Objects" +msgid "Deleted \"%(object)s.\"" +msgstr "Powiązane obiekty" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Usuń zaznaczone %(verbose_name_plural)s" + +#: plugins/actions.py:72 +#, fuzzy, python-format +#| msgid "Successfully deleted %(count)d %(items)s." +msgid "Batch delete %(count)d %(items)s." +msgstr "Z powodzieniem usunięto %(count)d %(items)s." + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Z powodzieniem usunięto %(count)d %(items)s." + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "Nie można usunąć %(name)s" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "Jesteś pewny ?" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "%(total_count)s zaznaczony" +msgstr[1] "%(total_count)s zaznaczone" +msgstr[2] "%(total_count)s zaznaczonych" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "0 z %(cnt)s zaznaczonych" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" +"Elementy muszą być zaznaczone, by wykonać akcję na nich. Żaden element nie " +"został zmienony." + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "Min" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "Max" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "Śred" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "Sum" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "Liczba" + +#: plugins/auth.py:21 +#, python-format +msgid "Can add %s" +msgstr "Może dodawać %s" + +#: plugins/auth.py:22 +#, python-format +msgid "Can change %s" +msgstr "Może zmieniać %s" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "Może edytować %s" + +#: plugins/auth.py:24 +#, python-format +msgid "Can delete %s" +msgstr "Może usuwać %s" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "Może oglądać %s" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "Informacje osobiste" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "Uprawnienia" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "Ważne daty" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "Status" + +#: plugins/auth.py:111 +msgid "Permission Name" +msgstr "Nazwa uprawnienia" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "Zmień hasło" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "Zmień hasło: %s" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "Zmiana hasła zakończona powodzieniem" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "Zmień hasło" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "Zmień to pole" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "Zmiana grupowa wybrana %(verbose_name_plural)s" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "Z powodzeniem zmieniono %(count)d %(items)s." + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "Zmiana grupowa %s" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "zakładka" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "Widget zakładek, pozwala pokazać dane dla zakładki w widgecie." + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "Pokaż prosty wykres dla modelu." + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "%s Wykresy" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "Metadane" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "oflagowany" +msgstr[1] "oflagowane" +msgstr[2] "oflagowanych" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "Oflaguj zaznaczony komentarz" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "zatwierdzony" +msgstr[1] "zatwierdzone" +msgstr[2] "zatwierdzonych" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "Zatwierdź zaznaczony komentarz" + +#: plugins/comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "usunięty" +msgstr[1] "usunięte" +msgstr[2] "usuniętych" + +#: plugins/comments.py:73 +msgid "Remove selected comments" +msgstr "Usuń zaznaczone komentarze" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "1 komentarz został z powodzeniem %(action)s." +msgstr[1] "%(count)s komentarze zostało z powodzeniem %(action)s." +msgstr[2] "%(count)s komentarzy zostało z powodzeniem %(action)s." + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "Szczegóły %s" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "Wejdz w %s" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "Obiekt %(name)s z kluczem głównym %(key)r nie istnieje." + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "Arkusz" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "Błąd filtracji: %s" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "Poprzedni" + +#: plugins/images.py:29 +msgid "Next" +msgstr "Następny" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "Pokaz slajdów" + +#: plugins/images.py:29 +msgid "Download" +msgstr "Ściągnij" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "Zmień:" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "Tabela" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "Miniaturki" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "Zapomniałeś swojego hasła lub loginu ?" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "Utwórz nowy %s" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "Powiązane obiekty" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "Szukaj %s" + +#: plugins/relfield.py:67 +#, fuzzy, python-format +#| msgid "Select Date" +msgid "Select %s" +msgstr "Wybierz datę" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "Domyślny" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "Domyślny temat bootstrapa" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "Bootstrap2" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "Tematy Bootstrap 2.x" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "Dodaj %s" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "Wersja startowa." + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "Zmień wersję." + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "Przywróć wersję." + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "Odzyskaj wersję." + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "Usunięte %(verbose_name)s." + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "Odzyskaj" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "Historia" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "Odzyskaj usunięte %(name)s" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "Zmień historię: %s" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "Musisz wybrać dwie wersje." + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "Proszę, wybierz dwie różne wersje." + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "Obecny: %s" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "Przywróć %s" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" +"%(model)s \"%(name)s\" został przywrócony z powodzeniem. Możesz edytować go " +"ponownie poniżej." + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "Odzyskaj %s" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" +"%(model)s \"%(name)s\" został z powodzeniem odzyskany. Możesz edytować go " +"ponownie poniżej." + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "Strona nie została odnaleziona" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "Przepraszamy, ale żądana strona nie została odnaleziona." + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "Home" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "Błąd serwera" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "Błąd serwera (500)" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "Błąd Serwera (500)" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"Wystąpił błąd. Został zaraportowany do administratorów strony przez e-mail i " +"wkrótce powienien zostać naprawiony. Dziękujemy za wyrozumiałość i " +"cierpliwość." + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "Reset hasła zakończony powodzeniem" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "" +"Twoje hasło zostało ustawione. Możesz teraz przejść dalej i zalogować się." + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "Zaloguj się" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "Wpisz nowe hasło" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Proszę wpisać Twoje nowe hasło dwukrotnie, aby zweryfikować, czy wpisałeś je " +"poprawnie." + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "Zmień moje hasło" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "Resetowanie hasło zakończone niepowodzeniem" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"Twój link do resetowania hasła jest niepoprawny, prawdopodobnie został już " +"użyty. Proszę, zażądaj nowego linku (wykonaj raz jeszcze reset hasła)." + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" +"Wysłaliśmy Ci e-mailem instrukcję ustawienia Twojego hasła na adres, który " +"podałeś. Powinieneś go wkrótce otrzymać." + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Otrzymałeś tego e-maila, ponieważ zarządałeś zresetowania hasła do twojego " +"konta na maszynie %(site_name)s." + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "Przejdź proszę do podanej strony i wybierz nowe hasło: " + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "Twoja nazwa użytkownika, gdybyś ją zapomniał: " + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "Dziękujemy za skorzystanie z naszej strony !" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "%(site_name)s team" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "Reset hasła" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" +"Zapomiałeś swoje hasło ? Wpisz Twój adres e-mail poniżej, a my prześlemy Ci " +"maila z instrukcjami, jak ustawić nowe." + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "Adres e-mail:" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "Zresetuj moje hasło" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"Po pierwsze, wpisz nazwę użytkownika i hasło. Potem bedziesz mógł edytować " +"pozostałe opcje użytkownika." + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "Wpisz nazwę użytkownika i hasło." + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Proszę napraw poniższy błąd." +msgstr[1] "Proszę napraw poniższe błędy." +msgstr[2] "Proszę napraw poniższe błędy." + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "Wpisz Twoje nowe hasło." + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "Wpisz nowe hasło dla użytkownika %(username)s." + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "Witaj, " + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "Wyloguj" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "Nie masz uprawnień by edytować cokolwiek." + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "Tematy" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "Szukaj" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "Dodaj" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "Poprzedni krok" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "Następny krok" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "Zapisz" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "Wyczyść zakłądki" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "Brak zakładek" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "Nowa zakładka" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "Zapisz obecną stronę jako zakładkę" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "Wprowadź tytuł zakładki" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "Oczekuje" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "Zapisz zakładkę" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "Filtry" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "Wyczyść filtry" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "Kliknij tutaj, aby wybrać wszystkie obiekty na wszystkich stronach" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "Wybierz wszystkie %(total_count)s %(model_name)s" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "Wyczyść wybór" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "Wykresy" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "Eksportuj" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "Eksportuj wraz z nagłówkiem tabeli." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "Exportuj do formatu." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "Eksportuj wszystkie dane." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "Zamknij" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "Układ graficzny" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "Wyczyść odświeżanie" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "Co każde %(t)s sekund" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "Null" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "Wejdź" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "Data wyboru" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "YY" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "rok" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "MM" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "miesiąc" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "DD" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "dzień" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "Zatwierdź" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "Zakres dat" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "Wybierz datę" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "Od" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "Do" + +#: templates/xadmin/filters/fk_search.html:14 +#, fuzzy +#| msgid "Select Date" +msgid "Select" +msgstr "Wybierz datę" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "Wyczyść" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "Wpisz numer" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " po %(filter_title)s" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "Dostępny" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "Kliknij by wybrać wszystkie za jednym razem." + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "Wybierz wszystkie" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "Wybierz" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "Usuń" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "Wybrane" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "Kliknij, by usunąć za jednym razem wszystkie wybrane." + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "Usuń wszystkie" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "Pokaż wszystkie" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "Zapisuję.." + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "Zapisz jako nowe" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "Zapisz i dodaj kolejne" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "Zapisz i kontynuuj edycję" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "Usuń" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "Zmień wiele obiektów" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "Zmień %(objects_name)s" +msgstr[1] "Grupowa zmiana %(counter)s %(objects_name)s" +msgstr[2] "Grupowa zmiana %(counter)s %(objects_name)s" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "Zmień wiele" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "Dodaj widget" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"Coś złego dzieje się z Twoją bazą danych. Upewnij się, że konieczne tabele w " +"Twojej bazie danych zostały skreowane i mogą być czytane przez właściwych " +"użytkowników." + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "Wylogowanie zakończone sukcesem" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Dzięki za spędzenie dzisiaj cennego czasu na naszej stronie." + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "Zamknij okno" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "Zaloguj się ponownie" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "Proszę, zaloguj się" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "Nazwa użytkownika" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "Hasło" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "zaloguj się" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "Edytuj" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" +"Usunięcie %(verbose_name)s '%(escaped_object)s' spowoduje usunięcie " +"powiązanych obiektów, ale Twoje konto nie ma uprawnień do usunięcia " +"następujących typów obiektów:" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" +"Usunięcie %(verbose_name)s '%(escaped_object)s' będzie wymagać usunięcia " +"następujących, chronionych obiektów powiązanych:" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" +"Czy jesteś pewien, że chcesz usunąć %(verbose_name)s \"%(escaped_object)s" +"\" ? Wszystkie następujące powiązane obiekty zostaną usunięte:" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "Tak, jestem pewny" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "Anuluj" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "Usuń wiele obiektów" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" +"Usunięcie wybranego obiektów %(objects_name)s będzie skutkowało usunięciem " +"powiązanych obiektów, ale Twoje konto nie posiada uprawnień do usunięcia " +"następujących obiektów:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" +"Usunięcie zaznaczonych obiektów %(objects_name)s będzie wymagało usunięcia " +"następujących zabezpieczonych powiązanych obiektów:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" +"Jesteś pewny, że chcesz usunąc zaznaczone obiekty %(objects_name)s ? " +"Wszystkie następujące obiekty i ich powiązania zostaną usunięte:" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "Różnica" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "Data/czas" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "Użytkownik" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "Komentarz" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "Róznica w wybranych wersjach" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" +"Ten obiekt nie posiada historii zmian. Prawdopodobnie nie został on dodany " +"przez panel administratora." + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "Dodaj %(name)s" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "Kolumny" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "Odzyskaj wybrane" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "Pusta lista" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "Naciśnij przycisk odzyskiwania poniżej, by odzyskać tę wersję obiektu." + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" +"Wybierz datę z poniższej listy aby odzyskać usuniętą wersję danego obiektu." + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "Nie ma usuniętych obiektów, które można odzyskać." + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "Róznice %(verbose_name)s" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "Pole" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "Wersja A" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "Wersja B" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "Przywróć do" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "Przywróć" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "Przywróć %(verbose_name)s" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" +"Naciśnij przycisk przywracania poniżej, aby przywrócić obiekt do tej wersji." + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "Przywróć tę rewizję" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "Sukces" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "Dodawanie udane, kliknij edytuj aby edytować." + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "Szybkie dodaj" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "Opcje widgetów" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "Zapisz zmiany" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "Django Xadmin" + +#: views/base.py:316 +#, fuzzy +#| msgid "my-company.inc 2013" +msgid "my-company.inc" +msgstr "moja-firma.inc 2013" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "ID widgetu" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "Tytuł widgetu" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "Widget treści HTML, możesz wpisać dowolną treść HTMLową w ten widget." + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "Treść HTML" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "Model docelowy" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "Widget szybkich przycisków, pozwala szybko otworzyć dowolna stronę." + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "Szybkie przyciski" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "Dowolny widget listy obiektów." + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "Dodaj dowolny widget modelu obiektu." + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "Dashboard" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "%s Dashboard" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "%(name)s \"%(obj)s\" został usunięty z powodzeniem." + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "Inne pola" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "Szczegóły %s" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, fuzzy, python-format +#| msgid "Change %s" +msgid "Changed %s." +msgstr "Zmień %s" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "%(name)s \"%(obj)s\" został dodany z sukcesem." + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "Możesz edytować to powtórnie poniżej." + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "Możesz dodać kolejny %s poniżej." + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "Zmień %s" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "%(name)s \"%(obj)s\" został zmieniony z powodzeniem." + +#: views/form.py:165 +#, python-format +msgid "The %s was changed successfully." +msgstr "%s został z sukcesem zmieniony." + +#: views/list.py:199 +msgid "Database error" +msgstr "Błąd bazy danych" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "Lista %s" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "Sortuj ASC" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "Sortuj DESC" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "Anuluj sortowanie" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "Główny Dashboard" + +#: widgets.py:48 +msgid "Now" +msgstr "Teraz" diff --git a/extra_apps/xadmin/locale/pl/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/pl/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..9bfc00a Binary files /dev/null and b/extra_apps/xadmin/locale/pl/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/pl/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/pl/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..b087169 --- /dev/null +++ b/extra_apps/xadmin/locale/pl/LC_MESSAGES/djangojs.po @@ -0,0 +1,83 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django-xadmin\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-08-12 21:07+0200\n" +"PO-Revision-Date: 2014-08-12 21:23+0100\n" +"Last-Translator: Michał Szpadzik \n" +"Language-Team: Polish translators \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 1.5.4\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:11 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "%(sel)s z %(cnt)s wybranych" +msgstr[1] "%(sel)s z %(cnt)s wybranych" +msgstr[2] "%(sel)s z %(cnt)s wybranych" + +#: static/xadmin/js/xadmin.plugin.quick-form.js:172 +msgid "Close" +msgstr "Zamknij" + +#: static/xadmin/js/xadmin.plugin.quick-form.js:173 +msgid "Add" +msgstr "Dodaj" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "Nowy obiekt" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "niedziela poniedziałek wtorek środa czwartek piątek sobota niedziela" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "niedz. pon. wt. śr. czw. pt. sob. niedz." + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "niedz. pn. wt. śr. czw. pt. sob. niedz." + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November " +"December" +msgstr "" +"styczeń luty marzec kwiecień maj czerwiec lipiec sierpień wrzesień " +"październik " + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "sty. lut. marz. kwie. maj czerw. lip. sier. wrze. paź. list. grudz." + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "Dzisiaj" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "%a %d %b %Y %T %Z" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "AM PM" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "am pm" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "%T" diff --git a/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000..0187836 Binary files /dev/null and b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/django.po new file mode 100644 index 0000000..31d6ed0 --- /dev/null +++ b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/django.po @@ -0,0 +1,1479 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# korndorfer , 2013 +# Ellison Leão, 2013 +# Gladson Simplício Brito , 2013 +# gladson , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-11-20 10:21+0000\n" +"Last-Translator: gladson \n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/" +"xadmin/language/pt_BR/)\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "Tudo" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "Sim" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "Não" + +#: filters.py:175 +msgid "Unknown" +msgstr "Desconhecido" + +#: filters.py:267 +msgid "Any date" +msgstr "Qualquer data" + +#: filters.py:268 +msgid "Has date" +msgstr "Tem data" + +#: filters.py:271 +msgid "Has no date" +msgstr "Não tem data" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "Hoje" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "Passados 7 dias" + +#: filters.py:282 +msgid "This month" +msgstr "Este mês" + +#: filters.py:286 +msgid "This year" +msgstr "Este ano" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" +"Por favor, insira o nome de usuário e a senha corretamente para sua conta " +"pessoal. Perceba que ambos os campos são case-sensitive." + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "Por favor faça login novamente, porque a sua sessão expirou." + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" +"O seu endereço de e-mail não é seu nome de usuário. Tente '% s' em seu lugar." + +#: models.py:48 +msgid "Title" +msgstr "Título" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "Usuário" + +#: models.py:50 +msgid "Url Name" +msgstr "Nome da Url" + +#: models.py:52 +msgid "Query String" +msgstr "String de Consulta" + +#: models.py:53 +msgid "Is Shared" +msgstr "É Compartilhada" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "Favorito" + +#: models.py:67 +msgid "Bookmarks" +msgstr "Favoritos" + +#: models.py:89 +msgid "Settings Key" +msgstr "Configuração da chave" + +#: models.py:90 +msgid "Settings Content" +msgstr "Configurações de conteúdo" + +#: models.py:102 +msgid "User Setting" +msgstr "Configuração de usuário" + +#: models.py:103 +msgid "User Settings" +msgstr "Configurações do Usuário" + +#: models.py:108 +msgid "Page" +msgstr "Página" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "Tipo de Widget" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "Parâmetros do Widget" + +#: models.py:137 +msgid "User Widget" +msgstr "Widget do Usuário" + +#: models.py:138 +msgid "User Widgets" +msgstr "Widgets do Usuário" + +#: models.py:142 +#, fuzzy +#| msgid "Date/time" +msgid "action time" +msgstr "Data/Hora" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +#, fuzzy +#| msgid "Change %s" +msgid "change message" +msgstr "Alterar %s" + +#: models.py:164 +#, fuzzy +#| msgid "log in" +msgid "log entry" +msgstr "Entrar" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, fuzzy, python-format +#| msgid "Change one %(objects_name)s" +#| msgid_plural "Batch change %(counter)s %(objects_name)s" +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "Alterar um %(objects_name)s" + +#: models.py:180 +#, fuzzy, python-format +#| msgid "Related Objects" +msgid "Deleted \"%(object)s.\"" +msgstr "Objetos Relacionados" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Excluir selecionado %(verbose_name_plural)s" + +#: plugins/actions.py:72 +#, fuzzy, python-format +#| msgid "Successfully deleted %(count)d %(items)s." +msgid "Batch delete %(count)d %(items)s." +msgstr "Excluído com sucesso %(count)d %(items)s." + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Excluído com sucesso %(count)d %(items)s." + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "Não é possível excluir %(name)s" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "Você tem certeza?" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "Todos %(total_count)s selecionados" +msgstr[1] "Todos %(total_count)s selecionados" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "0 de %(cnt)s selecionados" + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" +"Os itens devem ser selecionados, a fim de executar ações sobre eles. Não há " +"itens alterados." + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "Min" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "Max" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "Médio" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "Soma" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "Contar" + +#: plugins/auth.py:21 +#, fuzzy, python-format +msgid "Can add %s" +msgstr "Pode ver %s" + +#: plugins/auth.py:22 +#, fuzzy, python-format +msgid "Can change %s" +msgstr "Alterar %s" + +#: plugins/auth.py:23 +#, fuzzy, python-format +msgid "Can edit %s" +msgstr "Pode ver %s" + +#: plugins/auth.py:24 +#, fuzzy, python-format +msgid "Can delete %s" +msgstr "Não é possível excluir %(name)s" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "Pode ver %s" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "Informações pessoais" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "Permissões" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "Datas importantes" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "Status" + +#: plugins/auth.py:111 +#, fuzzy +msgid "Permission Name" +msgstr "Permissões" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "Alterar Senha" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "Alterar senha: %s" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "Senha alterada com sucesso." + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "Alterar a senha" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "Alterar este campo" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "Alterar lote selecionado %(verbose_name_plural)s" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "Alterado com sucesso %(count)d %(items)s." + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "Lote alterado %s" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "Favorito" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" +"Widget de Marcador, pode mostrar a lista de marcadores do usuário no widget" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "Mostrar modelos gráfico simples." + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "%s Gráficos" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +#, fuzzy +msgid "removed" +msgid_plural "removed" +msgstr[0] "Remover" +msgstr[1] "Remover" + +#: plugins/comments.py:73 +#, fuzzy +msgid "Remove selected comments" +msgstr "Recuperar deletado %(name)s" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "Detalhes de %s" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "Entrar %s" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "%(name)s objeto com chave primária %(key)r não existe." + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "Planilha" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "Filtrar erro: %s" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "Anterior" + +#: plugins/images.py:29 +msgid "Next" +msgstr "Próximo" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "Slideshow" + +#: plugins/images.py:29 +msgid "Download" +msgstr "Baixar" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "Alterar:" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "Tabela" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "Miniaturas" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "Esqueceu seu nome de usuário ou senha?" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "Criar novo %s" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "Objetos Relacionados" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "Pesquisar %s" + +#: plugins/relfield.py:67 +#, fuzzy, python-format +#| msgid "Select Date" +msgid "Select %s" +msgstr "Selecionar Data" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "Padrão" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "Tema padrão bootstrap" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "Bootstrap2" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "Tema Bootstrap 2.x" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "Adicionar %s" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "Versão inicial." + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "Alterar versão." + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "Reverter versão." + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "Recuperar versão." + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "Excluídos %(verbose_name)s." + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "Recuperar" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "Histórico" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "Recuperar deletado %(name)s" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "Alterar histórico: %s" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "É necessário selecionar 2 versões" + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "Por favor selecione duas versões diferentes." + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "Atual: %s" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "Revertido: %s" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" +"%(model)s \"%(name)s\" foi revertido(a) com sucesso. Você pode editá-lo(a) " +"novamente abaixo." + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "Recuperar %s" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" +"%(model)s \"%(name)s\" foi recuperado(a) com sucesso. Você pode editá-lo(a) " +"novamente abaixo." + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "Página não encontrada" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "Pedimos desculpas, mas a página solicitada não foi encontrada." + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "Início" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "Erro do servidor" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "Erro do servidor (500)" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "Erro do Servidor (500)" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"Ocorreu um erro. E foi relatado aos administradores do site via e-mail e " +"deve ser corrigido em breve. Obrigado por sua paciência." + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "Redefinição de senha completada." + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "Sua senha foi definida. Você pode seguir e entrar agora." + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "Entrar" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "Digite a nova senha" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Por favor forneça sua nova senha 2 vezes para que possamos verificar se a " +"mesma foi digitada corretamente." + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "Alterar minha senha" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "A senha foi redefinida com sucesso" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"O link de redefinição de senha era inválida, possivelmente porque ele já foi " +"usado. Por favor, solicite uma nova redefinição de senha." + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" +"Nós enviamos um e-mail com instruções para configurar sua senha para o " +"endereço de e-mail que você solicitou. Você deve recebê-lo em breve." + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Você está recebendo este e-mail porque você pediu uma redefinição de senha " +"para sua conta de usuário em %(site_name)s." + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "Por favor, vá para a página seguinte e escolha uma nova senha:" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "Seu nome de usuário, para o caso de ter esquecido:" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "Obrigado por utilizar o nosso site!" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "A equipe %(site_name)s" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "Redefinição de senha" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" +"Esqueceu sua senha? Forneça seu endereço de e-mail abaixo, e nós lhe " +"enviaremos instruções para definir uma nova." + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "Endereço de e-mail:" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "Redefinir minha senha" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" +"Primeiro, insira um nome de usuário e senha. Então, você vai ser capaz de " +"editar mais opções do usuário." + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "Forneça um nome de usuário e uma senha." + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Por favor corrija o erro abaixo." +msgstr[1] "Por favor corrija os erros abaixo." + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "Digite sua nova senha." + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "Digite uma nova senha para o usuário %(username)s." + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "Bem-Vindo," + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "Sair" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "Você não tem permissão para editar nada." + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "Temas" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "Pesquisar" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "Adicionar" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "Passo anterior" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "Próximo passo" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "Gravar" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "Limpar Favoritos" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "Sem Favoritos" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "Novo Favorito" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "Marcar a página atual como favorito" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "Digite o título do favorito" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "Aguardando" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "Marcar Favorito" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "Filtros" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "Limpar Filtros" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "Clique aqui para selecionar os objetos através de todas as páginas" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "Selecionar todos %(total_count)s %(model_name)s" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "Limpar Seleção" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "Gráficos" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "Exportar" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "Exportar com cabeçalho da tabela" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "Exportar com o formato." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "Exportar todos os dados." + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "Fechar" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "Layout" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "Atualização Limpa" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "A cada %(t)s segundos" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "Nulo" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "Entrar" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "Data Escolhida" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "YY" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "ano" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "MM" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "mês" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "DD" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "dia" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "Aplicar" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "Intervalo de Datas" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "Selecionar Data" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "De" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "Para" + +#: templates/xadmin/filters/fk_search.html:14 +#, fuzzy +#| msgid "Select Date" +msgid "Select" +msgstr "Selecionar Data" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "Limpar" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "Digite o Número" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " Por %(filter_title)s " + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "Disponível" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "Clique para selecionar tudo de uma só vez." + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "Escolher tudo" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "Escolher" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "Remover" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "Escolhido" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "Clique para remover todos os escolhidos de uma vez." + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "Remover tudo" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "Mostrar Tudo" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "Salvando..." + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "Gravar como novo" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "Gravar e adicionar outro" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "Gravar e continuar editando" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "Excluir" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "Alterar múltiplos objetos" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "Alterar um %(objects_name)s" +msgstr[1] "Alterar lote %(counter)s %(objects_name)s" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "Alterar Múltiplos" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "Adicionar Widget" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"Algo está errado com a instalação do banco de dados. Certifique-se que as " +"tabelas foram criadas apropriadamente, e certifique-se que o banco de dados " +"pode ser lido pelo usuário apropriado." + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "Saída com Sucesso" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Obrigado por gastar algum tempo de qualidade com o site hoje." + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "Fechar Janela" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "Entrar novamente" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "Por Favor Autentique-se" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "Nome de Usuário" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "Senha" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "Entrar" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "Editar" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" +"Excluir o %(verbose_name)s '%(escaped_object)s' resultaria na exclusão dos " +"objetos relacionados, mas a sua conta não tem permissão para excluir os " +"seguintes tipos de objetos:" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" +"Excluir o %(verbose_name)s '%(escaped_object)s' exigiria exclusão dos " +"seguintes objetos protegidos relacionados:" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" +"Tem certeza de que deseja excluir %(verbose_name)s \"%(escaped_object)s\"? " +"Todos os seguintes itens relacionados serão excluídos:" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "Sim, tenho certeza" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "Cancelar" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "Excluir múltiplos objetos" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" +"Excluir o %(objects_name)s selecionado resultaria na exclusão de objetos " +"relacionados, mas a sua conta não tem permissão para excluir os seguintes " +"tipos de objetos:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" +"Excluir o %(objects_name)s selecionado exigiria eliminar os seguintes " +"objetos protegidos relacionados:" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" +"Tem certeza de que deseja excluir o %(objects_name)s selecionado? Todos os " +"seguintes objetos e seus itens relacionados serão excluídos:" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "Comparar" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "Data/Hora" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "Usuário" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "Comentário" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "Comparar Versões Selecionadas" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" +"Este objeto não possui um histórico de mudança. Provavelmente não foi " +"adicionado pelo site de administração." + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "Adicionar %(name)s" + +#: templates/xadmin/views/model_list.html:39 +#, fuzzy +msgid "Columns" +msgstr "Colunas" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "Restaurar Selecionados" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "Limpar lista" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "Clique no botão recuperar abaixo para recuperar esta versão do objeto." + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" +"Escolha a data a partir da lista abaixo para recuperar a versão excluída do " +"objeto." + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "Não há objetos excluídos para recuperar." + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "Comparar %(verbose_name)s" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "Campo" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "Versão A" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "Versão B" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "Reverter para" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "Reverter" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "Reverter %(verbose_name)s" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" +"Clique no botão reverter abaixo para reverter para esta versão do objeto." + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "Reverter esta revisão" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "Sucesso" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "Sucesso na adição, clique editar para editar." + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "Adição Rápida" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "Opções do Widget" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "Gravar alterações" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "Django Xadmin" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "ID do Widget" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "Título do Widget" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" +"Widget de Conteúdo HTML, pode-se escrever qualquer conteúdo html no widget." + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "Conteúdo HTML" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "Modelo Alvo" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "Widget de Botão Rápido, abre rapidamente qualquer página." + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "Botões Rápidos" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "Widget de listagem de Qualquer Objeto" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "Widget de adição de qualquer objeto." + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "Painel" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "%s Painel" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "%(name)s \"%(obj)s\" excluído(a) com sucesso." + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "Outros Campos" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "%s Detalhes" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, fuzzy, python-format +#| msgid "Change %s" +msgid "Changed %s." +msgstr "Alterar %s" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "%(name)s \"%(obj)s\" adicionado(a) com sucesso." + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "Você pode editar novamente abaixo." + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "Você pode adicionar outro(a) %s abaixo." + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "Alterar %s" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "%(name)s \"%(obj)s\" alterado(a) com sucesso." + +#: views/form.py:165 +#, fuzzy, python-format +msgid "The %s was changed successfully." +msgstr "%(name)s \"%(obj)s\" alterado(a) com sucesso." + +#: views/list.py:199 +msgid "Database error" +msgstr "Erro da base de dados" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "Lista %s" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "Classificação Ascendente" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "Classificação Descendente" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "Cancelar Classificação" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "Painel Principal" + +#: widgets.py:48 +msgid "Now" +msgstr "Agora" diff --git a/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..31666c0 Binary files /dev/null and b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..8441f0a --- /dev/null +++ b/extra_apps/xadmin/locale/pt_BR/LC_MESSAGES/djangojs.po @@ -0,0 +1,71 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# korndorfer , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: korndorfer \n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/xadmin/language/pt_BR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt_BR\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "%(sel)s de %(cnt)s selecionado" +msgstr[1] "%(sel)s de %(cnt)s selecionados" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "Novo Item" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "Domingo Segunda Terça Quarta Quinta Sexta Sábado Domingo" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "Dom Seg Ter Qua Qui Sex Sáb Dom" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "Do Sg Te Qa Qi Sx Sa Do" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "Janeiro Fevereiro Março Abril Maio Junho Julho Agosto Setembro Outubro Novembro Dezembro" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "Hoje" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "%a %d %b %Y %T %Z" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "AM PM" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "am pm" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "%T" diff --git a/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/django.mo new file mode 100644 index 0000000..58d8e71 Binary files /dev/null and b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/django.po new file mode 100644 index 0000000..6bdc794 --- /dev/null +++ b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/django.po @@ -0,0 +1,1438 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# crazyzubr , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-20 13:28+0800\n" +"PO-Revision-Date: 2013-12-28 19:36+0000\n" +"Last-Translator: crazyzubr \n" +"Language-Team: Russian (Russia) (http://www.transifex.com/projects/p/xadmin/" +"language/ru_RU/)\n" +"Language: ru_RU\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: adminx.py:19 +msgid "Admin Object" +msgstr "" + +#: apps.py:11 +msgid "Administration" +msgstr "" + +#: filters.py:159 filters.py:191 filters.py:407 filters.py:493 filters.py:531 +msgid "All" +msgstr "Все" + +#: filters.py:160 plugins/export.py:165 +msgid "Yes" +msgstr "Да" + +#: filters.py:161 plugins/export.py:165 +msgid "No" +msgstr "Нет" + +#: filters.py:175 +msgid "Unknown" +msgstr "Неизвестно" + +#: filters.py:267 +msgid "Any date" +msgstr "Любая дата" + +#: filters.py:268 +msgid "Has date" +msgstr "" + +#: filters.py:271 +msgid "Has no date" +msgstr "" + +#: filters.py:274 widgets.py:30 +msgid "Today" +msgstr "Сегодня" + +#: filters.py:278 +msgid "Past 7 days" +msgstr "За последние 7 дней" + +#: filters.py:282 +msgid "This month" +msgstr "В этом месяце" + +#: filters.py:286 +msgid "This year" +msgstr "В этом году" + +#: forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" +"Пожалуйста, введите корректные имя пользователя и пароль для аккаунта. Оба " +"поля могут быть чувствительны к регистру." + +#: forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "Пожалуйста, войдите снова, поскольку ваша сессия устарела." + +#: forms.py:41 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "" + +#: models.py:48 +msgid "Title" +msgstr "Заголовок" + +#: models.py:49 models.py:88 models.py:107 models.py:149 +msgid "user" +msgstr "" + +#: models.py:50 +msgid "Url Name" +msgstr "" + +#: models.py:52 +msgid "Query String" +msgstr "Строка запроса" + +#: models.py:53 +msgid "Is Shared" +msgstr "" + +#: models.py:66 plugins/bookmark.py:50 plugins/bookmark.py:180 +msgid "Bookmark" +msgstr "Закладка" + +#: models.py:67 +msgid "Bookmarks" +msgstr "Закладки" + +#: models.py:89 +msgid "Settings Key" +msgstr "" + +#: models.py:90 +msgid "Settings Content" +msgstr "" + +#: models.py:102 +msgid "User Setting" +msgstr "" + +#: models.py:103 +msgid "User Settings" +msgstr "" + +#: models.py:108 +msgid "Page" +msgstr "Страница" + +#: models.py:109 views/dashboard.py:82 views/dashboard.py:92 +msgid "Widget Type" +msgstr "Тип виджета" + +#: models.py:110 views/dashboard.py:83 +msgid "Widget Params" +msgstr "Параметры виджета" + +#: models.py:137 +msgid "User Widget" +msgstr "" + +#: models.py:138 +msgid "User Widgets" +msgstr "" + +#: models.py:142 +msgid "action time" +msgstr "" + +#: models.py:151 +msgid "action ip" +msgstr "" + +#: models.py:155 +msgid "content type" +msgstr "" + +#: models.py:158 +msgid "object id" +msgstr "" + +#: models.py:159 +msgid "object repr" +msgstr "" + +#: models.py:160 +msgid "action flag" +msgstr "" + +#: models.py:161 +#, fuzzy +#| msgid "Change %s" +msgid "change message" +msgstr "Изменить %s" + +#: models.py:164 +msgid "log entry" +msgstr "" + +#: models.py:165 +msgid "log entries" +msgstr "" + +#: models.py:173 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "" + +#: models.py:175 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "" + +#: models.py:180 +#, fuzzy, python-format +#| msgid "Related Objects" +msgid "Deleted \"%(object)s.\"" +msgstr "Связанные объекты" + +#: plugins/actions.py:57 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "Удалить выбранные %(verbose_name_plural)s" + +#: plugins/actions.py:72 +#, fuzzy, python-format +#| msgid "Successfully deleted %(count)d %(items)s." +msgid "Batch delete %(count)d %(items)s." +msgstr "Успешно удалены %(count)d %(items)s." + +#: plugins/actions.py:78 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "Успешно удалены %(count)d %(items)s." + +#: plugins/actions.py:110 views/delete.py:70 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "Не удается удалить %(name)s" + +#: plugins/actions.py:112 views/delete.py:73 +msgid "Are you sure?" +msgstr "Вы уверены?" + +#: plugins/actions.py:158 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "Выбран %(total_count)s" +msgstr[1] "Выбраны все %(total_count)s" +msgstr[2] "Выбраны все %(total_count)s" + +#: plugins/actions.py:162 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "Выбрано 0 объектов из %(cnt)s " + +#: plugins/actions.py:179 plugins/actions.py:189 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" +"Чтобы произвести действия над объектами, необходимо их выбрать. Объекты не " +"были изменены." + +#: plugins/aggregation.py:14 +msgid "Min" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Max" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Avg" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Sum" +msgstr "" + +#: plugins/aggregation.py:14 +msgid "Count" +msgstr "" + +#: plugins/auth.py:21 +#, fuzzy, python-format +msgid "Can add %s" +msgstr "Добавить %s" + +#: plugins/auth.py:22 +#, fuzzy, python-format +msgid "Can change %s" +msgstr "Изменить %s" + +#: plugins/auth.py:23 +#, python-format +msgid "Can edit %s" +msgstr "" + +#: plugins/auth.py:24 +#, fuzzy, python-format +msgid "Can delete %s" +msgstr "Не удается удалить %(name)s" + +#: plugins/auth.py:25 +#, python-format +msgid "Can view %s" +msgstr "" + +#: plugins/auth.py:87 +msgid "Personal info" +msgstr "Персональная информация" + +#: plugins/auth.py:91 +msgid "Permissions" +msgstr "Права" + +#: plugins/auth.py:94 +msgid "Important dates" +msgstr "Важные даты" + +#: plugins/auth.py:99 +msgid "Status" +msgstr "Статус" + +#: plugins/auth.py:111 +#, fuzzy +msgid "Permission Name" +msgstr "Права" + +#: plugins/auth.py:167 +msgid "Change Password" +msgstr "Изменить пароль" + +#: plugins/auth.py:198 +#, python-format +msgid "Change password: %s" +msgstr "Изменить пароль: %s" + +#: plugins/auth.py:223 plugins/auth.py:255 +msgid "Password changed successfully." +msgstr "Пароль успешно изменен" + +#: plugins/auth.py:242 templates/xadmin/auth/user/change_password.html:11 +#: templates/xadmin/auth/user/change_password.html:22 +#: templates/xadmin/auth/user/change_password.html:55 +msgid "Change password" +msgstr "Изменить пароль" + +#: plugins/batch.py:44 +msgid "Change this field" +msgstr "" + +#: plugins/batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "" + +#: plugins/batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "" + +#: plugins/batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "" + +#: plugins/bookmark.py:173 +msgid "bookmark" +msgstr "" + +#: plugins/bookmark.py:176 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "" + +#: plugins/chart.py:25 +msgid "Show models simple chart." +msgstr "" + +#: plugins/chart.py:51 +#, python-format +msgid "%s Charts" +msgstr "" + +#: plugins/comments.py:33 +msgid "Metadata" +msgstr "" + +#: plugins/comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: plugins/comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: plugins/comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/comments.py:73 +msgid "Remove selected comments" +msgstr "" + +#: plugins/comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: plugins/details.py:52 views/list.py:578 +#, python-format +msgid "Details of %s" +msgstr "Детали %s" + +#: plugins/editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "" + +#: plugins/editable.py:73 views/dashboard.py:649 views/delete.py:27 +#: views/detail.py:145 views/edit.py:454 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "" + +#: plugins/export.py:98 plugins/export.py:135 +msgid "Sheet" +msgstr "Лист" + +#: plugins/filters.py:133 plugins/quickfilter.py:141 +#, python-format +msgid "Filtering error: %s" +msgstr "" + +#: plugins/images.py:29 +msgid "Previous" +msgstr "" + +#: plugins/images.py:29 +msgid "Next" +msgstr "" + +#: plugins/images.py:29 +msgid "Slideshow" +msgstr "Слайдшоу" + +#: plugins/images.py:29 +msgid "Download" +msgstr "Загрузить" + +#: plugins/images.py:50 +msgid "Change:" +msgstr "Изменить:" + +#: plugins/layout.py:16 +msgid "Table" +msgstr "" + +#: plugins/layout.py:22 +msgid "Thumbnails" +msgstr "" + +#: plugins/passwords.py:64 +msgid "Forgotten your password or username?" +msgstr "" + +#: plugins/quickform.py:79 +#, python-format +msgid "Create New %s" +msgstr "" + +#: plugins/relate.py:104 +msgid "Related Objects" +msgstr "Связанные объекты" + +#: plugins/relfield.py:29 plugins/topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "Поиск %s" + +#: plugins/relfield.py:67 +#, python-format +msgid "Select %s" +msgstr "" + +#: plugins/themes.py:47 +msgid "Default" +msgstr "" + +#: plugins/themes.py:48 +msgid "Default bootstrap theme" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap2" +msgstr "" + +#: plugins/themes.py:49 +msgid "Bootstrap 2.x theme" +msgstr "" + +#: plugins/topnav.py:62 views/dashboard.py:465 views/edit.py:387 +#: views/edit.py:396 +#, python-format +msgid "Add %s" +msgstr "Добавить %s" + +#: plugins/xversion.py:106 +msgid "Initial version." +msgstr "" + +#: plugins/xversion.py:108 +msgid "Change version." +msgstr "" + +#: plugins/xversion.py:110 +msgid "Revert version." +msgstr "" + +#: plugins/xversion.py:112 +msgid "Rercover version." +msgstr "" + +#: plugins/xversion.py:114 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "" + +#: plugins/xversion.py:127 templates/xadmin/views/recover_form.html:26 +msgid "Recover" +msgstr "" + +#: plugins/xversion.py:143 templates/xadmin/views/model_history.html:11 +#: templates/xadmin/views/revision_diff.html:11 +#: templates/xadmin/views/revision_form.html:15 +msgid "History" +msgstr "История" + +#: plugins/xversion.py:194 templates/xadmin/views/recover_form.html:14 +#: templates/xadmin/views/recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "" + +#: plugins/xversion.py:238 +#, python-format +msgid "Change history: %s" +msgstr "" + +#: plugins/xversion.py:288 +msgid "Must select two versions." +msgstr "Необходимо выбрать две версии." + +#: plugins/xversion.py:296 +msgid "Please select two different versions." +msgstr "Пожалуйста, выберите две различные версии." + +#: plugins/xversion.py:383 plugins/xversion.py:500 +#, python-format +msgid "Current: %s" +msgstr "" + +#: plugins/xversion.py:424 +#, python-format +msgid "Revert %s" +msgstr "" + +#: plugins/xversion.py:440 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "" + +#: plugins/xversion.py:461 +#, python-format +msgid "Recover %s" +msgstr "" + +#: plugins/xversion.py:477 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "" + +#: templates/xadmin/404.html:4 templates/xadmin/404.html:8 +msgid "Page not found" +msgstr "Страница не найдена" + +#: templates/xadmin/404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "" + +#: templates/xadmin/500.html:7 +#: templates/xadmin/auth/user/change_password.html:10 +#: templates/xadmin/auth/user/change_password.html:15 +#: templates/xadmin/base_site.html:53 +#: templates/xadmin/includes/sitemenu_default.html:7 +#: templates/xadmin/views/app_index.html:9 +#: templates/xadmin/views/batch_change_form.html:9 +#: templates/xadmin/views/invalid_setup.html:7 +#: templates/xadmin/views/model_dashboard.html:7 +#: templates/xadmin/views/model_delete_selected_confirm.html:8 +#: templates/xadmin/views/model_history.html:8 +#: templates/xadmin/views/recover_form.html:8 +#: templates/xadmin/views/recover_list.html:8 +#: templates/xadmin/views/revision_diff.html:8 +#: templates/xadmin/views/revision_form.html:8 views/base.py:473 +msgid "Home" +msgstr "Главная" + +#: templates/xadmin/500.html:8 +msgid "Server error" +msgstr "" + +#: templates/xadmin/500.html:12 +msgid "Server error (500)" +msgstr "" + +#: templates/xadmin/500.html:15 +msgid "Server Error (500)" +msgstr "" + +#: templates/xadmin/500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:11 +#: templates/xadmin/auth/password_reset/done.html:11 +msgid "Password reset successful" +msgstr "Пароль успешно восстановлен" + +#: templates/xadmin/auth/password_reset/complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "" + +#: templates/xadmin/auth/password_reset/complete.html:15 +msgid "Log in" +msgstr "Войти" + +#: templates/xadmin/auth/password_reset/confirm.html:12 +msgid "Enter new password" +msgstr "Введите новый пароль:" + +#: templates/xadmin/auth/password_reset/confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "" +"Пожалуйста, введите новый пароль дважды, чтобы мы могли убедиться в " +"правильности написания." + +#: templates/xadmin/auth/password_reset/confirm.html:19 +msgid "Change my password" +msgstr "" + +#: templates/xadmin/auth/password_reset/confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "Ошибка восстановления пароля" + +#: templates/xadmin/auth/password_reset/confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "" +"Неверная ссылка для восстановления пароля. Возможно, ей уже воспользовались. " +"Пожалуйста, попробуйте восстановить пароль еще раз." + +#: templates/xadmin/auth/password_reset/done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" +"Мы отправили инструкцию по восстановлению пароля на указанный вами адрес " +"электронной почты. Вы должны её вскоре получить." + +#: templates/xadmin/auth/password_reset/email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "" +"Вы получили это письмо, потому что вы (или кто-то другой) запросили " +"восстановление пароля от учётной записи на сайте %(site_name)s, которая " +"связана с этим адресом электронной почты." + +#: templates/xadmin/auth/password_reset/email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "Пожалуйста, перейдите на эту страницу и введите новый пароль:" + +#: templates/xadmin/auth/password_reset/email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:10 +msgid "Thanks for using our site!" +msgstr "" + +#: templates/xadmin/auth/password_reset/email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:13 +msgid "Password reset" +msgstr "Восстановление пароля" + +#: templates/xadmin/auth/password_reset/form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:25 +msgid "E-mail address:" +msgstr "" + +#: templates/xadmin/auth/password_reset/form.html:33 +msgid "Reset my password" +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "" + +#: templates/xadmin/auth/user/add_form.html:8 +msgid "Enter a username and password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:31 +#: templates/xadmin/views/batch_change_form.html:24 +#: templates/xadmin/views/form.html:18 +#: templates/xadmin/views/model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Пожалуйста, исправьте ошибку ниже." +msgstr[1] "Пожалуйста, исправьте ошибки ниже." +msgstr[2] "Пожалуйста, исправьте ошибки ниже." + +#: templates/xadmin/auth/user/change_password.html:38 +msgid "Enter your new password." +msgstr "" + +#: templates/xadmin/auth/user/change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "" + +#: templates/xadmin/base_site.html:18 +msgid "Welcome," +msgstr "" + +#: templates/xadmin/base_site.html:24 +msgid "Log out" +msgstr "Выйти" + +#: templates/xadmin/base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "" + +#: templates/xadmin/blocks/comm.top.theme.html:4 +msgid "Themes" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:9 +#: templates/xadmin/blocks/model_list.nav_form.search_form.html:8 +#: templates/xadmin/filters/char.html:7 +#: templates/xadmin/filters/fk_search.html:7 +#: templates/xadmin/filters/fk_search.html:16 +#: templates/xadmin/filters/number.html:7 +msgid "Search" +msgstr "" + +#: templates/xadmin/blocks/comm.top.topnav.html:23 +msgid "Add" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:9 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:13 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "" + +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:15 +#: templates/xadmin/blocks/model_form.submit_line.wizard.html:31 +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Save" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "" + +#: templates/xadmin/blocks/model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:4 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:8 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:19 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:47 +msgid "Export" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:26 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:29 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:35 +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:42 +msgid "Export all data." +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.exports.html:46 +#: templates/xadmin/widgets/base.html:41 +msgid "Close" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "" + +#: templates/xadmin/blocks/model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "" + +#: templates/xadmin/edit_inline/blank.html:5 views/detail.py:23 +#: views/edit.py:102 views/list.py:29 +msgid "Null" +msgstr "" + +#: templates/xadmin/filters/char.html:13 +msgid "Enter" +msgstr "" + +#: templates/xadmin/filters/date.html:10 templates/xadmin/filters/date.html:13 +msgid "Choice Date" +msgstr "" + +#: templates/xadmin/filters/date.html:18 +msgid "YY" +msgstr "" + +#: templates/xadmin/filters/date.html:19 +msgid "year" +msgstr "" + +#: templates/xadmin/filters/date.html:22 +msgid "MM" +msgstr "" + +#: templates/xadmin/filters/date.html:23 +msgid "month" +msgstr "" + +#: templates/xadmin/filters/date.html:26 +msgid "DD" +msgstr "" + +#: templates/xadmin/filters/date.html:27 +msgid "day" +msgstr "" + +#: templates/xadmin/filters/date.html:29 templates/xadmin/filters/date.html:46 +#: templates/xadmin/filters/date.html:54 +#: templates/xadmin/filters/fk_search.html:24 +#: templates/xadmin/filters/number.html:37 +msgid "Apply" +msgstr "" + +#: templates/xadmin/filters/date.html:34 +msgid "Date Range" +msgstr "" + +#: templates/xadmin/filters/date.html:41 +msgid "Select Date" +msgstr "" + +#: templates/xadmin/filters/date.html:42 +msgid "From" +msgstr "" + +#: templates/xadmin/filters/date.html:44 +msgid "To" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:14 +msgid "Select" +msgstr "" + +#: templates/xadmin/filters/fk_search.html:26 +#: templates/xadmin/filters/number.html:39 +msgid "Clean" +msgstr "" + +#: templates/xadmin/filters/number.html:17 +#: templates/xadmin/filters/number.html:25 +#: templates/xadmin/filters/number.html:33 +msgid "Enter Number" +msgstr "" + +#: templates/xadmin/filters/rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr "" + +#: templates/xadmin/forms/transfer.html:4 +msgid "Available" +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Click to choose all at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:12 +msgid "Choose all" +msgstr "" + +#: templates/xadmin/forms/transfer.html:16 +msgid "Choose" +msgstr "" + +#: templates/xadmin/forms/transfer.html:19 +#: templates/xadmin/widgets/base.html:40 +msgid "Remove" +msgstr "" + +#: templates/xadmin/forms/transfer.html:23 +msgid "Chosen" +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "" + +#: templates/xadmin/forms/transfer.html:27 +msgid "Remove all" +msgstr "" + +#: templates/xadmin/includes/pagination.html:9 +msgid "Show all" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:10 +#: templates/xadmin/includes/submit_line.html:13 +#: templates/xadmin/views/form.html:30 templates/xadmin/views/form.html:31 +msgid "Saving.." +msgstr "" + +#: templates/xadmin/includes/submit_line.html:17 +msgid "Save as new" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:18 +msgid "Save and add another" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:19 +msgid "Save and continue editing" +msgstr "" + +#: templates/xadmin/includes/submit_line.html:24 +#: templates/xadmin/views/model_detail.html:28 views/delete.py:93 +msgid "Delete" +msgstr "" + +#: templates/xadmin/views/app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "" + +#: templates/xadmin/views/batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: templates/xadmin/views/batch_change_form.html:38 +msgid "Change Multiple" +msgstr "" + +#: templates/xadmin/views/dashboard.html:15 +#: templates/xadmin/views/dashboard.html:22 +#: templates/xadmin/views/dashboard.html:23 +msgid "Add Widget" +msgstr "" + +#: templates/xadmin/views/invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" + +#: templates/xadmin/views/logged_out.html:16 +msgid "Logout Success" +msgstr "" + +#: templates/xadmin/views/logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/xadmin/views/logged_out.html:19 +msgid "Close Window" +msgstr "Закрыть окно" + +#: templates/xadmin/views/logged_out.html:20 +msgid "Log in again" +msgstr "Войти заново" + +#: templates/xadmin/views/login.html:39 views/website.py:38 +msgid "Please Login" +msgstr "" + +#: templates/xadmin/views/login.html:52 +msgid "Username" +msgstr "" + +#: templates/xadmin/views/login.html:64 +msgid "Password" +msgstr "" + +#: templates/xadmin/views/login.html:75 +msgid "log in" +msgstr "" + +#: templates/xadmin/views/model_dashboard.html:26 +#: templates/xadmin/views/model_detail.html:25 +msgid "Edit" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:34 +#: templates/xadmin/views/model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/xadmin/views/model_delete_confirm.html:35 +#: templates/xadmin/views/model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "" + +#: templates/xadmin/views/model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" + +#: templates/xadmin/views/model_history.html:26 +msgid "Diff" +msgstr "" + +#: templates/xadmin/views/model_history.html:27 +#: templates/xadmin/views/recover_list.html:25 +msgid "Date/time" +msgstr "" + +#: templates/xadmin/views/model_history.html:28 +msgid "User" +msgstr "" + +#: templates/xadmin/views/model_history.html:29 +msgid "Comment" +msgstr "" + +#: templates/xadmin/views/model_history.html:54 +msgid "Diff Select Versions" +msgstr "" + +#: templates/xadmin/views/model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "" + +#: templates/xadmin/views/model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "" + +#: templates/xadmin/views/model_list.html:39 +msgid "Columns" +msgstr "" + +#: templates/xadmin/views/model_list.html:42 +msgid "Restore Selected" +msgstr "" + +#: templates/xadmin/views/model_list.html:147 +#: templates/xadmin/widgets/list.html:33 +msgid "Empty list" +msgstr "" + +#: templates/xadmin/views/recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "" + +#: templates/xadmin/views/recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "" + +#: templates/xadmin/views/revision_diff.html:12 +#: templates/xadmin/views/revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:25 +msgid "Field" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:26 +msgid "Version A" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:27 +msgid "Version B" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:39 +msgid "Revert to" +msgstr "" + +#: templates/xadmin/views/revision_diff.html:40 +#: templates/xadmin/views/revision_diff.html:41 +msgid "Revert" +msgstr "" + +#: templates/xadmin/views/revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "" + +#: templates/xadmin/views/revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "" + +#: templates/xadmin/views/revision_form.html:27 +msgid "Revert this revision" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Success" +msgstr "" + +#: templates/xadmin/widgets/addform.html:14 +msgid "Add success, click edit to edit." +msgstr "" + +#: templates/xadmin/widgets/addform.html:17 +msgid "Quick Add" +msgstr "" + +#: templates/xadmin/widgets/base.html:31 +msgid "Widget Options" +msgstr "" + +#: templates/xadmin/widgets/base.html:42 +msgid "Save changes" +msgstr "" + +#: views/base.py:315 +msgid "Django Xadmin" +msgstr "" + +#: views/base.py:316 +msgid "my-company.inc" +msgstr "" + +#: views/dashboard.py:186 +msgid "Widget ID" +msgstr "" + +#: views/dashboard.py:187 +msgid "Widget Title" +msgstr "" + +#: views/dashboard.py:252 +msgid "Html Content Widget, can write any html content in widget." +msgstr "" + +#: views/dashboard.py:255 +msgid "Html Content" +msgstr "" + +#: views/dashboard.py:318 +msgid "Target Model" +msgstr "" + +#: views/dashboard.py:369 +msgid "Quick button Widget, quickly open any page." +msgstr "" + +#: views/dashboard.py:371 +msgid "Quick Buttons" +msgstr "" + +#: views/dashboard.py:416 +msgid "Any Objects list Widget." +msgstr "" + +#: views/dashboard.py:456 +msgid "Add any model object Widget." +msgstr "" + +#: views/dashboard.py:492 +msgid "Dashboard" +msgstr "" + +#: views/dashboard.py:633 +#, python-format +msgid "%s Dashboard" +msgstr "" + +#: views/delete.py:103 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "" + +#: views/detail.py:173 views/edit.py:211 views/form.py:72 +msgid "Other Fields" +msgstr "" + +#: views/detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "" + +#: views/edit.py:253 +msgid "Added." +msgstr "" + +#: views/edit.py:255 +#, fuzzy, python-format +#| msgid "Change %s" +msgid "Changed %s." +msgstr "Изменить %s" + +#: views/edit.py:255 +msgid "and" +msgstr "" + +#: views/edit.py:258 +msgid "No fields changed." +msgstr "" + +#: views/edit.py:420 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "" + +#: views/edit.py:425 views/edit.py:520 +msgid "You may edit it again below." +msgstr "" + +#: views/edit.py:429 views/edit.py:523 +#, python-format +msgid "You may add another %s below." +msgstr "" + +#: views/edit.py:471 +#, python-format +msgid "Change %s" +msgstr "Изменить %s" + +#: views/edit.py:516 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "" + +#: views/form.py:165 +#, fuzzy, python-format +msgid "The %s was changed successfully." +msgstr "Пароль успешно изменен" + +#: views/list.py:199 +msgid "Database error" +msgstr "" + +#: views/list.py:373 +#, python-format +msgid "%s List" +msgstr "" + +#: views/list.py:499 +msgid "Sort ASC" +msgstr "" + +#: views/list.py:500 +msgid "Sort DESC" +msgstr "" + +#: views/list.py:504 +msgid "Cancel Sort" +msgstr "" + +#: views/website.py:16 +msgid "Main Dashboard" +msgstr "" + +#: widgets.py:48 +msgid "Now" +msgstr "Сейчас" diff --git a/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..801ea7b Binary files /dev/null and b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..baa8343 --- /dev/null +++ b/extra_apps/xadmin/locale/ru_RU/LC_MESSAGES/djangojs.po @@ -0,0 +1,71 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-04-30 23:11+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Russian (Russia) (http://www.transifex.com/projects/p/xadmin/language/ru_RU/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru_RU\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: static/xadmin/js/xadmin.plugin.actions.js:20 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "" +"January February March April May June July August September October November" +" December" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "" diff --git a/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/django.mo b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/django.mo new file mode 100644 index 0000000..2107c5b Binary files /dev/null and b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/django.mo differ diff --git a/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/django.po b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/django.po new file mode 100644 index 0000000..cd41423 --- /dev/null +++ b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/django.po @@ -0,0 +1,1528 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# sshwsfc , 2013 +# sshwsfc , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-09-04 15:12+0800\n" +"PO-Revision-Date: 2013-11-20 10:21+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/xadmin/" +"language/zh_CN/)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: .\adminx.py:20 +msgid "Admin Object" +msgstr "管理对象" + +#: .\apps.py:11 +msgid "Administration" +msgstr "管理" + +#: .\filters.py:169 .\filters.py:207 .\filters.py:427 .\filters.py:513 +#: .\filters.py:551 +msgid "All" +msgstr "全部" + +#: .\filters.py:170 .\plugins\export.py:167 +msgid "Yes" +msgstr "是" + +#: .\filters.py:171 .\plugins\export.py:167 +msgid "No" +msgstr "否" + +#: .\filters.py:191 +msgid "Unknown" +msgstr "未知" + +#: .\filters.py:287 +msgid "Any date" +msgstr "任意日期" + +#: .\filters.py:288 +msgid "Has date" +msgstr "有日期" + +#: .\filters.py:291 +msgid "Has no date" +msgstr "无日期" + +#: .\filters.py:294 .\widgets.py:35 .\widgets.py:81 +msgid "Today" +msgstr "今天" + +#: .\filters.py:298 +msgid "Past 7 days" +msgstr "过去7天" + +#: .\filters.py:302 +msgid "This month" +msgstr "本月" + +#: .\filters.py:306 +msgid "This year" +msgstr "今年" + +#: .\forms.py:10 +msgid "" +"Please enter the correct username and password for a staff account. Note " +"that both fields are case-sensitive." +msgstr "" +"请输入正确的用户名和密码来登陆您的管理账户。请注意用户名和密码均为大小写相" +"关。" + +#: .\forms.py:21 +msgid "Please log in again, because your session has expired." +msgstr "请重新登录,因为你的会话已经过期。" + +#: .\forms.py:42 +#, python-format +msgid "Your e-mail address is not your username. Try '%s' instead." +msgstr "你的 e-mail 地址不是你的用户名。换 '%s' 试试。" + +#: .\models.py:46 +msgid "Title" +msgstr "标题" + +#: .\models.py:47 .\models.py:87 .\models.py:107 .\models.py:151 +msgid "user" +msgstr "用户" + +#: .\models.py:48 +msgid "Url Name" +msgstr "URL名字" + +#: .\models.py:50 +msgid "Query String" +msgstr "Query参数" + +#: .\models.py:51 +msgid "Is Shared" +msgstr "是否共享" + +#: .\models.py:64 .\plugins\bookmark.py:59 .\plugins\bookmark.py:194 +msgid "Bookmark" +msgstr "书签" + +#: .\models.py:65 +msgid "Bookmarks" +msgstr "书签" + +#: .\models.py:88 +msgid "Settings Key" +msgstr "设置KEY" + +#: .\models.py:89 +msgid "Settings Content" +msgstr "设置内容" + +#: .\models.py:101 +msgid "User Setting" +msgstr "用户设置" + +#: .\models.py:102 +msgid "User Settings" +msgstr "用户设置" + +#: .\models.py:108 +msgid "Page" +msgstr "页面" + +#: .\models.py:109 .\views\dashboard.py:85 .\views\dashboard.py:95 +msgid "Widget Type" +msgstr "Widget类型" + +#: .\models.py:110 .\views\dashboard.py:86 +msgid "Widget Params" +msgstr "Widget参数" + +#: .\models.py:137 +msgid "User Widget" +msgstr "用户小组件" + +#: .\models.py:138 +msgid "User Widgets" +msgstr "用户小组件" + +#: .\models.py:144 +msgid "action time" +msgstr "记录时间" + +#: .\models.py:153 +msgid "action ip" +msgstr "操作IP" + +#: .\models.py:157 +msgid "content type" +msgstr "数据类型" + +#: .\models.py:160 +msgid "object id" +msgstr "数据ID" + +#: .\models.py:161 +msgid "object repr" +msgstr "数据描述" + +#: .\models.py:162 +msgid "action flag" +msgstr "操作标示" + +#: .\models.py:163 +msgid "change message" +msgstr "修改信息" + +#: .\models.py:166 +msgid "log entry" +msgstr "日志" + +#: .\models.py:167 +msgid "log entries" +msgstr "日志" + +#: .\models.py:175 +#, python-format +msgid "Added \"%(object)s\"." +msgstr "添加 \"%(object)s\"。" + +#: .\models.py:177 +#, python-format +msgid "Changed \"%(object)s\" - %(changes)s" +msgstr "修改 \"%(object)s\" - %(changes)s" + +#: .\models.py:182 +#, python-format +msgid "Deleted \"%(object)s.\"" +msgstr "删除 \"%(object)s.\"" + +#: .\plugins\actions.py:58 +#, python-format +msgid "Delete selected %(verbose_name_plural)s" +msgstr "删除所选的 %(verbose_name_plural)s" + +#: .\plugins\actions.py:73 +#, python-format +msgid "Batch delete %(count)d %(items)s." +msgstr "批量删除 %(count)d 个 %(items)s" + +#: .\plugins\actions.py:79 +#, python-format +msgid "Successfully deleted %(count)d %(items)s." +msgstr "成功删除了 %(count)d 个 %(items)s" + +#: .\plugins\actions.py:111 .\views\delete.py:71 +#, python-format +msgid "Cannot delete %(name)s" +msgstr "无法删除 %(name)s" + +#: .\plugins\actions.py:113 .\views\delete.py:74 +msgid "Are you sure?" +msgstr "你确定吗?" + +#: .\plugins\actions.py:159 +#, python-format +msgid "%(total_count)s selected" +msgid_plural "All %(total_count)s selected" +msgstr[0] "选中了 %(total_count)s 个" + +#: .\plugins\actions.py:163 +#, python-format +msgid "0 of %(cnt)s selected" +msgstr "%(cnt)s 个中 0 个被选" + +#: .\plugins\actions.py:180 .\plugins\actions.py:190 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "条目必须选中以对其进行操作。没有任何条目被更改。" + +#: .\plugins\aggregation.py:14 +msgid "Min" +msgstr "最小" + +#: .\plugins\aggregation.py:14 +msgid "Max" +msgstr "最大" + +#: .\plugins\aggregation.py:14 +msgid "Avg" +msgstr "平均" + +#: .\plugins\aggregation.py:14 +msgid "Sum" +msgstr "总和" + +#: .\plugins\aggregation.py:14 +msgid "Count" +msgstr "总数" + +#: .\plugins\auth.py:25 +#, python-format +msgid "Can add %s" +msgstr "添加:%s" + +#: .\plugins\auth.py:26 +#, python-format +msgid "Can change %s" +msgstr "修改:%s" + +#: .\plugins\auth.py:27 +#, python-format +msgid "Can edit %s" +msgstr "编辑:%s" + +#: .\plugins\auth.py:28 +#, python-format +msgid "Can delete %s" +msgstr "删除:%s" + +#: .\plugins\auth.py:29 +#, python-format +msgid "Can view %s" +msgstr "查看:%s" + +#: .\plugins\auth.py:91 +msgid "Personal info" +msgstr "个人信息" + +#: .\plugins\auth.py:95 +msgid "Permissions" +msgstr "权限" + +#: .\plugins\auth.py:98 +msgid "Important dates" +msgstr "重要日期" + +#: .\plugins\auth.py:103 +msgid "Status" +msgstr "状态" + +#: .\plugins\auth.py:115 +msgid "Permission Name" +msgstr "权限" + +#: .\plugins\auth.py:171 +msgid "Change Password" +msgstr "更改密码" + +#: .\plugins\auth.py:202 +#, python-format +msgid "Change password: %s" +msgstr "更改密码:%s" + +#: .\plugins\auth.py:227 .\plugins\auth.py:259 +msgid "Password changed successfully." +msgstr "密码更改成功" + +#: .\plugins\auth.py:246 .\templates\xadmin\auth\user\change_password.html:11 +#: .\templates\xadmin\auth\user\change_password.html:22 +#: .\templates\xadmin\auth\user\change_password.html:55 +msgid "Change password" +msgstr "修改密码" + +#: .\plugins\batch.py:44 +msgid "Change this field" +msgstr "修改该字段" + +#: .\plugins\batch.py:65 +#, python-format +msgid "Batch Change selected %(verbose_name_plural)s" +msgstr "批量修改选择的%(verbose_name_plural)s" + +#: .\plugins\batch.py:89 +#, python-format +msgid "Successfully change %(count)d %(items)s." +msgstr "成功修改了 %(count)d 个 %(items)s" + +#: .\plugins\batch.py:138 +#, python-format +msgid "Batch change %s" +msgstr "批量修改 %s" + +#: .\plugins\bookmark.py:187 +msgid "bookmark" +msgstr "书签" + +#: .\plugins\bookmark.py:190 +msgid "Bookmark Widget, can show user's bookmark list data in widget." +msgstr "书签组件,展示用户书签页内容。" + +#: .\plugins\chart.py:24 +msgid "Show models simple chart." +msgstr "展示简单数据图表" + +#: .\plugins\chart.py:50 +#, python-format +msgid "%s Charts" +msgstr "%s图表" + +#: .\plugins\comments.py:33 +msgid "Metadata" +msgstr "" + +#: .\plugins\comments.py:60 +msgid "flagged" +msgid_plural "flagged" +msgstr[0] "" + +#: .\plugins\comments.py:61 +msgid "Flag selected comments" +msgstr "" + +#: .\plugins\comments.py:66 +msgid "approved" +msgid_plural "approved" +msgstr[0] "" + +#: .\plugins\comments.py:67 +msgid "Approve selected comments" +msgstr "" + +#: .\plugins\comments.py:72 +msgid "removed" +msgid_plural "removed" +msgstr[0] "删除" + +#: .\plugins\comments.py:73 +msgid "Remove selected comments" +msgstr "恢复删除的%(name)s" + +#: .\plugins\comments.py:86 +#, python-format +msgid "1 comment was successfully %(action)s." +msgid_plural "%(count)s comments were successfully %(action)s." +msgstr[0] "" + +#: .\plugins\details.py:52 .\views\list.py:577 +#, python-format +msgid "Details of %s" +msgstr "%s详情" + +#: .\plugins\editable.py:46 +#, python-format +msgid "Enter %s" +msgstr "输入%s" + +#: .\plugins\editable.py:73 .\views\dashboard.py:652 .\views\delete.py:28 +#: .\views\detail.py:145 .\views\edit.py:460 +#, python-format +msgid "%(name)s object with primary key %(key)r does not exist." +msgstr "具有主键 %(key)r 的对象 %(name)s 不存在。" + +#: .\plugins\export.py:100 .\plugins\export.py:137 +msgid "Sheet" +msgstr "表" + +#: .\plugins\filters.py:137 .\plugins\quickfilter.py:143 +#, python-format +msgid "Filtering error: %s" +msgstr "过滤器错误: %s" + +#: .\plugins\images.py:29 +msgid "Previous" +msgstr "上一个" + +#: .\plugins\images.py:29 +msgid "Next" +msgstr "下一个" + +#: .\plugins\images.py:29 +msgid "Slideshow" +msgstr "幻灯片" + +#: .\plugins\images.py:29 +msgid "Download" +msgstr "下载" + +#: .\plugins\images.py:50 +msgid "Change:" +msgstr "修改:" + +#: .\plugins\importexport.py:174 .\plugins\importexport.py:244 +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.import.html:4 +#: .\templates\xadmin\import_export\import.html:6 +#: .\templates\xadmin\import_export\import.html:13 +#, fuzzy +#| msgid "Export" +msgid "Import" +msgstr "导出" + +#: .\plugins\importexport.py:227 +#, python-format +msgid "

Imported file has a wrong encoding: %s

" +msgstr "

导入文件编码错误: %s

" + +#: .\plugins\importexport.py:229 +#, python-format +msgid "

%s encountered while trying to read file: %s

" +msgstr "

%s读取文件是发生错误: %s

" + +#: .\plugins\importexport.py:300 +msgid "Import finished" +msgstr "导入完成" + +#: .\plugins\importexport.py:300 +#: .\templates\xadmin\blocks\comm.top.topnav.html:23 +msgid "Add" +msgstr "增加" + +#: .\plugins\importexport.py:301 +#: .\templates\xadmin\import_export\import.html:109 +msgid "Update" +msgstr "更新" + +#: .\plugins\importexport.py:435 +msgid "You must select an export format." +msgstr "必须选择一种导入格式" + +#: .\plugins\layout.py:16 +msgid "Table" +msgstr "表格" + +#: .\plugins\layout.py:22 +msgid "Thumbnails" +msgstr "图标" + +#: .\plugins\passwords.py:62 +msgid "Forgotten your password or username?" +msgstr "忘记了您的密码或用户名?" + +#: .\plugins\quickform.py:80 +#, python-format +msgid "Create New %s" +msgstr "创建新的 %s" + +#: .\plugins\relate.py:105 +msgid "Related Objects" +msgstr "关联数据" + +#: .\plugins\relfield.py:29 .\plugins\topnav.py:38 +#, python-format +msgid "Search %s" +msgstr "搜索%s" + +#: .\plugins\relfield.py:77 +#, python-format +msgid "Select %s" +msgstr "选择%s" + +#: .\plugins\themes.py:59 +msgid "Default" +msgstr "默认" + +#: .\plugins\themes.py:59 +msgid "Default bootstrap theme" +msgstr "默认Bootstrap主题" + +#: .\plugins\themes.py:60 +msgid "Bootstrap2" +msgstr "Bootstrap2" + +#: .\plugins\themes.py:60 +msgid "Bootstrap 2.x theme" +msgstr "Bootstrap2主题" + +#: .\plugins\topnav.py:62 .\views\dashboard.py:468 .\views\edit.py:393 +#: .\views\edit.py:402 +#, python-format +msgid "Add %s" +msgstr "增加 %s" + +#: .\plugins\xversion.py:107 +msgid "Initial version." +msgstr "初始化版本" + +#: .\plugins\xversion.py:109 +msgid "Change version." +msgstr "修改版本" + +#: .\plugins\xversion.py:111 +msgid "Revert version." +msgstr "还原版本" + +#: .\plugins\xversion.py:113 +msgid "Rercover version." +msgstr "恢复版本" + +#: .\plugins\xversion.py:115 +#, python-format +msgid "Deleted %(verbose_name)s." +msgstr "删除%(verbose_name)s。" + +#: .\plugins\xversion.py:128 .\templates\xadmin\views\recover_form.html:26 +msgid "Recover" +msgstr "还原" + +#: .\plugins\xversion.py:144 .\templates\xadmin\views\model_history.html:11 +#: .\templates\xadmin\views\revision_diff.html:11 +#: .\templates\xadmin\views\revision_form.html:15 +msgid "History" +msgstr "历史" + +#: .\plugins\xversion.py:195 .\templates\xadmin\views\recover_form.html:14 +#: .\templates\xadmin\views\recover_list.html:10 +#, python-format +msgid "Recover deleted %(name)s" +msgstr "恢复删除的%(name)s" + +#: .\plugins\xversion.py:239 +#, python-format +msgid "Change history: %s" +msgstr "变更历史: %s" + +#: .\plugins\xversion.py:289 +msgid "Must select two versions." +msgstr "必须选择两个版本。" + +#: .\plugins\xversion.py:297 +msgid "Please select two different versions." +msgstr "请选择两个不同的版本。" + +#: .\plugins\xversion.py:384 .\plugins\xversion.py:501 +#, python-format +msgid "Current: %s" +msgstr "当前:%s" + +#: .\plugins\xversion.py:425 +#, python-format +msgid "Revert %s" +msgstr "还原%s" + +#: .\plugins\xversion.py:441 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was reverted successfully. You may edit it again " +"below." +msgstr "%(model)s “%(name)s”成功还原,您可以继续编辑。" + +#: .\plugins\xversion.py:462 +#, python-format +msgid "Recover %s" +msgstr "恢复%s" + +#: .\plugins\xversion.py:478 +#, python-format +msgid "" +"The %(model)s \"%(name)s\" was recovered successfully. You may edit it again " +"below." +msgstr "%(model)s “%(name)s”成功恢复,您可以继续编辑。" + +#: .\templates\xadmin\404.html:4 .\templates\xadmin\404.html:8 +msgid "Page not found" +msgstr "页面没有找到" + +#: .\templates\xadmin\404.html:10 +msgid "We're sorry, but the requested page could not be found." +msgstr "很报歉,请求页面无法找到。" + +#: .\templates\xadmin\500.html:7 +#: .\templates\xadmin\auth\user\change_password.html:10 +#: .\templates\xadmin\auth\user\change_password.html:15 +#: .\templates\xadmin\base_site.html:53 +#: .\templates\xadmin\import_export\export_action.html:13 +#: .\templates\xadmin\import_export\import.html:11 +#: .\templates\xadmin\includes\sitemenu_default.html:7 +#: .\templates\xadmin\views\app_index.html:9 +#: .\templates\xadmin\views\batch_change_form.html:9 +#: .\templates\xadmin\views\invalid_setup.html:7 +#: .\templates\xadmin\views\model_dashboard.html:7 +#: .\templates\xadmin\views\model_delete_selected_confirm.html:8 +#: .\templates\xadmin\views\model_history.html:8 +#: .\templates\xadmin\views\recover_form.html:8 +#: .\templates\xadmin\views\recover_list.html:8 +#: .\templates\xadmin\views\revision_diff.html:8 +#: .\templates\xadmin\views\revision_form.html:8 .\views\base.py:478 +msgid "Home" +msgstr "首页" + +#: .\templates\xadmin\500.html:8 +msgid "Server error" +msgstr "服务器错误" + +#: .\templates\xadmin\500.html:12 +msgid "Server error (500)" +msgstr "服务器错误(500)" + +#: .\templates\xadmin\500.html:15 +msgid "Server Error (500)" +msgstr "服务器错误 (500)" + +#: .\templates\xadmin\500.html:16 +msgid "" +"There's been an error. It's been reported to the site administrators via e-" +"mail and should be fixed shortly. Thanks for your patience." +msgstr "" +"发生了一个错误。系统已将错误通过电子邮件报告给了站点管理员,相信问题应该会很" +"快得到解决。感谢您的耐心。" + +#: .\templates\xadmin\auth\password_reset\complete.html:11 +#: .\templates\xadmin\auth\password_reset\done.html:11 +msgid "Password reset successful" +msgstr "密码重设成功" + +#: .\templates\xadmin\auth\password_reset\complete.html:14 +msgid "Your password has been set. You may go ahead and log in now." +msgstr "你的口令己经设置。现在你可以继续进行登录。" + +#: .\templates\xadmin\auth\password_reset\complete.html:15 +msgid "Log in" +msgstr "登录" + +#: .\templates\xadmin\auth\password_reset\confirm.html:12 +msgid "Enter new password" +msgstr "输入新密码" + +#: .\templates\xadmin\auth\password_reset\confirm.html:17 +msgid "" +"Please enter your new password twice so we can verify you typed it in " +"correctly." +msgstr "请输入两遍新密码,以便我们校验你输入的是否正确。" + +#: .\templates\xadmin\auth\password_reset\confirm.html:19 +msgid "Change my password" +msgstr "修改我的密码" + +#: .\templates\xadmin\auth\password_reset\confirm.html:24 +msgid "Password reset unsuccessful" +msgstr "密码重设失败" + +#: .\templates\xadmin\auth\password_reset\confirm.html:27 +msgid "" +"The password reset link was invalid, possibly because it has already been " +"used. Please request a new password reset." +msgstr "密码重置链接无效,可能是因为它已使用。可以请求一次新的密码重置。" + +#: .\templates\xadmin\auth\password_reset\done.html:14 +msgid "" +"We've e-mailed you instructions for setting your password to the e-mail " +"address you submitted. You should be receiving it shortly." +msgstr "" +"我们已经按你所提交的电子邮箱地址发送了密码设置说明。你应该很快就能收到这封邮" +"件。" + +#: .\templates\xadmin\auth\password_reset\email.html:2 +#, python-format +msgid "" +"You're receiving this e-mail because you requested a password reset for your " +"user account at %(site_name)s." +msgstr "因为你要求重置 %(site_name)s 上的账户密码, 所以收到了这封邮件." + +#: .\templates\xadmin\auth\password_reset\email.html:4 +msgid "Please go to the following page and choose a new password:" +msgstr "请访问该页面并选择一个新密码:" + +#: .\templates\xadmin\auth\password_reset\email.html:8 +msgid "Your username, in case you've forgotten:" +msgstr "你的用户名,如果已忘记的话:" + +#: .\templates\xadmin\auth\password_reset\email.html:10 +msgid "Thanks for using our site!" +msgstr "感谢使用我们的站点!" + +#: .\templates\xadmin\auth\password_reset\email.html:12 +#, python-format +msgid "The %(site_name)s team" +msgstr "%(site_name)s 团队" + +#: .\templates\xadmin\auth\password_reset\form.html:13 +msgid "Password reset" +msgstr "密码重设" + +#: .\templates\xadmin\auth\password_reset\form.html:17 +msgid "" +"Forgotten your password? Enter your e-mail address below, and we'll e-mail " +"instructions for setting a new one." +msgstr "" +"忘记了你的密码?请在下面输入你的 e-mail 地址,我们将把新密码设置说明通过邮件" +"发送给你。" + +#: .\templates\xadmin\auth\password_reset\form.html:25 +msgid "E-mail address:" +msgstr "E-mail 地址:" + +#: .\templates\xadmin\auth\password_reset\form.html:33 +msgid "Reset my password" +msgstr "重设我的密码" + +#: .\templates\xadmin\auth\user\add_form.html:6 +msgid "" +"First, enter a username and password. Then, you'll be able to edit more user " +"options." +msgstr "首先,输入一个用户名和密码。然后,你就可以编辑更多的用户选项。" + +#: .\templates\xadmin\auth\user\add_form.html:8 +msgid "Enter a username and password." +msgstr "输入用户名和" + +#: .\templates\xadmin\auth\user\change_password.html:31 +#: .\templates\xadmin\views\batch_change_form.html:24 +#: .\templates\xadmin\views\form.html:18 +#: .\templates\xadmin\views\model_form.html:20 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "请修正下面的错误。" + +#: .\templates\xadmin\auth\user\change_password.html:38 +msgid "Enter your new password." +msgstr "输入你的新密码" + +#: .\templates\xadmin\auth\user\change_password.html:40 +#, python-format +msgid "Enter a new password for the user %(username)s." +msgstr "为用户 %(username)s 输入一个新的密码。" + +#: .\templates\xadmin\base_site.html:18 +msgid "Welcome," +msgstr "欢迎," + +#: .\templates\xadmin\base_site.html:24 +msgid "Log out" +msgstr "注销" + +#: .\templates\xadmin\base_site.html:36 +msgid "You don't have permission to edit anything." +msgstr "你无权修改任何东西。" + +#: .\templates\xadmin\blocks\comm.top.theme.html:4 +msgid "Themes" +msgstr "主题" + +#: .\templates\xadmin\blocks\comm.top.topnav.html:9 +#: .\templates\xadmin\blocks\model_list.nav_form.search_form.html:8 +#: .\templates\xadmin\filters\char.html:7 +#: .\templates\xadmin\filters\fk_search.html:7 +#: .\templates\xadmin\filters\fk_search.html:16 +#: .\templates\xadmin\filters\number.html:7 +msgid "Search" +msgstr "搜索" + +#: .\templates\xadmin\blocks\model_form.submit_line.wizard.html:9 +#: .\templates\xadmin\blocks\model_form.submit_line.wizard.html:26 +msgid "Prev step" +msgstr "上一步" + +#: .\templates\xadmin\blocks\model_form.submit_line.wizard.html:13 +#: .\templates\xadmin\blocks\model_form.submit_line.wizard.html:29 +msgid "Next step" +msgstr "下一步" + +#: .\templates\xadmin\blocks\model_form.submit_line.wizard.html:15 +#: .\templates\xadmin\blocks\model_form.submit_line.wizard.html:31 +#: .\templates\xadmin\includes\submit_line.html:10 +#: .\templates\xadmin\includes\submit_line.html:13 +#: .\templates\xadmin\views\form.html:30 .\templates\xadmin\views\form.html:31 +msgid "Save" +msgstr "保存" + +#: .\templates\xadmin\blocks\model_list.nav_menu.bookmarks.html:7 +msgid "Clean Bookmarks" +msgstr "清除书签" + +#: .\templates\xadmin\blocks\model_list.nav_menu.bookmarks.html:18 +msgid "No Bookmarks" +msgstr "没有书签" + +#: .\templates\xadmin\blocks\model_list.nav_menu.bookmarks.html:22 +msgid "New Bookmark" +msgstr "新建书签" + +#: .\templates\xadmin\blocks\model_list.nav_menu.bookmarks.html:26 +msgid "Save current page as Bookmark" +msgstr "将当前页面保存为书签" + +#: .\templates\xadmin\blocks\model_list.nav_menu.bookmarks.html:32 +msgid "Enter bookmark title" +msgstr "输入书签标题" + +#: .\templates\xadmin\blocks\model_list.nav_menu.bookmarks.html:33 +msgid "Waiting" +msgstr "请稍侯" + +#: .\templates\xadmin\blocks\model_list.nav_menu.bookmarks.html:33 +msgid "Save Bookmark" +msgstr "保存书签" + +#: .\templates\xadmin\blocks\model_list.nav_menu.filters.html:4 +msgid "Filters" +msgstr "过滤器" + +#: .\templates\xadmin\blocks\model_list.nav_menu.filters.html:8 +msgid "Clean Filters" +msgstr "清除过滤器" + +#: .\templates\xadmin\blocks\model_list.results_bottom.actions.html:19 +msgid "Click here to select the objects across all pages" +msgstr "点击此处选择所有页面中包含的对象。" + +#: .\templates\xadmin\blocks\model_list.results_bottom.actions.html:19 +#, python-format +msgid "Select all %(total_count)s %(model_name)s" +msgstr "选中所有的 %(total_count)s 个 %(model_name)s" + +#: .\templates\xadmin\blocks\model_list.results_bottom.actions.html:20 +msgid "Clear selection" +msgstr "清除选中" + +#: .\templates\xadmin\blocks\model_list.results_top.charts.html:4 +msgid "Charts" +msgstr "图表" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:4 +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:8 +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:19 +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:47 +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:4 +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:12 +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:41 +#: .\templates\xadmin\import_export\export_action.html:7 +#: .\templates\xadmin\import_export\export_action.html:15 +msgid "Export" +msgstr "导出" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:26 +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:29 +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:32 +msgid "Export with table header." +msgstr "导出表头" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:35 +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:38 +msgid "Export with format." +msgstr "导出格式" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:42 +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:35 +msgid "Export all data." +msgstr "导出全部数据" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.exports.html:46 +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:39 +#: .\templates\xadmin\widgets\base.html:41 +msgid "Close" +msgstr "关闭" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:33 +msgid "Export current page data." +msgstr "导出当前页数据" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:34 +msgid "Export selected data." +msgstr "导出所选择数据" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.importexport.export.html:36 +msgid "Export header only." +msgstr "仅导出表头" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.layouts.html:4 +msgid "Layout" +msgstr "布局" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.refresh.html:8 +msgid "Clean Refresh" +msgstr "清除自动刷新" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.refresh.html:14 +#, python-format +msgid "Every %(t)s seconds" +msgstr "每 %(t)s 秒" + +#: .\templates\xadmin\blocks\model_list.top_toolbar.saveorder.html:4 +msgid "Save Order" +msgstr "保存排序" + +#: .\templates\xadmin\edit_inline\blank.html:5 .\views\detail.py:25 +#: .\views\edit.py:104 .\views\list.py:31 +msgid "Null" +msgstr "空" + +#: .\templates\xadmin\filters\char.html:13 +msgid "Enter" +msgstr "输入" + +#: .\templates\xadmin\filters\date.html:10 +#: .\templates\xadmin\filters\date.html:13 +msgid "Choice Date" +msgstr "选择日期" + +#: .\templates\xadmin\filters\date.html:18 +msgid "YY" +msgstr "年" + +#: .\templates\xadmin\filters\date.html:19 +msgid "year" +msgstr "年" + +#: .\templates\xadmin\filters\date.html:22 +msgid "MM" +msgstr "月" + +#: .\templates\xadmin\filters\date.html:23 +msgid "month" +msgstr "月" + +#: .\templates\xadmin\filters\date.html:26 +msgid "DD" +msgstr "日" + +#: .\templates\xadmin\filters\date.html:27 +msgid "day" +msgstr "日" + +#: .\templates\xadmin\filters\date.html:29 +#: .\templates\xadmin\filters\date.html:46 +#: .\templates\xadmin\filters\date.html:54 +#: .\templates\xadmin\filters\fk_search.html:24 +#: .\templates\xadmin\filters\number.html:37 +msgid "Apply" +msgstr "应用" + +#: .\templates\xadmin\filters\date.html:34 +msgid "Date Range" +msgstr "日期范围" + +#: .\templates\xadmin\filters\date.html:41 +msgid "Select Date" +msgstr "选择日期" + +#: .\templates\xadmin\filters\date.html:42 +msgid "From" +msgstr "从" + +#: .\templates\xadmin\filters\date.html:44 +msgid "To" +msgstr "到" + +#: .\templates\xadmin\filters\fk_search.html:14 +msgid "Select" +msgstr "选择" + +#: .\templates\xadmin\filters\fk_search.html:26 +#: .\templates\xadmin\filters\number.html:39 +msgid "Clean" +msgstr "清除" + +#: .\templates\xadmin\filters\number.html:17 +#: .\templates\xadmin\filters\number.html:25 +#: .\templates\xadmin\filters\number.html:33 +msgid "Enter Number" +msgstr "输入数字" + +#: .\templates\xadmin\filters\rel.html:3 +#, python-format +msgid " By %(filter_title)s " +msgstr " 以 %(filter_title)s" + +#: .\templates\xadmin\forms\transfer.html:4 +msgid "Available" +msgstr "可用项" + +#: .\templates\xadmin\forms\transfer.html:12 +msgid "Click to choose all at once." +msgstr "点击一次性选择全部" + +#: .\templates\xadmin\forms\transfer.html:12 +msgid "Choose all" +msgstr "选择全部" + +#: .\templates\xadmin\forms\transfer.html:16 +msgid "Choose" +msgstr "选择" + +#: .\templates\xadmin\forms\transfer.html:19 +#: .\templates\xadmin\widgets\base.html:40 +msgid "Remove" +msgstr "删除" + +#: .\templates\xadmin\forms\transfer.html:23 +msgid "Chosen" +msgstr "已选项" + +#: .\templates\xadmin\forms\transfer.html:27 +msgid "Click to remove all chosen at once." +msgstr "点击一次性删除全部" + +#: .\templates\xadmin\forms\transfer.html:27 +msgid "Remove all" +msgstr "删除全部" + +#: .\templates\xadmin\import_export\export_action.html:43 +#: .\templates\xadmin\import_export\import.html:59 +msgid "Submit" +msgstr "" + +#: .\templates\xadmin\import_export\import.html:26 +msgid "" +"Below is a preview of data to be imported. If you are satisfied with the " +"results, click 'Confirm import'" +msgstr "" + +#: .\templates\xadmin\import_export\import.html:29 +msgid "Confirm import" +msgstr "" + +#: .\templates\xadmin\import_export\import.html:38 +msgid "This importer will import the following fields: " +msgstr "" + +#: .\templates\xadmin\import_export\import.html:67 +msgid "Errors" +msgstr "" + +#: .\templates\xadmin\import_export\import.html:78 +#, fuzzy +#| msgid "Enter Number" +msgid "Line number" +msgstr "输入数字" + +#: .\templates\xadmin\import_export\import.html:88 +#, fuzzy +#| msgid "Previous" +msgid "Preview" +msgstr "上一个" + +#: .\templates\xadmin\import_export\import.html:103 +#, fuzzy +#| msgid "Now" +msgid "New" +msgstr "现在" + +#: .\templates\xadmin\import_export\import.html:105 +msgid "Skipped" +msgstr "" + +#: .\templates\xadmin\import_export\import.html:107 +#: .\templates\xadmin\includes\submit_line.html:24 +#: .\templates\xadmin\views\model_detail.html:28 .\views\delete.py:94 +msgid "Delete" +msgstr "删除" + +#: .\templates\xadmin\includes\pagination.html:9 +msgid "Show all" +msgstr "显示全部" + +#: .\templates\xadmin\includes\submit_line.html:10 +#: .\templates\xadmin\includes\submit_line.html:13 +#: .\templates\xadmin\views\form.html:30 .\templates\xadmin\views\form.html:31 +msgid "Saving.." +msgstr "保存中.." + +#: .\templates\xadmin\includes\submit_line.html:17 +msgid "Save as new" +msgstr "保存为新的" + +#: .\templates\xadmin\includes\submit_line.html:18 +msgid "Save and add another" +msgstr "保存并增加另一个" + +#: .\templates\xadmin\includes\submit_line.html:19 +msgid "Save and continue editing" +msgstr "保存并继续编辑" + +#: .\templates\xadmin\views\app_index.html:13 +#, python-format +msgid "%(name)s" +msgstr "%(name)s" + +#: .\templates\xadmin\views\batch_change_form.html:11 +msgid "Change multiple objects" +msgstr "修改多个数据" + +#: .\templates\xadmin\views\batch_change_form.html:16 +#, python-format +msgid "Change one %(objects_name)s" +msgid_plural "Batch change %(counter)s %(objects_name)s" +msgstr[0] "批量修改 %(counter)s 个 %(objects_name)s" + +#: .\templates\xadmin\views\batch_change_form.html:38 +msgid "Change Multiple" +msgstr "修改多个数据" + +#: .\templates\xadmin\views\dashboard.html:15 +#: .\templates\xadmin\views\dashboard.html:22 +#: .\templates\xadmin\views\dashboard.html:23 +msgid "Add Widget" +msgstr "添加小组件" + +#: .\templates\xadmin\views\invalid_setup.html:13 +msgid "" +"Something's wrong with your database installation. Make sure the appropriate " +"database tables have been created, and make sure the database is readable by " +"the appropriate user." +msgstr "" +"你的数据库安装有误。确保已经创建了相应的数据库表,并确保数据库可被相关的用户" +"读取。" + +#: .\templates\xadmin\views\logged_out.html:16 +msgid "Logout Success" +msgstr "成功退出" + +#: .\templates\xadmin\views\logged_out.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "感谢您今天在本站花费了一些宝贵时间。" + +#: .\templates\xadmin\views\logged_out.html:19 +msgid "Close Window" +msgstr "关闭窗口" + +#: .\templates\xadmin\views\logged_out.html:20 +msgid "Log in again" +msgstr "重新登录" + +#: .\templates\xadmin\views\login.html:39 .\views\website.py:39 +msgid "Please Login" +msgstr "请登录" + +#: .\templates\xadmin\views\login.html:52 +msgid "Username" +msgstr "用户名" + +#: .\templates\xadmin\views\login.html:64 +msgid "Password" +msgstr "密码" + +#: .\templates\xadmin\views\login.html:75 +msgid "log in" +msgstr "登录" + +#: .\templates\xadmin\views\model_dashboard.html:26 +#: .\templates\xadmin\views\model_detail.html:25 +msgid "Edit" +msgstr "编辑" + +#: .\templates\xadmin\views\model_delete_confirm.html:11 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would result in deleting " +"related objects, but your account doesn't have permission to delete the " +"following types of objects:" +msgstr "" +"要删除所选的%(verbose_name)s '%(escaped_object)s' 结果会删除相关对象, 但你的" +"账户没有权限删除这类对象:" + +#: .\templates\xadmin\views\model_delete_confirm.html:19 +#, python-format +msgid "" +"Deleting the %(verbose_name)s '%(escaped_object)s' would require deleting " +"the following protected related objects:" +msgstr "" +"要删除所选的%(verbose_name)s '%(escaped_object)s' 将要求删除以下受保护的相关" +"对象:" + +#: .\templates\xadmin\views\model_delete_confirm.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the %(verbose_name)s \"%(escaped_object)s\"? " +"All of the following related items will be deleted:" +msgstr "" +"请确认要删除选中的%(verbose_name)s \"%(escaped_object)s\"吗?以下所有对象和余" +"它们相关的条目将都会被删除:" + +#: .\templates\xadmin\views\model_delete_confirm.html:34 +#: .\templates\xadmin\views\model_delete_selected_confirm.html:49 +msgid "Yes, I'm sure" +msgstr "是的,我确定" + +#: .\templates\xadmin\views\model_delete_confirm.html:35 +#: .\templates\xadmin\views\model_delete_selected_confirm.html:50 +msgid "Cancel" +msgstr "取消" + +#: .\templates\xadmin\views\model_delete_selected_confirm.html:10 +msgid "Delete multiple objects" +msgstr "删除多个对象" + +#: .\templates\xadmin\views\model_delete_selected_confirm.html:18 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would result in deleting related " +"objects, but your account doesn't have permission to delete the following " +"types of objects:" +msgstr "" +"要删除所选的 %(objects_name)s 结果会删除相关对象, 但你的账户没有权限删除这类" +"对象:" + +#: .\templates\xadmin\views\model_delete_selected_confirm.html:26 +#, python-format +msgid "" +"Deleting the selected %(objects_name)s would require deleting the following " +"protected related objects:" +msgstr "要删除所选的 %(objects_name)s, 将要求删除以下受保护的相关对象:" + +#: .\templates\xadmin\views\model_delete_selected_confirm.html:34 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following objects and their related items will be deleted:" +msgstr "" +"请确认要删除选中的 %(objects_name)s 吗?以下所有对象和余它们相关的条目将都会" +"被删除:" + +#: .\templates\xadmin\views\model_history.html:26 +msgid "Diff" +msgstr "不同" + +#: .\templates\xadmin\views\model_history.html:27 +#: .\templates\xadmin\views\recover_list.html:25 +msgid "Date/time" +msgstr "日期/时间" + +#: .\templates\xadmin\views\model_history.html:28 +msgid "User" +msgstr "用户" + +#: .\templates\xadmin\views\model_history.html:29 +msgid "Comment" +msgstr "注释" + +#: .\templates\xadmin\views\model_history.html:54 +msgid "Diff Select Versions" +msgstr "查看所选版本的不同" + +#: .\templates\xadmin\views\model_history.html:58 +msgid "" +"This object doesn't have a change history. It probably wasn't added via this " +"admin site." +msgstr "该对象没有变更历史记录。可能从未通过这个管理站点添加。" + +#: .\templates\xadmin\views\model_list.html:29 +#, python-format +msgid "Add %(name)s" +msgstr "增加 %(name)s" + +#: .\templates\xadmin\views\model_list.html:39 +msgid "Columns" +msgstr "显示列" + +#: .\templates\xadmin\views\model_list.html:42 +msgid "Restore Selected" +msgstr "恢复显示列" + +#: .\templates\xadmin\views\model_list.html:147 +#: .\templates\xadmin\widgets\list.html:33 +msgid "Empty list" +msgstr "空列表" + +#: .\templates\xadmin\views\recover_form.html:20 +msgid "Press the recover button below to recover this version of the object." +msgstr "点击下方的“还原”按钮还原到该版本。" + +#: .\templates\xadmin\views\recover_list.html:19 +msgid "" +"Choose a date from the list below to recover a deleted version of an object." +msgstr "从以下列表中选择一个日期来恢复删除掉的数据。" + +#: .\templates\xadmin\views\recover_list.html:39 +msgid "There are no deleted objects to recover." +msgstr "没有已删除的数据。" + +#: .\templates\xadmin\views\revision_diff.html:12 +#: .\templates\xadmin\views\revision_diff.html:17 +#, python-format +msgid "Diff %(verbose_name)s" +msgstr "%(verbose_name)s的不同" + +#: .\templates\xadmin\views\revision_diff.html:25 +msgid "Field" +msgstr "字段" + +#: .\templates\xadmin\views\revision_diff.html:26 +msgid "Version A" +msgstr "版本A" + +#: .\templates\xadmin\views\revision_diff.html:27 +msgid "Version B" +msgstr "版本B" + +#: .\templates\xadmin\views\revision_diff.html:39 +msgid "Revert to" +msgstr "还原到" + +#: .\templates\xadmin\views\revision_diff.html:40 +#: .\templates\xadmin\views\revision_diff.html:41 +msgid "Revert" +msgstr "还原" + +#: .\templates\xadmin\views\revision_form.html:16 +#, python-format +msgid "Revert %(verbose_name)s" +msgstr "还原%(verbose_name)s" + +#: .\templates\xadmin\views\revision_form.html:21 +msgid "Press the revert button below to revert to this version of the object." +msgstr "点击下方的“还原”按钮还原数据到该版本。" + +#: .\templates\xadmin\views\revision_form.html:27 +msgid "Revert this revision" +msgstr "还原该版本" + +#: .\templates\xadmin\widgets\addform.html:14 +msgid "Success" +msgstr "成功" + +#: .\templates\xadmin\widgets\addform.html:14 +msgid "Add success, click edit to edit." +msgstr "添加成功,点击 编辑 可以继续修改该数据。" + +#: .\templates\xadmin\widgets\addform.html:17 +msgid "Quick Add" +msgstr "快速添加" + +#: .\templates\xadmin\widgets\base.html:31 +msgid "Widget Options" +msgstr "小组件设置项" + +#: .\templates\xadmin\widgets\base.html:42 +msgid "Save changes" +msgstr "保存变更" + +#: .\views\base.py:320 +msgid "Django Xadmin" +msgstr "Django Xadmin" + +#: .\views\base.py:321 +msgid "my-company.inc" +msgstr "我的公司" + +#: .\views\dashboard.py:189 +msgid "Widget ID" +msgstr "小组件ID" + +#: .\views\dashboard.py:190 +msgid "Widget Title" +msgstr "小组件标题" + +#: .\views\dashboard.py:255 +msgid "Html Content Widget, can write any html content in widget." +msgstr "HTML内容小组件,可以编写任意HTML内容。" + +#: .\views\dashboard.py:258 +msgid "Html Content" +msgstr "HTML内容" + +#: .\views\dashboard.py:321 +msgid "Target Model" +msgstr "目标数据" + +#: .\views\dashboard.py:372 +msgid "Quick button Widget, quickly open any page." +msgstr "快捷按钮小组件,可以快速打开任意页面。" + +#: .\views\dashboard.py:374 +msgid "Quick Buttons" +msgstr "快速按钮" + +#: .\views\dashboard.py:419 +msgid "Any Objects list Widget." +msgstr "数据列表小组件" + +#: .\views\dashboard.py:459 +msgid "Add any model object Widget." +msgstr "添加任意数据的小组件" + +#: .\views\dashboard.py:495 +msgid "Dashboard" +msgstr "仪表盘" + +#: .\views\dashboard.py:636 +#, python-format +msgid "%s Dashboard" +msgstr "%s 主页" + +#: .\views\delete.py:104 +#, python-format +msgid "The %(name)s \"%(obj)s\" was deleted successfully." +msgstr "%(name)s \"%(obj)s\" 删除成功。" + +#: .\views\detail.py:173 .\views\edit.py:216 .\views\form.py:74 +msgid "Other Fields" +msgstr "其它字段" + +#: .\views\detail.py:235 +#, python-format +msgid "%s Detail" +msgstr "%s详情" + +#: .\views\edit.py:258 +msgid "Added." +msgstr "已添加" + +#: .\views\edit.py:260 +#, python-format +msgid "Changed %s." +msgstr "修改 %s" + +#: .\views\edit.py:260 +msgid "and" +msgstr "和" + +#: .\views\edit.py:263 +msgid "No fields changed." +msgstr "没有数据变化" + +#: .\views\edit.py:426 +#, python-format +msgid "The %(name)s \"%(obj)s\" was added successfully." +msgstr "%(name)s \"%(obj)s\" 添加成功。" + +#: .\views\edit.py:431 .\views\edit.py:526 +msgid "You may edit it again below." +msgstr "你可以在下面再次编辑它。" + +#: .\views\edit.py:435 .\views\edit.py:529 +#, python-format +msgid "You may add another %s below." +msgstr "你可以在下面增加另一个 %s 。" + +#: .\views\edit.py:477 +#, python-format +msgid "Change %s" +msgstr "修改 %s" + +#: .\views\edit.py:522 +#, python-format +msgid "The %(name)s \"%(obj)s\" was changed successfully." +msgstr "%(name)s \"%(obj)s\" 修改成功。" + +#: .\views\form.py:168 +#, python-format +msgid "The %s was changed successfully." +msgstr "%s 修改成功。" + +#: .\views\list.py:192 +msgid "Database error" +msgstr "数据库错误" + +#: .\views\list.py:369 +#, python-format +msgid "%s List" +msgstr "%s列表" + +#: .\views\list.py:498 +msgid "Sort ASC" +msgstr "正序" + +#: .\views\list.py:499 +msgid "Sort DESC" +msgstr "倒序" + +#: .\views\list.py:503 +msgid "Cancel Sort" +msgstr "取消排序" + +#: .\views\website.py:17 +msgid "Main Dashboard" +msgstr "主页面" + +#: .\widgets.py:53 .\widgets.py:81 +msgid "Now" +msgstr "现在" diff --git a/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/djangojs.mo b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/djangojs.mo new file mode 100644 index 0000000..dea0231 Binary files /dev/null and b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/djangojs.mo differ diff --git a/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/djangojs.po b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/djangojs.po new file mode 100644 index 0000000..65fb767 --- /dev/null +++ b/extra_apps/xadmin/locale/zh_Hans/LC_MESSAGES/djangojs.po @@ -0,0 +1,87 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Translators: +# sshwsfc , 2013 +msgid "" +msgstr "" +"Project-Id-Version: xadmin-core\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-05-22 16:02+0800\n" +"PO-Revision-Date: 2013-11-20 12:41+0000\n" +"Last-Translator: sshwsfc \n" +"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/xadmin/language/zh_CN/)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: static/xadmin/js/xadmin.page.dashboard.js:14 +#: static/xadmin/js/xadmin.plugin.details.js:24 +#: static/xadmin/js/xadmin.plugin.quick-form.js:172 +msgid "Close" +msgstr "关闭" + +#: static/xadmin/js/xadmin.page.dashboard.js:15 +msgid "Save changes" +msgstr "保存修改" + +#: static/xadmin/js/xadmin.plugin.actions.js:11 +msgid "%(sel)s of %(cnt)s selected" +msgid_plural "%(sel)s of %(cnt)s selected" +msgstr[0] "选中了 %(cnt)s 个中的 %(sel)s 个" +msgstr[1] "选中了 %(cnt)s 个中的 %(sel)s 个" + +#: static/xadmin/js/xadmin.plugin.details.js:25 +msgid "Edit" +msgstr "编辑" + +#: static/xadmin/js/xadmin.plugin.quick-form.js:173 +msgid "Add" +msgstr "添加" + +#: static/xadmin/js/xadmin.plugin.revision.js:25 +msgid "New Item" +msgstr "新项目" + +#: static/xadmin/js/xadmin.widget.datetime.js:32 +msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday" +msgstr "星期日 星期一 星期二 星期三 星期四 星期五 星期六" + +#: static/xadmin/js/xadmin.widget.datetime.js:33 +msgid "Sun Mon Tue Wed Thu Fri Sat Sun" +msgstr "日 一 二 三 四 五 六" + +#: static/xadmin/js/xadmin.widget.datetime.js:34 +msgid "Su Mo Tu We Th Fr Sa Su" +msgstr "日 一 二 三 四 五 六" + +#: static/xadmin/js/xadmin.widget.datetime.js:35 +msgid "January February March April May June July August September October November December" +msgstr "一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月" + +#: static/xadmin/js/xadmin.widget.datetime.js:36 +msgid "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +msgstr "一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一 十二" + +#: static/xadmin/js/xadmin.widget.datetime.js:37 +msgid "Today" +msgstr "今天" + +#: static/xadmin/js/xadmin.widget.datetime.js:38 +msgid "%a %d %b %Y %T %Z" +msgstr "" + +#: static/xadmin/js/xadmin.widget.datetime.js:39 +msgid "AM PM" +msgstr "上午 下午" + +#: static/xadmin/js/xadmin.widget.datetime.js:40 +msgid "am pm" +msgstr "上午 下午" + +#: static/xadmin/js/xadmin.widget.datetime.js:43 +msgid "%T" +msgstr "%T" diff --git a/extra_apps/xadmin/migrations/0001_initial.py b/extra_apps/xadmin/migrations/0001_initial.py new file mode 100644 index 0000000..1eeee38 --- /dev/null +++ b/extra_apps/xadmin/migrations/0001_initial.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.2 on 2016-03-20 13:46 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL) + ] + + operations = [ + migrations.CreateModel( + name='Bookmark', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=128, verbose_name='Title')), + ('url_name', models.CharField(max_length=64, verbose_name='Url Name')), + ('query', models.CharField(blank=True, max_length=1000, verbose_name='Query String')), + ('is_share', models.BooleanField(default=False, verbose_name='Is Shared')), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'verbose_name': 'Bookmark', + 'verbose_name_plural': 'Bookmarks', + }, + ), + migrations.CreateModel( + name='UserSettings', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('key', models.CharField(max_length=256, verbose_name='Settings Key')), + ('value', models.TextField(verbose_name='Settings Content')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'verbose_name': 'User Setting', + 'verbose_name_plural': 'User Settings', + }, + ), + migrations.CreateModel( + name='UserWidget', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('page_id', models.CharField(max_length=256, verbose_name='Page')), + ('widget_type', models.CharField(max_length=50, verbose_name='Widget Type')), + ('value', models.TextField(verbose_name='Widget Params')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'verbose_name': 'User Widget', + 'verbose_name_plural': 'User Widgets', + }, + ), + ] diff --git a/extra_apps/xadmin/migrations/0002_log.py b/extra_apps/xadmin/migrations/0002_log.py new file mode 100644 index 0000000..3153bee --- /dev/null +++ b/extra_apps/xadmin/migrations/0002_log.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-15 05:50 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('xadmin', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Log', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('action_time', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='action time')), + ('ip_addr', models.GenericIPAddressField(blank=True, null=True, verbose_name='action ip')), + ('object_id', models.TextField(blank=True, null=True, verbose_name='object id')), + ('object_repr', models.CharField(max_length=200, verbose_name='object repr')), + ('action_flag', models.PositiveSmallIntegerField(verbose_name='action flag')), + ('message', models.TextField(blank=True, verbose_name='change message')), + ('content_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contenttypes.ContentType', verbose_name='content type')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user')), + ], + options={ + 'ordering': ('-action_time',), + 'verbose_name': 'log entry', + 'verbose_name_plural': 'log entries', + }, + ), + ] diff --git a/extra_apps/xadmin/migrations/0003_auto_20160715_0100.py b/extra_apps/xadmin/migrations/0003_auto_20160715_0100.py new file mode 100644 index 0000000..073f5b4 --- /dev/null +++ b/extra_apps/xadmin/migrations/0003_auto_20160715_0100.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.7 on 2016-07-15 06:00 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('xadmin', '0002_log'), + ] + + operations = [ + migrations.AlterField( + model_name='log', + name='action_flag', + field=models.CharField(max_length=32, verbose_name='action flag'), + ), + ] diff --git a/extra_apps/xadmin/migrations/__init__.py b/extra_apps/xadmin/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extra_apps/xadmin/migrations/__pycache__/0001_initial.cpython-36.pyc b/extra_apps/xadmin/migrations/__pycache__/0001_initial.cpython-36.pyc new file mode 100644 index 0000000..85a8a1b Binary files /dev/null and b/extra_apps/xadmin/migrations/__pycache__/0001_initial.cpython-36.pyc differ diff --git a/extra_apps/xadmin/migrations/__pycache__/0002_log.cpython-36.pyc b/extra_apps/xadmin/migrations/__pycache__/0002_log.cpython-36.pyc new file mode 100644 index 0000000..2b7bf4b Binary files /dev/null and b/extra_apps/xadmin/migrations/__pycache__/0002_log.cpython-36.pyc differ diff --git a/extra_apps/xadmin/migrations/__pycache__/0003_auto_20160715_0100.cpython-36.pyc b/extra_apps/xadmin/migrations/__pycache__/0003_auto_20160715_0100.cpython-36.pyc new file mode 100644 index 0000000..991017a Binary files /dev/null and b/extra_apps/xadmin/migrations/__pycache__/0003_auto_20160715_0100.cpython-36.pyc differ diff --git a/extra_apps/xadmin/migrations/__pycache__/__init__.cpython-36.pyc b/extra_apps/xadmin/migrations/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..4027de1 Binary files /dev/null and b/extra_apps/xadmin/migrations/__pycache__/__init__.cpython-36.pyc differ diff --git a/extra_apps/xadmin/models.py b/extra_apps/xadmin/models.py new file mode 100644 index 0000000..f389fd3 --- /dev/null +++ b/extra_apps/xadmin/models.py @@ -0,0 +1,190 @@ +import json +import django +from django.db import models +from django.utils import timezone +from django.conf import settings +from django.contrib.contenttypes.models import ContentType +from django.utils.translation import ugettext_lazy as _, ugettext +from django.urls.base import reverse +from django.core.serializers.json import DjangoJSONEncoder +from django.db.models.base import ModelBase +from django.utils.encoding import python_2_unicode_compatible, smart_text + +from django.db.models.signals import post_migrate +from django.contrib.auth.models import Permission + +import datetime +import decimal +from xadmin.util import quote + +AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User') + + +def add_view_permissions(sender, **kwargs): + """ + This syncdb hooks takes care of adding a view permission too all our + content types. + """ + # for each of our content types + for content_type in ContentType.objects.all(): + # build our permission slug + codename = "view_%s" % content_type.model + + # if it doesn't exist.. + if not Permission.objects.filter(content_type=content_type, codename=codename): + # add it + Permission.objects.create(content_type=content_type, + codename=codename, + name="Can view %s" % content_type.name) + # print "Added view permission for %s" % content_type.name + +# check for all our view permissions after a syncdb +post_migrate.connect(add_view_permissions) + + +@python_2_unicode_compatible +class Bookmark(models.Model): + title = models.CharField(_(u'Title'), max_length=128) + user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_(u"user"), blank=True, null=True) + url_name = models.CharField(_(u'Url Name'), max_length=64) + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) + query = models.CharField(_(u'Query String'), max_length=1000, blank=True) + is_share = models.BooleanField(_(u'Is Shared'), default=False) + + @property + def url(self): + base_url = reverse(self.url_name) + if self.query: + base_url = base_url + '?' + self.query + return base_url + + def __str__(self): + return self.title + + class Meta: + verbose_name = _(u'Bookmark') + verbose_name_plural = _('Bookmarks') + + +class JSONEncoder(DjangoJSONEncoder): + + def default(self, o): + if isinstance(o, datetime.datetime): + return o.strftime('%Y-%m-%d %H:%M:%S') + elif isinstance(o, datetime.date): + return o.strftime('%Y-%m-%d') + elif isinstance(o, decimal.Decimal): + return str(o) + elif isinstance(o, ModelBase): + return '%s.%s' % (o._meta.app_label, o._meta.model_name) + else: + try: + return super(JSONEncoder, self).default(o) + except Exception: + return smart_text(o) + + +@python_2_unicode_compatible +class UserSettings(models.Model): + user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_(u"user")) + key = models.CharField(_('Settings Key'), max_length=256) + value = models.TextField(_('Settings Content')) + + def json_value(self): + return json.loads(self.value) + + def set_json(self, obj): + self.value = json.dumps(obj, cls=JSONEncoder, ensure_ascii=False) + + def __str__(self): + return "%s %s" % (self.user, self.key) + + class Meta: + verbose_name = _(u'User Setting') + verbose_name_plural = _('User Settings') + + +@python_2_unicode_compatible +class UserWidget(models.Model): + user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_(u"user")) + page_id = models.CharField(_(u"Page"), max_length=256) + widget_type = models.CharField(_(u"Widget Type"), max_length=50) + value = models.TextField(_(u"Widget Params")) + + def get_value(self): + value = json.loads(self.value) + value['id'] = self.id + value['type'] = self.widget_type + return value + + def set_value(self, obj): + self.value = json.dumps(obj, cls=JSONEncoder, ensure_ascii=False) + + def save(self, *args, **kwargs): + created = self.pk is None + super(UserWidget, self).save(*args, **kwargs) + if created: + try: + portal_pos = UserSettings.objects.get( + user=self.user, key="dashboard:%s:pos" % self.page_id) + portal_pos.value = "%s,%s" % (self.pk, portal_pos.value) if portal_pos.value else self.pk + portal_pos.save() + except Exception: + pass + + def __str__(self): + return "%s %s widget" % (self.user, self.widget_type) + + class Meta: + verbose_name = _(u'User Widget') + verbose_name_plural = _('User Widgets') + + +@python_2_unicode_compatible +class Log(models.Model): + action_time = models.DateTimeField( + _('action time'), + default=timezone.now, + editable=False, + ) + user = models.ForeignKey( + AUTH_USER_MODEL, + models.CASCADE, + verbose_name=_('user'), + ) + ip_addr = models.GenericIPAddressField(_('action ip'), blank=True, null=True) + content_type = models.ForeignKey( + ContentType, + models.SET_NULL, + verbose_name=_('content type'), + blank=True, null=True, + ) + object_id = models.TextField(_('object id'), blank=True, null=True) + object_repr = models.CharField(_('object repr'), max_length=200) + action_flag = models.CharField(_('action flag'), max_length=32) + message = models.TextField(_('change message'), blank=True) + + class Meta: + verbose_name = _('log entry') + verbose_name_plural = _('log entries') + ordering = ('-action_time',) + + def __repr__(self): + return smart_text(self.action_time) + + def __str__(self): + if self.action_flag == 'create': + return ugettext('Added "%(object)s".') % {'object': self.object_repr} + elif self.action_flag == 'change': + return ugettext('Changed "%(object)s" - %(changes)s') % { + 'object': self.object_repr, + 'changes': self.message, + } + elif self.action_flag == 'delete' and self.object_repr: + return ugettext('Deleted "%(object)s."') % {'object': self.object_repr} + + return self.message + + def get_edited_object(self): + "Returns the edited object represented by this log entry" + return self.content_type.get_object_for_this_type(pk=self.object_id) diff --git a/extra_apps/xadmin/plugins/__init__.py b/extra_apps/xadmin/plugins/__init__.py new file mode 100644 index 0000000..d061165 --- /dev/null +++ b/extra_apps/xadmin/plugins/__init__.py @@ -0,0 +1,41 @@ + +PLUGINS = ( + 'actions', + 'filters', + 'bookmark', + 'export', + 'layout', + 'refresh', + 'details', + 'editable', + 'relate', + 'chart', + 'ajax', + 'relfield', + 'inline', + 'topnav', + 'portal', + 'quickform', + 'wizard', + 'images', + 'auth', + 'multiselect', + 'themes', + 'aggregation', + # 'mobile', + 'passwords', + 'sitemenu', + 'language', + 'quickfilter', + 'sortablelist', + 'importexport' +) + + +def register_builtin_plugins(site): + from importlib import import_module + from django.conf import settings + + exclude_plugins = getattr(settings, 'XADMIN_EXCLUDE_PLUGINS', []) + + [import_module('xadmin.plugins.%s' % plugin) for plugin in PLUGINS if plugin not in exclude_plugins] diff --git a/extra_apps/xadmin/plugins/__pycache__/__init__.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..e90a5e2 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/__init__.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/actions.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/actions.cpython-36.pyc new file mode 100644 index 0000000..e7edcf5 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/actions.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/aggregation.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/aggregation.cpython-36.pyc new file mode 100644 index 0000000..623cfb9 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/aggregation.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/ajax.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/ajax.cpython-36.pyc new file mode 100644 index 0000000..d407637 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/ajax.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/auth.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/auth.cpython-36.pyc new file mode 100644 index 0000000..9b76405 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/auth.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/bookmark.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/bookmark.cpython-36.pyc new file mode 100644 index 0000000..ba7d7c4 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/bookmark.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/chart.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/chart.cpython-36.pyc new file mode 100644 index 0000000..56d70f7 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/chart.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/details.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/details.cpython-36.pyc new file mode 100644 index 0000000..0fbbfc6 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/details.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/editable.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/editable.cpython-36.pyc new file mode 100644 index 0000000..0a0c4c8 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/editable.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/export.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/export.cpython-36.pyc new file mode 100644 index 0000000..e11a991 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/export.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/filters.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/filters.cpython-36.pyc new file mode 100644 index 0000000..7f5064d Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/filters.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/images.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/images.cpython-36.pyc new file mode 100644 index 0000000..e5af5ee Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/images.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/importexport.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/importexport.cpython-36.pyc new file mode 100644 index 0000000..e3b0228 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/importexport.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/inline.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/inline.cpython-36.pyc new file mode 100644 index 0000000..3b27dba Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/inline.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/language.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/language.cpython-36.pyc new file mode 100644 index 0000000..30b853d Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/language.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/layout.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/layout.cpython-36.pyc new file mode 100644 index 0000000..97f5645 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/layout.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/multiselect.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/multiselect.cpython-36.pyc new file mode 100644 index 0000000..40febfa Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/multiselect.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/passwords.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/passwords.cpython-36.pyc new file mode 100644 index 0000000..4936e40 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/passwords.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/portal.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/portal.cpython-36.pyc new file mode 100644 index 0000000..139b810 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/portal.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/quickfilter.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/quickfilter.cpython-36.pyc new file mode 100644 index 0000000..e5c3896 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/quickfilter.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/quickform.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/quickform.cpython-36.pyc new file mode 100644 index 0000000..4815d01 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/quickform.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/refresh.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/refresh.cpython-36.pyc new file mode 100644 index 0000000..71e9089 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/refresh.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/relate.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/relate.cpython-36.pyc new file mode 100644 index 0000000..47cbf40 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/relate.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/relfield.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/relfield.cpython-36.pyc new file mode 100644 index 0000000..a949c3e Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/relfield.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/sitemenu.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/sitemenu.cpython-36.pyc new file mode 100644 index 0000000..28e9735 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/sitemenu.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/sortablelist.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/sortablelist.cpython-36.pyc new file mode 100644 index 0000000..9f10c38 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/sortablelist.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/themes.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/themes.cpython-36.pyc new file mode 100644 index 0000000..094ff7e Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/themes.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/topnav.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/topnav.cpython-36.pyc new file mode 100644 index 0000000..a420579 Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/topnav.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/utils.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/utils.cpython-36.pyc new file mode 100644 index 0000000..25c399f Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/utils.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/__pycache__/wizard.cpython-36.pyc b/extra_apps/xadmin/plugins/__pycache__/wizard.cpython-36.pyc new file mode 100644 index 0000000..7ab0bab Binary files /dev/null and b/extra_apps/xadmin/plugins/__pycache__/wizard.cpython-36.pyc differ diff --git a/extra_apps/xadmin/plugins/actions.py b/extra_apps/xadmin/plugins/actions.py new file mode 100644 index 0000000..d3c2440 --- /dev/null +++ b/extra_apps/xadmin/plugins/actions.py @@ -0,0 +1,316 @@ +from collections import OrderedDict +from django import forms, VERSION as django_version +from django.core.exceptions import PermissionDenied +from django.db import router +from django.http import HttpResponse, HttpResponseRedirect +from django.template import loader +from django.template.response import TemplateResponse +from django.utils import six +from django.utils.encoding import force_text +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _, ungettext +from django.utils.text import capfirst + +from django.contrib.admin.utils import get_deleted_objects + +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.util import model_format_dict, model_ngettext +from xadmin.views import BaseAdminPlugin, ListAdminView +from xadmin.views.base import filter_hook, ModelAdminView + +from xadmin import views + +ACTION_CHECKBOX_NAME = '_selected_action' +checkbox = forms.CheckboxInput({'class': 'action-select'}, lambda value: False) + + +def action_checkbox(obj): + return checkbox.render(ACTION_CHECKBOX_NAME, force_text(obj.pk)) + + +action_checkbox.short_description = mark_safe( + '') +action_checkbox.allow_tags = True +action_checkbox.allow_export = False +action_checkbox.is_column = False + + +class BaseActionView(ModelAdminView): + action_name = None + description = None + icon = 'fa fa-tasks' + + model_perm = 'change' + + @classmethod + def has_perm(cls, list_view): + return list_view.get_model_perms()[cls.model_perm] + + def init_action(self, list_view): + self.list_view = list_view + self.admin_site = list_view.admin_site + + @filter_hook + def do_action(self, queryset): + pass + + def __init__(self, request, *args, **kwargs): + super().__init__(request, *args, **kwargs) + if django_version > (2, 0): + for model in self.admin_site._registry: + if not hasattr(self.admin_site._registry[model], 'has_delete_permission'): + setattr(self.admin_site._registry[model], 'has_delete_permission', self.has_delete_permission) + + +class DeleteSelectedAction(BaseActionView): + + action_name = "delete_selected" + description = _(u'Delete selected %(verbose_name_plural)s') + + delete_confirmation_template = None + delete_selected_confirmation_template = None + + delete_models_batch = True + + model_perm = 'delete' + icon = 'fa fa-times' + + @filter_hook + def delete_models(self, queryset): + n = queryset.count() + if n: + if self.delete_models_batch: + self.log('delete', _('Batch delete %(count)d %(items)s.') % {"count": n, "items": model_ngettext(self.opts, n)}) + queryset.delete() + else: + for obj in queryset: + self.log('delete', '', obj) + obj.delete() + self.message_user(_("Successfully deleted %(count)d %(items)s.") % { + "count": n, "items": model_ngettext(self.opts, n) + }, 'success') + + @filter_hook + def do_action(self, queryset): + # Check that the user has delete permission for the actual model + if not self.has_delete_permission(): + raise PermissionDenied + + # Populate deletable_objects, a data structure of all related objects that + # will also be deleted. + + if django_version > (2, 1): + deletable_objects, model_count, perms_needed, protected = get_deleted_objects( + queryset, self.opts, self.admin_site) + else: + using = router.db_for_write(self.model) + deletable_objects, model_count, perms_needed, protected = get_deleted_objects( + queryset, self.opts, self.user, self.admin_site, using) + + + # The user has already confirmed the deletion. + # Do the deletion and return a None to display the change list view again. + if self.request.POST.get('post'): + if perms_needed: + raise PermissionDenied + self.delete_models(queryset) + # Return None to display the change list page again. + return None + + if len(queryset) == 1: + objects_name = force_text(self.opts.verbose_name) + else: + objects_name = force_text(self.opts.verbose_name_plural) + + if perms_needed or protected: + title = _("Cannot delete %(name)s") % {"name": objects_name} + else: + title = _("Are you sure?") + + context = self.get_context() + context.update({ + "title": title, + "objects_name": objects_name, + "deletable_objects": [deletable_objects], + 'queryset': queryset, + "perms_lacking": perms_needed, + "protected": protected, + "opts": self.opts, + "app_label": self.app_label, + 'action_checkbox_name': ACTION_CHECKBOX_NAME, + }) + + # Display the confirmation page + return TemplateResponse(self.request, self.delete_selected_confirmation_template or + self.get_template_list('views/model_delete_selected_confirm.html'), context) + + +class ActionPlugin(BaseAdminPlugin): + + # Actions + actions = [] + actions_selection_counter = True + global_actions = [DeleteSelectedAction] + + def init_request(self, *args, **kwargs): + self.actions = self.get_actions() + return bool(self.actions) + + def get_list_display(self, list_display): + if self.actions: + list_display.insert(0, 'action_checkbox') + self.admin_view.action_checkbox = action_checkbox + return list_display + + def get_list_display_links(self, list_display_links): + if self.actions: + if len(list_display_links) == 1 and list_display_links[0] == 'action_checkbox': + return list(self.admin_view.list_display[1:2]) + return list_display_links + + def get_context(self, context): + if self.actions and self.admin_view.result_count: + av = self.admin_view + selection_note_all = ungettext('%(total_count)s selected', + 'All %(total_count)s selected', av.result_count) + + new_context = { + 'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(av.result_list)}, + 'selection_note_all': selection_note_all % {'total_count': av.result_count}, + 'action_choices': self.get_action_choices(), + 'actions_selection_counter': self.actions_selection_counter, + } + context.update(new_context) + return context + + def post_response(self, response, *args, **kwargs): + request = self.admin_view.request + av = self.admin_view + + # Actions with no confirmation + if self.actions and 'action' in request.POST: + action = request.POST['action'] + + if action not in self.actions: + msg = _("Items must be selected in order to perform " + "actions on them. No items have been changed.") + av.message_user(msg) + else: + ac, name, description, icon = self.actions[action] + select_across = request.POST.get('select_across', False) == '1' + selected = request.POST.getlist(ACTION_CHECKBOX_NAME) + + if not selected and not select_across: + # Reminder that something needs to be selected or nothing will happen + msg = _("Items must be selected in order to perform " + "actions on them. No items have been changed.") + av.message_user(msg) + else: + queryset = av.list_queryset._clone() + if not select_across: + # Perform the action only on the selected objects + queryset = av.list_queryset.filter(pk__in=selected) + response = self.response_action(ac, queryset) + # Actions may return an HttpResponse, which will be used as the + # response from the POST. If not, we'll be a good little HTTP + # citizen and redirect back to the changelist page. + if isinstance(response, HttpResponse): + return response + else: + return HttpResponseRedirect(request.get_full_path()) + return response + + def response_action(self, ac, queryset): + if isinstance(ac, type) and issubclass(ac, BaseActionView): + action_view = self.get_model_view(ac, self.admin_view.model) + action_view.init_action(self.admin_view) + return action_view.do_action(queryset) + else: + return ac(self.admin_view, self.request, queryset) + + def get_actions(self): + if self.actions is None: + return OrderedDict() + + actions = [self.get_action(action) for action in self.global_actions] + + for klass in self.admin_view.__class__.mro()[::-1]: + class_actions = getattr(klass, 'actions', []) + if not class_actions: + continue + actions.extend( + [self.get_action(action) for action in class_actions]) + + # get_action might have returned None, so filter any of those out. + actions = filter(None, actions) + if six.PY3: + actions = list(actions) + + # Convert the actions into a OrderedDict keyed by name. + actions = OrderedDict([ + (name, (ac, name, desc, icon)) + for ac, name, desc, icon in actions + ]) + + return actions + + def get_action_choices(self): + """ + Return a list of choices for use in a form object. Each choice is a + tuple (name, description). + """ + choices = [] + for ac, name, description, icon in self.actions.values(): + choice = (name, description % model_format_dict(self.opts), icon) + choices.append(choice) + return choices + + def get_action(self, action): + if isinstance(action, type) and issubclass(action, BaseActionView): + if not action.has_perm(self.admin_view): + return None + return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon') + + elif callable(action): + func = action + action = action.__name__ + + elif hasattr(self.admin_view.__class__, action): + func = getattr(self.admin_view.__class__, action) + + else: + return None + + if hasattr(func, 'short_description'): + description = func.short_description + else: + description = capfirst(action.replace('_', ' ')) + + return func, action, description, getattr(func, 'icon', 'tasks') + + # View Methods + def result_header(self, item, field_name, row): + if item.attr and field_name == 'action_checkbox': + item.classes.append("action-checkbox-column") + return item + + def result_item(self, item, obj, field_name, row): + if item.field is None and field_name == u'action_checkbox': + item.classes.append("action-checkbox") + return item + + # Media + def get_media(self, media): + if self.actions and self.admin_view.result_count: + media = media + self.vendor('xadmin.plugin.actions.js', 'xadmin.plugins.css') + return media + + # Block Views + def block_results_bottom(self, context, nodes): + if self.actions and self.admin_view.result_count: + nodes.append(loader.render_to_string('xadmin/blocks/model_list.results_bottom.actions.html', + context=get_context_dict(context))) + + +site.register_plugin(ActionPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/aggregation.py b/extra_apps/xadmin/plugins/aggregation.py new file mode 100644 index 0000000..1e7553f --- /dev/null +++ b/extra_apps/xadmin/plugins/aggregation.py @@ -0,0 +1,68 @@ +from django.db.models import FieldDoesNotExist, Avg, Max, Min, Count, Sum +from django.utils.translation import ugettext as _ +from django.forms import Media + +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView + +from xadmin.views.list import ResultRow, ResultItem +from xadmin.util import display_for_field + +AGGREGATE_METHODS = { + 'min': Min, 'max': Max, 'avg': Avg, 'sum': Sum, 'count': Count +} +AGGREGATE_TITLE = { + 'min': _('Min'), 'max': _('Max'), 'avg': _('Avg'), 'sum': _('Sum'), 'count': _('Count') +} + + +class AggregationPlugin(BaseAdminPlugin): + + aggregate_fields = {} + + def init_request(self, *args, **kwargs): + return bool(self.aggregate_fields) + + def _get_field_aggregate(self, field_name, obj, row): + item = ResultItem(field_name, row) + item.classes = ['aggregate', ] + if field_name not in self.aggregate_fields: + item.text = "" + else: + try: + f = self.opts.get_field(field_name) + agg_method = self.aggregate_fields[field_name] + key = '%s__%s' % (field_name, agg_method) + if key not in obj: + item.text = "" + else: + item.text = display_for_field(obj[key], f) + item.wraps.append('%%s%s' % AGGREGATE_TITLE[agg_method]) + item.classes.append(agg_method) + except FieldDoesNotExist: + item.text = "" + + return item + + def _get_aggregate_row(self): + queryset = self.admin_view.list_queryset._clone() + obj = queryset.aggregate(*[AGGREGATE_METHODS[method](field_name) for field_name, method in + self.aggregate_fields.items() if method in AGGREGATE_METHODS]) + + row = ResultRow() + row['is_display_first'] = False + row.cells = [self._get_field_aggregate(field_name, obj, row) for field_name in self.admin_view.list_display] + row.css_class = 'info aggregate' + return row + + def results(self, rows): + if rows: + rows.append(self._get_aggregate_row()) + return rows + + # Media + def get_media(self, media): + return media + Media(css={'screen': [self.static('xadmin/css/xadmin.plugin.aggregation.css'), ]}) + + +site.register_plugin(AggregationPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/ajax.py b/extra_apps/xadmin/plugins/ajax.py new file mode 100644 index 0000000..b09bea2 --- /dev/null +++ b/extra_apps/xadmin/plugins/ajax.py @@ -0,0 +1,99 @@ +from collections import OrderedDict +from django.forms.utils import ErrorDict +from django.utils.html import escape +from django.utils.encoding import force_text +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView, ModelFormAdminView, DetailAdminView + + +NON_FIELD_ERRORS = '__all__' + + +class BaseAjaxPlugin(BaseAdminPlugin): + + def init_request(self, *args, **kwargs): + return bool(self.request.is_ajax() or self.request.GET.get('_ajax')) + + +class AjaxListPlugin(BaseAjaxPlugin): + + def get_list_display(self,list_display): + list_fields = [field for field in self.request.GET.get('_fields',"").split(",") + if field.strip() != ""] + if list_fields: + return list_fields + return list_display + + def get_result_list(self, response): + av = self.admin_view + base_fields = self.get_list_display(av.base_list_display) + headers = dict([(c.field_name, force_text(c.text)) for c in av.result_headers( + ).cells if c.field_name in base_fields]) + + objects = [dict([(o.field_name, escape(str(o.value))) for i, o in + enumerate(filter(lambda c:c.field_name in base_fields, r.cells))]) + for r in av.results()] + + return self.render_response({'headers': headers, 'objects': objects, 'total_count': av.result_count, 'has_more': av.has_more}) + + +class JsonErrorDict(ErrorDict): + + def __init__(self, errors, form): + super(JsonErrorDict, self).__init__(errors) + self.form = form + + def as_json(self): + if not self: + return u'' + return [{'id': self.form[k].auto_id if k != NON_FIELD_ERRORS else NON_FIELD_ERRORS, 'name': k, 'errors': v} for k, v in self.items()] + + +class AjaxFormPlugin(BaseAjaxPlugin): + + def post_response(self, __): + new_obj = self.admin_view.new_obj + return self.render_response({ + 'result': 'success', + 'obj_id': new_obj.pk, + 'obj_repr': str(new_obj), + 'change_url': self.admin_view.model_admin_url('change', new_obj.pk), + 'detail_url': self.admin_view.model_admin_url('detail', new_obj.pk) + }) + + def get_response(self, __): + if self.request.method.lower() != 'post': + return __() + + result = {} + form = self.admin_view.form_obj + if form.is_valid(): + result['result'] = 'success' + else: + result['result'] = 'error' + result['errors'] = JsonErrorDict(form.errors, form).as_json() + + return self.render_response(result) + + +class AjaxDetailPlugin(BaseAjaxPlugin): + + def get_response(self, __): + if self.request.GET.get('_format') == 'html': + self.admin_view.detail_template = 'xadmin/views/quick_detail.html' + return __() + + form = self.admin_view.form_obj + layout = form.helper.layout + + results = [] + + for p, f in layout.get_field_names(): + result = self.admin_view.get_field_result(f) + results.append((result.label, result.val)) + + return self.render_response(OrderedDict(results)) + +site.register_plugin(AjaxListPlugin, ListAdminView) +site.register_plugin(AjaxFormPlugin, ModelFormAdminView) +site.register_plugin(AjaxDetailPlugin, DetailAdminView) diff --git a/extra_apps/xadmin/plugins/auth.py b/extra_apps/xadmin/plugins/auth.py new file mode 100644 index 0000000..1ab6f61 --- /dev/null +++ b/extra_apps/xadmin/plugins/auth.py @@ -0,0 +1,269 @@ +# coding=utf-8 +from django import forms +from django.contrib.auth.forms import (UserCreationForm, UserChangeForm, + AdminPasswordChangeForm, PasswordChangeForm) +from django.contrib.auth.models import Group, Permission +from django.core.exceptions import PermissionDenied +from django.conf import settings +from django.template.response import TemplateResponse +from django.utils.decorators import method_decorator +from django.http import HttpResponseRedirect +from django.utils.html import escape +from django.utils.encoding import smart_text +from django.utils.translation import ugettext as _ +from django.views.decorators.debug import sensitive_post_parameters +from django.forms import ModelMultipleChoiceField +from django.contrib.auth import get_user_model +from xadmin.layout import Fieldset, Main, Side, Row, FormHelper +from xadmin.sites import site +from xadmin.util import unquote +from xadmin.views import BaseAdminPlugin, ModelFormAdminView, ModelAdminView, CommAdminView, csrf_protect_m + +User = get_user_model() + +ACTION_NAME = { + 'add': _('Can add %s'), + 'change': _('Can change %s'), + 'edit': _('Can edit %s'), + 'delete': _('Can delete %s'), + 'view': _('Can view %s'), +} + + +def get_permission_name(p): + action = p.codename.split('_')[0] + if action in ACTION_NAME: + return ACTION_NAME[action] % str(p.content_type) + else: + return p.name + + +class PermissionModelMultipleChoiceField(ModelMultipleChoiceField): + + def label_from_instance(self, p): + return get_permission_name(p) + + +class GroupAdmin(object): + search_fields = ('name',) + ordering = ('name',) + style_fields = {'permissions': 'm2m_transfer'} + model_icon = 'fa fa-group' + + def get_field_attrs(self, db_field, **kwargs): + attrs = super(GroupAdmin, self).get_field_attrs(db_field, **kwargs) + if db_field.name == 'permissions': + attrs['form_class'] = PermissionModelMultipleChoiceField + return attrs + + +class UserAdmin(object): + change_user_password_template = None + list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff') + list_filter = ('is_staff', 'is_superuser', 'is_active') + search_fields = ('username', 'first_name', 'last_name', 'email') + ordering = ('username',) + style_fields = {'user_permissions': 'm2m_transfer'} + model_icon = 'fa fa-user' + relfield_style = 'fk-ajax' + + def get_field_attrs(self, db_field, **kwargs): + attrs = super(UserAdmin, self).get_field_attrs(db_field, **kwargs) + if db_field.name == 'user_permissions': + attrs['form_class'] = PermissionModelMultipleChoiceField + return attrs + + def get_model_form(self, **kwargs): + if self.org_obj is None: + self.form = UserCreationForm + else: + self.form = UserChangeForm + return super(UserAdmin, self).get_model_form(**kwargs) + + def get_form_layout(self): + if self.org_obj: + self.form_layout = ( + Main( + Fieldset('', + 'username', 'password', + css_class='unsort no_title' + ), + Fieldset(_('Personal info'), + Row('first_name', 'last_name'), + 'email' + ), + Fieldset(_('Permissions'), + 'groups', 'user_permissions' + ), + Fieldset(_('Important dates'), + 'last_login', 'date_joined' + ), + ), + Side( + Fieldset(_('Status'), + 'is_active', 'is_staff', 'is_superuser', + ), + ) + ) + return super(UserAdmin, self).get_form_layout() + + +class PermissionAdmin(object): + + def show_name(self, p): + return get_permission_name(p) + show_name.short_description = _('Permission Name') + show_name.is_column = True + + model_icon = 'fa fa-lock' + list_display = ('show_name', ) + +site.register(Group, GroupAdmin) +site.register(User, UserAdmin) +site.register(Permission, PermissionAdmin) + + +class UserFieldPlugin(BaseAdminPlugin): + + user_fields = [] + + def get_field_attrs(self, __, db_field, **kwargs): + if self.user_fields and db_field.name in self.user_fields: + return {'widget': forms.HiddenInput} + return __() + + def get_form_datas(self, datas): + if self.user_fields and 'data' in datas: + if hasattr(datas['data'],'_mutable') and not datas['data']._mutable: + datas['data'] = datas['data'].copy() + for f in self.user_fields: + datas['data'][f] = self.user.id + return datas + +site.register_plugin(UserFieldPlugin, ModelFormAdminView) + + +class ModelPermissionPlugin(BaseAdminPlugin): + + user_can_access_owned_objects_only = False + user_owned_objects_field = 'user' + + def queryset(self, qs): + if self.user_can_access_owned_objects_only and \ + not self.user.is_superuser: + filters = {self.user_owned_objects_field: self.user} + qs = qs.filter(**filters) + return qs + + def get_list_display(self, list_display): + if self.user_can_access_owned_objects_only and \ + not self.user.is_superuser and \ + self.user_owned_objects_field in list_display: + list_display.remove(self.user_owned_objects_field) + return list_display + +site.register_plugin(ModelPermissionPlugin, ModelAdminView) + + +class AccountMenuPlugin(BaseAdminPlugin): + + def block_top_account_menu(self, context, nodes): + return '
  • %s
  • ' % (self.get_admin_url('account_password'), _('Change Password')) + +site.register_plugin(AccountMenuPlugin, CommAdminView) + + +class ChangePasswordView(ModelAdminView): + model = User + change_password_form = AdminPasswordChangeForm + change_user_password_template = None + + @csrf_protect_m + def get(self, request, object_id): + if not self.has_change_permission(request): + raise PermissionDenied + self.obj = self.get_object(unquote(object_id)) + self.form = self.change_password_form(self.obj) + + return self.get_response() + + def get_media(self): + media = super(ChangePasswordView, self).get_media() + media = media + self.vendor('xadmin.form.css', 'xadmin.page.form.js') + self.form.media + return media + + def get_context(self): + context = super(ChangePasswordView, self).get_context() + helper = FormHelper() + helper.form_tag = False + helper.include_media = False + self.form.helper = helper + context.update({ + 'title': _('Change password: %s') % escape(smart_text(self.obj)), + 'form': self.form, + 'has_delete_permission': False, + 'has_change_permission': True, + 'has_view_permission': True, + 'original': self.obj, + }) + return context + + def get_response(self): + return TemplateResponse(self.request, [ + self.change_user_password_template or + 'xadmin/auth/user/change_password.html' + ], self.get_context()) + + @method_decorator(sensitive_post_parameters()) + @csrf_protect_m + def post(self, request, object_id): + if not self.has_change_permission(request): + raise PermissionDenied + self.obj = self.get_object(unquote(object_id)) + self.form = self.change_password_form(self.obj, request.POST) + + if self.form.is_valid(): + self.form.save() + self.message_user(_('Password changed successfully.'), 'success') + return HttpResponseRedirect(self.model_admin_url('change', self.obj.pk)) + else: + return self.get_response() + + +class ChangeAccountPasswordView(ChangePasswordView): + change_password_form = PasswordChangeForm + + @csrf_protect_m + def get(self, request): + self.obj = self.user + self.form = self.change_password_form(self.obj) + + return self.get_response() + + def get_context(self): + context = super(ChangeAccountPasswordView, self).get_context() + context.update({ + 'title': _('Change password'), + 'account_view': True, + }) + return context + + @method_decorator(sensitive_post_parameters()) + @csrf_protect_m + def post(self, request): + self.obj = self.user + self.form = self.change_password_form(self.obj, request.POST) + + if self.form.is_valid(): + self.form.save() + self.message_user(_('Password changed successfully.'), 'success') + return HttpResponseRedirect(self.get_admin_url('index')) + else: + return self.get_response() + + +user_model = settings.AUTH_USER_MODEL.lower().replace('.','/') +site.register_view(r'^%s/(.+)/password/$' % user_model, + ChangePasswordView, name='user_change_password') +site.register_view(r'^account/password/$', ChangeAccountPasswordView, + name='account_password') diff --git a/extra_apps/xadmin/plugins/batch.py b/extra_apps/xadmin/plugins/batch.py new file mode 100644 index 0000000..b322af9 --- /dev/null +++ b/extra_apps/xadmin/plugins/batch.py @@ -0,0 +1,156 @@ + +import copy +from django import forms +from django.db import models +from django.core.exceptions import PermissionDenied +from django.forms.models import modelform_factory +from django.template.response import TemplateResponse +from django.utils.encoding import force_text +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _, ugettext_lazy +from xadmin.layout import FormHelper, Layout, Fieldset, Container, Col +from xadmin.plugins.actions import BaseActionView, ACTION_CHECKBOX_NAME +from xadmin.util import model_ngettext, vendor +from xadmin.views.base import filter_hook +from xadmin.views.edit import ModelFormAdminView + +BATCH_CHECKBOX_NAME = '_batch_change_fields' + + +class ChangeFieldWidgetWrapper(forms.Widget): + + def __init__(self, widget): + self.needs_multipart_form = widget.needs_multipart_form + self.attrs = widget.attrs + self.widget = widget + + def __deepcopy__(self, memo): + obj = copy.copy(self) + obj.widget = copy.deepcopy(self.widget, memo) + obj.attrs = self.widget.attrs + memo[id(self)] = obj + return obj + + @property + def media(self): + media = self.widget.media + vendor('xadmin.plugin.batch.js') + return media + + def render(self, name, value, attrs=None): + output = [] + is_required = self.widget.is_required + output.append(u'' % + (BATCH_CHECKBOX_NAME, name, (is_required and ' checked="checked"' or ''), _('Change this field'))) + output.extend([('
    ' % + ((not is_required and 'display: none;' or ''), name)), + self.widget.render(name, value, attrs), '
    ']) + return mark_safe(u''.join(output)) + + def build_attrs(self, extra_attrs=None, **kwargs): + "Helper function for building an attribute dictionary." + self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs) + return self.attrs + + def value_from_datadict(self, data, files, name): + return self.widget.value_from_datadict(data, files, name) + + def id_for_label(self, id_): + return self.widget.id_for_label(id_) + +class BatchChangeAction(BaseActionView): + + action_name = "change_selected" + description = ugettext_lazy( + u'Batch Change selected %(verbose_name_plural)s') + + batch_change_form_template = None + + model_perm = 'change' + + batch_fields = [] + + def change_models(self, queryset, cleaned_data): + n = queryset.count() + + data = {} + fields = self.opts.fields + self.opts.many_to_many + for f in fields: + if not f.editable or isinstance(f, models.AutoField) \ + or not f.name in cleaned_data: + continue + data[f] = cleaned_data[f.name] + + if n: + for obj in queryset: + for f, v in data.items(): + f.save_form_data(obj, v) + obj.save() + self.message_user(_("Successfully change %(count)d %(items)s.") % { + "count": n, "items": model_ngettext(self.opts, n) + }, 'success') + + def get_change_form(self, is_post, fields): + edit_view = self.get_model_view(ModelFormAdminView, self.model) + + def formfield_for_dbfield(db_field, **kwargs): + formfield = edit_view.formfield_for_dbfield(db_field, required=is_post, **kwargs) + formfield.widget = ChangeFieldWidgetWrapper(formfield.widget) + return formfield + + defaults = { + "form": edit_view.form, + "fields": fields, + "formfield_callback": formfield_for_dbfield, + } + return modelform_factory(self.model, **defaults) + + def do_action(self, queryset): + if not self.has_change_permission(): + raise PermissionDenied + + change_fields = [f for f in self.request.POST.getlist(BATCH_CHECKBOX_NAME) if f in self.batch_fields] + + if change_fields and self.request.POST.get('post'): + self.form_obj = self.get_change_form(True, change_fields)( + data=self.request.POST, files=self.request.FILES) + if self.form_obj.is_valid(): + self.change_models(queryset, self.form_obj.cleaned_data) + return None + else: + self.form_obj = self.get_change_form(False, self.batch_fields)() + + helper = FormHelper() + helper.form_tag = False + helper.include_media = False + helper.add_layout(Layout(Container(Col('full', + Fieldset("", *self.form_obj.fields.keys(), css_class="unsort no_title"), horizontal=True, span=12) + ))) + self.form_obj.helper = helper + count = len(queryset) + if count == 1: + objects_name = force_text(self.opts.verbose_name) + else: + objects_name = force_text(self.opts.verbose_name_plural) + + context = self.get_context() + context.update({ + "title": _("Batch change %s") % objects_name, + 'objects_name': objects_name, + 'form': self.form_obj, + 'queryset': queryset, + 'count': count, + "opts": self.opts, + "app_label": self.app_label, + 'action_checkbox_name': ACTION_CHECKBOX_NAME, + }) + + return TemplateResponse(self.request, self.batch_change_form_template or + self.get_template_list('views/batch_change_form.html'), context) + + @filter_hook + def get_media(self): + media = super(BatchChangeAction, self).get_media() + media = media + self.form_obj.media + self.vendor( + 'xadmin.page.form.js', 'xadmin.form.css') + return media diff --git a/extra_apps/xadmin/plugins/bookmark.py b/extra_apps/xadmin/plugins/bookmark.py new file mode 100644 index 0000000..f6e0708 --- /dev/null +++ b/extra_apps/xadmin/plugins/bookmark.py @@ -0,0 +1,236 @@ + +from django.contrib.contenttypes.models import ContentType +from django.urls.base import reverse +from django.db import transaction +from django.db.models import Q +from django.forms import ModelChoiceField +from django.http import QueryDict +from django.template import loader +from django.utils.decorators import method_decorator +from django.utils.encoding import smart_text +from django.utils.translation import ugettext_lazy as _ +from django.views.decorators.csrf import csrf_protect + +from xadmin.filters import FILTER_PREFIX, SEARCH_VAR +from xadmin.plugins.relate import RELATE_PREFIX +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import ModelAdminView, BaseAdminPlugin, ListAdminView +from xadmin.views.list import COL_LIST_VAR, ORDER_VAR +from xadmin.views.dashboard import widget_manager, BaseWidget, PartialBaseWidget + +from xadmin.models import Bookmark + +csrf_protect_m = method_decorator(csrf_protect) + + +class BookmarkPlugin(BaseAdminPlugin): + + # [{'title': "Female", 'query': {'gender': True}, 'order': ('-age'), 'cols': ('first_name', 'age', 'phones'), 'search': 'Tom'}] + list_bookmarks = [] + show_bookmarks = True + + def has_change_permission(self, obj=None): + if not obj or self.user.is_superuser: + return True + else: + return obj.user == self.user + + def get_context(self, context): + if not self.show_bookmarks: + return context + + bookmarks = [] + + current_qs = '&'.join([ + '%s=%s' % (k, v) + for k, v in sorted(filter( + lambda i: bool(i[1] and ( + i[0] in (COL_LIST_VAR, ORDER_VAR, SEARCH_VAR) + or i[0].startswith(FILTER_PREFIX) + or i[0].startswith(RELATE_PREFIX) + )), + self.request.GET.items() + )) + ]) + + model_info = (self.opts.app_label, self.opts.model_name) + has_selected = False + menu_title = _(u"Bookmark") + list_base_url = reverse('xadmin:%s_%s_changelist' % + model_info, current_app=self.admin_site.name) + + # local bookmarks + for bk in self.list_bookmarks: + title = bk['title'] + params = dict([ + (FILTER_PREFIX + k, v) + for (k, v) in bk['query'].items() + ]) + if 'order' in bk: + params[ORDER_VAR] = '.'.join(bk['order']) + if 'cols' in bk: + params[COL_LIST_VAR] = '.'.join(bk['cols']) + if 'search' in bk: + params[SEARCH_VAR] = bk['search'] + + def check_item(i): + return bool(i[1]) or i[1] == False + bk_qs = '&'.join([ + '%s=%s' % (k, v) + for k, v in sorted(filter(check_item, params.items())) + ]) + + url = list_base_url + '?' + bk_qs + selected = (current_qs == bk_qs) + + bookmarks.append( + {'title': title, 'selected': selected, 'url': url}) + if selected: + menu_title = title + has_selected = True + + content_type = ContentType.objects.get_for_model(self.model) + bk_model_info = (Bookmark._meta.app_label, Bookmark._meta.model_name) + bookmarks_queryset = Bookmark.objects.filter( + content_type=content_type, + url_name='xadmin:%s_%s_changelist' % model_info + ).filter(Q(user=self.user) | Q(is_share=True)) + + for bk in bookmarks_queryset: + selected = (current_qs == bk.query) + + if self.has_change_permission(bk): + change_or_detail = 'change' + else: + change_or_detail = 'detail' + + bookmarks.append({'title': bk.title, 'selected': selected, 'url': bk.url, 'edit_url': + reverse('xadmin:%s_%s_%s' % (bk_model_info[0], bk_model_info[1], change_or_detail), + args=(bk.id,))}) + if selected: + menu_title = bk.title + has_selected = True + + post_url = reverse('xadmin:%s_%s_bookmark' % model_info, + current_app=self.admin_site.name) + + new_context = { + 'bk_menu_title': menu_title, + 'bk_bookmarks': bookmarks, + 'bk_current_qs': current_qs, + 'bk_has_selected': has_selected, + 'bk_list_base_url': list_base_url, + 'bk_post_url': post_url, + 'has_add_permission_bookmark': self.admin_view.request.user.has_perm('xadmin.add_bookmark'), + 'has_change_permission_bookmark': self.admin_view.request.user.has_perm('xadmin.change_bookmark') + } + context.update(new_context) + return context + + # Media + def get_media(self, media): + return media + self.vendor('xadmin.plugin.bookmark.js') + + # Block Views + def block_nav_menu(self, context, nodes): + if self.show_bookmarks: + nodes.insert(0, loader.render_to_string('xadmin/blocks/model_list.nav_menu.bookmarks.html', + context=get_context_dict(context))) + + +class BookmarkView(ModelAdminView): + + @csrf_protect_m + @transaction.atomic + def post(self, request): + model_info = (self.opts.app_label, self.opts.model_name) + url_name = 'xadmin:%s_%s_changelist' % model_info + bookmark = Bookmark( + content_type=ContentType.objects.get_for_model(self.model), + title=request.POST[ + 'title'], user=self.user, query=request.POST.get('query', ''), + is_share=request.POST.get('is_share', 0), url_name=url_name) + bookmark.save() + content = {'title': bookmark.title, 'url': bookmark.url} + return self.render_response(content) + + +class BookmarkAdmin(object): + + model_icon = 'fa fa-book' + list_display = ('title', 'user', 'url_name', 'query') + list_display_links = ('title',) + user_fields = ['user'] + hidden_menu = True + + def queryset(self): + if self.user.is_superuser: + return Bookmark.objects.all() + return Bookmark.objects.filter(Q(user=self.user) | Q(is_share=True)) + + def get_list_display(self): + list_display = super(BookmarkAdmin, self).get_list_display() + if not self.user.is_superuser: + list_display.remove('user') + return list_display + + def has_change_permission(self, obj=None): + if not obj or self.user.is_superuser: + return True + else: + return obj.user == self.user + + +@widget_manager.register +class BookmarkWidget(PartialBaseWidget): + widget_type = _('bookmark') + widget_icon = 'fa fa-bookmark' + description = _( + 'Bookmark Widget, can show user\'s bookmark list data in widget.') + template = "xadmin/widgets/list.html" + + bookmark = ModelChoiceField( + label=_('Bookmark'), queryset=Bookmark.objects.all(), required=False) + + def setup(self): + BaseWidget.setup(self) + + bookmark = self.cleaned_data['bookmark'] + model = bookmark.content_type.model_class() + data = QueryDict(bookmark.query) + self.bookmark = bookmark + + if not self.title: + self.title = smart_text(bookmark) + + req = self.make_get_request("", data.items()) + self.list_view = self.get_view_class( + ListAdminView, model, list_per_page=10, list_editable=[])(req) + + def has_perm(self): + return True + + def context(self, context): + list_view = self.list_view + list_view.make_result_list() + + base_fields = list_view.base_list_display + if len(base_fields) > 5: + base_fields = base_fields[0:5] + + context['result_headers'] = [c for c in list_view.result_headers( + ).cells if c.field_name in base_fields] + context['results'] = [ + [o for i, o in enumerate(filter( + lambda c: c.field_name in base_fields, + r.cells + ))] + for r in list_view.results() + ] + context['result_count'] = list_view.result_count + context['page_url'] = self.bookmark.url + +site.register(Bookmark, BookmarkAdmin) +site.register_plugin(BookmarkPlugin, ListAdminView) +site.register_modelview(r'^bookmark/$', BookmarkView, name='%s_%s_bookmark') diff --git a/extra_apps/xadmin/plugins/chart.py b/extra_apps/xadmin/plugins/chart.py new file mode 100644 index 0000000..e2b0a64 --- /dev/null +++ b/extra_apps/xadmin/plugins/chart.py @@ -0,0 +1,160 @@ + +import calendar +import datetime +import decimal + +from django.core.serializers.json import DjangoJSONEncoder +from django.db import models +from django.http import HttpResponse, HttpResponseNotFound +from django.template import loader +from django.utils.http import urlencode +from django.utils.encoding import force_text, smart_text +from django.utils.translation import ugettext_lazy as _, ugettext + +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView +from xadmin.views.dashboard import ModelBaseWidget, widget_manager +from xadmin.util import lookup_field, label_for_field, json + + +@widget_manager.register +class ChartWidget(ModelBaseWidget): + widget_type = 'chart' + description = _('Show models simple chart.') + template = 'xadmin/widgets/chart.html' + widget_icon = 'fa fa-bar-chart-o' + + def convert(self, data): + self.list_params = data.pop('params', {}) + self.chart = data.pop('chart', None) + + def setup(self): + super(ChartWidget, self).setup() + + self.charts = {} + self.one_chart = False + model_admin = self.admin_site._registry[self.model] + chart = self.chart + + if hasattr(model_admin, 'data_charts'): + if chart and chart in model_admin.data_charts: + self.charts = {chart: model_admin.data_charts[chart]} + self.one_chart = True + if self.title is None: + self.title = model_admin.data_charts[chart].get('title') + else: + self.charts = model_admin.data_charts + if self.title is None: + self.title = ugettext( + "%s Charts") % self.model._meta.verbose_name_plural + + def filte_choices_model(self, model, modeladmin): + return bool(getattr(modeladmin, 'data_charts', None)) and \ + super(ChartWidget, self).filte_choices_model(model, modeladmin) + + def get_chart_url(self, name, v): + return self.model_admin_url('chart', name) + "?" + urlencode(self.list_params) + + def context(self, context): + context.update({ + 'charts': [{"name": name, "title": v['title'], 'url': self.get_chart_url(name, v)} for name, v in self.charts.items()], + }) + + # Media + def media(self): + return self.vendor('flot.js', 'xadmin.plugin.charts.js') + + +class JSONEncoder(DjangoJSONEncoder): + def default(self, o): + if isinstance(o, (datetime.date, datetime.datetime)): + return calendar.timegm(o.timetuple()) * 1000 + elif isinstance(o, decimal.Decimal): + return str(o) + else: + try: + return super(JSONEncoder, self).default(o) + except Exception: + return smart_text(o) + + +class ChartsPlugin(BaseAdminPlugin): + + data_charts = {} + + def init_request(self, *args, **kwargs): + return bool(self.data_charts) + + def get_chart_url(self, name, v): + return self.admin_view.model_admin_url('chart', name) + self.admin_view.get_query_string() + + # Media + def get_media(self, media): + return media + self.vendor('flot.js', 'xadmin.plugin.charts.js') + + # Block Views + def block_results_top(self, context, nodes): + context.update({ + 'charts': [{"name": name, "title": v['title'], 'url': self.get_chart_url(name, v)} for name, v in self.data_charts.items()], + }) + nodes.append(loader.render_to_string('xadmin/blocks/model_list.results_top.charts.html', + context=get_context_dict(context))) + + +class ChartsView(ListAdminView): + + data_charts = {} + + def get_ordering(self): + if 'order' in self.chart: + return self.chart['order'] + else: + return super(ChartsView, self).get_ordering() + + def get(self, request, name): + if name not in self.data_charts: + return HttpResponseNotFound() + + self.chart = self.data_charts[name] + + self.x_field = self.chart['x-field'] + y_fields = self.chart['y-field'] + self.y_fields = ( + y_fields,) if type(y_fields) not in (list, tuple) else y_fields + + datas = [{"data":[], "label": force_text(label_for_field( + i, self.model, model_admin=self))} for i in self.y_fields] + + self.make_result_list() + + for obj in self.result_list: + xf, attrs, value = lookup_field(self.x_field, obj, self) + for i, yfname in enumerate(self.y_fields): + yf, yattrs, yv = lookup_field(yfname, obj, self) + datas[i]["data"].append((value, yv)) + + option = {'series': {'lines': {'show': True}, 'points': {'show': False}}, + 'grid': {'hoverable': True, 'clickable': True}} + try: + xfield = self.opts.get_field(self.x_field) + if type(xfield) in (models.DateTimeField, models.DateField, models.TimeField): + option['xaxis'] = {'mode': "time", 'tickLength': 5} + if type(xfield) is models.DateField: + option['xaxis']['timeformat'] = "%y/%m/%d" + elif type(xfield) is models.TimeField: + option['xaxis']['timeformat'] = "%H:%M:%S" + else: + option['xaxis']['timeformat'] = "%y/%m/%d %H:%M:%S" + except Exception: + pass + + option.update(self.chart.get('option', {})) + + content = {'data': datas, 'option': option} + result = json.dumps(content, cls=JSONEncoder, ensure_ascii=False) + + return HttpResponse(result) + +site.register_plugin(ChartsPlugin, ListAdminView) +site.register_modelview(r'^chart/(.+)/$', ChartsView, name='%s_%s_chart') diff --git a/extra_apps/xadmin/plugins/comments.py b/extra_apps/xadmin/plugins/comments.py new file mode 100644 index 0000000..0e90462 --- /dev/null +++ b/extra_apps/xadmin/plugins/comments.py @@ -0,0 +1,94 @@ +import xadmin + +from xadmin.layout import * +from xadmin.util import username_field + +from django.conf import settings +from django.contrib.comments.models import Comment +from django.utils.translation import ugettext_lazy as _, ungettext +from django.contrib.comments import get_model +from django.contrib.comments.views.moderation import perform_flag, perform_approve, perform_delete + +class UsernameSearch(object): + """The User object may not be auth.User, so we need to provide + a mechanism for issuing the equivalent of a .filter(user__username=...) + search in CommentAdmin. + """ + def __str__(self): + return 'user__%s' % username_field + + +class CommentsAdmin(object): + form_layout = ( + Main( + Fieldset(None, + 'content_type', 'object_pk', 'site', + css_class='unsort no_title' + ), + Fieldset('Content', + 'user', 'user_name', 'user_email', 'user_url', 'comment' + ), + ), + Side( + Fieldset(_('Metadata'), + 'submit_date', 'ip_address', 'is_public', 'is_removed' + ), + ) + ) + + list_display = ('name', 'content_type', 'object_pk', 'ip_address', 'submit_date', 'is_public', 'is_removed') + list_filter = ('submit_date', 'site', 'is_public', 'is_removed') + ordering = ('-submit_date',) + search_fields = ('comment', UsernameSearch(), 'user_name', 'user_email', 'user_url', 'ip_address') + actions = ["flag_comments", "approve_comments", "remove_comments"] + model_icon = 'fa fa-comment' + + def get_actions(self): + actions = super(CommentsAdmin, self).get_actions() + # Only superusers should be able to delete the comments from the DB. + if not self.user.is_superuser and 'delete_selected' in actions: + actions.pop('delete_selected') + if not self.user.has_perm('comments.can_moderate'): + if 'approve_comments' in actions: + actions.pop('approve_comments') + if 'remove_comments' in actions: + actions.pop('remove_comments') + return actions + + def flag_comments(self, request, queryset): + self._bulk_flag(queryset, perform_flag, + lambda n: ungettext('flagged', 'flagged', n)) + flag_comments.short_description = _("Flag selected comments") + flag_comments.icon = 'flag' + + def approve_comments(self, request, queryset): + self._bulk_flag(queryset, perform_approve, + lambda n: ungettext('approved', 'approved', n)) + approve_comments.short_description = _("Approve selected comments") + approve_comments.icon = 'ok' + + def remove_comments(self, request, queryset): + self._bulk_flag(queryset, perform_delete, + lambda n: ungettext('removed', 'removed', n)) + remove_comments.short_description = _("Remove selected comments") + remove_comments.icon = 'remove-circle' + + def _bulk_flag(self, queryset, action, done_message): + """ + Flag, approve, or remove some comments from an admin action. Actually + calls the `action` argument to perform the heavy lifting. + """ + n_comments = 0 + for comment in queryset: + action(self.request, comment) + n_comments += 1 + + msg = ungettext('1 comment was successfully %(action)s.', + '%(count)s comments were successfully %(action)s.', + n_comments) + self.message_user(msg % {'count': n_comments, 'action': done_message(n_comments)}, 'success') + +# Only register the default admin if the model is the built-in comment model +# (this won't be true if there's a custom comment app). +if 'django.contrib.comments' in settings.INSTALLED_APPS and (get_model() is Comment): + xadmin.site.register(Comment, CommentsAdmin) diff --git a/extra_apps/xadmin/plugins/details.py b/extra_apps/xadmin/plugins/details.py new file mode 100644 index 0000000..ba167fd --- /dev/null +++ b/extra_apps/xadmin/plugins/details.py @@ -0,0 +1,63 @@ + + +from django.utils.translation import ugettext as _ +from django.urls.base import reverse, NoReverseMatch +from django.db import models + +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView + + +class DetailsPlugin(BaseAdminPlugin): + + show_detail_fields = [] + show_all_rel_details = True + + def result_item(self, item, obj, field_name, row): + if (self.show_all_rel_details or (field_name in self.show_detail_fields)): + rel_obj = None + if hasattr(item.field, 'remote_field') and isinstance(item.field.remote_field, models.ManyToOneRel): + rel_obj = getattr(obj, field_name) + elif field_name in self.show_detail_fields: + rel_obj = obj + + if rel_obj: + if rel_obj.__class__ in site._registry: + try: + model_admin = site._registry[rel_obj.__class__] + has_view_perm = model_admin(self.admin_view.request).has_view_permission(rel_obj) + has_change_perm = model_admin(self.admin_view.request).has_change_permission(rel_obj) + except: + has_view_perm = self.admin_view.has_model_perm(rel_obj.__class__, 'view') + has_change_perm = self.has_model_perm(rel_obj.__class__, 'change') + else: + has_view_perm = self.admin_view.has_model_perm(rel_obj.__class__, 'view') + has_change_perm = self.has_model_perm(rel_obj.__class__, 'change') + + if rel_obj and has_view_perm: + opts = rel_obj._meta + try: + item_res_uri = reverse( + '%s:%s_%s_detail' % (self.admin_site.app_name, + opts.app_label, opts.model_name), + args=(getattr(rel_obj, opts.pk.attname),)) + if item_res_uri: + if has_change_perm: + edit_url = reverse( + '%s:%s_%s_change' % (self.admin_site.app_name, opts.app_label, opts.model_name), + args=(getattr(rel_obj, opts.pk.attname),)) + else: + edit_url = '' + item.btns.append('' + % (item_res_uri, edit_url, _(u'Details of %s') % str(rel_obj))) + except NoReverseMatch: + pass + return item + + # Media + def get_media(self, media): + if self.show_all_rel_details or self.show_detail_fields: + media = media + self.vendor('xadmin.plugin.details.js', 'xadmin.form.css') + return media + +site.register_plugin(DetailsPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/editable.py b/extra_apps/xadmin/plugins/editable.py new file mode 100644 index 0000000..68a5960 --- /dev/null +++ b/extra_apps/xadmin/plugins/editable.py @@ -0,0 +1,167 @@ +from django import template +from django.core.exceptions import PermissionDenied, ObjectDoesNotExist +from django.db import models, transaction +from django.forms.models import modelform_factory +from django.forms import Media +from django.http import Http404, HttpResponse +from django.utils.encoding import force_text, smart_text +from django.utils.html import escape, conditional_escape +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _ +from xadmin.plugins.ajax import JsonErrorDict +from xadmin.sites import site +from xadmin.util import lookup_field, display_for_field, label_for_field, unquote, boolean_icon +from xadmin.views import BaseAdminPlugin, ModelFormAdminView, ListAdminView +from xadmin.views.base import csrf_protect_m, filter_hook +from xadmin.views.edit import ModelFormAdminUtil +from xadmin.views.list import EMPTY_CHANGELIST_VALUE +from xadmin.layout import FormHelper + + +class EditablePlugin(BaseAdminPlugin): + + list_editable = [] + + def __init__(self, admin_view): + super(EditablePlugin, self).__init__(admin_view) + self.editable_need_fields = {} + + def init_request(self, *args, **kwargs): + active = bool(self.request.method == 'GET' and self.admin_view.has_change_permission() and self.list_editable) + if active: + self.model_form = self.get_model_view(ModelFormAdminUtil, self.model).form_obj + return active + + def result_item(self, item, obj, field_name, row): + if self.list_editable and item.field and item.field.editable and (field_name in self.list_editable): + pk = getattr(obj, obj._meta.pk.attname) + field_label = label_for_field(field_name, obj, + model_admin=self.admin_view, + return_attr=False + ) + + item.wraps.insert(0, '%s') + item.btns.append(( + '' + + '') % + (_(u"Enter %s") % field_label, field_name, self.admin_view.model_admin_url('patch', pk) + '?fields=' + field_name)) + + if field_name not in self.editable_need_fields: + self.editable_need_fields[field_name] = item.field + return item + + # Media + def get_media(self, media): + if self.editable_need_fields: + + try: + m = self.model_form.media + except: + m = Media() + media = media + m +\ + self.vendor( + 'xadmin.plugin.editable.js', 'xadmin.widget.editable.css') + return media + + +class EditPatchView(ModelFormAdminView, ListAdminView): + + def init_request(self, object_id, *args, **kwargs): + self.org_obj = self.get_object(unquote(object_id)) + + # For list view get new field display html + self.pk_attname = self.opts.pk.attname + + if not self.has_change_permission(self.org_obj): + raise PermissionDenied + + if self.org_obj is None: + raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % + {'name': force_text(self.opts.verbose_name), 'key': escape(object_id)}) + + def get_new_field_html(self, f): + result = self.result_item(self.org_obj, f, {'is_display_first': + False, 'object': self.org_obj}) + return mark_safe(result.text) if result.allow_tags else conditional_escape(result.text) + + def _get_new_field_html(self, field_name): + try: + f, attr, value = lookup_field(field_name, self.org_obj, self) + except (AttributeError, ObjectDoesNotExist): + return EMPTY_CHANGELIST_VALUE + else: + allow_tags = False + if f is None: + allow_tags = getattr(attr, 'allow_tags', False) + boolean = getattr(attr, 'boolean', False) + if boolean: + allow_tags = True + text = boolean_icon(value) + else: + text = smart_text(value) + else: + if isinstance(f.rel, models.ManyToOneRel): + field_val = getattr(self.org_obj, f.name) + if field_val is None: + text = EMPTY_CHANGELIST_VALUE + else: + text = field_val + else: + text = display_for_field(value, f) + return mark_safe(text) if allow_tags else conditional_escape(text) + + @filter_hook + def get(self, request, object_id): + model_fields = [f.name for f in self.opts.fields] + fields = [f for f in request.GET['fields'].split(',') if f in model_fields] + defaults = { + "form": self.form, + "fields": fields, + "formfield_callback": self.formfield_for_dbfield, + } + form_class = modelform_factory(self.model, **defaults) + form = form_class(instance=self.org_obj) + + helper = FormHelper() + helper.form_tag = False + helper.include_media = False + form.helper = helper + + s = '{% load i18n crispy_forms_tags %}
    {% crispy form %}' + \ + '
    ' + t = template.Template(s) + c = template.Context({'form': form, 'action_url': self.model_admin_url('patch', self.org_obj.pk)}) + + return HttpResponse(t.render(c)) + + @filter_hook + @csrf_protect_m + @transaction.atomic + def post(self, request, object_id): + model_fields = [f.name for f in self.opts.fields] + fields = [f for f in request.POST.keys() if f in model_fields] + defaults = { + "form": self.form, + "fields": fields, + "formfield_callback": self.formfield_for_dbfield, + } + form_class = modelform_factory(self.model, **defaults) + form = form_class( + instance=self.org_obj, data=request.POST, files=request.FILES) + + result = {} + if form.is_valid(): + form.save(commit=True) + result['result'] = 'success' + result['new_data'] = form.cleaned_data + result['new_html'] = dict( + [(f, self.get_new_field_html(f)) for f in fields]) + else: + result['result'] = 'error' + result['errors'] = JsonErrorDict(form.errors, form).as_json() + + return self.render_response(result) + + +site.register_plugin(EditablePlugin, ListAdminView) +site.register_modelview(r'^(.+)/patch/$', EditPatchView, name='%s_%s_patch') diff --git a/extra_apps/xadmin/plugins/export.py b/extra_apps/xadmin/plugins/export.py new file mode 100644 index 0000000..8ccc0f4 --- /dev/null +++ b/extra_apps/xadmin/plugins/export.py @@ -0,0 +1,249 @@ +import io +import datetime +import sys +from future.utils import iteritems + +from django.http import HttpResponse +from django.template import loader +from django.utils import six +from django.utils.encoding import force_text, smart_text +from django.utils.html import escape +from django.utils.translation import ugettext as _ +from django.utils.xmlutils import SimplerXMLGenerator +from django.db.models import BooleanField, NullBooleanField + +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView +from xadmin.util import json +from xadmin.views.list import ALL_VAR + +try: + import xlwt + has_xlwt = True +except: + has_xlwt = False + +try: + import xlsxwriter + has_xlsxwriter = True +except: + has_xlsxwriter = False + + +class ExportMenuPlugin(BaseAdminPlugin): + + list_export = ('xlsx', 'xls', 'csv', 'xml', 'json') + export_names = {'xlsx': 'Excel 2007', 'xls': 'Excel', 'csv': 'CSV', + 'xml': 'XML', 'json': 'JSON'} + + def init_request(self, *args, **kwargs): + self.list_export = [ + f for f in self.list_export + if (f != 'xlsx' or has_xlsxwriter) and (f != 'xls' or has_xlwt)] + + def block_top_toolbar(self, context, nodes): + if self.list_export: + context.update({ + 'show_export_all': self.admin_view.paginator.count > self.admin_view.list_per_page and not ALL_VAR in self.admin_view.request.GET, + 'form_params': self.admin_view.get_form_params({'_do_': 'export'}, ('export_type',)), + 'export_types': [{'type': et, 'name': self.export_names[et]} for et in self.list_export], + }) + nodes.append(loader.render_to_string('xadmin/blocks/model_list.top_toolbar.exports.html', + context=get_context_dict(context))) + + +class ExportPlugin(BaseAdminPlugin): + + export_mimes = {'xlsx': 'application/vnd.ms-excel', + 'xls': 'application/vnd.ms-excel', 'csv': 'text/csv', + 'xml': 'application/xhtml+xml', 'json': 'application/json'} + + def init_request(self, *args, **kwargs): + return self.request.GET.get('_do_') == 'export' + + def _format_value(self, o): + if (o.field is None and getattr(o.attr, 'boolean', False)) or \ + (o.field and isinstance(o.field, (BooleanField, NullBooleanField))): + value = o.value + elif str(o.text).startswith(""): + value = escape(str(o.text)[25:-7]) + else: + value = escape(str(o.text)) + return value + + def _get_objects(self, context): + headers = [c for c in context['result_headers'].cells if c.export] + rows = context['results'] + + return [dict([ + (force_text(headers[i].text), self._format_value(o)) for i, o in + enumerate(filter(lambda c:getattr(c, 'export', False), r.cells))]) for r in rows] + + def _get_datas(self, context): + rows = context['results'] + + new_rows = [[self._format_value(o) for o in + filter(lambda c:getattr(c, 'export', False), r.cells)] for r in rows] + new_rows.insert(0, [force_text(c.text) for c in context['result_headers'].cells if c.export]) + return new_rows + + def get_xlsx_export(self, context): + datas = self._get_datas(context) + output = io.BytesIO() + export_header = ( + self.request.GET.get('export_xlsx_header', 'off') == 'on') + + model_name = self.opts.verbose_name + book = xlsxwriter.Workbook(output) + sheet = book.add_worksheet( + u"%s %s" % (_(u'Sheet'), force_text(model_name))) + styles = {'datetime': book.add_format({'num_format': 'yyyy-mm-dd hh:mm:ss'}), + 'date': book.add_format({'num_format': 'yyyy-mm-dd'}), + 'time': book.add_format({'num_format': 'hh:mm:ss'}), + 'header': book.add_format({'font': 'name Times New Roman', 'color': 'red', 'bold': 'on', 'num_format': '#,##0.00'}), + 'default': book.add_format()} + + if not export_header: + datas = datas[1:] + for rowx, row in enumerate(datas): + for colx, value in enumerate(row): + if export_header and rowx == 0: + cell_style = styles['header'] + else: + if isinstance(value, datetime.datetime): + cell_style = styles['datetime'] + elif isinstance(value, datetime.date): + cell_style = styles['date'] + elif isinstance(value, datetime.time): + cell_style = styles['time'] + else: + cell_style = styles['default'] + sheet.write(rowx, colx, value, cell_style) + book.close() + + output.seek(0) + return output.getvalue() + + def get_xls_export(self, context): + datas = self._get_datas(context) + output = io.BytesIO() + export_header = ( + self.request.GET.get('export_xls_header', 'off') == 'on') + + model_name = self.opts.verbose_name + book = xlwt.Workbook(encoding='utf8') + sheet = book.add_sheet( + u"%s %s" % (_(u'Sheet'), force_text(model_name))) + styles = {'datetime': xlwt.easyxf(num_format_str='yyyy-mm-dd hh:mm:ss'), + 'date': xlwt.easyxf(num_format_str='yyyy-mm-dd'), + 'time': xlwt.easyxf(num_format_str='hh:mm:ss'), + 'header': xlwt.easyxf('font: name Times New Roman, color-index red, bold on', num_format_str='#,##0.00'), + 'default': xlwt.Style.default_style} + + if not export_header: + datas = datas[1:] + for rowx, row in enumerate(datas): + for colx, value in enumerate(row): + if export_header and rowx == 0: + cell_style = styles['header'] + else: + if isinstance(value, datetime.datetime): + cell_style = styles['datetime'] + elif isinstance(value, datetime.date): + cell_style = styles['date'] + elif isinstance(value, datetime.time): + cell_style = styles['time'] + else: + cell_style = styles['default'] + sheet.write(rowx, colx, value, style=cell_style) + book.save(output) + + output.seek(0) + return output.getvalue() + + def _format_csv_text(self, t): + if isinstance(t, bool): + return _('Yes') if t else _('No') + t = t.replace('"', '""').replace(',', '\,') + cls_str = str if six.PY3 else basestring + if isinstance(t, cls_str): + t = '"%s"' % t + return t + + def get_csv_export(self, context): + datas = self._get_datas(context) + stream = [] + + if self.request.GET.get('export_csv_header', 'off') != 'on': + datas = datas[1:] + + for row in datas: + stream.append(','.join(map(self._format_csv_text, row))) + + return '\r\n'.join(stream) + + def _to_xml(self, xml, data): + if isinstance(data, (list, tuple)): + for item in data: + xml.startElement("row", {}) + self._to_xml(xml, item) + xml.endElement("row") + elif isinstance(data, dict): + for key, value in iteritems(data): + key = key.replace(' ', '_') + xml.startElement(key, {}) + self._to_xml(xml, value) + xml.endElement(key) + else: + xml.characters(smart_text(data)) + + def get_xml_export(self, context): + results = self._get_objects(context) + stream = io.StringIO() + + xml = SimplerXMLGenerator(stream, "utf-8") + xml.startDocument() + xml.startElement("objects", {}) + + self._to_xml(xml, results) + + xml.endElement("objects") + xml.endDocument() + + return stream.getvalue().split('\n')[1] + + def get_json_export(self, context): + results = self._get_objects(context) + return json.dumps({'objects': results}, ensure_ascii=False, + indent=(self.request.GET.get('export_json_format', 'off') == 'on') and 4 or None) + + def get_response(self, response, context, *args, **kwargs): + file_type = self.request.GET.get('export_type', 'csv') + response = HttpResponse( + content_type="%s; charset=UTF-8" % self.export_mimes[file_type]) + + file_name = self.opts.verbose_name.replace(' ', '_') + response['Content-Disposition'] = ('attachment; filename=%s.%s' % ( + file_name, file_type)).encode('utf-8') + + response.write(getattr(self, 'get_%s_export' % file_type)(context)) + return response + + # View Methods + def get_result_list(self, __): + if self.request.GET.get('all', 'off') == 'on': + self.admin_view.list_per_page = sys.maxsize + return __() + + def result_header(self, item, field_name, row): + item.export = not item.attr or field_name == '__str__' or getattr(item.attr, 'allow_export', True) + return item + + def result_item(self, item, obj, field_name, row): + item.export = item.field or field_name == '__str__' or getattr(item.attr, 'allow_export', True) + return item + + +site.register_plugin(ExportMenuPlugin, ListAdminView) +site.register_plugin(ExportPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/filters.py b/extra_apps/xadmin/plugins/filters.py new file mode 100644 index 0000000..a17777f --- /dev/null +++ b/extra_apps/xadmin/plugins/filters.py @@ -0,0 +1,246 @@ +import operator +from future.utils import iteritems +from xadmin import widgets +from xadmin.plugins.utils import get_context_dict + +from django.contrib.admin.utils import get_fields_from_path, lookup_needs_distinct +from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured, ValidationError +from django.db import models +from django.db.models.fields import FieldDoesNotExist +from django.db.models.constants import LOOKUP_SEP +# from django.db.models.sql.constants import QUERY_TERMS +from django.template import loader +from django.utils import six +from django.utils.encoding import smart_str +from django.utils.translation import ugettext as _ + +from xadmin.filters import manager as filter_manager, FILTER_PREFIX, SEARCH_VAR, DateFieldListFilter, \ + RelatedFieldSearchFilter +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView +from xadmin.util import is_related_field +from functools import reduce + + +class IncorrectLookupParameters(Exception): + pass + + +class FilterPlugin(BaseAdminPlugin): + list_filter = () + search_fields = () + free_query_filter = True + + def lookup_allowed(self, lookup, value): + model = self.model + # Check FKey lookups that are allowed, so that popups produced by + # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, + # are allowed to work. + for l in model._meta.related_fkey_lookups: + for k, v in widgets.url_params_from_lookup_dict(l).items(): + if k == lookup and v == value: + return True + + parts = lookup.split(LOOKUP_SEP) + + # Last term in lookup is a query term (__exact, __startswith etc) + # This term can be ignored. + # if len(parts) > 1 and parts[-1] in QUERY_TERMS: + # parts.pop() + + # Special case -- foo__id__exact and foo__id queries are implied + # if foo has been specificially included in the lookup list; so + # drop __id if it is the last part. However, first we need to find + # the pk attribute name. + rel_name = None + for part in parts[:-1]: + try: + field = model._meta.get_field(part) + except FieldDoesNotExist: + # Lookups on non-existants fields are ok, since they're ignored + # later. + return True + if hasattr(field, 'remote_field'): + model = field.remote_field.to + rel_name = field.remote_field.get_related_field().name + elif is_related_field(field): + model = field.model + rel_name = model._meta.pk.name + else: + rel_name = None + if rel_name and len(parts) > 1 and parts[-1] == rel_name: + parts.pop() + + if len(parts) == 1: + return True + clean_lookup = LOOKUP_SEP.join(parts) + return clean_lookup in self.list_filter + + def get_list_queryset(self, queryset): + lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items() + if smart_str(k).startswith(FILTER_PREFIX) and v != '']) + for p_key, p_val in iteritems(lookup_params): + if p_val == "False": + lookup_params[p_key] = False + use_distinct = False + + # for clean filters + self.admin_view.has_query_param = bool(lookup_params) + self.admin_view.clean_query_url = self.admin_view.get_query_string(remove=[k for k in self.request.GET.keys() if + k.startswith(FILTER_PREFIX)]) + + # Normalize the types of keys + if not self.free_query_filter: + for key, value in lookup_params.items(): + if not self.lookup_allowed(key, value): + raise SuspiciousOperation( + "Filtering by %s not allowed" % key) + + self.filter_specs = [] + if self.list_filter: + for list_filter in self.list_filter: + if callable(list_filter): + # This is simply a custom list filter class. + spec = list_filter(self.request, lookup_params, + self.model, self) + else: + field_path = None + field_parts = [] + if isinstance(list_filter, (tuple, list)): + # This is a custom FieldListFilter class for a given field. + field, field_list_filter_class = list_filter + else: + # This is simply a field name, so use the default + # FieldListFilter class that has been registered for + # the type of the given field. + field, field_list_filter_class = list_filter, filter_manager.create + if not isinstance(field, models.Field): + field_path = field + field_parts = get_fields_from_path( + self.model, field_path) + field = field_parts[-1] + spec = field_list_filter_class( + field, self.request, lookup_params, + self.model, self.admin_view, field_path=field_path) + + if len(field_parts) > 1: + # Add related model name to title + spec.title = "%s %s" % (field_parts[-2].name, spec.title) + + # Check if we need to use distinct() + use_distinct = (use_distinct or + lookup_needs_distinct(self.opts, field_path)) + if spec and spec.has_output(): + try: + new_qs = spec.do_filte(queryset) + except ValidationError as e: + new_qs = None + self.admin_view.message_user(_("Filtering error: %s") % e.messages[0], 'error') + if new_qs is not None: + queryset = new_qs + + self.filter_specs.append(spec) + + self.has_filters = bool(self.filter_specs) + self.admin_view.filter_specs = self.filter_specs + obj = filter(lambda f: f.is_used, self.filter_specs) + if six.PY3: + obj = list(obj) + self.admin_view.used_filter_num = len(obj) + + try: + for key, value in lookup_params.items(): + use_distinct = ( + use_distinct or lookup_needs_distinct(self.opts, key)) + except FieldDoesNotExist as e: + raise IncorrectLookupParameters(e) + + try: + # fix a bug by david: In demo, quick filter by IDC Name() cannot be used. + if isinstance(queryset, models.query.QuerySet) and lookup_params: + new_lookup_parames = dict() + for k, v in lookup_params.items(): + list_v = v.split(',') + if len(list_v) > 0: + new_lookup_parames.update({k: list_v}) + else: + new_lookup_parames.update({k: v}) + queryset = queryset.filter(**new_lookup_parames) + except (SuspiciousOperation, ImproperlyConfigured): + raise + except Exception as e: + raise IncorrectLookupParameters(e) + else: + if not isinstance(queryset, models.query.QuerySet): + pass + + query = self.request.GET.get(SEARCH_VAR, '') + + # Apply keyword searches. + def construct_search(field_name): + if field_name.startswith('^'): + return "%s__istartswith" % field_name[1:] + elif field_name.startswith('='): + return "%s__iexact" % field_name[1:] + elif field_name.startswith('@'): + return "%s__search" % field_name[1:] + else: + return "%s__icontains" % field_name + + if self.search_fields and query: + orm_lookups = [construct_search(str(search_field)) + for search_field in self.search_fields] + for bit in query.split(): + or_queries = [models.Q(**{orm_lookup: bit}) + for orm_lookup in orm_lookups] + queryset = queryset.filter(reduce(operator.or_, or_queries)) + if not use_distinct: + for search_spec in orm_lookups: + if lookup_needs_distinct(self.opts, search_spec): + use_distinct = True + break + self.admin_view.search_query = query + + if use_distinct: + return queryset.distinct() + else: + return queryset + + # Media + def get_media(self, media): + arr = filter(lambda s: isinstance(s, DateFieldListFilter), self.filter_specs) + if six.PY3: + arr = list(arr) + if bool(arr): + media = media + self.vendor('datepicker.css', 'datepicker.js', + 'xadmin.widget.datetime.js') + arr = filter(lambda s: isinstance(s, RelatedFieldSearchFilter), self.filter_specs) + if six.PY3: + arr = list(arr) + if bool(arr): + media = media + self.vendor( + 'select.js', 'select.css', 'xadmin.widget.select.js') + return media + self.vendor('xadmin.plugin.filters.js') + + # Block Views + def block_nav_menu(self, context, nodes): + if self.has_filters: + nodes.append(loader.render_to_string('xadmin/blocks/model_list.nav_menu.filters.html', + context=get_context_dict(context))) + + def block_nav_form(self, context, nodes): + if self.search_fields: + context = get_context_dict(context or {}) # no error! + context.update({ + 'search_var': SEARCH_VAR, + 'remove_search_url': self.admin_view.get_query_string(remove=[SEARCH_VAR]), + 'search_form_params': self.admin_view.get_form_params(remove=[SEARCH_VAR]) + }) + nodes.append( + loader.render_to_string( + 'xadmin/blocks/model_list.nav_form.search_form.html', + context=context) + ) + + +site.register_plugin(FilterPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/images.py b/extra_apps/xadmin/plugins/images.py new file mode 100644 index 0000000..7fea2b3 --- /dev/null +++ b/extra_apps/xadmin/plugins/images.py @@ -0,0 +1,119 @@ +from django.db import models +from django import forms +from django.utils.translation import ugettext as _ +from django.utils.safestring import mark_safe +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ModelFormAdminView, DetailAdminView, ListAdminView + + +def get_gallery_modal(): + return """ + + + """ % (_('Previous'), _('Next'), _('Slideshow'), _('Download')) + + +class AdminImageField(forms.ImageField): + + def widget_attrs(self, widget): + return {'label': self.label} + + +class AdminImageWidget(forms.FileInput): + """ + A ImageField Widget that shows its current value if it has one. + """ + def __init__(self, attrs={}): + super(AdminImageWidget, self).__init__(attrs) + + def render(self, name, value, attrs=None, renderer=None): + output = [] + if value and hasattr(value, "url"): + label = self.attrs.get('label', name) + output.append('
    %s ' % + (value.url, label, value.url, _('Change:'))) + output.append(super(AdminImageWidget, self).render(name, value, attrs, renderer)) + return mark_safe(u''.join(output)) + + +class ModelDetailPlugin(BaseAdminPlugin): + + def __init__(self, admin_view): + super(ModelDetailPlugin, self).__init__(admin_view) + self.include_image = False + + def get_field_attrs(self, attrs, db_field, **kwargs): + if isinstance(db_field, models.ImageField): + attrs['widget'] = AdminImageWidget + attrs['form_class'] = AdminImageField + self.include_image = True + return attrs + + def get_field_result(self, result, field_name): + if isinstance(result.field, models.ImageField): + if result.value: + img = getattr(result.obj, field_name) + result.text = mark_safe('' % (img.url, result.label, img.url)) + self.include_image = True + return result + + # Media + def get_media(self, media): + if self.include_image: + media = media + self.vendor('image-gallery.js', + 'image-gallery.css') + return media + + def block_before_fieldsets(self, context, node): + if self.include_image: + return '" + + def block_extrabody(self, context, node): + if self.include_image: + return get_gallery_modal() + + +class ModelListPlugin(BaseAdminPlugin): + + list_gallery = False + + def init_request(self, *args, **kwargs): + return bool(self.list_gallery) + + # Media + def get_media(self, media): + return media + self.vendor('image-gallery.js', 'image-gallery.css') + + def block_results_top(self, context, node): + return '" + + def block_extrabody(self, context, node): + return get_gallery_modal() + + +site.register_plugin(ModelDetailPlugin, DetailAdminView) +site.register_plugin(ModelDetailPlugin, ModelFormAdminView) +site.register_plugin(ModelListPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/importexport.py b/extra_apps/xadmin/plugins/importexport.py new file mode 100644 index 0000000..507ae5e --- /dev/null +++ b/extra_apps/xadmin/plugins/importexport.py @@ -0,0 +1,462 @@ +#!/usr/bin/env python +# encoding=utf-8 +""" +Author:zcyuefan +Topic:django-import-export plugin for xadmin to help importing and exporting data using .csv/.xls/.../.json files + +Use: ++++ settings.py +++ +INSTALLED_APPS = ( + ... + 'import_export', +) + ++++ model.py +++ +from django.db import models + +class Foo(models.Model): + name = models.CharField(max_length=64) + description = models.TextField() + ++++ adminx.py +++ +import xadmin +from import_export import resources +from .models import Foo + +class FooResource(resources.ModelResource): + + class Meta: + model = Foo + # fields = ('name', 'description',) + # exclude = () + + +@xadmin.sites.register(Foo) +class FooAdmin(object): + import_export_args = {'import_resource_class': FooResource, 'export_resource_class': FooResource} + +++++++++++++++++ +More info about django-import-export please refer https://github.com/django-import-export/django-import-export +""" +from datetime import datetime +from django.template import loader +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView, ModelAdminView +from xadmin.views.base import csrf_protect_m, filter_hook +from django.db import transaction +from import_export.admin import DEFAULT_FORMATS, SKIP_ADMIN_LOG, TMP_STORAGE_CLASS +from import_export.resources import modelresource_factory +from import_export.forms import ( + ImportForm, + ConfirmImportForm, + ExportForm, +) +from import_export.results import RowResult +from import_export.signals import post_export, post_import +try: + from django.utils.encoding import force_text +except ImportError: + from django.utils.encoding import force_unicode as force_text +from django.utils.translation import ugettext_lazy as _ +from django.template.response import TemplateResponse +from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION +from django.contrib.contenttypes.models import ContentType +from django.contrib import messages +from django.urls.base import reverse +from django.core.exceptions import PermissionDenied +from django.http import HttpResponseRedirect, HttpResponse + + +class ImportMenuPlugin(BaseAdminPlugin): + import_export_args = {} + + def init_request(self, *args, **kwargs): + return bool(self.import_export_args.get('import_resource_class')) + + def block_top_toolbar(self, context, nodes): + has_change_perm = self.has_model_perm(self.model, 'change') + has_add_perm = self.has_model_perm(self.model, 'add') + if has_change_perm and has_add_perm: + model_info = (self.opts.app_label, self.opts.model_name) + import_url = reverse('xadmin:%s_%s_import' % model_info, current_app=self.admin_site.name) + context = get_context_dict(context or {}) # no error! + context.update({ + 'import_url': import_url, + }) + nodes.append(loader.render_to_string('xadmin/blocks/model_list.top_toolbar.importexport.import.html', + context=context)) + + +class ImportBaseView(ModelAdminView): + """ + """ + resource_class = None + import_export_args = {} + #: template for import view + import_template_name = 'xadmin/import_export/import.html' + #: resource class + #: available import formats + formats = DEFAULT_FORMATS + #: import data encoding + from_encoding = "utf-8" + skip_admin_log = None + # storage class for saving temporary files + tmp_storage_class = None + + def get_skip_admin_log(self): + if self.skip_admin_log is None: + return SKIP_ADMIN_LOG + else: + return self.skip_admin_log + + def get_tmp_storage_class(self): + if self.tmp_storage_class is None: + return TMP_STORAGE_CLASS + else: + return self.tmp_storage_class + + def get_resource_kwargs(self, request, *args, **kwargs): + return {} + + def get_import_resource_kwargs(self, request, *args, **kwargs): + return self.get_resource_kwargs(request, *args, **kwargs) + + def get_resource_class(self, usage): + if usage == 'import': + return self.import_export_args.get('import_resource_class') if self.import_export_args.get( + 'import_resource_class') else modelresource_factory(self.model) + elif usage == 'export': + return self.import_export_args.get('export_resource_class') if self.import_export_args.get( + 'export_resource_class') else modelresource_factory(self.model) + else: + return modelresource_factory(self.model) + + def get_import_resource_class(self): + """ + Returns ResourceClass to use for import. + """ + return self.process_import_resource(self.get_resource_class(usage='import')) + + def process_import_resource(self, resource): + """ + Returns processed ResourceClass to use for import. + Override to custom your own process + """ + return resource + + def get_import_formats(self): + """ + Returns available import formats. + """ + return [f for f in self.formats if f().can_import()] + + +class ImportView(ImportBaseView): + + def get_media(self): + media = super(ImportView, self).get_media() + media = media + self.vendor('xadmin.plugin.importexport.css') + return media + + @filter_hook + def get(self, request, *args, **kwargs): + if not (self.has_change_permission() and self.has_add_permission()): + raise PermissionDenied + + resource = self.get_import_resource_class()(**self.get_import_resource_kwargs(request, *args, **kwargs)) + + context = super(ImportView, self).get_context() + + import_formats = self.get_import_formats() + form = ImportForm(import_formats, + request.POST or None, + request.FILES or None) + + context['title'] = _("Import") + ' ' + self.opts.verbose_name + context['form'] = form + context['opts'] = self.model._meta + context['fields'] = [f.column_name for f in resource.get_user_visible_fields()] + + request.current_app = self.admin_site.name + return TemplateResponse(request, [self.import_template_name], + context) + + @filter_hook + @csrf_protect_m + @transaction.atomic + def post(self, request, *args, **kwargs): + """ + Perform a dry_run of the import to make sure the import will not + result in errors. If there where no error, save the user + uploaded file to a local temp file that will be used by + 'process_import' for the actual import. + """ + if not (self.has_change_permission() and self.has_add_permission()): + raise PermissionDenied + + resource = self.get_import_resource_class()(**self.get_import_resource_kwargs(request, *args, **kwargs)) + + context = super(ImportView, self).get_context() + + import_formats = self.get_import_formats() + form = ImportForm(import_formats, + request.POST or None, + request.FILES or None) + + if request.POST and form.is_valid(): + input_format = import_formats[ + int(form.cleaned_data['input_format']) + ]() + import_file = form.cleaned_data['import_file'] + # first always write the uploaded file to disk as it may be a + # memory file or else based on settings upload handlers + tmp_storage = self.get_tmp_storage_class()() + data = bytes() + for chunk in import_file.chunks(): + data += chunk + + tmp_storage.save(data, input_format.get_read_mode()) + + # then read the file, using the proper format-specific mode + # warning, big files may exceed memory + try: + data = tmp_storage.read(input_format.get_read_mode()) + if not input_format.is_binary() and self.from_encoding: + data = force_text(data, self.from_encoding) + dataset = input_format.create_dataset(data) + except UnicodeDecodeError as e: + return HttpResponse(_(u"

    Imported file has a wrong encoding: %s

    " % e)) + except Exception as e: + return HttpResponse(_(u"

    %s encountered while trying to read file: %s

    " % (type(e).__name__, + import_file.name))) + result = resource.import_data(dataset, dry_run=True, + raise_errors=False, + file_name=import_file.name, + user=request.user) + + context['result'] = result + + if not result.has_errors(): + context['confirm_form'] = ConfirmImportForm(initial={ + 'import_file_name': tmp_storage.name, + 'original_file_name': import_file.name, + 'input_format': form.cleaned_data['input_format'], + }) + + context['title'] = _("Import") + ' ' + self.opts.verbose_name + context['form'] = form + context['opts'] = self.model._meta + context['fields'] = [f.column_name for f in resource.get_user_visible_fields()] + + request.current_app = self.admin_site.name + return TemplateResponse(request, [self.import_template_name], + context) + + +class ImportProcessView(ImportBaseView): + + @filter_hook + @csrf_protect_m + @transaction.atomic + def post(self, request, *args, **kwargs): + """ + Perform the actual import action (after the user has confirmed he + wishes to import) + """ + resource = self.get_import_resource_class()(**self.get_import_resource_kwargs(request, *args, **kwargs)) + + confirm_form = ConfirmImportForm(request.POST) + if confirm_form.is_valid(): + import_formats = self.get_import_formats() + input_format = import_formats[ + int(confirm_form.cleaned_data['input_format']) + ]() + tmp_storage = self.get_tmp_storage_class()(name=confirm_form.cleaned_data['import_file_name']) + data = tmp_storage.read(input_format.get_read_mode()) + if not input_format.is_binary() and self.from_encoding: + data = force_text(data, self.from_encoding) + dataset = input_format.create_dataset(data) + + result = resource.import_data(dataset, dry_run=False, + raise_errors=True, + file_name=confirm_form.cleaned_data['original_file_name'], + user=request.user) + + if not self.get_skip_admin_log(): + # Add imported objects to LogEntry + logentry_map = { + RowResult.IMPORT_TYPE_NEW: ADDITION, + RowResult.IMPORT_TYPE_UPDATE: CHANGE, + RowResult.IMPORT_TYPE_DELETE: DELETION, + } + content_type_id = ContentType.objects.get_for_model(self.model).pk + for row in result: + if row.import_type != row.IMPORT_TYPE_ERROR and row.import_type != row.IMPORT_TYPE_SKIP: + LogEntry.objects.log_action( + user_id=request.user.pk, + content_type_id=content_type_id, + object_id=row.object_id, + object_repr=row.object_repr, + action_flag=logentry_map[row.import_type], + change_message="%s through import_export" % row.import_type, + ) + success_message = str(_(u'Import finished')) + ' , ' + str(_(u'Add')) + ' : %d' % result.totals[ + RowResult.IMPORT_TYPE_NEW] + ' , ' + str(_(u'Update')) + ' : %d' % result.totals[ + RowResult.IMPORT_TYPE_UPDATE] + + messages.success(request, success_message) + tmp_storage.remove() + + post_import.send(sender=None, model=self.model) + model_info = (self.opts.app_label, self.opts.model_name) + url = reverse('xadmin:%s_%s_changelist' % model_info, + current_app=self.admin_site.name) + return HttpResponseRedirect(url) + + +class ExportMixin(object): + #: resource class + resource_class = None + #: template for change_list view + change_list_template = None + import_export_args = {} + #: template for export view + # export_template_name = 'xadmin/import_export/export.html' + #: available export formats + formats = DEFAULT_FORMATS + #: export data encoding + to_encoding = "utf-8" + list_select_related = None + + def get_resource_kwargs(self, request, *args, **kwargs): + return {} + + def get_export_resource_kwargs(self, request, *args, **kwargs): + return self.get_resource_kwargs(request, *args, **kwargs) + + def get_resource_class(self, usage): + if usage == 'import': + return self.import_export_args.get('import_resource_class') if self.import_export_args.get( + 'import_resource_class') else modelresource_factory(self.model) + elif usage == 'export': + return self.import_export_args.get('export_resource_class') if self.import_export_args.get( + 'export_resource_class') else modelresource_factory(self.model) + else: + return modelresource_factory(self.model) + + def get_export_resource_class(self): + """ + Returns ResourceClass to use for export. + """ + return self.get_resource_class(usage='export') + + def get_export_formats(self): + """ + Returns available export formats. + """ + return [f for f in self.formats if f().can_export()] + + def get_export_filename(self, file_format): + date_str = datetime.now().strftime('%Y-%m-%d-%H%M%S') + filename = "%s-%s.%s" % (self.opts.verbose_name.encode('utf-8'), + date_str, + file_format.get_extension()) + return filename + + def get_export_queryset(self, request, context): + """ + Returns export queryset. + + Default implementation respects applied search and filters. + """ + # scope = self.request.POST.get('_select_across', False) == '1' + scope = request.GET.get('scope') + select_across = request.GET.get('_select_across', False) == '1' + selected = request.GET.get('_selected_actions', '') + if scope == 'all': + queryset = self.admin_view.queryset() + elif scope == 'header_only': + queryset = [] + elif scope == 'selected': + if not select_across: + selected_pk = selected.split(',') + queryset = self.admin_view.queryset().filter(pk__in=selected_pk) + else: + queryset = self.admin_view.queryset() + else: + queryset = [r['object'] for r in context['results']] + return queryset + + def get_export_data(self, file_format, queryset, *args, **kwargs): + """ + Returns file_format representation for given queryset. + """ + request = kwargs.pop("request") + resource_class = self.get_export_resource_class() + data = resource_class(**self.get_export_resource_kwargs(request)).export(queryset, *args, **kwargs) + export_data = file_format.export_data(data) + return export_data + + +class ExportMenuPlugin(ExportMixin, BaseAdminPlugin): + import_export_args = {} + + # Media + def get_media(self, media): + return media + self.vendor('xadmin.plugin.importexport.css', 'xadmin.plugin.importexport.js') + + def init_request(self, *args, **kwargs): + return bool(self.import_export_args.get('export_resource_class')) + + def block_top_toolbar(self, context, nodes): + formats = self.get_export_formats() + form = ExportForm(formats) + + context = get_context_dict(context or {}) # no error! + context.update({ + 'form': form, + 'opts': self.opts, + 'form_params': self.admin_view.get_form_params({'_action_': 'export'}), + }) + nodes.append(loader.render_to_string('xadmin/blocks/model_list.top_toolbar.importexport.export.html', + context=context)) + + +class ExportPlugin(ExportMixin, BaseAdminPlugin): + + def init_request(self, *args, **kwargs): + return self.request.GET.get('_action_') == 'export' + + def get_response(self, response, context, *args, **kwargs): + has_view_perm = self.has_model_perm(self.model, 'view') + if not has_view_perm: + raise PermissionDenied + + export_format = self.request.GET.get('file_format') + + if not export_format: + messages.warning(self.request, _('You must select an export format.')) + else: + formats = self.get_export_formats() + file_format = formats[int(export_format)]() + queryset = self.get_export_queryset(self.request, context) + export_data = self.get_export_data(file_format, queryset, request=self.request) + content_type = file_format.get_content_type() + # Django 1.7 uses the content_type kwarg instead of mimetype + try: + response = HttpResponse(export_data, content_type=content_type) + except TypeError: + response = HttpResponse(export_data, mimetype=content_type) + response['Content-Disposition'] = 'attachment; filename=%s' % ( + self.get_export_filename(file_format), + ) + post_export.send(sender=None, model=self.model) + return response + + +site.register_modelview(r'^import/$', ImportView, name='%s_%s_import') +site.register_modelview(r'^process_import/$', ImportProcessView, name='%s_%s_process_import') +site.register_plugin(ImportMenuPlugin, ListAdminView) +site.register_plugin(ExportMenuPlugin, ListAdminView) +site.register_plugin(ExportPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/inline.py b/extra_apps/xadmin/plugins/inline.py new file mode 100644 index 0000000..c959285 --- /dev/null +++ b/extra_apps/xadmin/plugins/inline.py @@ -0,0 +1,491 @@ +import copy +import inspect +from django import forms +from django.forms.formsets import all_valid, DELETION_FIELD_NAME +from django.forms.models import inlineformset_factory, BaseInlineFormSet, modelform_defines_fields +from django.contrib.contenttypes.forms import BaseGenericInlineFormSet, generic_inlineformset_factory +from django.template import loader +from django.template.loader import render_to_string +from django.contrib.auth import get_permission_codename +from django.utils import six +from django.utils.encoding import smart_text +from crispy_forms.utils import TEMPLATE_PACK + +from xadmin.layout import FormHelper, Layout, flatatt, Container, Column, Field, Fieldset +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ModelFormAdminView, DetailAdminView, filter_hook + + +class ShowField(Field): + template = "xadmin/layout/field_value.html" + + def __init__(self, admin_view, *args, **kwargs): + super(ShowField, self).__init__(*args, **kwargs) + self.admin_view = admin_view + if admin_view.style == 'table': + self.template = "xadmin/layout/field_value_td.html" + + def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs): + html = '' + detail = form.detail + for field in self.fields: + if not isinstance(form.fields[field].widget, forms.HiddenInput): + result = detail.get_field_result(field) + html += loader.render_to_string( + self.template, context={'field': form[field], 'result': result}) + return html + + +class DeleteField(Field): + + def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs): + if form.instance.pk: + self.attrs['type'] = 'hidden' + return super(DeleteField, self).render(form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs) + else: + return "" + + +class TDField(Field): + template = "xadmin/layout/td-field.html" + + +class InlineStyleManager(object): + inline_styles = {} + + def register_style(self, name, style): + self.inline_styles[name] = style + + def get_style(self, name='stacked'): + return self.inline_styles.get(name) + +style_manager = InlineStyleManager() + + +class InlineStyle(object): + template = 'xadmin/edit_inline/stacked.html' + + def __init__(self, view, formset): + self.view = view + self.formset = formset + + def update_layout(self, helper): + pass + + def get_attrs(self): + return {} +style_manager.register_style('stacked', InlineStyle) + + +class OneInlineStyle(InlineStyle): + template = 'xadmin/edit_inline/one.html' +style_manager.register_style("one", OneInlineStyle) + + +class AccInlineStyle(InlineStyle): + template = 'xadmin/edit_inline/accordion.html' +style_manager.register_style("accordion", AccInlineStyle) + + +class TabInlineStyle(InlineStyle): + template = 'xadmin/edit_inline/tab.html' +style_manager.register_style("tab", TabInlineStyle) + + +class TableInlineStyle(InlineStyle): + template = 'xadmin/edit_inline/tabular.html' + + def update_layout(self, helper): + helper.add_layout( + Layout(*[TDField(f) for f in self.formset[0].fields.keys()])) + + def get_attrs(self): + fields = [] + readonly_fields = [] + if len(self.formset): + fields = [f for k, f in self.formset[0].fields.items() if k != DELETION_FIELD_NAME] + readonly_fields = [f for f in getattr(self.formset[0], 'readonly_fields', [])] + return { + 'fields': fields, + 'readonly_fields': readonly_fields + } +style_manager.register_style("table", TableInlineStyle) + + +def replace_field_to_value(layout, av): + if layout: + cls_str = str if six.PY3 else basestring + for i, lo in enumerate(layout.fields): + if isinstance(lo, Field) or issubclass(lo.__class__, Field): + layout.fields[i] = ShowField(av, *lo.fields, **lo.attrs) + elif isinstance(lo, cls_str): + layout.fields[i] = ShowField(av, lo) + elif hasattr(lo, 'get_field_names'): + replace_field_to_value(lo, av) + + +class InlineModelAdmin(ModelFormAdminView): + + fk_name = None + formset = BaseInlineFormSet + extra = 3 + max_num = None + can_delete = True + fields = [] + admin_view = None + style = 'stacked' + + def init(self, admin_view): + self.admin_view = admin_view + self.parent_model = admin_view.model + self.org_obj = getattr(admin_view, 'org_obj', None) + self.model_instance = self.org_obj or admin_view.model() + + return self + + @filter_hook + def get_formset(self, **kwargs): + """Returns a BaseInlineFormSet class for use in admin add/change views.""" + if self.exclude is None: + exclude = [] + else: + exclude = list(self.exclude) + exclude.extend(self.get_readonly_fields()) + if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: + # Take the custom ModelForm's Meta.exclude into account only if the + # InlineModelAdmin doesn't define its own. + exclude.extend(self.form._meta.exclude) + # if exclude is an empty list we use None, since that's the actual + # default + exclude = exclude or None + can_delete = self.can_delete and self.has_delete_permission() + defaults = { + "form": self.form, + "formset": self.formset, + "fk_name": self.fk_name, + 'fields': forms.ALL_FIELDS, + "exclude": exclude, + "formfield_callback": self.formfield_for_dbfield, + "extra": self.extra, + "max_num": self.max_num, + "can_delete": can_delete, + } + defaults.update(kwargs) + + return inlineformset_factory(self.parent_model, self.model, **defaults) + + @filter_hook + def instance_form(self, **kwargs): + formset = self.get_formset(**kwargs) + attrs = { + 'instance': self.model_instance, + 'queryset': self.queryset() + } + if self.request_method == 'post': + attrs.update({ + 'data': self.request.POST, 'files': self.request.FILES, + 'save_as_new': "_saveasnew" in self.request.POST + }) + instance = formset(**attrs) + instance.view = self + + helper = FormHelper() + helper.form_tag = False + helper.include_media = False + # override form method to prevent render csrf_token in inline forms, see template 'bootstrap/whole_uni_form.html' + helper.form_method = 'get' + + style = style_manager.get_style( + 'one' if self.max_num == 1 else self.style)(self, instance) + style.name = self.style + + if len(instance): + layout = copy.deepcopy(self.form_layout) + + if layout is None: + layout = Layout(*instance[0].fields.keys()) + elif type(layout) in (list, tuple) and len(layout) > 0: + layout = Layout(*layout) + + rendered_fields = [i[1] for i in layout.get_field_names()] + layout.extend([f for f in instance[0] + .fields.keys() if f not in rendered_fields]) + + helper.add_layout(layout) + style.update_layout(helper) + + # replace delete field with Dynamic field, for hidden delete field when instance is NEW. + helper[DELETION_FIELD_NAME].wrap(DeleteField) + + instance.helper = helper + instance.style = style + + readonly_fields = self.get_readonly_fields() + if readonly_fields: + for form in instance: + form.readonly_fields = [] + inst = form.save(commit=False) + if inst: + meta_field_names = [field.name for field in inst._meta.get_fields()] + for readonly_field in readonly_fields: + value = None + label = None + if readonly_field in meta_field_names: + label = inst._meta.get_field(readonly_field).verbose_name + value = smart_text(getattr(inst, readonly_field)) + elif inspect.ismethod(getattr(inst, readonly_field, None)): + value = getattr(inst, readonly_field)() + label = getattr(getattr(inst, readonly_field), 'short_description', readonly_field) + elif inspect.ismethod(getattr(self, readonly_field, None)): + value = getattr(self, readonly_field)(inst) + label = getattr(getattr(self, readonly_field), 'short_description', readonly_field) + if value: + form.readonly_fields.append({'label': label, 'contents': value}) + return instance + + def has_auto_field(self, form): + if form._meta.model._meta.has_auto_field: + return True + for parent in form._meta.model._meta.get_parent_list(): + if parent._meta.has_auto_field: + return True + return False + + def queryset(self): + queryset = super(InlineModelAdmin, self).queryset() + if not self.has_change_permission() and not self.has_view_permission(): + queryset = queryset.none() + return queryset + + def has_add_permission(self): + if self.opts.auto_created: + return self.has_change_permission() + + codename = get_permission_codename('add', self.opts) + return self.user.has_perm("%s.%s" % (self.opts.app_label, codename)) + + def has_change_permission(self): + opts = self.opts + if opts.auto_created: + for field in opts.fields: + if field.remote_field and field.remote_field.model != self.parent_model: + opts = field.remote_field.model._meta + break + + codename = get_permission_codename('change', opts) + return self.user.has_perm("%s.%s" % (opts.app_label, codename)) + + def has_delete_permission(self): + if self.opts.auto_created: + return self.has_change_permission() + + codename = get_permission_codename('delete', self.opts) + return self.user.has_perm("%s.%s" % (self.opts.app_label, codename)) + + +class GenericInlineModelAdmin(InlineModelAdmin): + ct_field = "content_type" + ct_fk_field = "object_id" + + formset = BaseGenericInlineFormSet + + def get_formset(self, **kwargs): + if self.exclude is None: + exclude = [] + else: + exclude = list(self.exclude) + exclude.extend(self.get_readonly_fields()) + if self.exclude is None and hasattr(self.form, '_meta') and self.form._meta.exclude: + # Take the custom ModelForm's Meta.exclude into account only if the + # GenericInlineModelAdmin doesn't define its own. + exclude.extend(self.form._meta.exclude) + exclude = exclude or None + can_delete = self.can_delete and self.has_delete_permission() + defaults = { + "ct_field": self.ct_field, + "fk_field": self.ct_fk_field, + "form": self.form, + "formfield_callback": self.formfield_for_dbfield, + "formset": self.formset, + "extra": self.extra, + "can_delete": can_delete, + "can_order": False, + "max_num": self.max_num, + "exclude": exclude, + 'fields': forms.ALL_FIELDS + } + defaults.update(kwargs) + + return generic_inlineformset_factory(self.model, **defaults) + + +class InlineFormset(Fieldset): + + def __init__(self, formset, allow_blank=False, **kwargs): + self.fields = [] + self.css_class = kwargs.pop('css_class', '') + self.css_id = "%s-group" % formset.prefix + self.template = formset.style.template + self.inline_style = formset.style.name + if allow_blank and len(formset) == 0: + self.template = 'xadmin/edit_inline/blank.html' + self.inline_style = 'blank' + self.formset = formset + self.model = formset.model + self.opts = formset.model._meta + self.flat_attrs = flatatt(kwargs) + self.extra_attrs = formset.style.get_attrs() + + def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs): + context = get_context_dict(context) + context.update(dict( + formset=self, + prefix=self.formset.prefix, + inline_style=self.inline_style, + **self.extra_attrs + )) + return render_to_string(self.template, context) + + +class Inline(Fieldset): + + def __init__(self, rel_model): + self.model = rel_model + self.fields = [] + super(Inline, self).__init__(legend="") + + def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs): + return "" + + +def get_first_field(layout, clz): + for layout_object in layout.fields: + if issubclass(layout_object.__class__, clz): + return layout_object + elif hasattr(layout_object, 'get_field_names'): + gf = get_first_field(layout_object, clz) + if gf: + return gf + + +def replace_inline_objects(layout, fs): + if not fs: + return + for i, layout_object in enumerate(layout.fields): + if isinstance(layout_object, Inline) and layout_object.model in fs: + layout.fields[i] = fs.pop(layout_object.model) + elif hasattr(layout_object, 'get_field_names'): + replace_inline_objects(layout_object, fs) + + +class InlineFormsetPlugin(BaseAdminPlugin): + inlines = [] + + @property + def inline_instances(self): + if not hasattr(self, '_inline_instances'): + inline_instances = [] + for inline_class in self.inlines: + inline = self.admin_view.get_view( + (getattr(inline_class, 'generic_inline', False) and GenericInlineModelAdmin or InlineModelAdmin), + inline_class).init(self.admin_view) + if not (inline.has_add_permission() or + inline.has_change_permission() or + inline.has_delete_permission() or + inline.has_view_permission()): + continue + if not inline.has_add_permission(): + inline.max_num = 0 + inline_instances.append(inline) + self._inline_instances = inline_instances + + return self._inline_instances + + def instance_forms(self, ret): + self.formsets = [] + for inline in self.inline_instances: + if inline.has_change_permission(): + self.formsets.append(inline.instance_form()) + else: + self.formsets.append(self._get_detail_formset_instance(inline)) + self.admin_view.formsets = self.formsets + + def valid_forms(self, result): + return all_valid(self.formsets) and result + + def save_related(self): + for formset in self.formsets: + formset.instance = self.admin_view.new_obj + formset.save() + + def get_context(self, context): + context['inline_formsets'] = self.formsets + return context + + def get_error_list(self, errors): + for fs in self.formsets: + errors.extend(fs.non_form_errors()) + for errors_in_inline_form in fs.errors: + errors.extend(errors_in_inline_form.values()) + return errors + + def get_form_layout(self, layout): + allow_blank = isinstance(self.admin_view, DetailAdminView) + # fixed #176 bug, change dict to list + fs = [(f.model, InlineFormset(f, allow_blank)) for f in self.formsets] + replace_inline_objects(layout, fs) + + if fs: + container = get_first_field(layout, Column) + if not container: + container = get_first_field(layout, Container) + if not container: + container = layout + + # fixed #176 bug, change dict to list + for key, value in fs: + container.append(value) + + return layout + + def get_media(self, media): + for fs in self.formsets: + media = media + fs.media + if self.formsets: + media = media + self.vendor( + 'xadmin.plugin.formset.js', 'xadmin.plugin.formset.css') + return media + + def _get_detail_formset_instance(self, inline): + formset = inline.instance_form(extra=0, max_num=0, can_delete=0) + formset.detail_page = True + if True: + replace_field_to_value(formset.helper.layout, inline) + model = inline.model + opts = model._meta + fake_admin_class = type(str('%s%sFakeAdmin' % (opts.app_label, opts.model_name)), (object, ), {'model': model}) + for form in formset.forms: + instance = form.instance + if instance.pk: + form.detail = self.get_view( + DetailAdminUtil, fake_admin_class, instance) + return formset + + +class DetailAdminUtil(DetailAdminView): + + def init_request(self, obj): + self.obj = obj + self.org_obj = obj + + +class DetailInlineFormsetPlugin(InlineFormsetPlugin): + + def get_model_form(self, form, **kwargs): + self.formsets = [self._get_detail_formset_instance( + inline) for inline in self.inline_instances] + return form + +site.register_plugin(InlineFormsetPlugin, ModelFormAdminView) +site.register_plugin(DetailInlineFormsetPlugin, DetailAdminView) diff --git a/extra_apps/xadmin/plugins/language.py b/extra_apps/xadmin/plugins/language.py new file mode 100644 index 0000000..7c73b9d --- /dev/null +++ b/extra_apps/xadmin/plugins/language.py @@ -0,0 +1,27 @@ + +from django.conf import settings +from django.template import loader +from django.views.i18n import set_language +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, CommAdminView, BaseAdminView + + +class SetLangNavPlugin(BaseAdminPlugin): + + def block_top_navmenu(self, context, nodes): + context = get_context_dict(context) + context['redirect_to'] = self.request.get_full_path() + nodes.append(loader.render_to_string('xadmin/blocks/comm.top.setlang.html', context=context)) + + +class SetLangView(BaseAdminView): + + def post(self, request, *args, **kwargs): + if 'nav_menu' in request.session: + del request.session['nav_menu'] + return set_language(request) + +if settings.LANGUAGES and 'django.middleware.locale.LocaleMiddleware' in settings.MIDDLEWARE: + site.register_plugin(SetLangNavPlugin, CommAdminView) + site.register_view(r'^i18n/setlang/$', SetLangView, 'set_language') diff --git a/extra_apps/xadmin/plugins/layout.py b/extra_apps/xadmin/plugins/layout.py new file mode 100644 index 0000000..dd4f566 --- /dev/null +++ b/extra_apps/xadmin/plugins/layout.py @@ -0,0 +1,81 @@ +# coding=utf-8 +from django.template import loader +from django.utils.translation import ugettext_lazy as _ + +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView +from xadmin.util import label_for_field + +LAYOUT_VAR = '_layout' + +DEFAULT_LAYOUTS = { + 'table': { + 'key': 'table', + 'icon': 'fa fa-table', + 'name': _(u'Table'), + 'template': 'views/model_list.html', + }, + 'thumbnails': { + 'key': 'thumbnails', + 'icon': 'fa fa-th-large', + 'name': _(u'Thumbnails'), + 'template': 'grids/thumbnails.html', + }, +} + + +class GridLayoutPlugin(BaseAdminPlugin): + + grid_layouts = [] + + _active_layouts = [] + _current_layout = None + _current_icon = 'table' + + def get_layout(self, l): + item = (type(l) is dict) and l or DEFAULT_LAYOUTS[l] + return dict({'url': self.admin_view.get_query_string({LAYOUT_VAR: item['key']}), 'selected': False}, **item) + + def init_request(self, *args, **kwargs): + active = bool(self.request.method == 'GET' and self.grid_layouts) + if active: + layouts = (type(self.grid_layouts) in (list, tuple)) and self.grid_layouts or (self.grid_layouts,) + self._active_layouts = [self.get_layout(l) for l in layouts] + self._current_layout = self.request.GET.get(LAYOUT_VAR, self._active_layouts[0]['key']) + for layout in self._active_layouts: + if self._current_layout == layout['key']: + self._current_icon = layout['icon'] + layout['selected'] = True + self.admin_view.object_list_template = self.admin_view.get_template_list(layout['template']) + return active + + def result_item(self, item, obj, field_name, row): + if self._current_layout == 'thumbnails': + if getattr(item.attr, 'is_column', True): + item.field_label = label_for_field( + field_name, self.model, + model_admin=self.admin_view, + return_attr=False + ) + if getattr(item.attr, 'thumbnail_img', False): + setattr(item, 'thumbnail_hidden', True) + row['thumbnail_img'] = item + elif item.is_display_link: + setattr(item, 'thumbnail_hidden', True) + row['thumbnail_label'] = item + + return item + + # Block Views + def block_top_toolbar(self, context, nodes): + if len(self._active_layouts) > 1: + context.update({ + 'layouts': self._active_layouts, + 'current_icon': self._current_icon, + }) + nodes.append(loader.render_to_string('xadmin/blocks/model_list.top_toolbar.layouts.html', + context=get_context_dict(context))) + + +site.register_plugin(GridLayoutPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/mobile.py b/extra_apps/xadmin/plugins/mobile.py new file mode 100644 index 0000000..4c6a566 --- /dev/null +++ b/extra_apps/xadmin/plugins/mobile.py @@ -0,0 +1,30 @@ +#coding:utf-8 +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, CommAdminView + + +class MobilePlugin(BaseAdminPlugin): + + def _test_mobile(self): + try: + return self.request.META['HTTP_USER_AGENT'].find('Android') >= 0 or \ + self.request.META['HTTP_USER_AGENT'].find('iPhone') >= 0 + except Exception: + return False + + def init_request(self, *args, **kwargs): + return self._test_mobile() + + def get_context(self, context): + #context['base_template'] = 'xadmin/base_mobile.html' + context['is_mob'] = True + return context + + # Media + # def get_media(self, media): + # return media + self.vendor('xadmin.mobile.css', ) + + def block_extrahead(self, context, nodes): + nodes.append('') + +site.register_plugin(MobilePlugin, CommAdminView) diff --git a/extra_apps/xadmin/plugins/multiselect.py b/extra_apps/xadmin/plugins/multiselect.py new file mode 100644 index 0000000..0681af8 --- /dev/null +++ b/extra_apps/xadmin/plugins/multiselect.py @@ -0,0 +1,107 @@ +# coding:utf-8 +from itertools import chain + +import xadmin +from django import forms +from django.db.models import ManyToManyField +from django.forms.utils import flatatt +from django.template import loader +from django.utils.encoding import force_text +from django.utils.html import escape, conditional_escape +from django.utils.safestring import mark_safe +from xadmin.util import vendor +from xadmin.views import BaseAdminPlugin, ModelFormAdminView + + +class SelectMultipleTransfer(forms.SelectMultiple): + + @property + def media(self): + return vendor('xadmin.widget.select-transfer.js', 'xadmin.widget.select-transfer.css') + + def __init__(self, verbose_name, is_stacked, attrs=None, choices=()): + self.verbose_name = verbose_name + self.is_stacked = is_stacked + super(SelectMultipleTransfer, self).__init__(attrs, choices) + + def render_opt(self, selected_choices, option_value, option_label): + option_value = force_text(option_value) + return u'' % ( + escape(option_value), conditional_escape(force_text(option_label))), bool(option_value in selected_choices) + + def render(self, name, value, attrs=None, choices=()): + if attrs is None: + attrs = {} + attrs['class'] = '' + if self.is_stacked: + attrs['class'] += 'stacked' + if value is None: + value = [] + final_attrs = self.build_attrs(attrs, extra_attrs={'name': name}) + + selected_choices = set(force_text(v) for v in value) + available_output = [] + chosen_output = [] + + for option_value, option_label in chain(self.choices, choices): + if isinstance(option_label, (list, tuple)): + available_output.append(u'' % + escape(force_text(option_value))) + for option in option_label: + output, selected = self.render_opt( + selected_choices, *option) + if selected: + chosen_output.append(output) + else: + available_output.append(output) + available_output.append(u'') + else: + output, selected = self.render_opt( + selected_choices, option_value, option_label) + if selected: + chosen_output.append(output) + else: + available_output.append(output) + + context = { + 'verbose_name': self.verbose_name, + 'attrs': attrs, + 'field_id': attrs['id'], + 'flatatts': flatatt(final_attrs), + 'available_options': u'\n'.join(available_output), + 'chosen_options': u'\n'.join(chosen_output), + } + return mark_safe(loader.render_to_string('xadmin/forms/transfer.html', context)) + + +class SelectMultipleDropdown(forms.SelectMultiple): + + @property + def media(self): + return vendor('multiselect.js', 'multiselect.css', 'xadmin.widget.multiselect.js') + + def render(self, name, value, attrs=None, choices=()): + if attrs is None: + attrs = {} + attrs['class'] = 'selectmultiple selectdropdown' + return super(SelectMultipleDropdown, self).render(name, value, attrs, choices) + + +class M2MSelectPlugin(BaseAdminPlugin): + + def init_request(self, *args, **kwargs): + return hasattr(self.admin_view, 'style_fields') and \ + ( + 'm2m_transfer' in self.admin_view.style_fields.values() or + 'm2m_dropdown' in self.admin_view.style_fields.values() + ) + + def get_field_style(self, attrs, db_field, style, **kwargs): + if style == 'm2m_transfer' and isinstance(db_field, ManyToManyField): + return {'widget': SelectMultipleTransfer(db_field.verbose_name, False), 'help_text': ''} + if style == 'm2m_dropdown' and isinstance(db_field, ManyToManyField): + return {'widget': SelectMultipleDropdown, 'help_text': ''} + return attrs + + +xadmin.site.register_plugin(M2MSelectPlugin, ModelFormAdminView) diff --git a/extra_apps/xadmin/plugins/passwords.py b/extra_apps/xadmin/plugins/passwords.py new file mode 100644 index 0000000..a5f3eeb --- /dev/null +++ b/extra_apps/xadmin/plugins/passwords.py @@ -0,0 +1,115 @@ +# coding=utf-8 +from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm +from django.contrib.auth.tokens import default_token_generator +from django.contrib.auth.views import PasswordResetConfirmView as password_reset_confirm +from django.template.response import TemplateResponse +from django.utils.translation import ugettext as _ + +from xadmin.sites import site +from xadmin.views.base import BaseAdminPlugin, BaseAdminView, csrf_protect_m +from xadmin.views.website import LoginView + + +class ResetPasswordSendView(BaseAdminView): + + need_site_permission = False + + password_reset_form = PasswordResetForm + password_reset_template = 'xadmin/auth/password_reset/form.html' + password_reset_done_template = 'xadmin/auth/password_reset/done.html' + password_reset_token_generator = default_token_generator + + password_reset_from_email = None + password_reset_email_template = 'xadmin/auth/password_reset/email.html' + password_reset_subject_template = None + + def get(self, request, *args, **kwargs): + context = super(ResetPasswordSendView, self).get_context() + context['form'] = kwargs.get('form', self.password_reset_form()) + + return TemplateResponse(request, self.password_reset_template, context) + + @csrf_protect_m + def post(self, request, *args, **kwargs): + form = self.password_reset_form(request.POST) + + if form.is_valid(): + opts = { + 'use_https': request.is_secure(), + 'token_generator': self.password_reset_token_generator, + 'email_template_name': self.password_reset_email_template, + 'request': request, + 'domain_override': request.get_host() + } + + if self.password_reset_from_email: + opts['from_email'] = self.password_reset_from_email + if self.password_reset_subject_template: + opts['subject_template_name'] = self.password_reset_subject_template + + form.save(**opts) + context = super(ResetPasswordSendView, self).get_context() + return TemplateResponse(request, self.password_reset_done_template, context) + else: + return self.get(request, form=form) + + +site.register_view(r'^xadmin/password_reset/$', ResetPasswordSendView, name='xadmin_password_reset') + + +class ResetLinkPlugin(BaseAdminPlugin): + + def block_form_bottom(self, context, nodes): + reset_link = self.get_admin_url('xadmin_password_reset') + return '' % (reset_link, _('Forgotten your password or username?')) + + +site.register_plugin(ResetLinkPlugin, LoginView) + + +class ResetPasswordComfirmView(BaseAdminView): + + need_site_permission = False + + password_reset_set_form = SetPasswordForm + password_reset_confirm_template = 'xadmin/auth/password_reset/confirm.html' + password_reset_token_generator = default_token_generator + + def do_view(self, request, uidb36, token, *args, **kwargs): + context = super(ResetPasswordComfirmView, self).get_context() + return password_reset_confirm(request, uidb36, token, + template_name=self.password_reset_confirm_template, + token_generator=self.password_reset_token_generator, + set_password_form=self.password_reset_set_form, + post_reset_redirect=self.get_admin_url('xadmin_password_reset_complete'), + current_app=self.admin_site.name, extra_context=context) + + def get(self, request, uidb36, token, *args, **kwargs): + return self.do_view(request, uidb36, token) + + def post(self, request, uidb36, token, *args, **kwargs): + return self.do_view(request, uidb36, token) + + def get_media(self): + return super(ResetPasswordComfirmView, self).get_media() + \ + self.vendor('xadmin.page.form.js', 'xadmin.form.css') + + +site.register_view(r'^xadmin/password_reset/(?P[0-9A-Za-z]{1,13})-(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', + ResetPasswordComfirmView, name='xadmin_password_reset_confirm') + + +class ResetPasswordCompleteView(BaseAdminView): + + need_site_permission = False + + password_reset_complete_template = 'xadmin/auth/password_reset/complete.html' + + def get(self, request, *args, **kwargs): + context = super(ResetPasswordCompleteView, self).get_context() + context['login_url'] = self.get_admin_url('index') + + return TemplateResponse(request, self.password_reset_complete_template, context) + + +site.register_view(r'^xadmin/password_reset/complete/$', ResetPasswordCompleteView, name='xadmin_password_reset_complete') diff --git a/extra_apps/xadmin/plugins/portal.py b/extra_apps/xadmin/plugins/portal.py new file mode 100644 index 0000000..40199a2 --- /dev/null +++ b/extra_apps/xadmin/plugins/portal.py @@ -0,0 +1,74 @@ +#coding:utf-8 +from xadmin.sites import site +from xadmin.models import UserSettings +from xadmin.views import BaseAdminPlugin, ModelFormAdminView, DetailAdminView +from xadmin.layout import Fieldset, Column + + +class BasePortalPlugin(BaseAdminPlugin): + + # Media + def get_media(self, media): + return media + self.vendor('xadmin.plugin.portal.js') + + +def get_layout_objects(layout, clz, objects): + for i, layout_object in enumerate(layout.fields): + if layout_object.__class__ is clz or issubclass(layout_object.__class__, clz): + objects.append(layout_object) + elif hasattr(layout_object, 'get_field_names'): + get_layout_objects(layout_object, clz, objects) + + +class ModelFormPlugin(BasePortalPlugin): + + def _portal_key(self): + return '%s_%s_editform_portal' % (self.opts.app_label, self.opts.model_name) + + def get_form_helper(self, helper): + cs = [] + layout = helper.layout + get_layout_objects(layout, Column, cs) + for i, c in enumerate(cs): + if not getattr(c, 'css_id', None): + c.css_id = 'column-%d' % i + + # make fieldset index + fs = [] + get_layout_objects(layout, Fieldset, fs) + fs_map = {} + for i, f in enumerate(fs): + if not getattr(f, 'css_id', None): + f.css_id = 'box-%d' % i + fs_map[f.css_id] = f + + try: + layout_pos = UserSettings.objects.get( + user=self.user, key=self._portal_key()).value + layout_cs = layout_pos.split('|') + for i, c in enumerate(cs): + c.fields = [fs_map.pop(j) for j in layout_cs[i].split( + ',') if j in fs_map] if len(layout_cs) > i else [] + if fs_map and cs: + cs[0].fields.extend(fs_map.values()) + except Exception: + pass + + return helper + + def block_form_top(self, context, node): + # put portal key and submit url to page + return "" % self._portal_key() + + +class ModelDetailPlugin(ModelFormPlugin): + + def _portal_key(self): + return '%s_%s_detail_portal' % (self.opts.app_label, self.opts.model_name) + + def block_after_fieldsets(self, context, node): + # put portal key and submit url to page + return "" % self._portal_key() + +site.register_plugin(ModelFormPlugin, ModelFormAdminView) +site.register_plugin(ModelDetailPlugin, DetailAdminView) diff --git a/extra_apps/xadmin/plugins/quickfilter.py b/extra_apps/xadmin/plugins/quickfilter.py new file mode 100644 index 0000000..59b3ecc --- /dev/null +++ b/extra_apps/xadmin/plugins/quickfilter.py @@ -0,0 +1,168 @@ +''' +Created on Mar 26, 2014 + +@author: LAB_ADM +''' +from future.utils import iteritems +from django.utils import six +from django.utils.translation import ugettext_lazy as _ +from xadmin.filters import manager, MultiSelectFieldListFilter +from xadmin.plugins.filters import * +from xadmin.util import is_related_field + + +@manager.register +class QuickFilterMultiSelectFieldListFilter(MultiSelectFieldListFilter): + """ Delegates the filter to the default filter and ors the results of each + + Lists the distinct values of each field as a checkbox + Uses the default spec for each + + """ + template = 'xadmin/filters/quickfilter.html' + + +class QuickFilterPlugin(BaseAdminPlugin): + """ Add a filter menu to the left column of the page """ + list_quick_filter = () # these must be a subset of list_filter to work + quickfilter = {} + search_fields = () + free_query_filter = True + + def init_request(self, *args, **kwargs): + menu_style_accordian = hasattr(self.admin_view, 'menu_style') and self.admin_view.menu_style == 'accordion' + return bool(self.list_quick_filter) and not menu_style_accordian + + # Media + def get_media(self, media): + return media + self.vendor('xadmin.plugin.quickfilter.js', 'xadmin.plugin.quickfilter.css') + + def lookup_allowed(self, lookup, value): + model = self.model + # Check FKey lookups that are allowed, so that popups produced by + # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, + # are allowed to work. + for l in model._meta.related_fkey_lookups: + for k, v in widgets.url_params_from_lookup_dict(l).items(): + if k == lookup and v == value: + return True + + parts = lookup.split(LOOKUP_SEP) + + # Last term in lookup is a query term (__exact, __startswith etc) + # This term can be ignored. + if len(parts) > 1 and parts[-1] in QUERY_TERMS: + parts.pop() + + # Special case -- foo__id__exact and foo__id queries are implied + # if foo has been specificially included in the lookup list; so + # drop __id if it is the last part. However, first we need to find + # the pk attribute name. + rel_name = None + for part in parts[:-1]: + try: + field = model._meta.get_field(part) + except FieldDoesNotExist: + # Lookups on non-existants fields are ok, since they're ignored + # later. + return True + if hasattr(field, 'remote_field'): + model = field.remote_field.model + rel_name = field.remote_field.get_related_field().name + elif is_related_field(field): + model = field.model + rel_name = model._meta.pk.name + else: + rel_name = None + if rel_name and len(parts) > 1 and parts[-1] == rel_name: + parts.pop() + + if len(parts) == 1: + return True + clean_lookup = LOOKUP_SEP.join(parts) + return clean_lookup in self.list_quick_filter + + def get_list_queryset(self, queryset): + lookup_params = dict([(smart_str(k)[len(FILTER_PREFIX):], v) for k, v in self.admin_view.params.items() if smart_str(k).startswith(FILTER_PREFIX) and v != '']) + for p_key, p_val in iteritems(lookup_params): + if p_val == "False": + lookup_params[p_key] = False + use_distinct = False + + if not hasattr(self.admin_view, 'quickfilter'): + self.admin_view.quickfilter = {} + + # for clean filters + self.admin_view.quickfilter['has_query_param'] = bool(lookup_params) + self.admin_view.quickfilter['clean_query_url'] = self.admin_view.get_query_string(remove=[k for k in self.request.GET.keys() if k.startswith(FILTER_PREFIX)]) + + # Normalize the types of keys + if not self.free_query_filter: + for key, value in lookup_params.items(): + if not self.lookup_allowed(key, value): + raise SuspiciousOperation("Filtering by %s not allowed" % key) + + self.filter_specs = [] + if self.list_quick_filter: + for list_quick_filter in self.list_quick_filter: + field_path = None + field_order_by = None + field_limit = None + field_parts = [] + sort_key = None + cache_config = None + + if type(list_quick_filter) == dict and 'field' in list_quick_filter: + field = list_quick_filter['field'] + if 'order_by' in list_quick_filter: + field_order_by = list_quick_filter['order_by'] + if 'limit' in list_quick_filter: + field_limit = list_quick_filter['limit'] + if 'sort' in list_quick_filter and callable(list_quick_filter['sort']): + sort_key = list_quick_filter['sort'] + if 'cache' in list_quick_filter and type(list_quick_filter) == dict: + cache_config = list_quick_filter['cache'] + + else: + field = list_quick_filter # This plugin only uses MultiselectFieldListFilter + + if not isinstance(field, models.Field): + field_path = field + field_parts = get_fields_from_path(self.model, field_path) + field = field_parts[-1] + spec = QuickFilterMultiSelectFieldListFilter(field, self.request, lookup_params, self.model, self.admin_view, field_path=field_path, + field_order_by=field_order_by, field_limit=field_limit, sort_key=sort_key, cache_config=cache_config) + + if len(field_parts) > 1: + spec.title = "%s %s" % (field_parts[-2].name, spec.title) + + # Check if we need to use distinct() + use_distinct = True # (use_distinct orlookup_needs_distinct(self.opts, field_path)) + if spec and spec.has_output(): + try: + new_qs = spec.do_filte(queryset) + except ValidationError as e: + new_qs = None + self.admin_view.message_user(_("Filtering error: %s") % e.messages[0], 'error') + if new_qs is not None: + queryset = new_qs + + self.filter_specs.append(spec) + + self.has_filters = bool(self.filter_specs) + self.admin_view.quickfilter['filter_specs'] = self.filter_specs + obj = filter(lambda f: f.is_used, self.filter_specs) + if six.PY3: + obj = list(obj) + self.admin_view.quickfilter['used_filter_num'] = len(obj) + + if use_distinct: + return queryset.distinct() + else: + return queryset + + def block_left_navbar(self, context, nodes): + nodes.append(loader.render_to_string('xadmin/blocks/modal_list.left_navbar.quickfilter.html', + get_context_dict(context))) + +site.register_plugin(QuickFilterPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/quickform.py b/extra_apps/xadmin/plugins/quickform.py new file mode 100644 index 0000000..7516f68 --- /dev/null +++ b/extra_apps/xadmin/plugins/quickform.py @@ -0,0 +1,110 @@ +from django.db import models +from django import forms +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext as _ +from django.forms.models import modelform_factory +import copy +from xadmin.sites import site +from xadmin.util import get_model_from_relation, vendor +from xadmin.views import BaseAdminPlugin, ModelFormAdminView +from xadmin.layout import Layout + + +class QuickFormPlugin(BaseAdminPlugin): + + def init_request(self, *args, **kwargs): + if self.request.method == 'GET' and self.request.is_ajax() or self.request.GET.get('_ajax'): + self.admin_view.add_form_template = 'xadmin/views/quick_form.html' + self.admin_view.change_form_template = 'xadmin/views/quick_form.html' + return True + return False + + def get_model_form(self, __, **kwargs): + if '_field' in self.request.GET: + defaults = { + "form": self.admin_view.form, + "fields": self.request.GET['_field'].split(','), + "formfield_callback": self.admin_view.formfield_for_dbfield, + } + return modelform_factory(self.model, **defaults) + return __() + + def get_form_layout(self, __): + if '_field' in self.request.GET: + return Layout(*self.request.GET['_field'].split(',')) + return __() + + def get_context(self, context): + context['form_url'] = self.request.path + return context + + +class RelatedFieldWidgetWrapper(forms.Widget): + """ + This class is a wrapper to a given widget to add the add icon for the + admin interface. + """ + + def __init__(self, widget, rel, add_url, rel_add_url): + self.needs_multipart_form = widget.needs_multipart_form + self.attrs = widget.attrs + self.choices = widget.choices + self.is_required = widget.is_required + self.widget = widget + self.rel = rel + + self.add_url = add_url + self.rel_add_url = rel_add_url + + if hasattr(self, 'input_type'): + self.input_type = widget.input_type + + def __deepcopy__(self, memo): + obj = copy.copy(self) + obj.widget = copy.deepcopy(self.widget, memo) + obj.attrs = self.widget.attrs + memo[id(self)] = obj + return obj + + @property + def media(self): + media = self.widget.media + vendor('xadmin.plugin.quick-form.js') + return media + + def render(self, name, value, renderer=None, *args, **kwargs): + self.widget.choices = self.choices + output = [] + if self.add_url: + output.append(u'' + % ( + self.add_url, (_('Create New %s') % self.rel.model._meta.verbose_name), name, + "%s?_field=%s&%s=" % (self.rel_add_url, name, name))) + output.extend(['
    ' % name, + self.widget.render(name, value, *args, **kwargs), '
    ']) + return mark_safe(u''.join(output)) + + def build_attrs(self, extra_attrs=None, **kwargs): + "Helper function for building an attribute dictionary." + self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs) + return self.attrs + + def value_from_datadict(self, data, files, name): + return self.widget.value_from_datadict(data, files, name) + + def id_for_label(self, id_): + return self.widget.id_for_label(id_) + + +class QuickAddBtnPlugin(BaseAdminPlugin): + + def formfield_for_dbfield(self, formfield, db_field, **kwargs): + if formfield and self.model in self.admin_site._registry and isinstance(db_field, (models.ForeignKey, models.ManyToManyField)): + rel_model = get_model_from_relation(db_field) + if rel_model in self.admin_site._registry and self.has_model_perm(rel_model, 'add'): + add_url = self.get_model_url(rel_model, 'add') + formfield.widget = RelatedFieldWidgetWrapper( + formfield.widget, db_field.remote_field, add_url, self.get_model_url(self.model, 'add')) + return formfield + +site.register_plugin(QuickFormPlugin, ModelFormAdminView) +site.register_plugin(QuickAddBtnPlugin, ModelFormAdminView) diff --git a/extra_apps/xadmin/plugins/refresh.py b/extra_apps/xadmin/plugins/refresh.py new file mode 100644 index 0000000..a1341a2 --- /dev/null +++ b/extra_apps/xadmin/plugins/refresh.py @@ -0,0 +1,39 @@ +# coding=utf-8 +from django.template import loader + +from xadmin.plugins.utils import get_context_dict +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView + +REFRESH_VAR = '_refresh' + + +class RefreshPlugin(BaseAdminPlugin): + + refresh_times = [] + + # Media + def get_media(self, media): + if self.refresh_times and self.request.GET.get(REFRESH_VAR): + media = media + self.vendor('xadmin.plugin.refresh.js') + return media + + # Block Views + def block_top_toolbar(self, context, nodes): + if self.refresh_times: + current_refresh = self.request.GET.get(REFRESH_VAR) + context.update({ + 'has_refresh': bool(current_refresh), + 'clean_refresh_url': self.admin_view.get_query_string(remove=(REFRESH_VAR,)), + 'current_refresh': current_refresh, + 'refresh_times': [{ + 'time': r, + 'url': self.admin_view.get_query_string({REFRESH_VAR: r}), + 'selected': str(r) == current_refresh, + } for r in self.refresh_times], + }) + nodes.append(loader.render_to_string('xadmin/blocks/model_list.top_toolbar.refresh.html', + get_context_dict(context))) + + +site.register_plugin(RefreshPlugin, ListAdminView) diff --git a/extra_apps/xadmin/plugins/relate.py b/extra_apps/xadmin/plugins/relate.py new file mode 100644 index 0000000..3164275 --- /dev/null +++ b/extra_apps/xadmin/plugins/relate.py @@ -0,0 +1,240 @@ +# coding=UTF-8 +from itertools import chain + +from django.urls.base import reverse +from django.db.models.options import PROXY_PARENTS +from django.utils import six +from django.utils.encoding import force_text +from django.utils.encoding import smart_str +from django.utils.safestring import mark_safe +from django.db.models.sql.query import LOOKUP_SEP +from django.utils.translation import ugettext as _ +from django.db import models + + +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ListAdminView, CreateAdminView, UpdateAdminView, DeleteAdminView +from xadmin.util import is_related_field2 + +RELATE_PREFIX = '_rel_' + + +class RelateMenuPlugin(BaseAdminPlugin): + + related_list = [] + use_related_menu = True + + def _get_all_related_objects(self, local_only=False, include_hidden=False, + include_proxy_eq=False): + """ + Returns a list of related fields (also many to many) + :param local_only: + :param include_hidden: + :return: list + """ + include_parents = True if local_only is False else PROXY_PARENTS + fields = self.opts._get_fields( + forward=False, reverse=True, + include_parents=include_parents, + include_hidden=include_hidden + ) + if include_proxy_eq: + children = chain.from_iterable(c._relation_tree + for c in self.opts.concrete_model._meta.proxied_children + if c is not self.opts) + relations = (f.remote_field for f in children + if include_hidden or not f.remote_field.field.remote_field.is_hidden()) + fields = chain(fields, relations) + return list(fields) + + def get_related_list(self): + if hasattr(self, '_related_acts'): + return self._related_acts + + _related_acts = [] + for rel in self._get_all_related_objects(): + if self.related_list and (rel.get_accessor_name() not in self.related_list): + continue + if rel.related_model not in self.admin_site._registry.keys(): + continue + has_view_perm = self.has_model_perm(rel.related_model, 'view') + has_add_perm = self.has_model_perm(rel.related_model, 'add') + if not (has_view_perm or has_add_perm): + continue + + _related_acts.append((rel, has_view_perm, has_add_perm)) + + self._related_acts = _related_acts + return self._related_acts + + def related_link(self, instance): + links = [] + for rel, view_perm, add_perm in self.get_related_list(): + opts = rel.related_model._meta + + label = opts.app_label + model_name = opts.model_name + + field = rel.field + rel_name = rel.get_related_field().name + + verbose_name = force_text(opts.verbose_name) + lookup_name = '%s__%s__exact' % (field.name, rel_name) + + link = ''.join(('
  • ', + + ' %s' % + ( + reverse('%s:%s_%s_changelist' % ( + self.admin_site.app_name, label, model_name)), + RELATE_PREFIX + lookup_name, str(instance.pk), verbose_name, verbose_name) if view_perm else + ' %s' % verbose_name, + + '' % + ( + reverse('%s:%s_%s_add' % ( + self.admin_site.app_name, label, model_name)), + RELATE_PREFIX + lookup_name, str( + instance.pk)) if add_perm else "", + + '
  • ')) + links.append(link) + ul_html = '' % ''.join( + links) + return '' % (_('Related Objects'), ul_html) + related_link.short_description = ' ' + related_link.allow_tags = True + related_link.allow_export = False + related_link.is_column = False + + def get_list_display(self, list_display): + if self.use_related_menu and len(self.get_related_list()): + list_display.append('related_link') + self.admin_view.related_link = self.related_link + return list_display + + +class RelateObject(object): + + def __init__(self, admin_view, lookup, value): + self.admin_view = admin_view + self.org_model = admin_view.model + self.opts = admin_view.opts + self.lookup = lookup + self.value = value + + parts = lookup.split(LOOKUP_SEP) + field = self.opts.get_field(parts[0]) + + if not is_related_field2(field): + raise Exception(u'Relate Lookup field must a related field') + + self.to_model = field.related_model + self.rel_name = '__'.join(parts[1:]) + self.is_m2m = bool(field.many_to_many) + + to_qs = self.to_model._default_manager.get_queryset() + self.to_objs = to_qs.filter(**{self.rel_name: value}).all() + + self.field = field + + def filter(self, queryset): + return queryset.filter(**{self.lookup: self.value}) + + def get_brand_name(self): + if len(self.to_objs) == 1: + to_model_name = str(self.to_objs[0]) + else: + to_model_name = force_text(self.to_model._meta.verbose_name) + + return mark_safe(u"%s %s" % (to_model_name, force_text(self.opts.verbose_name_plural))) + + +class BaseRelateDisplayPlugin(BaseAdminPlugin): + + def init_request(self, *args, **kwargs): + self.relate_obj = None + for k, v in self.request.GET.items(): + if smart_str(k).startswith(RELATE_PREFIX): + self.relate_obj = RelateObject( + self.admin_view, smart_str(k)[len(RELATE_PREFIX):], v) + break + return bool(self.relate_obj) + + def _get_relate_params(self): + return RELATE_PREFIX + self.relate_obj.lookup, self.relate_obj.value + + def _get_input(self): + return '' % self._get_relate_params() + + def _get_url(self, url): + return url + ('&' if url.find('?') > 0 else '?') + ('%s=%s' % self._get_relate_params()) + + +class ListRelateDisplayPlugin(BaseRelateDisplayPlugin): + + def get_list_queryset(self, queryset): + if self.relate_obj: + queryset = self.relate_obj.filter(queryset) + return queryset + + def url_for_result(self, url, result): + return self._get_url(url) + + def get_context(self, context): + context['brand_name'] = self.relate_obj.get_brand_name() + context['rel_objs'] = self.relate_obj.to_objs + if len(self.relate_obj.to_objs) == 1: + context['rel_obj'] = self.relate_obj.to_objs[0] + if 'add_url' in context: + context['add_url'] = self._get_url(context['add_url']) + return context + + def get_list_display(self, list_display): + if not self.relate_obj.is_m2m: + try: + list_display.remove(self.relate_obj.field.name) + except Exception: + pass + return list_display + + +class EditRelateDisplayPlugin(BaseRelateDisplayPlugin): + + def get_form_datas(self, datas): + if self.admin_view.org_obj is None and self.admin_view.request_method == 'get': + datas['initial'][ + self.relate_obj.field.name] = self.relate_obj.value + return datas + + def post_response(self, response): + cls_str = str if six.PY3 else basestring + if isinstance(response, cls_str) and response != self.get_admin_url('index'): + return self._get_url(response) + return response + + def get_context(self, context): + if 'delete_url' in context: + context['delete_url'] = self._get_url(context['delete_url']) + return context + + def block_after_fieldsets(self, context, nodes): + return self._get_input() + + +class DeleteRelateDisplayPlugin(BaseRelateDisplayPlugin): + + def post_response(self, response): + cls_str = str if six.PY3 else basestring + if isinstance(response, cls_str) and response != self.get_admin_url('index'): + return self._get_url(response) + return response + + def block_form_fields(self, context, nodes): + return self._get_input() + +site.register_plugin(RelateMenuPlugin, ListAdminView) +site.register_plugin(ListRelateDisplayPlugin, ListAdminView) +site.register_plugin(EditRelateDisplayPlugin, CreateAdminView) +site.register_plugin(EditRelateDisplayPlugin, UpdateAdminView) +site.register_plugin(DeleteRelateDisplayPlugin, DeleteAdminView) diff --git a/extra_apps/xadmin/plugins/relfield.py b/extra_apps/xadmin/plugins/relfield.py new file mode 100644 index 0000000..19b403e --- /dev/null +++ b/extra_apps/xadmin/plugins/relfield.py @@ -0,0 +1,84 @@ +from django.db import models +from django.forms.utils import flatatt +from django.utils.html import escape, format_html +from django.utils.safestring import mark_safe +from django.utils.text import Truncator +from django.utils.translation import ugettext as _ +from django import forms +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ModelFormAdminView +from xadmin.util import vendor + + +class ForeignKeySearchWidget(forms.Widget): + + def __init__(self, rel, admin_view, attrs=None, using=None): + self.rel = rel + self.admin_view = admin_view + self.db = using + super(ForeignKeySearchWidget, self).__init__(attrs) + + def build_attrs(self, attrs={}, extra_attrs=None, **kwargs): + to_opts = self.rel.model._meta + if "class" not in attrs: + attrs['class'] = 'select-search' + else: + attrs['class'] = attrs['class'] + ' select-search' + attrs['data-search-url'] = self.admin_view.get_admin_url( + '%s_%s_changelist' % (to_opts.app_label, to_opts.model_name)) + attrs['data-placeholder'] = _('Search %s') % to_opts.verbose_name + attrs['data-choices'] = '?' + if self.rel.limit_choices_to: + for i in list(self.rel.limit_choices_to): + attrs['data-choices'] += "&_p_%s=%s" % (i, self.rel.limit_choices_to[i]) + attrs['data-choices'] = format_html(attrs['data-choices']) + attrs.update(kwargs) + return super(ForeignKeySearchWidget, self).build_attrs(attrs, extra_attrs=extra_attrs) + + def render(self, name, value, attrs=None): + final_attrs = self.build_attrs(attrs, extra_attrs={'name': name}) + output = [format_html('', flatatt(final_attrs))] + if value: + output.append(format_html('', value, self.label_for_value(value))) + output.append('') + return mark_safe('\n'.join(output)) + + def label_for_value(self, value): + key = self.rel.get_related_field().name + try: + obj = self.rel.to._default_manager.using( + self.db).get(**{key: value}) + return '%s' % escape(Truncator(obj).words(14, truncate='...')) + except (ValueError, self.rel.to.DoesNotExist): + return "" + + @property + def media(self): + return vendor('select.js', 'select.css', 'xadmin.widget.select.js') + + +class ForeignKeySelectWidget(ForeignKeySearchWidget): + + def build_attrs(self, attrs={}, **kwargs): + attrs = super(ForeignKeySelectWidget, self).build_attrs(attrs, **kwargs) + if "class" not in attrs: + attrs['class'] = 'select-preload' + else: + attrs['class'] = attrs['class'] + ' select-preload' + attrs['data-placeholder'] = _('Select %s') % self.rel.model._meta.verbose_name + return attrs + + +class RelateFieldPlugin(BaseAdminPlugin): + + def get_field_style(self, attrs, db_field, style, **kwargs): + # search able fk field + if style in ('fk-ajax', 'fk-select') and isinstance(db_field, models.ForeignKey): + if (db_field.remote_field.to in self.admin_view.admin_site._registry) and \ + self.has_model_perm(db_field.remote_field.to, 'view'): + db = kwargs.get('using') + return dict(attrs or {}, + widget=(style == 'fk-ajax' and ForeignKeySearchWidget or ForeignKeySelectWidget)(db_field.remote_field, self.admin_view, using=db)) + return attrs + +site.register_plugin(RelateFieldPlugin, ModelFormAdminView) diff --git a/extra_apps/xadmin/plugins/sitemenu.py b/extra_apps/xadmin/plugins/sitemenu.py new file mode 100644 index 0000000..02acdd1 --- /dev/null +++ b/extra_apps/xadmin/plugins/sitemenu.py @@ -0,0 +1,22 @@ + +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, CommAdminView + +BUILDIN_STYLES = { + 'default': 'xadmin/includes/sitemenu_default.html', + 'accordion': 'xadmin/includes/sitemenu_accordion.html', +} + + +class SiteMenuStylePlugin(BaseAdminPlugin): + + menu_style = None + + def init_request(self, *args, **kwargs): + return bool(self.menu_style) and self.menu_style in BUILDIN_STYLES + + def get_context(self, context): + context['menu_template'] = BUILDIN_STYLES[self.menu_style] + return context + +site.register_plugin(SiteMenuStylePlugin, CommAdminView) diff --git a/extra_apps/xadmin/plugins/sortablelist.py b/extra_apps/xadmin/plugins/sortablelist.py new file mode 100644 index 0000000..17d34b6 --- /dev/null +++ b/extra_apps/xadmin/plugins/sortablelist.py @@ -0,0 +1,81 @@ +# coding: utf-8 +""" +Make items sortable by drag-drop in list view. Diffierent from +builtin plugin sortable, it touches model field indeed intead +of only for display. +""" + +from __future__ import unicode_literals + +from django.template.loader import render_to_string +from django.urls.base import reverse +from django.db import transaction + +from xadmin.views import ( + BaseAdminPlugin, ModelAdminView, ListAdminView +) +from xadmin.sites import site +from xadmin.views.base import csrf_protect_m + + +class SortableListPlugin(BaseAdminPlugin): + + list_order_field = None + + def init_request(self, *args, **kwargs): + return bool(self.list_order_field) + + @property + def is_list_sortable(self): + return True + + def result_row(self, __, obj): + row = __() + row.update({ + "tagattrs": "order-key=order_{}".format(obj.pk) + }) + return row + + def result_item(self, item, obj, field_name, row): + if self.is_list_sortable and field_name == self.list_order_field: + item.btns.append('') + return item + + def get_context(self, context): + context['save_order_url'] = self.get_model_url(self.admin_view.model, 'save_order') + return context + + def block_top_toolbar(self, context, nodes): + save_node = render_to_string( + 'xadmin/blocks/model_list.top_toolbar.saveorder.html', context_instance=context + ) + nodes.append(save_node) + + def get_media(self, media): + if self.is_list_sortable: + media = media + self.vendor('xadmin.plugin.sortablelist.js') + return media + + +class SaveOrderView(ModelAdminView): + + @csrf_protect_m + @transaction.atomic + def post(self, request): + order_objs = request.POST.getlist("order[]") + for order_value, pk in enumerate(order_objs, start=1): + self.save_order(pk, order_value) + return self.render_response({}) + + def save_order(self, pk, order_value): + obj = self.model.objects.get(pk=pk) + order_field = self.list_order_field + is_order_changed = lambda x: getattr(x, order_field) != order_value + + if is_order_changed(obj): + setattr(obj, order_field, order_value) + obj.save() + + +site.register_plugin(SortableListPlugin, ListAdminView) +site.register_modelview(r'^save-order/$', SaveOrderView, name='%s_%s_save_order') diff --git a/extra_apps/xadmin/plugins/themes.py b/extra_apps/xadmin/plugins/themes.py new file mode 100644 index 0000000..fca1e45 --- /dev/null +++ b/extra_apps/xadmin/plugins/themes.py @@ -0,0 +1,93 @@ +# coding:utf-8 +from __future__ import print_function +import httplib2 +from django.template import loader +from django.core.cache import cache +from django.utils import six +from django.utils.translation import ugettext as _ +from xadmin.sites import site +from xadmin.models import UserSettings +from xadmin.views import BaseAdminPlugin, BaseAdminView +from xadmin.util import static, json +import six +if six.PY2: + import urllib +else: + import urllib.parse + +THEME_CACHE_KEY = 'xadmin_themes' + + +class ThemePlugin(BaseAdminPlugin): + + enable_themes = False + # {'name': 'Blank Theme', 'description': '...', 'css': 'http://...', 'thumbnail': '...'} + user_themes = None + use_bootswatch = False + default_theme = static('xadmin/css/themes/bootstrap-xadmin.css') + bootstrap2_theme = static('xadmin/css/themes/bootstrap-theme.css') + + def init_request(self, *args, **kwargs): + return self.enable_themes + + def _get_theme(self): + if self.user: + try: + return UserSettings.objects.get(user=self.user, key="site-theme").value + except Exception: + pass + if '_theme' in self.request.COOKIES: + if six.PY2: + func = urllib.unquote + else: + func = urllib.parse.unquote + return func(self.request.COOKIES['_theme']) + return self.default_theme + + def get_context(self, context): + context['site_theme'] = self._get_theme() + return context + + # Media + def get_media(self, media): + return media + self.vendor('jquery-ui-effect.js', 'xadmin.plugin.themes.js') + + # Block Views + def block_top_navmenu(self, context, nodes): + + themes = [ + {'name': _(u"Default"), 'description': _(u"Default bootstrap theme"), 'css': self.default_theme}, + {'name': _(u"Bootstrap2"), 'description': _(u"Bootstrap 2.x theme"), 'css': self.bootstrap2_theme}, + ] + select_css = context.get('site_theme', self.default_theme) + + if self.user_themes: + themes.extend(self.user_themes) + + if self.use_bootswatch: + ex_themes = cache.get(THEME_CACHE_KEY) + if ex_themes: + themes.extend(json.loads(ex_themes)) + else: + ex_themes = [] + try: + h = httplib2.Http() + resp, content = h.request("https://bootswatch.com/api/3.json", 'GET', '', + headers={"Accept": "application/json", "User-Agent": self.request.META['HTTP_USER_AGENT']}) + if six.PY3: + content = content.decode() + watch_themes = json.loads(content)['themes'] + ex_themes.extend([ + {'name': t['name'], 'description': t['description'], + 'css': t['cssMin'], 'thumbnail': t['thumbnail']} + for t in watch_themes]) + except Exception as e: + print(e) + + cache.set(THEME_CACHE_KEY, json.dumps(ex_themes), 24 * 3600) + themes.extend(ex_themes) + + nodes.append(loader.render_to_string('xadmin/blocks/comm.top.theme.html', {'themes': themes, 'select_css': select_css})) + + +site.register_plugin(ThemePlugin, BaseAdminView) diff --git a/extra_apps/xadmin/plugins/topnav.py b/extra_apps/xadmin/plugins/topnav.py new file mode 100644 index 0000000..fdf458b --- /dev/null +++ b/extra_apps/xadmin/plugins/topnav.py @@ -0,0 +1,73 @@ + +from django.template import loader +from django.utils.text import capfirst +from django.urls.base import reverse, NoReverseMatch +from django.utils.translation import ugettext as _ + +from xadmin.sites import site +from xadmin.filters import SEARCH_VAR +from xadmin.views import BaseAdminPlugin, CommAdminView + + +class TopNavPlugin(BaseAdminPlugin): + + global_search_models = None + global_add_models = None + + def get_context(self, context): + return context + + # Block Views + def block_top_navbar(self, context, nodes): + search_models = [] + + site_name = self.admin_site.name + if self.global_search_models == None: + models = self.admin_site._registry.keys() + else: + models = self.global_search_models + + for model in models: + app_label = model._meta.app_label + + if self.has_model_perm(model, "view"): + info = (app_label, model._meta.model_name) + if getattr(self.admin_site._registry[model], 'search_fields', None): + try: + search_models.append({ + 'title': _('Search %s') % capfirst(model._meta.verbose_name_plural), + 'url': reverse('xadmin:%s_%s_changelist' % info, current_app=site_name), + 'model': model + }) + except NoReverseMatch: + pass + return nodes.append(loader.render_to_string('xadmin/blocks/comm.top.topnav.html', {'search_models': search_models, 'search_name': SEARCH_VAR})) + + def block_top_navmenu(self, context, nodes): + add_models = [] + + site_name = self.admin_site.name + + if self.global_add_models == None: + models = self.admin_site._registry.keys() + else: + models = self.global_add_models + for model in models: + app_label = model._meta.app_label + + if self.has_model_perm(model, "add"): + info = (app_label, model._meta.model_name) + try: + add_models.append({ + 'title': _('Add %s') % capfirst(model._meta.verbose_name), + 'url': reverse('xadmin:%s_%s_add' % info, current_app=site_name), + 'model': model + }) + except NoReverseMatch: + pass + + nodes.append( + loader.render_to_string('xadmin/blocks/comm.top.topnav.html', {'add_models': add_models})) + + +site.register_plugin(TopNavPlugin, CommAdminView) diff --git a/extra_apps/xadmin/plugins/utils.py b/extra_apps/xadmin/plugins/utils.py new file mode 100644 index 0000000..6bc7e79 --- /dev/null +++ b/extra_apps/xadmin/plugins/utils.py @@ -0,0 +1,15 @@ +from django.template.context import RequestContext + + +def get_context_dict(context): + """ + Contexts in django version 1.9+ must be dictionaries. As xadmin has a legacy with older versions of django, + the function helps the transition by converting the [RequestContext] object to the dictionary when necessary. + :param context: RequestContext + :return: dict + """ + if isinstance(context, RequestContext): + ctx = context.flatten() + else: + ctx = context + return ctx diff --git a/extra_apps/xadmin/plugins/wizard.py b/extra_apps/xadmin/plugins/wizard.py new file mode 100644 index 0000000..84c46fd --- /dev/null +++ b/extra_apps/xadmin/plugins/wizard.py @@ -0,0 +1,343 @@ +import re +from collections import OrderedDict +from django import forms +from django.db import models +from django.template import loader +try: + from formtools.wizard.storage import get_storage + from formtools.wizard.forms import ManagementForm + from formtools.wizard.views import StepsHelper +except: + # work for django<1.8 + from django.contrib.formtools.wizard.storage import get_storage + from django.contrib.formtools.wizard.forms import ManagementForm + from django.contrib.formtools.wizard.views import StepsHelper + +from django.utils import six +from django.utils.encoding import smart_text +from django.utils.module_loading import import_string +from django.forms import ValidationError +from django.forms.models import modelform_factory + +from xadmin.sites import site +from xadmin.views import BaseAdminPlugin, ModelFormAdminView + + +def normalize_name(name): + new = re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', '_\\1', name) + return new.lower().strip('_') + + +class WizardFormPlugin(BaseAdminPlugin): + + wizard_form_list = None + wizard_for_update = False + + storage_name = 'formtools.wizard.storage.session.SessionStorage' + form_list = None + initial_dict = None + instance_dict = None + condition_dict = None + file_storage = None + + def _get_form_prefix(self, step=None): + if step is None: + step = self.steps.current + obj = self.get_form_list().keys() + if six.PY3: + obj = [s for s in obj] + return 'step_%d' % obj.index(step) + + def get_form_list(self): + if not hasattr(self, '_form_list'): + init_form_list = OrderedDict() + + assert len( + self.wizard_form_list) > 0, 'at least one form is needed' + + for i, form in enumerate(self.wizard_form_list): + init_form_list[smart_text(form[0])] = form[1] + + self._form_list = init_form_list + + return self._form_list + + # Plugin replace methods + def init_request(self, *args, **kwargs): + if self.request.is_ajax() or ("_ajax" in self.request.GET) or not hasattr(self.request, 'session') or (args and not self.wizard_for_update): + # update view + return False + return bool(self.wizard_form_list) + + def prepare_form(self, __): + # init storage and step helper + self.prefix = normalize_name(self.__class__.__name__) + self.storage = get_storage( + self.storage_name, self.prefix, self.request, + getattr(self, 'file_storage', None)) + self.steps = StepsHelper(self) + self.wizard_goto_step = False + + if self.request.method == 'GET': + self.storage.reset() + self.storage.current_step = self.steps.first + + self.admin_view.model_form = self.get_step_form() + else: + # Look for a wizard_goto_step element in the posted data which + # contains a valid step name. If one was found, render the requested + # form. (This makes stepping back a lot easier). + wizard_goto_step = self.request.POST.get('wizard_goto_step', None) + if wizard_goto_step and int(wizard_goto_step) < len(self.get_form_list()): + obj = self.get_form_list().keys() + if six.PY3: + obj = [s for s in obj] + self.storage.current_step = obj[int(wizard_goto_step)] + self.admin_view.model_form = self.get_step_form() + self.wizard_goto_step = True + return + + # Check if form was refreshed + management_form = ManagementForm( + self.request.POST, prefix=self.prefix) + + if not management_form.is_valid(): + raise ValidationError( + 'ManagementForm data is missing or has been tampered.') + + form_current_step = management_form.cleaned_data['current_step'] + if (form_current_step != self.steps.current and + self.storage.current_step is not None): + # form refreshed, change current step + self.storage.current_step = form_current_step + + # get the form for the current step + self.admin_view.model_form = self.get_step_form() + + def get_form_layout(self, __): + attrs = self.get_form_list()[self.steps.current] + if type(attrs) is dict and 'layout' in attrs: + self.admin_view.form_layout = attrs['layout'] + else: + self.admin_view.form_layout = None + return __() + + def get_step_form(self, step=None): + if step is None: + step = self.steps.current + attrs = self.get_form_list()[step] + if type(attrs) in (list, tuple): + return modelform_factory(self.model, form=forms.ModelForm, + fields=attrs, formfield_callback=self.admin_view.formfield_for_dbfield) + elif type(attrs) is dict: + if attrs.get('fields', None): + return modelform_factory(self.model, form=forms.ModelForm, + fields=attrs['fields'], formfield_callback=self.admin_view.formfield_for_dbfield) + if attrs.get('callback', None): + callback = attrs['callback'] + if callable(callback): + return callback(self) + elif hasattr(self.admin_view, str(callback)): + return getattr(self.admin_view, str(callback))(self) + elif issubclass(attrs, forms.BaseForm): + return attrs + return None + + def get_step_form_obj(self, step=None): + if step is None: + step = self.steps.current + form = self.get_step_form(step) + return form(prefix=self._get_form_prefix(step), + data=self.storage.get_step_data(step), + files=self.storage.get_step_files(step)) + + def get_form_datas(self, datas): + datas['prefix'] = self._get_form_prefix() + if self.request.method == 'POST' and self.wizard_goto_step: + datas.update({ + 'data': self.storage.get_step_data(self.steps.current), + 'files': self.storage.get_step_files(self.steps.current) + }) + return datas + + def valid_forms(self, __): + if self.wizard_goto_step: + # goto get_response directly + return False + return __() + + def _done(self): + cleaned_data = self.get_all_cleaned_data() + exclude = self.admin_view.exclude + + opts = self.admin_view.opts + instance = self.admin_view.org_obj or self.admin_view.model() + + file_field_list = [] + for f in opts.fields: + if not f.editable or isinstance(f, models.AutoField) \ + or not f.name in cleaned_data: + continue + if exclude and f.name in exclude: + continue + # Defer saving file-type fields until after the other fields, so a + # callable upload_to can use the values from other fields. + if isinstance(f, models.FileField): + file_field_list.append(f) + else: + f.save_form_data(instance, cleaned_data[f.name]) + + for f in file_field_list: + f.save_form_data(instance, cleaned_data[f.name]) + + instance.save() + + for f in opts.many_to_many: + if f.name in cleaned_data: + f.save_form_data(instance, cleaned_data[f.name]) + + self.admin_view.new_obj = instance + + def save_forms(self, __): + # if the form is valid, store the cleaned data and files. + form_obj = self.admin_view.form_obj + self.storage.set_step_data(self.steps.current, form_obj.data) + self.storage.set_step_files(self.steps.current, form_obj.files) + + # check if the current step is the last step + if self.steps.current == self.steps.last: + # no more steps, render done view + return self._done() + + def save_models(self, __): + pass + + def save_related(self, __): + pass + + def get_context(self, context): + context.update({ + "show_save": False, + "show_save_as_new": False, + "show_save_and_add_another": False, + "show_save_and_continue": False, + }) + return context + + def get_response(self, response): + self.storage.update_response(response) + return response + + def post_response(self, __): + if self.steps.current == self.steps.last: + self.storage.reset() + return __() + + # change the stored current step + self.storage.current_step = self.steps.next + + self.admin_view.form_obj = self.get_step_form_obj() + self.admin_view.setup_forms() + + return self.admin_view.get_response() + + def get_all_cleaned_data(self): + """ + Returns a merged dictionary of all step cleaned_data dictionaries. + If a step contains a `FormSet`, the key will be prefixed with formset + and contain a list of the formset cleaned_data dictionaries. + """ + cleaned_data = {} + for form_key, attrs in self.get_form_list().items(): + form_obj = self.get_step_form_obj(form_key) + if form_obj.is_valid(): + if type(attrs) is dict and 'convert' in attrs: + callback = attrs['convert'] + if callable(callback): + callback(self, cleaned_data, form_obj) + elif hasattr(self.admin_view, str(callback)): + getattr(self.admin_view, + str(callback))(self, cleaned_data, form_obj) + elif isinstance(form_obj.cleaned_data, (tuple, list)): + cleaned_data.update({ + 'formset-%s' % form_key: form_obj.cleaned_data + }) + else: + cleaned_data.update(form_obj.cleaned_data) + return cleaned_data + + def get_cleaned_data_for_step(self, step): + """ + Returns the cleaned data for a given `step`. Before returning the + cleaned data, the stored values are being revalidated through the + form. If the data doesn't validate, None will be returned. + """ + if step in self.get_form_list(): + form_obj = self.get_step_form_obj(step) + if form_obj.is_valid(): + return form_obj.cleaned_data + return None + + def get_next_step(self, step=None): + """ + Returns the next step after the given `step`. If no more steps are + available, None will be returned. If the `step` argument is None, the + current step will be determined automatically. + """ + if step is None: + step = self.steps.current + obj = self.get_form_list().keys() + if six.PY3: + obj = [s for s in obj] + key = obj.index(step) + 1 + if len(obj) > key: + return obj[key] + return None + + def get_prev_step(self, step=None): + """ + Returns the previous step before the given `step`. If there are no + steps available, None will be returned. If the `step` argument is + None, the current step will be determined automatically. + """ + if step is None: + step = self.steps.current + obj = self.get_form_list().keys() + if six.PY3: + obj = [s for s in obj] + key = obj.index(step) - 1 + if key >= 0: + return obj[key] + return None + + def get_step_index(self, step=None): + """ + Returns the index for the given `step` name. If no step is given, + the current step will be used to get the index. + """ + if step is None: + step = self.steps.current + obj = self.get_form_list().keys() + if six.PY3: + obj = [s for s in obj] + return obj.index(step) + + def block_before_fieldsets(self, context, nodes): + context = context.update(dict(self.storage.extra_data)) + context['wizard'] = { + 'steps': self.steps, + 'management_form': ManagementForm(prefix=self.prefix, initial={ + 'current_step': self.steps.current, + }), + } + nodes.append(loader.render_to_string('xadmin/blocks/model_form.before_fieldsets.wizard.html', context)) + + def block_submit_line(self, context, nodes): + context = context.update(dict(self.storage.extra_data)) + context['wizard'] = { + 'steps': self.steps + } + + nodes.append(loader.render_to_string('xadmin/blocks/model_form.submit_line.wizard.html', context)) + +site.register_plugin(WizardFormPlugin, ModelFormAdminView) diff --git a/extra_apps/xadmin/plugins/xversion.py b/extra_apps/xadmin/plugins/xversion.py new file mode 100644 index 0000000..a0f6107 --- /dev/null +++ b/extra_apps/xadmin/plugins/xversion.py @@ -0,0 +1,618 @@ +from crispy_forms.utils import TEMPLATE_PACK +from django.contrib.contenttypes.fields import GenericRelation +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import PermissionDenied +from django.db import models +from django.db.models.query import QuerySet +from django.forms.models import model_to_dict +from django.http import HttpResponseRedirect +from django.shortcuts import get_object_or_404 +from django.template.response import TemplateResponse +from django.utils import six +from django.utils.encoding import force_text, smart_text +from django.utils.safestring import mark_safe +from django.utils.text import capfirst +from django.utils.translation import ugettext as _ +from xadmin.layout import Field, render_field +from xadmin.plugins.inline import Inline +from xadmin.plugins.actions import BaseActionView +from xadmin.plugins.inline import InlineModelAdmin +from xadmin.sites import site +from xadmin.util import unquote, quote, model_format_dict, is_related_field2 +from xadmin.views import BaseAdminPlugin, ModelAdminView, CreateAdminView, UpdateAdminView, DetailAdminView, ModelFormAdminView, DeleteAdminView, ListAdminView +from xadmin.views.base import csrf_protect_m, filter_hook +from xadmin.views.detail import DetailAdminUtil +from reversion.models import Revision, Version +from reversion.revisions import is_active, register, is_registered, set_comment, create_revision, set_user +from contextlib import contextmanager +from functools import partial + + +def _autoregister(admin, model, follow=None): + """Registers a model with reversion, if required.""" + if model._meta.proxy: + raise RegistrationError("Proxy models cannot be used with django-reversion, register the parent class instead") + if not is_registered(model): + follow = follow or [] + for parent_cls, field in model._meta.parents.items(): + follow.append(field.name) + _autoregister(admin, parent_cls) + register(model, follow=follow, format=admin.reversion_format) + + +def _register_model(admin, model): + if not hasattr(admin, 'reversion_format'): + admin.reversion_format = 'json' + + if not is_registered(model): + inline_fields = [] + for inline in getattr(admin, 'inlines', []): + inline_model = inline.model + if getattr(inline, 'generic_inline', False): + ct_field = getattr(inline, 'ct_field', 'content_type') + ct_fk_field = getattr(inline, 'ct_fk_field', 'object_id') + for field in model._meta.many_to_many: + if isinstance(field, GenericRelation) \ + and field.rel.to == inline_model \ + and field.object_id_field_name == ct_fk_field \ + and field.content_type_field_name == ct_field: + inline_fields.append(field.name) + _autoregister(admin, inline_model) + else: + fk_name = getattr(inline, 'fk_name', None) + if not fk_name: + for field in inline_model._meta.fields: + if isinstance(field, (models.ForeignKey, models.OneToOneField)) and issubclass(model, field.remote_field.model): + fk_name = field.name + _autoregister(admin, inline_model, follow=[fk_name]) + if not inline_model._meta.get_field(fk_name).remote_field.is_hidden(): + accessor = inline_model._meta.get_field(fk_name).remote_field.get_accessor_name() + inline_fields.append(accessor) + _autoregister(admin, model, inline_fields) + + +def register_models(admin_site=None): + if admin_site is None: + admin_site = site + + for model, admin in admin_site._registry.items(): + if getattr(admin, 'reversion_enable', False): + _register_model(admin, model) + + +@contextmanager +def do_create_revision(request): + with create_revision(): + set_user(request.user) + yield + + +class ReversionPlugin(BaseAdminPlugin): + + # The serialization format to use when registering models with reversion. + reversion_format = "json" + + # Whether to ignore duplicate revision data. + ignore_duplicate_revisions = False + + reversion_enable = False + + def init_request(self, *args, **kwargs): + return self.reversion_enable + + def do_post(self, __): + def _method(): + self.revision_context_manager.set_user(self.user) + comment = '' + admin_view = self.admin_view + if isinstance(admin_view, CreateAdminView): + comment = _(u"Initial version.") + elif isinstance(admin_view, UpdateAdminView): + comment = _(u"Change version.") + elif isinstance(admin_view, RevisionView): + comment = _(u"Revert version.") + elif isinstance(admin_view, RecoverView): + comment = _(u"Rercover version.") + elif isinstance(admin_view, DeleteAdminView): + comment = _(u"Deleted %(verbose_name)s.") % { + "verbose_name": self.opts.verbose_name} + self.revision_context_manager.set_comment(comment) + return __() + return _method + + def post(self, __, request, *args, **kwargs): + with do_create_revision(request): + return __() + + # Block Views + def block_top_toolbar(self, context, nodes): + recoverlist_url = self.admin_view.model_admin_url('recoverlist') + nodes.append(mark_safe('' % (recoverlist_url, _(u"Recover")))) + + def block_nav_toggles(self, context, nodes): + obj = getattr( + self.admin_view, 'org_obj', getattr(self.admin_view, 'obj', None)) + if obj: + revisionlist_url = self.admin_view.model_admin_url( + 'revisionlist', quote(obj.pk)) + nodes.append(mark_safe('' % revisionlist_url)) + + def block_nav_btns(self, context, nodes): + obj = getattr( + self.admin_view, 'org_obj', getattr(self.admin_view, 'obj', None)) + if obj: + revisionlist_url = self.admin_view.model_admin_url( + 'revisionlist', quote(obj.pk)) + nodes.append(mark_safe(' %s' % (revisionlist_url, _(u'History')))) + +# action revision + + +class ActionRevisionPlugin(BaseAdminPlugin): + + reversion_enable = False + + def init_request(self, *args, **kwargs): + return self.reversion_enable + + def do_action(self, __, queryset): + with do_create_revision(self.request): + return __() + + +class BaseReversionView(ModelAdminView): + + # The serialization format to use when registering models with reversion. + reversion_format = "json" + + # Whether to ignore duplicate revision data. + ignore_duplicate_revisions = False + + # If True, then the default ordering of object_history and recover lists will be reversed. + history_latest_first = False + + reversion_enable = False + + def init_request(self, *args, **kwargs): + if not self.has_change_permission() and not self.has_add_permission(): + raise PermissionDenied + + def _order_version_queryset(self, queryset): + """Applies the correct ordering to the given version queryset.""" + if self.history_latest_first: + return queryset.order_by("-pk") + return queryset.order_by("pk") + + +class RecoverListView(BaseReversionView): + + recover_list_template = None + + def get_context(self): + context = super(RecoverListView, self).get_context() + opts = self.opts + deleted = self._order_version_queryset(Version.objects.get_deleted(self.model)) + context.update({ + "opts": opts, + "app_label": opts.app_label, + "model_name": capfirst(opts.verbose_name), + "title": _("Recover deleted %(name)s") % {"name": force_text(opts.verbose_name_plural)}, + "deleted": deleted, + "changelist_url": self.model_admin_url("changelist"), + }) + return context + + @csrf_protect_m + def get(self, request, *args, **kwargs): + context = self.get_context() + + return TemplateResponse( + request, self.recover_list_template or self.get_template_list( + "views/recover_list.html"), + context) + + +class RevisionListView(BaseReversionView): + + object_history_template = None + revision_diff_template = None + + def _reversion_order_version_queryset(self, queryset): + """Applies the correct ordering to the given version queryset.""" + if not self.history_latest_first: + queryset = queryset.order_by("pk") + return queryset + + def get_context(self): + context = super(RevisionListView, self).get_context() + + opts = self.opts + action_list = [ + { + "revision": version.revision, + "url": self.model_admin_url('revision', quote(version.object_id), version.id), + "version": version + } + for version + in self._reversion_order_version_queryset(Version.objects.get_for_object_reference( + self.model, + self.obj.pk, + ).select_related("revision__user")) + ] + context.update({ + 'title': _('Change history: %s') % force_text(self.obj), + 'action_list': action_list, + 'model_name': capfirst(force_text(opts.verbose_name_plural)), + 'object': self.obj, + 'app_label': opts.app_label, + "changelist_url": self.model_admin_url("changelist"), + "update_url": self.model_admin_url("change", self.obj.pk), + 'opts': opts, + }) + return context + + def get(self, request, object_id, *args, **kwargs): + object_id = unquote(object_id) + self.obj = self.get_object(object_id) + + if not self.has_change_permission(self.obj): + raise PermissionDenied + + return self.get_response() + + def get_response(self): + context = self.get_context() + + return TemplateResponse(self.request, self.object_history_template or + self.get_template_list('views/model_history.html'), context) + + def get_version_object(self, version): + obj_version = version._object_version + obj = obj_version.object + obj._state.db = self.obj._state.db + + for field_name, pks in obj_version.m2m_data.items(): + f = self.opts.get_field(field_name) + if f.rel and isinstance(f.rel, models.ManyToManyRel): + setattr(obj, f.name, f.rel.to._default_manager.get_query_set( + ).filter(pk__in=pks).all()) + + detail = self.get_model_view(DetailAdminUtil, self.model, obj) + + return obj, detail + + def post(self, request, object_id, *args, **kwargs): + object_id = unquote(object_id) + self.obj = self.get_object(object_id) + + if not self.has_change_permission(self.obj): + raise PermissionDenied + + params = self.request.POST + if 'version_a' not in params or 'version_b' not in params: + self.message_user(_("Must select two versions."), 'error') + return self.get_response() + + version_a_id = params['version_a'] + version_b_id = params['version_b'] + + if version_a_id == version_b_id: + self.message_user( + _("Please select two different versions."), 'error') + return self.get_response() + + version_a = get_object_or_404(Version, pk=version_a_id) + version_b = get_object_or_404(Version, pk=version_b_id) + + diffs = [] + + obj_a, detail_a = self.get_version_object(version_a) + obj_b, detail_b = self.get_version_object(version_b) + + for f in (self.opts.fields + self.opts.many_to_many): + if is_related_field2(f): + label = f.opts.verbose_name + else: + label = f.verbose_name + + value_a = f.value_from_object(obj_a) + value_b = f.value_from_object(obj_b) + is_diff = value_a != value_b + + if type(value_a) in (list, tuple) and type(value_b) in (list, tuple) \ + and len(value_a) == len(value_b) and is_diff: + is_diff = False + for i in xrange(len(value_a)): + if value_a[i] != value_a[i]: + is_diff = True + break + if type(value_a) is QuerySet and type(value_b) is QuerySet: + is_diff = list(value_a) != list(value_b) + + diffs.append((label, detail_a.get_field_result( + f.name).val, detail_b.get_field_result(f.name).val, is_diff)) + + context = super(RevisionListView, self).get_context() + context.update({ + 'object': self.obj, + 'opts': self.opts, + 'version_a': version_a, + 'version_b': version_b, + 'revision_a_url': self.model_admin_url('revision', quote(version_a.object_id), version_a.id), + 'revision_b_url': self.model_admin_url('revision', quote(version_b.object_id), version_b.id), + 'diffs': diffs + }) + + return TemplateResponse( + self.request, self.revision_diff_template or self.get_template_list('views/revision_diff.html'), + context) + + @filter_hook + def get_media(self): + return super(RevisionListView, self).get_media() + self.vendor('xadmin.plugin.revision.js', 'xadmin.form.css') + + +class BaseRevisionView(ModelFormAdminView): + + @filter_hook + def get_revision(self): + return self.version.field_dict + + @filter_hook + def get_form_datas(self): + datas = {"instance": self.org_obj, "initial": self.get_revision()} + if self.request_method == 'post': + datas.update( + {'data': self.request.POST, 'files': self.request.FILES}) + return datas + + @filter_hook + def get_context(self): + context = super(BaseRevisionView, self).get_context() + context.update({ + 'object': self.org_obj + }) + return context + + @filter_hook + def get_media(self): + return super(BaseRevisionView, self).get_media() + self.vendor('xadmin.plugin.revision.js') + + +class DiffField(Field): + + def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs): + html = '' + for field in self.fields: + html += ('
    %s
    ' % + (_('Current: %s') % self.attrs.pop('orgdata', ''), render_field(field, form, form_style, context, template_pack=template_pack, attrs=self.attrs))) + return html + + +class RevisionView(BaseRevisionView): + + revision_form_template = None + + def init_request(self, object_id, version_id): + self.detail = self.get_model_view( + DetailAdminView, self.model, object_id) + self.org_obj = self.detail.obj + self.version = get_object_or_404( + Version, pk=version_id, object_id=smart_text(self.org_obj.pk)) + + self.prepare_form() + + def get_form_helper(self): + helper = super(RevisionView, self).get_form_helper() + diff_fields = {} + version_data = self.version.field_dict + + for f in self.opts.fields: + fvalue = f.value_from_object(self.org_obj) + vvalue = version_data.get(f.name, None) + + if fvalue is None and vvalue == '': + vvalue = None + if is_related_field2(f): + vvalue = version_data.get(f.name + '_' + f.rel.get_related_field().name, None) + + if fvalue != vvalue: + diff_fields[f.name] = self.detail.get_field_result(f.name).val + for k, v in diff_fields.items(): + helper[k].wrap(DiffField, orgdata=v) + return helper + + @filter_hook + def get_context(self): + context = super(RevisionView, self).get_context() + context["title"] = _( + "Revert %s") % force_text(self.model._meta.verbose_name) + return context + + @filter_hook + def get_response(self): + context = self.get_context() + context.update(self.kwargs or {}) + + form_template = self.revision_form_template + return TemplateResponse( + self.request, form_template or self.get_template_list( + 'views/revision_form.html'), + context) + + @filter_hook + def post_response(self): + self.message_user(_('The %(model)s "%(name)s" was reverted successfully. You may edit it again below.') % + {"model": force_text(self.opts.verbose_name), "name": smart_text(self.new_obj)}, 'success') + return HttpResponseRedirect(self.model_admin_url('change', self.new_obj.pk)) + + +class RecoverView(BaseRevisionView): + + recover_form_template = None + + def init_request(self, version_id): + if not self.has_change_permission() and not self.has_add_permission(): + raise PermissionDenied + + self.version = get_object_or_404(Version, pk=version_id) + self.org_obj = self.version._object_version.object + + self.prepare_form() + + @filter_hook + def get_context(self): + context = super(RecoverView, self).get_context() + context["title"] = _("Recover %s") % self.version.object_repr + return context + + @filter_hook + def get_response(self): + context = self.get_context() + context.update(self.kwargs or {}) + + form_template = self.recover_form_template + return TemplateResponse( + self.request, form_template or self.get_template_list( + 'views/recover_form.html'), + context) + + @filter_hook + def post_response(self): + self.message_user(_('The %(model)s "%(name)s" was recovered successfully. You may edit it again below.') % + {"model": force_text(self.opts.verbose_name), "name": smart_text(self.new_obj)}, 'success') + return HttpResponseRedirect(self.model_admin_url('change', self.new_obj.pk)) + + +class InlineDiffField(Field): + + def render(self, form, form_style, context, template_pack=TEMPLATE_PACK, **kwargs): + html = '' + instance = form.instance + if not instance.pk: + return super(InlineDiffField, self).render(form, form_style, context) + + initial = form.initial + opts = instance._meta + detail = form.detail + for field in self.fields: + f = opts.get_field(field) + f_html = render_field(field, form, form_style, context, + template_pack=template_pack, attrs=self.attrs) + if f.value_from_object(instance) != initial.get(field, None): + current_val = detail.get_field_result(f.name).val + html += ('
    %s
    ' + % (_('Current: %s') % current_val, f_html)) + else: + html += f_html + return html + +# inline hack plugin + + +class InlineRevisionPlugin(BaseAdminPlugin): + + def get_related_versions(self, obj, version, formset): + """Retreives all the related Version objects for the given FormSet.""" + object_id = obj.pk + # Get the fk name. + try: + fk_name = formset.fk.name + '_' + formset.fk.rel.get_related_field().name + except AttributeError: + # This is a GenericInlineFormset, or similar. + fk_name = formset.ct_fk_field.name + # Look up the revision data. + revision_versions = version.revision.version_set.all() + related_versions = dict([(related_version.object_id, related_version) + for related_version in revision_versions + if ContentType.objects.get_for_id(related_version.content_type_id).model_class() == formset.model + and smart_text(related_version.field_dict[fk_name]) == smart_text(object_id)]) + return related_versions + + def _hack_inline_formset_initial(self, revision_view, formset): + """Hacks the given formset to contain the correct initial data.""" + # Now we hack it to push in the data from the revision! + initial = [] + related_versions = self.get_related_versions( + revision_view.org_obj, revision_view.version, formset) + formset.related_versions = related_versions + for related_obj in formset.queryset: + if smart_text(related_obj.pk) in related_versions: + initial.append( + related_versions.pop(smart_text(related_obj.pk)).field_dict) + else: + initial_data = model_to_dict(related_obj) + initial_data["DELETE"] = True + initial.append(initial_data) + for related_version in related_versions.values(): + initial_row = related_version.field_dict + pk_name = ContentType.objects.get_for_id( + related_version.content_type_id).model_class()._meta.pk.name + del initial_row[pk_name] + initial.append(initial_row) + # Reconstruct the forms with the new revision data. + formset.initial = initial + formset.forms = [formset._construct_form( + n) for n in xrange(len(initial))] + # Hack the formset to force a save of everything. + + def get_changed_data(form): + return [field.name for field in form.fields] + for form in formset.forms: + form.has_changed = lambda: True + form._get_changed_data = partial(get_changed_data, form=form) + + def total_form_count_hack(count): + return lambda: count + formset.total_form_count = total_form_count_hack(len(initial)) + + if self.request.method == 'GET' and formset.helper and formset.helper.layout: + helper = formset.helper + cls_str = str if six.PY3 else basestring + helper.filter(cls_str).wrap(InlineDiffField) + fake_admin_class = type(str('%s%sFakeAdmin' % (self.opts.app_label, self.opts.model_name)), (object, ), {'model': self.model}) + for form in formset.forms: + instance = form.instance + if instance.pk: + form.detail = self.get_view( + DetailAdminUtil, fake_admin_class, instance) + + def instance_form(self, formset, **kwargs): + admin_view = self.admin_view.admin_view + if hasattr(admin_view, 'version') and hasattr(admin_view, 'org_obj'): + self._hack_inline_formset_initial(admin_view, formset) + return formset + + +class VersionInline(object): + model = Version + extra = 0 + style = 'accordion' + + +class ReversionAdmin(object): + model_icon = 'fa fa-exchange' + + list_display = ('__str__', 'date_created', 'user', 'comment') + list_display_links = ('__str__',) + + list_filter = ('date_created', 'user') + inlines = [VersionInline] + +site.register(Revision, ReversionAdmin) + +site.register_modelview( + r'^recover/$', RecoverListView, name='%s_%s_recoverlist') +site.register_modelview( + r'^recover/([^/]+)/$', RecoverView, name='%s_%s_recover') +site.register_modelview( + r'^([^/]+)/revision/$', RevisionListView, name='%s_%s_revisionlist') +site.register_modelview( + r'^([^/]+)/revision/([^/]+)/$', RevisionView, name='%s_%s_revision') + +site.register_plugin(ReversionPlugin, ListAdminView) +site.register_plugin(ReversionPlugin, ModelFormAdminView) +site.register_plugin(ReversionPlugin, DeleteAdminView) + +site.register_plugin(InlineRevisionPlugin, InlineModelAdmin) +site.register_plugin(ActionRevisionPlugin, BaseActionView) diff --git a/extra_apps/xadmin/sites.py b/extra_apps/xadmin/sites.py new file mode 100644 index 0000000..fe5f4da --- /dev/null +++ b/extra_apps/xadmin/sites.py @@ -0,0 +1,361 @@ +import sys +from functools import update_wrapper +from future.utils import iteritems +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from django.db.models.base import ModelBase +from django.utils import six +from django.views.decorators.cache import never_cache +from django.template.engine import Engine +import inspect + +if six.PY2 and sys.getdefaultencoding() == 'ascii': + import imp + imp.reload(sys) + sys.setdefaultencoding("utf-8") + + +class AlreadyRegistered(Exception): + pass + + +class NotRegistered(Exception): + pass + + +class MergeAdminMetaclass(type): + + def __new__(cls, name, bases, attrs): + return type.__new__(cls, str(name), bases, attrs) + + +class AdminSite(object): + + def __init__(self, name='xadmin'): + self.name = name + self.app_name = 'xadmin' + + self._registry = {} # model_class class -> admin_class class + self._registry_avs = {} # admin_view_class class -> admin_class class + self._registry_settings = {} # settings name -> admin_class class + self._registry_views = [] + # url instance contains (path, admin_view class, name) + self._registry_modelviews = [] + # url instance contains (path, admin_view class, name) + self._registry_plugins = {} # view_class class -> plugin_class class + + self._admin_view_cache = {} + + # self.check_dependencies() + + self.model_admins_order = 0 + + def copy_registry(self): + import copy + return { + 'models': copy.copy(self._registry), + 'avs': copy.copy(self._registry_avs), + 'views': copy.copy(self._registry_views), + 'settings': copy.copy(self._registry_settings), + 'modelviews': copy.copy(self._registry_modelviews), + 'plugins': copy.copy(self._registry_plugins), + } + + def restore_registry(self, data): + self._registry = data['models'] + self._registry_avs = data['avs'] + self._registry_views = data['views'] + self._registry_settings = data['settings'] + self._registry_modelviews = data['modelviews'] + self._registry_plugins = data['plugins'] + + def register_modelview(self, path, admin_view_class, name): + from xadmin.views.base import BaseAdminView + if issubclass(admin_view_class, BaseAdminView): + self._registry_modelviews.append((path, admin_view_class, name)) + else: + raise ImproperlyConfigured(u'The registered view class %s isn\'t subclass of %s' % + (admin_view_class.__name__, BaseAdminView.__name__)) + + def register_view(self, path, admin_view_class, name): + self._registry_views.append((path, admin_view_class, name)) + + def register_plugin(self, plugin_class, admin_view_class): + from xadmin.views.base import BaseAdminPlugin + if issubclass(plugin_class, BaseAdminPlugin): + self._registry_plugins.setdefault( + admin_view_class, []).append(plugin_class) + else: + raise ImproperlyConfigured(u'The registered plugin class %s isn\'t subclass of %s' % + (plugin_class.__name__, BaseAdminPlugin.__name__)) + + def register_settings(self, name, admin_class): + self._registry_settings[name.lower()] = admin_class + + def register(self, model_or_iterable, admin_class=object, **options): + from xadmin.views.base import BaseAdminView + if isinstance(model_or_iterable, ModelBase) or issubclass(model_or_iterable, BaseAdminView): + model_or_iterable = [model_or_iterable] + for model in model_or_iterable: + if isinstance(model, ModelBase): + if model._meta.abstract: + raise ImproperlyConfigured('The model %s is abstract, so it ' + 'cannot be registered with admin.' % model.__name__) + + if model in self._registry: + raise AlreadyRegistered( + 'The model %s is already registered' % model.__name__) + + # If we got **options then dynamically construct a subclass of + # admin_class with those **options. + if options: + # For reasons I don't quite understand, without a __module__ + # the created class appears to "live" in the wrong place, + # which causes issues later on. + options['__module__'] = __name__ + + admin_class = type(str("%s%sAdmin" % (model._meta.app_label, model._meta.model_name)), (admin_class,), options or {}) + admin_class.model = model + admin_class.order = self.model_admins_order + self.model_admins_order += 1 + self._registry[model] = admin_class + else: + if model in self._registry_avs: + raise AlreadyRegistered('The admin_view_class %s is already registered' % model.__name__) + if options: + options['__module__'] = __name__ + admin_class = type(str( + "%sAdmin" % model.__name__), (admin_class,), options) + + # Instantiate the admin class to save in the registry + self._registry_avs[model] = admin_class + + def unregister(self, model_or_iterable): + """ + Unregisters the given model(s). + + If a model isn't already registered, this will raise NotRegistered. + """ + from xadmin.views.base import BaseAdminView + if isinstance(model_or_iterable, (ModelBase, BaseAdminView)): + model_or_iterable = [model_or_iterable] + for model in model_or_iterable: + if isinstance(model, ModelBase): + if model not in self._registry: + raise NotRegistered( + 'The model %s is not registered' % model.__name__) + del self._registry[model] + else: + if model not in self._registry_avs: + raise NotRegistered('The admin_view_class %s is not registered' % model.__name__) + del self._registry_avs[model] + + def set_loginview(self, login_view): + self.login_view = login_view + + def has_permission(self, request): + """ + Returns True if the given HttpRequest has permission to view + *at least one* page in the admin site. + """ + return request.user.is_active and request.user.is_staff + + def check_dependencies(self): + """ + Check that all things needed to run the admin have been correctly installed. + + The default implementation checks that LogEntry, ContentType and the + auth context processor are installed. + """ + from django.contrib.contenttypes.models import ContentType + + if not ContentType._meta.installed: + raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in " + "your INSTALLED_APPS setting in order to use the admin application.") + + default_template_engine = Engine.get_default() + if not ('django.contrib.auth.context_processors.auth' in default_template_engine.context_processors or + 'django.core.context_processors.auth' in default_template_engine.context_processors): + raise ImproperlyConfigured("Put 'django.contrib.auth.context_processors.auth' " + "in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.") + + def admin_view(self, view, cacheable=False): + """ + Decorator to create an admin view attached to this ``AdminSite``. This + wraps the view and provides permission checking by calling + ``self.has_permission``. + + You'll want to use this from within ``AdminSite.get_urls()``: + + class MyAdminSite(AdminSite): + + def get_urls(self): + from django.conf.urls import url + + urls = super(MyAdminSite, self).get_urls() + urls += [ + url(r'^my_view/$', self.admin_view(some_view)) + ] + return urls + + By default, admin_views are marked non-cacheable using the + ``never_cache`` decorator. If the view can be safely cached, set + cacheable=True. + """ + def inner(request, *args, **kwargs): + if not self.has_permission(request) and getattr(view, 'need_site_permission', True): + return self.create_admin_view(self.login_view)(request, *args, **kwargs) + return view(request, *args, **kwargs) + if not cacheable: + inner = never_cache(inner) + return update_wrapper(inner, view) + + def _get_merge_attrs(self, option_class, plugin_class): + return dict([(name, getattr(option_class, name)) for name in dir(option_class) + if name[0] != '_' and not callable(getattr(option_class, name)) and hasattr(plugin_class, name)]) + + def _get_settings_class(self, admin_view_class): + name = admin_view_class.__name__.lower() + + if name in self._registry_settings: + return self._registry_settings[name] + elif name.endswith('admin') and name[0:-5] in self._registry_settings: + return self._registry_settings[name[0:-5]] + elif name.endswith('adminview') and name[0:-9] in self._registry_settings: + return self._registry_settings[name[0:-9]] + + return None + + def _create_plugin(self, option_classes): + def merge_class(plugin_class): + if option_classes: + attrs = {} + bases = [plugin_class] + for oc in option_classes: + attrs.update(self._get_merge_attrs(oc, plugin_class)) + meta_class = getattr(oc, plugin_class.__name__, getattr(oc, plugin_class.__name__.replace('Plugin', ''), None)) + if meta_class: + bases.insert(0, meta_class) + if attrs: + plugin_class = MergeAdminMetaclass( + '%s%s' % (''.join([oc.__name__ for oc in option_classes]), plugin_class.__name__), + tuple(bases), attrs) + return plugin_class + return merge_class + + def get_plugins(self, admin_view_class, *option_classes): + from xadmin.views import BaseAdminView + plugins = [] + opts = [oc for oc in option_classes if oc] + for klass in admin_view_class.mro(): + if klass == BaseAdminView or issubclass(klass, BaseAdminView): + merge_opts = [] + reg_class = self._registry_avs.get(klass) + if reg_class: + merge_opts.append(reg_class) + settings_class = self._get_settings_class(klass) + if settings_class: + merge_opts.append(settings_class) + merge_opts.extend(opts) + ps = self._registry_plugins.get(klass, []) + plugins.extend(map(self._create_plugin( + merge_opts), ps) if merge_opts else ps) + return plugins + + def get_view_class(self, view_class, option_class=None, **opts): + merges = [option_class] if option_class else [] + for klass in view_class.mro(): + reg_class = self._registry_avs.get(klass) + if reg_class: + merges.append(reg_class) + settings_class = self._get_settings_class(klass) + if settings_class: + merges.append(settings_class) + merges.append(klass) + new_class_name = ''.join([c.__name__ for c in merges]) + + if new_class_name not in self._admin_view_cache: + plugins = self.get_plugins(view_class, option_class) + self._admin_view_cache[new_class_name] = MergeAdminMetaclass( + new_class_name, tuple(merges), + dict({'plugin_classes': plugins, 'admin_site': self}, **opts)) + + return self._admin_view_cache[new_class_name] + + def create_admin_view(self, admin_view_class): + return self.get_view_class(admin_view_class).as_view() + + def create_model_admin_view(self, admin_view_class, model, option_class): + return self.get_view_class(admin_view_class, option_class).as_view() + + def get_urls(self): + from django.urls import include, path, re_path + from xadmin.views.base import BaseAdminView + + if settings.DEBUG: + self.check_dependencies() + + def wrap(view, cacheable=False): + def wrapper(*args, **kwargs): + return self.admin_view(view, cacheable)(*args, **kwargs) + wrapper.admin_site = self + return update_wrapper(wrapper, view) + + # Admin-site-wide views. + urlpatterns = [ + path('jsi18n/', wrap(self.i18n_javascript, cacheable=True), name='jsi18n') + ] + + # Registed admin views + # inspect[isclass]: Only checks if the object is a class. With it lets you create an custom view that + # inherits from multiple views and have more of a metaclass. + urlpatterns += [ + re_path( + _path, + wrap(self.create_admin_view(clz_or_func)) + if inspect.isclass(clz_or_func) and issubclass(clz_or_func, BaseAdminView) + else include(clz_or_func(self)), + name=name + ) + for _path, clz_or_func, name in self._registry_views + ] + + # Add in each model's views. + for model, admin_class in iteritems(self._registry): + view_urls = [ + re_path( + _path, + wrap(self.create_model_admin_view(clz, model, admin_class)), + name=name % (model._meta.app_label, model._meta.model_name) + ) + for _path, clz, name in self._registry_modelviews + ] + urlpatterns += [ + re_path(r'^%s/%s/' % (model._meta.app_label, model._meta.model_name), include(view_urls)) + ] + return urlpatterns + + @property + def urls(self): + return self.get_urls(), self.name, self.app_name + + def i18n_javascript(self, request): + from django.views.i18n import JavaScriptCatalog + """ + Displays the i18n JavaScript that the Django admin requires. + + This takes into account the USE_I18N setting. If it's set to False, the + generated JavaScript will be leaner and faster. + """ + return JavaScriptCatalog.as_view(packages=['django.contrib.admin'])(request) + +# This global object represents the default admin site, for the common case. +# You can instantiate AdminSite in your own code to create a custom admin site. +site = AdminSite() + + +def register(models, **kwargs): + + def _model_admin_wrapper(admin_class): + site.register(models, admin_class) + return _model_admin_wrapper diff --git a/extra_apps/xadmin/static/xadmin/component.json b/extra_apps/xadmin/static/xadmin/component.json new file mode 100644 index 0000000..a81adb9 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/component.json @@ -0,0 +1,20 @@ +{ + "name": "xadmin", + "version": "0.1.0", + "dependencies": { + "jquery": ">=1.8.3", + "jquery-ui": ">=1.10.0", + "bootstrap": "http://twitter.github.io/bootstrap/assets/bootstrap.zip", + "bootstrap-timepicker": ">=0.2.3", + "bootstrap-datepicker": ">=1.0.0", + "bootstrap-modal": ">=2.1", + "flot": ">=0.8", + "font-awesome": ">=3.0.2", + "load-image": "blueimp/JavaScript-Load-Image", + "bootstrap-image-gallery": "blueimp/Bootstrap-Image-Gallery", + "select2": ">=3.3.2", + "selectize": ">=0.8.4", + "datejs": "datejs/Datejs", + "bootstrap-multiselect": "davidstutz/bootstrap-multiselect" + } +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-theme.css b/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-theme.css new file mode 100644 index 0000000..c9c347e --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-theme.css @@ -0,0 +1,459 @@ +/*! + * Bootstrap v3.0.2 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +.btn-default, +.btn-primary, +.btn-success, +.btn-info, +.btn-warning, +.btn-danger { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.btn-default:active, +.btn-primary:active, +.btn-success:active, +.btn-info:active, +.btn-warning:active, +.btn-danger:active, +.btn-default.active, +.btn-primary.active, +.btn-success.active, +.btn-info.active, +.btn-warning.active, +.btn-danger.active { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} + +.btn:active, +.btn.active { + background-image: none; +} + +.btn-default { + text-shadow: 0 1px 0 #fff; + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ffffff), to(#e0e0e0)); + background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); + background-image: -moz-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); + background-repeat: repeat-x; + border-color: #dbdbdb; + border-color: #ccc; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-default:hover, +.btn-default:focus { + background-color: #e0e0e0; + background-position: 0 -15px; +} + +.btn-default:active, +.btn-default.active { + background-color: #e0e0e0; + border-color: #dbdbdb; +} + +.btn-primary { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#2d6ca2)); + background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); + background-image: -moz-linear-gradient(top, #428bca 0%, #2d6ca2 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); + background-repeat: repeat-x; + border-color: #2b669a; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:focus { + background-color: #2d6ca2; + background-position: 0 -15px; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #2d6ca2; + border-color: #2b669a; +} + +.btn-success { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5cb85c), to(#419641)); + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: -moz-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); + background-repeat: repeat-x; + border-color: #3e8f3e; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:focus { + background-color: #419641; + background-position: 0 -15px; +} + +.btn-success:active, +.btn-success.active { + background-color: #419641; + border-color: #3e8f3e; +} + +.btn-warning { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f0ad4e), to(#eb9316)); + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: -moz-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); + background-repeat: repeat-x; + border-color: #e38d13; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:focus { + background-color: #eb9316; + background-position: 0 -15px; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #eb9316; + border-color: #e38d13; +} + +.btn-danger { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9534f), to(#c12e2a)); + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: -moz-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); + background-repeat: repeat-x; + border-color: #b92c28; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:focus { + background-color: #c12e2a; + background-position: 0 -15px; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #c12e2a; + border-color: #b92c28; +} + +.btn-info { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5bc0de), to(#2aabd2)); + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: -moz-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); + background-repeat: repeat-x; + border-color: #28a4c9; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:focus { + background-color: #2aabd2; + background-position: 0 -15px; +} + +.btn-info:active, +.btn-info.active { + background-color: #2aabd2; + border-color: #28a4c9; +} + +.thumbnail, +.img-thumbnail { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-color: #e8e8e8; + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f5f5f5), to(#e8e8e8)); + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -moz-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + background-color: #357ebd; + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#357ebd)); + background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: -moz-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); +} + +.navbar-default { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ffffff), to(#f8f8f8)); + background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); + background-image: -moz-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); + background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); + background-repeat: repeat-x; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); +} + +.navbar-default .navbar-nav > .active > a { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ebebeb), to(#f3f3f3)); + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); + background-image: -moz-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); +} + +.navbar-brand, +.navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); +} + +.navbar-inverse { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#3c3c3c), to(#222222)); + background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); + background-image: -moz-linear-gradient(top, #3c3c3c 0%, #222222 100%); + background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .navbar-nav > .active > a { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#222222), to(#282828)); + background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); + background-image: -moz-linear-gradient(top, #222222 0%, #282828 100%); + background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .navbar-brand, +.navbar-inverse .navbar-nav > li > a { + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-static-top, +.navbar-fixed-top, +.navbar-fixed-bottom { + border-radius: 0; +} + +.alert { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.alert-success { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#c8e5bc)); + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: -moz-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); + background-repeat: repeat-x; + border-color: #b2dba1; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); +} + +.alert-info { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#b9def0)); + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: -moz-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); + background-repeat: repeat-x; + border-color: #9acfea; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); +} + +.alert-warning { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#f8efc0)); + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: -moz-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); + background-repeat: repeat-x; + border-color: #f5e79e; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); +} + +.alert-danger { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#e7c3c3)); + background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: -moz-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); + background-repeat: repeat-x; + border-color: #dca7a7; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); +} + +.progress { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ebebeb), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: -moz-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); +} + +.progress-bar { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9)); + background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); + background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); +} + +.progress-bar-success { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5cb85c), to(#449d44)); + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: -moz-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); +} + +.progress-bar-info { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5bc0de), to(#31b0d5)); + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: -moz-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); +} + +.progress-bar-warning { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f0ad4e), to(#ec971f)); + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: -moz-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); +} + +.progress-bar-danger { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9534f), to(#c9302c)); + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: -moz-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); +} + +.list-group { + border-radius: 4px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); +} + +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + text-shadow: 0 -1px 0 #3071a9; + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3278b3)); + background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); + background-image: -moz-linear-gradient(top, #428bca 0%, #3278b3 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); + background-repeat: repeat-x; + border-color: #3278b3; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); +} + +.panel { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.panel-default > .panel-heading { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f5f5f5), to(#e8e8e8)); + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -moz-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); +} + +.panel-primary > .panel-heading { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#357ebd)); + background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: -moz-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); +} + +.panel-success > .panel-heading { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#d0e9c6)); + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: -moz-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); +} + +.panel-info > .panel-heading { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#c4e3f3)); + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: -moz-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); +} + +.panel-warning > .panel-heading { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#faf2cc)); + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: -moz-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); +} + +.panel-danger > .panel-heading { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#ebcccc)); + background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: -moz-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); +} + +.well { + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#e8e8e8), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: -moz-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); + background-repeat: repeat-x; + border-color: #dcdcdc; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-theme.min.css b/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-theme.min.css new file mode 100644 index 0000000..9164277 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-theme.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v3.0.2 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. + */ + +.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#2d6ca2));background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-moz-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#419641));background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#eb9316));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c12e2a));background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#2aabd2));background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#f8f8f8));background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-moz-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f3f3f3));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-gradient(linear,left 0,left 100%,from(#3c3c3c),to(#222));background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-moz-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#222),to(#282828));background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-moz-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#c8e5bc));background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#b9def0));background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#f8efc0));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#e7c3c3));background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3278b3));background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#d0e9c6));background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#c4e3f3));background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#faf2cc));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#ebcccc));background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-gradient(linear,left 0,left 100%,from(#e8e8e8),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-xadmin.css b/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-xadmin.css new file mode 100644 index 0000000..4f98d57 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/themes/bootstrap-xadmin.css @@ -0,0 +1,62 @@ + +/* results table */ +.table th { + background-color: #FAFAFA; + background-image: -moz-linear-gradient(top, white, #F2F2F2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#F2F2F2)); + background-image: -webkit-linear-gradient(top, white, #F2F2F2); + background-image: -o-linear-gradient(top, white, #F2F2F2); + background-image: linear-gradient(to bottom, white, #F2F2F2); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + border-bottom-width: 1px !important; +} + +/** panel **/ +.panel-default { + border-radius: 2px; +} +.panel-default > .panel-heading { + background-color: #F8F8F8; + background-image: -moz-linear-gradient(top, #FDFDFD, #F6F6F6); + background-image: -ms-linear-gradient(top, #FDFDFD, #F6F6F6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#FDFDFD), to(#F6F6F6)); + background-image: -webkit-linear-gradient(top, #FDFDFD, #F6F6F6); + background-image: -o-linear-gradient(top, #FDFDFD, #F6F6F6); + background-image: linear-gradient(top, #FDFDFD, #F6F6F6); +} + +.form-group { + border-bottom: 1px solid #EEE; + background-color: #FBFBFB; + margin-top: 0px !important; + margin-bottom: 0px !important; +} +.controls { + background-color: white; + padding: 15px !important; +} +.control-label { + margin-bottom: 0px !important; +} +.fieldset .panel-body { + padding-top: 0px !important; + padding-bottom: 0px !important; +} +.form-inline .form-group { + background: transparent; + border: none; +} + +/** fieldset **/ +@media (min-width: 768px) { + .form-horizontal .controls{ + border-left: 1px solid #EEE; + } + .form-horizontal .control-label { + padding-top: 22px !important; + } +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.form.css b/extra_apps/xadmin/static/xadmin/css/xadmin.form.css new file mode 100644 index 0000000..689788f --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.form.css @@ -0,0 +1,195 @@ + +/* CUSTOM FORM FIELDS */ +select.selectmultiple { + width: 100%; + height: 120px; +} +.select2-container{ + width: 100%; +} +.select2-container.form-control{ + padding: 0px; + border: 0px; +} +.select2-container .select2-choice { + height: 35px; + padding-top: 3px; +} + +/* form css */ +.form-container .column{ + min-height: 60px; +} +.form-group { + margin-right: -15px; + margin-left: -15px; +} +.control-label { + padding: 7px 10px; + font-weight: bold; +} +.form-horizontal .control-label { + margin-bottom: 5px; +} +.controls { + padding: 0px 15px 0px 15px; +} +.controls:before, +.controls:after { + display: table; + content: " "; +} +.controls:after { + clear: both; +} +.control-wrap { + display: block; + width: 100%; + padding-right: 45px; +} +.asteriskField, .asterisk-field { + color: red; +} +.controls > .radio:first-child, +.controls > .checkbox:first-child, +.control-wrap > .radio:first-child, +.control-wrap > .checkbox:first-child { + margin-top: -7px; +} +.controls > span { + padding: 5px 0; + display: inline-block; +} + +.help-block { + margin-bottom: 0px; +} + +.form-row .row { + margin: 0px !important; +} + +.fieldset .panel-body { + padding-bottom: 0px; +} + +@media (min-width: 768px) { + + .text-field, + .textinput, + .url-field, + select, + .input-group ~ .text-field, + .input-group ~ .textinput, + .input-group ~ .url-field + { + max-width: 300px; + } + .input-group.date{ max-width: 300px;} + .input-group.time{ max-width: 180px;} + .int-field { + max-width: 100px; + } + .datetime > .input-group { + float: left; + margin-right: 5px; + } + .datetime > .input-group:last-child { + margin-right: 0px; + } + select.selectmultiple { + max-width: 350px; + } + .select2-container, .selectize-control{ + max-width: 300px; + } + + .form-actions.fixed{ + position:fixed; + _position:absolute; + bottom:0px; + z-index:295; + margin-left: -10px; + -webkit-box-shadow: 2px 2px 16px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 2px 2px 16px rgba(0, 0, 0, 0.5); + box-shadow: 2px 2px 16px rgba(0, 0, 0, 0.5); + right: 10px; + } + + .form-actions.fixed .pull-right{ + float: none !important; + margin-left: 10px; + } + + .form-horizontal .control-label { + width: 170px; + float: left; + } + .form-horizontal .controls { + margin-left: 175px; + } + .form-horizontal.short_label .control-label, + .form-horizontal .short_label .control-label { + width: 120px; + } + .form-horizontal.short_label .controls, + .form-horizontal .short_label .controls { + margin-left: 120px; + } + .form-horizontal .form-group { + margin-bottom: 24px; + } + .form-horizontal .form-inline .form-group { + margin: 0px; + padding-left: 0px; + padding-right: 0px; + } + .form-horizontal .fieldset .panel-body { + padding-top: 24px; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .form-horizontal .control-label { + width: 150px; + } + .form-horizontal .controls { + margin-left: 155px; + } + .form-horizontal.short_label .control-label, + .form-horizontal .short_label .control-label { + width: 100px; + } + .form-horizontal.short_label .controls, + .form-horizontal .short_label .controls { + margin-left: 100px; + } +} +@media (max-width: 767px) { + .btn-toolbar.top-toolbar { + margin: 0 10px 10px; + text-align: right; + } +} + +/** detail page **/ +img.field_img { + max-height: 100px; +} + +/** revision form **/ +.diff_field .control-label { + color: #FF8040; +} +.diff_field .controls{ + background-color: #FCF8E3; +} + +/** tabs **/ +.nav.nav-tabs { + margin-bottom: 15px; +} + +/** selectize **/ +.selectize-input { + vertical-align: bottom; +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.main.css b/extra_apps/xadmin/static/xadmin/css/xadmin.main.css new file mode 100644 index 0000000..66f8916 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.main.css @@ -0,0 +1,429 @@ + +a { cursor: pointer;} + +#body-content { + margin-top: 65px; + margin-left: 0px; + margin-right: 0px; +} + +.popover{ + width: auto; +} +.dropdown-submenu .popover { + padding: 0px; + max-width: none; + left: 100%; +} +.dropdown-submenu .popover.right { + margin-top: -35px; + margin-left: -10px; +} +.dropdown-submenu .popover.left { + margin-top: -35px; +} +.dropdown-submenu .popover.right .arrow, .dropdown-submenu .popover.left .arrow{ + top: 47px; +} +.dropdown-submenu .popover form{ + margin: 6px 0; +} +.dropdown-submenu .popover form input { + min-width: 120px; +} +.dropdown-submenu .popover form > .input-group { + width: 100%; +} +.dropdown-submenu .popover form > .btn { + margin-top: 10px; +} +.dropdown-submenu .popover form > .input-group + .input-group { + margin-top: 5px; +} + +.filter-date .menu-choice-date .input-group-addon { + width: 50px; + text-align: right; +} +.filter-date .menu-date-range .ranges .btn{ + margin-top: 10px; +} +@media (min-width: 768px) { + .filter-date .menu-date-range .popover { + width: 600px; + left: 10px; + top: 35px; + margin-top: -2px; + margin-left: -40px; + } + .filter-date .menu-date-range .popover .arrow { + left: 60px; + } + .top-search-form { + margin-top: 6px; + margin-bottom: 0px; + } + .top-search-form .input-group { + width: 240px; + } +} +@media (max-width: 767px) { + .filter-date .menu-date-range .datepicker-inline{ + width: auto; + } + .filter-date .menu-date-range .table-condensed{ + width: 100%; + } +} + +.filter-fk-search .select-search{ + min-width: 160px; +} +.filter-char form input.input-char{ + min-width: 180px; +} +.filter-number form .input-group-btn > .btn { + width: 34px; + text-align: center; +} + + +.panel .panel-heading .icon{ + float: right; + top: 50%; + margin-left: 10px; + cursor: pointer; + font-size: 15px; + margin-top: 2px; +} +.panel .panel-heading .badge { float: right; top: 50%; margin-left: 10px;} +.panel.no_title .panel-heading{ + display: none; +} + +.panel .panel-body.nopadding{ + padding: 0px; +} +.ui-sortable-placeholder { border: 1px dotted #CCC; visibility: visible !important; } +.ui-sortable-placeholder * { visibility: hidden; } + +/* dropdowns */ +.dropdown-menu li.with_menu_btn > a:first-child { + padding-right: 35px; +} +.dropdown-menu .dropdown-menu-btn { + float: right; + margin-top: -26px; + height: 26px; + padding: 6px 8px 6px 5px; + margin-right: 7px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.dropdown-menu .dropdown-menu-btn:hover { + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +/* mask */ +.mask { + display: none; + position: absolute; + left: 0px; + top: 8px; + width: 100%; + z-index: 9999; + margin-top: -8px; + background-color: rgba(255,255,255,.6); + height: 100%; + padding-top: 24px; +} +.mask .progress{ + position: absolute; + width: 80%; + top: 50%; + margin-top: -8px; + left: 10%; +} +.mask .progress .bar{ + width: 100%; +} + +/* export */ +.export .dropdown-submenu .popover{ + width: 240px; + margin-left: -80px; +} + +/* search form */ +.input-group.search-group{ + width: 220px; +} + +/* results table */ +.table th { + white-space: nowrap; + text-overflow: ellipsis; +} + +.table td .btn-group { + font-size: 13px; +} + +.content-toolbar, .steps-nav { + margin-bottom: 10px; +} + +/* details dl */ +.data-details dl.dl-horizontal dt{ + width: 80px; +} +.data-details dl.dl-horizontal dd{ + margin-left: 90px; +} +.data-details .btn{ + float: right; + margin-bottom: 10px; +} + +/* related menu */ +.dropdown.related_menu .dropdown-menu { + width: 200px; +} +.dropdown.related_menu .dropdown-menu > li > a { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.rel-brand { + font-size: .8em; + color: #a10000; +} + +/* list overflow */ +.x-scroll { + overflow-x: auto; +} + +/* nav sitemenu */ +ul.nav-sitemenu { + padding: 10px; +} +ul.nav-sitemenu li a { + padding: 6px 10px; +} +.panel-group.nav-sitemenu .panel .accordion-toggle{ + text-decoration: none; +} +.panel-group.nav-sitemenu .panel:not(:first-child) { + border-radius: 0px; + border-top: 0px; + margin-top: 0px; +} +.panel-group.nav-sitemenu .panel:not(:first-child) .panel-heading { + border-radius: 0px; +} +.panel-group.nav-sitemenu .panel:first-child { + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} +.panel-group.nav-sitemenu .panel .list-group { + border-radius: 0px; +} +.panel-group.nav-sitemenu .panel .list-group .list-group-item:first-child { + border-top-width: 1px; +} +.panel-group.nav-sitemenu .panel .list-group .list-group-item:last-child { + border-bottom-right-radius: 0px; + border-bottom-left-radius: 0px; +} + +@media (min-width: 768px) { + .panel-group.nav-sitemenu { + top: 65px; + bottom: 0; + overflow-y: auto; + position: fixed; + margin-left: -15px; + } + .panel-group.nav-sitemenu .panel .list-group.in{ + max-height: 500px; + overflow-y: auto; + } +} +@media (max-width: 767px) { + .panel-group.nav-sitemenu { + padding: 0px; + } +} + +/* models list */ +ul.model_ul{ + margin-bottom: 20px; +} +ul.model_ul, ul.model_ul ul{ + padding-left: 20px; + list-style: none; +} +ul.model_ul li{ + line-height: 20px; + margin: 8px 0px; +} +ul.model_ul li span { + padding: 3px 6px; + min-width: auto; + min-height: auto; +} + +/* icon */ +*[class^="icon-"] sub, +*[class^="icon-"] sup{ + font-size: 0.5em; + margin-left: -6px; +} + +/* ajax btn */ +.btn-ajax { + margin-left: 10px; +} + +/* g-search */ +#g-search .btn-group{ + margin: 0px; + padding: 0px; +} + +/** Font Icons **/ +a[class^="icon-"]:before, a[class*=" icon-"]:before { + margin-right: 0.3em; +} +.btn[class^="icon-"]:before, .btn[class*=" icon-"]:before { + margin-right: 0.3em; +} + +/** fix navbar input-append and input-prepend margin **/ +.navbar .navbar-brand { + max-width: 400px; +} + +/** import for bp3.0 */ +.pagination.pagination-inline{margin-top: 0px; margin-bottom: 10px;} +.modal { overflow-y: auto;} +.dropdown {position: relative;} +.input-group-btn:not(:first-child):not(:last-child) > .btn{ + border-radius: 0px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + border-top-left-radius: 0; +} + +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + border-bottom-left-radius: 0; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + border-top-right-radius: 0; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.dropdown-submenu:hover > .dropdown-menu, +.dropdown-submenu:hover > .popover { + display: none; +} +.dropdown-submenu.open > .dropdown-menu, +.dropdown-submenu.open > .popover { + display: block; +} + +/** nav-header **/ +.navbar-collapse {max-height: none !important;} +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 1.428571429; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} +.nav > li + .nav-header { + margin-top: 9px; +} + +/** table in panel **/ +.panel .panel-body > .table { + margin-bottom: 0px; +} + +/** thumbnail **/ +.thumbnail-panel.panel .panel-body { padding-bottom: 0px;} +.thumbnail-panel .thumbnail{margin-bottom: 15px;} +.thumbnail-panel .thumbnail:hover { background-color: #efefef; } +.thumbnail > h1 { margin: 0px; } +.thumbnail.warning { + background-color: #fcf8e3; + border-color: #fbeed5; +} +.thumbnail .action-select {position: absolute; top: 0px; left: 20px;} +.thumbnail .dropdown.related_menu {position: absolute; top: 0px; right: 20px;} + +/* panel single **/ +.panel-single { + margin: 50px auto 20px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + -webkit-box-shadow: 0 0 40px rgba(0,0,0,.3); + -moz-box-shadow: 0 0 40px rgba(0,0,0,.3); + box-shadow: 0 0 40px rgba(0,0,0,.3); +} + +/* change list */ +form#changelist-form + .pagination { + margin-top: 0px; +} diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.mobile.css b/extra_apps/xadmin/static/xadmin/css/xadmin.mobile.css new file mode 100644 index 0000000..03246de --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.mobile.css @@ -0,0 +1,106 @@ +#body-content { + margin-top: 50px; + padding-top: 10px; +} +#top-nav, #footer, .breadcrumb { + display: none; +} + +#top-nav .breadcrumb { + margin-top: 20px; +} +#left-side { + min-height: 0px; + position: fixed; + padding: 0px; + top: 50px; + left: 0px; + right: 0px; + bottom: 0px; + background: #FFF; + z-index: 999; + overflow: auto; +} +#left-side .well { + border: 0px; +} +#changelist-form { + clear: both; +} +.navbar-brand { + max-width: 300px; +} + +.panel-content.nopadding { + margin: -15px; +} + +.panel-content.nopadding .table { + margin-bottom: 0; +} + +.col { + padding-right: 10px; + padding-left: 10px; +} +.row { + margin-right: -10px; + margin-left: -10px; +} + +.results { + width: 100%; + overflow-x: auto; +} + +.form-actions { + margin-bottom: 0px; + padding: 10px; + position:fixed; + bottom:0px; + z-index:295; + width: 100%; + margin-right: -10px; + margin-left: -10px; +} +.form-actions .more-btns input:first-child{ + margin-top: 10px; +} +.change-form #body-content { + padding-bottom: 60px; +} +.model_ul { + margin-left: 0px; + margin-right: 0px; +} + +.navbar-inverse .navbar-toggle{ + color: white; + top: 7px; + padding: 7px 12px; +} +.navbar.tools-navbar { + height: 50px; + margin-top: -10px; + text-align: right; +} +.navbar-btns .btn span{ + display: none; +} +.navbar-btns { + position: absolute; + top: 1px; + right: 10px; +} +.nav-back { + left: 10px; + right: auto; +} + +.layout-btns { + display: none; +} +.pagination.pagination-small{ + display: none; +} + diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.page.dashboard.css b/extra_apps/xadmin/static/xadmin/css/xadmin.page.dashboard.css new file mode 100644 index 0000000..7b7dd7e --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.page.dashboard.css @@ -0,0 +1,47 @@ + +.dashboard.container-fluid { + padding-left: 0px; +} +.dashboard .column{ + min-height: 60px; +} + +.widget { +} +.widget_options { +} + +/* Quick Buttons +=================================================================== */ +.qbutton .panel-body { + padding-top: 5px; +} +.btn-quick { + margin-top: 10px; + padding: 20px 0px 0px 0px; + font-size: 15px; + display:block; + text-align: center; + cursor: pointer; + position: relative; +} +.btn-quick i { + font-size: 32px; +} + +/* Quick Buttons Small +=================================================================== */ + +.btn-quick-small { + border-radius: 3px; + padding: 15px 0px 0px 0px; + font-size: 10px; + display:block; + text-align: center; + cursor: pointer; + position: relative; +} + +.btn-quick-small i { + font-size: 20px; +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.aggregation.css b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.aggregation.css new file mode 100644 index 0000000..3a28909 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.aggregation.css @@ -0,0 +1,6 @@ +td.aggregate { + font-weight: bold; +} +td.aggregate span.aggregate_title { + float: right; +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.formset.css b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.formset.css new file mode 100644 index 0000000..60aa065 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.formset.css @@ -0,0 +1,63 @@ + +.empty-form { + display: none; +} +.formset:not(.one) > .panel-body { + padding-top: 0px !important; +} +.formset .row-deleted{ + background: #fff0f0 !important; +} +.formset .row-added { + background: #d1ffdd !important; +} +.formset .formset-heading{ + padding: 10px; + border-bottom: 1px solid #EEE; +} +.formset .row-deleted .formset-form { + display: none; +} +.formset .box-content.accordion { + margin: 0px; + padding: 5px 5px 3px; +} +.formset .formset-form { + padding-left: 15px; + padding-right: 15px; +} +.formset .accordion-heading .delete-row { + float: right; + margin: 8px; +} +.formset .nav{ + margin-bottom: 5px; +} +.formset .nav.nav-tabs{ + padding: 10px 10px 0px; +} +.formset .panel-body.tabs { + padding-left: 0px; + padding-right: 0px; +} +.formset .box-content.tabs{ + padding: 5px 0px 0px; +} +.formset .tabs .tab-content{ + overflow: hidden; +} +.formset .tabs .delete-row{ + float: right; + margin: 8px 8px; +} +.formset .table{ + margin-bottom: 0px; +} +.formset .table td{ + padding: 4px; +} + +.formset .table td .delete-row{ + margin-top: 4px; + display: block; +} diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.importexport.css b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.importexport.css new file mode 100644 index 0000000..72d8cd6 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.importexport.css @@ -0,0 +1,21 @@ +/* FORM ROWS */ + +.form-row { + overflow: hidden; + padding: 10px; + font-size: 13px; + border-bottom: 1px solid #eee; +} + +.form-row img, .form-row input { + vertical-align: middle; +} + +.form-row label input[type="checkbox"] { + margin-top: 0; + vertical-align: 0; +} + +form .form-row p { + padding-left: 0; +} diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.quickfilter.css b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.quickfilter.css new file mode 100644 index 0000000..9d55909 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.plugin.quickfilter.css @@ -0,0 +1,17 @@ +.nav-quickfilter .filter-item { + white-space: nowrap; + overflow: hidden; + padding: 5px; +} + +.nav-quickfilter .filter-col-1 { + margin: 3px 2px 0 -2px; + float: left; +} + +.nav-quickfilter .filter-col-2 { +} + +.nav-quickfilter .nav-expand { + z-index:100; +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.plugins.css b/extra_apps/xadmin/static/xadmin/css/xadmin.plugins.css new file mode 100644 index 0000000..324eba7 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.plugins.css @@ -0,0 +1,12 @@ +/** Action **/ +.action-checkbox-column { + width: 14px; +} + +/** quick-form **/ +.quick-form .modal-body { + padding-bottom: 0px; +} +.quick-form .modal-footer { + margin-top: 0px; +} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.responsive.css b/extra_apps/xadmin/static/xadmin/css/xadmin.responsive.css new file mode 100644 index 0000000..6fad0a9 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.responsive.css @@ -0,0 +1,249 @@ + + +@media (min-width: 768px) and (max-width: 991px) { + ul.nav-sitemenu{ + padding: 0px; + } + ul.nav-sitemenu > li.app_menu>a{ + padding: 3px 0px; + margin: 0px; + text-align: center; + } + ul.nav-sitemenu .dropdown-menu{ + z-index: 1100; + } + ul.nav-sitemenu > li.app_menu>a:after{ + display: none; + } + ul.nav-sitemenu > li.app_menu>hr{ margin: 0px;} + ul.nav-sitemenu > li.app_menu>a>i.icon{ + font-size: 20px; + line-height: 1.7em; + } + ul.nav-sitemenu > li.app_menu li { + + } +} + +@media (min-width: 768px) { + #content-block:not(.full-content) { + padding-left: 5px; + min-height: 450px; + } + .form-actions .more-btns{ + display: inline-block !important; + } + .form-actions .hidden-sm{ + display: inline-block !important; + } + .form-actions .col-1, + .form-actions .col-2, + .form-actions .col-3, + .form-actions .col-4, + .form-actions .col-5, + .form-actions .col-6, + .form-actions .col-7, + .form-actions .col-8, + .form-actions .col-9, + .form-actions .col-10, + .form-actions .col-11, + .form-actions .col-12 + { + width: auto !important; + } + + .quick-form .modal-dialog { + width: auto; + } + .detail-modal .modal-dialog { + width: 80%; + } +} + +@media (max-width: 767px) { +#body-content { + margin-top: 50px; + padding-top: 10px; +} +#body-content.show_menu{ + width: 100%; + overflow-x: hidden; +} +#footer, .breadcrumb { + display: none; +} +#top-nav .navbar-nav { + float: none; +} +#left-side { + min-height: 0px; + position: fixed; + top: 65px; + left: 0px; + bottom: 0px; + background: #FFF; + z-index: 999; + overflow: auto; + display: none; + width: 70%; +} +#body-content.show_menu #left-side { + display: block; +} +#body-content.show_menu #content-block{ + margin-left: 70%; + width: 100%; +} +#left-side .well { + border: 0px; +} +#changelist-form { + clear: both; +} +.popover.dropdown-menu form > .btn { + width: 100%; +} +.navbar .navbar-brand { + max-width: 260px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.panel-content.nopadding { + margin: -15px; +} + +.panel-content.nopadding .table { + margin-bottom: 0; +} + +.form-actions { + margin-bottom: 0px; + padding: 10px; + position:fixed; + bottom:0px; + z-index:295; + width: 100%; + margin-right: -15px; + margin-left: -15px; + border: 0px; + border-radius: 0px; +} +.form-actions .btn-group { + padding-left: 10px; + padding-right: 0px; +} +.form-actions .more-btns{ + clear: both; + overflow: hidden; +} +.form-actions .more-btns .btn:first-child{ +} +.form-actions .more-btns .btn, .form-actions .more-btns .btn-group { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; +} +.form-actions .more-btns .btn, +.form-actions .more-btns .btn-group { + margin-top: 5px; +} + +#body-content { + padding-bottom: 60px; +} +.model_ul { + margin-left: 0px; + margin-right: 0px; +} +.navbar.content-navbar { + position: fixed; + right: 0; + left: 0; + top: 0px; + z-index: 1030; + border-radius: 0; +} +.content-navbar .navbar-toggle{ + padding: 3px 10px; + font-size: 20px; + color: white; + width: auto; + height: auto; +} +.navbar-toggle.pull-left{ + margin-left: 15px; + margin-right: 0px; +} +.btn span{ + display: none; +} +.navbar-btn { + position: absolute; + top: 0px; + right: 10px; +} +.navbar-nav > .dropdown > .dropdown-menu{ + position: relative; + float: none; + max-height: 400px; + overflow: auto; +} +.navbar-nav > .dropdown > .dropdown-menu li>a{ + padding: 8px 20px; +} +.navbar-nav > .dropdown .dropdown-submenu > .dropdown-menu, +.navbar-nav > .dropdown .dropdown-submenu > .popover{ + position: relative; + top: 0px; + left: 0px; + margin: 10px; + float: none; +} +.navbar-nav .dropdown-submenu .popover { + max-width: none; +} +.navbar-nav .dropdown-submenu .popover .arrow { + display: none; +} + +.layout-btns { + display: none; +} +.pagination.pagination-small{ + display: none; +} + +/* search form */ +.input-group.search-group{ + max-width: none; + width: auto; +} + +} + +@media (max-width: 767px) { + .show-sm, .show-md, .show-lg, .hide-xs{ + display: none !important; + } +} + +@media (min-width: 768px) and (max-width: 991px) { + .show-xs, .show-md, .show-lg, .hide-sm{ + display: none !important; + } +} + +@media (min-width: 992px) and (max-width: 1199px) { + .show-xs, .show-sm, .show-lg, .hide-md{ + display: none !important; + } +} + +@media (min-width: 1200px) { + .show-xs, .show-sm, .show-md, .hide-lg{ + display: none !important; + } +} diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.widget.editable.css b/extra_apps/xadmin/static/xadmin/css/xadmin.widget.editable.css new file mode 100644 index 0000000..4eded86 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.widget.editable.css @@ -0,0 +1,63 @@ +.editable-handler .popover{ + width: auto; +} +.editable .popover-title{ + white-space:nowrap; +} +.editable .popover-title .close { + margin: -4px 0px 0px 10px; +} +.editable form .btn-ajax{ + display: none; +} +.editable form .control-wrap{ + padding-right: 0px; +} +.editable form{ + margin-bottom: 0px; +} +.editable form .controls{ + margin: 0px; + padding: 0px !important; + border: 0px; +} +.editable form .form-group { + margin: 0px 0px 10px !important; +} +.editable form .control-label{ + display: none; +} +.editable form .controls label { + white-space:nowrap; +} + +@media (min-width: 768px) { +.editable form .text-field, +.editable form .textinput { + width: 200px; +} +.editable form .int-field { + width: 150px; +} +.editable form .textarea-field{ + width: 250px; + height: 50px; +} + +.editable form select, +.editable form .select2-container { + max-width: 200px; + min-width: 100px; + width: 100%; +} +} +@media (max-width: 767px) { + .popover.editpop{ + position: fixed; + top: 30px !important; + left: 10px !important; + right: 10px !important; + z-index: 1040; + max-width: none; + } +} diff --git a/extra_apps/xadmin/static/xadmin/css/xadmin.widget.select-transfer.css b/extra_apps/xadmin/static/xadmin/css/xadmin.widget.select-transfer.css new file mode 100644 index 0000000..46e60e7 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/css/xadmin.widget.select-transfer.css @@ -0,0 +1,101 @@ + +.selector { + position: relative; + float: left; + overflow: hidden; + width: 100%; +} +.selector-available, .selector-chosen { + float: left; + width: 45%; +} +.selector.stacked .selector-available, .selector.stacked .selector-chosen { + width: 756px; +} +.selector p.title { + padding: 7px 5px 0px 7px; + font-size: 14px; + line-height: 13px; + font-weight: bold; +} + +.selector .selector-filter { + width: 100%; +} +.selector .selector-available .selector-filter { +} +.selector .selector-chosen .selector-filter { +} +.selector.stacked .selector-filter input[type=text] { + width: 716px !important; + max-width: 716px !important; +} +.selector select[multiple=multiple] { + margin: 0; + padding-left: 3px; + width: 100%; + height: 200px; + display: block; + max-width: none !important; +} +.selector .selector-chosen select[multiple=multiple] { + height: 230px; +} +.selector.stacked select[multiple=multiple] { + width: 757px !important; + max-width: 757px !important; +} +.selector ul.selector-chooser { + float: left; + margin: 100px 2px 0; + padding: 0; + width: 31px; + list-style: none; +} +.selector ul.selector-chooser li { + margin-top: 10px; +} +.selector.stacked ul.selector-chooser { + margin: 4px 0 0 356px; + width: 36px; +} +.selector.stacked ul.selector-chooser li { + float: left; +} +a.selector-chooseall, a.selector-clearall { + display: block; + margin: 0; + padding: 2px 7px; + font-size: 11px; + line-height: 20px; + font-weight: bold; +} +.selector-available, .selector-chosen { + border: 1px solid #ddd; + border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; + background: #eee; +} +.selector h3, .inline-group .selector h3, +.inline-related fieldset .selector-available h3, .inline-related fieldset .selector-chosen h3 { + border: 0; + border-bottom: 1px solid #d0d0d0; + background: transparent; +} +.selector select[multiple=multiple] { + border-left: 0; + border-top: 1px solid #d0d0d0; + border-bottom: 1px solid #d0d0d0; + border-radius: 0; -moz-border-radius: 0; -webkit-border-radius: 0; +} + +a.selector-chooseall, a.selector-clearall { + border-top: 1px solid #e4e4e4; +} + +.selector h3 + select { + border-top: 0; +} + +a.selector-chooseall, a.selector-clearall { + border-top: 1px solid #e4e4e4; +} diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.main.js b/extra_apps/xadmin/static/xadmin/js/xadmin.main.js new file mode 100644 index 0000000..a06a5af --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.main.js @@ -0,0 +1,108 @@ +;(function($){ + + $.fn.exform = function(){ + this.each(function () { + var form = $(this); + for (var i = $.fn.exform.renders.length - 1; i >= 0; i--) { + $.fn.exform.renders[i](form) + }; + form.addClass('rended'); + }) + } + $.fn.exform.renders = []; + $(function() { + $('.exform:not(.rended)').exform(); + }); + + $.getCookie = function(name) { + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + + //dropdown submenu plugin + $(document) + .on('click.xa.dropdown.data-api touchstart.xa.dropdown.data-api', '.dropdown-submenu', function (e) { e.stopPropagation(); }) + .on('click.xa.dropdown.data-api', function(e){ + $('.dropdown-submenu.open').removeClass('open'); + }); + + if ('ontouchstart' in document.documentElement) { + $('.dropdown-submenu a').on('click.xa.dropdown.data-api', function(e){ + $(this).parent().toggleClass('open'); + }); + } else{ + $('.dropdown-submenu').on('click.xa.dropdown.data-api mouseover.xa.dropdown.data-api', function(e){ + $(this).parent().find('>.dropdown-submenu.open').removeClass('open'); + $(this).addClass('open'); + }); + } + + //toggle class button + $('body').on('click.xa.togglebtn.data-api', '[data-toggle=class]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var className = $this.attr('data-class-name') + $(target).toggleClass(className) + }) + + // loading btn + // $('.btn.btn-loading,.btn[type=submit]') + // .click(function () { + // var btn = $(this) + // btn.button('loading') + // }) + + //.nav-content bar nav-menu + $('.navbar-xs .navbar-nav > li') + .on('shown.bs.dropdown', function(e){ + $(this).find('>.dropdown-menu').css('max-height', $(window).height()-120); + $(this).parent().find('>li').addClass('hidden-xs'); + $(this).removeClass('hidden-xs'); + }) + .on('hidden.bs.dropdown', function(e){ + $(this).parent().find('>li').removeClass('hidden-xs'); + }); + + // dashboard widget + $('.widget-form').each(function(e){ + var el = $(this); + el.find('.btn-remove').click(function(){ + el.find('input[name=_delete]').val('on'); + el.submit(); + }); + }); + + // g-search + $('#g-search .dropdown-menu a').click(function(){ + $('#g-search').attr('action', $(this).data('action')).submit(); + }) + + // save settings + $.save_user_settings = function(key, value, success, error){ + var csrftoken = $.getCookie('csrftoken'); + $.ajax({ + type: 'POST', + url: window.__admin_path_prefix__ + 'settings/user', + data: {'key': key, 'value': value}, + success: success, + error: error, + beforeSend: function(xhr, settings) { + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + }); + } + +})(jQuery) \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.page.dashboard.js b/extra_apps/xadmin/static/xadmin/js/xadmin.page.dashboard.js new file mode 100644 index 0000000..520fe5d --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.page.dashboard.js @@ -0,0 +1,78 @@ +jQuery(function() { + $( ".btn-quick-form" ).click(function(){ + var btn = $(this), + form_url; + if(btn.is('a')){ + form_url = btn.attr('href'); + } + if(form_url == undefined){ + form_url = btn.data('form-url'); + } + if(!btn.data('form-modal')){ + var modal = $(''); + $('body').append(modal); + btn.data('form-modal', modal); + modal.find('.modal-body').load(form_url, function(form_html, status, xhr){ + var form = $(this).find('form'); + form.exform(); + modal.find('.btn-submit').click(function(){ + var csrftoken = $.getCookie('csrftoken'); + //clean form errors + form.find('.text-error,.help-inline.error').remove(); + form.find('.control-group').removeClass('error'); + $.ajax({ + type: 'POST', + url: form.attr('action'), + data: form.serialize(), + success: function(data){ + if(data['result'] != 'success' && data['errors']){ + var non_fields_errors = []; + for (var i = data['errors'].length - 1; i >= 0; i--) { + var e = data['errors'][i]; + var errdiv = form.find('#div_' + e['id']); + if(errdiv.length){ + errdiv.addClass('error'); + var err_html = []; + for (var i = e['errors'].length - 1; i >= 0; i--) { + err_html.push(''+e['errors'][i]+''); + }; + errdiv.find('.controls').append(err_html.join('\n')); + } else { + non_fields_errors = non_fields_errors.concat(e['errors']); + } + }; + if(non_fields_errors.length){ + var err_html = []; + for (var i = non_fields_errors.length - 1; i >= 0; i--) { + err_html.push('

    '+e['errors'][i]+'

    '); + }; + form.prepend(err_html.join('\n')); + } + } else { + btn.trigger('post-success'); + } + }, + dataType: 'json', + beforeSend: function(xhr, settings) { + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + }); + }) + }); + } + btn.data('form-modal').modal().css( + { + 'margin-top': function () { + return window.pageYOffset; + } + }); + return false; + }); + + $('.btn-quick-form').on('post-success', function(e){ + window.location.reload(); + }); +}); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.page.form.js b/extra_apps/xadmin/static/xadmin/js/xadmin.page.form.js new file mode 100644 index 0000000..9fdb85f --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.page.form.js @@ -0,0 +1,51 @@ +;(function($){ + $(function() { + var action_bar = $('.form-actions'); + if(action_bar.length){ + var height=action_bar[0].offsetTop + action_bar.outerHeight(); + var onchange = function(){ + var s=(document.body.scrollTop||document.documentElement.scrollTop) + window.innerHeight; + if(s 0){ + var first_activated = false; + exform.find('.error').each(function(){ + if (!first_activated){ + var parent = $(this); + while (!(parent.html() == exform.html())){ + if (parent.hasClass('tab-pane')){ + parent.addClass('active'); + parent.siblings().removeClass('active'); + var menu_tab = $('a[href="#' + parent.attr('id') + '"]'); + menu_tab.parent().addClass('active'); + menu_tab.parent().siblings().removeClass('active'); + first_activated = true; + + } + if (parent.hasClass('box-content')){ + parent.show(); + } + parent = parent.parent(); + } + } + }); + } +})(jQuery) + diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.page.list.js b/extra_apps/xadmin/static/xadmin/js/xadmin.page.list.js new file mode 100644 index 0000000..4d8bd78 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.page.list.js @@ -0,0 +1,29 @@ +jQuery(function($){ + //full screen btn + $('.layout-btns .layout-full').click(function(e){ + var icon = $(this).find('i') + if($(this).hasClass('active')){ + // reset + $('#left-side, ul.breadcrumb').show('fast'); + $('#content-block').removeClass('col-md-12 col-sm-12 full-content').addClass('col-sm-11 col-md-10'); + icon.removeClass('fa-compress').addClass('fa-expand'); + $(window).trigger('resize'); + } else { + // full screen + $('#left-side, ul.breadcrumb').hide('fast', function(){ + $('#content-block').removeClass('col-sm-11 col-md-10').addClass('col-md-12 col-sm-12 full-content'); + icon.removeClass('fa-expand').addClass('fa-compress'); + $(window).trigger('resize'); + }); + } + }); + + $('.layout-btns .layout-normal').click(function(e){ + $('.results table').removeClass('table-condensed'); + }); + + $('.layout-btns .layout-condensed').click(function(e){ + $('.results table').addClass('table-condensed'); + }); + +}); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.actions.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.actions.js new file mode 100644 index 0000000..f307d0a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.actions.js @@ -0,0 +1,118 @@ +(function($) { + + $.fn.actions = function(opts) { + var options = $.extend({}, $.fn.actions.defaults, opts); + var actionCheckboxes = $(this); + + updateCounter = function() { + var sel = $(actionCheckboxes).filter(":checked").length; + + $(options.counterContainer).html(interpolate( + ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { + sel: sel, + cnt: _actions_icnt + }, true)); + + if (sel == actionCheckboxes.length) { + showQuestion(); + $(options.allToggle).prop('checked', true); + } else { + clearAcross(); + $(options.allToggle).prop('checked', false); + } + } + showQuestion = function() { + $(options.acrossClears).hide(); + $(options.acrossQuestions).show(); + $(options.allContainer).hide(); + } + showClear = function() { + $(options.acrossClears).show(); + $(options.acrossQuestions).hide(); + $(options.allContainer).show(); + $(options.counterContainer).hide(); + } + reset = function() { + $(options.acrossClears).hide(); + $(options.acrossQuestions).hide(); + $(options.allContainer).hide(); + $(options.counterContainer).show(); + } + clearAcross = function() { + reset(); + $(options.acrossInput).val(0); + } + + // Show counter by default + $(options.counterContainer).show(); + $(options.allToggle).show().click(function() { + $(actionCheckboxes).trigger('checker', $(this).is(":checked")); + }); + + $("div.form-actions .question").click(function(event) { + event.preventDefault(); + $(options.acrossInput).val(1); + showClear(); + }); + $("div.form-actions .clear").click(function(event) { + event.preventDefault(); + $(options.allToggle).prop("checked", false); + $(actionCheckboxes).trigger('checker', false); + clearAcross(); + }); + + $(actionCheckboxes).bind('checker', function(e, checked){ + $(this).prop("checked", checked) + .parentsUntil('.grid-item').parent().toggleClass(options.selectedClass, checked); + updateCounter(); + }); + + lastChecked = null; + $(actionCheckboxes).click(function(event) { + if (!event) { var event = window.event; } + var target = event.target ? event.target : event.srcElement; + + if (lastChecked && $.data(lastChecked) != $.data(target) && event.shiftKey == true) { + var inrange = false; + $(lastChecked).trigger('checker', target.checked); + $(actionCheckboxes).each(function() { + if ($.data(this) == $.data(lastChecked) || $.data(this) == $.data(target)) { + inrange = (inrange) ? false : true; + } + if (inrange) { + $(this).trigger('checker', target.checked); + } + }); + } + + $(target).trigger('checker', target.checked); + lastChecked = target; + }); + + // Check state of checkboxes and reinit state if needed + $(this).filter(":checked").trigger('checker', true); + updateCounter(); + if ($(options.acrossInput).val() == 1) { + showClear(); + } + } + /* Setup plugin defaults */ + $.fn.actions.defaults = { + counterContainer: "div.form-actions .action-counter", + allContainer: "div.form-actions .all", + acrossInput: "div.form-actions #select-across", + acrossQuestions: "div.form-actions .question", + acrossClears: "div.form-actions .clear", + allToggle: "#action-toggle", + selectedClass: "warning" + } + + $.do_action = function(name){ + $('#action').val(name); + $('#changelist-form').submit(); + } + + $(document).ready(function($) { + $(".results input.action-select").actions(); + }); +})(jQuery); diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.batch.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.batch.js new file mode 100644 index 0000000..9917224 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.batch.js @@ -0,0 +1,16 @@ + +;(function($){ + + $('.batch-field-checkbox').bind('click', function(event){ + if (!event) { var event = window.event; } + var target = event.target ? event.target : event.srcElement; + + var wrap = $(this).parent().parent().find('.control-wrap'); + if(target.checked){ + wrap.show('fast'); + } else { + wrap.hide('fast'); + } + }); + +})(jQuery) diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.bookmark.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.bookmark.js new file mode 100644 index 0000000..8af6f0d --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.bookmark.js @@ -0,0 +1,17 @@ +(function($) { + + $(function(){ + $('#bookmark_form').each(function(){ + var f = $(this); + f.submit(function(e){ + f.find('button[type=submit]').button('loading'); + $.post(f.attr('action'), f.serialize(), function(data){ + $('#bookmark-menu .add-bookmark').remove(); + $('#bookmark-menu').append('
  • '+ data.title +'
  • '); + }, 'json'); + return false; + }); + }); + }); + +})(jQuery); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.charts.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.charts.js new file mode 100644 index 0000000..66f18e0 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.charts.js @@ -0,0 +1,58 @@ +$(document).ready(function(){ + + function showTooltip(x, y, contents) { + $('
    ' + contents + '
    ').css( { + position: 'absolute', + display: 'none', + top: y + 5, + left: x + 5 + }).appendTo("body").fadeIn(200); + } + + $.fn.chart = function(){ + $(this).each(function(){ + var $chart = $(this); + + if($chart.data('chart-obj')) return; + + $chart.html(' Loading chart...'); + + $.getJSON($chart.data('chart-url'), function(data){ + var chart = $.plot($chart, data.data, data.option); + var previousPoint = null; + $chart.bind("plothover", function (event, pos, item) { + if (item) { + if (previousPoint != item.dataIndex) { + previousPoint = item.dataIndex; + + $("#chart-tooltip").remove(); + var x = item.series.xaxis.tickFormatter(item.datapoint[0], item.series.xaxis), + y = item.series.yaxis.tickFormatter(item.datapoint[1], item.series.yaxis); + if (item.series.xaxis.options.mode=="categories") { + x = item.series.data[item.dataIndex][0]; + } + if (item.series.yaxis.options.mode=="categories") { + y = item.series.data[item.dataIndex][1]; + } + showTooltip(item.pageX, item.pageY, + item.series.label + " :
    (" + x + " , " + y+")"); + } + } else { + $("#chart-tooltip").remove(); + previousPoint = null; + } + }); + $chart.data('chart-obj', chart); + }); + }) + } + + $('.chart-tab a').click(function(e){ + e.preventDefault(); + $(this).tab('show'); + + $($(this).attr('href')).chart(); + }); + $('.chart-tab a:first').click(); + $('.chart.init').chart(); +}); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.details.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.details.js new file mode 100644 index 0000000..12b4a0b --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.details.js @@ -0,0 +1,61 @@ +(function($){ + + var DetailsPop = function(element){ + this.$element = $(element); + this.res_uri = this.$element.data('res-uri'); + this.edit_uri = this.$element.data('edit-uri'); + this.obj_data = null; + + this.$element.on('click', $.proxy(this.click, this)); + }; + + DetailsPop.prototype = { + constructor: DetailsPop, + + click: function(e){ + e.stopPropagation(); + e.preventDefault(); + var modal = $('#detail-modal-id'); + var el = this.$element; + if(!modal.length){ + modal = $(''); + $('body').append(modal); + } + modal.find('.modal-title').html(el.attr('title')); + var edit_btn = modal.find('.edit-btn'); + if(this.edit_uri != ""){ + edit_btn.attr('href', this.edit_uri); + }else{ + edit_btn.remove(); + } + modal.find('.modal-body').html('

    '); + modal.find('.modal-body').load(this.res_uri + '?_format=html', function(response, status, xhr) { + if (status == "error") { + var msg = "Sorry but there was an error: "; + modal.find('.modal-body').html(msg + xhr.status + " " + (typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!')); + } + }); + modal.modal(); + } + }; + + $.fn.details = function () { + return this.each(function () { + var $this = $(this), data = $this.data('details'); + if (!data) { + $this.data('details', (data = new DetailsPop(this))); + } + }); + }; + + $(function(){ + $('.details-handler').details(); + }); + +})(jQuery); + + diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.editable.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.editable.js new file mode 100644 index 0000000..2518613 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.editable.js @@ -0,0 +1,208 @@ + ++function ($) { "use strict"; + + // POPOVER PUBLIC CLASS DEFINITION + // =============================== + + var Editpop = function (element, options) { + this.einit('editpop', element, options) + } + + Editpop.DEFAULTS = $.extend({} , $.fn.popover.Constructor.DEFAULTS, { + container: 'body' + , trigger: 'manual' + , placement: function(tip, el) { + var $tip = $(tip) + var $el = $(el) + + var tip_width = $tip.width(), + tip_height = $tip.height(), + el_width = $el.width(), + el_height = $el.height(), + client_width = document.body.clientWidth, + gap = 20 + + var top_gap = $el.offset().top - $("body").scrollTop() - 40, + left_gap = $el.offset().left - $("body").scrollLeft(), + right_gap = client_width - left_gap - el_width + + if(top_gap > tip_height + gap && left_gap > tip_width/2 + gap && right_gap > tip_width/2 + gap){ + return 'top' + } + if(top_gap > tip_height/2){ + if(right_gap > tip_width + gap){ + return 'right' + } else if(left_gap > tip_width + gap) { + return 'left' + } + } + return 'bottom' + } + , template: '

    ' + }) + + + // NOTE: POPOVER EXTENDS tooltip.js + // ================================ + + Editpop.prototype = $.extend({}, $.fn.popover.Constructor.prototype) + + Editpop.prototype.constructor = Editpop + + Editpop.prototype.einit = function (type, element, options) { + this.init(type, element, options) + this.content = null + this.$element.on('click.' + this.type, $.proxy(this.beforeToggle, this)) + + this.$text = this.$element.parent().parent().find('.editable-field') + this.field = this.$element.data('editable-field') + } + + Editpop.prototype.getDefaults = function () { + return Editpop.DEFAULTS + } + + Editpop.prototype.beforeToggle = function() { + var $el = this.$element + + if(this.content == null){ + var that = this + $el.find('>i').removeClass('fa fa-edit').addClass('fa fa-spinner fa-spin') + $.ajax({ + url: $el.data('editable-loadurl'), + success: function(content){ + $el.find('>i').removeClass('fa fa-spinner fa-spin').addClass('fa fa-edit') + that.content = content + that.toggle() + }, + dataType: 'html' + }) + } else { + this.toggle() + } + } + + Editpop.prototype.setContent = function () { + var $tip = this.tip() + var title = this.getTitle() + + $tip.find('.popover-title').html('' + title) + $tip.find('.popover-content').html(this.content) + + var $form = $tip.find('.popover-content > form') + $form.exform() + $form.submit($.proxy(this.submit, this)) + + this.$form = $form + this.$mask = $('

    ') + $tip.find('.popover-content').prepend(this.$mask) + + $tip.removeClass('fade top bottom left right in') + + //bind events + $tip.find('[data-dismiss=editpop]').on('click.' + this.type, $.proxy(this.leave, this, this)) + + var me = ((Math.random() * 10) + "").replace(/\D/g, '') + var click_event_ns = "click." + me + " touchstart." + me + var that = this + + // $('body').on(click_event_ns, function(e) { + // if ( !$tip.has(e.target).length ) { that.hide() } + // }) + + $(document).bind('keyup.editpop', function(e) { + if (e.keyCode == 27) { that.leave(that) } + return + }) + } + + Editpop.prototype.hasContent = function () { + return this.getTitle() || this.content + } + + Editpop.prototype.submit = function(e) { + e.stopPropagation() + e.preventDefault() + + $.when(this.save()) + .done($.proxy(function(data) { + this.$mask.hide() + this.$mask.parents('.popover').hide() + if(data['result'] != 'success' && data['errors']){ + var err_html = [] + for (var i = data['errors'].length - 1; i >= 0; i--) { + var e = data['errors'][i] + for (var j = e['errors'].length - 1; j >= 0; j--) { + err_html.push(''+e['errors'][j]+'') + } + } + this.$form.find(".control-group").addClass('has-error') + this.$form.find('.controls').append(err_html.join('\n')) + } else { + this.$text.html(data['new_html'][this.field]) + this.leave(this) + } + }, this)) + .fail($.proxy(function(xhr) { + this.$mask.hide() + this.$mask.parents('.popover').hide() + alert(typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!'); + }, this)) + } + + Editpop.prototype.save = function(newValue) { + this.$form.find('.control-group').removeClass('has-error') + this.$form.find('.controls .help-block.error').remove() + + this.$mask.show() + + var off_check_box = Object(); + this.$form.find('input[type=checkbox]').each(function(){ + if(!$(this).is(':checked')){ + off_check_box[$(this).attr('name')] = '' + } + }) + + return $.ajax({ + data: [this.$form.serialize(), $.param(off_check_box)].join('&'), + url: this.$form.attr('action'), + type: "POST", + dataType: 'json', + beforeSend: function(xhr, settings) { + xhr.setRequestHeader("X-CSRFToken", $.getCookie('csrftoken')) + } + }) + } + + // POPOVER PLUGIN DEFINITION + // ========================= + + var old = $.fn.editpop + + $.fn.editpop = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.editpop') + var options = typeof option == 'object' && options + + if (!data) $this.data('bs.editpop', (data = new Editpop(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.editpop.Constructor = Editpop + + + // POPOVER NO CONFLICT + // =================== + + $.fn.editpop.noConflict = function () { + $.fn.editpop = old + return this + } + + $(function(){ + $('.editable-handler').editpop(); + }) + +}(window.jQuery); diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.filters.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.filters.js new file mode 100644 index 0000000..2d77cd6 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.filters.js @@ -0,0 +1,57 @@ +(function($) { + + $(function(){ + + // filter + $('.filter-multiselect input[type=checkbox]').click(function(e){ + window.location.href = $(this).parent().attr('href'); + }); + + // menber filter + $('.filter-number .remove').click(function(e){ + $(this).parent().parent().find('input[type="number"]').val(''); + }); + + $('.filter-number .toggle').click(function(e){ + var new_name = $(this).hasClass('active') ? $(this).attr('data-off-name') : $(this).attr('data-on-name'); + $(this).parent().parent().find('input[type="number"]').attr('name', new_name); + }); + + $('#filter-menu form').submit(function(){ + $(this).find('input[type="text"],input[type="number"]').each(function(e){ + if(!$(this).val()) $(this).attr('name', ''); + }); + return true; + }); + + $('.menu-date-range form').each(function(){ + var el = $(this); + var start_date = el.find('.calendar.date-start').datepicker({format: 'yyyy-mm-dd', language: 'xadmin'}); + var end_date = el.find('.calendar.date-end').datepicker({format: 'yyyy-mm-dd', language: 'xadmin'}); + + var checkAvailable = function(){ + if(start_date.data('datepicker').getDate().valueOf() <= end_date.data('datepicker').getDate().valueOf()){ + el.find('button[type=submit]').removeAttr('disabled'); + } else { + el.find('button[type=submit]').attr('disabled', 'disabled'); + } + } + + start_date.on('changeDate', function(ev){ + var startdate = start_date.data('date'); + el.find('.start_input').val(startdate); + end_date.data('datepicker').setStartDate(startdate); + checkAvailable(); + }); + end_date.on('changeDate', function(ev){ + var enddate = end_date.data('date'); + el.find('.end_input').val(enddate); + start_date.data('datepicker').setEndDate(enddate); + checkAvailable(); + }); + + checkAvailable(); + }); + }); + +})(jQuery); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.formset.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.formset.js new file mode 100644 index 0000000..3c30dae --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.formset.js @@ -0,0 +1,145 @@ +;(function($) { + $.fn.formset = function(opts){ + var $$ = $(this); + + var options = $.extend({ + prefix: $$.data('prefix') + }, $.fn.formset.styles[$$.data('style')], opts), + + updateElementIndex = function(elem, prefix, ndx) { + var idRegex = new RegExp(prefix + '-(\\d+|__prefix__)-'), + replacement = prefix + '-' + ndx + '-'; + if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement)); + if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement)); + if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement)); + if (elem.attr('href')) elem.attr('href', elem.attr('href').replace(idRegex, replacement)); + elem.find('.formset-num').html(ndx + 1); + }, + + hasChildElements = function(row) { + return row.find('input,select,textarea,label,div,a').length > 0; + }, + + updateRowIndex = function(row, i){ + if (options.update) options.update(row, (function(elem){ + updateElementIndex(elem, options.prefix, i); + })); + updateElementIndex(row, options.prefix, i); + row.find('input,select,textarea,label,div,a').each(function() { + updateElementIndex($(this), options.prefix, i); + }); + row.data('row-index', i); + }, + + insertDeleteLink = function(row) { + row.find('a.delete-row').click(function() { + var row = $(this).parents(".formset-row"), + del = row.find('input[id $= "-DELETE"]'); + + if (options.removed) options.removed(row, del, $$); + + if (del.length) { + if(del.val() == 'on'){ + row.removeClass('row-deleted'); + } else { + row.addClass('row-deleted'); + } + del.val(del.val() == 'on'?'':'on'); + } else { + var parent = row.parent(); + row.remove(); + var forms = parent.find('.formset-row'); + $('#id_' + options.prefix + '-TOTAL_FORMS').val(forms.length); + for (var i=0, formCount=forms.length; i#'+ (row.data('row-index') + 1) +''); + $$.parent().find('.nav-tabs').append(new_tab); + new_tab.find('a').tab('show'); + }, + update: function(row, update){ + var rowId = row.attr('id'); + if(rowId){ + $('a[href=#'+rowId+']').each(function(){ + update($(this)); + }) + } + }, + removed: function(row, del, $$){ + var rowId = row.attr('id'); + if(rowId){ + var tab = $('a[href=#'+rowId+']'); + if (del.length) { + if(del.val() == 'on'){ + tab.removeClass('row-deleted'); + } else { + tab.addClass('row-deleted'); + } + } else { + if(tab.parent().next().length){ + tab.parent().next().find('a').tab('show'); + } else { + tab.parent().prev().find('a').tab('show'); + } + tab.parent().remove(); + } + } + } + } + }; + + $(function(){ + $('.formset-content').each(function(){ + $(this).formset(); + }); + }); +})(jQuery); diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.importexport.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.importexport.js new file mode 100644 index 0000000..4f76c4d --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.importexport.js @@ -0,0 +1,12 @@ +$("#export-menu").click(function () { + $("input[name='_select_across']").val($("input[name='select_across']").val()); + if (0 == $("input[name='select_across']").val()) { + var selectedRecords = []; + $.each($('.action-select'), function () { + if (true == $(this).prop('checked')) { + selectedRecords.push($(this).val()); + } + }); + $("input[name='_selected_actions']").val(selectedRecords.join(',')); + } +}); diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.portal.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.portal.js new file mode 100644 index 0000000..18d04bd --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.portal.js @@ -0,0 +1,30 @@ +jQuery(function() { + $( ".column" ).sortable({ + connectWith: ".column", + handle: '.panel-heading', + forcePlaceholderSize: true, + cursor: "move", + cancel: ".unsort, .tab-content", + stop: function( event, ui ) { + var pos = []; + $('.column').each(function(){ + var col = []; + $(this).find('.panel').each(function(){ + col.push($(this).attr('id')); + }); + pos.push(col.join(',')); + }); + var pos_val = pos.join('|'); + var key = $('#_portal_key').val(); + $.save_user_settings(key, pos_val, function(){ + //alert('success'); + }); + } + }); + + $( ".panel-heading .icon.chevron" ).click(function() { + $( this ).toggleClass( "fa fa-chevron-up" ).toggleClass( "fa fa-chevron-down" ); + $( this ).parents( ".panel:first" ).find( ".panel-body" ).toggle('fast'); + }); + +}); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.quick-form.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.quick-form.js new file mode 100644 index 0000000..779300d --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.quick-form.js @@ -0,0 +1,231 @@ + +;(function($){ + + $('form.widget-form').on('post-success', function(e, data){ + $(this).data('ajaxform').clean() + $('.alert-success #change-link').attr('href', data['change_url']) + $('.alert-success').show() + }) + + var AjaxForm = function(element, options) { + var that = this + + this.$form = $(element) + this.ainit() + } + + AjaxForm.prototype = { + + constructor: AjaxForm + + , ainit: function(){ + this.$mask = $('

    ') + + this.$form.prepend(this.$mask) + this.$form.submit($.proxy(this.submit, this)) + + this.$form.find('input, select, textarea').each(function(){ + var el = $(this) + if (el.is("[type=checkbox]")) { + el.data('init-value', el.attr('checked')) + } else if (el.is("select")) { + el.data('init-value', el[0].selectedIndex) + } else { + el.data('init-value', el.val()) + } + }) + } + + , clean: function(){ + this.$form.find('input, select, textarea').each(function(){ + var el = $(this) + if (el.is("[type=checkbox]")) { + el.removeAttr('checked') + } else if (el.is("select")) { + el[0].selectedIndex = el.data('init-value')||0 + } else { + el.val(el.data('init-value')||'') + } + el.change() + }) + } + + , submit: function(e) { + e.stopPropagation(); + e.preventDefault(); + + $.when(this.save()) + .done($.proxy(function(data) { + this.$mask.hide(); + + this.$form.find('submit, button[type=submit], input[type=submit]').removeClass('disabled'); + this.$form.find('.alert-success').hide() + + if(data['result'] != 'success' && data['errors']){ + var non_fields_errors = [] + for (var i = data['errors'].length - 1; i >= 0; i--) { + var e = data['errors'][i] + var errdiv = this.$form.find('#div_' + e['id']) + if(errdiv.length){ + errdiv.addClass('has-error') + var err_html = [] + for (var j = e['errors'].length - 1; j >= 0; j--) { + err_html.push(''+e['errors'][j]+'') + } + errdiv.find('.controls').append(err_html.join('\n')) + } else { + non_fields_errors = non_fields_errors.concat(e['errors']) + } + } + if(non_fields_errors.length){ + var err_html = [] + for (var i = non_fields_errors.length - 1; i >= 0; i--) { + err_html.push('

    '+e['errors'][i]+'

    ') + } + this.$form.prepend(err_html.join('\n')) + } + } else { + this.$form.trigger('post-success', data); + } + }, this)) + .fail($.proxy(function(xhr) { + this.$mask.hide(); + alert(typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!'); + }, this)); + } + , save: function(newValue) { + + this.$form.find('.text-error, .help-inline.error').remove(); + this.$form.find('.control-group').removeClass('error'); + + this.$mask.show(); + this.$form.find('submit, button[type=submit], input[type=submit]').addClass('disabled'); + + var off_check_box = Object(); + // this.$form.find('input[type=checkbox]').each(function(){ + // if(!$(this).attr('checked')){ + // off_check_box[$(this).attr('name')] = ''; + // } + // }) + + return $.ajax({ + data: [this.$form.serialize(), $.param(off_check_box)].join('&'), + url: this.$form.attr('action'), + type: "POST", + dataType: 'json', + beforeSend: function(xhr, settings) { + xhr.setRequestHeader("X-CSRFToken", $.getCookie('csrftoken')); + } + }) + }, + } + + $.fn.ajaxform = function ( option ) { + var args = Array.apply(null, arguments); + args.shift(); + return this.each(function () { + var $this = $(this), + data = $this.data('ajaxform'), + options = typeof option == 'object' && option; + if (!data) { + $this.data('ajaxform', (data = new AjaxForm(this))); + } + }); + }; + + $.fn.ajaxform.Constructor = AjaxForm + + $.fn.exform.renders.push(function(f){ + if (f.is('.quick-form')) { + f.ajaxform() + } + }) + + var QuickAddBtn = function(element, options) { + var that = this; + + this.$btn = $(element) + this.add_url = this.$btn.attr('href') + this.$for_input = $('#' + this.$btn.data('for-id')) + this.$for_wrap = $('#' + this.$btn.data('for-id') + '_wrap_container') + this.refresh_url = this.$btn.data('refresh-url') + this.rendered_form = false + + this.binit(element, options); + } + + QuickAddBtn.prototype = { + + constructor: QuickAddBtn + + , binit: function(element, options){ + this.$btn.click($.proxy(this.click, this)) + } + , click: function(e) { + e.stopPropagation() + e.preventDefault() + + if(!this.modal){ + var modal = $('') + $('body').append(modal) + + var self = this + modal.find('.modal-body').html('

    ') + modal.find('.modal-body').load(this.add_url, function(form_html, status, xhr){ + var form = $(this).find('form') + form.addClass('quick-form') + form.on('post-success', $.proxy(self.post, self)) + form.exform() + + modal.find('.modal-footer').show() + modal.find('.btn-submit').click(function(){form.submit()}) + + self.$form = form + }) + this.modal = modal + } + this.modal.modal(); + + return false + } + , post: function(e, data){ + this.$form.data('ajaxform').clean(); + var wrap = this.$for_wrap; + var input = this.$for_input; + var selected = [data['obj_id']]; + if (input.attr('multiple')){ + var opt = 'option'; + if (input.hasClass('selectdropdown') || input.hasClass('select-multi')){ + opt = 'option:selected'; + } + selected.push($.map(input.find(opt) ,function(opt) { return opt.value; })); + } + $.get(this.refresh_url + selected.join() ,function(form_html, status, xhr){ + wrap.html($('' + form_html + '').find('#' + wrap.attr('id')).html()); + wrap.exform(); + }); + this.modal.modal('hide'); + } + + } + + $.fn.ajax_addbtn = function ( option ) { + return this.each(function () { + var $this = $(this), data = $this.data('ajax_addbtn'); + if (!data) { + $this.data('ajax_addbtn', (data = new QuickAddBtn(this))); + } + }); + }; + + $.fn.ajax_addbtn.Constructor = QuickAddBtn + + $.fn.exform.renders.push(function(f){ + f.find('a.btn-ajax').ajax_addbtn() + }) + +})(jQuery) diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.quickfilter.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.quickfilter.js new file mode 100644 index 0000000..6caaf79 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.quickfilter.js @@ -0,0 +1,49 @@ +;(function($){ + $('[data-toggle=tooltip]').tooltip(); + var max=10; + + function addShowMore($,v){ + $(v).nextUntil('li.nav-header').last().after( + $('
  • Show more
  • ').click(function(e){ + e.preventDefault(); + e.stopPropagation(); + $(v).nextUntil('li.nav-header').show(); + $(v).nextUntil('li.nav-header').last().remove(); + addShowLess($,v); + }) + ); + $(v).nextUntil('li.nav-header').last().show(); + } + + function addShowLess($,v){ + $(v).nextUntil('li.nav-header').last().after( + $('
  • Show less
  • ').click(function(e){ + e.preventDefault(); + e.stopPropagation(); + $(v).nextUntil('li.nav-header').filter(function(i){return !$(this).find('input').is(':checked');}).slice(max).hide(); + $(v).nextUntil('li.nav-header').last().remove(); + $(v).scrollMinimal(3000); + addShowMore($,v); + }) + ); + $(v).nextUntil('li.nav-header').last().show(); + } + + $.each($('.nav-quickfilter li.nav-header'),function(i,v){ + if ($(v).nextUntil('li.nav-header').size()>max) { + $(v).nextUntil('li.nav-header').filter(function(i){return !$(this).find('input').is(':checked');}).slice(max).hide(); + addShowMore($,v); + } + }); + + $('.nav-quickfilter li.nav-header').on('click',function(e) { + e.preventDefault(); + e.stopPropagation(); + $('.nav-quickfilter li.nav-header i').toggleClass('icon-chevron-right'); + $('.nav-quickfilter li.nav-header i').toggleClass('icon-chevron-left'); + $('#left-side').toggleClass('col-md-2'); + $('#left-side').toggleClass('col-md-4'); + $('#content-block').toggleClass('col-md-10'); + $('#content-block').toggleClass('col-md-8'); + }); +})(jQuery) \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.refresh.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.refresh.js new file mode 100644 index 0000000..0b0a19f --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.refresh.js @@ -0,0 +1,22 @@ +(function($) { + + $.dofresh = function(){ + var refresh_el = $('#refresh_time'); + var time = parseInt(refresh_el.text()); + if(time == 1){ + refresh_el.text(0); + window.location.reload(); + } else { + refresh_el.text(time-1); + setTimeout("$.dofresh()",1000) + } + }; + + $(function(){ + var refresh_el = $('#refresh_time'); + if(refresh_el){ + setTimeout("$.dofresh()",1000) + } + }); + +})(jQuery); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.revision.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.revision.js new file mode 100644 index 0000000..4ff6a37 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.revision.js @@ -0,0 +1,28 @@ +jQuery(function($){ + $('.diff_field').each(function(){ + var el = $(this); + var textarea = el.find('textarea.org-data'); + var title = el.data('org-data') || el.attr('title'); + if(textarea.length){ + title = textarea.val(); + } + el.find('.controls').tooltip({ + title: title, + html: true + }) + }); + + $('.formset-content .formset-row').each(function(){ + var row = $(this); + var del = row.find('input[id $= "-DELETE"]'); + if(del.val() == 'on' || del.val() == 'True'){ + row.addClass('row-deleted'); + del.val('on'); + } + var idinput = row.find('input[id $= "-id"]'); + if(idinput.val() == '' || idinput.val() == undefined){ + row.addClass('row-added'); + row.find('.formset-num').html(gettext('New Item')); + } + }); +}); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.sortablelist.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.sortablelist.js new file mode 100644 index 0000000..0f78e10 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.sortablelist.js @@ -0,0 +1,49 @@ +(function($) { + $(function() { + $.ajaxSetup({ + beforeSend: function(xhr, settings) { + function getCookie(name) { + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) { + // Only send the token to relative URLs i.e. locally. + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); + } + } + }); + + $(".results table tbody").sortable({ + axis: 'y', + items: 'tr', + cursor: 'move', + opacity: 0.8, + update: function(event, ui) { + var $rows = $(this); + $("#save-order").on("click", function(e) { + $.ajax({ + url: $(this).attr('post-url'), + method: 'POST', + data: $rows.sortable('serialize', { + attribute: 'order-key', + expression: (/(.+)_(.+)/), + }) + }); + location.reload(); + }).show(); + } + }); + }); + +})(jQuery); diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.themes.js b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.themes.js new file mode 100644 index 0000000..fcd7158 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.plugin.themes.js @@ -0,0 +1,95 @@ +(function($) { + + $.setCookie = function(name, value, options){ + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + var path = options.path ? '; path=' + options.path : ''; + var domain = options.domain ? '; domain=' + options.domain : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } + + $(function(){ + var top_nav = $('#top-nav'); + $('#body-content').css('margin-top', (top_nav.height() + 15) + 'px'); + + if($("#g-theme-menu")){ + $('#g-theme-menu li>a').click(function(){ + var $el = $(this); + var themeHref = $el.data('css-href'); + + var topmenu = $('#top-nav .navbar-collapse'); + if(topmenu.data('bs.collapse')) topmenu.collapse('hide'); + + var modal = $(''); + $('body').append(modal); + + modal.on('shown.bs.modal', function(){ + $.save_user_settings("site-theme", themeHref, function(){ + $.setCookie('_theme', themeHref); + + var iframe = document.createElement("IFRAME"); + iframe.style.display = 'none'; + document.body.appendChild(iframe); + + modal.on('hidden', function(e){ + if(iframe){ + $(iframe).unbind('load'); + iframe.parentNode.removeChild(iframe); + iframe = null; + } + modal.remove(); + }); + + $(iframe).load(function () { + $('#site-theme').attr('href', themeHref); + + setTimeout(function(){ + var nav_height = $('#top-nav').height(); + $('#body-content').animate({'margin-top': (nav_height + 15)}, 500, 'easeOutBounce'); + }, 500); + + modal.modal('hide'); + iframe.parentNode.removeChild(iframe); + iframe = null; + }) + + var ifmDoc = iframe.contentDocument || iframe.contentWindow.document; + ifmDoc.open(); + ifmDoc.write(''); + ifmDoc.write(''); + ifmDoc.write(''); + ifmDoc.close(); + + + $('#g-theme-menu li').removeClass('active'); + $el.parent().addClass('active'); + }); + }) + + modal.modal().css( + { + 'margin-top': function () { + return window.pageYOffset; + } + }); + }) + } + }); + +})(jQuery); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.responsive.js b/extra_apps/xadmin/static/xadmin/js/xadmin.responsive.js new file mode 100644 index 0000000..5478467 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.responsive.js @@ -0,0 +1,132 @@ +/* include breakpoints.js + Breakpoints.js + version 1.0 + + Creates handy events for your responsive design breakpoints + + Copyright 2011 XOXCO, Inc + http://xoxco.com/ + + Documentation for this plugin lives here: + http://xoxco.com/projects/code/breakpoints + + Licensed under the MIT license: + http://www.opensource.org/licenses/mit-license.php + +*/ +(function($) { + + var lastSize = 0; + var interval = null; + + $.fn.resetBreakpoints = function() { + $(window).unbind('resize'); + if (interval) { + clearInterval(interval); + } + lastSize = 0; + }; + + $.fn.setBreakpoints = function(settings) { + var options = jQuery.extend({ + distinct: true, + breakpoints: new Array(320,480,768,1024) + },settings); + + + interval = setInterval(function() { + + var w = $(window).width(); + var done = false; + + for (var bp in options.breakpoints.sort(function(a,b) { return (b-a) })) { + + // fire onEnter when a browser expands into a new breakpoint + // if in distinct mode, remove all other breakpoints first. + if (!done && w >= options.breakpoints[bp] && lastSize < options.breakpoints[bp]) { + if (options.distinct) { + for (var x in options.breakpoints.sort(function(a,b) { return (b-a) })) { + if ($('body').hasClass('breakpoint-' + options.breakpoints[x])) { + $('body').removeClass('breakpoint-' + options.breakpoints[x]); + $(window).trigger('exitBreakpoint' + options.breakpoints[x]); + } + } + done = true; + } + $('body').addClass('breakpoint-' + options.breakpoints[bp]); + $(window).trigger('enterBreakpoint' + options.breakpoints[bp]); + + } + + // fire onExit when browser contracts out of a larger breakpoint + if (w < options.breakpoints[bp] && lastSize >= options.breakpoints[bp]) { + $('body').removeClass('breakpoint-' + options.breakpoints[bp]); + $(window).trigger('exitBreakpoint' + options.breakpoints[bp]); + + } + + // if in distinct mode, fire onEnter when browser contracts into a smaller breakpoint + if ( + options.distinct && // only one breakpoint at a time + w >= options.breakpoints[bp] && // and we are in this one + w < options.breakpoints[bp-1] && // and smaller than the bigger one + lastSize > w && // and we contracted + lastSize >0 && // and this is not the first time + !$('body').hasClass('breakpoint-' + options.breakpoints[bp]) // and we aren't already in this breakpoint + ) { + $('body').addClass('breakpoint-' + options.breakpoints[bp]); + $(window).trigger('enterBreakpoint' + options.breakpoints[bp]); + + } + } + + // set up for next call + if (lastSize != w) { + lastSize = w; + } + },250); + }; + + var enterPhone = function(){ + $('.content-navbar .navbar-brand').html("sm-" + $(window).width()); + } + + var exitPhone = function(){ + $('.content-navbar .navbar-brand').html("lg-" + $(window).width()); + } + + $(function(){ + $(window).bind('enterBreakpoint768',function() { + enterPhone(); + }); + $(window).bind('exitBreakpoint768',function() { + exitPhone(); + }); + //$(window).setBreakpoints(); + var lastMode = 'lg'; + $(window).bind('resize', function(e){ + var width = $(window).width(); + var mode = 'lg'; + if(width < 768){ mode = 'xs'; } + else if(width < 992){ mode = 'sm'; } + else if(width < 1200){ mode = 'md'; } + if(lastMode != mode){ + $('[data-toggle=breakpoint]').each(function(){ + if(newClass = $(this).data('class-' + mode)){ + $(this)[0].className = newClass; + } else { + $(this)[0].className = $(this).data('class-org'); + } + }) + lastMode = mode; + } + }); + $('[data-toggle=breakpoint]').each(function(){ + $(this).data('class-org', $(this)[0].className); + }) + $(window).trigger('resize'); + }) + +})(jQuery); + + diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.widget.datetime.js b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.datetime.js new file mode 100644 index 0000000..b0eb9cb --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.datetime.js @@ -0,0 +1,90 @@ +;(function($){ + $.convert_format = function(format){ + var fields = { + d: 'dd', + H: 'hh', + I: "HH", + m: 'mm', + M: 'MM', + p: 'PM/AM', + S: 'ss', + w: 'w', + y: 'yy', + Y: 'yyyy', + '%' : '%' + }; + var result = '', i = 0; + while (i < format.length) { + if (format.charAt(i) === '%') { + if(f = fields[format.charAt(i + 1)]){ + result = result + f; + } + ++i; + } else { + result = result + format.charAt(i); + } + ++i; + } + return result; + } + + $.date_local = { + days: gettext("Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday").split(' '), + daysShort: gettext("Sun Mon Tue Wed Thu Fri Sat Sun").split(' '), + daysMin: gettext("Su Mo Tu We Th Fr Sa Su").split(' '), + months: gettext('January February March April May June July August September October November December').split(' '), + monthsShort: gettext("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec").split(' '), + today: gettext("Today"), + date_string: gettext('%a %d %b %Y %T %Z'), + ampm: gettext("AM PM").split(' '), + ampmLower: gettext("am pm").split(' '), + dateFormat: get_format('DATE_INPUT_FORMATS')[0], + dateJSFormat: $.convert_format(get_format('DATE_INPUT_FORMATS')[0]), + timeRepr: gettext('%T') + } + + $.fn.datepicker.dates['xadmin'] = $.date_local; + + $.fn.exform.renders.push(function(f){ + f.find('.input-group.date input').each(function(e){ + var dp = $(this).datepicker({format: $.date_local.dateJSFormat, language: 'xadmin', todayBtn: "linked", autoclose: true}) + .data('datepicker'); + $(this).parent().find('button').click(function(e){ + dp.update(new Date()); + }) + }) + if($.fn.clockpicker){ + f.find('.input-group.bootstrap-clockpicker').each(function(e){ + var el = $(this).find('input'); + var tp = el.clockpicker({ + autoclose: true, + 'default': 'now' + }); + + $(this).find('button').click(function(e){ + var now = new Date() + , value = now.getHours() + ':' + now.getMinutes(); + el.attr('value', value); + }) + }) + } + if($.fn.timepicker){ + f.find('.input-group.bootstrap-timepicker').each(function(e){ + var el = $(this).find('input'); + var value = el.val(); + var tp = el.timepicker({ + minuteStep: 1, + showSeconds: true, + showMeridian: false, + defaultTime: false + }).data('timepicker'); + $(this).find('button').click(function(e){ + tp.$element.val(""); + tp.setDefaultTime('current'); + tp.update(); + }) + }) + } + }); + +})(jQuery) diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.widget.multiselect.js b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.multiselect.js new file mode 100644 index 0000000..3e7d88e --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.multiselect.js @@ -0,0 +1,12 @@ + +;(function($){ + + $.fn.exform.renders.push(function(f){ + if($.fn.multiselect){ + f.find('.selectmultiple.selectdropdown').multiselect({ + + }); + } + }); + +})(jQuery) \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.widget.select-transfer.js b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.select-transfer.js new file mode 100644 index 0000000..0741600 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.select-transfer.js @@ -0,0 +1,241 @@ + +;(function($){ + + var SelectBox = function(element, options) { + var that = this; + + this.el = $(element); + var el = this.el; + + this.filter_input = el.find('.selector-filter input'); + this.from_box = el.find('.selector-available select'); + this.to_box = el.find('.selector-chosen select'); + + var findForm = function(node) { + if (node.tagName.toLowerCase() != 'form') { + return findForm(node.parentNode); + } + return node; + } + this.form = $(findForm(element)); + + // link + this.btn_add_all = el.find(".btn.selector-chooseall"); + this.btn_remove_all = el.find(".btn.selector-clearall"); + this.btn_add = el.find(".btn.selector-add"); + this.btn_remove = el.find(".btn.selector-remove"); + + // setup event + this.filter_input.keyup($.proxy(this.filter_key_up, this)); + this.filter_input.keydown($.proxy(this.filter_key_down, this)); + + this.from_box.on('change', $.proxy(this.refresh_icons, this)); + this.to_box.on('change', $.proxy(this.refresh_icons, this)); + + this.from_box.on('dblclick', $.proxy(this.move, this)); + this.to_box.on('dblclick', $.proxy(this.remove, this)); + + this.btn_add.on('click', $.proxy(this.move, this)); + this.btn_remove.on('click', $.proxy(this.remove, this)); + + this.btn_add_all.on('click', $.proxy(this.move_all, this)); + this.btn_remove_all.on('click', $.proxy(this.remove_all, this)); + + this.form.submit($.proxy(this.select_all, this)); + + // init cache + var from_cache = new Array(); + for (var i = 0; (node = this.from_box[0].options[i]); i++) { + from_cache.push({value: node.value, text: node.text, displayed: 1}); + } + this.from_box.data('cache', from_cache); + + var to_cache = new Array(); + for (var i = 0; (node = this.to_box[0].options[i]); i++) { + to_cache.push({value: node.value, text: node.text, displayed: 1}); + } + this.to_box.data('cache', to_cache); + + this.refresh_icons(); + } + + SelectBox.prototype = { + constructor: SelectBox, + redisplay : function(box){ + var select = box[0]; + var cache = box.data('cache'); + select.options.length = 0; // clear all options + for (var i = 0, j = cache.length; i < j; i++) { + var node = cache[i]; + if (node.displayed) { + select.options[select.options.length] = new Option(node.text, node.value, false, false); + } + } + }, + filter: function(text) { + // Redisplay the HTML select box, displaying only the choices containing ALL + // the words in text. (It's an AND search.) + var tokens = text.toLowerCase().split(/\s+/); + var node, token; + for (var i = 0; (node = this.from_box.data('cache')[i]); i++) { + node.displayed = 1; + for (var j = 0; (token = tokens[j]); j++) { + if (node.text.toLowerCase().indexOf(token) == -1) { + node.displayed = 0; + } + } + } + this.redisplay(this.from_box); + }, + remove: function(){ + this.trans(this.to_box, this.from_box); + }, + move: function(){ + this.trans(this.from_box, this.to_box); + }, + delete_from_cache: function(box, value) { + var node, delete_index = null; + var cache = box.data('cache'); + for (var i = 0; (node = cache[i]); i++) { + if (node.value == value) { + delete_index = i; + break; + } + } + var j = cache.length - 1; + for (var i = delete_index; i < j; i++) { + cache[i] = cache[i+1]; + } + cache.length--; + }, + add_to_cache: function(box, option) { + box.data('cache').push({value: option.value, text: option.text, displayed: 1}); + }, + cache_contains: function(box, value) { + // Check if an item is contained in the cache + var node; + for (var i = 0; (node = box.data('cache')[i]); i++) { + if (node.value == value) { + return true; + } + } + return false; + }, + trans: function(from, to){ + for (var i = 0; (option = from[0].options[i]); i++) { + if (option.selected && this.cache_contains(from, option.value)) { + this.add_to_cache(to, {value: option.value, text: option.text, displayed: 1}); + this.delete_from_cache(from, option.value); + } + } + this.redisplay(from); + this.redisplay(to); + + this.refresh_icons(); + }, + move_all : function(){ + this.trans_all(this.from_box, this.to_box); + }, + remove_all: function(){ + this.trans_all(this.to_box, this.from_box); + }, + trans_all: function(from, to) { + var option; + for (var i = 0; (option = from[0].options[i]); i++) { + if (this.cache_contains(from, option.value)) { + this.add_to_cache(to, {value: option.value, text: option.text, displayed: 1}); + this.delete_from_cache(from, option.value); + } + } + this.redisplay(from); + this.redisplay(to); + + this.refresh_icons(); + }, + sort: function(box) { + box.data('cache').sort( function(a, b) { + a = a.text.toLowerCase(); + b = b.text.toLowerCase(); + try { + if (a > b) return 1; + if (a < b) return -1; + } + catch (e) { + // silently fail on IE 'unknown' exception + } + return 0; + } ); + }, + select_all: function() { + var box = this.to_box[0]; + for (var i = 0; i < box.options.length; i++) { + box.options[i].selected = 'selected'; + } + }, + refresh_icons: function() { + var is_from_selected = this.from_box.find('option:selected').length > 0; + var is_to_selected = this.to_box.find('option:selected').length > 0; + // Active if at least one item is selected + this.btn_add.toggleClass('disabled', !is_from_selected); + this.btn_remove.toggleClass('disabled', !is_to_selected); + // Active if the corresponding box isn't empty + this.btn_add_all.toggleClass('disabled', this.from_box.find('option').length == 0); + this.btn_remove_all.toggleClass('disabled', this.to_box.find('option').length == 0); + }, + filter_key_up: function(event) { + var from = this.from_box[0]; + // don't submit form if user pressed Enter + if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) { + var temp = from.selectedIndex; + this.move(); + from.selectedIndex = temp; + return false; + } + var temp = from.selectedIndex; + this.filter(this.filter_input.val()); + from.selectedIndex = temp; + return true; + }, + filter_key_down: function(event) { + var from = this.from_box[0]; + if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) { + return false; + } + // right arrow -- move across + if ((event.which && event.which == 39) || (event.keyCode && event.keyCode == 39)) { + var old_index = from.selectedIndex; + this.move(); + from.selectedIndex = (old_index == from.length) ? from.length - 1 : old_index; + return false; + } + // down arrow -- wrap around + if ((event.which && event.which == 40) || (event.keyCode && event.keyCode == 40)) { + from.selectedIndex = (from.length == from.selectedIndex + 1) ? 0 : from.selectedIndex + 1; + } + // up arrow -- wrap around + if ((event.which && event.which == 38) || (event.keyCode && event.keyCode == 38)) { + from.selectedIndex = (from.selectedIndex == 0) ? from.length - 1 : from.selectedIndex - 1; + } + return true; + } + + } + + $.fn.select_transfer = function ( option ) { + var args = Array.apply(null, arguments); + args.shift(); + return this.each(function () { + var $this = $(this), + data = $this.data('transfer'), + options = typeof option == 'object' && option; + if (!data) { + $this.data('transfer', (data = new SelectBox(this))); + } + }); + }; + + $.fn.exform.renders.push(function(f){ + f.find('.select-transfer').select_transfer(); + }); + +})(jQuery) diff --git a/extra_apps/xadmin/static/xadmin/js/xadmin.widget.select.js b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.select.js new file mode 100644 index 0000000..1dd9a38 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/js/xadmin.widget.select.js @@ -0,0 +1,38 @@ +;(function($){ + // add select render + $.fn.exform.renders.push(function(f){ + if($.fn.selectize){ + f.find('select:not(.select-search):not([multiple=multiple])').selectize(); + f.find('.select-search').each(function(){ + var $el = $(this); + var preload = $el.hasClass('select-preload'); + $el.selectize({ + valueField: 'id', + labelField: '__str__', + searchField: '__str__', + create: false, + maxItems: 1, + preload: preload, + load: function(query, callback) { + if(!preload && !query.length) return callback(); + $.ajax({ + url: $el.data('search-url')+$el.data('choices'), + dataType: 'json', + data: { + '_q_' : query, + '_cols': 'id.__str__' + }, + type: 'GET', + error: function() { + callback(); + }, + success: function(res) { + callback(res.objects); + } + }); + } + }); + }) + }}); +})(jQuery) + diff --git a/extra_apps/xadmin/static/xadmin/vendor/autotype/index.js b/extra_apps/xadmin/static/xadmin/vendor/autotype/index.js new file mode 100644 index 0000000..4fc86fb --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/autotype/index.js @@ -0,0 +1,283 @@ +/** + * jQuery.autotype - Simple, accurate, typing simulation for jQuery + * + * version 0.5.0 + * + * http://michaelmonteleone.net/projects/autotype + * http://github.com/mmonteleone/jquery.autotype + * + * Copyright (c) 2009 Michael Monteleone + * Licensed under terms of the MIT License (README.markdown) + */ +(function($){ + + // code type constants + var CHARACTER = 1, + NON_CHARACTER = 2, + MODIFIER_BEGIN = 3, + MODIFIER_END = 4, + isNullOrEmpty = function(val) { return val === null || val.length === 0; }, + isUpper = function(char) { return char.toUpperCase() === char; }, + isLower = function(char) { return char.toLowerCase() === char; }, + areDifferentlyCased = function(char1,char2) { + return (isUpper(char1) && isLower(char2)) || + (isLower(char1) && isUpper(char2)); + }, + convertCase = function(char) { + return isUpper(char) ? char.toLowerCase() : char.toUpperCase(); + }, + parseCodes = function(value, codeMap) { + // buffer to hold a collection of key/char code pairs corresponding to input string value + var codes = [], + // buffer to hold the name of a control key as it's being parsed + definingControlKey = false, + // hold a collection of currently pushed modifier keys + activeModifiers = { + alt: false, + meta: false, + shift: false, + ctrl: false + }, + explicitModifiers = $.extend({}, activeModifiers), + // buffer to hold construction of current control key + currentControlKey = '', + previousChar = '', + pushCode = function(opts) { + codes.push($.extend({}, opts, activeModifiers)); + }, + pushModifierBeginCode = function(modifierName) { + activeModifiers[modifierName] = true; + pushCode({ + keyCode: codeMap[modifierName], + charCode: 0, + char: '', + type: MODIFIER_BEGIN + }); + }, + pushModifierEndCode = function(modifierName) { + activeModifiers[modifierName] = false; + pushCode({ + keyCode: codeMap[modifierName], + charCode: 0, + char: '', + type: MODIFIER_END + }); + }; + + for(var i=0;i 0) { + codes = codes.reverse(); + var keyInterval = global.setInterval(function(){ + var code = codes.pop(); + triggerCodeOnField(code, field); + if(codes.length === 0) { + global.clearInterval(keyInterval); + field.trigger('autotyped'); + } + }, delay); + } else { + $.each(codes,function(){ + triggerCodeOnField(this, field); + }); + field.trigger('autotyped'); + } + }; + + $.fn.autotype = function(value, options) { + if(value === undefined || value === null) { throw("Value is required by jQuery.autotype plugin"); } + var settings = $.extend({}, $.fn.autotype.defaults, options); + + // 1st Pass + // step through the input string and convert it into + // a logical sequence of steps, key, and charcodes to apply to the inputs + var codes = parseCodes(value, settings.keyCodes[settings.keyBoard]); + + // 2nd Pass + // Run the translated codes against each input through a realistic + // and cancelable series of key down/press/up events + return this.each(function(){ triggerCodesOnField(codes, $(this), settings.delay, settings.global); }); + }; + + $.fn.autotype.defaults = { + version: '0.5.0', + keyBoard: 'enUs', + delay: 0, + global: window, + keyCodes: { + enUs: { 'back':8,'ins':45,'del':46,'enter':13,'shift':16,'ctrl':17,'meta':224, + 'alt':18,'pause':19,'caps':20,'esc':27,'pgup':33,'pgdn':34, + 'end':35,'home':36,'left':37,'up':38,'right':39,'down':40, + 'printscr':44,'num0':96,'num1':97,'num2':98,'num3':99,'num4':100, + 'num5':101,'num6':102,'num7':103,'num8':104,'num9':105, + 'multiply':106,'add':107,'subtract':109,'decimal':110, + 'divide':111,'f1':112,'f2':113,'f3':114,'f4':115,'f5':116, + 'f6':117,'f7':118,'f8':119,'f9':120,'f10':121,'f11':122, + 'f12':123,'numlock':144,'scrolllock':145,' ':9,' ':32, + 'tab':9,'space':32,'0':48,'1':49,'2':50,'3':51,'4':52, + '5':53,'6':54,'7':55,'8':56,'9':57,')':48,'!':49,'@':50, + '#':51,'$':52,'%':53,'^':54,'&':55,'*':56,'(':57,';':186, + '=':187,',':188,'-':189,'.':190,'/':191,'[':219,'\\':220, + ']':221,"'":222,':':186,'+':187,'<':188,'_':189,'>':190, + '?':191,'{':219,'|':220,'}':221,'"':222,'a':65,'b':66,'c':67, + 'd':68,'e':69,'f':70,'g':71,'h':72,'i':73,'j':74,'k':75, + 'l':76,'m':77,'n':78,'o':79,'p':80,'q':81,'r':82,'s':83, + 't':84,'u':85,'v':86,'w':87,'x':88,'y':89,'z':90,'A':65, + 'B':66,'C':67,'D':68,'E':69,'F':70,'G':71,'H':72,'I':73, + 'J':74,'K':75,'L':76,'M':77,'N':78,'O':79,'P':80,'Q':81, + 'R':82,'S':83,'T':84,'U':85,'V':86,'W':87,'X':88,'Y':89,'Z':90 } + } + }; + +})(jQuery); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.css b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.css new file mode 100644 index 0000000..67d2dc3 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.css @@ -0,0 +1,168 @@ +/*! + * ClockPicker v0.0.7 for Bootstrap (http://weareoutman.github.io/clockpicker/) + * Copyright 2014 Wang Shenwei. + * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) + */ + +.clockpicker .input-group-addon { + cursor: pointer; +} +.clockpicker-moving { + cursor: move; +} +.clockpicker-align-left.popover > .arrow { + left: 25px; +} +.clockpicker-align-top.popover > .arrow { + top: 17px; +} +.clockpicker-align-right.popover > .arrow { + left: auto; + right: 25px; +} +.clockpicker-align-bottom.popover > .arrow { + top: auto; + bottom: 6px; +} +.clockpicker-popover .popover-title { + background-color: #fff; + color: #999; + font-size: 24px; + font-weight: bold; + line-height: 30px; + text-align: center; +} +.clockpicker-popover .popover-title span { + cursor: pointer; +} +.clockpicker-popover .popover-content { + background-color: #f8f8f8; + padding: 12px; +} +.popover-content:last-child { + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} +.clockpicker-plate { + background-color: #fff; + border: 1px solid #ccc; + border-radius: 50%; + width: 200px; + height: 200px; + overflow: visible; + position: relative; + /* Disable text selection highlighting. Thanks to Hermanya */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.clockpicker-canvas, +.clockpicker-dial { + width: 200px; + height: 200px; + position: absolute; + left: -1px; + top: -1px; +} +.clockpicker-minutes { + visibility: hidden; +} +.clockpicker-tick { + border-radius: 50%; + color: #666; + line-height: 26px; + text-align: center; + width: 26px; + height: 26px; + position: absolute; + cursor: pointer; +} +.clockpicker-tick.active, +.clockpicker-tick:hover { + background-color: rgb(192, 229, 247); + background-color: rgba(0, 149, 221, .25); +} +.clockpicker-button { + background-image: none; + background-color: #fff; + border-width: 1px 0 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + margin: 0; + padding: 10px 0; +} +.clockpicker-button:hover { + background-image: none; + background-color: #ebebeb; +} +.clockpicker-button:focus { + outline: none!important; +} +.clockpicker-dial { + -webkit-transition: -webkit-transform 350ms, opacity 350ms; + -moz-transition: -moz-transform 350ms, opacity 350ms; + -ms-transition: -ms-transform 350ms, opacity 350ms; + -o-transition: -o-transform 350ms, opacity 350ms; + transition: transform 350ms, opacity 350ms; +} +.clockpicker-dial-out { + opacity: 0; +} +.clockpicker-hours.clockpicker-dial-out { + -webkit-transform: scale(1.2, 1.2); + -moz-transform: scale(1.2, 1.2); + -ms-transform: scale(1.2, 1.2); + -o-transform: scale(1.2, 1.2); + transform: scale(1.2, 1.2); +} +.clockpicker-minutes.clockpicker-dial-out { + -webkit-transform: scale(.8, .8); + -moz-transform: scale(.8, .8); + -ms-transform: scale(.8, .8); + -o-transform: scale(.8, .8); + transform: scale(.8, .8); +} +.clockpicker-canvas { + -webkit-transition: opacity 175ms; + -moz-transition: opacity 175ms; + -ms-transition: opacity 175ms; + -o-transition: opacity 175ms; + transition: opacity 175ms; +} +.clockpicker-canvas-out { + opacity: 0.25; +} +.clockpicker-canvas-bearing, +.clockpicker-canvas-fg { + stroke: none; + fill: rgb(0, 149, 221); +} +.clockpicker-canvas-bg { + stroke: none; + fill: rgb(192, 229, 247); +} +.clockpicker-canvas-bg-trans { + fill: rgba(0, 149, 221, .25); +} +.clockpicker-canvas line { + stroke: rgb(0, 149, 221); + stroke-width: 1; + stroke-linecap: round; + /*shape-rendering: crispEdges;*/ +} +.clockpicker-button.am-button { + margin: 1px; + padding: 5px; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 4px; + +} +.clockpicker-button.pm-button { + margin: 1px 1px 1px 136px; + padding: 5px; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 4px; +} diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.js new file mode 100644 index 0000000..e930b4f --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.js @@ -0,0 +1,729 @@ +/*! + * ClockPicker v0.0.7 (http://weareoutman.github.io/clockpicker/) + * Copyright 2014 Wang Shenwei. + * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) + */ + +;(function(){ + var $ = window.jQuery, + $win = $(window), + $doc = $(document), + $body; + + // Can I use inline svg ? + var svgNS = 'http://www.w3.org/2000/svg', + svgSupported = 'SVGAngle' in window && (function(){ + var supported, + el = document.createElement('div'); + el.innerHTML = ''; + supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS; + el.innerHTML = ''; + return supported; + })(); + + // Can I use transition ? + var transitionSupported = (function(){ + var style = document.createElement('div').style; + return 'transition' in style || + 'WebkitTransition' in style || + 'MozTransition' in style || + 'msTransition' in style || + 'OTransition' in style; + })(); + + // Listen touch events in touch screen device, instead of mouse events in desktop. + var touchSupported = 'ontouchstart' in window, + mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : ''), + mousemoveEvent = 'mousemove.clockpicker' + ( touchSupported ? ' touchmove.clockpicker' : ''), + mouseupEvent = 'mouseup.clockpicker' + ( touchSupported ? ' touchend.clockpicker' : ''); + + // Vibrate the device if supported + var vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null; + + function createSvgElement(name) { + return document.createElementNS(svgNS, name); + } + + function leadingZero(num) { + return (num < 10 ? '0' : '') + num; + } + + // Get a unique id + var idCounter = 0; + function uniqueId(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + } + + // Clock size + var dialRadius = 100, + outerRadius = 80, + // innerRadius = 80 on 12 hour clock + innerRadius = 54, + tickRadius = 13, + diameter = dialRadius * 2, + duration = transitionSupported ? 350 : 1; + + // Popover template + var tpl = [ + '
    ', + '
    ', + '
    ', + '', + ' : ', + '', + '', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + '', + '', + '
    ', + '
    ' + ].join(''); + + // ClockPicker + function ClockPicker(element, options) { + var popover = $(tpl), + plate = popover.find('.clockpicker-plate'), + hoursView = popover.find('.clockpicker-hours'), + minutesView = popover.find('.clockpicker-minutes'), + amPmBlock = popover.find('.clockpicker-am-pm-block'), + isInput = element.prop('tagName') === 'INPUT', + input = isInput ? element : element.find('input'), + addon = element.find('.input-group-addon'), + self = this, + timer; + + this.id = uniqueId('cp'); + this.element = element; + this.options = options; + this.isAppended = false; + this.isShown = false; + this.currentView = 'hours'; + this.isInput = isInput; + this.input = input; + this.addon = addon; + this.popover = popover; + this.plate = plate; + this.hoursView = hoursView; + this.minutesView = minutesView; + this.amPmBlock = amPmBlock; + this.spanHours = popover.find('.clockpicker-span-hours'); + this.spanMinutes = popover.find('.clockpicker-span-minutes'); + this.spanAmPm = popover.find('.clockpicker-span-am-pm'); + this.amOrPm = "PM"; + + // Setup for for 12 hour clock if option is selected + if (options.twelvehour) { + + var amPmButtonsTemplate = ['
    ', + '', + '', + '
    '].join(''); + + var amPmButtons = $(amPmButtonsTemplate); + //amPmButtons.appendTo(plate); + + ////Not working b/c they are not shown when this runs + //$('clockpicker-am-button') + // .on("click", function() { + // self.amOrPm = "AM"; + // $('.clockpicker-span-am-pm').empty().append('AM'); + // }); + // + //$('clockpicker-pm-button') + // .on("click", function() { + // self.amOrPm = "PM"; + // $('.clockpicker-span-am-pm').empty().append('PM'); + // }); + + $('') + .on("click", function() { + self.amOrPm = "AM"; + $('.clockpicker-span-am-pm').empty().append('AM'); + }).appendTo(this.amPmBlock); + + + $('') + .on("click", function() { + self.amOrPm = 'PM'; + $('.clockpicker-span-am-pm').empty().append('PM'); + }).appendTo(this.amPmBlock); + + } + + if (! options.autoclose) { + // If autoclose is not setted, append a button + $('') + .click($.proxy(this.done, this)) + .appendTo(popover); + } + + // Placement and arrow align - make sure they make sense. + if ((options.placement === 'top' || options.placement === 'bottom') && (options.align === 'top' || options.align === 'bottom')) options.align = 'left'; + if ((options.placement === 'left' || options.placement === 'right') && (options.align === 'left' || options.align === 'right')) options.align = 'top'; + + popover.addClass(options.placement); + popover.addClass('clockpicker-align-' + options.align); + + this.spanHours.click($.proxy(this.toggleView, this, 'hours')); + this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes')); + + // Show or toggle + input.on('focus.clockpicker click.clockpicker', $.proxy(this.show, this)); + addon.on('click.clockpicker', $.proxy(this.toggle, this)); + + // Build ticks + var tickTpl = $('
    '), + i, tick, radian, radius; + + // Hours view + if (options.twelvehour) { + for (i = 1; i < 13; i += 1) { + tick = tickTpl.clone(); + radian = i / 6 * Math.PI; + radius = outerRadius; + tick.css('font-size', '120%'); + tick.css({ + left: dialRadius + Math.sin(radian) * radius - tickRadius, + top: dialRadius - Math.cos(radian) * radius - tickRadius + }); + tick.html(i === 0 ? '00' : i); + hoursView.append(tick); + tick.on(mousedownEvent, mousedown); + } + } else { + for (i = 0; i < 24; i += 1) { + tick = tickTpl.clone(); + radian = i / 6 * Math.PI; + var inner = i > 0 && i < 13; + radius = inner ? innerRadius : outerRadius; + tick.css({ + left: dialRadius + Math.sin(radian) * radius - tickRadius, + top: dialRadius - Math.cos(radian) * radius - tickRadius + }); + if (inner) { + tick.css('font-size', '120%'); + } + tick.html(i === 0 ? '00' : i); + hoursView.append(tick); + tick.on(mousedownEvent, mousedown); + } + } + + // Minutes view + for (i = 0; i < 60; i += 5) { + tick = tickTpl.clone(); + radian = i / 30 * Math.PI; + tick.css({ + left: dialRadius + Math.sin(radian) * outerRadius - tickRadius, + top: dialRadius - Math.cos(radian) * outerRadius - tickRadius + }); + tick.css('font-size', '120%'); + tick.html(leadingZero(i)); + minutesView.append(tick); + tick.on(mousedownEvent, mousedown); + } + + // Clicking on minutes view space + plate.on(mousedownEvent, function(e){ + if ($(e.target).closest('.clockpicker-tick').length === 0) { + mousedown(e, true); + } + }); + + // Mousedown or touchstart + function mousedown(e, space) { + var offset = plate.offset(), + isTouch = /^touch/.test(e.type), + x0 = offset.left + dialRadius, + y0 = offset.top + dialRadius, + dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, + dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0, + z = Math.sqrt(dx * dx + dy * dy), + moved = false; + + // When clicking on minutes view space, check the mouse position + if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius)) { + return; + } + e.preventDefault(); + + // Set cursor style of body after 200ms + var movingTimer = setTimeout(function(){ + $body.addClass('clockpicker-moving'); + }, 200); + + // Place the canvas to top + if (svgSupported) { + plate.append(self.canvas); + } + + // Clock + self.setHand(dx, dy, ! space, true); + + // Mousemove on document + $doc.off(mousemoveEvent).on(mousemoveEvent, function(e){ + e.preventDefault(); + var isTouch = /^touch/.test(e.type), + x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, + y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0; + if (! moved && x === dx && y === dy) { + // Clicking in chrome on windows will trigger a mousemove event + return; + } + moved = true; + self.setHand(x, y, false, true); + }); + + // Mouseup on document + $doc.off(mouseupEvent).on(mouseupEvent, function(e){ + $doc.off(mouseupEvent); + e.preventDefault(); + var isTouch = /^touch/.test(e.type), + x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0, + y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0; + if ((space || moved) && x === dx && y === dy) { + self.setHand(x, y); + } + if (self.currentView === 'hours') { + self.toggleView('minutes', duration / 2); + } else { + if (options.autoclose) { + self.minutesView.addClass('clockpicker-dial-out'); + setTimeout(function(){ + self.done(); + }, duration / 2); + } + } + plate.prepend(canvas); + + // Reset cursor style of body + clearTimeout(movingTimer); + $body.removeClass('clockpicker-moving'); + + // Unbind mousemove event + $doc.off(mousemoveEvent); + }); + } + + if (svgSupported) { + // Draw clock hands and others + var canvas = popover.find('.clockpicker-canvas'), + svg = createSvgElement('svg'); + svg.setAttribute('class', 'clockpicker-svg'); + svg.setAttribute('width', diameter); + svg.setAttribute('height', diameter); + var g = createSvgElement('g'); + g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); + var bearing = createSvgElement('circle'); + bearing.setAttribute('class', 'clockpicker-canvas-bearing'); + bearing.setAttribute('cx', 0); + bearing.setAttribute('cy', 0); + bearing.setAttribute('r', 2); + var hand = createSvgElement('line'); + hand.setAttribute('x1', 0); + hand.setAttribute('y1', 0); + var bg = createSvgElement('circle'); + bg.setAttribute('class', 'clockpicker-canvas-bg'); + bg.setAttribute('r', tickRadius); + var fg = createSvgElement('circle'); + fg.setAttribute('class', 'clockpicker-canvas-fg'); + fg.setAttribute('r', 3.5); + g.appendChild(hand); + g.appendChild(bg); + g.appendChild(fg); + g.appendChild(bearing); + svg.appendChild(g); + canvas.append(svg); + + this.hand = hand; + this.bg = bg; + this.fg = fg; + this.bearing = bearing; + this.g = g; + this.canvas = canvas; + } + + raiseCallback(this.options.init); + } + + function raiseCallback(callbackFunction) { + if (callbackFunction && typeof callbackFunction === "function") { + callbackFunction(); + } + } + + // Default options + ClockPicker.DEFAULTS = { + 'default': '', // default time, 'now' or '13:14' e.g. + fromnow: 0, // set default time to * milliseconds from now (using with default = 'now') + placement: 'bottom', // clock popover placement + align: 'left', // popover arrow align + donetext: '完成', // done button text + autoclose: false, // auto close when minute is selected + twelvehour: false, // change to 12 hour AM/PM clock from 24 hour + vibrate: true // vibrate the device when dragging clock hand + }; + + // Show or hide popover + ClockPicker.prototype.toggle = function(){ + this[this.isShown ? 'hide' : 'show'](); + }; + + // Set popover position + ClockPicker.prototype.locate = function(){ + var element = this.element, + popover = this.popover, + offset = element.offset(), + width = element.outerWidth(), + height = element.outerHeight(), + placement = this.options.placement, + align = this.options.align, + styles = {}, + self = this; + + popover.show(); + + // Place the popover + switch (placement) { + case 'bottom': + styles.top = offset.top + height; + break; + case 'right': + styles.left = offset.left + width; + break; + case 'top': + styles.top = offset.top - popover.outerHeight(); + break; + case 'left': + styles.left = offset.left - popover.outerWidth(); + break; + } + + // Align the popover arrow + switch (align) { + case 'left': + styles.left = offset.left; + break; + case 'right': + styles.left = offset.left + width - popover.outerWidth(); + break; + case 'top': + styles.top = offset.top; + break; + case 'bottom': + styles.top = offset.top + height - popover.outerHeight(); + break; + } + + popover.css(styles); + }; + + // Show popover + ClockPicker.prototype.show = function(e){ + // Not show again + if (this.isShown) { + return; + } + + raiseCallback(this.options.beforeShow); + + var self = this; + + // Initialize + if (! this.isAppended) { + // Append popover to body + $body = $(document.body).append(this.popover); + + // Reset position when resize + $win.on('resize.clockpicker' + this.id, function(){ + if (self.isShown) { + self.locate(); + } + }); + + this.isAppended = true; + } + + // Get the time + var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':'); + if (value[0] === 'now') { + var now = new Date(+ new Date() + this.options.fromnow); + value = [ + now.getHours(), + now.getMinutes() + ]; + } + this.hours = + value[0] || 0; + this.minutes = + value[1] || 0; + this.spanHours.html(leadingZero(this.hours)); + this.spanMinutes.html(leadingZero(this.minutes)); + + // Toggle to hours view + this.toggleView('hours'); + + // Set position + this.locate(); + + this.isShown = true; + + // Hide when clicking or tabbing on any element except the clock, input and addon + $doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function(e){ + var target = $(e.target); + if (target.closest(self.popover).length === 0 && + target.closest(self.addon).length === 0 && + target.closest(self.input).length === 0) { + self.hide(); + } + }); + + // Hide when ESC is pressed + $doc.on('keyup.clockpicker.' + this.id, function(e){ + if (e.keyCode === 27) { + self.hide(); + } + }); + + raiseCallback(this.options.afterShow); + }; + + // Hide popover + ClockPicker.prototype.hide = function(){ + raiseCallback(this.options.beforeHide); + + this.isShown = false; + + // Unbinding events on document + $doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id); + $doc.off('keyup.clockpicker.' + this.id); + + this.popover.hide(); + + raiseCallback(this.options.afterHide); + }; + + // Toggle to hours or minutes view + ClockPicker.prototype.toggleView = function(view, delay){ + var raiseAfterHourSelect = false; + if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") { + raiseCallback(this.options.beforeHourSelect); + raiseAfterHourSelect = true; + } + var isHours = view === 'hours', + nextView = isHours ? this.hoursView : this.minutesView, + hideView = isHours ? this.minutesView : this.hoursView; + + this.currentView = view; + + this.spanHours.toggleClass('text-primary', isHours); + this.spanMinutes.toggleClass('text-primary', ! isHours); + + // Let's make transitions + hideView.addClass('clockpicker-dial-out'); + nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out'); + + // Reset clock hand + this.resetClock(delay); + + // After transitions ended + clearTimeout(this.toggleViewTimer); + this.toggleViewTimer = setTimeout(function(){ + hideView.css('visibility', 'hidden'); + }, duration); + + if (raiseAfterHourSelect) { + raiseCallback(this.options.afterHourSelect); + } + }; + + // Reset clock hand + ClockPicker.prototype.resetClock = function(delay){ + var view = this.currentView, + value = this[view], + isHours = view === 'hours', + unit = Math.PI / (isHours ? 6 : 30), + radian = value * unit, + radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius, + x = Math.sin(radian) * radius, + y = - Math.cos(radian) * radius, + self = this; + if (svgSupported && delay) { + self.canvas.addClass('clockpicker-canvas-out'); + setTimeout(function(){ + self.canvas.removeClass('clockpicker-canvas-out'); + self.setHand(x, y); + }, delay); + } else { + this.setHand(x, y); + } + }; + + // Set clock hand to (x, y) + ClockPicker.prototype.setHand = function(x, y, roundBy5, dragging){ + var radian = Math.atan2(x, - y), + isHours = this.currentView === 'hours', + unit = Math.PI / (isHours || roundBy5 ? 6 : 30), + z = Math.sqrt(x * x + y * y), + options = this.options, + inner = isHours && z < (outerRadius + innerRadius) / 2, + radius = inner ? innerRadius : outerRadius, + value; + + if (options.twelvehour) { + radius = outerRadius; + } + + // Radian should in range [0, 2PI] + if (radian < 0) { + radian = Math.PI * 2 + radian; + } + + // Get the round value + value = Math.round(radian / unit); + + // Get the round radian + radian = value * unit; + + // Correct the hours or minutes + if (options.twelvehour) { + if (isHours) { + if (value === 0) { + value = 12; + } + } else { + if (roundBy5) { + value *= 5; + } + if (value === 60) { + value = 0; + } + } + } else { + if (isHours) { + if (value === 12) { + value = 0; + } + value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12; + } else { + if (roundBy5) { + value *= 5; + } + if (value === 60) { + value = 0; + } + } + } + + // Once hours or minutes changed, vibrate the device + if (this[this.currentView] !== value) { + if (vibrate && this.options.vibrate) { + // Do not vibrate too frequently + if (! this.vibrateTimer) { + navigator[vibrate](10); + this.vibrateTimer = setTimeout($.proxy(function(){ + this.vibrateTimer = null; + }, this), 100); + } + } + } + + this[this.currentView] = value; + this[isHours ? 'spanHours' : 'spanMinutes'].html(leadingZero(value)); + + // If svg is not supported, just add an active class to the tick + if (! svgSupported) { + this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function(){ + var tick = $(this); + tick.toggleClass('active', value === + tick.html()); + }); + return; + } + + // Place clock hand at the top when dragging + if (dragging || (! isHours && value % 5)) { + this.g.insertBefore(this.hand, this.bearing); + this.g.insertBefore(this.bg, this.fg); + this.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans'); + } else { + // Or place it at the bottom + this.g.insertBefore(this.hand, this.bg); + this.g.insertBefore(this.fg, this.bg); + this.bg.setAttribute('class', 'clockpicker-canvas-bg'); + } + + // Set clock hand and others' position + var cx = Math.sin(radian) * radius, + cy = - Math.cos(radian) * radius; + this.hand.setAttribute('x2', cx); + this.hand.setAttribute('y2', cy); + this.bg.setAttribute('cx', cx); + this.bg.setAttribute('cy', cy); + this.fg.setAttribute('cx', cx); + this.fg.setAttribute('cy', cy); + }; + + // Hours and minutes are selected + ClockPicker.prototype.done = function() { + raiseCallback(this.options.beforeDone); + this.hide(); + var last = this.input.prop('value'), + value = leadingZero(this.hours) + ':' + leadingZero(this.minutes); + if (this.options.twelvehour) { + value = value + this.amOrPm; + } + + this.input.prop('value', value); + if (value !== last) { + this.input.triggerHandler('change'); + if (! this.isInput) { + this.element.trigger('change'); + } + } + + if (this.options.autoclose) { + this.input.trigger('blur'); + } + + raiseCallback(this.options.afterDone); + }; + + // Remove clockpicker from input + ClockPicker.prototype.remove = function() { + this.element.removeData('clockpicker'); + this.input.off('focus.clockpicker click.clockpicker'); + this.addon.off('click.clockpicker'); + if (this.isShown) { + this.hide(); + } + if (this.isAppended) { + $win.off('resize.clockpicker' + this.id); + this.popover.remove(); + } + }; + + // Extends $.fn.clockpicker + $.fn.clockpicker = function(option){ + var args = Array.prototype.slice.call(arguments, 1); + return this.each(function(){ + var $this = $(this), + data = $this.data('clockpicker'); + if (! data) { + var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option); + $this.data('clockpicker', new ClockPicker($this, options)); + } else { + // Manual operatsions. show, hide, remove, e.g. + if (typeof data[option] === 'function') { + data[option].apply(data, args); + } + } + }); + }; +}()); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.min.css b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.min.css new file mode 100644 index 0000000..cf15078 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.min.css @@ -0,0 +1,5 @@ +/*! + * ClockPicker v0.0.7 for Bootstrap (http://weareoutman.github.io/clockpicker/) + * Copyright 2014 Wang Shenwei. + * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) + */.clockpicker .input-group-addon{cursor:pointer}.clockpicker-moving{cursor:move}.clockpicker-align-left.popover>.arrow{left:25px}.clockpicker-align-top.popover>.arrow{top:17px}.clockpicker-align-right.popover>.arrow{left:auto;right:25px}.clockpicker-align-bottom.popover>.arrow{top:auto;bottom:6px}.clockpicker-popover .popover-title{background-color:#fff;color:#999;font-size:24px;font-weight:700;line-height:30px;text-align:center}.clockpicker-popover .popover-title span{cursor:pointer}.clockpicker-popover .popover-content{background-color:#f8f8f8;padding:12px}.popover-content:last-child{border-bottom-left-radius:5px;border-bottom-right-radius:5px}.clockpicker-plate{background-color:#fff;border:1px solid #ccc;border-radius:50%;width:200px;height:200px;overflow:visible;position:relative;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.clockpicker-canvas,.clockpicker-dial{width:200px;height:200px;position:absolute;left:-1px;top:-1px}.clockpicker-minutes{visibility:hidden}.clockpicker-tick{border-radius:50%;color:#666;line-height:26px;text-align:center;width:26px;height:26px;position:absolute;cursor:pointer}.clockpicker-tick.active,.clockpicker-tick:hover{background-color:#c0e5f7;background-color:rgba(0,149,221,.25)}.clockpicker-button{background-image:none;background-color:#fff;border-width:1px 0 0;border-top-left-radius:0;border-top-right-radius:0;margin:0;padding:10px 0}.clockpicker-button:hover{background-image:none;background-color:#ebebeb}.clockpicker-button:focus{outline:0!important}.clockpicker-dial{-webkit-transition:-webkit-transform 350ms,opacity 350ms;-moz-transition:-moz-transform 350ms,opacity 350ms;-ms-transition:-ms-transform 350ms,opacity 350ms;-o-transition:-o-transform 350ms,opacity 350ms;transition:transform 350ms,opacity 350ms}.clockpicker-dial-out{opacity:0}.clockpicker-hours.clockpicker-dial-out{-webkit-transform:scale(1.2,1.2);-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-o-transform:scale(1.2,1.2);transform:scale(1.2,1.2)}.clockpicker-minutes.clockpicker-dial-out{-webkit-transform:scale(.8,.8);-moz-transform:scale(.8,.8);-ms-transform:scale(.8,.8);-o-transform:scale(.8,.8);transform:scale(.8,.8)}.clockpicker-canvas{-webkit-transition:opacity 175ms;-moz-transition:opacity 175ms;-ms-transition:opacity 175ms;-o-transition:opacity 175ms;transition:opacity 175ms}.clockpicker-canvas-out{opacity:.25}.clockpicker-canvas-bearing,.clockpicker-canvas-fg{stroke:none;fill:#0095dd}.clockpicker-canvas-bg{stroke:none;fill:#c0e5f7}.clockpicker-canvas-bg-trans{fill:rgba(0,149,221,.25)}.clockpicker-canvas line{stroke:#0095dd;stroke-width:1;stroke-linecap:round}.clockpicker-button.am-button{margin:1px;padding:5px;border:1px solid rgba(0,0,0,.2);border-radius:4px}.clockpicker-button.pm-button{margin:1px 1px 1px 136px;padding:5px;border:1px solid rgba(0,0,0,.2);border-radius:4px} \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.min.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.min.js new file mode 100644 index 0000000..c8006a3 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.min.js @@ -0,0 +1,6 @@ +/*! + * ClockPicker v0.0.7 (http://weareoutman.github.io/clockpicker/) + * Copyright 2014 Wang Shenwei. + * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) + */ +!function(){function t(t){return document.createElementNS(p,t)}function i(t){return(10>t?"0":"")+t}function e(t){var i=++m+"";return t?t+i:i}function s(s,r){function p(t,i){var e=u.offset(),s=/^touch/.test(t.type),o=e.left+b,n=e.top+b,p=(s?t.originalEvent.touches[0]:t).pageX-o,h=(s?t.originalEvent.touches[0]:t).pageY-n,k=Math.sqrt(p*p+h*h),v=!1;if(!i||!(g-y>k||k>g+y)){t.preventDefault();var m=setTimeout(function(){c.addClass("clockpicker-moving")},200);l&&u.append(x.canvas),x.setHand(p,h,!i,!0),a.off(d).on(d,function(t){t.preventDefault();var i=/^touch/.test(t.type),e=(i?t.originalEvent.touches[0]:t).pageX-o,s=(i?t.originalEvent.touches[0]:t).pageY-n;(v||e!==p||s!==h)&&(v=!0,x.setHand(e,s,!1,!0))}),a.off(f).on(f,function(t){a.off(f),t.preventDefault();var e=/^touch/.test(t.type),s=(e?t.originalEvent.changedTouches[0]:t).pageX-o,l=(e?t.originalEvent.changedTouches[0]:t).pageY-n;(i||v)&&s===p&&l===h&&x.setHand(s,l),"hours"===x.currentView?x.toggleView("minutes",A/2):r.autoclose&&(x.minutesView.addClass("clockpicker-dial-out"),setTimeout(function(){x.done()},A/2)),u.prepend(j),clearTimeout(m),c.removeClass("clockpicker-moving"),a.off(d)})}}var h=n(V),u=h.find(".clockpicker-plate"),v=h.find(".clockpicker-hours"),m=h.find(".clockpicker-minutes"),T=h.find(".clockpicker-am-pm-block"),C="INPUT"===s.prop("tagName"),H=C?s:s.find("input"),P=s.find(".input-group-addon"),x=this;if(this.id=e("cp"),this.element=s,this.options=r,this.isAppended=!1,this.isShown=!1,this.currentView="hours",this.isInput=C,this.input=H,this.addon=P,this.popover=h,this.plate=u,this.hoursView=v,this.minutesView=m,this.amPmBlock=T,this.spanHours=h.find(".clockpicker-span-hours"),this.spanMinutes=h.find(".clockpicker-span-minutes"),this.spanAmPm=h.find(".clockpicker-span-am-pm"),this.amOrPm="PM",r.twelvehour){{var S=['
    ','",'","
    "].join("");n(S)}n('').on("click",function(){x.amOrPm="AM",n(".clockpicker-span-am-pm").empty().append("AM")}).appendTo(this.amPmBlock),n('').on("click",function(){x.amOrPm="PM",n(".clockpicker-span-am-pm").empty().append("PM")}).appendTo(this.amPmBlock)}r.autoclose||n('").click(n.proxy(this.done,this)).appendTo(h),"top"!==r.placement&&"bottom"!==r.placement||"top"!==r.align&&"bottom"!==r.align||(r.align="left"),"left"!==r.placement&&"right"!==r.placement||"left"!==r.align&&"right"!==r.align||(r.align="top"),h.addClass(r.placement),h.addClass("clockpicker-align-"+r.align),this.spanHours.click(n.proxy(this.toggleView,this,"hours")),this.spanMinutes.click(n.proxy(this.toggleView,this,"minutes")),H.on("focus.clockpicker click.clockpicker",n.proxy(this.show,this)),P.on("click.clockpicker",n.proxy(this.toggle,this));var E,D,I,B,z=n('
    ');if(r.twelvehour)for(E=1;13>E;E+=1)D=z.clone(),I=E/6*Math.PI,B=g,D.css("font-size","120%"),D.css({left:b+Math.sin(I)*B-y,top:b-Math.cos(I)*B-y}),D.html(0===E?"00":E),v.append(D),D.on(k,p);else for(E=0;24>E;E+=1){D=z.clone(),I=E/6*Math.PI;var O=E>0&&13>E;B=O?w:g,D.css({left:b+Math.sin(I)*B-y,top:b-Math.cos(I)*B-y}),O&&D.css("font-size","120%"),D.html(0===E?"00":E),v.append(D),D.on(k,p)}for(E=0;60>E;E+=5)D=z.clone(),I=E/30*Math.PI,D.css({left:b+Math.sin(I)*g-y,top:b-Math.cos(I)*g-y}),D.css("font-size","120%"),D.html(i(E)),m.append(D),D.on(k,p);if(u.on(k,function(t){0===n(t.target).closest(".clockpicker-tick").length&&p(t,!0)}),l){var j=h.find(".clockpicker-canvas"),L=t("svg");L.setAttribute("class","clockpicker-svg"),L.setAttribute("width",M),L.setAttribute("height",M);var U=t("g");U.setAttribute("transform","translate("+b+","+b+")");var W=t("circle");W.setAttribute("class","clockpicker-canvas-bearing"),W.setAttribute("cx",0),W.setAttribute("cy",0),W.setAttribute("r",2);var N=t("line");N.setAttribute("x1",0),N.setAttribute("y1",0);var X=t("circle");X.setAttribute("class","clockpicker-canvas-bg"),X.setAttribute("r",y);var Y=t("circle");Y.setAttribute("class","clockpicker-canvas-fg"),Y.setAttribute("r",3.5),U.appendChild(N),U.appendChild(X),U.appendChild(Y),U.appendChild(W),L.appendChild(U),j.append(L),this.hand=N,this.bg=X,this.fg=Y,this.bearing=W,this.g=U,this.canvas=j}o(this.options.init)}function o(t){t&&"function"==typeof t&&t()}var c,n=window.jQuery,r=n(window),a=n(document),p="http://www.w3.org/2000/svg",l="SVGAngle"in window&&function(){var t,i=document.createElement("div");return i.innerHTML="",t=(i.firstChild&&i.firstChild.namespaceURI)==p,i.innerHTML="",t}(),h=function(){var t=document.createElement("div").style;return"transition"in t||"WebkitTransition"in t||"MozTransition"in t||"msTransition"in t||"OTransition"in t}(),u="ontouchstart"in window,k="mousedown"+(u?" touchstart":""),d="mousemove.clockpicker"+(u?" touchmove.clockpicker":""),f="mouseup.clockpicker"+(u?" touchend.clockpicker":""),v=navigator.vibrate?"vibrate":navigator.webkitVibrate?"webkitVibrate":null,m=0,b=100,g=80,w=54,y=13,M=2*b,A=h?350:1,V=['
    ','
    ','
    ',''," : ",'','',"
    ",'
    ','
    ','
    ','
    ','
    ',"
    ",'',"","
    ","
    "].join("");s.DEFAULTS={"default":"",fromnow:0,placement:"bottom",align:"left",donetext:"完成",autoclose:!1,twelvehour:!1,vibrate:!0},s.prototype.toggle=function(){this[this.isShown?"hide":"show"]()},s.prototype.locate=function(){var t=this.element,i=this.popover,e=t.offset(),s=t.outerWidth(),o=t.outerHeight(),c=this.options.placement,n=this.options.align,r={};switch(i.show(),c){case"bottom":r.top=e.top+o;break;case"right":r.left=e.left+s;break;case"top":r.top=e.top-i.outerHeight();break;case"left":r.left=e.left-i.outerWidth()}switch(n){case"left":r.left=e.left;break;case"right":r.left=e.left+s-i.outerWidth();break;case"top":r.top=e.top;break;case"bottom":r.top=e.top+o-i.outerHeight()}i.css(r)},s.prototype.show=function(){if(!this.isShown){o(this.options.beforeShow);var t=this;this.isAppended||(c=n(document.body).append(this.popover),r.on("resize.clockpicker"+this.id,function(){t.isShown&&t.locate()}),this.isAppended=!0);var e=((this.input.prop("value")||this.options["default"]||"")+"").split(":");if("now"===e[0]){var s=new Date(+new Date+this.options.fromnow);e=[s.getHours(),s.getMinutes()]}this.hours=+e[0]||0,this.minutes=+e[1]||0,this.spanHours.html(i(this.hours)),this.spanMinutes.html(i(this.minutes)),this.toggleView("hours"),this.locate(),this.isShown=!0,a.on("click.clockpicker."+this.id+" focusin.clockpicker."+this.id,function(i){var e=n(i.target);0===e.closest(t.popover).length&&0===e.closest(t.addon).length&&0===e.closest(t.input).length&&t.hide()}),a.on("keyup.clockpicker."+this.id,function(i){27===i.keyCode&&t.hide()}),o(this.options.afterShow)}},s.prototype.hide=function(){o(this.options.beforeHide),this.isShown=!1,a.off("click.clockpicker."+this.id+" focusin.clockpicker."+this.id),a.off("keyup.clockpicker."+this.id),this.popover.hide(),o(this.options.afterHide)},s.prototype.toggleView=function(t,i){var e=!1;"minutes"===t&&"visible"===n(this.hoursView).css("visibility")&&(o(this.options.beforeHourSelect),e=!0);var s="hours"===t,c=s?this.hoursView:this.minutesView,r=s?this.minutesView:this.hoursView;this.currentView=t,this.spanHours.toggleClass("text-primary",s),this.spanMinutes.toggleClass("text-primary",!s),r.addClass("clockpicker-dial-out"),c.css("visibility","visible").removeClass("clockpicker-dial-out"),this.resetClock(i),clearTimeout(this.toggleViewTimer),this.toggleViewTimer=setTimeout(function(){r.css("visibility","hidden")},A),e&&o(this.options.afterHourSelect)},s.prototype.resetClock=function(t){var i=this.currentView,e=this[i],s="hours"===i,o=Math.PI/(s?6:30),c=e*o,n=s&&e>0&&13>e?w:g,r=Math.sin(c)*n,a=-Math.cos(c)*n,p=this;l&&t?(p.canvas.addClass("clockpicker-canvas-out"),setTimeout(function(){p.canvas.removeClass("clockpicker-canvas-out"),p.setHand(r,a)},t)):this.setHand(r,a)},s.prototype.setHand=function(t,e,s,o){var c,r=Math.atan2(t,-e),a="hours"===this.currentView,p=Math.PI/(a||s?6:30),h=Math.sqrt(t*t+e*e),u=this.options,k=a&&(g+w)/2>h,d=k?w:g;if(u.twelvehour&&(d=g),0>r&&(r=2*Math.PI+r),c=Math.round(r/p),r=c*p,u.twelvehour?a?0===c&&(c=12):(s&&(c*=5),60===c&&(c=0)):a?(12===c&&(c=0),c=k?0===c?12:c:0===c?0:c+12):(s&&(c*=5),60===c&&(c=0)),this[this.currentView]!==c&&v&&this.options.vibrate&&(this.vibrateTimer||(navigator[v](10),this.vibrateTimer=setTimeout(n.proxy(function(){this.vibrateTimer=null},this),100))),this[this.currentView]=c,this[a?"spanHours":"spanMinutes"].html(i(c)),!l)return void this[a?"hoursView":"minutesView"].find(".clockpicker-tick").each(function(){var t=n(this);t.toggleClass("active",c===+t.html())});o||!a&&c%5?(this.g.insertBefore(this.hand,this.bearing),this.g.insertBefore(this.bg,this.fg),this.bg.setAttribute("class","clockpicker-canvas-bg clockpicker-canvas-bg-trans")):(this.g.insertBefore(this.hand,this.bg),this.g.insertBefore(this.fg,this.bg),this.bg.setAttribute("class","clockpicker-canvas-bg"));var f=Math.sin(r)*d,m=-Math.cos(r)*d;this.hand.setAttribute("x2",f),this.hand.setAttribute("y2",m),this.bg.setAttribute("cx",f),this.bg.setAttribute("cy",m),this.fg.setAttribute("cx",f),this.fg.setAttribute("cy",m)},s.prototype.done=function(){o(this.options.beforeDone),this.hide();var t=this.input.prop("value"),e=i(this.hours)+":"+i(this.minutes);this.options.twelvehour&&(e+=this.amOrPm),this.input.prop("value",e),e!==t&&(this.input.triggerHandler("change"),this.isInput||this.element.trigger("change")),this.options.autoclose&&this.input.trigger("blur"),o(this.options.afterDone)},s.prototype.remove=function(){this.element.removeData("clockpicker"),this.input.off("focus.clockpicker click.clockpicker"),this.addon.off("click.clockpicker"),this.isShown&&this.hide(),this.isAppended&&(r.off("resize.clockpicker"+this.id),this.popover.remove())},n.fn.clockpicker=function(t){var i=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=n(this),o=e.data("clockpicker");if(o)"function"==typeof o[t]&&o[t].apply(o,i);else{var c=n.extend({},s.DEFAULTS,e.data(),"object"==typeof t&&t);e.data("clockpicker",new s(e,c))}})}}(); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/css/datepicker.css b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/css/datepicker.css new file mode 100644 index 0000000..5ecec5d --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/css/datepicker.css @@ -0,0 +1,301 @@ +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ + +} +.datepicker-inline { + width: 220px; +} +.datepicker.datepicker-rtl { + direction: rtl; +} +.datepicker.datepicker-rtl table tr td span { + float: right; +} +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0, 0, 0, 0.2); + position: absolute; + top: -7px; + left: 6px; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 7px; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; +} +.datepicker td, +.datepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover { + background: #eeeeee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #999999; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + background-color: #fde19a; + background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); + background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); + background-image: linear-gradient(top, #fdd49a, #fdf59a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); + border-color: #fdf59a #fdf59a #fbed50; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #000 !important; +} +.datepicker table tr td.today:hover, +.datepicker table tr td.today:hover:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today:hover.disabled, +.datepicker table tr td.today.disabled.disabled, +.datepicker table tr td.today.disabled:hover.disabled, +.datepicker table tr td.today[disabled], +.datepicker table tr td.today:hover[disabled], +.datepicker table tr td.today.disabled[disabled], +.datepicker table tr td.today.disabled:hover[disabled] { + background-color: #fdf59a; +} +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active { + background-color: #fbf069 \9; +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active:hover, +.datepicker table tr td.active:hover:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active:hover.disabled, +.datepicker table tr td.active.disabled.disabled, +.datepicker table tr td.active.disabled:hover.disabled, +.datepicker table tr td.active[disabled], +.datepicker table tr td.active:hover[disabled], +.datepicker table tr td.active.disabled[disabled], +.datepicker table tr td.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eeeeee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active:hover:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active:hover.disabled, +.datepicker table tr td span.active.disabled.disabled, +.datepicker table tr td span.active.disabled:hover.disabled, +.datepicker table tr td span.active[disabled], +.datepicker table tr td span.active:hover[disabled], +.datepicker table tr td span.active.disabled[disabled], +.datepicker table tr td span.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span.old { + color: #999999; +} +.datepicker th.switch { + width: 145px; +} +.datepicker thead tr:first-child th, +.datepicker tfoot tr:first-child th { + cursor: pointer; +} +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr:first-child th:hover { + background: #eeeeee; +} +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; +} +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-append.date .add-on i, +.input-prepend.date .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; +} diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/bootstrap-datepicker.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/bootstrap-datepicker.js new file mode 100644 index 0000000..da25ad2 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/bootstrap-datepicker.js @@ -0,0 +1,1047 @@ +/* ========================================================= + * bootstrap-datepicker.js + * http://www.eyecon.ro/bootstrap-datepicker + * ========================================================= + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * + * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +!function( $ ) { + + function UTCDate(){ + return new Date(Date.UTC.apply(Date, arguments)); + } + function UTCToday(){ + var today = new Date(); + return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()); + } + + // Picker object + + var Datepicker = function(element, options) { + var that = this; + + this.element = $(element); + this.language = options.language||this.element.data('date-language')||"en"; + this.language = this.language in dates ? this.language : this.language.split('-')[0]; //Check if "de-DE" style date is available, if not language should fallback to 2 letter code eg "de" + this.language = this.language in dates ? this.language : "en"; + this.isRTL = dates[this.language].rtl||false; + this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||dates[this.language].format||'mm/dd/yyyy'); + this.isInline = false; + this.isInput = this.element.is('input'); + this.component = this.element.is('.date') ? this.element.find('.add-on, .btn') : false; + this.hasInput = this.component && this.element.find('input').length; + if(this.component && this.component.length === 0) + this.component = false; + + this.forceParse = true; + if ('forceParse' in options) { + this.forceParse = options.forceParse; + } else if ('dateForceParse' in this.element.data()) { + this.forceParse = this.element.data('date-force-parse'); + } + + this.picker = $(DPGlobal.template); + this._buildEvents(); + this._attachEvents(); + + if(this.isInline) { + this.picker.addClass('datepicker-inline').appendTo(this.element); + } else { + this.picker.addClass('datepicker-dropdown dropdown-menu'); + } + if (this.isRTL){ + this.picker.addClass('datepicker-rtl'); + this.picker.find('.prev i, .next i') + .toggleClass('fa fa-arrow-left fa-arrow-right'); + } + + this.autoclose = false; + if ('autoclose' in options) { + this.autoclose = options.autoclose; + } else if ('dateAutoclose' in this.element.data()) { + this.autoclose = this.element.data('date-autoclose'); + } + + this.keyboardNavigation = true; + if ('keyboardNavigation' in options) { + this.keyboardNavigation = options.keyboardNavigation; + } else if ('dateKeyboardNavigation' in this.element.data()) { + this.keyboardNavigation = this.element.data('date-keyboard-navigation'); + } + + this.viewMode = this.startViewMode = 0; + switch(options.startView || this.element.data('date-start-view')){ + case 2: + case 'decade': + this.viewMode = this.startViewMode = 2; + break; + case 1: + case 'year': + this.viewMode = this.startViewMode = 1; + break; + } + + this.minViewMode = options.minViewMode||this.element.data('date-min-view-mode')||0; + if (typeof this.minViewMode === 'string') { + switch (this.minViewMode) { + case 'months': + this.minViewMode = 1; + break; + case 'years': + this.minViewMode = 2; + break; + default: + this.minViewMode = 0; + break; + } + } + + this.viewMode = this.startViewMode = Math.max(this.startViewMode, this.minViewMode); + + this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false); + this.todayHighlight = (options.todayHighlight||this.element.data('date-today-highlight')||false); + + this.calendarWeeks = false; + if ('calendarWeeks' in options) { + this.calendarWeeks = options.calendarWeeks; + } else if ('dateCalendarWeeks' in this.element.data()) { + this.calendarWeeks = this.element.data('date-calendar-weeks'); + } + if (this.calendarWeeks) + this.picker.find('tfoot th.today') + .attr('colspan', function(i, val){ + return parseInt(val) + 1; + }); + + this._allow_update = false; + + this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7); + this.weekEnd = ((this.weekStart + 6) % 7); + this.startDate = -Infinity; + this.endDate = Infinity; + this.daysOfWeekDisabled = []; + this.setStartDate(options.startDate||this.element.data('date-startdate')); + this.setEndDate(options.endDate||this.element.data('date-enddate')); + this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled')); + this.fillDow(); + this.fillMonths(); + + this._allow_update = true; + + this.update(); + this.showMode(); + + if(this.isInline) { + this.show(); + } + }; + + Datepicker.prototype = { + constructor: Datepicker, + + _events: [], + _secondaryEvents: [], + _applyEvents: function(evs){ + for (var i=0, el, ev; i this.endDate) { + this.viewDate = new Date(this.endDate); + } else { + this.viewDate = new Date(this.date); + } + this.fill(); + }, + + fillDow: function(){ + var dowCnt = this.weekStart, + html = ''; + if(this.calendarWeeks){ + var cell = ' '; + html += cell; + this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); + } + while (dowCnt < this.weekStart + 7) { + html += ''+dates[this.language].daysMin[(dowCnt++)%7]+''; + } + html += ''; + this.picker.find('.datepicker-days thead').append(html); + }, + + fillMonths: function(){ + var html = '', + i = 0; + while (i < 12) { + html += ''+dates[this.language].monthsShort[i++]+''; + } + this.picker.find('.datepicker-months td').html(html); + }, + + fill: function() { + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(), + startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity, + startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity, + endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity, + endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity, + currentDate = this.date && this.date.valueOf(), + today = new Date(); + this.picker.find('.datepicker-days thead th.switch') + .text(dates[this.language].months[month]+' '+year); + this.picker.find('tfoot th.today') + .text(dates[this.language].today) + .toggle(this.todayBtn !== false); + this.updateNavArrows(); + this.fillMonths(); + var prevMonth = UTCDate(year, month-1, 28,0,0,0,0), + day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); + prevMonth.setUTCDate(day); + prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7); + var nextMonth = new Date(prevMonth); + nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + var clsName; + while(prevMonth.valueOf() < nextMonth) { + if (prevMonth.getUTCDay() == this.weekStart) { + html.push(''); + if(this.calendarWeeks){ + // ISO 8601: First week contains first thursday. + // ISO also states week starts on Monday, but we can be more abstract here. + var + // Start of current week: based on weekstart/current date + ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), + // Thursday of this week + th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), + // First Thursday of year, year from thursday + yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), + // Calendar week: ms between thursdays, div ms per day, div 7 days + calWeek = (th - yth) / 864e5 / 7 + 1; + html.push(''+ calWeek +''); + + } + } + clsName = ''; + if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) { + clsName += ' old'; + } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) { + clsName += ' new'; + } + // Compare internal UTC date with local today, not UTC today + if (this.todayHighlight && + prevMonth.getUTCFullYear() == today.getFullYear() && + prevMonth.getUTCMonth() == today.getMonth() && + prevMonth.getUTCDate() == today.getDate()) { + clsName += ' today'; + } + if (currentDate && prevMonth.valueOf() == currentDate) { + clsName += ' active'; + } + if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate || + $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) { + clsName += ' disabled'; + } + html.push(''+prevMonth.getUTCDate() + ''); + if (prevMonth.getUTCDay() == this.weekEnd) { + html.push(''); + } + prevMonth.setUTCDate(prevMonth.getUTCDate()+1); + } + this.picker.find('.datepicker-days tbody').empty().append(html.join('')); + var currentYear = this.date && this.date.getUTCFullYear(); + + var months = this.picker.find('.datepicker-months') + .find('th:eq(1)') + .text(year) + .end() + .find('span').removeClass('active'); + if (currentYear && currentYear == year) { + months.eq(this.date.getUTCMonth()).addClass('active'); + } + if (year < startYear || year > endYear) { + months.addClass('disabled'); + } + if (year == startYear) { + months.slice(0, startMonth).addClass('disabled'); + } + if (year == endYear) { + months.slice(endMonth+1).addClass('disabled'); + } + + html = ''; + year = parseInt(year/10, 10) * 10; + var yearCont = this.picker.find('.datepicker-years') + .find('th:eq(1)') + .text(year + '-' + (year + 9)) + .end() + .find('td'); + year -= 1; + for (var i = -1; i < 11; i++) { + html += ''+year+''; + year += 1; + } + yearCont.html(html); + }, + + updateNavArrows: function() { + if (!this._allow_update) return; + + var d = new Date(this.viewDate), + year = d.getUTCFullYear(), + month = d.getUTCMonth(); + switch (this.viewMode) { + case 0: + if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + case 1: + case 2: + if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) { + this.picker.find('.prev').css({visibility: 'hidden'}); + } else { + this.picker.find('.prev').css({visibility: 'visible'}); + } + if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) { + this.picker.find('.next').css({visibility: 'hidden'}); + } else { + this.picker.find('.next').css({visibility: 'visible'}); + } + break; + } + }, + + click: function(e) { + e.stopPropagation(); + e.preventDefault(); + var target = $(e.target).closest('span, td, th'); + if (target.length == 1) { + switch(target[0].nodeName.toLowerCase()) { + case 'th': + switch(target[0].className) { + case 'switch': + this.showMode(1); + break; + case 'prev': + case 'next': + var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1); + switch(this.viewMode){ + case 0: + this.viewDate = this.moveMonth(this.viewDate, dir); + break; + case 1: + case 2: + this.viewDate = this.moveYear(this.viewDate, dir); + break; + } + this.fill(); + break; + case 'today': + var date = new Date(); + date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); + + this.showMode(-2); + var which = this.todayBtn == 'linked' ? null : 'view'; + this._setDate(date, which); + break; + } + break; + case 'span': + if (!target.is('.disabled')) { + this.viewDate.setUTCDate(1); + if (target.is('.month')) { + var day = 1; + var month = target.parent().find('span').index(target); + var year = this.viewDate.getUTCFullYear(); + this.viewDate.setUTCMonth(month); + this.element.trigger({ + type: 'changeMonth', + date: this.viewDate + }); + if ( this.minViewMode == 1 ) { + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + } else { + var year = parseInt(target.text(), 10)||0; + var day = 1; + var month = 0; + this.viewDate.setUTCFullYear(year); + this.element.trigger({ + type: 'changeYear', + date: this.viewDate + }); + if ( this.minViewMode == 2 ) { + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + } + this.showMode(-1); + this.fill(); + } + break; + case 'td': + if (target.is('.day') && !target.is('.disabled')){ + var day = parseInt(target.text(), 10)||1; + var year = this.viewDate.getUTCFullYear(), + month = this.viewDate.getUTCMonth(); + if (target.is('.old')) { + if (month === 0) { + month = 11; + year -= 1; + } else { + month -= 1; + } + } else if (target.is('.new')) { + if (month == 11) { + month = 0; + year += 1; + } else { + month += 1; + } + } + this._setDate(UTCDate(year, month, day,0,0,0,0)); + } + break; + } + } + }, + + _setDate: function(date, which){ + if (!which || which == 'date') + this.date = date; + if (!which || which == 'view') + this.viewDate = date; + this.fill(); + this.setValue(); + this.element.trigger({ + type: 'changeDate', + date: this.date + }); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component){ + element = this.element.find('input'); + } + if (element) { + element.change(); + if (this.autoclose && (!which || which == 'date')) { + this.hide(); + } + } + }, + + moveMonth: function(date, dir){ + if (!dir) return date; + var new_date = new Date(date.valueOf()), + day = new_date.getUTCDate(), + month = new_date.getUTCMonth(), + mag = Math.abs(dir), + new_month, test; + dir = dir > 0 ? 1 : -1; + if (mag == 1){ + test = dir == -1 + // If going back one month, make sure month is not current month + // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) + ? function(){ return new_date.getUTCMonth() == month; } + // If going forward one month, make sure month is as expected + // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) + : function(){ return new_date.getUTCMonth() != new_month; }; + new_month = month + dir; + new_date.setUTCMonth(new_month); + // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 + if (new_month < 0 || new_month > 11) + new_month = (new_month + 12) % 12; + } else { + // For magnitudes >1, move one month at a time... + for (var i=0; i= this.startDate && date <= this.endDate; + }, + + keydown: function(e){ + if (this.picker.is(':not(:visible)')){ + if (e.keyCode == 27) // allow escape to hide and re-show picker + this.show(); + return; + } + var dateChanged = false, + dir, day, month, + newDate, newViewDate; + switch(e.keyCode){ + case 27: // escape + this.hide(); + e.preventDefault(); + break; + case 37: // left + case 39: // right + if (!this.keyboardNavigation) break; + dir = e.keyCode == 37 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + } else if (e.shiftKey){ + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + } else { + newDate = new Date(this.date); + newDate.setUTCDate(this.date.getUTCDate() + dir); + newViewDate = new Date(this.viewDate); + newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir); + } + if (this.dateWithinRange(newDate)){ + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 38: // up + case 40: // down + if (!this.keyboardNavigation) break; + dir = e.keyCode == 38 ? -1 : 1; + if (e.ctrlKey){ + newDate = this.moveYear(this.date, dir); + newViewDate = this.moveYear(this.viewDate, dir); + } else if (e.shiftKey){ + newDate = this.moveMonth(this.date, dir); + newViewDate = this.moveMonth(this.viewDate, dir); + } else { + newDate = new Date(this.date); + newDate.setUTCDate(this.date.getUTCDate() + dir * 7); + newViewDate = new Date(this.viewDate); + newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7); + } + if (this.dateWithinRange(newDate)){ + this.date = newDate; + this.viewDate = newViewDate; + this.setValue(); + this.update(); + e.preventDefault(); + dateChanged = true; + } + break; + case 13: // enter + this.hide(); + e.preventDefault(); + break; + case 9: // tab + this.hide(); + break; + } + if (dateChanged){ + this.element.trigger({ + type: 'changeDate', + date: this.date + }); + var element; + if (this.isInput) { + element = this.element; + } else if (this.component){ + element = this.element.find('input'); + } + if (element) { + element.change(); + } + } + }, + + showMode: function(dir) { + if (dir) { + this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); + } + /* + vitalets: fixing bug of very special conditions: + jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover. + Method show() does not set display css correctly and datepicker is not shown. + Changed to .css('display', 'block') solve the problem. + See https://github.com/vitalets/x-editable/issues/37 + + In jquery 1.7.2+ everything works fine. + */ + //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); + this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); + this.updateNavArrows(); + } + }; + + $.fn.datepicker = function ( option ) { + var args = Array.apply(null, arguments); + args.shift(); + return this.each(function () { + var $this = $(this), + data = $this.data('datepicker'), + options = typeof option == 'object' && option; + if (!data) { + $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); + } + if (typeof option == 'string' && typeof data[option] == 'function') { + data[option].apply(data, args); + } + }); + }; + + $.fn.datepicker.defaults = { + }; + $.fn.datepicker.Constructor = Datepicker; + var dates = $.fn.datepicker.dates = { + en: { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Today" + } + }; + + var DPGlobal = { + modes: [ + { + clsName: 'days', + navFnc: 'Month', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'FullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'FullYear', + navStep: 10 + }], + isLeapYear: function (year) { + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); + }, + getDaysInMonth: function (year, month) { + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + }, + validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, + nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, + parseFormat: function(format){ + // IE treats \0 as a string end in inputs (truncating the value), + // so it's a bad format delimiter, anyway + var separators = format.replace(this.validParts, '\0').split('\0'), + parts = format.match(this.validParts); + if (!separators || !separators.length || !parts || parts.length === 0){ + throw new Error("Invalid date format."); + } + return {separators: separators, parts: parts}; + }, + parseDate: function(date, format, language) { + if (date instanceof Date) return date; + if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) { + var part_re = /([\-+]\d+)([dmwy])/, + parts = date.match(/([\-+]\d+)([dmwy])/g), + part, dir; + date = new Date(); + for (var i=0; i'+ + ''+ + ''+ + ''+ + ''+ + ''+ + '', + contTemplate: '', + footTemplate: '' + }; + DPGlobal.template = '
    '+ + '
    '+ + ''+ + DPGlobal.headTemplate+ + ''+ + DPGlobal.footTemplate+ + '
    '+ + '
    '+ + '
    '+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
    '+ + '
    '+ + '
    '+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + DPGlobal.footTemplate+ + '
    '+ + '
    '+ + '
    '; + + $.fn.datepicker.DPGlobal = DPGlobal; + +}( window.jQuery ); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.bg.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.bg.js new file mode 100644 index 0000000..6837afd --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.bg.js @@ -0,0 +1,14 @@ +/** + * Bulgarian translation for bootstrap-datepicker + * Apostol Apostolov + */ +;(function($){ + $.fn.datepicker.dates['bg'] = { + days: ["Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"], + daysShort: ["Нед", "Пон", "Вто", "Сря", "Чет", "Пет", "Съб", "Нед"], + daysMin: ["Н", "П", "В", "С", "Ч", "П", "С", "Н"], + months: ["Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"], + monthsShort: ["Ян", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Ное", "Дек"], + today: "днес" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ca.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ca.js new file mode 100644 index 0000000..3fc4d84 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ca.js @@ -0,0 +1,14 @@ +/** + * Catalan translation for bootstrap-datepicker + * J. Garcia + */ +;(function($){ + $.fn.datepicker.dates['ca'] = { + days: ["Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte", "Diumenge"], + daysShort: ["Diu", "Dil", "Dmt", "Dmc", "Dij", "Div", "Dis", "Diu"], + daysMin: ["dg", "dl", "dt", "dc", "dj", "dv", "ds", "dg"], + months: ["Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"], + monthsShort: ["Gen", "Feb", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Oct", "Nov", "Des"], + today: "Avui" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.cs.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.cs.js new file mode 100644 index 0000000..f76a2c0 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.cs.js @@ -0,0 +1,15 @@ +/** + * Czech translation for bootstrap-datepicker + * Matěj Koubík + * Fixes by Michal Remiš + */ +;(function($){ + $.fn.datepicker.dates['cs'] = { + days: ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"], + daysShort: ["Ned", "Pon", "Úte", "Stř", "Čtv", "Pát", "Sob", "Ned"], + daysMin: ["Ne", "Po", "Út", "St", "Čt", "Pá", "So", "Ne"], + months: ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"], + monthsShort: ["Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čnc", "Srp", "Zář", "Říj", "Lis", "Pro"], + today: "Dnes" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.da.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.da.js new file mode 100644 index 0000000..6307be5 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.da.js @@ -0,0 +1,14 @@ +/** + * Danish translation for bootstrap-datepicker + * Christian Pedersen + */ +;(function($){ + $.fn.datepicker.dates['da'] = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], + months: ["Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "I Dag" + }; +}(jQuery)); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.de.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.de.js new file mode 100644 index 0000000..3d491a2 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.de.js @@ -0,0 +1,16 @@ +/** + * German translation for bootstrap-datepicker + * Sam Zurcher + */ +;(function($){ + $.fn.datepicker.dates['de'] = { + days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"], + daysShort: ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam", "Son"], + daysMin: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"], + months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"], + monthsShort: ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"], + today: "Heute", + weekStart: 1, + format: "dd.mm.yyyy" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.el.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.el.js new file mode 100644 index 0000000..6de26bc --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.el.js @@ -0,0 +1,13 @@ +/** +* Greek translation for bootstrap-datepicker +*/ +;(function($){ + $.fn.datepicker.dates['el'] = { + days: ["Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο", "Κυριακή"], + daysShort: ["Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ", "Κυρ"], + daysMin: ["Κυ", "Δε", "Τρ", "Τε", "Πε", "Πα", "Σα", "Κυ"], + months: ["Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"], + monthsShort: ["Ιαν", "Φεβ", "Μαρ", "Απρ", "Μάι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ"], + today: "Σήμερα" + }; +}(jQuery)); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.es.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.es.js new file mode 100644 index 0000000..7217690 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.es.js @@ -0,0 +1,14 @@ +/** + * Spanish translation for bootstrap-datepicker + * Bruno Bonamin + */ +;(function($){ + $.fn.datepicker.dates['es'] = { + days: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado", "Domingo"], + daysShort: ["Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"], + daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"], + months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"], + monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"], + today: "Hoy" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.fi.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.fi.js new file mode 100644 index 0000000..e13e6b9 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.fi.js @@ -0,0 +1,14 @@ +/** + * Finnish translation for bootstrap-datepicker + * Jaakko Salonen + */ +;(function($){ + $.fn.datepicker.dates['fi'] = { + days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai", "sunnuntai"], + daysShort: ["sun", "maa", "tii", "kes", "tor", "per", "lau", "sun"], + daysMin: ["su", "ma", "ti", "ke", "to", "pe", "la", "su"], + months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"], + monthsShort: ["tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mar", "jou"], + today: "tänään" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.fr.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.fr.js new file mode 100644 index 0000000..498babe --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.fr.js @@ -0,0 +1,16 @@ +/** + * French translation for bootstrap-datepicker + * Nico Mollet + */ +;(function($){ + $.fn.datepicker.dates['fr'] = { + days: ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche"], + daysShort: ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"], + daysMin: ["D", "L", "Ma", "Me", "J", "V", "S", "D"], + months: ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"], + monthsShort: ["Jan", "Fev", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Dec"], + today: "Aujourd'hui", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.he.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.he.js new file mode 100644 index 0000000..2e17393 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.he.js @@ -0,0 +1,15 @@ +/** + * Hebrew translation for bootstrap-datepicker + * Sagie Maoz + */ +;(function($){ + $.fn.datepicker.dates['he'] = { + days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת", "ראשון"], + daysShort: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + daysMin: ["א", "ב", "ג", "ד", "ה", "ו", "ש", "א"], + months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"], + monthsShort: ["ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ"], + today: "היום", + rtl: true + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.hr.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.hr.js new file mode 100644 index 0000000..8d13d11 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.hr.js @@ -0,0 +1,13 @@ +/** + * Croatian localisation + */ +;(function($){ + $.fn.datepicker.dates['hr'] = { + days: ["Nedjelja", "Ponedjelja", "Utorak", "Srijeda", "Četrtak", "Petak", "Subota", "Nedjelja"], + daysShort: ["Ned", "Pon", "Uto", "Srr", "Čet", "Pet", "Sub", "Ned"], + daysMin: ["Ne", "Po", "Ut", "Sr", "Če", "Pe", "Su", "Ne"], + months: ["Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac"], + monthsShort: ["Sije", "Velj", "Ožu", "Tra", "Svi", "Lip", "Jul", "Kol", "Ruj", "Lis", "Stu", "Pro"], + today: "Danas" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.hu.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.hu.js new file mode 100644 index 0000000..bf5308a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.hu.js @@ -0,0 +1,16 @@ +/** + * Hungarian translation for bootstrap-datepicker + * Sotus László + */ +;(function($){ + $.fn.datepicker.dates['hu'] = { + days: ["Vasárnap", "Hétfő", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat", "Vasárnap"], + daysShort: ["Vas", "Hét", "Ked", "Sze", "Csü", "Pén", "Szo", "Vas"], + daysMin: ["Va", "Hé", "Ke", "Sz", "Cs", "Pé", "Sz", "Va"], + months: ["Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Már", "Ápr", "Máj", "Jún", "Júl", "Aug", "Sze", "Okt", "Nov", "Dec"], + today: "Ma", + weekStart: 1, + format: "yyyy.mm.dd" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.id.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.id.js new file mode 100644 index 0000000..d48aa48 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.id.js @@ -0,0 +1,13 @@ +/** + * Bahasa translation for bootstrap-datepicker + * Azwar Akbar + */ +;(function($){ + $.fn.datepicker.dates['id'] = { + days: ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu"], + daysShort: ["Mgu", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Mgu"], + daysMin: ["Mg", "Sn", "Sl", "Ra", "Ka", "Ju", "Sa", "Mg"], + months: ["Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ags", "Sep", "Okt", "Nov", "Des"] + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.is.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.is.js new file mode 100644 index 0000000..0e57a91 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.is.js @@ -0,0 +1,14 @@ +/** + * Icelandic translation for bootstrap-datepicker + * Hinrik Örn Sigurðsson + */ +;(function($){ + $.fn.datepicker.dates['is'] = { + days: ["Sunnudagur", "Mánudagur", "Þriðjudagur", "Miðvikudagur", "Fimmtudagur", "Föstudagur", "Laugardagur", "Sunnudagur"], + daysShort: ["Sun", "Mán", "Þri", "Mið", "Fim", "Fös", "Lau", "Sun"], + daysMin: ["Su", "Má", "Þr", "Mi", "Fi", "Fö", "La", "Su"], + months: ["Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maí", "Jún", "Júl", "Ágú", "Sep", "Okt", "Nóv", "Des"], + today: "Í Dag" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.it.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.it.js new file mode 100644 index 0000000..8209f2a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.it.js @@ -0,0 +1,16 @@ +/** + * Italian translation for bootstrap-datepicker + * Enrico Rubboli + */ +;(function($){ + $.fn.datepicker.dates['it'] = { + days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato", "Domenica"], + daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab", "Dom"], + daysMin: ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"], + months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], + monthsShort: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], + today: "Oggi", + weekStart: 1, + format: "dd/mm/yyyy" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ja.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ja.js new file mode 100644 index 0000000..ed0bc0f --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ja.js @@ -0,0 +1,15 @@ +/** + * Japanese translation for bootstrap-datepicker + * Norio Suzuki + */ +;(function($){ + $.fn.datepicker.dates['ja'] = { + days: ["日曜", "月曜", "火曜", "水曜", "木曜", "金曜", "土曜", "日曜"], + daysShort: ["日", "月", "火", "水", "木", "金", "土", "日"], + daysMin: ["日", "月", "火", "水", "木", "金", "土", "日"], + months: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], + today: "今日", + format: "yyyy/mm/dd" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.kr.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.kr.js new file mode 100644 index 0000000..183a88d --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.kr.js @@ -0,0 +1,13 @@ +/** + * Korean translation for bootstrap-datepicker + * Gu Youn + */ +;(function($){ + $.fn.datepicker.dates['kr'] = { + days: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"], + daysShort: ["일", "월", "화", "수", "목", "금", "토", "일"], + daysMin: ["일", "월", "화", "수", "목", "금", "토", "일"], + months: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"], + monthsShort: ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"] + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.lt.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.lt.js new file mode 100644 index 0000000..11c1b3a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.lt.js @@ -0,0 +1,16 @@ +/** + * Lithuanian translation for bootstrap-datepicker + * Šarūnas Gliebus + */ + +;(function($){ + $.fn.datepicker.dates['lt'] = { + days: ["Sekmadienis", "Pirmadienis", "Antradienis", "Trečiadienis", "Ketvirtadienis", "Penktadienis", "Šeštadienis", "Sekmadienis"], + daysShort: ["S", "Pr", "A", "T", "K", "Pn", "Š", "S"], + daysMin: ["Sk", "Pr", "An", "Tr", "Ke", "Pn", "Št", "Sk"], + months: ["Sausis", "Vasaris", "Kovas", "Balandis", "Gegužė", "Birželis", "Liepa", "Rugpjūtis", "Rugsėjis", "Spalis", "Lapkritis", "Gruodis"], + monthsShort: ["Sau", "Vas", "Kov", "Bal", "Geg", "Bir", "Lie", "Rugp", "Rugs", "Spa", "Lap", "Gru"], + today: "Šiandien", + weekStart: 1 + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.lv.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.lv.js new file mode 100644 index 0000000..cc75fe0 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.lv.js @@ -0,0 +1,16 @@ +/** + * Latvian translation for bootstrap-datepicker + * Artis Avotins + */ + +;(function($){ + $.fn.datepicker.dates['lv'] = { + days: ["Svētdiena", "Pirmdiena", "Otrdiena", "Trešdiena", "Ceturtdiena", "Piektdiena", "Sestdiena", "Svētdiena"], + daysShort: ["Sv", "P", "O", "T", "C", "Pk", "S", "Sv"], + daysMin: ["Sv", "Pr", "Ot", "Tr", "Ce", "Pk", "St", "Sv"], + months: ["Janvāris", "Februāris", "Marts", "Aprīlis", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jūn", "Jūl", "Aug", "Sep", "Okt", "Nov", "Dec."], + today: "Šodien", + weekStart: 1 + }; +}(jQuery)); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ms.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ms.js new file mode 100644 index 0000000..fa3a21a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ms.js @@ -0,0 +1,14 @@ +/** + * Malay translation for bootstrap-datepicker + * Ateman Faiz + */ +;(function($){ + $.fn.datepicker.dates['ms'] = { + days: ["Ahad", "Isnin", "Selasa", "Rabu", "Khamis", "Jumaat", "Sabtu", "Ahad"], + daysShort: ["Aha", "Isn", "Sel", "Rab", "Kha", "Jum", "Sab", "Aha"], + daysMin: ["Ah", "Is", "Se", "Ra", "Kh", "Ju", "Sa", "Ah"], + months: ["Januari", "Februari", "Mac", "April", "Mei", "Jun", "Julai", "Ogos", "September", "Oktober", "November", "Disember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Ogo", "Sep", "Okt", "Nov", "Dis"], + today: "Hari Ini" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.nb.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.nb.js new file mode 100644 index 0000000..fb9fe2a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.nb.js @@ -0,0 +1,14 @@ +/** + * Norwegian (bokmål) translation for bootstrap-datepicker + * Fredrik Sundmyhr + */ +;(function($){ + $.fn.datepicker.dates['nb'] = { + days: ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag", "Søndag"], + daysShort: ["Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør", "Søn"], + daysMin: ["Sø", "Ma", "Ti", "On", "To", "Fr", "Lø", "Sø"], + months: ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Des"], + today: "I Dag" + }; +}(jQuery)); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.nl.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.nl.js new file mode 100644 index 0000000..13a2f1a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.nl.js @@ -0,0 +1,14 @@ +/** + * Dutch translation for bootstrap-datepicker + * Reinier Goltstein + */ +;(function($){ + $.fn.datepicker.dates['nl'] = { + days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"], + daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"], + months: ["Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Vandaag" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pl.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pl.js new file mode 100644 index 0000000..f3fff8c --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pl.js @@ -0,0 +1,15 @@ +/** + * Polish translation for bootstrap-datepicker + * Robert + */ +;(function($){ + $.fn.datepicker.dates['pl'] = { + days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela"], + daysShort: ["Nie", "Pn", "Wt", "Śr", "Czw", "Pt", "So", "Nie"], + daysMin: ["N", "Pn", "Wt", "Śr", "Cz", "Pt", "So", "N"], + months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"], + monthsShort: ["Sty", "Lu", "Mar", "Kw", "Maj", "Cze", "Lip", "Sie", "Wrz", "Pa", "Lis", "Gru"], + today: "Dzisiaj", + weekStart: 1 + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pt-BR.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pt-BR.js new file mode 100644 index 0000000..8d1fc27 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pt-BR.js @@ -0,0 +1,14 @@ +/** + * Brazilian translation for bootstrap-datepicker + * Cauan Cabral + */ +;(function($){ + $.fn.datepicker.dates['pt-BR'] = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + today: "Hoje" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pt.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pt.js new file mode 100644 index 0000000..64179e8 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.pt.js @@ -0,0 +1,14 @@ +/** + * Portuguese translation for bootstrap-datepicker + * Original code: Cauan Cabral + * Tiago Melo + */ +;(function($){ + $.fn.datepicker.dates['pt'] = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado", "Domingo"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa", "Do"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"] + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ro.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ro.js new file mode 100644 index 0000000..03c1a47 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ro.js @@ -0,0 +1,15 @@ +/** + * Romanian translation for bootstrap-datepicker + * Cristian Vasile + */ +;(function($){ + $.fn.datepicker.dates['ro'] = { + days: ["Duminică", "Luni", "Marţi", "Miercuri", "Joi", "Vineri", "Sâmbătă", "Duminică"], + daysShort: ["Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm", "Dum"], + daysMin: ["Du", "Lu", "Ma", "Mi", "Jo", "Vi", "Sâ", "Du"], + months: ["Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"], + monthsShort: ["Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Nov", "Dec"], + today: "Astăzi", + weekStart: 1 + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.rs-latin.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.rs-latin.js new file mode 100644 index 0000000..1e0523d --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.rs-latin.js @@ -0,0 +1,14 @@ +/** + * Serbian latin translation for bootstrap-datepicker + * Bojan Milosavlević + */ +;(function($){ + $.fn.datepicker.dates['rs'] = { + days: ["Nedelja","Ponedeljak", "Utorak", "Sreda", "Četvrtak", "Petak", "Subota", "Nedelja"], + daysShort: ["Ned", "Pon", "Uto", "Sre", "Čet", "Pet", "Sub", "Ned"], + daysMin: ["N", "Po", "U", "Sr", "Č", "Pe", "Su", "N"], + months: ["Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danas" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.rs.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.rs.js new file mode 100644 index 0000000..6b65747 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.rs.js @@ -0,0 +1,14 @@ +/** + * Serbian cyrillic translation for bootstrap-datepicker + * Bojan Milosavlević + */ +;(function($){ + $.fn.datepicker.dates['rs'] = { + days: ["Недеља","Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота", "Недеља"], + daysShort: ["Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб", "Нед"], + daysMin: ["Н", "По", "У", "Ср", "Ч", "Пе", "Су", "Н"], + months: ["Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"], + monthsShort: ["Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец"], + today: "Данас" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ru.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ru.js new file mode 100644 index 0000000..9404cff --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.ru.js @@ -0,0 +1,14 @@ +/** + * Russian translation for bootstrap-datepicker + * Victor Taranenko + */ +;(function($){ + $.fn.datepicker.dates['ru'] = { + days: ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота", "Воскресенье"], + daysShort: ["Вск", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Вск"], + daysMin: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"], + months: ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], + monthsShort: ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"], + today: "Сегодня" + }; +}(jQuery)); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sk.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sk.js new file mode 100644 index 0000000..c48032a --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sk.js @@ -0,0 +1,15 @@ +/** + * Slovak translation for bootstrap-datepicker + * Marek Lichtner + * Fixes by Michal Remiš + */ +;(function($){ + $.fn.datepicker.dates["sk"] = { + days: ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota", "Nedeľa"], + daysShort: ["Ned", "Pon", "Uto", "Str", "Štv", "Pia", "Sob", "Ned"], + daysMin: ["Ne", "Po", "Ut", "St", "Št", "Pia", "So", "Ne"], + months: ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "Dnes" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sl.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sl.js new file mode 100644 index 0000000..41b0e06 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sl.js @@ -0,0 +1,14 @@ +/** + * Slovene translation for bootstrap-datepicker + * Gregor Rudolf + */ +;(function($){ + $.fn.datepicker.dates['sl'] = { + days: ["Nedelja", "Ponedeljek", "Torek", "Sreda", "Četrtek", "Petek", "Sobota", "Nedelja"], + daysShort: ["Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob", "Ned"], + daysMin: ["Ne", "Po", "To", "Sr", "Če", "Pe", "So", "Ne"], + months: ["Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Avg", "Sep", "Okt", "Nov", "Dec"], + today: "Danes" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sv.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sv.js new file mode 100644 index 0000000..5cb1d0c --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sv.js @@ -0,0 +1,14 @@ +/** + * Swedish translation for bootstrap-datepicker + * Patrik Ragnarsson + */ +;(function($){ + $.fn.datepicker.dates['sv'] = { + days: ["Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"], + daysShort: ["Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör", "Sön"], + daysMin: ["Sö", "Må", "Ti", "On", "To", "Fr", "Lö", "Sö"], + months: ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"], + today: "I Dag" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sw.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sw.js new file mode 100644 index 0000000..622e0ef --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.sw.js @@ -0,0 +1,15 @@ +/** + * Swahili translation for bootstrap-datepicker + * Edwin Mugendi + * Source: http://scriptsource.org/cms/scripts/page.php?item_id=entry_detail&uid=xnfaqyzcku + */ +;(function($){ + $.fn.datepicker.dates['sw'] = { + days: ["Jumapili", "Jumatatu", "Jumanne", "Jumatano", "Alhamisi", "Ijumaa", "Jumamosi", "Jumapili"], + daysShort: ["J2", "J3", "J4", "J5", "Alh", "Ij", "J1", "J2"], + daysMin: ["2", "3", "4", "5", "A", "I", "1", "2"], + months: ["Januari", "Februari", "Machi", "Aprili", "Mei", "Juni", "Julai", "Agosti", "Septemba", "Oktoba", "Novemba", "Desemba"], + monthsShort: ["Jan", "Feb", "Mac", "Apr", "Mei", "Jun", "Jul", "Ago", "Sep", "Okt", "Nov", "Des"], + today: "Leo" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.th.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.th.js new file mode 100644 index 0000000..562b063 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.th.js @@ -0,0 +1,14 @@ +/** + * Thai translation for bootstrap-datepicker + * Suchau Jiraprapot + */ +;(function($){ + $.fn.datepicker.dates['th'] = { + days: ["อาทิตย์", "จันทร์", "อังคาร", "พุธ", "พฤหัส", "ศุกร์", "เสาร์", "อาทิตย์"], + daysShort: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + daysMin: ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส", "อา"], + months: ["มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"], + monthsShort: ["ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."], + today: "วันนี้" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.tr.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.tr.js new file mode 100644 index 0000000..e46eced --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.tr.js @@ -0,0 +1,15 @@ +/** + * Turkish translation for bootstrap-datepicker + * Serkan Algur + */ +;(function($){ + $.fn.datepicker.dates['tr'] = { + days: ["Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi", "Pazar"], + daysShort: ["Pz", "Pzt", "Sal", "Çrş", "Prş", "Cu", "Cts", "Pz"], + daysMin: ["Pz", "Pzt", "Sa", "Çr", "Pr", "Cu", "Ct", "Pz"], + months: ["Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"], + monthsShort: ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"], + today: "Bugün" + }; +}(jQuery)); + diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.uk.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.uk.js new file mode 100644 index 0000000..bbd0c73 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.uk.js @@ -0,0 +1,14 @@ +/** + * Ukrainian translation for bootstrap-datepicker + * Andrey Vityuk + */ +;(function($){ + $.fn.datepicker.dates['uk'] = { + days: ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота", "Неділя"], + daysShort: ["Нед", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Суб", "Нед"], + daysMin: ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Нд"], + months: ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"], + monthsShort: ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру"], + today: "Сьогодні" + }; +}(jQuery)); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.zh-CN.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.zh-CN.js new file mode 100644 index 0000000..7cdcd03 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.zh-CN.js @@ -0,0 +1,14 @@ +/** + * Simplified Chinese translation for bootstrap-datepicker + * Yuan Cheung + */ +;(function($){ + $.fn.datepicker.dates['zh-CN'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], + daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], + daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + today: "今日" + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.zh-TW.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.zh-TW.js new file mode 100644 index 0000000..d21afc1 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-datepicker/js/locales/bootstrap-datepicker.zh-TW.js @@ -0,0 +1,13 @@ +/** + * Traditional Chinese translation for bootstrap-datepicker + * Rung-Sheng Jang + */ +;(function($){ + $.fn.datepicker.dates['zh-TW'] = { + days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"], + daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"], + daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"], + months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"], + monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"] + }; +}(jQuery)); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/css/bootstrap-image-gallery.css b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/css/bootstrap-image-gallery.css new file mode 100644 index 0000000..02aa7cf --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/css/bootstrap-image-gallery.css @@ -0,0 +1,153 @@ +@charset 'UTF-8'; +/* + * Bootstrap Image Gallery CSS 2.5.3 + * https://github.com/blueimp/Bootstrap-Image-Gallery + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.modal-gallery { +} +.modal-gallery.fade.in { +} +.modal-gallery .modal-body { +} +.modal-gallery .modal-title { +} +.modal-gallery .modal-image { + position: relative; + margin: auto; + min-width: 128px; + min-height: 128px; + overflow: hidden; + cursor: pointer; +} +.modal-gallery .modal-footer { + margin-top: 0px; +} +.modal-gallery .modal-image:hover:before, +.modal-gallery .modal-image:hover:after { + content: '\2039'; + position: absolute; + top: 50%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 24px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); + z-index: 1; +} +.modal-gallery .modal-image:hover:after { + content: '\203A'; + left: auto; + right: 15px; +} +.modal-single .modal-image:hover:before, +.modal-single .modal-image:hover:after { + display: none; +} +.modal-gallery.fade .modal-image, .modal-gallery.fade .modal-dialog { + -webkit-transition: width 0.15s ease, height 0.15s ease; + -moz-transition: width 0.15s ease, height 0.15s ease; + -ms-transition: width 0.15s ease, height 0.15s ease; + -o-transition: width 0.15s ease, height 0.15s ease; + transition: width 0.15s ease, height 0.15s ease; +} +.modal-gallery .modal-image *:not(.loader) { + position: absolute; + top: 0; +} +.modal-gallery .modal-image *:not(.loader) { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-gallery .modal-image h1.loader { + height: 50%; + width: 100%; + text-align: center; + font-size: 4em; + display: none; +} +.modal-loading.modal-gallery .modal-image h1.loader { + display: block; +} +.modal-gallery.fade .modal-image * { + -webkit-transition: opacity 0.5s linear; + -moz-transition: opacity 0.5s linear; + -ms-transition: opacity 0.5s linear; + -o-transition: opacity 0.5s linear; + transition: opacity 0.5s linear; +} +.modal-gallery .modal-image *.in { + opacity: 1; + filter: alpha(opacity=100); +} +.modal-fullscreen { + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + background: transparent; + overflow: hidden; +} +.modal-fullscreen.modal-loading { + border: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} +.modal-fullscreen .modal-body { + padding: 0; +} +.modal-fullscreen .modal-header, +.modal-fullscreen .modal-footer { + position: absolute; + top: 0; + right: 0; + left: 0; + background: transparent; + border: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + opacity: 0; + z-index: 2000; +} +.modal-fullscreen .modal-footer { + top: auto; + bottom: 0; +} +.modal-fullscreen .close, +.modal-fullscreen .modal-title { + color: #fff; + text-shadow: 0 0 2px rgba(33, 33, 33, 0.8); +} +.modal-fullscreen .modal-header:hover, +.modal-fullscreen .modal-footer:hover { + opacity: 1; +} + +@media (max-width: 767px) { + .modal-gallery .btn span { + display: none; + } + .modal-fullscreen { + right: 0; + left: 0; + } +} diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/css/bootstrap-image-gallery.min.css b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/css/bootstrap-image-gallery.min.css new file mode 100644 index 0000000..4b7366b --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/css/bootstrap-image-gallery.min.css @@ -0,0 +1,22 @@ +@charset 'UTF-8'; +.modal-gallery{width:auto;max-height:none;outline:none;} +.modal-gallery.fade.in{top:50%;} +.modal-gallery .modal-body{max-height:none;} +.modal-gallery .modal-title{display:inline-block;max-height:54px;overflow:hidden;} +.modal-gallery .modal-image{position:relative;margin:auto;min-width:128px;min-height:128px;overflow:hidden;cursor:pointer;} +.modal-gallery .modal-image:hover:before,.modal-gallery .modal-image:hover:after{content:'\2039';position:absolute;top:50%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);z-index:1;} +.modal-gallery .modal-image:hover:after{content:'\203A';left:auto;right:15px;} +.modal-single .modal-image:hover:before,.modal-single .modal-image:hover:after{display:none;} +.modal-loading .modal-image{background:url(../img/loading.gif) center no-repeat;} +.modal-gallery.fade .modal-image{-webkit-transition:width 0.15s ease, height 0.15s ease;-moz-transition:width 0.15s ease, height 0.15s ease;-ms-transition:width 0.15s ease, height 0.15s ease;-o-transition:width 0.15s ease, height 0.15s ease;transition:width 0.15s ease, height 0.15s ease;} +.modal-gallery .modal-image *{position:absolute;top:0;opacity:0;filter:alpha(opacity=0);} +.modal-gallery.fade .modal-image *{-webkit-transition:opacity 0.5s linear;-moz-transition:opacity 0.5s linear;-ms-transition:opacity 0.5s linear;-o-transition:opacity 0.5s linear;transition:opacity 0.5s linear;} +.modal-gallery .modal-image *.in{opacity:1;filter:alpha(opacity=100);} +.modal-fullscreen{border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;background:transparent;overflow:hidden;} +.modal-fullscreen.modal-loading{border:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.modal-fullscreen .modal-body{padding:0;} +.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{position:absolute;top:0;right:0;left:0;background:transparent;border:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:0;z-index:2000;} +.modal-fullscreen .modal-footer{top:auto;bottom:0;} +.modal-fullscreen .close,.modal-fullscreen .modal-title{color:#fff;text-shadow:0 0 2px rgba(33, 33, 33, 0.8);} +.modal-fullscreen .modal-header:hover,.modal-fullscreen .modal-footer:hover{opacity:1;} +@media (max-width:767px){.modal-gallery .btn span{display:none;} .modal-fullscreen{right:0;left:0;}} diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/img/loading.gif b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/img/loading.gif new file mode 100644 index 0000000..90f28cb Binary files /dev/null and b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/img/loading.gif differ diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/js/bootstrap-image-gallery.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/js/bootstrap-image-gallery.js new file mode 100644 index 0000000..32bb4ad --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/js/bootstrap-image-gallery.js @@ -0,0 +1,402 @@ +/* + * Bootstrap Image Gallery 2.10 + * https://github.com/blueimp/Bootstrap-Image-Gallery + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/*jslint nomen: true, regexp: true */ +/*global define, window, document, jQuery */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'load-image', + 'bootstrap' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.loadImage + ); + } +}(function ($, loadImage) { + 'use strict'; + // Bootstrap Image Gallery is an extension to the Modal dialog of Twitter's + // Bootstrap toolkit, to ease navigation between a set of gallery images. + // It features transition effects, fullscreen mode and slideshow functionality. + $.extend($.fn.modal.Constructor.DEFAULTS, { + // Delegate to search gallery links from, can be anything that + // is accepted as parameter for $(): + delegate: document, + // Selector for gallery links: + selector: null, + // The filter for the selected gallery links (e.g. set to ":odd" to + // filter out label and thumbnail linking twice to the same image): + filter: '*', + // The index of the first gallery image to show: + index: 0, + // The href of the first gallery image to show (overrides index): + href: null, + // The range of images around the current one to preload: + preloadRange: 2, + // Offset of image width to viewport width: + offsetWidth: 100, + // Offset of image height to viewport height: + offsetHeight: 230, + // Set to true to display images as canvas elements: + canvas: false, + // Shows the next image after the given time in ms (0 = disabled): + slideshow: 0, + // Defines the image division for previous/next clicks: + imageClickDivision: 0.5 + }); + var originalShow = $.fn.modal.Constructor.prototype.show, + originalHide = $.fn.modal.Constructor.prototype.hide; + $.extend($.fn.modal.Constructor.prototype, { + initLinks: function () { + var $this = this, + options = this.options, + selector = options.selector || + 'a[data-target=' + options.target + ']'; + this.$links = $(options.delegate).find(selector) + .each(function (index) { + if ($this.getUrl(this) === options.href) { + options.index = index; + } + }); + if (!this.$links[options.index]) { + options.index = 0; + } + }, + getUrl: function (element) { + return element.href || $(element).data('href'); + }, + getDownloadUrl: function (element) { + return $(element).data('download'); + }, + startSlideShow: function () { + var $this = this; + if (this.options.slideshow) { + this._slideShow = window.setTimeout( + function () { + $this.next(); + }, + this.options.slideshow + ); + } + }, + stopSlideShow: function () { + window.clearTimeout(this._slideShow); + }, + toggleSlideShow: function () { + var node = this.$element.find('.modal-slideshow'); + if (this.options.slideshow) { + this.options.slideshow = 0; + this.stopSlideShow(); + } else { + this.options.slideshow = node.data('slideshow') || 5000; + this.startSlideShow(); + } + node.find('i').toggleClass('icon-play icon-pause'); + }, + preloadImages: function () { + var options = this.options, + range = options.index + options.preloadRange + 1, + link, + i; + for (i = options.index - options.preloadRange; i < range; i += 1) { + link = this.$links[i]; + if (link && i !== options.index) { + $('').prop('src', this.getUrl(link)); + } + } + }, + loadImage: function () { + var $this = this, + modal = this.$element, + index = this.options.index, + url = this.getUrl(this.$links[index]), + download = this.getDownloadUrl(this.$links[index]), + oldImg; + this.abortLoad(); + this.stopSlideShow(); + modal.trigger('beforeLoad'); + // The timeout prevents displaying a loading status, + // if the image has already been loaded: + this._loadingTimeout = window.setTimeout(function () { + modal.addClass('modal-loading'); + }, 100); + oldImg = modal.find('.modal-image').children('img').removeClass('in'); + // The timeout allows transition effects to finish: + window.setTimeout(function () { + oldImg.remove(); + }, 3000); + modal.find('.modal-title').text(this.$links[index].title); + modal.find('.modal-download').prop( + 'href', + download || url + ); + this._loadingImage = loadImage( + url, + function (img) { + $this.img = img; + window.clearTimeout($this._loadingTimeout); + modal.removeClass('modal-loading'); + modal.trigger('load'); + $this.showImage(img); + $this.startSlideShow(); + }, + this._loadImageOptions + ); + this.preloadImages(); + }, + showImage: function (img) { + var modal = this.$element, + transition = $.support.transition && modal.hasClass('fade'), + method = transition ? modal.animate : modal.css, + modalImage = modal.find('.modal-image'), + clone, + forceReflow; + modalImage.css({ + width: img.width, + height: img.height + }); + if ($(window).width() > 767) { + modal.find('.modal-dialog').css({width: Math.max(img.width + 60, 450)}); + } + // modal.find('.modal-title').css({ width: Math.max(img.width, 380) }); + // if (transition) { + // clone = modal.clone().hide().appendTo(document.body); + // } + // // if ($(window).width() > 767) { + // // method.call(modal.stop(), { + // // 'margin-top': -((clone || modal).outerHeight() / 2), + // // 'margin-left': -((clone || modal).outerWidth() / 2) + // // }); + // // } else { + // // modal.css({ + // // top: ($(window).height() - (clone || modal).outerHeight()) / 2 + // // }); + // // } + // if (clone) { + // clone.remove(); + // } + modalImage.append(img); + forceReflow = img.offsetWidth; + modal.trigger('display'); + if (transition) { + if (modal.is(':visible')) { + $(img).on( + $.support.transition.end, + function (e) { + // Make sure we don't respond to other transitions events + // in the container element, e.g. from button elements: + if (e.target === img) { + $(img).off($.support.transition.end); + modal.trigger('displayed'); + } + } + ).addClass('in'); + } else { + $(img).addClass('in'); + modal.one('shown', function () { + modal.trigger('displayed'); + }); + } + } else { + $(img).addClass('in'); + modal.trigger('displayed'); + } + }, + abortLoad: function () { + if (this._loadingImage) { + this._loadingImage.onload = this._loadingImage.onerror = null; + } + window.clearTimeout(this._loadingTimeout); + }, + prev: function () { + var options = this.options; + options.index -= 1; + if (options.index < 0) { + options.index = this.$links.length - 1; + } + this.loadImage(); + }, + next: function () { + var options = this.options; + options.index += 1; + if (options.index > this.$links.length - 1) { + options.index = 0; + } + this.loadImage(); + }, + keyHandler: function (e) { + switch (e.which) { + case 37: // left + case 38: // up + e.preventDefault(); + this.prev(); + break; + case 39: // right + case 40: // down + e.preventDefault(); + this.next(); + break; + } + }, + wheelHandler: function (e) { + e.preventDefault(); + e = e.originalEvent; + this._wheelCounter = this._wheelCounter || 0; + this._wheelCounter += (e.wheelDelta || e.detail || 0); + if ((e.wheelDelta && this._wheelCounter >= 120) || + (!e.wheelDelta && this._wheelCounter < 0)) { + this.prev(); + this._wheelCounter = 0; + } else if ((e.wheelDelta && this._wheelCounter <= -120) || + (!e.wheelDelta && this._wheelCounter > 0)) { + this.next(); + this._wheelCounter = 0; + } + }, + initGalleryEvents: function () { + var $this = this, + modal = this.$element; + modal.find('.modal-image').on('click.modal-gallery', function (e) { + var modalImage = $(this); + if ($this.$links.length === 1) { + $this.hide(); + } else { + if ((e.pageX - modalImage.offset().left) / modalImage.width() < + $this.options.imageClickDivision) { + $this.prev(e); + } else { + $this.next(e); + } + } + }); + modal.find('.modal-prev').on('click.modal-gallery', function (e) { + $this.prev(e); + }); + modal.find('.modal-next').on('click.modal-gallery', function (e) { + $this.next(e); + }); + modal.find('.modal-slideshow').on('click.modal-gallery', function (e) { + $this.toggleSlideShow(e); + }); + $(document) + .on('keydown.modal-gallery', function (e) { + $this.keyHandler(e); + }) + .on( + 'mousewheel.modal-gallery, DOMMouseScroll.modal-gallery', + function (e) { + $this.wheelHandler(e); + } + ); + }, + destroyGalleryEvents: function () { + var modal = this.$element; + this.abortLoad(); + this.stopSlideShow(); + modal.find('.modal-image, .modal-prev, .modal-next, .modal-slideshow') + .off('click.modal-gallery'); + $(document) + .off('keydown.modal-gallery') + .off('mousewheel.modal-gallery, DOMMouseScroll.modal-gallery'); + }, + show: function () { + if (!this.isShown && this.$element.hasClass('modal-gallery')) { + var modal = this.$element, + options = this.options, + windowWidth = $(window).width(), + windowHeight = $(window).height(); + if (modal.hasClass('modal-fullscreen')) { + this._loadImageOptions = { + maxWidth: windowWidth, + maxHeight: windowHeight, + canvas: options.canvas + }; + if (modal.hasClass('modal-fullscreen-stretch')) { + this._loadImageOptions.minWidth = windowWidth; + this._loadImageOptions.minHeight = windowHeight; + } + } else { + this._loadImageOptions = { + maxWidth: windowWidth - options.offsetWidth, + maxHeight: windowHeight - options.offsetHeight, + canvas: options.canvas + }; + } + // if (windowWidth > 767) { + // modal.css({ + // 'margin-top': -(modal.outerHeight() / 2), + // 'margin-left': -(modal.outerWidth() / 2) + // }); + // } else { + // modal.css({ + // top: ($(window).height() - modal.outerHeight()) / 2 + // }); + // } + this.initGalleryEvents(); + this.initLinks(); + if (this.$links.length) { + modal.find('.modal-slideshow, .modal-prev, .modal-next') + .toggle(this.$links.length !== 1); + modal.toggleClass( + 'modal-single', + this.$links.length === 1 + ); + this.loadImage(); + } + } + originalShow.apply(this, arguments); + }, + hide: function () { + if (this.isShown && this.$element.hasClass('modal-gallery')) { + this.options.delegate = document; + this.options.href = null; + this.destroyGalleryEvents(); + } + originalHide.apply(this, arguments); + } + }); + $(function () { + $(document.body).on( + 'click.modal-gallery.data-api', + '[data-toggle="modal-gallery"]', + function (e) { + var $this = $(this), + options = $this.data(), + modal = $(options.target), + data = modal.data('bs.modal'), + link; + if (!data) { + options = $.extend(modal.data(), options); + } + if (!options.selector) { + options.selector = 'a[data-gallery=gallery]'; + } + link = $(e.target).closest(options.selector); + if (link.length && modal.length) { + e.preventDefault(); + options.href = link.prop('href') || link.data('href'); + options.delegate = link[0] !== this ? this : document; + if (data) { + $.extend(data.options, options); + } + modal.modal(options); + } + } + ); + }); +})); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/js/bootstrap-image-gallery.min.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/js/bootstrap-image-gallery.min.js new file mode 100644 index 0000000..e8662f0 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-image-gallery/js/bootstrap-image-gallery.min.js @@ -0,0 +1 @@ +(function(a){"use strict",typeof define=="function"&&define.amd?define(["jquery","load-image","bootstrap"],a):a(window.jQuery,window.loadImage)})(function(a,b){"use strict",a.extend(a.fn.modal.defaults,{delegate:document,selector:null,filter:"*",index:0,href:null,preloadRange:2,offsetWidth:100,offsetHeight:200,canvas:!1,slideshow:0,imageClickDivision:.5});var c=a.fn.modal.Constructor.prototype.show,d=a.fn.modal.Constructor.prototype.hide;a.extend(a.fn.modal.Constructor.prototype,{initLinks:function(){var b=this,c=this.options,d=c.selector||"a[data-target="+c.target+"]";this.$links=a(c.delegate).find(d).filter(c.filter).each(function(a){b.getUrl(this)===c.href&&(c.index=a)}),this.$links[c.index]||(c.index=0)},getUrl:function(b){return b.href||a(b).data("href")},getDownloadUrl:function(b){return a(b).data("download")},startSlideShow:function(){var a=this;this.options.slideshow&&(this._slideShow=window.setTimeout(function(){a.next()},this.options.slideshow))},stopSlideShow:function(){window.clearTimeout(this._slideShow)},toggleSlideShow:function(){var a=this.$element.find(".modal-slideshow");this.options.slideshow?(this.options.slideshow=0,this.stopSlideShow()):(this.options.slideshow=a.data("slideshow")||5e3,this.startSlideShow()),a.find("i").toggleClass("icon-play icon-pause")},preloadImages:function(){var b=this.options,c=b.index+b.preloadRange+1,d,e;for(e=b.index-b.preloadRange;e").prop("src",this.getUrl(d))},loadImage:function(){var a=this,c=this.$element,d=this.options.index,e=this.getUrl(this.$links[d]),f=this.getDownloadUrl(this.$links[d]),g;this.abortLoad(),this.stopSlideShow(),c.trigger("beforeLoad"),this._loadingTimeout=window.setTimeout(function(){c.addClass("modal-loading")},100),g=c.find(".modal-image").children().removeClass("in"),window.setTimeout(function(){g.remove()},3e3),c.find(".modal-title").text(this.$links[d].title),c.find(".modal-download").prop("href",f||e),this._loadingImage=b(e,function(b){a.img=b,window.clearTimeout(a._loadingTimeout),c.removeClass("modal-loading"),c.trigger("load"),a.showImage(b),a.startSlideShow()},this._loadImageOptions),this.preloadImages()},showImage:function(b){var c=this.$element,d=a.support.transition&&c.hasClass("fade"),e=d?c.animate:c.css,f=c.find(".modal-image"),g,h;f.css({width:b.width,height:b.height}),c.find(".modal-title").css({width:Math.max(b.width,380)}),d&&(g=c.clone().hide().appendTo(document.body)),a(window).width()>767?e.call(c.stop(),{"margin-top":-((g||c).outerHeight()/2),"margin-left":-((g||c).outerWidth()/2)}):c.css({top:(a(window).height()-(g||c).outerHeight())/2}),g&&g.remove(),f.append(b),h=b.offsetWidth,c.trigger("display"),d?c.is(":visible")?a(b).on(a.support.transition.end,function(d){d.target===b&&(a(b).off(a.support.transition.end),c.trigger("displayed"))}).addClass("in"):(a(b).addClass("in"),c.one("shown",function(){c.trigger("displayed")})):(a(b).addClass("in"),c.trigger("displayed"))},abortLoad:function(){this._loadingImage&&(this._loadingImage.onload=this._loadingImage.onerror=null),window.clearTimeout(this._loadingTimeout)},prev:function(){var a=this.options;a.index-=1,a.index<0&&(a.index=this.$links.length-1),this.loadImage()},next:function(){var a=this.options;a.index+=1,a.index>this.$links.length-1&&(a.index=0),this.loadImage()},keyHandler:function(a){switch(a.which){case 37:case 38:a.preventDefault(),this.prev();break;case 39:case 40:a.preventDefault(),this.next()}},wheelHandler:function(a){a.preventDefault(),a=a.originalEvent,this._wheelCounter=this._wheelCounter||0,this._wheelCounter+=a.wheelDelta||a.detail||0;if(a.wheelDelta&&this._wheelCounter>=120||!a.wheelDelta&&this._wheelCounter<0)this.prev(),this._wheelCounter=0;else if(a.wheelDelta&&this._wheelCounter<=-120||!a.wheelDelta&&this._wheelCounter>0)this.next(),this._wheelCounter=0},initGalleryEvents:function(){var b=this,c=this.$element;c.find(".modal-image").on("click.modal-gallery",function(c){var d=a(this);b.$links.length===1?b.hide():(c.pageX-d.offset().left)/d.width()767?b.css({"margin-top":-(b.outerHeight()/2),"margin-left":-(b.outerWidth()/2)}):b.css({top:(a(window).height()-b.outerHeight())/2}),this.initGalleryEvents(),this.initLinks(),this.$links.length&&(b.find(".modal-slideshow, .modal-prev, .modal-next").toggle(this.$links.length!==1),b.toggleClass("modal-single",this.$links.length===1),this.loadImage())}c.apply(this,arguments)},hide:function(){this.isShown&&this.$element.hasClass("modal-gallery")&&(this.options.delegate=document,this.options.href=null,this.destroyGalleryEvents()),d.apply(this,arguments)}}),a(function(){a(document.body).on("click.modal-gallery.data-api",'[data-toggle="modal-gallery"]',function(b){var c=a(this),d=c.data(),e=a(d.target),f=e.data("modal"),g;f||(d=a.extend(e.data(),d)),d.selector||(d.selector="a[data-gallery=gallery]"),g=a(b.target).closest(d.selector),g.length&&e.length&&(b.preventDefault(),d.href=g.prop("href")||g.data("href"),d.delegate=g[0]!==this?this:document,f&&a.extend(f.options,d),e.modal(d))})})}); \ No newline at end of file diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/css/bootstrap-modal.css b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/css/bootstrap-modal.css new file mode 100644 index 0000000..76e3be2 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/css/bootstrap-modal.css @@ -0,0 +1,214 @@ +/*! + * Bootstrap Modal + * + * Copyright Jordan Schroter + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ + +.modal-open { + overflow: hidden; +} + + +/* add a scroll bar to stop page from jerking around */ +.modal-open.page-overflow .page-container, +.modal-open.page-overflow .page-container .navbar-fixed-top, +.modal-open.page-overflow .page-container .navbar-fixed-bottom, +.modal-open.page-overflow .modal-scrollable { + overflow-y: scroll; +} + +@media (max-width: 979px) { + .modal-open.page-overflow .page-container .navbar-fixed-top, + .modal-open.page-overflow .page-container .navbar-fixed-bottom { + overflow-y: visible; + } +} + + +.modal-scrollable { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: auto; +} + +.modal { + outline: none; + position: absolute; + margin-top: 0; + top: 50%; + overflow: visible; /* allow content to popup out (i.e tooltips) */ +} + +.modal.fade { + top: -100%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out, bottom 0.3s ease-out, margin-top 0.3s ease-out; +} + +.modal.fade.in { + top: 50%; +} + +.modal-body { + max-height: none; + overflow: visible; +} + +.modal.modal-absolute { + position: absolute; + z-index: 950; +} + +.modal .loading-mask { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background: #fff; + border-radius: 6px; +} + +.modal-backdrop.modal-absolute{ + position: absolute; + z-index: 940; +} + +.modal-backdrop, +.modal-backdrop.fade.in{ + opacity: 0.7; + filter: alpha(opacity=70); + background: #fff; +} + +.modal.container { + width: 940px; + margin-left: -470px; +} + +/* Modal Overflow */ + +.modal-overflow.modal { + top: 1%; +} + +.modal-overflow.modal.fade { + top: -100%; +} + +.modal-overflow.modal.fade.in { + top: 1%; +} + +.modal-overflow .modal-body { + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +/* Responsive */ + +@media (min-width: 1200px) { + .modal.container { + width: 1170px; + margin-left: -585px; + } +} + +@media (max-width: 979px) { + .modal, + .modal.container, + .modal.modal-overflow { + top: 1%; + right: 1%; + left: 1%; + bottom: auto; + width: auto !important; + height: auto !important; + margin: 0 !important; + padding: 0 !important; + } + + .modal.fade.in, + .modal.container.fade.in, + .modal.modal-overflow.fade.in { + top: 1%; + bottom: auto; + } + + .modal-body, + .modal-overflow .modal-body { + position: static; + margin: 0; + height: auto !important; + max-height: none !important; + overflow: visible !important; + } + + .modal-footer, + .modal-overflow .modal-footer { + position: static; + } +} + +.loading-spinner { + position: absolute; + top: 50%; + left: 50%; + margin: -12px 0 0 -12px; +} + +/* +Animate.css - http://daneden.me/animate +Licensed under the ☺ license (http://licence.visualidiot.com/) + +Copyright (c) 2012 Dan Eden*/ + +.animated { + -webkit-animation-duration: 1s; + -moz-animation-duration: 1s; + -o-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + -moz-animation-fill-mode: both; + -o-animation-fill-mode: both; + animation-fill-mode: both; +} + +@-webkit-keyframes shake { + 0%, 100% {-webkit-transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {-webkit-transform: translateX(-10px);} + 20%, 40%, 60%, 80% {-webkit-transform: translateX(10px);} +} + +@-moz-keyframes shake { + 0%, 100% {-moz-transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {-moz-transform: translateX(-10px);} + 20%, 40%, 60%, 80% {-moz-transform: translateX(10px);} +} + +@-o-keyframes shake { + 0%, 100% {-o-transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {-o-transform: translateX(-10px);} + 20%, 40%, 60%, 80% {-o-transform: translateX(10px);} +} + +@keyframes shake { + 0%, 100% {transform: translateX(0);} + 10%, 30%, 50%, 70%, 90% {transform: translateX(-10px);} + 20%, 40%, 60%, 80% {transform: translateX(10px);} +} + +.shake { + -webkit-animation-name: shake; + -moz-animation-name: shake; + -o-animation-name: shake; + animation-name: shake; +} diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/img/ajax-loader.gif b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/img/ajax-loader.gif new file mode 100644 index 0000000..4e651ed Binary files /dev/null and b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/img/ajax-loader.gif differ diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/js/bootstrap-modal.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/js/bootstrap-modal.js new file mode 100644 index 0000000..0e39e9b --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/js/bootstrap-modal.js @@ -0,0 +1,374 @@ +/* =========================================================== + * bootstrap-modal.js v2.1 + * =========================================================== + * Copyright 2012 Jordan Schroter + * + * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function (element, options) { + this.init(element, options); + }; + + Modal.prototype = { + + constructor: Modal, + + init: function (element, options) { + this.options = options; + + this.$element = $(element) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)); + + this.options.remote && this.$element.find('.modal-body').load(this.options.remote); + + var manager = typeof this.options.manager === 'function' ? + this.options.manager.call(this) : this.options.manager; + + manager = manager.appendModal ? + manager : $(manager).modalmanager().data('modalmanager'); + + manager.appendModal(this); + }, + + toggle: function () { + return this[!this.isShown ? 'show' : 'hide'](); + }, + + show: function () { + var e = $.Event('show'); + + if (this.isShown) return; + + this.$element.triggerHandler(e); + + if (e.isDefaultPrevented()) return; + + this.escape(); + + this.tab(); + + this.options.loading && this.loading(); + }, + + hide: function (e) { + e && e.preventDefault(); + + e = $.Event('hide'); + + this.$element.triggerHandler(e); + + if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false); + + this.isShown = false; + + this.escape(); + + this.tab(); + + this.isLoading && this.loading(); + + $(document).off('focusin.modal'); + + this.$element + .removeClass('in') + .removeClass('animated') + .removeClass(this.options.attentionAnimation) + .removeClass('modal-overflow') + .attr('aria-hidden', true); + + $.support.transition && this.$element.hasClass('fade') ? + this.hideWithTransition() : + this.hideModal(); + }, + + layout: function () { + var prop = this.options.height ? 'height' : 'max-height', + value = this.options.height || this.options.maxHeight; + + if (this.options.width){ + this.$element.css('width', this.options.width); + + var that = this; + this.$element.css('margin-left', function () { + if (/%/ig.test(that.options.width)){ + return -(parseInt(that.options.width) / 2) + '%'; + } else { + return -($(this).width() / 2) + 'px'; + } + }); + } else { + this.$element.css('width', ''); + this.$element.css('margin-left', ''); + } + + this.$element.find('.modal-body') + .css('overflow', '') + .css(prop, ''); + + var modalOverflow = $(window).height() - 10 < this.$element.height(); + + if (value){ + this.$element.find('.modal-body') + .css('overflow', 'auto') + .css(prop, value); + } + + if (modalOverflow || this.options.modalOverflow) { + this.$element + .css('margin-top', 0) + .addClass('modal-overflow'); + } else { + this.$element + .css('margin-top', 0 - this.$element.height() / 2) + .removeClass('modal-overflow'); + } + }, + + tab: function () { + var that = this; + + if (this.isShown && this.options.consumeTab) { + this.$element.on('keydown.tabindex.modal', '[data-tabindex]', function (e) { + if (e.keyCode && e.keyCode == 9){ + var $next = $(this), + $rollover = $(this); + + that.$element.find('[data-tabindex]:enabled:not([readonly])').each(function (e) { + if (!e.shiftKey){ + $next = $next.data('tabindex') < $(this).data('tabindex') ? + $next = $(this) : + $rollover = $(this); + } else { + $next = $next.data('tabindex') > $(this).data('tabindex') ? + $next = $(this) : + $rollover = $(this); + } + }); + + $next[0] !== $(this)[0] ? + $next.focus() : $rollover.focus(); + + e.preventDefault(); + } + }); + } else if (!this.isShown) { + this.$element.off('keydown.tabindex.modal'); + } + }, + + escape: function () { + var that = this; + if (this.isShown && this.options.keyboard) { + if (!this.$element.attr('tabindex')) this.$element.attr('tabindex', -1); + + this.$element.on('keyup.dismiss.modal', function (e) { + e.which == 27 && that.hide(); + }); + } else if (!this.isShown) { + this.$element.off('keyup.dismiss.modal') + } + }, + + hideWithTransition: function () { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end); + that.hideModal(); + }, 500); + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout); + that.hideModal(); + }); + }, + + hideModal: function () { + this.$element + .hide() + .triggerHandler('hidden'); + + var prop = this.options.height ? 'height' : 'max-height'; + var value = this.options.height || this.options.maxHeight; + + if (value){ + this.$element.find('.modal-body') + .css('overflow', '') + .css(prop, ''); + } + + }, + + removeLoading: function () { + this.$loading.remove(); + this.$loading = null; + this.isLoading = false; + }, + + loading: function (callback) { + callback = callback || function () {}; + + var animate = this.$element.hasClass('fade') ? 'fade' : ''; + + if (!this.isLoading) { + var doAnimate = $.support.transition && animate; + + this.$loading = $('
    ') + .append(this.options.spinner) + .appendTo(this.$element); + + if (doAnimate) this.$loading[0].offsetWidth; // force reflow + + this.$loading.addClass('in'); + + this.isLoading = true; + + doAnimate ? + this.$loading.one($.support.transition.end, callback) : + callback(); + + } else if (this.isLoading && this.$loading) { + this.$loading.removeClass('in'); + + var that = this; + $.support.transition && this.$element.hasClass('fade')? + this.$loading.one($.support.transition.end, function () { that.removeLoading() }) : + that.removeLoading(); + + } else if (callback) { + callback(this.isLoading); + } + }, + + focus: function () { + var $focusElem = this.$element.find(this.options.focusOn); + + $focusElem = $focusElem.length ? $focusElem : this.$element; + + $focusElem.focus(); + }, + + attention: function (){ + // NOTE: transitionEnd with keyframes causes odd behaviour + + if (this.options.attentionAnimation){ + this.$element + .removeClass('animated') + .removeClass(this.options.attentionAnimation); + + var that = this; + + setTimeout(function () { + that.$element + .addClass('animated') + .addClass(that.options.attentionAnimation); + }, 0); + } + + + this.focus(); + }, + + + destroy: function () { + var e = $.Event('destroy'); + this.$element.triggerHandler(e); + if (e.isDefaultPrevented()) return; + + this.teardown(); + }, + + teardown: function () { + if (!this.$parent.length){ + this.$element.remove(); + this.$element = null; + return; + } + + if (this.$parent !== this.$element.parent()){ + this.$element.appendTo(this.$parent); + } + + this.$element.off('.modal'); + this.$element.removeData('modal'); + this.$element + .removeClass('in') + .attr('aria-hidden', true); + } + }; + + + /* MODAL PLUGIN DEFINITION + * ======================= */ + + $.fn.modal = function (option, args) { + return this.each(function () { + var $this = $(this), + data = $this.data('modal'), + options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option); + + if (!data) $this.data('modal', (data = new Modal(this, options))); + if (typeof option == 'string') data[option].apply(data, [].concat(args)); + else if (options.show) data.show() + }) + }; + + $.fn.modal.defaults = { + keyboard: true, + backdrop: true, + loading: false, + show: true, + width: null, + height: null, + maxHeight: null, + modalOverflow: false, + consumeTab: true, + focusOn: null, + replace: false, + resize: false, + attentionAnimation: 'shake', + manager: 'body', + spinner: '
    ' + }; + + $.fn.modal.Constructor = Modal; + + + /* MODAL DATA-API + * ============== */ + + $(function () { + $(document).off('.modal').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) { + var $this = $(this), + href = $this.attr('href'), + $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))), //strip for ie7 + option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()); + + e.preventDefault(); + $target + .modal(option) + .one('hide', function () { + $this.focus(); + }) + }); + }); + +}(window.jQuery); diff --git a/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/js/bootstrap-modalmanager.js b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/js/bootstrap-modalmanager.js new file mode 100644 index 0000000..1373a47 --- /dev/null +++ b/extra_apps/xadmin/static/xadmin/vendor/bootstrap-modal/js/bootstrap-modalmanager.js @@ -0,0 +1,412 @@ +/* =========================================================== + * bootstrap-modalmanager.js v2.1 + * =========================================================== + * Copyright 2012 Jordan Schroter. + * + * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + +!function ($) { + + "use strict"; // jshint ;_; + + /* MODAL MANAGER CLASS DEFINITION + * ====================== */ + + var ModalManager = function (element, options) { + this.init(element, options); + }; + + ModalManager.prototype = { + + constructor: ModalManager, + + init: function (element, options) { + this.$element = $(element); + this.options = $.extend({}, $.fn.modalmanager.defaults, this.$element.data(), typeof options == 'object' && options); + this.stack = []; + this.backdropCount = 0; + + if (this.options.resize) { + var resizeTimeout, + that = this; + + $(window).on('resize.modal', function(){ + resizeTimeout && clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(function(){ + for (var i = 0; i < that.stack.length; i++){ + that.stack[i].isShown && that.stack[i].layout(); + } + }, 10); + }); + } + }, + + createModal: function (element, options) { + $(element).modal($.extend({ manager: this }, options)); + }, + + appendModal: function (modal) { + this.stack.push(modal); + + var that = this; + + modal.$element.on('show.modalmanager', targetIsSelf(function (e) { + + var showModal = function(){ + modal.isShown = true; + + var transition = $.support.transition && modal.$element.hasClass('fade'); + + that.$element + .toggleClass('modal-open', that.hasOpenModal()) + .toggleClass('page-overflow', $(window).height() < that.$element.height()); + + modal.$parent = modal.$element.parent(); + + modal.$container = that.createContainer(modal); + + modal.$element.appendTo(modal.$container); + + that.backdrop(modal, function () { + + modal.$element.show(); + + if (transition) { + //modal.$element[0].style.display = 'run-in'; + modal.$element[0].offsetWidth; + //modal.$element.one($.support.transition.end, function () { modal.$element[0].style.display = 'block' }); + } + + modal.layout(); + + modal.$element + .addClass('in') + .attr('aria-hidden', false); + + var complete = function () { + that.setFocus(); + modal.$element.triggerHandler('shown'); + }; + + transition ? + modal.$element.one($.support.transition.end, complete) : + complete(); + }); + }; + + modal.options.replace ? + that.replace(showModal) : + showModal(); + })); + + modal.$element.on('hidden.modalmanager', targetIsSelf(function (e) { + + that.backdrop(modal); + + if (modal.$backdrop){ + $.support.transition && modal.$element.hasClass('fade') ? + modal.$backdrop.one($.support.transition.end, function () { that.destroyModal(modal) }) : + that.destroyModal(modal); + } else { + that.destroyModal(modal); + } + + })); + + modal.$element.on('destroy.modalmanager', targetIsSelf(function (e) { + that.removeModal(modal); + })); + + }, + + destroyModal: function (modal) { + + modal.destroy(); + + var hasOpenModal = this.hasOpenModal(); + + this.$element.toggleClass('modal-open', hasOpenModal); + + if (!hasOpenModal){ + this.$element.removeClass('page-overflow'); + } + + this.removeContainer(modal); + + this.setFocus(); + }, + + hasOpenModal: function () { + for (var i = 0; i < this.stack.length; i++){ + if (this.stack[i].isShown) return true; + } + + return false; + }, + + setFocus: function () { + var topModal; + + for (var i = 0; i < this.stack.length; i++){ + if (this.stack[i].isShown) topModal = this.stack[i]; + } + + if (!topModal) return; + + topModal.focus(); + + }, + + removeModal: function (modal) { + modal.$element.off('.modalmanager'); + if (modal.$backdrop) this.removeBackdrop.call(modal); + this.stack.splice(this.getIndexOfModal(modal), 1); + }, + + getModalAt: function (index) { + return this.stack[index]; + }, + + getIndexOfModal: function (modal) { + for (var i = 0; i < this.stack.length; i++){ + if (modal === this.stack[i]) return i; + } + }, + + replace: function (callback) { + var topModal; + + for (var i = 0; i < this.stack.length; i++){ + if (this.stack[i].isShown) topModal = this.stack[i]; + } + + if (topModal) { + this.$backdropHandle = topModal.$backdrop; + topModal.$backdrop = null; + + callback && topModal.$element.one('hidden', + targetIsSelf( $.proxy(callback, this) )); + + topModal.hide(); + } else if (callback) { + callback(); + } + }, + + removeBackdrop: function (modal) { + modal.$backdrop.remove(); + modal.$backdrop = null; + }, + + createBackdrop: function (animate) { + var $backdrop; + + if (!this.$backdropHandle) { + $backdrop = $('