From 39aaacccb6e15b6cc24d751bc16f6f3a34e83891 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 09:37:25 +0200 Subject: [PATCH 01/58] PEP8 --- djadmin2/actions.py | 3 ++- djadmin2/core.py | 12 +++++------- djadmin2/forms.py | 14 ++++++++------ djadmin2/utils.py | 1 + djadmin2/views.py | 16 +++++++--------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index 71ae643..67e15c4 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -20,7 +20,8 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) - empty_message = 'Items must be selected in order to perform actions on them. No items have been changed.' + empty_message = 'Items must be selected in order to perform actions on them. ' + \ + 'No items have been changed.' success_message = 'Successfully deleted %d %s' queryset = None diff --git a/djadmin2/core.py b/djadmin2/core.py index 46a01e9..8068509 100644 --- a/djadmin2/core.py +++ b/djadmin2/core.py @@ -124,7 +124,7 @@ class Admin2(object): url(regex=r'^$', view=self.index_view.as_view(**self.get_index_kwargs()), name='dashboard' - ), + ), url(regex='^auth/user/(?P\d+)/update/password/$', view=views.PasswordChangeView.as_view(), name='password_change' @@ -137,16 +137,14 @@ class Admin2(object): view=views.LogoutView.as_view(), name='logout' ), - url( - regex=r'^(?P\w+)/$', + url(regex=r'^(?P\w+)/$', view=self.app_index_view.as_view(**self.get_app_index_kwargs()), name='app_index' - ), - url( - regex=r'^api/v0/$', + ), + url(regex=r'^api/v0/$', view=self.api_index_view.as_view(**self.get_api_index_kwargs()), name='api_index' - ), + ), ) for model, model_admin in self.registry.iteritems(): diff --git a/djadmin2/forms.py b/djadmin2/forms.py index 719e9c2..b0cb5e9 100644 --- a/djadmin2/forms.py +++ b/djadmin2/forms.py @@ -2,9 +2,8 @@ from __future__ import unicode_literals from copy import deepcopy from django.contrib.auth import authenticate -from django.contrib.auth.forms import ( - AuthenticationForm, UserCreationForm, UserChangeForm - ) +from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth.forms import UserCreationForm, UserChangeForm import django.forms import django.forms.models import django.forms.extras.widgets @@ -225,7 +224,7 @@ def floppify_form(form_class): def modelform_factory(model, form=django.forms.models.ModelForm, fields=None, - exclude=None, formfield_callback=None, widgets=None): + exclude=None, formfield_callback=None, widgets=None): form_class = django.forms.models.modelform_factory( model=model, form=form, @@ -246,8 +245,11 @@ class AdminAuthenticationForm(AuthenticationForm): Liberally copied from django.contrib.admin.forms.AdminAuthenticationForm """ - this_is_the_login_form = django.forms.BooleanField(widget=floppyforms.HiddenInput, initial=1, - error_messages={'required': ugettext_lazy("Please log in again, because your session has expired.")}) + error_messages = { + 'required': ugettext_lazy("Please log in again, because your session has expired."), + } + this_is_the_login_form = django.forms.BooleanField(widget=floppyforms.HiddenInput, + initial=1, error_messages=error_messages) def clean(self): username = self.cleaned_data.get('username') diff --git a/djadmin2/utils.py b/djadmin2/utils.py index 3f4256e..fd63458 100644 --- a/djadmin2/utils.py +++ b/djadmin2/utils.py @@ -22,6 +22,7 @@ def lookup_needs_distinct(opts, lookup_path): return True return False + def model_options(model): """ Wrapper for accessing model._meta. If this access point changes in core diff --git a/djadmin2/views.py b/djadmin2/views.py index 990f5c1..fb08700 100644 --- a/djadmin2/views.py +++ b/djadmin2/views.py @@ -20,21 +20,19 @@ from .viewmixins import Admin2Mixin, AdminModel2Mixin, Admin2ModelFormMixin class IndexView(Admin2Mixin, generic.TemplateView): - """ -Context Variables - - :apps: A dictionary of apps, each app being a dictionary with keys - being models and the value being djadmin2.types.ModelAdmin2 - objects. - - :request.user: The user object representing the current user. + """Context Variables + + :apps: A dictionary of apps, each app being a dictionary with keys + being models and the value being djadmin2.types.ModelAdmin2 + objects. + :request.user: The user object representing the current user. + """ default_template_name = "index.html" registry = None apps = None def get_context_data(self, **kwargs): - data = super(IndexView, self).get_context_data(**kwargs) data.update({ 'apps': self.apps, From da4cf6deb9c151d91ee101491568e13a67b8215d Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 09:53:24 +0200 Subject: [PATCH 02/58] Add Danilo Bargen to authors --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 4dbadf8..e18cfac 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -29,3 +29,4 @@ Developers * Ryan Balfanz (@RyanBalfanz / ) * Tom Christie (@tomchristie) * Chris Jones (@chrisjones-brack3t / ) +* Danilo Bargen (@dbrgn) From c4120fa22a1b418558e484d89f3a8780dfbc19cf Mon Sep 17 00:00:00 2001 From: Audrey Roy Date: Sat, 6 Jul 2013 09:55:06 +0200 Subject: [PATCH 03/58] Simpler way to pull upstream changes, with optional rebase for advanced git users. --- docs/contributing.rst | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 1e8df25..36509ce 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -27,7 +27,7 @@ Local Installation 1. Create a virtualenv_ (or use virtualenvwrapper_). Activate it. 2. cd into django-admin2 3. type ``$ pip install -r requirements.txt`` -4. type ``$ python setup.py develop`` +4. type ``$ python setup.py develop`` Try the example projects -------------------------- @@ -37,7 +37,7 @@ Try the example projects 3. run the dev server: ``$ python manage.py runserver`` .. _virtualenv: http://www.virtualenv.org/en/latest/ -.. _virtualenvwrapper: http://virtualenvwrapper.readthedocs.org/en/latest/ +.. _virtualenvwrapper: http://virtualenvwrapper.readthedocs.org/en/latest/ Issues! ======= @@ -61,7 +61,7 @@ Setting up topic branches and generating pull requests While it's handy to provide useful code snippets in an issue, it is better for you as a developer to submit pull requests. By submitting pull request your -contribution to django-admin2 will be recorded by Github. +contribution to django-admin2 will be recorded by Github. In git it is best to isolate each topic or feature into a "topic branch". While individual commits allow you control over how small individual changes are made @@ -113,23 +113,24 @@ add a comment to the discussion section of the pull request. Pull upstream changes into your fork regularly ================================================== -**django-admin2** is advancing quickly. It is therefore critical that you pull upstream changes from master into your fork on a regular basis. Nothing is worse than putting in a day of hard work into a pull request only to have it rejected because it has diverged too far from master. +**django-admin2** is advancing quickly. It is therefore critical that you pull upstream changes from master into your fork on a regular basis. Nothing is worse than putting in a day of hard work into a pull request only to have it rejected because it has diverged too far from master. To pull in upstream changes:: git remote add upstream https://github.com/twoscoops/django-admin2.git - git fetch upstream develop - -Check the log to be sure that you actually want the changes, before merging:: - - git log upstream/develop - -Then merge the changes that you fetched:: - - git merge upstream/develop + git pull upstream develop For more info, see http://help.github.com/fork-a-repo/ +Advanced git users: Pull with rebase +------------------------------------ + +This will pull and then reapply your work on top of the upcoming changes:: + + git pull --rebase upstream develop + +It saves you from an extra merge, keeping the history cleaner, but it's potentially dangerous because you're rewriting history. For more info, see http://gitready.com/advanced/2009/02/11/pull-with-rebase.html + How to get your pull request accepted ===================================== @@ -207,7 +208,7 @@ As much as possible, we follow the advice of the `Two Scoops of Django`_ book. P Templates ~~~~~~~~~ -Follow bootstrap's coding standards for HTML_ and CSS_. Use two spaces for indentation, and write so the templates are readable (not for the generated html). +Follow bootstrap's coding standards for HTML_ and CSS_. Use two spaces for indentation, and write so the templates are readable (not for the generated html). .. _HTML: https://github.com/twitter/bootstrap/blob/master/CONTRIBUTING.md#coding-standards-html .. _CSS: https://github.com/twitter/bootstrap/blob/master/CONTRIBUTING.md#coding-standards-css From 12579fdd0e815a723e0b3856c7ce5830622ffc0d Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 09:55:29 +0200 Subject: [PATCH 04/58] fix #234, this adds formal install instructions to the docs and includes reorganization of the docs --- README.rst | 4 +-- docs/architecture.rst | 22 --------------- docs/conf.py | 7 +++-- docs/index.rst | 42 ++++++++++++++-------------- docs/installation.rst | 46 +++++++++++++++++++++++++++++++ docs/{ => ref}/api.rst | 4 +-- docs/{ => ref}/built-in-views.rst | 0 docs/{ => ref}/meta.rst | 0 docs/{ => ref}/themes.rst | 0 9 files changed, 74 insertions(+), 51 deletions(-) delete mode 100644 docs/architecture.rst create mode 100644 docs/installation.rst rename docs/{ => ref}/api.rst (95%) rename docs/{ => ref}/built-in-views.rst (100%) rename docs/{ => ref}/meta.rst (100%) rename docs/{ => ref}/themes.rst (100%) diff --git a/README.rst b/README.rst index f3e3ed3..463f5d8 100644 --- a/README.rst +++ b/README.rst @@ -52,6 +52,7 @@ Requirements Installation ============ + Use pip to install from PyPI: .. code-block:: python @@ -85,9 +86,6 @@ Add djadmin2 urls to your URLconf: ... url(r'^admin2/', include(djadmin2.default.urls)), ) - - - How to write django-admin2 modules diff --git a/docs/architecture.rst b/docs/architecture.rst deleted file mode 100644 index d349c9b..0000000 --- a/docs/architecture.rst +++ /dev/null @@ -1,22 +0,0 @@ -================ -Architecture -================ - -.. warning:: This is out of date and will be updated shortly. - -Workflow Pieces ----------------- - -* Apps -* Apps.models -* AdminObj -* Appstore - -Workflow ----------------- - -1. Instantiate Appstore -2. Loop through the Apps then models per App -3. Admin2s are created from models: djadmin2.models.register(Poll) -4. Admin2s contain methods/properties necessaey for UI -5. Views diff --git a/docs/conf.py b/docs/conf.py index d843649..afa2358 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,7 +11,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -62,9 +63,9 @@ copyright = u'2013, Daniel Greenfeld' # built documents. # # The short X.Y version. -version = '0.4' +version = '0.5' # The full version, including alpha/beta/rc tags. -release = '0.4.0' +release = '0.5.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/index.rst b/docs/index.rst index 4864518..e6a0603 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,29 +1,33 @@ +========================================= Welcome to django-admin2's documentation! ========================================= +.. image:: https://travis-ci.org/pydanny/django-admin2.png + :alt: Build Status + :target: https://travis-ci.org/pydanny/django-admin2 + +**Warning:** This project is currently in an **alpha** state and currently not meant for real projects. + +One of the most useful parts of ``django.contrib.admin`` is the ability to configure various views that touch and alter data. django-admin2 is a complete rewrite of that library using modern Class-Based Views and enjoying a design focused on extendibility and adaptability. By starting over, we can avoid the legacy code and make it easier to write extensions and themes. + **django-admin2** aims to replace django's built-in admin that lives in -``django.contrib.admin``. Come and help us, have a look at the -:doc:`contributing` page and see our `GitHub`_ page. +``django.contrib.admin``. Come and help us, read the :doc:`design` and +:doc:`contributing` pages, and visit the `GitHub`_ project. This project is intentionally backwards-incompatible with ``django.contrib.admin``. -Requirements +Features ============= -* Django 1.5+ -* Python 2.7+ or Python 3.3+ -* django-braces -* django-extra-views -* django-floppyforms -* django-rest-framework -* Sphinx (for documentation) - +* Rewrite of the Django Admin backend +* Drop-in themes +* Built-in RESTful API Basic API ============== -Our goal is to make this API work: +If you've worked with Django, this implementation should look familiar: .. code-block:: python @@ -56,30 +60,26 @@ Content .. toctree:: :maxdepth: 2 + installation contributing design - architecture - api - themes - built-in-views - meta tutorial Reference ----------- -Most of django-admin2 is designed to be extensible, which means with a little bit of Python code you can do amazing things. You can easily create custom actions, implement alternative forms, set permissions per view, add new views, and even trivially replace the base views with those of your own design. Combined with the REST API, django-admin2 provides a wealth of customization options. - -One of the core design goals of django-admin2 is to embrace object-oriented design, making it easy to take one of the built-in classes and extend it to suit your needs. - .. toctree:: :maxdepth: 2 + ref/themes + ref/api ref/actions ref/forms ref/permissions ref/views + ref/built-in-views + ref/meta Indices and tables ================== diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..05924b4 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,46 @@ +============ +Installation +============ + +Adding django-admin2 to your project +==================================== + + +Use pip to install from PyPI: + +.. code-block:: python + + pip install django-admin2 + +Add djadmin2 and rest_framework to your settings file: + +.. code-block:: python + + INSTALLED_APPS = ( + ... + 'djadmin2', + 'rest_framework', # for the browsable API templates + ... + ) + +Add djadmin2 urls to your URLconf: + +.. code-block:: python + + # urls.py + from django.conf.urls import patterns, include + + import djadmin2 + + djadmin2.default.autodiscover() + + + urlpatterns = patterns( + ... + url(r'^admin2/', include(djadmin2.default.urls)), + ) + +Development Installation +========================= + +See :docs:`contributing`. \ No newline at end of file diff --git a/docs/api.rst b/docs/ref/api.rst similarity index 95% rename from docs/api.rst rename to docs/ref/api.rst index 78ae92c..5ffc930 100644 --- a/docs/api.rst +++ b/docs/ref/api.rst @@ -1,5 +1,5 @@ -API -=== +RESTful API +============= **django-admin2** comes with a builtin REST-API for accessing all the resources you can get from the frontend via JSON. diff --git a/docs/built-in-views.rst b/docs/ref/built-in-views.rst similarity index 100% rename from docs/built-in-views.rst rename to docs/ref/built-in-views.rst diff --git a/docs/meta.rst b/docs/ref/meta.rst similarity index 100% rename from docs/meta.rst rename to docs/ref/meta.rst diff --git a/docs/themes.rst b/docs/ref/themes.rst similarity index 100% rename from docs/themes.rst rename to docs/ref/themes.rst From 2ef846a8fab00e9c0d8c59ea41b5d79be3bf6cc2 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 09:58:47 +0200 Subject: [PATCH 05/58] Index test --- docs/index.rst | 1 - docs/installation.rst | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index e6a0603..4bc32fc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -85,5 +85,4 @@ Indices and tables ================== * :ref:`genindex` -* :ref:`modindex` * :ref:`search` diff --git a/docs/installation.rst b/docs/installation.rst index 05924b4..ac43a3c 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -2,6 +2,8 @@ Installation ============ +.. index:: installation + Adding django-admin2 to your project ==================================== From 9492c8372abd1f7708a15829ed4ca8fc99de822e Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 10:03:54 +0200 Subject: [PATCH 06/58] Indexing actions --- docs/ref/actions.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/ref/actions.rst b/docs/ref/actions.rst index 440b0d1..42eaa8e 100644 --- a/docs/ref/actions.rst +++ b/docs/ref/actions.rst @@ -2,6 +2,8 @@ Actions ======= +.. index:: Actions + Actions are defined to work on a single view type. Currently, actions are only implemented against the ``ModelListView``. This view contains the default ``DeleteSelectedAction`` method, which in end functionality mirrors ``django.contrib.admin.delete_selected``. However, under the hood, django-admin2's actions work very differently. Instead of functions with assigned attributes, they can either be functions or full fledged objects. Which means you can more easily extend them to suit your needs. @@ -39,6 +41,9 @@ The documentation works off a simple set of models, as listed below: Writing List Actions ----------------------- +.. index:: + single: Actions; Writing List Actions + The basic workflow of Django’s admin is, in a nutshell, “select an object, then change it.” This works well for a majority of use cases. However, if you need to make the same change to many objects at once, this workflow can be quite tedious. In these cases, Django’s admin lets you write and register “actions” – simple functions that get called with a list of objects selected on the change list page. From 807b3776fb7cea0d44507bce8ac4fc374c024740 Mon Sep 17 00:00:00 2001 From: Audrey Roy Date: Sat, 6 Jul 2013 10:57:00 +0200 Subject: [PATCH 07/58] Better example project home. Close #241. --- example/blog/templates/base.html | 30 ++++++++++++++++ example/blog/templates/blog/home.html | 50 ++++++++++++++++++++++---- example/example/settings.py | 4 +++ example/static/img/admin.png | Bin 0 -> 56205 bytes example/static/img/admin2.png | Bin 0 -> 56140 bytes 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 example/blog/templates/base.html create mode 100644 example/static/img/admin.png create mode 100644 example/static/img/admin2.png diff --git a/example/blog/templates/base.html b/example/blog/templates/base.html new file mode 100644 index 0000000..62f9c02 --- /dev/null +++ b/example/blog/templates/base.html @@ -0,0 +1,30 @@ +{% load i18n %} + + + + + Example.com + + + {% block css %} + + + {% endblock css %} + + +
+
+
+

+
+
+ {% block content %}{% endblock content %} +
+ + {% block javascript %} + + + + {% endblock javascript %} + + diff --git a/example/blog/templates/blog/home.html b/example/blog/templates/blog/home.html index 8609179..9a765c0 100644 --- a/example/blog/templates/blog/home.html +++ b/example/blog/templates/blog/home.html @@ -1,10 +1,48 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "base.html" %} +{% load staticfiles %} {% block content %} -

Example Home

+
+
+

Example.com

- +

Imagine that this is a real site

+ +

Pretend that this is the homepage of a big Django site.

+ +

Imagine lots of things are here:

+
    +
  • A blog
  • +
  • Comments
  • +
  • And so on...
  • +
+ +

In other words, these are items that we can introspect through the Django admin.

+ +

Under the hood

+ +

Now, explore the Django admin for example.com. Click on either of the following:

+
+
+ +
+
+

The original Django Admin

+ + + + + +

Powered by django.contrib.admin. This is just here for reference.

+
+
+

The new Admin2

+ + + + + +

Powered by django-admin2.

+
+
{% endblock %} \ No newline at end of file diff --git a/example/example/settings.py b/example/example/settings.py index 6d91c87..62c669e 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -1,4 +1,7 @@ # Django settings for example project. +import os + +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) DEBUG = True TEMPLATE_DEBUG = DEBUG @@ -67,6 +70,7 @@ STATICFILES_DIRS = ( # Put strings here, like "/home/html/static" or "C:/www/django/static". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. + os.path.join(BASE_DIR, "static"), ) # List of finder classes that know how to find static files in diff --git a/example/static/img/admin.png b/example/static/img/admin.png new file mode 100644 index 0000000000000000000000000000000000000000..da0ac0b628a579dc9716e4c0bec3e56d1d5a83c8 GIT binary patch literal 56205 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 EU!GtK1^@s6 literal 0 HcmV?d00001 diff --git a/example/static/img/admin2.png b/example/static/img/admin2.png new file mode 100644 index 0000000000000000000000000000000000000000..2424370dd1187d97db24206b7cbc590b171c1823 GIT binary patch literal 56140 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 literal 0 HcmV?d00001 From 1bea34ac1a0e35c64ed624f94c5505ee76bba9ea Mon Sep 17 00:00:00 2001 From: Ignasi Fosch Date: Sat, 6 Jul 2013 11:00:03 +0200 Subject: [PATCH 08/58] djadmin2.actions.get_description test implemented --- djadmin2/actions.py | 13 +++++++++---- djadmin2/tests/test_core.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index 71ae643..fc47c4f 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -11,8 +11,10 @@ from .viewmixins import AdminModel2Mixin def get_description(action): if hasattr(action, 'description'): + # This is for classes return action.description else: + # This if for functions return capfirst(action.__name__.replace('_', ' ')) @@ -20,7 +22,8 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) - empty_message = 'Items must be selected in order to perform actions on them. No items have been changed.' + empty_message = 'Items must be selected in order to perform actions' + empty_message += ' on them. No items have been changed.' success_message = 'Successfully deleted %d %s' queryset = None @@ -102,12 +105,14 @@ class BaseListAction(AdminModel2Mixin, TemplateView): return None else: - # The user has not confirmed that they want to delete the objects, so - # render a template asking for their confirmation. + # The user has not confirmed that they want to delete the + # objects, so render a template asking for their confirmation. return self.get(request) def process_queryset(self): - raise NotImplementedError('Must be provided to do some actions with queryset') + raise NotImplementedError( + 'Must be provided to do some actions with queryset' + ) class DeleteSelectedAction(BaseListAction): diff --git a/djadmin2/tests/test_core.py b/djadmin2/tests/test_core.py index 6828032..1d0b470 100644 --- a/djadmin2/tests/test_core.py +++ b/djadmin2/tests/test_core.py @@ -4,12 +4,21 @@ from django.test import TestCase from ..types import ModelAdmin2 from ..core import Admin2 +from ..actions import get_description class Thing(models.Model): pass +class TestAction(object): + description = "Test Action Class" + + +def test_function(): + pass + + class Admin2Test(TestCase): def setUp(self): self.admin2 = Admin2() @@ -33,3 +42,28 @@ class Admin2Test(TestCase): def test_get_urls(self): self.admin2.register(Thing) self.assertEquals(8, len(self.admin2.get_urls())) + + def test_action_description(self): + self.admin2.register(Thing) + self.admin2.registry[Thing].list_actions.extend([ + TestAction, + test_function + ]) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[0] + ), + 'Delete selected items' + ) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[1] + ), + 'Test Action Class' + ) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[2] + ), + 'Test function' + ) From 9e8efcd2189fcbd33c7807b00e2e45aea2cffeec Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 11:08:11 +0200 Subject: [PATCH 09/58] Add django-debug-toolbar to example2 --- example2/example2/settings.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/example2/example2/settings.py b/example2/example2/settings.py index 3b0a275..8ef70aa 100644 --- a/example2/example2/settings.py +++ b/example2/example2/settings.py @@ -155,3 +155,23 @@ LOGGING = { ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/" + +########## TOOLBAR CONFIGURATION +# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation +INSTALLED_APPS += ( + 'debug_toolbar', +) + +# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation +INTERNAL_IPS = ('127.0.0.1',) + +# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation +MIDDLEWARE_CLASSES += ( + 'debug_toolbar.middleware.DebugToolbarMiddleware', +) + +DEBUG_TOOLBAR_CONFIG = { + 'INTERCEPT_REDIRECTS': False, + 'SHOW_TEMPLATE_CONTEXT': True, +} +########## END TOOLBAR CONFIGURATION From 19e2bac4453ad425b1323307ca09ea90952533e3 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 08:13:51 +0200 Subject: [PATCH 10/58] Update AUTHORS.rst --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 41f2b2e..4dbadf8 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -28,3 +28,4 @@ Developers * Ethan Soergel (@esoergel / ) * Ryan Balfanz (@RyanBalfanz / ) * Tom Christie (@tomchristie) +* Chris Jones (@chrisjones-brack3t / ) From 4f904e73fd6c4de8d0923bb48d73eb35f4b4ecc5 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 09:37:25 +0200 Subject: [PATCH 11/58] PEP8 --- djadmin2/actions.py | 4 ++-- djadmin2/core.py | 12 +++++------- djadmin2/forms.py | 14 ++++++++------ djadmin2/utils.py | 1 + djadmin2/views.py | 16 +++++++--------- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index fc47c4f..446e9d7 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -22,8 +22,8 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) - empty_message = 'Items must be selected in order to perform actions' - empty_message += ' on them. No items have been changed.' + empty_message = 'Items must be selected in order to perform actions ' + \ + 'on them. No items have been changed.' success_message = 'Successfully deleted %d %s' queryset = None diff --git a/djadmin2/core.py b/djadmin2/core.py index 46a01e9..8068509 100644 --- a/djadmin2/core.py +++ b/djadmin2/core.py @@ -124,7 +124,7 @@ class Admin2(object): url(regex=r'^$', view=self.index_view.as_view(**self.get_index_kwargs()), name='dashboard' - ), + ), url(regex='^auth/user/(?P\d+)/update/password/$', view=views.PasswordChangeView.as_view(), name='password_change' @@ -137,16 +137,14 @@ class Admin2(object): view=views.LogoutView.as_view(), name='logout' ), - url( - regex=r'^(?P\w+)/$', + url(regex=r'^(?P\w+)/$', view=self.app_index_view.as_view(**self.get_app_index_kwargs()), name='app_index' - ), - url( - regex=r'^api/v0/$', + ), + url(regex=r'^api/v0/$', view=self.api_index_view.as_view(**self.get_api_index_kwargs()), name='api_index' - ), + ), ) for model, model_admin in self.registry.iteritems(): diff --git a/djadmin2/forms.py b/djadmin2/forms.py index 719e9c2..b0cb5e9 100644 --- a/djadmin2/forms.py +++ b/djadmin2/forms.py @@ -2,9 +2,8 @@ from __future__ import unicode_literals from copy import deepcopy from django.contrib.auth import authenticate -from django.contrib.auth.forms import ( - AuthenticationForm, UserCreationForm, UserChangeForm - ) +from django.contrib.auth.forms import AuthenticationForm +from django.contrib.auth.forms import UserCreationForm, UserChangeForm import django.forms import django.forms.models import django.forms.extras.widgets @@ -225,7 +224,7 @@ def floppify_form(form_class): def modelform_factory(model, form=django.forms.models.ModelForm, fields=None, - exclude=None, formfield_callback=None, widgets=None): + exclude=None, formfield_callback=None, widgets=None): form_class = django.forms.models.modelform_factory( model=model, form=form, @@ -246,8 +245,11 @@ class AdminAuthenticationForm(AuthenticationForm): Liberally copied from django.contrib.admin.forms.AdminAuthenticationForm """ - this_is_the_login_form = django.forms.BooleanField(widget=floppyforms.HiddenInput, initial=1, - error_messages={'required': ugettext_lazy("Please log in again, because your session has expired.")}) + error_messages = { + 'required': ugettext_lazy("Please log in again, because your session has expired."), + } + this_is_the_login_form = django.forms.BooleanField(widget=floppyforms.HiddenInput, + initial=1, error_messages=error_messages) def clean(self): username = self.cleaned_data.get('username') diff --git a/djadmin2/utils.py b/djadmin2/utils.py index 3f4256e..fd63458 100644 --- a/djadmin2/utils.py +++ b/djadmin2/utils.py @@ -22,6 +22,7 @@ def lookup_needs_distinct(opts, lookup_path): return True return False + def model_options(model): """ Wrapper for accessing model._meta. If this access point changes in core diff --git a/djadmin2/views.py b/djadmin2/views.py index 990f5c1..fb08700 100644 --- a/djadmin2/views.py +++ b/djadmin2/views.py @@ -20,21 +20,19 @@ from .viewmixins import Admin2Mixin, AdminModel2Mixin, Admin2ModelFormMixin class IndexView(Admin2Mixin, generic.TemplateView): - """ -Context Variables - - :apps: A dictionary of apps, each app being a dictionary with keys - being models and the value being djadmin2.types.ModelAdmin2 - objects. - - :request.user: The user object representing the current user. + """Context Variables + + :apps: A dictionary of apps, each app being a dictionary with keys + being models and the value being djadmin2.types.ModelAdmin2 + objects. + :request.user: The user object representing the current user. + """ default_template_name = "index.html" registry = None apps = None def get_context_data(self, **kwargs): - data = super(IndexView, self).get_context_data(**kwargs) data.update({ 'apps': self.apps, From 9fad9ff9d12c9ee2b51009fa50d310982361de7d Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 09:53:24 +0200 Subject: [PATCH 12/58] Add Danilo Bargen to authors --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 4dbadf8..e18cfac 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -29,3 +29,4 @@ Developers * Ryan Balfanz (@RyanBalfanz / ) * Tom Christie (@tomchristie) * Chris Jones (@chrisjones-brack3t / ) +* Danilo Bargen (@dbrgn) From f65d7e37228b76618f7b63ac426646ccd7399e4d Mon Sep 17 00:00:00 2001 From: Audrey Roy Date: Sat, 6 Jul 2013 09:55:06 +0200 Subject: [PATCH 13/58] Simpler way to pull upstream changes, with optional rebase for advanced git users. --- docs/contributing.rst | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 1e8df25..36509ce 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -27,7 +27,7 @@ Local Installation 1. Create a virtualenv_ (or use virtualenvwrapper_). Activate it. 2. cd into django-admin2 3. type ``$ pip install -r requirements.txt`` -4. type ``$ python setup.py develop`` +4. type ``$ python setup.py develop`` Try the example projects -------------------------- @@ -37,7 +37,7 @@ Try the example projects 3. run the dev server: ``$ python manage.py runserver`` .. _virtualenv: http://www.virtualenv.org/en/latest/ -.. _virtualenvwrapper: http://virtualenvwrapper.readthedocs.org/en/latest/ +.. _virtualenvwrapper: http://virtualenvwrapper.readthedocs.org/en/latest/ Issues! ======= @@ -61,7 +61,7 @@ Setting up topic branches and generating pull requests While it's handy to provide useful code snippets in an issue, it is better for you as a developer to submit pull requests. By submitting pull request your -contribution to django-admin2 will be recorded by Github. +contribution to django-admin2 will be recorded by Github. In git it is best to isolate each topic or feature into a "topic branch". While individual commits allow you control over how small individual changes are made @@ -113,23 +113,24 @@ add a comment to the discussion section of the pull request. Pull upstream changes into your fork regularly ================================================== -**django-admin2** is advancing quickly. It is therefore critical that you pull upstream changes from master into your fork on a regular basis. Nothing is worse than putting in a day of hard work into a pull request only to have it rejected because it has diverged too far from master. +**django-admin2** is advancing quickly. It is therefore critical that you pull upstream changes from master into your fork on a regular basis. Nothing is worse than putting in a day of hard work into a pull request only to have it rejected because it has diverged too far from master. To pull in upstream changes:: git remote add upstream https://github.com/twoscoops/django-admin2.git - git fetch upstream develop - -Check the log to be sure that you actually want the changes, before merging:: - - git log upstream/develop - -Then merge the changes that you fetched:: - - git merge upstream/develop + git pull upstream develop For more info, see http://help.github.com/fork-a-repo/ +Advanced git users: Pull with rebase +------------------------------------ + +This will pull and then reapply your work on top of the upcoming changes:: + + git pull --rebase upstream develop + +It saves you from an extra merge, keeping the history cleaner, but it's potentially dangerous because you're rewriting history. For more info, see http://gitready.com/advanced/2009/02/11/pull-with-rebase.html + How to get your pull request accepted ===================================== @@ -207,7 +208,7 @@ As much as possible, we follow the advice of the `Two Scoops of Django`_ book. P Templates ~~~~~~~~~ -Follow bootstrap's coding standards for HTML_ and CSS_. Use two spaces for indentation, and write so the templates are readable (not for the generated html). +Follow bootstrap's coding standards for HTML_ and CSS_. Use two spaces for indentation, and write so the templates are readable (not for the generated html). .. _HTML: https://github.com/twitter/bootstrap/blob/master/CONTRIBUTING.md#coding-standards-html .. _CSS: https://github.com/twitter/bootstrap/blob/master/CONTRIBUTING.md#coding-standards-css From 7e0a676ad9c3635245201d1df954cd8401d9c113 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 09:55:29 +0200 Subject: [PATCH 14/58] fix #234, this adds formal install instructions to the docs and includes reorganization of the docs --- README.rst | 4 +-- docs/architecture.rst | 22 --------------- docs/conf.py | 7 +++-- docs/index.rst | 42 ++++++++++++++-------------- docs/installation.rst | 46 +++++++++++++++++++++++++++++++ docs/{ => ref}/api.rst | 4 +-- docs/{ => ref}/built-in-views.rst | 0 docs/{ => ref}/meta.rst | 0 docs/{ => ref}/themes.rst | 0 9 files changed, 74 insertions(+), 51 deletions(-) delete mode 100644 docs/architecture.rst create mode 100644 docs/installation.rst rename docs/{ => ref}/api.rst (95%) rename docs/{ => ref}/built-in-views.rst (100%) rename docs/{ => ref}/meta.rst (100%) rename docs/{ => ref}/themes.rst (100%) diff --git a/README.rst b/README.rst index f3e3ed3..463f5d8 100644 --- a/README.rst +++ b/README.rst @@ -52,6 +52,7 @@ Requirements Installation ============ + Use pip to install from PyPI: .. code-block:: python @@ -85,9 +86,6 @@ Add djadmin2 urls to your URLconf: ... url(r'^admin2/', include(djadmin2.default.urls)), ) - - - How to write django-admin2 modules diff --git a/docs/architecture.rst b/docs/architecture.rst deleted file mode 100644 index d349c9b..0000000 --- a/docs/architecture.rst +++ /dev/null @@ -1,22 +0,0 @@ -================ -Architecture -================ - -.. warning:: This is out of date and will be updated shortly. - -Workflow Pieces ----------------- - -* Apps -* Apps.models -* AdminObj -* Appstore - -Workflow ----------------- - -1. Instantiate Appstore -2. Loop through the Apps then models per App -3. Admin2s are created from models: djadmin2.models.register(Poll) -4. Admin2s contain methods/properties necessaey for UI -5. Views diff --git a/docs/conf.py b/docs/conf.py index d843649..afa2358 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,7 +11,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. -import sys, os +import os +import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -62,9 +63,9 @@ copyright = u'2013, Daniel Greenfeld' # built documents. # # The short X.Y version. -version = '0.4' +version = '0.5' # The full version, including alpha/beta/rc tags. -release = '0.4.0' +release = '0.5.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/index.rst b/docs/index.rst index 4864518..e6a0603 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,29 +1,33 @@ +========================================= Welcome to django-admin2's documentation! ========================================= +.. image:: https://travis-ci.org/pydanny/django-admin2.png + :alt: Build Status + :target: https://travis-ci.org/pydanny/django-admin2 + +**Warning:** This project is currently in an **alpha** state and currently not meant for real projects. + +One of the most useful parts of ``django.contrib.admin`` is the ability to configure various views that touch and alter data. django-admin2 is a complete rewrite of that library using modern Class-Based Views and enjoying a design focused on extendibility and adaptability. By starting over, we can avoid the legacy code and make it easier to write extensions and themes. + **django-admin2** aims to replace django's built-in admin that lives in -``django.contrib.admin``. Come and help us, have a look at the -:doc:`contributing` page and see our `GitHub`_ page. +``django.contrib.admin``. Come and help us, read the :doc:`design` and +:doc:`contributing` pages, and visit the `GitHub`_ project. This project is intentionally backwards-incompatible with ``django.contrib.admin``. -Requirements +Features ============= -* Django 1.5+ -* Python 2.7+ or Python 3.3+ -* django-braces -* django-extra-views -* django-floppyforms -* django-rest-framework -* Sphinx (for documentation) - +* Rewrite of the Django Admin backend +* Drop-in themes +* Built-in RESTful API Basic API ============== -Our goal is to make this API work: +If you've worked with Django, this implementation should look familiar: .. code-block:: python @@ -56,30 +60,26 @@ Content .. toctree:: :maxdepth: 2 + installation contributing design - architecture - api - themes - built-in-views - meta tutorial Reference ----------- -Most of django-admin2 is designed to be extensible, which means with a little bit of Python code you can do amazing things. You can easily create custom actions, implement alternative forms, set permissions per view, add new views, and even trivially replace the base views with those of your own design. Combined with the REST API, django-admin2 provides a wealth of customization options. - -One of the core design goals of django-admin2 is to embrace object-oriented design, making it easy to take one of the built-in classes and extend it to suit your needs. - .. toctree:: :maxdepth: 2 + ref/themes + ref/api ref/actions ref/forms ref/permissions ref/views + ref/built-in-views + ref/meta Indices and tables ================== diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..05924b4 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,46 @@ +============ +Installation +============ + +Adding django-admin2 to your project +==================================== + + +Use pip to install from PyPI: + +.. code-block:: python + + pip install django-admin2 + +Add djadmin2 and rest_framework to your settings file: + +.. code-block:: python + + INSTALLED_APPS = ( + ... + 'djadmin2', + 'rest_framework', # for the browsable API templates + ... + ) + +Add djadmin2 urls to your URLconf: + +.. code-block:: python + + # urls.py + from django.conf.urls import patterns, include + + import djadmin2 + + djadmin2.default.autodiscover() + + + urlpatterns = patterns( + ... + url(r'^admin2/', include(djadmin2.default.urls)), + ) + +Development Installation +========================= + +See :docs:`contributing`. \ No newline at end of file diff --git a/docs/api.rst b/docs/ref/api.rst similarity index 95% rename from docs/api.rst rename to docs/ref/api.rst index 78ae92c..5ffc930 100644 --- a/docs/api.rst +++ b/docs/ref/api.rst @@ -1,5 +1,5 @@ -API -=== +RESTful API +============= **django-admin2** comes with a builtin REST-API for accessing all the resources you can get from the frontend via JSON. diff --git a/docs/built-in-views.rst b/docs/ref/built-in-views.rst similarity index 100% rename from docs/built-in-views.rst rename to docs/ref/built-in-views.rst diff --git a/docs/meta.rst b/docs/ref/meta.rst similarity index 100% rename from docs/meta.rst rename to docs/ref/meta.rst diff --git a/docs/themes.rst b/docs/ref/themes.rst similarity index 100% rename from docs/themes.rst rename to docs/ref/themes.rst From 7e96b27c5fd29d99a0abb7a35ecc2c3d7912e314 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 09:58:47 +0200 Subject: [PATCH 15/58] Index test --- docs/index.rst | 1 - docs/installation.rst | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index e6a0603..4bc32fc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -85,5 +85,4 @@ Indices and tables ================== * :ref:`genindex` -* :ref:`modindex` * :ref:`search` diff --git a/docs/installation.rst b/docs/installation.rst index 05924b4..ac43a3c 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -2,6 +2,8 @@ Installation ============ +.. index:: installation + Adding django-admin2 to your project ==================================== From 80aa636e82713349b3ad981145aebb2c48729ba9 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 10:03:54 +0200 Subject: [PATCH 16/58] Indexing actions --- docs/ref/actions.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/ref/actions.rst b/docs/ref/actions.rst index 440b0d1..42eaa8e 100644 --- a/docs/ref/actions.rst +++ b/docs/ref/actions.rst @@ -2,6 +2,8 @@ Actions ======= +.. index:: Actions + Actions are defined to work on a single view type. Currently, actions are only implemented against the ``ModelListView``. This view contains the default ``DeleteSelectedAction`` method, which in end functionality mirrors ``django.contrib.admin.delete_selected``. However, under the hood, django-admin2's actions work very differently. Instead of functions with assigned attributes, they can either be functions or full fledged objects. Which means you can more easily extend them to suit your needs. @@ -39,6 +41,9 @@ The documentation works off a simple set of models, as listed below: Writing List Actions ----------------------- +.. index:: + single: Actions; Writing List Actions + The basic workflow of Django’s admin is, in a nutshell, “select an object, then change it.” This works well for a majority of use cases. However, if you need to make the same change to many objects at once, this workflow can be quite tedious. In these cases, Django’s admin lets you write and register “actions” – simple functions that get called with a list of objects selected on the change list page. From 1a860031eee955984b6d26759607739f41b5f112 Mon Sep 17 00:00:00 2001 From: Audrey Roy Date: Sat, 6 Jul 2013 10:57:00 +0200 Subject: [PATCH 17/58] Better example project home. Close #241. --- example/blog/templates/base.html | 30 ++++++++++++++++ example/blog/templates/blog/home.html | 50 ++++++++++++++++++++++---- example/example/settings.py | 4 +++ example/static/img/admin.png | Bin 0 -> 56205 bytes example/static/img/admin2.png | Bin 0 -> 56140 bytes 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 example/blog/templates/base.html create mode 100644 example/static/img/admin.png create mode 100644 example/static/img/admin2.png diff --git a/example/blog/templates/base.html b/example/blog/templates/base.html new file mode 100644 index 0000000..62f9c02 --- /dev/null +++ b/example/blog/templates/base.html @@ -0,0 +1,30 @@ +{% load i18n %} + + + + + Example.com + + + {% block css %} + + + {% endblock css %} + + +
+
+
+

+
+
+ {% block content %}{% endblock content %} +
+ + {% block javascript %} + + + + {% endblock javascript %} + + diff --git a/example/blog/templates/blog/home.html b/example/blog/templates/blog/home.html index 8609179..9a765c0 100644 --- a/example/blog/templates/blog/home.html +++ b/example/blog/templates/blog/home.html @@ -1,10 +1,48 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "base.html" %} +{% load staticfiles %} {% block content %} -

Example Home

+
+ +
+
+

The original Django Admin

+ + + + + +

Powered by django.contrib.admin. This is just here for reference.

+
+
+

The new Admin2

+ + + + + +

Powered by django-admin2.

+
+
{% endblock %} \ No newline at end of file diff --git a/example/example/settings.py b/example/example/settings.py index 6d91c87..62c669e 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -1,4 +1,7 @@ # Django settings for example project. +import os + +BASE_DIR = os.path.dirname(os.path.dirname(__file__)) DEBUG = True TEMPLATE_DEBUG = DEBUG @@ -67,6 +70,7 @@ STATICFILES_DIRS = ( # Put strings here, like "/home/html/static" or "C:/www/django/static". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. + os.path.join(BASE_DIR, "static"), ) # List of finder classes that know how to find static files in diff --git a/example/static/img/admin.png b/example/static/img/admin.png new file mode 100644 index 0000000000000000000000000000000000000000..da0ac0b628a579dc9716e4c0bec3e56d1d5a83c8 GIT binary patch literal 56205 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 EU!GtK1^@s6 literal 0 HcmV?d00001 diff --git a/example/static/img/admin2.png b/example/static/img/admin2.png new file mode 100644 index 0000000000000000000000000000000000000000..2424370dd1187d97db24206b7cbc590b171c1823 GIT binary patch literal 56140 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 literal 0 HcmV?d00001 From 745f2750fa64eb8a0a94fa02bf9a94c756095620 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 11:08:11 +0200 Subject: [PATCH 18/58] Add django-debug-toolbar to example2 --- example2/example2/settings.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/example2/example2/settings.py b/example2/example2/settings.py index 3b0a275..8ef70aa 100644 --- a/example2/example2/settings.py +++ b/example2/example2/settings.py @@ -155,3 +155,23 @@ LOGGING = { ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/" + +########## TOOLBAR CONFIGURATION +# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation +INSTALLED_APPS += ( + 'debug_toolbar', +) + +# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation +INTERNAL_IPS = ('127.0.0.1',) + +# See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation +MIDDLEWARE_CLASSES += ( + 'debug_toolbar.middleware.DebugToolbarMiddleware', +) + +DEBUG_TOOLBAR_CONFIG = { + 'INTERCEPT_REDIRECTS': False, + 'SHOW_TEMPLATE_CONTEXT': True, +} +########## END TOOLBAR CONFIGURATION From 793cec78285848497df73a07dae7928b79aac162 Mon Sep 17 00:00:00 2001 From: Ignasi Fosch Date: Sat, 6 Jul 2013 11:16:13 +0200 Subject: [PATCH 19/58] djadmins.actions lines cut out to 80 characters long --- djadmin2/actions.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index 446e9d7..e7fa9ee 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -22,8 +22,13 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) +<<<<<<< HEAD empty_message = 'Items must be selected in order to perform actions ' + \ 'on them. No items have been changed.' +======= + empty_message = 'Items must be selected in order to perform actions on ' +\ + 'them. No items have been changed.' +>>>>>>> djadmin2.actions.get_description test implemented success_message = 'Successfully deleted %d %s' queryset = None From 7c6f6a7b4ab9e15d6c7192267de64aa8cf5a75e6 Mon Sep 17 00:00:00 2001 From: Ignasi Fosch Date: Sat, 6 Jul 2013 11:17:12 +0200 Subject: [PATCH 20/58] djadmins.actions lines cut out to 80 characters long --- djadmin2/actions.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index e7fa9ee..446e9d7 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -22,13 +22,8 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) -<<<<<<< HEAD empty_message = 'Items must be selected in order to perform actions ' + \ 'on them. No items have been changed.' -======= - empty_message = 'Items must be selected in order to perform actions on ' +\ - 'them. No items have been changed.' ->>>>>>> djadmin2.actions.get_description test implemented success_message = 'Successfully deleted %d %s' queryset = None From 3796d312e30406114c35333fe0b773d68cc5b721 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 11:18:38 +0200 Subject: [PATCH 21/58] Add index links for permissions --- docs/ref/permissions.rst | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/ref/permissions.rst b/docs/ref/permissions.rst index 4d0b106..5b11403 100644 --- a/docs/ref/permissions.rst +++ b/docs/ref/permissions.rst @@ -1,6 +1,8 @@ Permissions =========== +.. index:: Permissions + Permissions are handled on a per view basis. So basically each admin view can hold its own permissions. That way you are very flexible in defining who is allowed to access which view. For example, the edit view might need some @@ -28,8 +30,11 @@ attribute: See the following sections on which permission classes ship with **django-admin2**, ready to use and how you can roll your own. -Builtin permission classes --------------------------- +Built-in permission classes +--------------------------- + +.. index:: + single: Permissions; Built-In Permission Classes You can use the following permission classes directly in you views. @@ -48,6 +53,9 @@ You can use the following permission classes directly in you views. Writing your own permission class --------------------------------- +.. index:: + single: Permissions; Custom Permission Classes + If you need it, writing your own permission class is really easy. You just need to subclass the :class:`djadmin2.permissions.BasePermission` class and overwrite the :meth:`~djadmin2.permissions.BasePermission.has_permission` @@ -89,9 +97,12 @@ Here is an example implementation of a custom permission class: return False return True -Permissions in templates +Permissions in Templates ------------------------ +.. index:: + single: Permissions; Permissions in Templates + Since the permission handling is designed around views, the permission checks in the template will also always access a view and return either ``True`` or ``False`` if the user has access to the given view. There is a ``{{ permissions @@ -128,9 +139,12 @@ At the moment we can check for the following four basic permissions: ``has_delete_permission`` This will check the permissions against the current admin's ``delete_view``. -Object-level permissions +Object-Level Permissions ~~~~~~~~~~~~~~~~~~~~~~~~ +.. index:: + single: Permissions; Object-Level Permissions + The permission handling in templates also support checking for object-level permissions. To do so, you can use the ``for_object`` filter implemented in the ``admin2_tags`` templatetag library: @@ -181,9 +195,12 @@ permissions as well: {% include "list_of_model_actions.html" with permissions=object_permissions %} {% endwith %} -Checking for permissions on other models +Checking for Permissions on Other Models ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. index:: + single: Permissions; Checking for Permissions on Other Models + Sometimes you just need to check the permissions for that particular model. In that case, you can access its permissions like this: @@ -214,9 +231,12 @@ to a model admin, you can use the ``for_admin`` filter: {% endwith %} {% endfor %} -Dynamically check for a specific permission name +Dynamically Check for a Specific Permission Name ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. index:: + single: Permissions; Dynamically Check for a Specific Permission Name + Just like you can bind a permission dynamically to a model admin, you can also specify the actual permission name on the fly. There is the ``for_view`` filter to do so. From 56b26fb190cd11db05e332bf7677244799dc5624 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 11:14:06 +0200 Subject: [PATCH 22/58] Added new template filter: model_field_verbose_name --- djadmin2/templatetags/admin2_tags.py | 8 ++++++++ djadmin2/tests/test_admin2tags.py | 15 +++++++++++++++ djadmin2/tests/test_utils.py | 15 +++++++++++++++ djadmin2/utils.py | 17 +++++++++++++---- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/djadmin2/templatetags/admin2_tags.py b/djadmin2/templatetags/admin2_tags.py index b54756c..aaf8ff4 100644 --- a/djadmin2/templatetags/admin2_tags.py +++ b/djadmin2/templatetags/admin2_tags.py @@ -37,6 +37,14 @@ def model_verbose_name_plural(obj): return utils.model_verbose_name_plural(obj) +@register.filter +def model_field_verbose_name(obj, field_name): + """ + Returns the verbose name of a model field. + """ + return utils.model_field_verbose_name(obj, field_name) + + @register.filter def formset_visible_fieldlist(formset): """ diff --git a/djadmin2/tests/test_admin2tags.py b/djadmin2/tests/test_admin2tags.py index b51bb87..a0187e0 100644 --- a/djadmin2/tests/test_admin2tags.py +++ b/djadmin2/tests/test_admin2tags.py @@ -9,6 +9,9 @@ from ..views import IndexView class TagsTestsModel(models.Model): + field1 = models.CharField(max_length=23) + field2 = models.CharField('second field', max_length=42) + class Meta: verbose_name = "Tags Test Model" verbose_name_plural = "Tags Test Models" @@ -58,6 +61,18 @@ class TagsTests(TestCase): admin2_tags.model_verbose_name_plural(self.instance) ) + def test_model_field_verbose_name_autogenerated(self): + self.assertEquals( + 'field1', + admin2_tags.model_field_verbose_name(self.instance, 'field1') + ) + + def test_model_field_verbose_name_overridden(self): + self.assertEquals( + 'second field', + admin2_tags.model_field_verbose_name(self.instance, 'field2') + ) + def test_formset_visible_fieldlist(self): formset = TagsTestFormSet() self.assertEquals( diff --git a/djadmin2/tests/test_utils.py b/djadmin2/tests/test_utils.py index 2528592..f5f3434 100644 --- a/djadmin2/tests/test_utils.py +++ b/djadmin2/tests/test_utils.py @@ -7,6 +7,9 @@ from ..views import IndexView class UtilsTestModel(models.Model): + field1 = models.CharField(max_length=23) + field2 = models.CharField('second field', max_length=42) + class Meta: verbose_name = "Utils Test Model" verbose_name_plural = "Utils Test Models" @@ -71,6 +74,18 @@ class UtilsTest(TestCase): utils.model_verbose_name_plural(self.instance) ) + def test_model_field_verbose_name_autogenerated(self): + self.assertEquals( + 'field1', + utils.model_field_verbose_name(self.instance, 'field1') + ) + + def test_model_field_verbose_name_overridden(self): + self.assertEquals( + 'second field', + utils.model_field_verbose_name(self.instance, 'field2') + ) + def test_app_label_as_model_class(self): self.assertEquals( UtilsTestModel._meta.app_label, diff --git a/djadmin2/utils.py b/djadmin2/utils.py index fd63458..5aaaeb0 100644 --- a/djadmin2/utils.py +++ b/djadmin2/utils.py @@ -41,18 +41,27 @@ def admin2_urlname(view, action): return 'admin2:%s_%s_%s' % (view.app_label, view.model_name, action) -def model_verbose_name(obj): +def model_verbose_name(model): """ Returns the verbose name of a model instance or class. """ - return model_options(obj).verbose_name + return model_options(model).verbose_name -def model_verbose_name_plural(obj): +def model_verbose_name_plural(model): """ Returns the pluralized verbose name of a model instance or class. """ - return model_options(obj).verbose_name_plural + return model_options(model).verbose_name_plural + + +def model_field_verbose_name(model, field_name): + """ + Returns the verbose name of a model field. + """ + meta = model_options(model) + field = meta.get_field_by_name(field_name)[0] + return field.verbose_name def model_app_label(obj): From 6331b94a81118a89b2510eeef918a5ee5a58363d Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 11:23:26 +0200 Subject: [PATCH 23/58] Added model_method_verbose_name util function --- djadmin2/tests/test_utils.py | 20 ++++++++++++++++++++ djadmin2/utils.py | 12 ++++++++++++ 2 files changed, 32 insertions(+) diff --git a/djadmin2/tests/test_utils.py b/djadmin2/tests/test_utils.py index f5f3434..c4f32c1 100644 --- a/djadmin2/tests/test_utils.py +++ b/djadmin2/tests/test_utils.py @@ -10,6 +10,14 @@ class UtilsTestModel(models.Model): field1 = models.CharField(max_length=23) field2 = models.CharField('second field', max_length=42) + def simple_method(self): + return 42 + + def was_published_recently(self): + return True + was_published_recently.boolean = True + was_published_recently.short_description = 'Published recently?' + class Meta: verbose_name = "Utils Test Model" verbose_name_plural = "Utils Test Models" @@ -86,6 +94,18 @@ class UtilsTest(TestCase): utils.model_field_verbose_name(self.instance, 'field2') ) + def test_model_method_verbose_name(self): + self.assertEquals( + 'Published recently?', + utils.model_method_verbose_name(self.instance, 'was_published_recently') + ) + + def test_model_method_verbose_name_fallback(self): + self.assertEquals( + 'simple_method', + utils.model_method_verbose_name(self.instance, 'simple_method') + ) + def test_app_label_as_model_class(self): self.assertEquals( UtilsTestModel._meta.app_label, diff --git a/djadmin2/utils.py b/djadmin2/utils.py index 5aaaeb0..fa34af0 100644 --- a/djadmin2/utils.py +++ b/djadmin2/utils.py @@ -64,6 +64,18 @@ def model_field_verbose_name(model, field_name): return field.verbose_name +def model_method_verbose_name(model, method_name): + """ + Returns the verbose name / short description of a model field. + """ + meta = model_options(model) + method = getattr(model, method_name) + try: + return method.short_description + except AttributeError: + return method_name + + def model_app_label(obj): """ Returns the app label of a model instance or class. From 973996cfe07b357b0c7c657219fdf73e6f825355 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 11:31:19 +0200 Subject: [PATCH 24/58] Show verbose column name in list view (fixes #236) --- djadmin2/templates/admin2/bootstrap/model_list.html | 2 +- example2/example2/settings.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/djadmin2/templates/admin2/bootstrap/model_list.html b/djadmin2/templates/admin2/bootstrap/model_list.html index 9da5db2..e021a68 100644 --- a/djadmin2/templates/admin2/bootstrap/model_list.html +++ b/djadmin2/templates/admin2/bootstrap/model_list.html @@ -71,7 +71,7 @@ {% if forloop.first and attr == "__str__" %} {{ model_name|capfirst }} {% else %} - {{ attr }} + {{ model|model_attr_verbose_name:attr|capfirst }} {% endif%} {% endfor %} diff --git a/example2/example2/settings.py b/example2/example2/settings.py index 8ef70aa..aff938c 100644 --- a/example2/example2/settings.py +++ b/example2/example2/settings.py @@ -122,6 +122,7 @@ INSTALLED_APPS = ( 'rest_framework', 'djadmin2', 'polls', + 'django_extensions', ) # A sample logging configuration. The only tangible logging From 3e31974b39e71b234a93df2c975c6b511d9f3c13 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 11:30:14 +0200 Subject: [PATCH 25/58] Added model_attr_verbose_name template filter. Renamed the model_field_verbose_name to model_attr_verbose_name in order to handle both fields and methods. --- djadmin2/templatetags/admin2_tags.py | 10 +++++++--- djadmin2/tests/test_admin2tags.py | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/djadmin2/templatetags/admin2_tags.py b/djadmin2/templatetags/admin2_tags.py index aaf8ff4..48f45b2 100644 --- a/djadmin2/templatetags/admin2_tags.py +++ b/djadmin2/templatetags/admin2_tags.py @@ -1,4 +1,5 @@ from django import template +from django.db.models.fields import FieldDoesNotExist register = template.Library() @@ -38,11 +39,14 @@ def model_verbose_name_plural(obj): @register.filter -def model_field_verbose_name(obj, field_name): +def model_attr_verbose_name(obj, attr): """ - Returns the verbose name of a model field. + Returns the verbose name of a model field or method. """ - return utils.model_field_verbose_name(obj, field_name) + try: + return utils.model_field_verbose_name(obj, attr) + except FieldDoesNotExist: + return utils.model_method_verbose_name(obj, attr) @register.filter diff --git a/djadmin2/tests/test_admin2tags.py b/djadmin2/tests/test_admin2tags.py index a0187e0..a2c3cfc 100644 --- a/djadmin2/tests/test_admin2tags.py +++ b/djadmin2/tests/test_admin2tags.py @@ -12,6 +12,11 @@ class TagsTestsModel(models.Model): field1 = models.CharField(max_length=23) field2 = models.CharField('second field', max_length=42) + def was_published_recently(self): + return True + was_published_recently.boolean = True + was_published_recently.short_description = 'Published recently?' + class Meta: verbose_name = "Tags Test Model" verbose_name_plural = "Tags Test Models" @@ -64,13 +69,19 @@ class TagsTests(TestCase): def test_model_field_verbose_name_autogenerated(self): self.assertEquals( 'field1', - admin2_tags.model_field_verbose_name(self.instance, 'field1') + admin2_tags.model_attr_verbose_name(self.instance, 'field1') ) def test_model_field_verbose_name_overridden(self): self.assertEquals( 'second field', - admin2_tags.model_field_verbose_name(self.instance, 'field2') + admin2_tags.model_attr_verbose_name(self.instance, 'field2') + ) + + def test_model_method_verbose_name(self): + self.assertEquals( + 'Published recently?', + admin2_tags.model_attr_verbose_name(self.instance, 'was_published_recently') ) def test_formset_visible_fieldlist(self): From fa94f81e7fcb86d05815eaef1e3efaf020b74f99 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 11:36:42 +0200 Subject: [PATCH 26/58] Merge --- djadmin2/actions.py | 14 +++++++++----- djadmin2/tests/test_core.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index 67e15c4..446e9d7 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -11,8 +11,10 @@ from .viewmixins import AdminModel2Mixin def get_description(action): if hasattr(action, 'description'): + # This is for classes return action.description else: + # This if for functions return capfirst(action.__name__.replace('_', ' ')) @@ -20,8 +22,8 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) - empty_message = 'Items must be selected in order to perform actions on them. ' + \ - 'No items have been changed.' + empty_message = 'Items must be selected in order to perform actions ' + \ + 'on them. No items have been changed.' success_message = 'Successfully deleted %d %s' queryset = None @@ -103,12 +105,14 @@ class BaseListAction(AdminModel2Mixin, TemplateView): return None else: - # The user has not confirmed that they want to delete the objects, so - # render a template asking for their confirmation. + # The user has not confirmed that they want to delete the + # objects, so render a template asking for their confirmation. return self.get(request) def process_queryset(self): - raise NotImplementedError('Must be provided to do some actions with queryset') + raise NotImplementedError( + 'Must be provided to do some actions with queryset' + ) class DeleteSelectedAction(BaseListAction): diff --git a/djadmin2/tests/test_core.py b/djadmin2/tests/test_core.py index 6828032..1d0b470 100644 --- a/djadmin2/tests/test_core.py +++ b/djadmin2/tests/test_core.py @@ -4,12 +4,21 @@ from django.test import TestCase from ..types import ModelAdmin2 from ..core import Admin2 +from ..actions import get_description class Thing(models.Model): pass +class TestAction(object): + description = "Test Action Class" + + +def test_function(): + pass + + class Admin2Test(TestCase): def setUp(self): self.admin2 = Admin2() @@ -33,3 +42,28 @@ class Admin2Test(TestCase): def test_get_urls(self): self.admin2.register(Thing) self.assertEquals(8, len(self.admin2.get_urls())) + + def test_action_description(self): + self.admin2.register(Thing) + self.admin2.registry[Thing].list_actions.extend([ + TestAction, + test_function + ]) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[0] + ), + 'Delete selected items' + ) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[1] + ), + 'Test Action Class' + ) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[2] + ), + 'Test function' + ) From ce5566be820603756fa6cb94de1b2f80fe1c599f Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 11:53:46 +0200 Subject: [PATCH 27/58] Show verbose column name in list view (fixes #236) --- djadmin2/templates/admin2/bootstrap/model_list.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djadmin2/templates/admin2/bootstrap/model_list.html b/djadmin2/templates/admin2/bootstrap/model_list.html index 9da5db2..e021a68 100644 --- a/djadmin2/templates/admin2/bootstrap/model_list.html +++ b/djadmin2/templates/admin2/bootstrap/model_list.html @@ -71,7 +71,7 @@ {% if forloop.first and attr == "__str__" %} {{ model_name|capfirst }} {% else %} - {{ attr }} + {{ model|model_attr_verbose_name:attr|capfirst }} {% endif%} {% endfor %} From fd6eec2a543147f89c7168740ffbd43f9679ffab Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 11:56:18 +0200 Subject: [PATCH 28/58] Adding Ignasi Fosch Alonso to Authors --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index e18cfac..c0467ab 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -30,3 +30,4 @@ Developers * Tom Christie (@tomchristie) * Chris Jones (@chrisjones-brack3t / ) * Danilo Bargen (@dbrgn) +* Ignasi Fosch Alonso (@ifosch) From 142f33f2f65e648220696e8da00903b3fb83bd0d Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 11:56:29 +0200 Subject: [PATCH 29/58] Added .coveragerc --- .coveragerc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..d769d17 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,15 @@ +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Don't complain about missing debug-only code: + def __repr__ + if self\.debug + + # Don't complain if tests don't hit defensive assertion code: + raise AssertionError + raise NotImplementedError + + # Don't complain if non-runnable code isn't run: + if 0: + if False: + if __name__ == .__main__.: From 8217789e1184f077b2a4a6b8238346e25a662efb Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 11:57:57 +0200 Subject: [PATCH 30/58] Prepared travis.yml for coveralls --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index f7a3685..9a14417 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,3 +8,6 @@ install: - pip install -r requirements.txt script: - python runtests.py +after_script: + - pip install --quiet --use-mirrors coveralls + - coveralls From d407d804b04c35efcda7783055be8c1b63a67c23 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 12:09:13 +0200 Subject: [PATCH 31/58] Add coverage badge per #222 --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index 463f5d8..ece1fb5 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,9 @@ django-admin2 .. image:: https://travis-ci.org/pydanny/django-admin2.png :alt: Build Status :target: https://travis-ci.org/pydanny/django-admin2 +.. image:: https://coveralls.io/repos/evonove/django-oauth-toolkit/badge.png + :alt: Coverage Status + :target: https://coveralls.io/r/evonove/django-oauth-toolkit One of the most useful parts of ``django.contrib.admin`` is the ability to configure various views that touch and alter data. django-admin2 is a complete rewrite of that library using modern Class-Based Views and enjoying a design focused on extendibility and adaptability. By starting over, we can avoid the legacy code and make it easier to write extensions and themes. From 7db738d4698789a40a14e6725f613cdbb37daade Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 12:21:02 +0200 Subject: [PATCH 32/58] friendlier way of handling django_extensions --- example2/example2/settings.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/example2/example2/settings.py b/example2/example2/settings.py index aff938c..bda779b 100644 --- a/example2/example2/settings.py +++ b/example2/example2/settings.py @@ -122,9 +122,16 @@ INSTALLED_APPS = ( 'rest_framework', 'djadmin2', 'polls', - 'django_extensions', ) +try: + import django_extensions + INSTALLED_APPS += ( + 'django_extensions', + ) +except ImportError: + pass + # A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to # the site admins on every HTTP 500 error when DEBUG=False. From 74573faf7a760b31e5e4e2ff2fa10f9309377dbb Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 12:18:58 +0200 Subject: [PATCH 33/58] Update README.rst --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index ece1fb5..f2f5e9c 100644 --- a/README.rst +++ b/README.rst @@ -5,9 +5,9 @@ django-admin2 .. image:: https://travis-ci.org/pydanny/django-admin2.png :alt: Build Status :target: https://travis-ci.org/pydanny/django-admin2 -.. image:: https://coveralls.io/repos/evonove/django-oauth-toolkit/badge.png +.. image:: https://coveralls.io/repos/twoscoops/django-admin2/badge.png :alt: Coverage Status - :target: https://coveralls.io/r/evonove/django-oauth-toolkit + :target: https://coveralls.io/r/twoscoops/django-admin2 One of the most useful parts of ``django.contrib.admin`` is the ability to configure various views that touch and alter data. django-admin2 is a complete rewrite of that library using modern Class-Based Views and enjoying a design focused on extendibility and adaptability. By starting over, we can avoid the legacy code and make it easier to write extensions and themes. From 3feabdf938e065267c88989313e69da27924b0b1 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 12:23:36 +0200 Subject: [PATCH 34/58] Typo: `:docs:` should be `:doc` --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index ac43a3c..0eb0cb4 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -45,4 +45,4 @@ Add djadmin2 urls to your URLconf: Development Installation ========================= -See :docs:`contributing`. \ No newline at end of file +See :doc:`contributing`. From 5ab4f33b6a25233d96910887b8283982ad04f593 Mon Sep 17 00:00:00 2001 From: NotSqrt Date: Sat, 6 Jul 2013 12:13:36 +0200 Subject: [PATCH 35/58] check i18n completeness --- djadmin2/actions.py | 12 ++++++------ .../actions/delete_selected_confirmation.html | 6 +++--- djadmin2/templates/admin2/bootstrap/app_index.html | 2 +- djadmin2/templates/admin2/bootstrap/auth/login.html | 2 +- djadmin2/templates/admin2/bootstrap/auth/logout.html | 2 +- .../admin2/bootstrap/auth/password_change_done.html | 2 +- .../admin2/bootstrap/auth/password_change_form.html | 4 ++-- djadmin2/templates/admin2/bootstrap/base.html | 8 +++----- .../admin2/bootstrap/model_confirm_delete.html | 2 +- .../templates/admin2/bootstrap/model_detail.html | 2 +- djadmin2/templates/admin2/bootstrap/model_list.html | 10 ++++++---- .../admin2/bootstrap/model_update_form.html | 2 +- djadmin2/views.py | 5 +++-- 13 files changed, 30 insertions(+), 29 deletions(-) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index 446e9d7..628ccf6 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -22,9 +22,9 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) - empty_message = 'Items must be selected in order to perform actions ' + \ - 'on them. No items have been changed.' - success_message = 'Successfully deleted %d %s' + empty_message = _('Items must be selected in order to perform actions ' + 'on them. No items have been changed.') + success_message = _('Successfully deleted %(count)d %(items)s') queryset = None @@ -98,9 +98,9 @@ class BaseListAction(AdminModel2Mixin, TemplateView): if request.POST.get('confirmed'): if self.process_queryset() is None: - message = _(self.success_message % ( - self.item_count, self.objects_name) - ) + message = _(self.success_message % { + 'count': self.item_count, 'items': self.objects_name + }) messages.add_message(request, messages.INFO, message) return None diff --git a/djadmin2/templates/admin2/bootstrap/actions/delete_selected_confirmation.html b/djadmin2/templates/admin2/bootstrap/actions/delete_selected_confirmation.html index e4d0911..fa5d87f 100644 --- a/djadmin2/templates/admin2/bootstrap/actions/delete_selected_confirmation.html +++ b/djadmin2/templates/admin2/bootstrap/actions/delete_selected_confirmation.html @@ -1,13 +1,13 @@ {% extends "admin2/bootstrap/base.html" %} {% load admin2_tags i18n %} -{% block title %}Are you sure?{% endblock title %} +{% block title %}{% trans "Are you sure?" %}{% endblock title %} -{% block page_title %}Are you sure?{% endblock page_title %} +{% block page_title %}{% trans "Are you sure?" %}{% endblock page_title %} {% block breadcrumbs %}
  • diff --git a/djadmin2/templates/admin2/bootstrap/app_index.html b/djadmin2/templates/admin2/bootstrap/app_index.html index fc2be4d..5ed20d4 100644 --- a/djadmin2/templates/admin2/bootstrap/app_index.html +++ b/djadmin2/templates/admin2/bootstrap/app_index.html @@ -3,7 +3,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • {{ app_label|title }}
  • diff --git a/djadmin2/templates/admin2/bootstrap/auth/login.html b/djadmin2/templates/admin2/bootstrap/auth/login.html index 128a9c1..c055c15 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/login.html +++ b/djadmin2/templates/admin2/bootstrap/auth/login.html @@ -12,7 +12,7 @@ {% block breacrumbs %}{% endblock breacrumbs %} {% block class_page_title %}span12 login-title{% endblock class_page_title %} -{% block page_title %}{% trans "Site administration" %} - Login{% endblock page_title %} +{% block page_title %}{% trans "Site administration" %} - {% trans "Login" %}{% endblock page_title %} {% block content %}
    diff --git a/djadmin2/templates/admin2/bootstrap/auth/logout.html b/djadmin2/templates/admin2/bootstrap/auth/logout.html index 25f383f..7da8675 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/logout.html +++ b/djadmin2/templates/admin2/bootstrap/auth/logout.html @@ -5,7 +5,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • {% trans "Logout" %}
  • diff --git a/djadmin2/templates/admin2/bootstrap/auth/password_change_done.html b/djadmin2/templates/admin2/bootstrap/auth/password_change_done.html index 66a45ee..6f1b352 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/password_change_done.html +++ b/djadmin2/templates/admin2/bootstrap/auth/password_change_done.html @@ -8,7 +8,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • {% trans "Password change successful" %}
  • diff --git a/djadmin2/templates/admin2/bootstrap/auth/password_change_form.html b/djadmin2/templates/admin2/bootstrap/auth/password_change_form.html index f49abe7..18d6408 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/password_change_form.html +++ b/djadmin2/templates/admin2/bootstrap/auth/password_change_form.html @@ -7,7 +7,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • {% trans "Password change" %} /
  • @@ -17,7 +17,7 @@ {% block content %}
    -

    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.

    +

    {% trans "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." %}

    {% if form.errors %}

    diff --git a/djadmin2/templates/admin2/bootstrap/base.html b/djadmin2/templates/admin2/bootstrap/base.html index dd2448f..f65acf4 100644 --- a/djadmin2/templates/admin2/bootstrap/base.html +++ b/djadmin2/templates/admin2/bootstrap/base.html @@ -3,7 +3,7 @@ - {% block title %}Site administration{% endblock title %} | django-admin2 + {% block title %}{% trans "Site administration" %}{% endblock title %} | django-admin2 {% block css %} @@ -31,9 +31,7 @@ {% if user.get_full_name %} {{ user.get_full_name }} {% else %} - {% blocktrans with user=user.username %} - Logged in as {{ user }} - {% endblocktrans %} + {% blocktrans with user=user.username %}Logged in as {{ user }}{% endblocktrans %} {% endif %} @@ -54,7 +52,7 @@ {% block breacrumbs %}

    {% endblock breacrumbs %} diff --git a/djadmin2/templates/admin2/bootstrap/model_confirm_delete.html b/djadmin2/templates/admin2/bootstrap/model_confirm_delete.html index 819fd76..8f35b96 100644 --- a/djadmin2/templates/admin2/bootstrap/model_confirm_delete.html +++ b/djadmin2/templates/admin2/bootstrap/model_confirm_delete.html @@ -7,7 +7,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • diff --git a/djadmin2/templates/admin2/bootstrap/model_detail.html b/djadmin2/templates/admin2/bootstrap/model_detail.html index b115fcf..118d01c 100644 --- a/djadmin2/templates/admin2/bootstrap/model_detail.html +++ b/djadmin2/templates/admin2/bootstrap/model_detail.html @@ -8,7 +8,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • diff --git a/djadmin2/templates/admin2/bootstrap/model_list.html b/djadmin2/templates/admin2/bootstrap/model_list.html index e021a68..d5c521a 100644 --- a/djadmin2/templates/admin2/bootstrap/model_list.html +++ b/djadmin2/templates/admin2/bootstrap/model_list.html @@ -11,7 +11,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • @@ -28,8 +28,8 @@
    @@ -55,7 +55,9 @@
  • - 0 of {{ object_list|length }} selected + + {% blocktrans with selected='0' total=object_list|length %}{{selected}} of {{total}} selected{% endblocktrans %} +
    {% if permissions.has_add_permission %} {% blocktrans with model_verbose_name=model|model_verbose_name %}Add {{ model_verbose_name }}{% endblocktrans %} diff --git a/djadmin2/templates/admin2/bootstrap/model_update_form.html b/djadmin2/templates/admin2/bootstrap/model_update_form.html index f9cd750..d5b5825 100644 --- a/djadmin2/templates/admin2/bootstrap/model_update_form.html +++ b/djadmin2/templates/admin2/bootstrap/model_update_form.html @@ -8,7 +8,7 @@ {% block breadcrumbs %}
  • - Home + {% trans "Home" %} /
  • diff --git a/djadmin2/views.py b/djadmin2/views.py index fb08700..70551bf 100644 --- a/djadmin2/views.py +++ b/djadmin2/views.py @@ -4,6 +4,7 @@ from django.contrib.auth.views import (logout as auth_logout, login as auth_login) from django.contrib.auth import get_user_model from django.core.urlresolvers import reverse, reverse_lazy +from django.utils.translation import ugettext_lazy from django.db import models from django.http import HttpResponseRedirect from django.utils.encoding import force_text @@ -161,7 +162,7 @@ class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.Upda def get_context_data(self, **kwargs): context = super(ModelEditFormView, self).get_context_data(**kwargs) context['model'] = self.get_model() - context['action'] = "Change" + context['action'] = ugettext_lazy("Change") return context @@ -175,7 +176,7 @@ class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.Creat def get_context_data(self, **kwargs): context = super(ModelAddFormView, self).get_context_data(**kwargs) context['model'] = self.get_model() - context['action'] = "Add" + context['action'] = ugettext_lazy("Add") return context From 5de843313bed0b38d2959ef9d7fcda0a3a085c05 Mon Sep 17 00:00:00 2001 From: NotSqrt Date: Sat, 6 Jul 2013 12:13:57 +0200 Subject: [PATCH 36/58] make the examples use i18n --- example/example/settings.py | 1 + example2/example2/settings.py | 1 + 2 files changed, 2 insertions(+) diff --git a/example/example/settings.py b/example/example/settings.py index 62c669e..3a05928 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -93,6 +93,7 @@ TEMPLATE_LOADERS = ( MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', + 'django.middleware.locale.LocaleMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', diff --git a/example2/example2/settings.py b/example2/example2/settings.py index bda779b..48859d2 100644 --- a/example2/example2/settings.py +++ b/example2/example2/settings.py @@ -88,6 +88,7 @@ TEMPLATE_LOADERS = ( ) MIDDLEWARE_CLASSES = ( + 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', From 187773979bc0aee59ff2207456d47ac7ac62dce3 Mon Sep 17 00:00:00 2001 From: NotSqrt Date: Sat, 6 Jul 2013 12:28:45 +0200 Subject: [PATCH 37/58] add default english translation, add french translation --- djadmin2/locale/en/LC_MESSAGES/django.po | 244 ++++++++++++++++++++++ djadmin2/locale/fr/LC_MESSAGES/django.po | 248 +++++++++++++++++++++++ 2 files changed, 492 insertions(+) create mode 100644 djadmin2/locale/en/LC_MESSAGES/django.po create mode 100644 djadmin2/locale/fr/LC_MESSAGES/django.po diff --git a/djadmin2/locale/en/LC_MESSAGES/django.po b/djadmin2/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..907181b --- /dev/null +++ b/djadmin2/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,244 @@ +# This file is distributed under the same license as the django-admin2 package. +# +# Translators: +# NotSqrt , 2013. +msgid "" +msgstr "" +"Project-Id-Version: django-admin2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-06 12:25+0200\n" +"PO-Revision-Date: 2013-07-06 12:15+0200\n" +"Last-Translator: NotSqrt \n" +"Language-Team: English \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: actions.py:25 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." + +#: actions.py:27 +#, python-format +msgid "Successfully deleted %(count)d %(items)s" +msgstr "Successfully deleted %(count)d %(items)s" + +#: actions.py:102 +msgid "count" +msgstr "count" + +#: actions.py:125 +msgid "Delete selected items" +msgstr "Delete selected items" + +#: forms.py:238 +#, python-format +msgid "" +"Please enter the correct %(username)s and password for a staff account. Note " +"that both fields may be case-sensitive." +msgstr "" +"Please enter the correct %(username)s and password for a staff account. Note " +"that both fields may be case-sensitive." + +#: forms.py:249 +msgid "Please log in again, because your session has expired." +msgstr "Please log in again, because your session has expired." + +#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 +#: templates/admin2/bootstrap/includes/app_model_list.html:38 +msgid "Change" +msgstr "Change" + +#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +msgid "Add" +msgstr "Add" + +#: templates/admin2/bootstrap/app_index.html:6 +#: templates/admin2/bootstrap/base.html:55 +#: templates/admin2/bootstrap/model_confirm_delete.html:10 +#: templates/admin2/bootstrap/model_detail.html:11 +#: templates/admin2/bootstrap/model_list.html:14 +#: templates/admin2/bootstrap/model_update_form.html:11 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/admin2/bootstrap/auth/logout.html:8 +#: templates/admin2/bootstrap/auth/password_change_done.html:11 +#: templates/admin2/bootstrap/auth/password_change_form.html:10 +msgid "Home" +msgstr "Home" + +#: templates/admin2/bootstrap/app_index.html:12 +#, python-format +msgid "%(app_label)s administration" +msgstr "%(app_label)s administration" + +#: templates/admin2/bootstrap/base.html:6 +#: templates/admin2/bootstrap/base.html:71 +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Site administration" +msgstr "Site administration" + +#: templates/admin2/bootstrap/base.html:22 +msgid "API" +msgstr "API" + +#: templates/admin2/bootstrap/base.html:25 +msgid "Documentation" +msgstr "Documentation" + +#: templates/admin2/bootstrap/base.html:34 +#, python-format +msgid "Logged in as %(user)s" +msgstr "Logged in as %(user)s" + +#: templates/admin2/bootstrap/base.html:40 +msgid "Change password" +msgstr "Change password" + +#: templates/admin2/bootstrap/base.html:42 +msgid "Log out" +msgstr "Log out" + +#: templates/admin2/bootstrap/index.html:13 +msgid "Recent Actions" +msgstr "Recent Actions" + +#: templates/admin2/bootstrap/index.html:14 +msgid "My Actions" +msgstr "My Actions" + +#: templates/admin2/bootstrap/model_confirm_delete.html:4 +#: templates/admin2/bootstrap/model_confirm_delete.html:6 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +msgid "Are you sure?" +msgstr "Are you sure?" + +#: templates/admin2/bootstrap/model_confirm_delete.html:25 +#: templates/admin2/bootstrap/model_update_form.html:74 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +msgid "Delete" +msgstr "Delete" + +#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#, python-format +msgid "" +"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " +"the following items will be deleted:" +msgstr "" +"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " +"the following items will be deleted:" + +#: templates/admin2/bootstrap/model_confirm_delete.html:40 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +msgid "Yes, I'm sure" +msgstr "Yes, I'm sure" + +#: templates/admin2/bootstrap/model_list.html:4 +#: templates/admin2/bootstrap/model_list.html:6 +#, python-format +msgid "Select %(model_name)s to change" +msgstr "Select %(model_name)s to change" + +#: templates/admin2/bootstrap/model_list.html:31 +msgid "Search Term" +msgstr "Search Term" + +#: templates/admin2/bootstrap/model_list.html:32 +msgid "Search" +msgstr "Search" + +#: templates/admin2/bootstrap/model_list.html:59 +#, python-format +msgid "%(selected)s of %(total)s selected" +msgstr "%(selected)s of %(total)s selected" + +#: templates/admin2/bootstrap/model_list.html:63 +#, python-format +msgid "Add %(model_verbose_name)s" +msgstr "Add %(model_verbose_name)s" + +#: templates/admin2/bootstrap/model_update_form.html:5 +#: templates/admin2/bootstrap/model_update_form.html:7 +#, python-format +msgid "%(action)s %(model_name)s" +msgstr "%(action)s %(model_name)s" + +#: templates/admin2/bootstrap/model_update_form.html:78 +msgid "Save and add another" +msgstr "Save and add another" + +#: templates/admin2/bootstrap/model_update_form.html:79 +msgid "Save and continue editing" +msgstr "Save and continue editing" + +#: templates/admin2/bootstrap/model_update_form.html:80 +msgid "Save" +msgstr "Save" + +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following items will be deleted:" +msgstr "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following items will be deleted:" + +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Login" +msgstr "Login" + +#: templates/admin2/bootstrap/auth/login.html:27 +#: templates/admin2/bootstrap/auth/password_change_form.html:24 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Please correct the error below." +msgstr[1] "Please correct the errors below." + +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" +msgstr "Log in" + +#: templates/admin2/bootstrap/auth/logout.html:11 +msgid "Logout" +msgstr "Logout" + +#: templates/admin2/bootstrap/auth/logout.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Thanks for spending some quality time with the Web site today." + +#: templates/admin2/bootstrap/auth/logout.html:18 +msgid "Log in again" +msgstr "Log in again" + +#: templates/admin2/bootstrap/auth/password_change_done.html:6 +#: templates/admin2/bootstrap/auth/password_change_done.html:7 +#: templates/admin2/bootstrap/auth/password_change_done.html:14 +msgid "Password change successful" +msgstr "Password change successful" + +#: templates/admin2/bootstrap/auth/password_change_done.html:20 +msgid "Your password was changed." +msgstr "Your password was changed." + +#: templates/admin2/bootstrap/auth/password_change_form.html:6 +#: templates/admin2/bootstrap/auth/password_change_form.html:13 +msgid "Password change" +msgstr "Password change" + +#: templates/admin2/bootstrap/auth/password_change_form.html:20 +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 "" +"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." + +#: templates/admin2/bootstrap/auth/password_change_form.html:31 +msgid "Change my password" +msgstr "Change my password" diff --git a/djadmin2/locale/fr/LC_MESSAGES/django.po b/djadmin2/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..d96870b --- /dev/null +++ b/djadmin2/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,248 @@ +# This file is distributed under the same license as the django-admin2 package. +# +# Translators: +# NotSqrt , 2013. +msgid "" +msgstr "" +"Project-Id-Version: django-admin2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-06 12:25+0200\n" +"PO-Revision-Date: 2013-07-06 12:15+0200\n" +"Last-Translator: NotSqrt \n" +"Language-Team: French (http://www.transifex.com/projects/p/django-admin2/" +"language/fr/)\n" +"Language: fr\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" + +#: actions.py:25 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" +"Des éléments doivent être sélectionnés afin d'appliquer les actions. Aucun " +"élément n'a été modifié." + +#: actions.py:27 +#, python-format +msgid "Successfully deleted %(count)d %(items)s" +msgstr "La suppression de %(count)d %(items)s a réussi." + +#: actions.py:102 +msgid "count" +msgstr "count" + +#: actions.py:125 +msgid "Delete selected items" +msgstr "Supprimer les objets sélectionnés" + +#: forms.py:238 +#, python-format +msgid "" +"Please enter the correct %(username)s and password for a staff account. Note " +"that both fields may be case-sensitive." +msgstr "" +"Veuillez compléter correctement les champs « %(username)s » et « mot de " +"passe » d'un compte autorisé. Sachez que les deux champs peuvent être " +"sensibles à la casse." + +#: forms.py:249 +msgid "Please log in again, because your session has expired." +msgstr "Reconnectez-vous car votre session a expiré." + +#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 +#: templates/admin2/bootstrap/includes/app_model_list.html:38 +msgid "Change" +msgstr "Modifier" + +#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +msgid "Add" +msgstr "Ajouter" + +#: templates/admin2/bootstrap/app_index.html:6 +#: templates/admin2/bootstrap/base.html:55 +#: templates/admin2/bootstrap/model_confirm_delete.html:10 +#: templates/admin2/bootstrap/model_detail.html:11 +#: templates/admin2/bootstrap/model_list.html:14 +#: templates/admin2/bootstrap/model_update_form.html:11 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/admin2/bootstrap/auth/logout.html:8 +#: templates/admin2/bootstrap/auth/password_change_done.html:11 +#: templates/admin2/bootstrap/auth/password_change_form.html:10 +msgid "Home" +msgstr "Accueil" + +#: templates/admin2/bootstrap/app_index.html:12 +#, python-format +msgid "%(app_label)s administration" +msgstr "Administration de %(app_label)s" + +#: templates/admin2/bootstrap/base.html:6 +#: templates/admin2/bootstrap/base.html:71 +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Site administration" +msgstr "Administration du site" + +#: templates/admin2/bootstrap/base.html:22 +msgid "API" +msgstr "API" + +#: templates/admin2/bootstrap/base.html:25 +msgid "Documentation" +msgstr "Documentation" + +#: templates/admin2/bootstrap/base.html:34 +#, python-format +msgid "Logged in as %(user)s" +msgstr "Connecté en tant que %(user)s" + +#: templates/admin2/bootstrap/base.html:40 +msgid "Change password" +msgstr "Modifier votre mot de passe" + +#: templates/admin2/bootstrap/base.html:42 +msgid "Log out" +msgstr "Déconnexion" + +#: templates/admin2/bootstrap/index.html:13 +msgid "Recent Actions" +msgstr "Actions récentes" + +#: templates/admin2/bootstrap/index.html:14 +msgid "My Actions" +msgstr "Mes actions" + +#: templates/admin2/bootstrap/model_confirm_delete.html:4 +#: templates/admin2/bootstrap/model_confirm_delete.html:6 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +msgid "Are you sure?" +msgstr "Êtes-vous sûr ?" + +#: templates/admin2/bootstrap/model_confirm_delete.html:25 +#: templates/admin2/bootstrap/model_update_form.html:74 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +msgid "Delete" +msgstr "Supprimer" + +#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#, python-format +msgid "" +"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " +"the following items will be deleted:" +msgstr "" +"Voulez-vous vraiment supprimer l'objet %(model_name)s « %(object)s » ? Les " +"éléments suivants seront supprimés :" + +#: templates/admin2/bootstrap/model_confirm_delete.html:40 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +msgid "Yes, I'm sure" +msgstr "Oui, je suis sûr" + +#: templates/admin2/bootstrap/model_list.html:4 +#: templates/admin2/bootstrap/model_list.html:6 +#, python-format +msgid "Select %(model_name)s to change" +msgstr "Sélectionnez l'objet %(model_name)s à modifier" + +#: templates/admin2/bootstrap/model_list.html:31 +msgid "Search Term" +msgstr "Terme à rechercher" + +#: templates/admin2/bootstrap/model_list.html:32 +msgid "Search" +msgstr "Recherche" + +#: templates/admin2/bootstrap/model_list.html:59 +#, python-format +msgid "%(selected)s of %(total)s selected" +msgstr "%(selected)s sur %(total)s sélectionnés" + +#: templates/admin2/bootstrap/model_list.html:63 +#, python-format +msgid "Add %(model_verbose_name)s" +msgstr "Ajouter %(model_verbose_name)s" + +#: templates/admin2/bootstrap/model_update_form.html:5 +#: templates/admin2/bootstrap/model_update_form.html:7 +#, python-format +msgid "%(action)s %(model_name)s" +msgstr "%(action)s %(model_name)s" + +#: templates/admin2/bootstrap/model_update_form.html:78 +msgid "Save and add another" +msgstr "Enregistrer et ajouter un nouveau" + +#: templates/admin2/bootstrap/model_update_form.html:79 +msgid "Save and continue editing" +msgstr "Enregistrer et continuer les modifications" + +#: templates/admin2/bootstrap/model_update_form.html:80 +msgid "Save" +msgstr "Enregistrer" + +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following items will be deleted:" +msgstr "" +"Voulez-vous vraiment supprimer les objets %(objects_name)s sélectionnés ? " +"Les éléments suivants seront supprimés :" + +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Login" +msgstr "Connexion" + +#: templates/admin2/bootstrap/auth/login.html:27 +#: templates/admin2/bootstrap/auth/password_change_form.html:24 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "Corrigez l'erreur suivante." +msgstr[1] "Corrigez les erreurs suivantes." + +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" +msgstr "Connexion" + +#: templates/admin2/bootstrap/auth/logout.html:11 +msgid "Logout" +msgstr "Déconnexion" + +#: templates/admin2/bootstrap/auth/logout.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "Merci pour le temps que vous avez accordé à ce site aujourd'hui." + +#: templates/admin2/bootstrap/auth/logout.html:18 +msgid "Log in again" +msgstr "Connectez-vous à nouveau" + +#: templates/admin2/bootstrap/auth/password_change_done.html:6 +#: templates/admin2/bootstrap/auth/password_change_done.html:7 +#: templates/admin2/bootstrap/auth/password_change_done.html:14 +msgid "Password change successful" +msgstr "Mot de passe modifié avec succès" + +#: templates/admin2/bootstrap/auth/password_change_done.html:20 +msgid "Your password was changed." +msgstr "Votre mot de passe a été modifié." + +#: templates/admin2/bootstrap/auth/password_change_form.html:6 +#: templates/admin2/bootstrap/auth/password_change_form.html:13 +msgid "Password change" +msgstr "Modification de votre mot de passe" + +#: templates/admin2/bootstrap/auth/password_change_form.html:20 +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 "" +"Pour des raisons de sécurité, saisissez votre ancien mot de passe puis votre " +"nouveau mot de passe à deux reprises afin de vérifier qu'il est correctement " +"saisi." + +#: templates/admin2/bootstrap/auth/password_change_form.html:31 +msgid "Change my password" +msgstr "Modifier mon mot de passe" From 5889c5d8491e638805859f1aed75cdfb50332382 Mon Sep 17 00:00:00 2001 From: NotSqrt Date: Sat, 6 Jul 2013 13:29:33 +0200 Subject: [PATCH 38/58] i18n : fixes for tests -> use string interpolation, not positional interpolation --- djadmin2/actions.py | 12 +++++++----- djadmin2/locale/en/LC_MESSAGES/django.po | 18 +++++++----------- djadmin2/locale/fr/LC_MESSAGES/django.po | 18 +++++++----------- .../admin2/bootstrap/model_detail.html | 2 +- example/blog/actions.py | 2 +- 5 files changed, 23 insertions(+), 29 deletions(-) diff --git a/djadmin2/actions.py b/djadmin2/actions.py index 628ccf6..a725a32 100644 --- a/djadmin2/actions.py +++ b/djadmin2/actions.py @@ -22,9 +22,11 @@ class BaseListAction(AdminModel2Mixin, TemplateView): permission_classes = (permissions.IsStaffPermission,) - empty_message = _('Items must be selected in order to perform actions ' - 'on them. No items have been changed.') - success_message = _('Successfully deleted %(count)d %(items)s') + empty_message = ugettext_lazy( + 'Items must be selected in order to perform actions ' + 'on them. No items have been changed.' + ) + success_message = ugettext_lazy('Successfully deleted %(count)s %(items)s') queryset = None @@ -98,9 +100,9 @@ class BaseListAction(AdminModel2Mixin, TemplateView): if request.POST.get('confirmed'): if self.process_queryset() is None: - message = _(self.success_message % { + message = self.success_message % { 'count': self.item_count, 'items': self.objects_name - }) + } messages.add_message(request, messages.INFO, message) return None diff --git a/djadmin2/locale/en/LC_MESSAGES/django.po b/djadmin2/locale/en/LC_MESSAGES/django.po index 907181b..c0b0dc9 100644 --- a/djadmin2/locale/en/LC_MESSAGES/django.po +++ b/djadmin2/locale/en/LC_MESSAGES/django.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: django-admin2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-06 12:25+0200\n" -"PO-Revision-Date: 2013-07-06 12:15+0200\n" +"POT-Creation-Date: 2013-07-06 13:16+0200\n" +"PO-Revision-Date: 2013-07-06 13:27+0200\n" "Last-Translator: NotSqrt \n" "Language-Team: English \n" "Language: en\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: actions.py:25 +#: actions.py:26 msgid "" "Items must be selected in order to perform actions on them. No items have " "been changed." @@ -23,16 +23,12 @@ msgstr "" "Items must be selected in order to perform actions on them. No items have " "been changed." -#: actions.py:27 +#: actions.py:29 #, python-format -msgid "Successfully deleted %(count)d %(items)s" -msgstr "Successfully deleted %(count)d %(items)s" +msgid "Successfully deleted %(count)s %(items)s" +msgstr "Successfully deleted %(count)s %(items)s" -#: actions.py:102 -msgid "count" -msgstr "count" - -#: actions.py:125 +#: actions.py:127 msgid "Delete selected items" msgstr "Delete selected items" diff --git a/djadmin2/locale/fr/LC_MESSAGES/django.po b/djadmin2/locale/fr/LC_MESSAGES/django.po index d96870b..bf3da9d 100644 --- a/djadmin2/locale/fr/LC_MESSAGES/django.po +++ b/djadmin2/locale/fr/LC_MESSAGES/django.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: django-admin2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-06 12:25+0200\n" -"PO-Revision-Date: 2013-07-06 12:15+0200\n" +"POT-Creation-Date: 2013-07-06 13:16+0200\n" +"PO-Revision-Date: 2013-07-06 13:27+0200\n" "Last-Translator: NotSqrt \n" "Language-Team: French (http://www.transifex.com/projects/p/django-admin2/" "language/fr/)\n" @@ -17,7 +17,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: actions.py:25 +#: actions.py:26 msgid "" "Items must be selected in order to perform actions on them. No items have " "been changed." @@ -25,16 +25,12 @@ msgstr "" "Des éléments doivent être sélectionnés afin d'appliquer les actions. Aucun " "élément n'a été modifié." -#: actions.py:27 +#: actions.py:29 #, python-format -msgid "Successfully deleted %(count)d %(items)s" -msgstr "La suppression de %(count)d %(items)s a réussi." +msgid "Successfully deleted %(count)s %(items)s" +msgstr "La suppression de %(count)s %(items)s a réussi." -#: actions.py:102 -msgid "count" -msgstr "count" - -#: actions.py:125 +#: actions.py:127 msgid "Delete selected items" msgstr "Supprimer les objets sélectionnés" diff --git a/djadmin2/templates/admin2/bootstrap/model_detail.html b/djadmin2/templates/admin2/bootstrap/model_detail.html index 118d01c..f44e9da 100644 --- a/djadmin2/templates/admin2/bootstrap/model_detail.html +++ b/djadmin2/templates/admin2/bootstrap/model_detail.html @@ -1,6 +1,6 @@ {% extends "admin2/bootstrap/base.html" %} -{% load admin2_tags %} +{% load admin2_tags i18n %} {% block title %}{{ object }}{% endblock title %} diff --git a/example/blog/actions.py b/example/blog/actions.py index 8603b3c..07900f5 100644 --- a/example/blog/actions.py +++ b/example/blog/actions.py @@ -11,7 +11,7 @@ class CustomPublishAction(BaseListAction): ) description = ugettext_lazy('Publish selected items') - success_message = 'Successfully published %d %s' + success_message = ugettext_lazy('Successfully published %(count)s %(items)s') default_template_name = "actions/publish_selected_items.html" From 771af888776653fc35ec4dd3b22507354c70f6ec Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 12:58:45 +0200 Subject: [PATCH 39/58] Make django docs intersphinx work --- docs/_ext/djangodocs.py | 81 +++++++++++++++++++++++++++++++++++++++++ docs/conf.py | 11 ++++-- docs/ref/meta.rst | 7 +++- 3 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 docs/_ext/djangodocs.py diff --git a/docs/_ext/djangodocs.py b/docs/_ext/djangodocs.py new file mode 100644 index 0000000..a88a9f8 --- /dev/null +++ b/docs/_ext/djangodocs.py @@ -0,0 +1,81 @@ +# Taken from https://github.com/django/django/blob/master/docs/_ext/djangodocs.py + +import re +from sphinx import addnodes + + +# RE for option descriptions without a '--' prefix +simple_option_desc_re = re.compile( + r'([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)') + + +def setup(app): + app.add_crossref_type( + directivename="setting", + rolename="setting", + indextemplate="pair: %s; setting", + ) + app.add_crossref_type( + directivename="templatetag", + rolename="ttag", + indextemplate="pair: %s; template tag" + ) + app.add_crossref_type( + directivename="templatefilter", + rolename="tfilter", + indextemplate="pair: %s; template filter" + ) + app.add_crossref_type( + directivename="fieldlookup", + rolename="lookup", + indextemplate="pair: %s; field lookup type", + ) + app.add_description_unit( + directivename="django-admin", + rolename="djadmin", + indextemplate="pair: %s; django-admin command", + parse_node=parse_django_admin_node, + ) + app.add_description_unit( + directivename="django-admin-option", + rolename="djadminopt", + indextemplate="pair: %s; django-admin command-line option", + parse_node=parse_django_adminopt_node, + ) + + +def parse_django_admin_node(env, sig, signode): + command = sig.split(' ')[0] + env._django_curr_admin_command = command + title = "django-admin.py %s" % sig + signode += addnodes.desc_name(title, title) + return sig + + +def parse_django_adminopt_node(env, sig, signode): + """A copy of sphinx.directives.CmdoptionDesc.parse_signature()""" + from sphinx.domains.std import option_desc_re + count = 0 + firstname = '' + for m in option_desc_re.finditer(sig): + optname, args = m.groups() + if count: + signode += addnodes.desc_addname(', ', ', ') + signode += addnodes.desc_name(optname, optname) + signode += addnodes.desc_addname(args, args) + if not count: + firstname = optname + count += 1 + if not count: + for m in simple_option_desc_re.finditer(sig): + optname, args = m.groups() + if count: + signode += addnodes.desc_addname(', ', ', ') + signode += addnodes.desc_name(optname, optname) + signode += addnodes.desc_addname(args, args) + if not count: + firstname = optname + count += 1 + if not firstname: + raise ValueError + return firstname diff --git a/docs/conf.py b/docs/conf.py index afa2358..4c2e76e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,6 +33,10 @@ from example.example import settings from django.core.management import setup_environ setup_environ(settings) +# For intersphinx +ext_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "_ext")) +sys.path.append(ext_path) + # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. @@ -40,7 +44,7 @@ setup_environ(settings) # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] +extensions = ['djangodocs', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -265,7 +269,6 @@ texinfo_documents = [ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - 'django': ( - 'http://docs.djangoproject.com/en/dev/', - 'http://docs.djangoproject.com/en/dev/_objects/'), + 'python': ('http://python.readthedocs.org/en/v2.7.2/', None), + 'django': ('http://docs.djangoproject.com/en/dev/', None), } diff --git a/docs/ref/meta.rst b/docs/ref/meta.rst index d54b050..926c8fd 100644 --- a/docs/ref/meta.rst +++ b/docs/ref/meta.rst @@ -48,7 +48,8 @@ Attributes copied from ``Meta`` Some of ``_meta``'s attributes are just copied from the ``Meta`` options. The following attributes are those. Their behaviour is more detailed described in -the :doc:`django documentation `. +the `django documentation +`__. ``abstract`` A boolean value. @@ -87,7 +88,9 @@ the :doc:`django documentation `. :attr:`~django.db.models.Options.get_latest_by`. ``managed`` - If ``managed`` is ``True`` then the :djadmin:`syncdb` management command will take care of creating the database tables. Defaults to ``True``. + If ``managed`` is ``True`` then the :django:djadmin:`syncdb` management + command will take care of creating the database tables. Defaults to + ``True``. Also see the django documentation about :attr:`~django.db.models.Options.managed`. From 2282f9681d30529658d1d7836b636201dd3e0f62 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 13:54:48 +0200 Subject: [PATCH 40/58] Get rid of all Sphinx warnings --- .gitignore | 1 - docs/_static/README | 1 + docs/conf.py | 3 ++- docs/ref/built-in-views.rst | 6 ++++-- docs/ref/themes.rst | 6 +++--- 5 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 docs/_static/README diff --git a/.gitignore b/.gitignore index 85316c2..6911cad 100644 --- a/.gitignore +++ b/.gitignore @@ -42,7 +42,6 @@ coverage # Sphinx docs/_build -docs/_static # Launchpad lp-cache diff --git a/docs/_static/README b/docs/_static/README new file mode 100644 index 0000000..7fd9945 --- /dev/null +++ b/docs/_static/README @@ -0,0 +1 @@ +Put static files for Sphinx in here. diff --git a/docs/conf.py b/docs/conf.py index 4c2e76e..dfe4a65 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,7 +44,8 @@ sys.path.append(ext_path) # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['djangodocs', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] +extensions = ['djangodocs', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', +'sphinx.ext.todo'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/ref/built-in-views.rst b/docs/ref/built-in-views.rst index 0880299..84c633a 100644 --- a/docs/ref/built-in-views.rst +++ b/docs/ref/built-in-views.rst @@ -1,9 +1,11 @@ Built-In Views =============== -Each of these views contains the list of context variables that are included in their templates. +Each of these views contains the list of context variables that are included in +their templates. -TODO: Provide a list of template context variables for each view per GitHub issue in view class' top-level docstring `#220`_ +TODO: Provide a list of template context variables for each view per GitHub +issue in view class' top-level docstring `#220`_ .. _`#220`: https://github.com/twoscoops/django-admin2/issues/220 diff --git a/docs/ref/themes.rst b/docs/ref/themes.rst index 3a00aba..7180230 100644 --- a/docs/ref/themes.rst +++ b/docs/ref/themes.rst @@ -138,12 +138,12 @@ In the settings module, place the theme right after djadmin2 (change the highlig ) ########### END DJANGO-ADMIN2 CONFIGURATION -.. TODO:: Have someone besides pydanny test this! +.. todo:: Have someone besides pydanny test this! Views and their Templates ------------------------- -See :ref:`Built-In Views` +See doc:`built-in-views` Available Themes @@ -156,4 +156,4 @@ If you'd like to experiment with UI design that differs from the original Django Future ------ -Keep in mind that this project is an experiment just to get our ideas down. We are looking at other similar projects to see if we can merge or borrow things. \ No newline at end of file +Keep in mind that this project is an experiment just to get our ideas down. We are looking at other similar projects to see if we can merge or borrow things. From a6276c614198a70023ab4baae6d65838ce03b7c8 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 13:59:16 +0200 Subject: [PATCH 41/58] Fixed intersphinx objects reference for Django --- docs/conf.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index dfe4a65..17fb2a2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -271,5 +271,8 @@ texinfo_documents = [ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { 'python': ('http://python.readthedocs.org/en/v2.7.2/', None), - 'django': ('http://docs.djangoproject.com/en/dev/', None), + 'django': ( + 'http://docs.djangoproject.com/en/dev/', + 'http://docs.djangoproject.com/en/dev/_objects/' + ), } From 882da135858cb44939926ae2b04bfc3e518663e1 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 14:07:30 +0200 Subject: [PATCH 42/58] Adding Henri Colas to the authors file --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index c0467ab..68e5c7b 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -31,3 +31,4 @@ Developers * Chris Jones (@chrisjones-brack3t / ) * Danilo Bargen (@dbrgn) * Ignasi Fosch Alonso (@ifosch) +* Henri Colas (@NotSqrt) From 550c6b684b42de60df94ee65acbd02e4f112b052 Mon Sep 17 00:00:00 2001 From: Ignasi Fosch Date: Sat, 6 Jul 2013 14:17:04 +0200 Subject: [PATCH 43/58] Moving action tests to another file --- djadmin2/tests/test_actions.py | 49 ++++++++++++++++++++++++++++++++++ djadmin2/tests/test_core.py | 34 ----------------------- 2 files changed, 49 insertions(+), 34 deletions(-) create mode 100644 djadmin2/tests/test_actions.py diff --git a/djadmin2/tests/test_actions.py b/djadmin2/tests/test_actions.py new file mode 100644 index 0000000..ff11118 --- /dev/null +++ b/djadmin2/tests/test_actions.py @@ -0,0 +1,49 @@ +from django.db import models +from django.test import TestCase + +from ..core import Admin2 +from ..actions import get_description + + +class Thing(models.Model): + pass + + +class TestAction(object): + description = "Test Action Class" + + +def test_function(): + pass + + +class ActionTest(TestCase): + def setUp(self): + self.admin2 = Admin2() + + def test_action_description(self): + self.admin2.register(Thing) + self.admin2.registry[Thing].list_actions.extend([ + TestAction, + test_function, + ]) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[0] + ), + 'Delete selected items' + ) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[1] + ), + 'Test Action Class' + ) + self.assertEquals( + get_description( + self.admin2.registry[Thing].list_actions[2] + ), + 'Test function' + ) + self.admin2.registry[Thing].list_actions.remove(TestAction) + self.admin2.registry[Thing].list_actions.remove(test_function) diff --git a/djadmin2/tests/test_core.py b/djadmin2/tests/test_core.py index 1d0b470..6828032 100644 --- a/djadmin2/tests/test_core.py +++ b/djadmin2/tests/test_core.py @@ -4,21 +4,12 @@ from django.test import TestCase from ..types import ModelAdmin2 from ..core import Admin2 -from ..actions import get_description class Thing(models.Model): pass -class TestAction(object): - description = "Test Action Class" - - -def test_function(): - pass - - class Admin2Test(TestCase): def setUp(self): self.admin2 = Admin2() @@ -42,28 +33,3 @@ class Admin2Test(TestCase): def test_get_urls(self): self.admin2.register(Thing) self.assertEquals(8, len(self.admin2.get_urls())) - - def test_action_description(self): - self.admin2.register(Thing) - self.admin2.registry[Thing].list_actions.extend([ - TestAction, - test_function - ]) - self.assertEquals( - get_description( - self.admin2.registry[Thing].list_actions[0] - ), - 'Delete selected items' - ) - self.assertEquals( - get_description( - self.admin2.registry[Thing].list_actions[1] - ), - 'Test Action Class' - ) - self.assertEquals( - get_description( - self.admin2.registry[Thing].list_actions[2] - ), - 'Test function' - ) From 260cabcddfa44aa3f3f9cbfc83f4c398739e5824 Mon Sep 17 00:00:00 2001 From: Ignasi Fosch Date: Sat, 6 Jul 2013 14:22:38 +0200 Subject: [PATCH 44/58] Actions tests included in runtest.py execution --- djadmin2/tests/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/djadmin2/tests/__init__.py b/djadmin2/tests/__init__.py index 637e13c..a5f20b0 100644 --- a/djadmin2/tests/__init__.py +++ b/djadmin2/tests/__init__.py @@ -3,3 +3,4 @@ from test_types import * from test_utils import * from test_views import * from test_core import * +from test_actions import * From 679a997f8011749ba097ad4d30a64fddadf75591 Mon Sep 17 00:00:00 2001 From: bootandy Date: Sat, 6 Jul 2013 14:40:49 +0200 Subject: [PATCH 45/58] update docs - context variables --- djadmin2/views.py | 42 +++++++++++++++++++++++++++++++++++-- docs/ref/built-in-views.rst | 10 +++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/djadmin2/views.py b/djadmin2/views.py index 70551bf..1390a7d 100644 --- a/djadmin2/views.py +++ b/djadmin2/views.py @@ -26,8 +26,6 @@ class IndexView(Admin2Mixin, generic.TemplateView): :apps: A dictionary of apps, each app being a dictionary with keys being models and the value being djadmin2.types.ModelAdmin2 objects. - :request.user: The user object representing the current user. - """ default_template_name = "index.html" registry = None @@ -59,6 +57,13 @@ class AppIndexView(Admin2Mixin, generic.TemplateView): class ModelListView(AdminModel2Mixin, generic.ListView): + """Context Variables + + :is_paginated: If the page is paginated (page has a next button) + :model: Type of object you are editing + :model_name: Name of the object you are editing + :app_label: Name of your app + """ default_template_name = "model_list.html" permission_classes = ( permissions.IsStaffPermission, @@ -146,6 +151,12 @@ class ModelListView(AdminModel2Mixin, generic.ListView): class ModelDetailView(AdminModel2Mixin, generic.DetailView): + """Context Variables + + :model: Type of object you are editing + :model_name: Name of the object you are editing + :app_label: Name of your app + """ default_template_name = "model_detail.html" permission_classes = ( permissions.IsStaffPermission, @@ -153,6 +164,12 @@ class ModelDetailView(AdminModel2Mixin, generic.DetailView): class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.UpdateWithInlinesView): + """Context Variables + + :model: Type of object you are editing + :model_name: Name of the object you are editing + :app_label: Name of your app + """ form_class = None default_template_name = "model_update_form.html" permission_classes = ( @@ -167,6 +184,12 @@ class ModelEditFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.Upda class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.CreateWithInlinesView): + """Context Variables + + :model: Type of object you are editing + :model_name: Name of the object you are editing + :app_label: Name of your app + """ form_class = None default_template_name = "model_update_form.html" permission_classes = ( @@ -181,6 +204,13 @@ class ModelAddFormView(AdminModel2Mixin, Admin2ModelFormMixin, extra_views.Creat class ModelDeleteView(AdminModel2Mixin, generic.DeleteView): + """Context Variables + + :model: Type of object you are editing + :model_name: Name of the object you are editing + :app_label: Name of your app + :deletable_objects: Objects to delete + """ success_url = "../../" # TODO - fix this! default_template_name = "model_confirm_delete.html" permission_classes = ( @@ -233,6 +263,10 @@ class PasswordChangeDoneView(Admin2Mixin, generic.TemplateView): class LoginView(Admin2Mixin, generic.TemplateView): + """Context Variables + + :site_name: Name of the site + """ default_template_name = 'auth/login.html' authentication_form = AdminAuthenticationForm @@ -245,6 +279,10 @@ class LoginView(Admin2Mixin, generic.TemplateView): class LogoutView(Admin2Mixin, generic.TemplateView): + """Context Variables + + :site_name: Name of the site + """ default_template_name = 'auth/logout.html' diff --git a/docs/ref/built-in-views.rst b/docs/ref/built-in-views.rst index 84c633a..60600c8 100644 --- a/docs/ref/built-in-views.rst +++ b/docs/ref/built-in-views.rst @@ -9,6 +9,14 @@ issue in view class' top-level docstring `#220`_ .. _`#220`: https://github.com/twoscoops/django-admin2/issues/220 +.. code-block:: python + + :next: The page to redirect the user to after login + :MEDIA_URL: Specify a directory where file uploads for users who use your site go + :STATIC_URL: Specify a directory for JavaScript, CSS and image files. + :user: Currently logged in user + + .. autoclass:: djadmin2.views.IndexView :members: @@ -29,11 +37,9 @@ issue in view class' top-level docstring `#220`_ .. autoclass:: djadmin2.views.ModelAddFormView :members: - .. autoclass:: djadmin2.views.ModelDeleteView :members: - .. autoclass:: djadmin2.views.PasswordChangeView :members: From a6d407b887bed5e8304674b74cb22a4037219a07 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 14:46:15 +0200 Subject: [PATCH 46/58] Fixes in language files --- djadmin2/locale/en/LC_MESSAGES/django.po | 2 +- djadmin2/locale/fr/LC_MESSAGES/django.po | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/djadmin2/locale/en/LC_MESSAGES/django.po b/djadmin2/locale/en/LC_MESSAGES/django.po index c0b0dc9..542e9b9 100644 --- a/djadmin2/locale/en/LC_MESSAGES/django.po +++ b/djadmin2/locale/en/LC_MESSAGES/django.po @@ -9,8 +9,8 @@ msgstr "" "POT-Creation-Date: 2013-07-06 13:16+0200\n" "PO-Revision-Date: 2013-07-06 13:27+0200\n" "Last-Translator: NotSqrt \n" -"Language-Team: English \n" "Language: en\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" diff --git a/djadmin2/locale/fr/LC_MESSAGES/django.po b/djadmin2/locale/fr/LC_MESSAGES/django.po index bf3da9d..55416ff 100644 --- a/djadmin2/locale/fr/LC_MESSAGES/django.po +++ b/djadmin2/locale/fr/LC_MESSAGES/django.po @@ -9,13 +9,12 @@ msgstr "" "POT-Creation-Date: 2013-07-06 13:16+0200\n" "PO-Revision-Date: 2013-07-06 13:27+0200\n" "Last-Translator: NotSqrt \n" -"Language-Team: French (http://www.transifex.com/projects/p/django-admin2/" -"language/fr/)\n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/fr/\n" "Language: fr\n" +"Plural-Forms: nplurals=2; plural=n>1;\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" #: actions.py:26 msgid "" From 2842699b7141720e3c5e0c8e5ab7c9ecf717fc3a Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 14:54:21 +0200 Subject: [PATCH 47/58] Added German and Spanish translation files --- djadmin2/locale/de/LC_MESSAGES/django.po | 231 +++++++++++++++++++++++ djadmin2/locale/es/LC_MESSAGES/django.po | 231 +++++++++++++++++++++++ 2 files changed, 462 insertions(+) create mode 100644 djadmin2/locale/de/LC_MESSAGES/django.po create mode 100644 djadmin2/locale/es/LC_MESSAGES/django.po diff --git a/djadmin2/locale/de/LC_MESSAGES/django.po b/djadmin2/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000..02a1db0 --- /dev/null +++ b/djadmin2/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,231 @@ +# This file is distributed under the same license as the django-admin2 package. +# +# Translators: +# Danilo Bargen , 2013. +msgid "" +msgstr "" +"Project-Id-Version: django-admin2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-06 14:47+0200\n" +"PO-Revision-Date: 2013-07-06 14:47+0200\n" +"Last-Translator: Danilo Bargen \n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/de/\n" +"Language: 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" + +#: actions.py:26 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: actions.py:29 +#, python-format +msgid "Successfully deleted %(count)s %(items)s" +msgstr "" + +#: actions.py:127 +msgid "Delete selected items" +msgstr "" + +#: forms.py:238 +#, python-format +msgid "" +"Please enter the correct %(username)s and password for a staff account. Note " +"that both fields may be case-sensitive." +msgstr "" + +#: forms.py:249 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 +#: templates/admin2/bootstrap/includes/app_model_list.html:38 +msgid "Change" +msgstr "" + +#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +msgid "Add" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:6 +#: templates/admin2/bootstrap/base.html:55 +#: templates/admin2/bootstrap/model_confirm_delete.html:10 +#: templates/admin2/bootstrap/model_detail.html:11 +#: templates/admin2/bootstrap/model_list.html:14 +#: templates/admin2/bootstrap/model_update_form.html:11 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/admin2/bootstrap/auth/logout.html:8 +#: templates/admin2/bootstrap/auth/password_change_done.html:11 +#: templates/admin2/bootstrap/auth/password_change_form.html:10 +msgid "Home" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:12 +#, python-format +msgid "%(app_label)s administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:6 +#: templates/admin2/bootstrap/base.html:71 +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Site administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:22 +msgid "API" +msgstr "" + +#: templates/admin2/bootstrap/base.html:25 +msgid "Documentation" +msgstr "" + +#: templates/admin2/bootstrap/base.html:34 +#, python-format +msgid "Logged in as %(user)s" +msgstr "" + +#: templates/admin2/bootstrap/base.html:40 +msgid "Change password" +msgstr "" + +#: templates/admin2/bootstrap/base.html:42 +msgid "Log out" +msgstr "" + +#: templates/admin2/bootstrap/index.html:13 +msgid "Recent Actions" +msgstr "" + +#: templates/admin2/bootstrap/index.html:14 +msgid "My Actions" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:4 +#: templates/admin2/bootstrap/model_confirm_delete.html:6 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +msgid "Are you sure?" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:25 +#: templates/admin2/bootstrap/model_update_form.html:74 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +msgid "Delete" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#, python-format +msgid "" +"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " +"the following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:40 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:4 +#: templates/admin2/bootstrap/model_list.html:6 +#, python-format +msgid "Select %(model_name)s to change" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:31 +msgid "Search Term" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:32 +msgid "Search" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:59 +#, python-format +msgid "%(selected)s of %(total)s selected" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:63 +#, python-format +msgid "Add %(model_verbose_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:5 +#: templates/admin2/bootstrap/model_update_form.html:7 +#, python-format +msgid "%(action)s %(model_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:78 +msgid "Save and add another" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:79 +msgid "Save and continue editing" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:80 +msgid "Save" +msgstr "" + +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Login" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:27 +#: templates/admin2/bootstrap/auth/password_change_form.html:24 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" +msgstr[1] "" + +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:11 +msgid "Logout" +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:18 +msgid "Log in again" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:6 +#: templates/admin2/bootstrap/auth/password_change_done.html:7 +#: templates/admin2/bootstrap/auth/password_change_done.html:14 +msgid "Password change successful" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:20 +msgid "Your password was changed." +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:6 +#: templates/admin2/bootstrap/auth/password_change_form.html:13 +msgid "Password change" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:20 +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 "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:31 +msgid "Change my password" +msgstr "" diff --git a/djadmin2/locale/es/LC_MESSAGES/django.po b/djadmin2/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..cdb6b24 --- /dev/null +++ b/djadmin2/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,231 @@ +# This file is distributed under the same license as the django-admin2 package. +# +# Translators: +# Danilo Bargen , 2013. +msgid "" +msgstr "" +"Project-Id-Version: django-admin2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-06 14:47+0200\n" +"PO-Revision-Date: 2013-07-06 14:47+0200\n" +"Last-Translator: Danilo Bargen \n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/es/\n" +"Language: es\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" + +#: actions.py:26 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: actions.py:29 +#, python-format +msgid "Successfully deleted %(count)s %(items)s" +msgstr "" + +#: actions.py:127 +msgid "Delete selected items" +msgstr "" + +#: forms.py:238 +#, python-format +msgid "" +"Please enter the correct %(username)s and password for a staff account. Note " +"that both fields may be case-sensitive." +msgstr "" + +#: forms.py:249 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 +#: templates/admin2/bootstrap/includes/app_model_list.html:38 +msgid "Change" +msgstr "" + +#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +msgid "Add" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:6 +#: templates/admin2/bootstrap/base.html:55 +#: templates/admin2/bootstrap/model_confirm_delete.html:10 +#: templates/admin2/bootstrap/model_detail.html:11 +#: templates/admin2/bootstrap/model_list.html:14 +#: templates/admin2/bootstrap/model_update_form.html:11 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/admin2/bootstrap/auth/logout.html:8 +#: templates/admin2/bootstrap/auth/password_change_done.html:11 +#: templates/admin2/bootstrap/auth/password_change_form.html:10 +msgid "Home" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:12 +#, python-format +msgid "%(app_label)s administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:6 +#: templates/admin2/bootstrap/base.html:71 +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Site administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:22 +msgid "API" +msgstr "" + +#: templates/admin2/bootstrap/base.html:25 +msgid "Documentation" +msgstr "" + +#: templates/admin2/bootstrap/base.html:34 +#, python-format +msgid "Logged in as %(user)s" +msgstr "" + +#: templates/admin2/bootstrap/base.html:40 +msgid "Change password" +msgstr "" + +#: templates/admin2/bootstrap/base.html:42 +msgid "Log out" +msgstr "" + +#: templates/admin2/bootstrap/index.html:13 +msgid "Recent Actions" +msgstr "" + +#: templates/admin2/bootstrap/index.html:14 +msgid "My Actions" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:4 +#: templates/admin2/bootstrap/model_confirm_delete.html:6 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +msgid "Are you sure?" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:25 +#: templates/admin2/bootstrap/model_update_form.html:74 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +msgid "Delete" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#, python-format +msgid "" +"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " +"the following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:40 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:4 +#: templates/admin2/bootstrap/model_list.html:6 +#, python-format +msgid "Select %(model_name)s to change" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:31 +msgid "Search Term" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:32 +msgid "Search" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:59 +#, python-format +msgid "%(selected)s of %(total)s selected" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:63 +#, python-format +msgid "Add %(model_verbose_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:5 +#: templates/admin2/bootstrap/model_update_form.html:7 +#, python-format +msgid "%(action)s %(model_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:78 +msgid "Save and add another" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:79 +msgid "Save and continue editing" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:80 +msgid "Save" +msgstr "" + +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Login" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:27 +#: templates/admin2/bootstrap/auth/password_change_form.html:24 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" +msgstr[1] "" + +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:11 +msgid "Logout" +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:18 +msgid "Log in again" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:6 +#: templates/admin2/bootstrap/auth/password_change_done.html:7 +#: templates/admin2/bootstrap/auth/password_change_done.html:14 +msgid "Password change successful" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:20 +msgid "Your password was changed." +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:6 +#: templates/admin2/bootstrap/auth/password_change_form.html:13 +msgid "Password change" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:20 +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 "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:31 +msgid "Change my password" +msgstr "" From 3c44a8b930b3bbeebd61a2d69407a6315011b975 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 15:00:08 +0200 Subject: [PATCH 48/58] Changed inconsistent use of "login/logout" --- djadmin2/locale/de/LC_MESSAGES/django.po | 17 ++++++----------- djadmin2/locale/en/LC_MESSAGES/django.po | 18 ++++++------------ djadmin2/locale/es/LC_MESSAGES/django.po | 17 ++++++----------- djadmin2/locale/fr/LC_MESSAGES/django.po | 19 +++++++------------ .../admin2/bootstrap/auth/login.html | 2 +- .../admin2/bootstrap/auth/logout.html | 2 +- 6 files changed, 27 insertions(+), 48 deletions(-) diff --git a/djadmin2/locale/de/LC_MESSAGES/django.po b/djadmin2/locale/de/LC_MESSAGES/django.po index 02a1db0..d926136 100644 --- a/djadmin2/locale/de/LC_MESSAGES/django.po +++ b/djadmin2/locale/de/LC_MESSAGES/django.po @@ -6,10 +6,11 @@ msgid "" msgstr "" "Project-Id-Version: django-admin2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-06 14:47+0200\n" +"POT-Creation-Date: 2013-07-06 15:02+0200\n" "PO-Revision-Date: 2013-07-06 14:47+0200\n" "Last-Translator: Danilo Bargen \n" -"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/de/\n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/" +"de/\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -93,6 +94,7 @@ msgid "Change password" msgstr "" #: templates/admin2/bootstrap/base.html:42 +#: templates/admin2/bootstrap/auth/logout.html:11 msgid "Log out" msgstr "" @@ -179,7 +181,8 @@ msgid "" msgstr "" #: templates/admin2/bootstrap/auth/login.html:15 -msgid "Login" +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" msgstr "" #: templates/admin2/bootstrap/auth/login.html:27 @@ -189,14 +192,6 @@ msgid_plural "Please correct the errors below." msgstr[0] "" msgstr[1] "" -#: templates/admin2/bootstrap/auth/login.html:52 -msgid "Log in" -msgstr "" - -#: templates/admin2/bootstrap/auth/logout.html:11 -msgid "Logout" -msgstr "" - #: templates/admin2/bootstrap/auth/logout.html:17 msgid "Thanks for spending some quality time with the Web site today." msgstr "" diff --git a/djadmin2/locale/en/LC_MESSAGES/django.po b/djadmin2/locale/en/LC_MESSAGES/django.po index 542e9b9..c2c09dd 100644 --- a/djadmin2/locale/en/LC_MESSAGES/django.po +++ b/djadmin2/locale/en/LC_MESSAGES/django.po @@ -6,14 +6,14 @@ msgid "" msgstr "" "Project-Id-Version: django-admin2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-06 13:16+0200\n" +"POT-Creation-Date: 2013-07-06 15:02+0200\n" "PO-Revision-Date: 2013-07-06 13:27+0200\n" "Last-Translator: NotSqrt \n" "Language: en\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\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" #: actions.py:26 msgid "" @@ -96,6 +96,7 @@ msgid "Change password" msgstr "Change password" #: templates/admin2/bootstrap/base.html:42 +#: templates/admin2/bootstrap/auth/logout.html:11 msgid "Log out" msgstr "Log out" @@ -186,8 +187,9 @@ msgstr "" "following items will be deleted:" #: templates/admin2/bootstrap/auth/login.html:15 -msgid "Login" -msgstr "Login" +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" +msgstr "Log in" #: templates/admin2/bootstrap/auth/login.html:27 #: templates/admin2/bootstrap/auth/password_change_form.html:24 @@ -196,14 +198,6 @@ msgid_plural "Please correct the errors below." msgstr[0] "Please correct the error below." msgstr[1] "Please correct the errors below." -#: templates/admin2/bootstrap/auth/login.html:52 -msgid "Log in" -msgstr "Log in" - -#: templates/admin2/bootstrap/auth/logout.html:11 -msgid "Logout" -msgstr "Logout" - #: templates/admin2/bootstrap/auth/logout.html:17 msgid "Thanks for spending some quality time with the Web site today." msgstr "Thanks for spending some quality time with the Web site today." diff --git a/djadmin2/locale/es/LC_MESSAGES/django.po b/djadmin2/locale/es/LC_MESSAGES/django.po index cdb6b24..b75ade1 100644 --- a/djadmin2/locale/es/LC_MESSAGES/django.po +++ b/djadmin2/locale/es/LC_MESSAGES/django.po @@ -6,10 +6,11 @@ msgid "" msgstr "" "Project-Id-Version: django-admin2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-06 14:47+0200\n" +"POT-Creation-Date: 2013-07-06 15:02+0200\n" "PO-Revision-Date: 2013-07-06 14:47+0200\n" "Last-Translator: Danilo Bargen \n" -"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/es/\n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/" +"es/\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -93,6 +94,7 @@ msgid "Change password" msgstr "" #: templates/admin2/bootstrap/base.html:42 +#: templates/admin2/bootstrap/auth/logout.html:11 msgid "Log out" msgstr "" @@ -179,7 +181,8 @@ msgid "" msgstr "" #: templates/admin2/bootstrap/auth/login.html:15 -msgid "Login" +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" msgstr "" #: templates/admin2/bootstrap/auth/login.html:27 @@ -189,14 +192,6 @@ msgid_plural "Please correct the errors below." msgstr[0] "" msgstr[1] "" -#: templates/admin2/bootstrap/auth/login.html:52 -msgid "Log in" -msgstr "" - -#: templates/admin2/bootstrap/auth/logout.html:11 -msgid "Logout" -msgstr "" - #: templates/admin2/bootstrap/auth/logout.html:17 msgid "Thanks for spending some quality time with the Web site today." msgstr "" diff --git a/djadmin2/locale/fr/LC_MESSAGES/django.po b/djadmin2/locale/fr/LC_MESSAGES/django.po index 55416ff..13d7b76 100644 --- a/djadmin2/locale/fr/LC_MESSAGES/django.po +++ b/djadmin2/locale/fr/LC_MESSAGES/django.po @@ -6,15 +6,16 @@ msgid "" msgstr "" "Project-Id-Version: django-admin2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-06 13:16+0200\n" +"POT-Creation-Date: 2013-07-06 15:02+0200\n" "PO-Revision-Date: 2013-07-06 13:27+0200\n" "Last-Translator: NotSqrt \n" -"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/fr/\n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/" +"fr/\n" "Language: fr\n" -"Plural-Forms: nplurals=2; plural=n>1;\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" #: actions.py:26 msgid "" @@ -98,6 +99,7 @@ msgid "Change password" msgstr "Modifier votre mot de passe" #: templates/admin2/bootstrap/base.html:42 +#: templates/admin2/bootstrap/auth/logout.html:11 msgid "Log out" msgstr "Déconnexion" @@ -188,7 +190,8 @@ msgstr "" "Les éléments suivants seront supprimés :" #: templates/admin2/bootstrap/auth/login.html:15 -msgid "Login" +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" msgstr "Connexion" #: templates/admin2/bootstrap/auth/login.html:27 @@ -198,14 +201,6 @@ msgid_plural "Please correct the errors below." msgstr[0] "Corrigez l'erreur suivante." msgstr[1] "Corrigez les erreurs suivantes." -#: templates/admin2/bootstrap/auth/login.html:52 -msgid "Log in" -msgstr "Connexion" - -#: templates/admin2/bootstrap/auth/logout.html:11 -msgid "Logout" -msgstr "Déconnexion" - #: templates/admin2/bootstrap/auth/logout.html:17 msgid "Thanks for spending some quality time with the Web site today." msgstr "Merci pour le temps que vous avez accordé à ce site aujourd'hui." diff --git a/djadmin2/templates/admin2/bootstrap/auth/login.html b/djadmin2/templates/admin2/bootstrap/auth/login.html index c055c15..36421dc 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/login.html +++ b/djadmin2/templates/admin2/bootstrap/auth/login.html @@ -12,7 +12,7 @@ {% block breacrumbs %}{% endblock breacrumbs %} {% block class_page_title %}span12 login-title{% endblock class_page_title %} -{% block page_title %}{% trans "Site administration" %} - {% trans "Login" %}{% endblock page_title %} +{% block page_title %}{% trans "Site administration" %} - {% trans "Log in" %}{% endblock page_title %} {% block content %}
    diff --git a/djadmin2/templates/admin2/bootstrap/auth/logout.html b/djadmin2/templates/admin2/bootstrap/auth/logout.html index 7da8675..97974ca 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/logout.html +++ b/djadmin2/templates/admin2/bootstrap/auth/logout.html @@ -8,7 +8,7 @@ {% trans "Home" %} /
  • -
  • {% trans "Logout" %}
  • +
  • {% trans "Log out" %}
  • {% endblock breadcrumbs %} {% block content %} From 483386635d00cc7ae6524cc8d6f23655aade9416 Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 15:06:27 +0200 Subject: [PATCH 49/58] Slight tweak to the built-in-views --- docs/ref/built-in-views.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/ref/built-in-views.rst b/docs/ref/built-in-views.rst index 60600c8..5baf711 100644 --- a/docs/ref/built-in-views.rst +++ b/docs/ref/built-in-views.rst @@ -9,13 +9,18 @@ issue in view class' top-level docstring `#220`_ .. _`#220`: https://github.com/twoscoops/django-admin2/issues/220 -.. code-block:: python +View Constants +--------------- + +The following are available in every view: :next: The page to redirect the user to after login :MEDIA_URL: Specify a directory where file uploads for users who use your site go :STATIC_URL: Specify a directory for JavaScript, CSS and image files. :user: Currently logged in user +View Descriptions +------------------ .. autoclass:: djadmin2.views.IndexView :members: From 4288b2568ddc926d76abaa490afc7cf833d8acee Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 15:06:18 +0200 Subject: [PATCH 50/58] Adding Andy Boot to authors POW! :wink: --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 68e5c7b..715182d 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -32,3 +32,4 @@ Developers * Danilo Bargen (@dbrgn) * Ignasi Fosch Alonso (@ifosch) * Henri Colas (@NotSqrt) +* Andy Boot (@bootandy) From 1ef08cc20f48244c6606830f1e5c2afc75cc2f9c Mon Sep 17 00:00:00 2001 From: bootandy Date: Sat, 6 Jul 2013 15:18:01 +0200 Subject: [PATCH 51/58] first itteration --- README.rst | 12 ++++++------ djadmin2/settings.py | 2 +- .../actions/delete_selected_confirmation.html | 2 +- .../{admin2 => djadmin2}/bootstrap/app_index.html | 2 +- .../{admin2 => djadmin2}/bootstrap/auth/login.html | 2 +- .../{admin2 => djadmin2}/bootstrap/auth/logout.html | 2 +- .../bootstrap/auth/password_change_done.html | 2 +- .../bootstrap/auth/password_change_form.html | 2 +- .../{admin2 => djadmin2}/bootstrap/base.html | 0 .../bootstrap/includes/app_model_list.html | 0 .../{admin2 => djadmin2}/bootstrap/index.html | 2 +- .../bootstrap/model_confirm_delete.html | 2 +- .../{admin2 => djadmin2}/bootstrap/model_detail.html | 2 +- .../{admin2 => djadmin2}/bootstrap/model_list.html | 2 +- .../bootstrap/model_update_form.html | 2 +- .../bootstrap/actions/publish_selected_items.html | 2 +- example/example/settings.py | 2 +- example2/example2/settings.py | 2 +- example2/polls/templates/home.html | 2 +- 19 files changed, 22 insertions(+), 22 deletions(-) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/actions/delete_selected_confirmation.html (96%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/app_index.html (92%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/auth/login.html (98%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/auth/logout.html (92%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/auth/password_change_done.html (92%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/auth/password_change_form.html (96%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/base.html (100%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/includes/app_model_list.html (100%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/index.html (89%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/model_confirm_delete.html (96%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/model_detail.html (93%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/model_list.html (98%) rename djadmin2/templates/{admin2 => djadmin2}/bootstrap/model_update_form.html (98%) diff --git a/README.rst b/README.rst index f2f5e9c..2ed7408 100644 --- a/README.rst +++ b/README.rst @@ -79,9 +79,9 @@ Add djadmin2 urls to your URLconf: # urls.py from django.conf.urls import patterns, include - + import djadmin2 - + djadmin2.default.autodiscover() @@ -126,16 +126,16 @@ The default theme is whatever bootstrap is most current. Specifically: .. code-block:: python # settings.py - ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/" + ADMIN2_THEME_DIRECTORY = "djadmin2/bootstrap/" If you create a new theme, you define it thus: .. code-block:: python # settings.py - ADMIN2_THEME_DIRECTORY = "admin2/foundation/" + ADMIN2_THEME_DIRECTORY = "djadmin2/foundation/" + - History ========= @@ -144,7 +144,7 @@ History * Implemented both Function- and Class-based Action views * Implemented ModelAdmin2.list_display - * Implemented ModelAdmin2.fieldsets + * Implemented ModelAdmin2.fieldsets * Dropdown widget now displays the selected choice * Added support for callables in ModelAdmin2.list_display * Added screenshots to README diff --git a/djadmin2/settings.py b/djadmin2/settings.py index b84b862..ec3d674 100644 --- a/djadmin2/settings.py +++ b/djadmin2/settings.py @@ -6,4 +6,4 @@ MODEL_ADMIN_ATTRS = ( 'index_view', 'detail_view', 'create_view', 'update_view', 'delete_view', 'get_default_view_kwargs', 'get_list_actions') -ADMIN2_THEME_DIRECTORY = getattr(settings, "ADMIN2_THEME_DIRECTORY", "admin2/bootstrap") +ADMIN2_THEME_DIRECTORY = getattr(settings, "ADMIN2_THEME_DIRECTORY", "djadmin2/bootstrap") diff --git a/djadmin2/templates/admin2/bootstrap/actions/delete_selected_confirmation.html b/djadmin2/templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html similarity index 96% rename from djadmin2/templates/admin2/bootstrap/actions/delete_selected_confirmation.html rename to djadmin2/templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html index fa5d87f..1639cfd 100644 --- a/djadmin2/templates/admin2/bootstrap/actions/delete_selected_confirmation.html +++ b/djadmin2/templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} {% block title %}{% trans "Are you sure?" %}{% endblock title %} diff --git a/djadmin2/templates/admin2/bootstrap/app_index.html b/djadmin2/templates/djadmin2/bootstrap/app_index.html similarity index 92% rename from djadmin2/templates/admin2/bootstrap/app_index.html rename to djadmin2/templates/djadmin2/bootstrap/app_index.html index 5ed20d4..07c5e21 100644 --- a/djadmin2/templates/admin2/bootstrap/app_index.html +++ b/djadmin2/templates/djadmin2/bootstrap/app_index.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} {% block breadcrumbs %} diff --git a/djadmin2/templates/admin2/bootstrap/auth/login.html b/djadmin2/templates/djadmin2/bootstrap/auth/login.html similarity index 98% rename from djadmin2/templates/admin2/bootstrap/auth/login.html rename to djadmin2/templates/djadmin2/bootstrap/auth/login.html index c055c15..5a9ba15 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/login.html +++ b/djadmin2/templates/djadmin2/bootstrap/auth/login.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load i18n %} {% load admin2_tags %} diff --git a/djadmin2/templates/admin2/bootstrap/auth/logout.html b/djadmin2/templates/djadmin2/bootstrap/auth/logout.html similarity index 92% rename from djadmin2/templates/admin2/bootstrap/auth/logout.html rename to djadmin2/templates/djadmin2/bootstrap/auth/logout.html index 7da8675..433c62a 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/logout.html +++ b/djadmin2/templates/djadmin2/bootstrap/auth/logout.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load i18n %} {% load admin2_tags %} diff --git a/djadmin2/templates/admin2/bootstrap/auth/password_change_done.html b/djadmin2/templates/djadmin2/bootstrap/auth/password_change_done.html similarity index 92% rename from djadmin2/templates/admin2/bootstrap/auth/password_change_done.html rename to djadmin2/templates/djadmin2/bootstrap/auth/password_change_done.html index 6f1b352..85ecc89 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/password_change_done.html +++ b/djadmin2/templates/djadmin2/bootstrap/auth/password_change_done.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load i18n %} {% load admin2_tags %} diff --git a/djadmin2/templates/admin2/bootstrap/auth/password_change_form.html b/djadmin2/templates/djadmin2/bootstrap/auth/password_change_form.html similarity index 96% rename from djadmin2/templates/admin2/bootstrap/auth/password_change_form.html rename to djadmin2/templates/djadmin2/bootstrap/auth/password_change_form.html index 18d6408..ae06ac0 100644 --- a/djadmin2/templates/admin2/bootstrap/auth/password_change_form.html +++ b/djadmin2/templates/djadmin2/bootstrap/auth/password_change_form.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load i18n %} {% load admin2_tags %} diff --git a/djadmin2/templates/admin2/bootstrap/base.html b/djadmin2/templates/djadmin2/bootstrap/base.html similarity index 100% rename from djadmin2/templates/admin2/bootstrap/base.html rename to djadmin2/templates/djadmin2/bootstrap/base.html diff --git a/djadmin2/templates/admin2/bootstrap/includes/app_model_list.html b/djadmin2/templates/djadmin2/bootstrap/includes/app_model_list.html similarity index 100% rename from djadmin2/templates/admin2/bootstrap/includes/app_model_list.html rename to djadmin2/templates/djadmin2/bootstrap/includes/app_model_list.html diff --git a/djadmin2/templates/admin2/bootstrap/index.html b/djadmin2/templates/djadmin2/bootstrap/index.html similarity index 89% rename from djadmin2/templates/admin2/bootstrap/index.html rename to djadmin2/templates/djadmin2/bootstrap/index.html index 11eb551..fc78ac6 100644 --- a/djadmin2/templates/admin2/bootstrap/index.html +++ b/djadmin2/templates/djadmin2/bootstrap/index.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} {% block content %} diff --git a/djadmin2/templates/admin2/bootstrap/model_confirm_delete.html b/djadmin2/templates/djadmin2/bootstrap/model_confirm_delete.html similarity index 96% rename from djadmin2/templates/admin2/bootstrap/model_confirm_delete.html rename to djadmin2/templates/djadmin2/bootstrap/model_confirm_delete.html index 8f35b96..76a58e7 100644 --- a/djadmin2/templates/admin2/bootstrap/model_confirm_delete.html +++ b/djadmin2/templates/djadmin2/bootstrap/model_confirm_delete.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} {% block title %}{% trans "Are you sure?" %}{% endblock title %} diff --git a/djadmin2/templates/admin2/bootstrap/model_detail.html b/djadmin2/templates/djadmin2/bootstrap/model_detail.html similarity index 93% rename from djadmin2/templates/admin2/bootstrap/model_detail.html rename to djadmin2/templates/djadmin2/bootstrap/model_detail.html index f44e9da..8434f47 100644 --- a/djadmin2/templates/admin2/bootstrap/model_detail.html +++ b/djadmin2/templates/djadmin2/bootstrap/model_detail.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} diff --git a/djadmin2/templates/admin2/bootstrap/model_list.html b/djadmin2/templates/djadmin2/bootstrap/model_list.html similarity index 98% rename from djadmin2/templates/admin2/bootstrap/model_list.html rename to djadmin2/templates/djadmin2/bootstrap/model_list.html index d5c521a..8607e15 100644 --- a/djadmin2/templates/admin2/bootstrap/model_list.html +++ b/djadmin2/templates/djadmin2/bootstrap/model_list.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} {% block title %}{% blocktrans with model_name=model_name %}Select {{ model_name }} to change{% endblocktrans %}{% endblock title %} diff --git a/djadmin2/templates/admin2/bootstrap/model_update_form.html b/djadmin2/templates/djadmin2/bootstrap/model_update_form.html similarity index 98% rename from djadmin2/templates/admin2/bootstrap/model_update_form.html rename to djadmin2/templates/djadmin2/bootstrap/model_update_form.html index d5b5825..52c7f7f 100644 --- a/djadmin2/templates/admin2/bootstrap/model_update_form.html +++ b/djadmin2/templates/djadmin2/bootstrap/model_update_form.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} diff --git a/example/blog/templates/admin2/bootstrap/actions/publish_selected_items.html b/example/blog/templates/admin2/bootstrap/actions/publish_selected_items.html index 988e435..9cf329d 100644 --- a/example/blog/templates/admin2/bootstrap/actions/publish_selected_items.html +++ b/example/blog/templates/admin2/bootstrap/actions/publish_selected_items.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% load admin2_tags i18n %} {% block title %}Are you sure?{% endblock title %} diff --git a/example/example/settings.py b/example/example/settings.py index 3a05928..8dfb0e9 100644 --- a/example/example/settings.py +++ b/example/example/settings.py @@ -162,7 +162,7 @@ LOGGING = { } -ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/" +ADMIN2_THEME_DIRECTORY = "djadmin2/bootstrap/" ########## TOOLBAR CONFIGURATION diff --git a/example2/example2/settings.py b/example2/example2/settings.py index 48859d2..bb1df97 100644 --- a/example2/example2/settings.py +++ b/example2/example2/settings.py @@ -163,7 +163,7 @@ LOGGING = { } -ADMIN2_THEME_DIRECTORY = "admin2/bootstrap/" +ADMIN2_THEME_DIRECTORY = "djadmin2/bootstrap/" ########## TOOLBAR CONFIGURATION # See: https://github.com/django-debug-toolbar/django-debug-toolbar#installation diff --git a/example2/polls/templates/home.html b/example2/polls/templates/home.html index f00243e..d16e212 100644 --- a/example2/polls/templates/home.html +++ b/example2/polls/templates/home.html @@ -1,4 +1,4 @@ -{% extends "admin2/bootstrap/base.html" %} +{% extends "djadmin2/bootstrap/base.html" %} {% block content %}

    Example Home

    From ee4dfb4ac6b5074d0fbdd321557e3d592b01f8a3 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 15:19:22 +0200 Subject: [PATCH 52/58] =?UTF-8?q?Added=20Catal=C3=A0=20translation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- djadmin2/locale/ca/LC_MESSAGES/django.po | 226 +++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 djadmin2/locale/ca/LC_MESSAGES/django.po diff --git a/djadmin2/locale/ca/LC_MESSAGES/django.po b/djadmin2/locale/ca/LC_MESSAGES/django.po new file mode 100644 index 0000000..3544e67 --- /dev/null +++ b/djadmin2/locale/ca/LC_MESSAGES/django.po @@ -0,0 +1,226 @@ +# This file is distributed under the same license as the django-admin2 package. +# +# Translators: +# Ignasi Fosch Alonso , 2013. +msgid "" +msgstr "" +"Project-Id-Version: django-admin2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-06 15:02+0200\n" +"PO-Revision-Date: 2013-07-06 14:47+0200\n" +"Last-Translator: Ignasi Fosch Alonso \n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/" +"ca/\n" +"Language: ca\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" + +#: actions.py:26 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: actions.py:29 +#, python-format +msgid "Successfully deleted %(count)s %(items)s" +msgstr "" + +#: actions.py:127 +msgid "Delete selected items" +msgstr "" + +#: forms.py:238 +#, python-format +msgid "" +"Please enter the correct %(username)s and password for a staff account. Note " +"that both fields may be case-sensitive." +msgstr "" + +#: forms.py:249 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 +#: templates/admin2/bootstrap/includes/app_model_list.html:38 +msgid "Change" +msgstr "" + +#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +msgid "Add" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:6 +#: templates/admin2/bootstrap/base.html:55 +#: templates/admin2/bootstrap/model_confirm_delete.html:10 +#: templates/admin2/bootstrap/model_detail.html:11 +#: templates/admin2/bootstrap/model_list.html:14 +#: templates/admin2/bootstrap/model_update_form.html:11 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/admin2/bootstrap/auth/logout.html:8 +#: templates/admin2/bootstrap/auth/password_change_done.html:11 +#: templates/admin2/bootstrap/auth/password_change_form.html:10 +msgid "Home" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:12 +#, python-format +msgid "%(app_label)s administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:6 +#: templates/admin2/bootstrap/base.html:71 +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Site administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:22 +msgid "API" +msgstr "" + +#: templates/admin2/bootstrap/base.html:25 +msgid "Documentation" +msgstr "" + +#: templates/admin2/bootstrap/base.html:34 +#, python-format +msgid "Logged in as %(user)s" +msgstr "" + +#: templates/admin2/bootstrap/base.html:40 +msgid "Change password" +msgstr "" + +#: templates/admin2/bootstrap/base.html:42 +#: templates/admin2/bootstrap/auth/logout.html:11 +msgid "Log out" +msgstr "" + +#: templates/admin2/bootstrap/index.html:13 +msgid "Recent Actions" +msgstr "" + +#: templates/admin2/bootstrap/index.html:14 +msgid "My Actions" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:4 +#: templates/admin2/bootstrap/model_confirm_delete.html:6 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +msgid "Are you sure?" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:25 +#: templates/admin2/bootstrap/model_update_form.html:74 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +msgid "Delete" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#, python-format +msgid "" +"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " +"the following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:40 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:4 +#: templates/admin2/bootstrap/model_list.html:6 +#, python-format +msgid "Select %(model_name)s to change" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:31 +msgid "Search Term" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:32 +msgid "Search" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:59 +#, python-format +msgid "%(selected)s of %(total)s selected" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:63 +#, python-format +msgid "Add %(model_verbose_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:5 +#: templates/admin2/bootstrap/model_update_form.html:7 +#, python-format +msgid "%(action)s %(model_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:78 +msgid "Save and add another" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:79 +msgid "Save and continue editing" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:80 +msgid "Save" +msgstr "" + +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:15 +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:27 +#: templates/admin2/bootstrap/auth/password_change_form.html:24 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" +msgstr[1] "" + +#: templates/admin2/bootstrap/auth/logout.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:18 +msgid "Log in again" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:6 +#: templates/admin2/bootstrap/auth/password_change_done.html:7 +#: templates/admin2/bootstrap/auth/password_change_done.html:14 +msgid "Password change successful" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:20 +msgid "Your password was changed." +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:6 +#: templates/admin2/bootstrap/auth/password_change_form.html:13 +msgid "Password change" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:20 +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 "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:31 +msgid "Change my password" +msgstr "" From 6af02f448947afde1baa3f65d4f630cdc0bc8bdb Mon Sep 17 00:00:00 2001 From: Daniel Greenfeld Date: Sat, 6 Jul 2013 15:20:49 +0200 Subject: [PATCH 53/58] Update AUTHORS.rst --- AUTHORS.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 715182d..bdbeee7 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -5,6 +5,12 @@ Project Lead * Daniel Greenfeld (@pydanny / ) +Translation Managers +==================== + +* Henri Colas (@NotSqrt) +* Danilo Bargen (@dbrgn) + Developers ============= From 9f449a6b66888d21c1b8515dde8cc00cdaf6b440 Mon Sep 17 00:00:00 2001 From: bootandy Date: Sat, 6 Jul 2013 15:23:08 +0200 Subject: [PATCH 54/58] moving templates to djadmin --- djadmin2/locale/en/LC_MESSAGES/django.po | 122 +++++++++--------- djadmin2/locale/fr/LC_MESSAGES/django.po | 122 +++++++++--------- .../djadmin2/bootstrap/app_index.html | 2 +- .../templates/djadmin2/bootstrap/index.html | 2 +- 4 files changed, 124 insertions(+), 124 deletions(-) diff --git a/djadmin2/locale/en/LC_MESSAGES/django.po b/djadmin2/locale/en/LC_MESSAGES/django.po index c0b0dc9..497a7ce 100644 --- a/djadmin2/locale/en/LC_MESSAGES/django.po +++ b/djadmin2/locale/en/LC_MESSAGES/django.po @@ -45,82 +45,82 @@ msgstr "" msgid "Please log in again, because your session has expired." msgstr "Please log in again, because your session has expired." -#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 -#: templates/admin2/bootstrap/includes/app_model_list.html:38 +#: views.py:165 templates/djadmin2/bootstrap/model_update_form.html:29 +#: templates/djadmin2/bootstrap/includes/app_model_list.html:38 msgid "Change" msgstr "Change" -#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +#: views.py:179 templates/djadmin2/bootstrap/includes/app_model_list.html:30 msgid "Add" msgstr "Add" -#: templates/admin2/bootstrap/app_index.html:6 -#: templates/admin2/bootstrap/base.html:55 -#: templates/admin2/bootstrap/model_confirm_delete.html:10 -#: templates/admin2/bootstrap/model_detail.html:11 -#: templates/admin2/bootstrap/model_list.html:14 -#: templates/admin2/bootstrap/model_update_form.html:11 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 -#: templates/admin2/bootstrap/auth/logout.html:8 -#: templates/admin2/bootstrap/auth/password_change_done.html:11 -#: templates/admin2/bootstrap/auth/password_change_form.html:10 +#: templates/djadmin2/bootstrap/app_index.html:6 +#: templates/djadmin2/bootstrap/base.html:55 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:10 +#: templates/djadmin2/bootstrap/model_detail.html:11 +#: templates/djadmin2/bootstrap/model_list.html:14 +#: templates/djadmin2/bootstrap/model_update_form.html:11 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/djadmin2/bootstrap/auth/logout.html:8 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:11 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:10 msgid "Home" msgstr "Home" -#: templates/admin2/bootstrap/app_index.html:12 +#: templates/djadmin2/bootstrap/app_index.html:12 #, python-format msgid "%(app_label)s administration" msgstr "%(app_label)s administration" -#: templates/admin2/bootstrap/base.html:6 -#: templates/admin2/bootstrap/base.html:71 -#: templates/admin2/bootstrap/auth/login.html:15 +#: templates/djadmin2/bootstrap/base.html:6 +#: templates/djadmin2/bootstrap/base.html:71 +#: templates/djadmin2/bootstrap/auth/login.html:15 msgid "Site administration" msgstr "Site administration" -#: templates/admin2/bootstrap/base.html:22 +#: templates/djadmin2/bootstrap/base.html:22 msgid "API" msgstr "API" -#: templates/admin2/bootstrap/base.html:25 +#: templates/djadmin2/bootstrap/base.html:25 msgid "Documentation" msgstr "Documentation" -#: templates/admin2/bootstrap/base.html:34 +#: templates/djadmin2/bootstrap/base.html:34 #, python-format msgid "Logged in as %(user)s" msgstr "Logged in as %(user)s" -#: templates/admin2/bootstrap/base.html:40 +#: templates/djadmin2/bootstrap/base.html:40 msgid "Change password" msgstr "Change password" -#: templates/admin2/bootstrap/base.html:42 +#: templates/djadmin2/bootstrap/base.html:42 msgid "Log out" msgstr "Log out" -#: templates/admin2/bootstrap/index.html:13 +#: templates/djadmin2/bootstrap/index.html:13 msgid "Recent Actions" msgstr "Recent Actions" -#: templates/admin2/bootstrap/index.html:14 +#: templates/djadmin2/bootstrap/index.html:14 msgid "My Actions" msgstr "My Actions" -#: templates/admin2/bootstrap/model_confirm_delete.html:4 -#: templates/admin2/bootstrap/model_confirm_delete.html:6 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:4 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:6 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:6 msgid "Are you sure?" msgstr "Are you sure?" -#: templates/admin2/bootstrap/model_confirm_delete.html:25 -#: templates/admin2/bootstrap/model_update_form.html:74 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:25 +#: templates/djadmin2/bootstrap/model_update_form.html:74 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:21 msgid "Delete" msgstr "Delete" -#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:30 #, python-format msgid "" "Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " @@ -129,54 +129,54 @@ msgstr "" "Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " "the following items will be deleted:" -#: templates/admin2/bootstrap/model_confirm_delete.html:40 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:40 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:40 msgid "Yes, I'm sure" msgstr "Yes, I'm sure" -#: templates/admin2/bootstrap/model_list.html:4 -#: templates/admin2/bootstrap/model_list.html:6 +#: templates/djadmin2/bootstrap/model_list.html:4 +#: templates/djadmin2/bootstrap/model_list.html:6 #, python-format msgid "Select %(model_name)s to change" msgstr "Select %(model_name)s to change" -#: templates/admin2/bootstrap/model_list.html:31 +#: templates/djadmin2/bootstrap/model_list.html:31 msgid "Search Term" msgstr "Search Term" -#: templates/admin2/bootstrap/model_list.html:32 +#: templates/djadmin2/bootstrap/model_list.html:32 msgid "Search" msgstr "Search" -#: templates/admin2/bootstrap/model_list.html:59 +#: templates/djadmin2/bootstrap/model_list.html:59 #, python-format msgid "%(selected)s of %(total)s selected" msgstr "%(selected)s of %(total)s selected" -#: templates/admin2/bootstrap/model_list.html:63 +#: templates/djadmin2/bootstrap/model_list.html:63 #, python-format msgid "Add %(model_verbose_name)s" msgstr "Add %(model_verbose_name)s" -#: templates/admin2/bootstrap/model_update_form.html:5 -#: templates/admin2/bootstrap/model_update_form.html:7 +#: templates/djadmin2/bootstrap/model_update_form.html:5 +#: templates/djadmin2/bootstrap/model_update_form.html:7 #, python-format msgid "%(action)s %(model_name)s" msgstr "%(action)s %(model_name)s" -#: templates/admin2/bootstrap/model_update_form.html:78 +#: templates/djadmin2/bootstrap/model_update_form.html:78 msgid "Save and add another" msgstr "Save and add another" -#: templates/admin2/bootstrap/model_update_form.html:79 +#: templates/djadmin2/bootstrap/model_update_form.html:79 msgid "Save and continue editing" msgstr "Save and continue editing" -#: templates/admin2/bootstrap/model_update_form.html:80 +#: templates/djadmin2/bootstrap/model_update_form.html:80 msgid "Save" msgstr "Save" -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:27 #, python-format msgid "" "Are you sure you want to delete the selected %(objects_name)s? All of the " @@ -185,49 +185,49 @@ msgstr "" "Are you sure you want to delete the selected %(objects_name)s? All of the " "following items will be deleted:" -#: templates/admin2/bootstrap/auth/login.html:15 +#: templates/djadmin2/bootstrap/auth/login.html:15 msgid "Login" msgstr "Login" -#: templates/admin2/bootstrap/auth/login.html:27 -#: templates/admin2/bootstrap/auth/password_change_form.html:24 +#: templates/djadmin2/bootstrap/auth/login.html:27 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:24 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Please correct the error below." msgstr[1] "Please correct the errors below." -#: templates/admin2/bootstrap/auth/login.html:52 +#: templates/djadmin2/bootstrap/auth/login.html:52 msgid "Log in" msgstr "Log in" -#: templates/admin2/bootstrap/auth/logout.html:11 +#: templates/djadmin2/bootstrap/auth/logout.html:11 msgid "Logout" msgstr "Logout" -#: templates/admin2/bootstrap/auth/logout.html:17 +#: templates/djadmin2/bootstrap/auth/logout.html:17 msgid "Thanks for spending some quality time with the Web site today." msgstr "Thanks for spending some quality time with the Web site today." -#: templates/admin2/bootstrap/auth/logout.html:18 +#: templates/djadmin2/bootstrap/auth/logout.html:18 msgid "Log in again" msgstr "Log in again" -#: templates/admin2/bootstrap/auth/password_change_done.html:6 -#: templates/admin2/bootstrap/auth/password_change_done.html:7 -#: templates/admin2/bootstrap/auth/password_change_done.html:14 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:6 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:7 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:14 msgid "Password change successful" msgstr "Password change successful" -#: templates/admin2/bootstrap/auth/password_change_done.html:20 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:20 msgid "Your password was changed." msgstr "Your password was changed." -#: templates/admin2/bootstrap/auth/password_change_form.html:6 -#: templates/admin2/bootstrap/auth/password_change_form.html:13 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:6 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:13 msgid "Password change" msgstr "Password change" -#: templates/admin2/bootstrap/auth/password_change_form.html:20 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:20 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." @@ -235,6 +235,6 @@ msgstr "" "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." -#: templates/admin2/bootstrap/auth/password_change_form.html:31 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:31 msgid "Change my password" msgstr "Change my password" diff --git a/djadmin2/locale/fr/LC_MESSAGES/django.po b/djadmin2/locale/fr/LC_MESSAGES/django.po index bf3da9d..0d1d269 100644 --- a/djadmin2/locale/fr/LC_MESSAGES/django.po +++ b/djadmin2/locale/fr/LC_MESSAGES/django.po @@ -48,82 +48,82 @@ msgstr "" msgid "Please log in again, because your session has expired." msgstr "Reconnectez-vous car votre session a expiré." -#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 -#: templates/admin2/bootstrap/includes/app_model_list.html:38 +#: views.py:165 templates/djadmin2/bootstrap/model_update_form.html:29 +#: templates/djadmin2/bootstrap/includes/app_model_list.html:38 msgid "Change" msgstr "Modifier" -#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +#: views.py:179 templates/djadmin2/bootstrap/includes/app_model_list.html:30 msgid "Add" msgstr "Ajouter" -#: templates/admin2/bootstrap/app_index.html:6 -#: templates/admin2/bootstrap/base.html:55 -#: templates/admin2/bootstrap/model_confirm_delete.html:10 -#: templates/admin2/bootstrap/model_detail.html:11 -#: templates/admin2/bootstrap/model_list.html:14 -#: templates/admin2/bootstrap/model_update_form.html:11 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 -#: templates/admin2/bootstrap/auth/logout.html:8 -#: templates/admin2/bootstrap/auth/password_change_done.html:11 -#: templates/admin2/bootstrap/auth/password_change_form.html:10 +#: templates/djadmin2/bootstrap/app_index.html:6 +#: templates/djadmin2/bootstrap/base.html:55 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:10 +#: templates/djadmin2/bootstrap/model_detail.html:11 +#: templates/djadmin2/bootstrap/model_list.html:14 +#: templates/djadmin2/bootstrap/model_update_form.html:11 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/djadmin2/bootstrap/auth/logout.html:8 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:11 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:10 msgid "Home" msgstr "Accueil" -#: templates/admin2/bootstrap/app_index.html:12 +#: templates/djadmin2/bootstrap/app_index.html:12 #, python-format msgid "%(app_label)s administration" msgstr "Administration de %(app_label)s" -#: templates/admin2/bootstrap/base.html:6 -#: templates/admin2/bootstrap/base.html:71 -#: templates/admin2/bootstrap/auth/login.html:15 +#: templates/djadmin2/bootstrap/base.html:6 +#: templates/djadmin2/bootstrap/base.html:71 +#: templates/djadmin2/bootstrap/auth/login.html:15 msgid "Site administration" msgstr "Administration du site" -#: templates/admin2/bootstrap/base.html:22 +#: templates/djadmin2/bootstrap/base.html:22 msgid "API" msgstr "API" -#: templates/admin2/bootstrap/base.html:25 +#: templates/djadmin2/bootstrap/base.html:25 msgid "Documentation" msgstr "Documentation" -#: templates/admin2/bootstrap/base.html:34 +#: templates/djadmin2/bootstrap/base.html:34 #, python-format msgid "Logged in as %(user)s" msgstr "Connecté en tant que %(user)s" -#: templates/admin2/bootstrap/base.html:40 +#: templates/djadmin2/bootstrap/base.html:40 msgid "Change password" msgstr "Modifier votre mot de passe" -#: templates/admin2/bootstrap/base.html:42 +#: templates/djadmin2/bootstrap/base.html:42 msgid "Log out" msgstr "Déconnexion" -#: templates/admin2/bootstrap/index.html:13 +#: templates/djadmin2/bootstrap/index.html:13 msgid "Recent Actions" msgstr "Actions récentes" -#: templates/admin2/bootstrap/index.html:14 +#: templates/djadmin2/bootstrap/index.html:14 msgid "My Actions" msgstr "Mes actions" -#: templates/admin2/bootstrap/model_confirm_delete.html:4 -#: templates/admin2/bootstrap/model_confirm_delete.html:6 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:4 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:6 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:6 msgid "Are you sure?" msgstr "Êtes-vous sûr ?" -#: templates/admin2/bootstrap/model_confirm_delete.html:25 -#: templates/admin2/bootstrap/model_update_form.html:74 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:25 +#: templates/djadmin2/bootstrap/model_update_form.html:74 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:21 msgid "Delete" msgstr "Supprimer" -#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:30 #, python-format msgid "" "Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " @@ -132,54 +132,54 @@ msgstr "" "Voulez-vous vraiment supprimer l'objet %(model_name)s « %(object)s » ? Les " "éléments suivants seront supprimés :" -#: templates/admin2/bootstrap/model_confirm_delete.html:40 -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +#: templates/djadmin2/bootstrap/model_confirm_delete.html:40 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:40 msgid "Yes, I'm sure" msgstr "Oui, je suis sûr" -#: templates/admin2/bootstrap/model_list.html:4 -#: templates/admin2/bootstrap/model_list.html:6 +#: templates/djadmin2/bootstrap/model_list.html:4 +#: templates/djadmin2/bootstrap/model_list.html:6 #, python-format msgid "Select %(model_name)s to change" msgstr "Sélectionnez l'objet %(model_name)s à modifier" -#: templates/admin2/bootstrap/model_list.html:31 +#: templates/djadmin2/bootstrap/model_list.html:31 msgid "Search Term" msgstr "Terme à rechercher" -#: templates/admin2/bootstrap/model_list.html:32 +#: templates/djadmin2/bootstrap/model_list.html:32 msgid "Search" msgstr "Recherche" -#: templates/admin2/bootstrap/model_list.html:59 +#: templates/djadmin2/bootstrap/model_list.html:59 #, python-format msgid "%(selected)s of %(total)s selected" msgstr "%(selected)s sur %(total)s sélectionnés" -#: templates/admin2/bootstrap/model_list.html:63 +#: templates/djadmin2/bootstrap/model_list.html:63 #, python-format msgid "Add %(model_verbose_name)s" msgstr "Ajouter %(model_verbose_name)s" -#: templates/admin2/bootstrap/model_update_form.html:5 -#: templates/admin2/bootstrap/model_update_form.html:7 +#: templates/djadmin2/bootstrap/model_update_form.html:5 +#: templates/djadmin2/bootstrap/model_update_form.html:7 #, python-format msgid "%(action)s %(model_name)s" msgstr "%(action)s %(model_name)s" -#: templates/admin2/bootstrap/model_update_form.html:78 +#: templates/djadmin2/bootstrap/model_update_form.html:78 msgid "Save and add another" msgstr "Enregistrer et ajouter un nouveau" -#: templates/admin2/bootstrap/model_update_form.html:79 +#: templates/djadmin2/bootstrap/model_update_form.html:79 msgid "Save and continue editing" msgstr "Enregistrer et continuer les modifications" -#: templates/admin2/bootstrap/model_update_form.html:80 +#: templates/djadmin2/bootstrap/model_update_form.html:80 msgid "Save" msgstr "Enregistrer" -#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#: templates/djadmin2/bootstrap/actions/delete_selected_confirmation.html:27 #, python-format msgid "" "Are you sure you want to delete the selected %(objects_name)s? All of the " @@ -188,49 +188,49 @@ msgstr "" "Voulez-vous vraiment supprimer les objets %(objects_name)s sélectionnés ? " "Les éléments suivants seront supprimés :" -#: templates/admin2/bootstrap/auth/login.html:15 +#: templates/djadmin2/bootstrap/auth/login.html:15 msgid "Login" msgstr "Connexion" -#: templates/admin2/bootstrap/auth/login.html:27 -#: templates/admin2/bootstrap/auth/password_change_form.html:24 +#: templates/djadmin2/bootstrap/auth/login.html:27 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:24 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Corrigez l'erreur suivante." msgstr[1] "Corrigez les erreurs suivantes." -#: templates/admin2/bootstrap/auth/login.html:52 +#: templates/djadmin2/bootstrap/auth/login.html:52 msgid "Log in" msgstr "Connexion" -#: templates/admin2/bootstrap/auth/logout.html:11 +#: templates/djadmin2/bootstrap/auth/logout.html:11 msgid "Logout" msgstr "Déconnexion" -#: templates/admin2/bootstrap/auth/logout.html:17 +#: templates/djadmin2/bootstrap/auth/logout.html:17 msgid "Thanks for spending some quality time with the Web site today." msgstr "Merci pour le temps que vous avez accordé à ce site aujourd'hui." -#: templates/admin2/bootstrap/auth/logout.html:18 +#: templates/djadmin2/bootstrap/auth/logout.html:18 msgid "Log in again" msgstr "Connectez-vous à nouveau" -#: templates/admin2/bootstrap/auth/password_change_done.html:6 -#: templates/admin2/bootstrap/auth/password_change_done.html:7 -#: templates/admin2/bootstrap/auth/password_change_done.html:14 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:6 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:7 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:14 msgid "Password change successful" msgstr "Mot de passe modifié avec succès" -#: templates/admin2/bootstrap/auth/password_change_done.html:20 +#: templates/djadmin2/bootstrap/auth/password_change_done.html:20 msgid "Your password was changed." msgstr "Votre mot de passe a été modifié." -#: templates/admin2/bootstrap/auth/password_change_form.html:6 -#: templates/admin2/bootstrap/auth/password_change_form.html:13 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:6 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:13 msgid "Password change" msgstr "Modification de votre mot de passe" -#: templates/admin2/bootstrap/auth/password_change_form.html:20 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:20 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." @@ -239,6 +239,6 @@ msgstr "" "nouveau mot de passe à deux reprises afin de vérifier qu'il est correctement " "saisi." -#: templates/admin2/bootstrap/auth/password_change_form.html:31 +#: templates/djadmin2/bootstrap/auth/password_change_form.html:31 msgid "Change my password" msgstr "Modifier mon mot de passe" diff --git a/djadmin2/templates/djadmin2/bootstrap/app_index.html b/djadmin2/templates/djadmin2/bootstrap/app_index.html index 07c5e21..26b50a9 100644 --- a/djadmin2/templates/djadmin2/bootstrap/app_index.html +++ b/djadmin2/templates/djadmin2/bootstrap/app_index.html @@ -14,7 +14,7 @@ {% block content %}
    - {% include 'admin2/bootstrap/includes/app_model_list.html' %} + {% include 'djadmin2/bootstrap/includes/app_model_list.html' %}
    {% endblock content %} diff --git a/djadmin2/templates/djadmin2/bootstrap/index.html b/djadmin2/templates/djadmin2/bootstrap/index.html index fc78ac6..175927a 100644 --- a/djadmin2/templates/djadmin2/bootstrap/index.html +++ b/djadmin2/templates/djadmin2/bootstrap/index.html @@ -6,7 +6,7 @@
    {% for app_label, registry in apps.items %} - {% include 'admin2/bootstrap/includes/app_model_list.html' %} + {% include 'djadmin2/bootstrap/includes/app_model_list.html' %} {% endfor %}
    From 673a3027dd8c4661f3700bc5bcf7e59a31e6204d Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 15:27:19 +0200 Subject: [PATCH 55/58] Added Italian translation file --- djadmin2/locale/it/LC_MESSAGES/django.po | 226 +++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 djadmin2/locale/it/LC_MESSAGES/django.po diff --git a/djadmin2/locale/it/LC_MESSAGES/django.po b/djadmin2/locale/it/LC_MESSAGES/django.po new file mode 100644 index 0000000..a29e56b --- /dev/null +++ b/djadmin2/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,226 @@ +# This file is distributed under the same license as the django-admin2 package. +# +# Translators: +# Margherita Zamponi +msgid "" +msgstr "" +"Project-Id-Version: django-admin2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-06 15:02+0200\n" +"PO-Revision-Date: 2013-07-06 14:47+0200\n" +"Last-Translator: Margherita Zamponi \n" +"Language-Team: https://www.transifex.com/projects/p/django-admin2/language/" +"it/\n" +"Language: it\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" + +#: actions.py:26 +msgid "" +"Items must be selected in order to perform actions on them. No items have " +"been changed." +msgstr "" + +#: actions.py:29 +#, python-format +msgid "Successfully deleted %(count)s %(items)s" +msgstr "" + +#: actions.py:127 +msgid "Delete selected items" +msgstr "" + +#: forms.py:238 +#, python-format +msgid "" +"Please enter the correct %(username)s and password for a staff account. Note " +"that both fields may be case-sensitive." +msgstr "" + +#: forms.py:249 +msgid "Please log in again, because your session has expired." +msgstr "" + +#: views.py:165 templates/admin2/bootstrap/model_update_form.html:29 +#: templates/admin2/bootstrap/includes/app_model_list.html:38 +msgid "Change" +msgstr "" + +#: views.py:179 templates/admin2/bootstrap/includes/app_model_list.html:30 +msgid "Add" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:6 +#: templates/admin2/bootstrap/base.html:55 +#: templates/admin2/bootstrap/model_confirm_delete.html:10 +#: templates/admin2/bootstrap/model_detail.html:11 +#: templates/admin2/bootstrap/model_list.html:14 +#: templates/admin2/bootstrap/model_update_form.html:11 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:10 +#: templates/admin2/bootstrap/auth/logout.html:8 +#: templates/admin2/bootstrap/auth/password_change_done.html:11 +#: templates/admin2/bootstrap/auth/password_change_form.html:10 +msgid "Home" +msgstr "" + +#: templates/admin2/bootstrap/app_index.html:12 +#, python-format +msgid "%(app_label)s administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:6 +#: templates/admin2/bootstrap/base.html:71 +#: templates/admin2/bootstrap/auth/login.html:15 +msgid "Site administration" +msgstr "" + +#: templates/admin2/bootstrap/base.html:22 +msgid "API" +msgstr "" + +#: templates/admin2/bootstrap/base.html:25 +msgid "Documentation" +msgstr "" + +#: templates/admin2/bootstrap/base.html:34 +#, python-format +msgid "Logged in as %(user)s" +msgstr "" + +#: templates/admin2/bootstrap/base.html:40 +msgid "Change password" +msgstr "" + +#: templates/admin2/bootstrap/base.html:42 +#: templates/admin2/bootstrap/auth/logout.html:11 +msgid "Log out" +msgstr "" + +#: templates/admin2/bootstrap/index.html:13 +msgid "Recent Actions" +msgstr "" + +#: templates/admin2/bootstrap/index.html:14 +msgid "My Actions" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:4 +#: templates/admin2/bootstrap/model_confirm_delete.html:6 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:4 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:6 +msgid "Are you sure?" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:25 +#: templates/admin2/bootstrap/model_update_form.html:74 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:21 +msgid "Delete" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:30 +#, python-format +msgid "" +"Are you sure you want to delete the %(model_name)s \"%(object)s\"? All of " +"the following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/model_confirm_delete.html:40 +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:40 +msgid "Yes, I'm sure" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:4 +#: templates/admin2/bootstrap/model_list.html:6 +#, python-format +msgid "Select %(model_name)s to change" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:31 +msgid "Search Term" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:32 +msgid "Search" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:59 +#, python-format +msgid "%(selected)s of %(total)s selected" +msgstr "" + +#: templates/admin2/bootstrap/model_list.html:63 +#, python-format +msgid "Add %(model_verbose_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:5 +#: templates/admin2/bootstrap/model_update_form.html:7 +#, python-format +msgid "%(action)s %(model_name)s" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:78 +msgid "Save and add another" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:79 +msgid "Save and continue editing" +msgstr "" + +#: templates/admin2/bootstrap/model_update_form.html:80 +msgid "Save" +msgstr "" + +#: templates/admin2/bootstrap/actions/delete_selected_confirmation.html:27 +#, python-format +msgid "" +"Are you sure you want to delete the selected %(objects_name)s? All of the " +"following items will be deleted:" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:15 +#: templates/admin2/bootstrap/auth/login.html:52 +msgid "Log in" +msgstr "" + +#: templates/admin2/bootstrap/auth/login.html:27 +#: templates/admin2/bootstrap/auth/password_change_form.html:24 +msgid "Please correct the error below." +msgid_plural "Please correct the errors below." +msgstr[0] "" +msgstr[1] "" + +#: templates/admin2/bootstrap/auth/logout.html:17 +msgid "Thanks for spending some quality time with the Web site today." +msgstr "" + +#: templates/admin2/bootstrap/auth/logout.html:18 +msgid "Log in again" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:6 +#: templates/admin2/bootstrap/auth/password_change_done.html:7 +#: templates/admin2/bootstrap/auth/password_change_done.html:14 +msgid "Password change successful" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_done.html:20 +msgid "Your password was changed." +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:6 +#: templates/admin2/bootstrap/auth/password_change_form.html:13 +msgid "Password change" +msgstr "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:20 +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 "" + +#: templates/admin2/bootstrap/auth/password_change_form.html:31 +msgid "Change my password" +msgstr "" From 09201f8fbab3ba4d1956bc1c2c4288176164f7a5 Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Sat, 6 Jul 2013 15:39:27 +0200 Subject: [PATCH 56/58] Added translators to AUTHORS --- AUTHORS.rst | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index bdbeee7..5433008 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -1,18 +1,19 @@ CONTRIBUTORS +============ Project Lead -=============== +------------ * Daniel Greenfeld (@pydanny / ) Translation Managers -==================== +-------------------- * Henri Colas (@NotSqrt) * Danilo Bargen (@dbrgn) Developers -============= +---------- * Audrey Roy (@audreyr) * Peter Ingelsby (@inglesp) @@ -39,3 +40,11 @@ Developers * Ignasi Fosch Alonso (@ifosch) * Henri Colas (@NotSqrt) * Andy Boot (@bootandy) + +Translators +----------- + +* Henri Colas (@NotSqrt) +* Danilo Bargen (@dbrgn) +* Ignasi Fosch Alonso (@ifosch) +* Margherita Zamponi (@Margherita-) From 61ce055e70e2afdb4b2d0a2c81027da4d6e5a128 Mon Sep 17 00:00:00 2001 From: NotSqrt Date: Sat, 6 Jul 2013 15:43:56 +0200 Subject: [PATCH 57/58] doc on internationalization --- docs/index.rst | 1 + docs/internationalization.rst | 83 +++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 docs/internationalization.rst diff --git a/docs/index.rst b/docs/index.rst index 4bc32fc..e20f701 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -64,6 +64,7 @@ Content contributing design tutorial + internationalization Reference ----------- diff --git a/docs/internationalization.rst b/docs/internationalization.rst new file mode 100644 index 0000000..f904dd2 --- /dev/null +++ b/docs/internationalization.rst @@ -0,0 +1,83 @@ +===================================== +Internationalization and localization +===================================== + +.. index:: internationalization + +Refer to the `Django i18n documentation`_ to get started. + +.. _`Django i18n documentation`: https://docs.djangoproject.com/en/dev/topics/i18n/ + + +Using internationalization in your project +========================================== + +Make sure you've activated translation for your project +(the fastest way is to check in your ``settings.py`` file if ``MIDDLEWARE_CLASSES`` includes +``django.middleware.locale.LocaleMiddleware``). + +Then compile the messages so they can be used by Django. + +.. code-block:: bash + + python manage.py compilemessages + + +It should get you started ! + +Contributing to localization +============================ + +Django-admin2 has adopted `Transifex`_ to manage the localization process, `join and +help us`_ making django-admin2 available for everyone ! + +.. _Transifex: https://www.transifex.com +.. _`join and help us`: https://www.transifex.com/projects/p/django-admin2/ + + +Using internationalization in the django-admin2 project development +=================================================================== + +Internationalization +-------------------- + +Python code +########### + +Make sure to use ugettext or ugettext_lazy on strings that will be shown to the users, +with string interpolation ( "%(name_of_variable)s" instead of "%s" ) where needed. + +Remember that all languages do not use the same word order, so try to provide flexible strings to translate ! + +Templates +######### + +Make sure to load the i18n tags and put ``trans`` tags and ``blocktrans`` blocks where needed. + +Block variables are very useful to keep the strings simple. + +Adding a new locale +------------------- + +.. code-block:: bash + + cd djadmin2 + django-admin.py makemessages -l $LOCALE_CODE + +A new file will be created under ``locale/$LOCALE_CODE/LC_MESSAGES/django.po`` + +Update the headers of the newly created file to match existing files and start the translation ! + + +Updating existing locales +------------------------- + +.. code-block:: bash + + cd djadmin2 # or any other package, for instance example/blog + django-admin.py makemessages -a + + # update the translations + # make sure to fix all fuzzy translations + + django-admin.py compilemessages From a8cf4554ad9eb81e1b660b42ea29f12d3090048c Mon Sep 17 00:00:00 2001 From: bootandy Date: Sat, 6 Jul 2013 15:56:46 +0200 Subject: [PATCH 58/58] more example template admin2 reference to djadmin2 --- .../bootstrap/actions/publish_selected_items.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename example/blog/templates/{admin2 => djadmin2}/bootstrap/actions/publish_selected_items.html (100%) diff --git a/example/blog/templates/admin2/bootstrap/actions/publish_selected_items.html b/example/blog/templates/djadmin2/bootstrap/actions/publish_selected_items.html similarity index 100% rename from example/blog/templates/admin2/bootstrap/actions/publish_selected_items.html rename to example/blog/templates/djadmin2/bootstrap/actions/publish_selected_items.html
  • - Home + {% trans "Home" %} /
  • +
    +

    Example.com

    -
    +

    Imagine that this is a real site

    + +

    Pretend that this is the homepage of a big Django site.

    + +

    Imagine lots of things are here:

    +
      +
    • A blog
    • +
    • Comments
    • +
    • And so on...
    • +
    + +

    In other words, these are items that we can introspect through the Django admin.

    + +

    Under the hood

    + +

    Now, explore the Django admin for example.com. Click on either of the following:

    +
    +