Merge remote-tracking branch 'upstream/master' into fixbug-1298

This commit is contained in:
Alex Gleason 2015-09-11 11:09:28 -05:00
commit fce071d64e
667 changed files with 15247 additions and 6780 deletions

View file

@ -1,7 +0,0 @@
image: wagtail-ci
script:
- python3.4 setup.py install
- pip3.4 install -r requirements-dev.txt
- python3.4 runtests.py --keepdb
env:
- DATABASE_NAME=/base-dbs/wagtail.v1.0.sqlite

View file

@ -1,5 +1,8 @@
language: python
# Use container-based infrastructure
sudo: false
matrix:
include:
- env: TOXENV=py27-dj17-postgres

View file

@ -66,3 +66,15 @@ file_filter = wagtail/wagtailsites/locale/<lang>/LC_MESSAGES/django.po
source_file = wagtail/wagtailsites/locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO
[wagtail.wagtailsearchpromotions]
file_filter = wagtail/contrib/wagtailsearchpromotions/locale/<lang>/LC_MESSAGES/django.po
source_file = wagtail/contrib/wagtailsearchpromotions/locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO
[wagtail.wagtailstyleguide]
file_filter = wagtail/contrib/wagtailstyleguide/locale/<lang>/LC_MESSAGES/django.po
source_file = wagtail/contrib/wagtailstyleguide/locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO

View file

@ -1,13 +1,22 @@
Changelog
=========
1.2 (xx.xx.xxxx)
~~~~~~~~~~~~~~~~
* Fix: Deleting a page permission from the groups admin UI does not immediately submit the form
1.1 (xx.xx.xxxx)
~~~~~~~~~~~~~~~~
* Implemented the `specific()` method on PageQuerySet, to return pages as their most specific type
* "Promoted search results" has moved into its own module
* Elasticsearch backend now supports an experimental `ATOMIC_REBUILD` flag to keep the existing index available while the `update_index` task is running
* The wagtailapi module has been refactored to use Django REST Framework
* The wagtailapi module has been refactored to use Django REST Framework (Tom Christie)
* A number of permissions fixes have been made to the Wagtail admin interface. See release notes for a list of specific changes made.
* Snippets that inherit from `wagtail.wagtailsearch.index.Indexed` now appear as searchable within the Wagtail admin
* Implemented deletion of form submissions (Kyungil Choi)
* Implemented pagination in the page chooser modal
* Changed INSTALLED_APPS in project template to list apps in precedence order (Piet Delport)
* The `{% image %}` tag now supports filters on the image variable, e.g. `{% image primary_img|default:secondary_img width-500 %}`
@ -17,11 +26,33 @@ Changelog
* Added optional directory argument to "wagtail start" command (Mitchel Cabuloy)
* Non-superusers can now view/edit/delete sites if they have the correct permissions
* Image file size is now stored in the database, to avoid unnecessary filesystem lookups
* Page URL lookups hit the cache/database less often (Michael van Tellingen)
* Updated URLs within the admin backend to use namespaces
* The `update_index` task now indexes objects in batches of 1000, to indicate progress and avoid excessive memory use
* Added database indexes on PageRevision and Image to improve performance on large sites
* Search in page chooser now uses Wagtail's search framework, to order results by relevance
* `PageChooserPanel` now supports passing a list (or tuple) of accepted page types
* The snippet type parameter of `SnippetChooserPanel` can now be omitted, or passed as a model name string rather than a model class (Joss Ingram)
* Added aliases for the `self` template variable to accommodate Jinja as a templating engine: `page` for pages, `field_panel` for field panels / edit handlers, and `value` for blocks
* Added signposting text to the explorer to steer editors away from creating pages at the root level unless they are setting up new sites
* "Clear choice" and "Edit this page" buttons are no longer shown on the page field of the group page permissions form
* Altered styling of stream controls to be more like all other buttons
* Added ability to mark page models as not available for creation using the flag `is_creatable`; pages that are abstract Django models are automatically made non-creatable
* New translations for Norwegian Bokmål and Icelandic
* Fix: Text areas in the non-default tab of the page editor now resize to the correct height
* Fix: Tabs in "insert link" modal in the rich text editor no longer disappear (Tim Heap)
* Fix: H2 elements in rich text fields were accidentally given a click() binding when put insite a collapsible multi field panel
* Fix: The wagtailimages module is now compatible with remote storage backends that do not allow reopening closed files
* Fix: Search no longer crashes when auto-indexing a model that doesn't have an id field (Scot Hacker)
* Fix: The `wagtailfrontendcache` module's HTTP backend has been rewritten to reliably direct requests to the configured cache hostname
* Fix: Resizing single pixel images with the "fill" filter no longer raises "ZeroDivisionError" or "tile cannot extend outside image"
* Fix: The queryset returned from `search` operations when using the database search backend now correctly preserves additional properties of the original query, such as `prefetch_related` / `select_related`
* Fix: Responses from the external image URL generator are correctly marked as streaming and will no longer fail when used with Django's cache middleware
* Fix: Page copy now works with pages that use multiple inheritance (Jordi Joan)
* Fix: Form builder pages now pick up template variables defined in the `get_context` method (Christoph Lipp)
* Fix: When copying a page, IDs of child objects within page revision records were not remapped to the new objects; this would cause those objects to be lost from the original page when editing the new one
* Fix: Newly added redirects now take effect on all sites, rather than just the site that the Wagtail admin backend was accessed through
* Fix: Add user form no longer throws a hard error on validation failure
1.0 (16.07.2015)

View file

@ -58,6 +58,12 @@ Contributors
* Mitchel Cabuloy
* Piet Delport
* Tom Christie
* Michael van Tellingen
* Scot Hacker
* Kyungil Choi
* Joss Ingram
* Christoph Lipp
Translators
===========
@ -77,9 +83,11 @@ Translators
* German: Karl Sander, Johannes Spielmann, m0rph3u5, pcraston, Tammo van Lessen
* Greek: Serafeim Papastefanos, Jim Dal
* Hebrew (Israel): bjesus, Lior Abazon
* Icelandic: Arnar Tumi Þorsteinsson, saevarom
* Italian: Andrea Tagliazucchi, Claudio Bantaloukas, Alessio Di Stasio, Giacomo Ghizzani
* Japanese: Daigo Shitara, Toshikazu Michisu
* Mongolian: Delgermurun Purevkhuu, miiiga
* Norwegian Bokmål: Eirik Krogstad
* Polish: Łukasz Bołdys
* Portuguese (Brazil): Gilson Filho, Douglas Miranda, Thiago Cangussu, João Luiz Lorencetti, Gladson Brito, Marcelo J. Both
* Portuguese (Portugal): Jose Lourenco, Tiago Henriques

View file

@ -23,7 +23,7 @@ As standard, Wagtail organises panels into three tabs: 'Content', 'Promote' and
FieldPanel('body', classname="full"),
]
sidebar_content_panels = [
SnippetChooserPanel('advert', Advert),
SnippetChooserPanel('advert'),
InlinePanel('related_links', label="Related links"),
]

View file

@ -1,10 +1,8 @@
===========================
Creating multilingual sites
===========================
===========================================================
Creating a multilingual site (by duplicating the page tree)
===========================================================
This tutorial will show you a method of creating multilingual sites in Wagtail.
Currently, Wagtail doesn't support multiple languages in the same page. The recommended way of creating multilingual websites in Wagtail at the moment is to create one section of your website for each language.
This tutorial will show you a method of creating multilingual sites in Wagtail by duplicating the page tree.
For example::

View file

@ -0,0 +1,211 @@
====================
Internationalisation
====================
This document describes the internationalisation features of Wagtail and how to create multi-lingual sites.
Wagtail uses Django's `Internationalisation framework <https://docs.djangoproject.com/en/1.8/topics/i18n/>`_ so most of the steps are the same as other Django projects.
.. contents::
Wagtail admin translations
==========================
The Wagtail admin backend has been translated into many different languages. You can find a list of currently available translations on Wagtail's `Transifex page <https://www.transifex.com/torchbox/wagtail/>`_. (Note: if you're using an old version of Wagtail, this page may not accurately reflect what languages you have available).
If your language isn't listed on that page, you can easily contribute new languages or correct mistakes. Sign up and submit changes to `Transifex <https://www.transifex.com/torchbox/wagtail/>`_. Translation updates are typically merged into an official release within one month of being submitted.
Changing the primary language of your Wagtail installation
==========================================================
The default language of Wagtail is ``en-us`` (American English). You can change this by tweaking a couple of Django settings:
- Make sure `USE_I18N <https://docs.djangoproject.com/en/1.8/ref/settings/#use-i18n>`_ is set to ``True``
- Set `LANGUAGE_CODE <https://docs.djangoproject.com/en/1.8/ref/settings/#std:setting-LANGUAGE_CODE>`_ to your websites' primary language
If there is a translation available for your language, the Wagtail admin backend should now be in the language you've chosen.
Creating sites with multiple languages
======================================
You can create sites with multiple language support by leveraging Django's `translation features <https://docs.djangoproject.com/en/1.8/topics/i18n/translation/>`_.
This section of the documentation will show you how to use Django's translation features with Wagtail and also describe a couple of methods for storing/retrieving translated content using Wagtail pages.
Enabling multiple language support
----------------------------------
Firstly, make sure the `USE_I18N <https://docs.djangoproject.com/en/1.8/ref/settings/#use-i18n>`_ Django setting is set to ``True``.
To enable multi-language support, add ``django.middleware.locale.LocaleMiddleware`` to your ``MIDDLEWARE_CLASSES``:
.. code-block:: python
MIDDLEWARE_CLASSES = (
...
'django.middleware.locale.LocaleMiddleware',
)
This middleware class looks at the user's browser language and sets the `language of the site accordingly <https://docs.djangoproject.com/en/1.8/topics/i18n/translation/#how-django-discovers-language-preference>`_.
Serving different languages from different URLs
-----------------------------------------------
Just enabling the multi-language support in Django sometimes may not be enough. By default, Django will serve different languages of the same page with the same URL. This has a couple of drawbacks:
- Users cannot change language without changing their browser settings
- It may not work well with various caching setups (as content varies based on browser settings)
Django's ``i18n_patterns`` feature, when enabled, prefixes the URLs with the language code (eg ``/en/about-us``). Users are forwarded to their preferred version, based on browser language, when they first visit the site.
This feature is enabled through the project's root URL configuration. Just put the views you would like to have this enabled for in an ``i18n_patterns`` list and append that to the other URL patterns:
.. code-block:: python
# mysite/urls.py
from django.conf.urls import include, url
from django.conf.urls.i18n import i18n_patterns
from django.conf import settings
from django.contrib import admin
from wagtail.wagtailadmin import urls as wagtailadmin_urls
from wagtail.wagtaildocs import urls as wagtaildocs_urls
from wagtail.wagtailcore import urls as wagtail_urls
urlpatterns = [
url(r'^django-admin/', include(admin.site.urls)),
url(r'^admin/', include(wagtailadmin_urls)),
url(r'^documents/', include(wagtaildocs_urls)),
]
urlpatterns += i18n_patterns('',
# These URLs will have /<language_code>/ appended to the beginning
url(r'^search/$', 'search.views.search', name='search'),
url(r'', include(wagtail_urls)),
)
You can implement switching between languages by changing the part at the beginning of the URL. As each language has its own URL, it also works well with just about any caching setup.
Translating templates
---------------------
Static text in templates needs to be marked up in a way that allows Django's ``makemessages`` command to find and export the strings for translators and also allow them to switch to translated versions on the when the template is being served.
As Wagtail uses Django's templates, inserting this markup and the workflow for exporting and translating the strings is the same as any other Django project.
See: https://docs.djangoproject.com/en/1.8/topics/i18n/translation/#internationalization-in-template-code
Translating content
-------------------
The most common approach for translating content in Wagtail is to duplicate each translatable text field, providing a separate field for each language.
This section will describe how to implement this method manually but there is a third party module you can use, `wagtail modeltranslation <https://github.com/infoportugal/wagtail-modeltranslation>`_, which may be quicker if it meets your needs.
**Duplicating the fields in your model**
For each field you would like to be translatable, duplicate it for every language you support and suffix it with the language code:
.. code-block:: python
class BlogPage(Page):
title_fr = models.CharField(max_length=255)
body_en = StreamField(...)
body_fr = StreamField(...)
# Language-independent fields don't need to be duplicated
thumbnail_image = models.ForeignKey('wagtailimages.image', ...)
.. note::
We only define the French version of the ``title`` field as Wagtail already provides the English version for us.
**Organising the fields in the admin interface**
You can either put all the fields with their translations next to each other on the "content" tab or put the translations for other languages on different tabs.
See :ref:`customising_the_tabbed_interface` for information on how to add more tabs to the admin interface.
**Accessing the fields from the template**
In order for the translations to be shown on the site frontend, the correct field needs to be used in the template based on what language the client has selected.
Having to add language checks every time you display a field in a template, could make your templates very messy. Here's a little trick that will allow you to implement this while keeping your templates and model code clean.
You can use a snippet like the following to add accessor fields on to your page model. These accessor fields will point at the field that contains the language the user has selected.
Copy this into your project and make sure it's imported in any ``models.py`` files that contain a ``Page`` with translated fields. It will require some modification to support different languages.
.. code-block:: python
from django.utils import translation
class TranslatedField(object):
def __init__(self, en_field, fr_field):
self.en_field = en_field
self.fr_field = fr_field
def __get__(self, instance, owner):
en = getattr(instance, self.en_field)
fr = getattr(instance, self.fr_field)
if translation.get_language() == 'fr':
return fr
else:
return en
Then, for each translated field, create an instance of ``TranslatedField`` with a nice name (as this is the name your templates will reference).
For example, here's how we would apply this to the above ``BlogPage`` model:
.. code-block:: python
class BlogPage(Page):
...
translated_title = TranslatedField(
'title',
'title_fr',
)
body = TranslatedField(
'body_en',
'body_fr',
)
Finally, in the template, reference the accessors instead of the underlying database fields:
.. code-block:: html+Django
{{ self.translated_title }}
{{ self.body }}
Other approaches
----------------
.. toctree::
duplicate_tree

View file

@ -8,7 +8,7 @@ Advanced topics
settings
deploying
performance
multilingual_sites
i18n/index
privacy
customisation/index
third_party_tutorials

View file

@ -8,7 +8,7 @@ We recommend using the `Wagtail demo site <https://github.com/torchbox/wagtailde
Install the wagtaildemo following the instructions in the `wagtaildemo README <https://github.com/torchbox/wagtaildemo/blob/master/README.md>`_, then continue with the instructions below.
Clone a copy of `the Wagtail codebase <https://github.com/torchbox/wagtail>`_ alongside your demo site at the same level. So in the directory containing wagtaildemo, run::
Clone a copy of `the Wagtail codebase <https://github.com/torchbox/wagtail>`_ alongside your demo site at the same level. So in the directory containing the wagtaildemo repo, run::
git clone https://github.com/torchbox/wagtail.git

View file

@ -8,4 +8,3 @@ This section of the guide documents how to perform common tasks as an administra
managing_users
promoted_search_results
.. redirects

View file

@ -25,5 +25,5 @@ ___________
* This interface allows you to select a focal point which can effect how your image displays to visitors on the front-end.
* If your images are cropped in some way to make them fit to a specific shape, then the focal point will define the centre point from which the image is cropped.
* To set the focal point, simply a marquee around the most important element of the image.
* If the feature is set up in your website, then on the front-end you will see the crop of this image focusing on your selection.
* To set the focal point, simply drag a marquee around the most important element of the image.
* If the feature is set up in your website, then on the front-end you will see the crop of this image focusing on your selection.

View file

@ -3,7 +3,7 @@ Snippets
Snippets allow you to create elements on a website once and reuse them in multiple places. Then, if you want to change something on the snippet, you only need to change it once, and it will change across all the occurances of the snippet.
How snippets are used can vary widely between websites. Here are a few examples of things Torchbox have used snippets for on our clients websites:
How snippets are used can vary widely between websites. Here are a few examples of things Torchbox have used snippets for on our clients' websites:
* For staff contact details, so that they can be added to many pages but managed in one place
* For Adverts, either to be applied sitewide or on individual pages
@ -35,4 +35,4 @@ If you are editing a page, and you find yourself in need of a new snippet, do no
* You should now see your new snippet, even though you didn't leave the edit page.
.. Note::
Even though this is possible, it is worth saving your page as a draft as often as possible, to avoid your changes being lost by navigating away from the edit page accidentally.
Even though this is possible, it is worth saving your page as a draft as often as possible, to avoid your changes being lost by navigating away from the edit page accidentally.

View file

@ -15,7 +15,7 @@ You can return to the Dashboard at any time by clicking the Wagtail log in the t
- Clicking the logo returns you to your Dashboard.
- The stats at the top of the page describe the total amount of content on the CMS (just for fun!).
- The *Pages awaiting moderation* table will only displayed if you have moderator or administrator privileges
- The *Pages awaiting moderation* table will only be displayed if you have moderator or administrator privileges
- Clicking the name of a page will take you to the Edit page interface for this page.
- Clicking approve or reject will either change the page status to live or return the page to draft status. An email will be sent to the creator of the page giving the result of moderation either way.
@ -23,8 +23,8 @@ You can return to the Dashboard at any time by clicking the Wagtail log in the t
- The *Your most recent edits* table displays the five pages that you most recently edited.
- The date column displays the date that you edited the page. Hover your mouse over the date for a more exact time/date.
- The status column displays the current status of the page. A page will have on one of four statuses:
- The status column displays the current status of the page. A page will have one of three statuses:
- Live: Published and accessible to website visitors
- Draft: Not live on the website.
- Live + Draft: A version of the page is live, but a newer version is in draft mode.
- Live + Draft: A version of the page is live, but a newer version is in draft mode.

View file

@ -28,5 +28,5 @@ ________________
.. image:: ../../_static/images/screen08.5_reorder_page_handles.png
* Clicking the icon to the far left of the child pages table will enable the reordering handles. This allows you to reorder the way that content displays in the main menu of your website.
* Reorder by dragging the pages by the handles on the far left (the icon made up of 8 dots).
* Your new order will be automatically saved each time you drag and drop an item.
* Reorder by dragging the pages by the handles on the far left (the icon made up of 6 dots).
* Your new order will be automatically saved each time you drag and drop an item.

View file

@ -14,4 +14,4 @@ A common feature of Wagtail is the ability to add more than one of a particular
.. image:: ../../_static/images/screen26_reordering_multiple_items.png
4. You can reorder your multiple items using the up and down arrows. Doing this will affect the order in which they are display on the live page.
* You can reorder your multiple items using the up and down arrows. Doing this will affect the order in which they are display on the live page.

View file

@ -38,7 +38,7 @@ The image below demonstrates finding and inserting an image that is already pre
#. You must include an image title for your uploaded image
#. Click the *Choose file* button to choose an image from your computer.
#. This *Tags* allows you to associate tags with the image you are uploading. This allows them to be more easily found when searching. Each tag should be separated by a space. Good practice for creating multiple word tags is to use an underscore between each word (e.g. western_yellow_wagtail).
#. *Tags* allows you to associate tags with the image you are uploading. This allows them to be more easily found when searching. Each tag should be separated by a space. Good practice for creating multiple word tags is to use an underscore between each word (e.g. western_yellow_wagtail).
#. Click *Upload* to insert the uploaded image into the carousel. The image will also be added to the main CMS image library for reuse in other content.
Inserting images using the rich text field
@ -48,7 +48,7 @@ __________________________________________
Images can also be inserted into the body text of a page via the rich text editor. When working in a rich text field, click the image illustrated above. You will then be presented with the same options as for inserting images into the main carousel.
In addition, Wagtail allows you to chose an alignment for you image.
In addition, Wagtail allows you to choose an alignment for you image.
.. image:: ../../_static/images/screen18_image_alignment.png

View file

@ -10,9 +10,9 @@ Whichever way you insert a link, you will be presented with the form displayed b
* Search for an existing page to link to using the search bar at the top of the pop-up.
* Below the search bar you can select the type of link you want to insert. The following types are available:
* Internal link: A link to an existing page within the RCA website.
* Internal link: A link to an existing page within your website.
* External link: A link to a page on another website.
* Email link: A link that will open the users default email client with the email address prepopulated.
* Email link: A link that will open the user's default email client with the email address prepopulated.
* You can also navigate through the website to find an internal link via the explorer.

View file

@ -4,9 +4,9 @@ Selecting a page type
.. image:: ../../_static/images/screen09_page_type_selection.png
* On the left of the page chooser screen are listed all the types of pages that you can create. Clicking the page type name will take you to the Create new page screen for that page type (see below).
* Clicking the *View all … pages* links on the right will display all the pages that exist on the website of this type. This is to help you judge what type of page you will need to complete your task.
* Clicking the *Pages using … Page* links on the right will display all the pages that exist on the website of this type. This is to help you judge what type of page you will need to complete your task.
.. image:: ../../_static/images/screen10_blank_page_edit_screen.png
* Once you've selected a page type you will be presented with a blank New page screen.
* Click into the areas below each field's heading to start entering content.
* Click into the areas below each field's heading to start entering content.

View file

@ -143,7 +143,7 @@ FieldRowPanel
PageChooserPanel
----------------
.. class:: PageChooserPanel(field_name, model=None)
.. class:: PageChooserPanel(field_name, page_type=None)
You can explicitly link :class:`~wagtail.wagtailcore.models.Page`-derived models together using the :class:`~wagtail.wagtailcore.models.Page` model and ``PageChooserPanel``.
@ -166,7 +166,9 @@ PageChooserPanel
PageChooserPanel('related_page', 'demo.PublisherPage'),
]
``PageChooserPanel`` takes two arguments: a field name and an optional page type. Specifying a page type (in the form of an ``"appname.modelname"`` string) will filter the chooser to display only pages of that type.
``PageChooserPanel`` takes two arguments: a field name and an optional page type. Specifying a page type (in the form of an ``"appname.modelname"`` string) will filter the chooser to display only pages of that type. A list or tuple of page types can also be passed in, to allow choosing a page that matches any of those page types::
PageChooserPanel('related_page', ['demo.PublisherPage', 'demo.AuthorPage'])
ImageChooserPanel
-----------------
@ -231,9 +233,13 @@ DocumentChooserPanel
SnippetChooserPanel
-------------------
.. class:: wagtail.wagtailsnippets.edit_handlers.SnippetChooserPanel(field_name, model)
.. versionchanged:: 1.1
Snippets are vanilla Django models you create yourself without a Wagtail-provided base class. So using them as a field in a page requires specifying your own ``appname.modelname``. A chooser, ``SnippetChooserPanel``, is provided which takes the field name and snippet class.
Before Wagtail 1.1, it was necessary to pass the snippet model class as a second parameter to ``SnippetChooserPanel``. This is now automatically picked up from the field.
.. class:: wagtail.wagtailsnippets.edit_handlers.SnippetChooserPanel(field_name, snippet_type=None)
Snippets are vanilla Django models you create yourself without a Wagtail-provided base class. A chooser, ``SnippetChooserPanel``, is provided which takes the field name as an argument.
.. code-block:: python
@ -249,7 +255,7 @@ SnippetChooserPanel
)
content_panels = Page.content_panels + [
SnippetChooserPanel('advert', Advert),
SnippetChooserPanel('advert'),
]
See :ref:`snippets` for more information.

View file

@ -155,11 +155,11 @@ Using an example from the Wagtail demo site, here's what the tag model and the r
from modelcluster.fields import ParentalKey
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import Tag, TaggedItemBase
...
from taggit.models import TaggedItemBase
class BlogPageTag(TaggedItemBase):
content_object = ParentalKey('demo.BlogPage', related_name='tagged_items')
...
class BlogPage(Page):
...
tags = ClusterTaggableManager(through=BlogPageTag, blank=True)

View file

@ -153,6 +153,10 @@ In addition to the model fields provided, ``Page`` has many properties and metho
Defines which template file should be used to render the login form for Protected pages using this model. This overrides the default, defined using ``PASSWORD_REQUIRED_TEMPLATE`` in your settings. See :ref:`private_pages`
.. attribute:: is_creatable
Controls if this page can be created through the Wagtail administration. Defaults to True, and is not inherited by subclasses. This is useful when using `multi-table inheritance <https://docs.djangoproject.com/en/1.8/topics/db/models/#multi-table-inheritance>`_, to stop the base model from being created as an actual page.
``Site``
========

View file

@ -26,10 +26,28 @@ Atomic rebuilding of Elasticsearch indexes
The Elasticsearch search backend now accepts an experimental ``ATOMIC_REBUILD`` flag which ensures that the existing search index continues to be available while the ``update_index`` task is running. See :ref:`wagtailsearch_backends_atomic_rebuild`.
Permissions fixes in the admin interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A number of inconsistencies around permissions in the admin interface were fixed in this release:
* Removed all permissions for "User profile" (not used)
* Removed "delete" permission for Images and documents (not used)
* Users can now access images and documents when they only have the "change" permission (previously required "add" permission as well)
* Permissions for Users now taken from custom user model, if set (previously always used permissions on Djangos builtin User model)
* Groups and Users now respond consistently to their respective "add", "change" and "delete" permissions
Searchable snippets
~~~~~~~~~~~~~~~~~~~
Snippets that inherit from ``wagtail.wagtailsearch.index.Indexed`` are now given a search box on the snippet chooser and listing pages. See :ref:`wagtailsnippets_making_snippets_searchable`.
Minor features
~~~~~~~~~~~~~~
* The :mod:`~wagtail.contrib.wagtailapi` module has been refactored to use Django REST Framework
* Implemented deletion of form submissions
* Implemented pagination in the page chooser modal
* Changed INSTALLED_APPS in project template to list apps in precedence order
* The ``{% image %}`` tag now supports filters on the image variable, e.g. ``{% image primary_img|default:secondary_img width-500 %}``
@ -39,8 +57,19 @@ Minor features
* Added optional directory argument to "wagtail start" command
* Non-superusers can now view/edit/delete sites if they have the correct permissions
* Image file size is now stored in the database, to avoid unnecessary filesystem lookups
* Page URL lookups hit the cache/database less often
* Updated URLs within the admin backend to use namespaces
* The ``update_index`` task now indexes objects in batches of 1000, to indicate progress and avoid excessive memory use
* Added database indexes on PageRevision and Image to improve performance on large sites
* Search in page chooser now uses Wagtail's search framework, to order results by relevance
* ``PageChooserPanel`` now supports passing a list (or tuple) of accepted page types
* The snippet type parameter of ``SnippetChooserPanel`` can now be omitted, or passed as a model name string rather than a model class
* Added aliases for the ``self`` template variable to accommodate Jinja as a templating engine: ``page`` for pages, ``field_panel`` for field panels / edit handlers, and ``value`` for blocks
* Added signposting text to the explorer to steer editors away from creating pages at the root level unless they are setting up new sites
* "Clear choice" and "Edit this page" buttons are no longer shown on the page field of the group page permissions form
* Altered styling of stream controls to be more like all other buttons
* Added ability to mark page models as not available for creation using the flag ``is_creatable``; pages that are abstract Django models are automatically made non-creatable
* New translations for Norwegian Bokmål and Icelandic
Bug fixes
~~~~~~~~~
@ -48,6 +77,17 @@ Bug fixes
* Text areas in the non-default tab of the page editor now resize to the correct height
* Tabs in "insert link" modal in the rich text editor no longer disappear (Tim Heap)
* H2 elements in rich text fields were accidentally given a click() binding when put insite a collapsible multi field panel
* The ``wagtailimages`` module is now compatible with remote storage backends that do not allow reopening closed files
* Search no longer crashes when auto-indexing a model that doesn't have an ``id`` field
* The ``wagtailfrontendcache`` module's HTTP backend has been rewritten to reliably direct requests to the configured cache hostname
* Resizing single pixel images with the "fill" filter no longer raises "ZeroDivisionError" or "tile cannot extend outside image"
* The queryset returned from ``search`` operations when using the database search backend now correctly preserves additional properties of the original query, such as ``prefetch_related`` / ``select_related``
* Responses from the external image URL generator are correctly marked as streaming and will no longer fail when used with Django's cache middleware
* Page copy now works with pages that use multiple inheritance
* Form builder pages now pick up template variables defined in the ``get_context`` method
* When copying a page, IDs of child objects within page revision records were not remapped to the new objects; this would cause those objects to be lost from the original page when editing the new one
* Newly added redirects now take effect on all sites, rather than just the site that the Wagtail admin backend was accessed through
* Add user form no longer throws a hard error on validation failure
Upgrade considerations
@ -68,3 +108,19 @@ To re-enable it, add :mod:`wagtail.contrib.wagtailsearchpromotions` to your ``IN
'wagtail.contrib.wagtailsearchpromotions',
...
If you have references to the ``wagtail.wagtailsearch.models.EditorsPick`` model in your
project, you will need to update these to point to the :mod:`wagtail.contrib.wagtailsearchpromotions.models.SearchPromotion` model instead.
If you created your project using the ``wagtail start`` command with Wagtail 1.0,
you will probably have references to this model in the ``search/views.py`` file.
``is_abstract`` flag on page models has been replaced by ``is_creatable``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Previous versions of Wagtail provided an undocumented ``is_abstract`` flag on page models - not to be confused with Django's ``abstract`` Meta flag - to indicate that it should not be included in the list of available page types for creation. (Typically this would be used on model classes that were designed to be subclassed to create new page types, rather than used directly.) To avoid confusion with Django's distinct concept of abstract models, this has now been replaced by a new flag, ``is_creatable``.
If you have used ``is_abstract = True`` on any of your models, you should now change this to ``is_creatable = False``.
It is not necessary to include this flag if the model is abstract in the Django sense (i.e. it has ``abstract = True`` in the model's ``Meta`` class), since it would never be valid to create pages of that type.

18
docs/releases/1.2.rst Normal file
View file

@ -0,0 +1,18 @@
==========================================
Wagtail 1.2 release notes - IN DEVELOPMENT
==========================================
.. contents::
:local:
:depth: 1
What's new
==========
Bug fixes
~~~~~~~~~
* Deleting a page permission from the groups admin UI does not immediately submit the form

View file

@ -4,6 +4,7 @@ Release notes
.. toctree::
:maxdepth: 1
1.2
1.1
1.0
0.8.8

View file

@ -6,7 +6,7 @@ Snippets
Snippets are pieces of content which do not necessitate a full webpage to render. They could be used for making secondary content, such as headers, footers, and sidebars, editable in the Wagtail admin. Snippets are models which do not inherit the ``Page`` class and are thus not organized into the Wagtail tree, but can still be made editable by assigning panels and identifying the model as a snippet with the ``register_snippet`` class decorator.
Snippets are not search-able or order-able in the Wagtail admin, so decide carefully if the content type you would want to build into a snippet might be more suited to a page.
Snippets lack many of the features of pages, such as being orderable in the Wagtail admin or having a defined URL, so decide carefully if the content type you would want to build into a snippet might be more suited to a page.
Snippet Models
--------------
@ -24,20 +24,20 @@ Here's an example snippet from the Wagtail demo website:
@register_snippet
class Advert(models.Model):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [
FieldPanel('url'),
FieldPanel('text'),
]
def __unicode__(self):
return self.text
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [
FieldPanel('url'),
FieldPanel('text'),
]
def __str__(self): # __unicode__ on Python 2
return self.text
The ``Advert`` model uses the basic Django model class and defines two properties: text and URL. The editing interface is very close to that provided for ``Page``-derived models, with fields assigned in the panels property. Snippets do not use multiple tabs of fields, nor do they provide the "save as draft" or "submit for moderation" features.
``@register_snippet`` tells Wagtail to treat the model as a snippet. The ``panels`` list defines the fields to show on the snippet editing page. It's also important to provide a string representation of the class through ``def __unicode__(self):`` so that the snippet objects make sense when listed in the Wagtail admin.
``@register_snippet`` tells Wagtail to treat the model as a snippet. The ``panels`` list defines the fields to show on the snippet editing page. It's also important to provide a string representation of the class through ``def __str__(self):`` so that the snippet objects make sense when listed in the Wagtail admin.
Including Snippets in Template Tags
-----------------------------------
@ -60,10 +60,10 @@ First, add a new python file to a ``templatetags`` folder within your app. The d
# Advert snippets
@register.inclusion_tag('demo/tags/adverts.html', takes_context=True)
def adverts(context):
return {
'adverts': Advert.objects.all(),
'request': context['request'],
}
return {
'adverts': Advert.objects.all(),
'request': context['request'],
}
``@register.inclusion_tag()`` takes two variables: a template and a boolean on whether that template should be passed a request context. It's a good idea to include request contexts in your custom template tags, since some Wagtail-specific template tags like ``pageurl`` need the context to work properly. The template tag function could take arguments and filter the adverts to return a specific model, but for brevity we'll just use ``Advert.objects.all()``.
@ -102,17 +102,18 @@ In the above example, the list of adverts is a fixed list, displayed as part of
from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
# ...
class BookPage(Page):
advert = models.ForeignKey(
'demo.Advert',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
advert = models.ForeignKey(
'demo.Advert',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
BookPage.content_panels = [
SnippetChooserPanel('advert', Advert),
# ...
SnippetChooserPanel('advert'),
# ...
]
@ -133,29 +134,32 @@ To attach multiple adverts to a page, the ``SnippetChooserPanel`` can be placed
...
class BookPageAdvertPlacement(Orderable, models.Model):
page = ParentalKey('demo.BookPage', related_name='advert_placements')
advert = models.ForeignKey('demo.Advert', related_name='+')
class Meta:
verbose_name = "Advert Placement"
verbose_name_plural = "Advert Placements"
panels = [
SnippetChooserPanel('advert', Advert),
]
def __unicode__(self):
return self.page.title + " -> " + self.advert.text
page = ParentalKey('demo.BookPage', related_name='advert_placements')
advert = models.ForeignKey('demo.Advert', related_name='+')
class Meta:
verbose_name = "Advert Placement"
verbose_name_plural = "Advert Placements"
panels = [
SnippetChooserPanel('advert'),
]
def __str__(self): # __unicode__ on Python 2
return self.page.title + " -> " + self.advert.text
class BookPage(Page):
...
...
BookPage.content_panels = [
InlinePanel('advert_placements', label="Adverts"),
# ...
InlinePanel('advert_placements', label="Adverts"),
# ...
]
These child objects are now accessible through the page's ``advert_placements`` property, and from there we can access the linked Advert snippet as ``advert``. In the template for ``BookPage``, we could include the following:
.. code-block:: django
@ -165,3 +169,58 @@ These child objects are now accessible through the page's ``advert_placements``
{% endfor %}
.. _wagtailsnippets_making_snippets_searchable:
Making Snippets Searchable
--------------------------
If a snippet model inherits from ``wagtail.wagtailsearch.index.Indexed``, as described in :ref:`wagtailsearch_indexing_models`, Wagtail will automatically add a search box to the chooser interface for that snippet type. For example, the ``Advert`` snippet could be made searchable as follows:
.. code-block:: python
...
from wagtail.wagtailsearch import index
...
@register_snippet
class Advert(models.Model, index.Indexed):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [
FieldPanel('url'),
FieldPanel('text'),
]
search_fields = [
index.SearchField('text', partial_match=True),
]
Tagging snippets
----------------
Adding tags to snippets is very similar to adding tags to pages. The only difference is that :class:`taggit.manager.TaggableManager` should be used in the place of :class:`~modelcluster.contrib.taggit.ClusterTaggableManager`.
.. code-block:: python
from modelcluster.fields import ParentalKey
from taggit.models import TaggedItemBase
from taggit.managers import TaggableManager
class AdvertTag(TaggedItemBase):
content_object = ParentalKey('demo.Advert', related_name='tagged_items')
@register_snippet
class Advert(models.Model):
...
tags = TaggableManager(through=BlogPageTag, blank=True)
panels = [
...
FieldPanel('tags'),
]
The :ref:`documentation on tagging pages <tagging>` has more information on how to use tags in views.

View file

@ -11,7 +11,7 @@ tx pull -a --minimum-perc=30
# These things are only needed by translators (which they won't be seen by) and make the translation updates difficult to check
find ../wagtail -iname *.po ! -iwholename */en/* -exec msgattrib --translated --no-fuzzy --no-obsolete --no-location -o {} {} \;
# Run makemessages on each app
# Run compilemessages on each app
for d in $(find ../wagtail -iname *.po | sed 's|\(.*\)/locale.*|\1|' | sort -u);
do
pushd $d

View file

@ -0,0 +1,10 @@
# Delete old translation sources
find ../wagtail -iname *.po -iwholename */en/* -delete
# Run makemessages on each app
for d in $(find ../wagtail -iwholename */locale/* | sed 's|\(.*\)/locale.*|\1|' | sort -u);
do
pushd $d
django-admin makemessages --locale=en
popd
done

View file

@ -28,12 +28,11 @@ install_requires = [
"django-modelcluster>=0.6",
"django-taggit>=0.13.0",
"django-treebeard==3.0",
"djangorestframework==3.1.3",
"djangorestframework>=3.1.3",
"Pillow>=2.6.1",
"beautifulsoup4>=4.3.2",
"html5lib==0.999",
"Unidecode>=0.04.14",
'requests>=2.0.0',
"Willow==0.2.1",
]

View file

@ -28,7 +28,6 @@ deps =
html5lib==0.999
Unidecode>=0.04.14
six==1.7.3
requests==2.3.0
elasticsearch==1.1.0
mock==1.0.1
python-dateutil==2.2

View file

@ -1,5 +1,7 @@
from __future__ import absolute_import
from collections import OrderedDict
from django.conf.urls import url
from django.http import Http404
@ -18,14 +20,14 @@ from .filters import (
)
from .renderers import WagtailJSONRenderer
from .pagination import WagtailPagination
from .serializers import WagtailSerializer, PageSerializer, DocumentSerializer
from .serializers import BaseSerializer, PageSerializer, DocumentSerializer, ImageSerializer, get_serializer_class
from .utils import BadRequestError
class BaseAPIEndpoint(GenericViewSet):
renderer_classes = [WagtailJSONRenderer]
pagination_class = WagtailPagination
serializer_class = WagtailSerializer
base_serializer_class = BaseSerializer
filter_classes = []
queryset = None # Set on subclasses or implement `get_queryset()`.
@ -85,28 +87,61 @@ class BaseAPIEndpoint(GenericViewSet):
if unknown_parameters:
raise BadRequestError("query parameter is not an operation or a recognised field: %s" % ', '.join(sorted(unknown_parameters)))
def get_serializer_context(self):
"""
The serialization context differs between listing and detail views.
"""
def get_serializer_class(self):
request = self.request
if self.action == 'listing_view':
# Get model
if self.action == 'listing_view':
model = self.get_queryset().model
else:
model = type(self.get_object())
# Get all available fields
all_fields = self.get_api_fields(model)
all_fields = list(OrderedDict.fromkeys(all_fields)) # Removes any duplicates in case the developer put "title" in api_fields
if self.action == 'listing_view':
# Listing views just show the title field and any other allowed field the user specified
if 'fields' in request.GET:
fields = set(request.GET['fields'].split(','))
else:
fields = {'title'}
unknown_fields = fields - set(all_fields)
if unknown_fields:
raise BadRequestError("unknown fields: %s" % ', '.join(sorted(unknown_fields)))
# Reorder fields so it matches the order of all_fields
fields = [field for field in all_fields if field in fields]
else:
# Detail views show all fields all the time
fields = all_fields
# Always show id and meta first
fields = ['id', 'meta'] + fields
# If showing details, add the parent field
if isinstance(self, PagesAPIEndpoint) and self.get_serializer_context().get('show_details', False):
fields.insert(2, 'parent')
return get_serializer_class(model, fields, base=self.base_serializer_class)
def get_serializer_context(self):
"""
The serialization context differs between listing and detail views.
"""
request = self.request
if self.action == 'listing_view':
return {
'request': request,
'view': self,
'fields': fields
}
return {
'request': request,
'view': self,
'all_fields': True,
'show_details': True
}
@ -135,7 +170,7 @@ class BaseAPIEndpoint(GenericViewSet):
class PagesAPIEndpoint(BaseAPIEndpoint):
serializer_class = PageSerializer
base_serializer_class = PageSerializer
filter_backends = [
FieldsFilter,
ChildOfFilter,
@ -185,6 +220,7 @@ class PagesAPIEndpoint(BaseAPIEndpoint):
class ImagesAPIEndpoint(BaseAPIEndpoint):
queryset = get_image_model().objects.all().order_by('id')
base_serializer_class = ImageSerializer
filter_backends = [FieldsFilter, OrderingFilter, SearchFilter]
extra_api_fields = ['title', 'tags', 'width', 'height']
name = 'images'
@ -196,7 +232,7 @@ class ImagesAPIEndpoint(BaseAPIEndpoint):
class DocumentsAPIEndpoint(BaseAPIEndpoint):
queryset = Document.objects.all().order_by('id')
serializer_class = DocumentSerializer
base_serializer_class = DocumentSerializer
filter_backends = [FieldsFilter, OrderingFilter, SearchFilter]
extra_api_fields = ['title', 'tags']
name = 'documents'

View file

@ -6,11 +6,6 @@ from django.utils.six import text_type
from rest_framework import renderers
from taggit.managers import _TaggableManager
from taggit.models import Tag
from wagtail.wagtailcore.blocks import StreamValue
from .utils import URLPath, ObjectDetailURL, get_base_url
@ -35,11 +30,7 @@ class WagtailJSONRenderer(renderers.BaseRenderer):
class WagtailAPIJSONEncoder(DjangoJSONEncoder):
def default(self, o):
if isinstance(o, _TaggableManager):
return list(o.all())
elif isinstance(o, Tag):
return o.name
elif isinstance(o, URLPath):
if isinstance(o, URLPath):
return get_full_url(request, o.path)
elif isinstance(o, ObjectDetailURL):
detail_view = find_model_detail_view(o.model, endpoints)
@ -48,8 +39,6 @@ class WagtailJSONRenderer(renderers.BaseRenderer):
return get_full_url(request, reverse(detail_view, args=(o.pk, )))
else:
return None
elif isinstance(o, StreamValue):
return o.stream_block.get_prep_value(o)
else:
return super(WagtailAPIJSONEncoder, self).default(o)

View file

@ -2,171 +2,282 @@ from __future__ import absolute_import
from collections import OrderedDict
from django.db import models
from django.utils.encoding import force_text
from modelcluster.models import get_all_child_relations
from rest_framework.serializers import BaseSerializer
from taggit.managers import _TaggableManager
from rest_framework import serializers
from rest_framework.fields import Field
from rest_framework import relations
from wagtail.utils.compat import get_related_model
from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore import fields as wagtailcore_fields
from .utils import ObjectDetailURL, URLPath, BadRequestError, pages_for_site
from .utils import ObjectDetailURL, URLPath, pages_for_site
def get_api_data(obj, fields):
# Find any child relations (pages only)
child_relations = {}
if isinstance(obj, Page):
child_relations = {
child_relation.field.rel.related_name: get_related_model(child_relation)
for child_relation in get_all_child_relations(type(obj))
}
class MetaField(Field):
"""
Serializes the "meta" section of each object.
# Loop through fields
for field_name in fields:
# Check child relations
if field_name in child_relations and hasattr(child_relations[field_name], 'api_fields'):
yield field_name, [
dict(get_api_data(child_object, child_relations[field_name].api_fields))
for child_object in getattr(obj, field_name).all()
]
continue
This section is used for storing non-field data such as model name, urls, etc.
# Check django fields
try:
field = obj._meta.get_field(field_name)
Example:
if field.rel and isinstance(field.rel, models.ManyToOneRel):
# Foreign key
val = field._get_val_from_obj(obj)
"meta": {
"type": "wagtailimages.Image",
"detail_url": "http://api.example.com/v1/images/1/"
}
"""
def get_attribute(self, instance):
return instance
if val:
yield field_name, OrderedDict([
('id', field._get_val_from_obj(obj)),
('meta', OrderedDict([
('type', field.rel.to._meta.app_label + '.' + field.rel.to.__name__),
('detail_url', ObjectDetailURL(field.rel.to, val)),
])),
])
else:
yield field_name, None
else:
yield field_name, field._get_val_from_obj(obj)
continue
except models.fields.FieldDoesNotExist:
pass
# Check attributes
if hasattr(obj, field_name):
value = getattr(obj, field_name)
yield field_name, force_text(value, strings_only=True)
continue
def to_representation(self, obj):
return OrderedDict([
('type', type(obj)._meta.app_label + '.' + type(obj).__name__),
('detail_url', ObjectDetailURL(type(obj), obj.pk)),
])
class WagtailSerializer(BaseSerializer):
def to_representation(self, instance):
request = self.context['request']
fields = self.context.get('fields', frozenset())
all_fields = self.context.get('all_fields', False)
show_details = self.context.get('show_details', False)
return self.serialize_object(
request,
instance,
fields=fields,
all_fields=all_fields,
show_details=show_details
)
class PageMetaField(MetaField):
"""
A subclass of MetaField for Page objects.
def serialize_object_metadata(self, request, obj, show_details=False):
"""
This returns a JSON-serialisable dict to use for the "meta"
section of a particlular object.
"""
data = OrderedDict()
Changes the "type" field to use the name of the specific model of the page.
# Add type
data['type'] = type(obj)._meta.app_label + '.' + type(obj).__name__
data['detail_url'] = ObjectDetailURL(type(obj), obj.pk)
Example:
return data
def serialize_object(self, request, obj, fields=frozenset(), extra_data=(), all_fields=False, show_details=False):
"""
This converts an object into JSON-serialisable dict so it can
be used in the API.
"""
data = [
('id', obj.id),
]
# Add meta
metadata = self.serialize_object_metadata(request, obj, show_details=show_details)
if metadata:
data.append(('meta', metadata))
# Add extra data
data.extend(extra_data)
# Add other fields
api_fields = self.context['view'].get_api_fields(type(obj))
api_fields = list(OrderedDict.fromkeys(api_fields)) # Removes any duplicates in case the user put "title" in api_fields
if all_fields:
fields = api_fields
else:
unknown_fields = fields - set(api_fields)
if unknown_fields:
raise BadRequestError("unknown fields: %s" % ', '.join(sorted(unknown_fields)))
# Reorder fields so it matches the order of api_fields
fields = [field for field in api_fields if field in fields]
data.extend(get_api_data(obj, fields))
return OrderedDict(data)
"meta": {
"type": "blog.BlogPage",
"detail_url": "http://api.example.com/v1/pages/1/"
}
"""
def to_representation(self, page):
return OrderedDict([
('type', page.specific_class._meta.app_label + '.' + page.specific_class.__name__),
('detail_url', ObjectDetailURL(type(page), page.pk)),
])
class PageSerializer(WagtailSerializer):
def serialize_object_metadata(self, request, page, show_details=False):
data = super(PageSerializer, self).serialize_object_metadata(request, page, show_details=show_details)
class DocumentMetaField(MetaField):
"""
A subclass of MetaField for Document objects.
# Add type
data['type'] = page.specific_class._meta.app_label + '.' + page.specific_class.__name__
Adds a "download_url" field.
return data
"meta": {
"type": "wagtaildocs.Document",
"detail_url": "http://api.example.com/v1/documents/1/",
"download_url": "http://api.example.com/documents/1/my_document.pdf"
}
"""
def to_representation(self, document):
data = OrderedDict([
('type', "wagtaildocs.Document"),
('detail_url', ObjectDetailURL(type(document), document.pk)),
])
def serialize_object(self, request, page, fields=frozenset(), extra_data=(), all_fields=False, show_details=False):
# Add parent
if show_details:
parent = page.get_parent()
site_pages = pages_for_site(request.site)
if site_pages.filter(id=parent.id).exists():
parent_class = parent.specific_class
extra_data += (
('parent', OrderedDict([
('id', parent.id),
('meta', OrderedDict([
('type', parent_class._meta.app_label + '.' + parent_class.__name__),
('detail_url', ObjectDetailURL(parent_class, parent.id)),
])),
])),
)
return super(PageSerializer, self).serialize_object(request, page, fields=fields, extra_data=extra_data, all_fields=all_fields, show_details=show_details)
class DocumentSerializer(WagtailSerializer):
def serialize_object_metadata(self, request, document, show_details=False):
data = super(DocumentSerializer, self).serialize_object_metadata(request, document, show_details=show_details)
# Download URL
if show_details:
# Add download url
if self.context.get('show_details', False):
data['download_url'] = URLPath(document.url)
return data
class RelatedField(relations.RelatedField):
"""
Serializes related objects (eg, foreign keys).
Example:
"feed_image": {
"id": 1,
"meta": {
"type": "wagtailimages.Image",
"detail_url": "http://api.example.com/v1/images/1/"
}
}
"""
meta_field_serializer_class = MetaField
def to_representation(self, value):
return OrderedDict([
('id', value.pk),
('meta', self.meta_field_serializer_class().to_representation(value)),
])
class PageParentField(RelatedField):
"""
Serializes the "parent" field on Page objects.
Pages don't have a "parent" field so some extra logic is needed to find the
parent page. That logic is implemented in this class.
The representation is the same as the RelatedField class.
"""
meta_field_serializer_class = PageMetaField
def get_attribute(self, instance):
parent = instance.get_parent()
site_pages = pages_for_site(self.context['request'].site)
if site_pages.filter(id=parent.id).exists():
return parent
class ChildRelationField(Field):
"""
Serializes child relations.
Child relations are any model that is related to a Page using a ParentalKey.
They are used for repeated fields on a page such as carousel items or related
links.
Child objects are part of the pages content so we nest them. The relation is
represented as a list of objects.
Example:
"carousel_items": [
{
"title": "First carousel item",
"image": {
"id": 1,
"meta": {
"type": "wagtailimages.Image",
"detail_url": "http://api.example.com/v1/images/1/"
}
}
},
"carousel_items": [
{
"title": "Second carousel item (no image)",
"image": null
}
]
"""
def __init__(self, *args, **kwargs):
self.child_fields = kwargs.pop('child_fields')
super(ChildRelationField, self).__init__(*args, **kwargs)
def to_representation(self, value):
serializer_class = get_serializer_class(value.model, self.child_fields)
serializer = serializer_class()
return [
serializer.to_representation(child_object)
for child_object in value.all()
]
class StreamField(Field):
"""
Serializes StreamField values.
Stream fields are stored in JSON format in the database. We reuse that in
the API.
Example:
"body": [
{
"type": "heading",
"value": {
"text": "Hello world!",
"size": "h1"
}
},
{
"type": "paragraph",
"value": "Some content"
}
{
"type": "image",
"value": 1
}
]
Where "heading" is a struct block containing "text" and "size" fields, and
"paragraph" is a simple text block.
Note that foreign keys are represented slightly differently in stream fields
to other parts of the API. In stream fields, a foreign key is represented
by an integer (the ID of the related object) but elsewhere in the API,
foreign objects are nested objects with id and meta as attributes.
"""
def to_representation(self, value):
return value.stream_block.get_prep_value(value)
class TagsField(Field):
"""
Serializes django-taggit TaggableManager fields.
These fields are a common way to link tags to objects in Wagtail. The API
serializes these as a list of strings taken from the name attribute of each
tag.
Example:
"tags": ["bird", "wagtail"]
"""
def to_representation(self, value):
return list(value.all().order_by('name').values_list('name', flat=True))
class BaseSerializer(serializers.ModelSerializer):
# Add StreamField to serializer_field_mapping
serializer_field_mapping = serializers.ModelSerializer.serializer_field_mapping.copy()
serializer_field_mapping.update({
wagtailcore_fields.StreamField: StreamField,
})
serializer_related_field = RelatedField
meta = MetaField()
def build_property_field(self, field_name, model_class):
# TaggableManager is not a Django field so it gets treated as a property
field = getattr(model_class, field_name)
if isinstance(field, _TaggableManager):
return TagsField, {}
return super(BaseSerializer, self).build_property_field(field_name, model_class)
class PageSerializer(BaseSerializer):
meta = PageMetaField()
parent = PageParentField(read_only=True)
def build_relational_field(self, field_name, relation_info):
# Find all relation fields that point to child class and make them use
# the ChildRelationField class.
if relation_info.to_many:
model = getattr(self.Meta, 'model')
child_relations = {
child_relation.field.rel.related_name: get_related_model(child_relation)
for child_relation in get_all_child_relations(model)
}
if field_name in child_relations and hasattr(child_relations[field_name], 'api_fields'):
return ChildRelationField, {'child_fields': child_relations[field_name].api_fields}
return super(BaseSerializer, self).build_relational_field(field_name, relation_info)
class ImageSerializer(BaseSerializer):
pass
class DocumentSerializer(BaseSerializer):
meta = DocumentMetaField()
def get_serializer_class(model_, fields_, base=BaseSerializer):
class Meta:
model = model_
fields = fields_
return type(model_.__name__ + 'Serializer', (base, ), {
'Meta': Meta
})

View file

@ -586,7 +586,7 @@ class TestPageDetail(TestCase):
self.assertEqual(content['date'], '2013-12-02')
# Check that the tags were serialised properly
self.assertEqual(content['tags'], ['wagtail', 'bird'])
self.assertEqual(content['tags'], ['bird', 'wagtail'])
# Check that the feed image was serialised properly
self.assertIsInstance(content['feed_image'], dict)

View file

@ -1,9 +1,11 @@
import logging
import requests
import json
from django.utils.six.moves.urllib.parse import urlparse
from django.utils.six.moves.urllib.parse import urlparse, urlunparse, urlencode
from django.utils.six.moves.urllib.request import Request, urlopen
from django.utils.six.moves.urllib.error import URLError, HTTPError
from requests.adapters import HTTPAdapter
from wagtail.wagtailcore import __version__
logger = logging.getLogger('wagtail.frontendcache')
@ -15,44 +17,41 @@ class BaseBackend(object):
class HTTPBackend(BaseBackend):
class CustomHTTPAdapter(HTTPAdapter):
"""
Requests will always send requests to whatever server is in the netloc
part of the URL. This is a problem with purging the cache as this netloc
may point to a different server (such as an nginx instance running in
front of the cache).
This class allows us to send a purge request directly to the cache server
with the host header still set correctly. It does this by changing the "url"
parameter of get_connection to always point to the cache server. Requests
will then use this connection to purge the page.
"""
def __init__(self, cache_url):
self.cache_url = cache_url
super(HTTPBackend.CustomHTTPAdapter, self).__init__()
def get_connection(self, url, proxies=None):
return super(HTTPBackend.CustomHTTPAdapter, self).get_connection(self.cache_url, proxies)
def __init__(self, params):
self.cache_location = params.pop('LOCATION')
self.session = requests.Session()
self.session.mount('http://', self.CustomHTTPAdapter(self.cache_location))
location_url_parsed = urlparse(params.pop('LOCATION'))
self.cache_scheme = location_url_parsed.scheme
self.cache_netloc = location_url_parsed.netloc
def purge(self, url):
try:
response = self.session.request('PURGE', url)
except requests.ConnectionError:
logger.error("Couldn't purge '%s' from HTTP cache: Connection error", url)
return
url_parsed = urlparse(url)
host = url_parsed.hostname
# Check for error
if response.status_code != 200:
logger.error("Couldn't purge '%s' from HTTP cache: Didn't recieve a 200 response (instead, we got '%d %s')", url, response.status_code, response.reason)
return
# Append port to host if it is set in the original URL
if url_parsed.port:
host += (':' + str(url_parsed.port))
request = Request(
url=urlunparse([
self.cache_scheme,
self.cache_netloc,
url_parsed.path,
url_parsed.params,
url_parsed.query,
url_parsed.fragment
]),
headers={
'Host': host,
'User-Agent': 'Wagtail-frontendcache/' + __version__
},
method='PURGE'
)
try:
urlopen(request)
except HTTPError as e:
logger.error("Couldn't purge '%s' from HTTP cache. HTTPError: %d %s", url, e.code, e.reason)
except URLError as e:
logger.error("Couldn't purge '%s' from HTTP cache. URLError: %s", url, e.reason)
class CloudflareBackend(BaseBackend):
@ -62,23 +61,21 @@ class CloudflareBackend(BaseBackend):
def purge(self, url):
try:
response = requests.post('https://www.cloudflare.com/api_json.html', {
response = urlopen('https://www.cloudflare.com/api_json.html', data=urlencode({
'email': self.cloudflare_email,
'tkn': self.cloudflare_token,
'a': 'zone_file_purge',
'z': urlparse(url).netloc,
'url': url
})
except requests.ConnectionError:
logger.error("Couldn't purge '%s' from Cloudflare: Connection error", url)
}).encode('utf-8'))
except HTTPError as e:
logger.error("Couldn't purge '%s' from Cloudflare. HTTPError: %d %s", url, e.code, e.reason)
return
except URLError as e:
logger.error("Couldn't purge '%s' from Cloudflare. URLError: %s", url, e.reason)
return
# Check for error
if response.status_code != 200:
logger.error("Couldn't purge '%s' from Cloudflare: Didn't recieve a 200 response (instead, we got '%d %s')", url, response.status_code, response.reason)
return
response_json = response.json()
response_json = json.loads(response.read().decode('utf-8'))
if response_json['result'] == 'error':
logger.error("Couldn't purge '%s' from Cloudflare: Cloudflare error '%s'", url, response_json['msg'])
logger.error("Couldn't purge '%s' from Cloudflare. Cloudflare error '%s'", url, response_json['msg'])
return

View file

@ -25,7 +25,8 @@ class TestBackendConfiguration(TestCase):
self.assertEqual(set(backends.keys()), set(['varnish']))
self.assertIsInstance(backends['varnish'], HTTPBackend)
self.assertEqual(backends['varnish'].cache_location, 'http://localhost:8000')
self.assertEqual(backends['varnish'].cache_scheme, 'http')
self.assertEqual(backends['varnish'].cache_netloc, 'localhost:8000')
def test_cloudflare(self):
backends = get_backends(backend_settings={
@ -78,7 +79,8 @@ class TestBackendConfiguration(TestCase):
self.assertEqual(set(backends.keys()), set(['default']))
self.assertIsInstance(backends['default'], HTTPBackend)
self.assertEqual(backends['default'].cache_location, 'http://localhost:8000')
self.assertEqual(backends['default'].cache_scheme, 'http')
self.assertEqual(backends['default'].cache_netloc, 'localhost:8000')
PURGED_URLS = []

View file

@ -138,7 +138,5 @@ class RoutablePage(RoutablePageMixin, Page):
added to it.
"""
is_abstract = True
class Meta:
abstract = True

View file

@ -151,8 +151,6 @@ class TestOldStyleRoutablePage(TestNewStyleRoutablePage, WagtailTestUtils):
# prevent this class appearing in the global PAGE_MODEL_CLASSES list, as
# its non-standard location causes failures when translating from content types
# back to models
is_abstract = True
class Meta:
abstract = True

View file

@ -0,0 +1,79 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Lyuboslav Petrov <petrov.lyuboslav@gmail.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Bulgarian (http://www.transifex.com/torchbox/wagtail/language/"
"bg/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: bg\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Save"
msgstr "Запази"
#, python-format
msgid "Delete %(query)s"
msgstr "Изтрий %(query)s"
msgid "Delete"
msgstr "Изтрий"
msgid "Yes, delete"
msgstr "Да, изтрий го"
#, python-format
msgid "Editing %(query)s"
msgstr "Редакция на %(query)s"
msgid "Editing"
msgstr "Редактиране"
msgid "Move up"
msgstr "Нагоре"
msgid "Move down"
msgstr "Надолу"
msgid "Add recommended page"
msgstr "Добави препоръчана страница"
msgid "Search Terms"
msgstr "Фрази за търсене"
msgid "Search term(s)"
msgstr "Дума/Фраза за търсене"
msgid "Views (past week)"
msgstr "Преглед (последната седмица)"
msgid "None"
msgstr "Нищо"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" Има едно съвпадение\n"
" "
msgstr[1] ""
"\n"
" Има %(counter)s съвпадения\n"
" "

View file

@ -0,0 +1,91 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# David Llop <d.lloople@gmail.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Catalan (http://www.transifex.com/torchbox/wagtail/language/"
"ca/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ca\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Save"
msgstr "Desa"
#, python-format
msgid "Delete %(query)s"
msgstr "Esborra %(query)s"
msgid "Delete"
msgstr "Esborra"
msgid "Yes, delete"
msgstr "Si, esborra"
#, python-format
msgid "Editing %(query)s"
msgstr "Editant %(query)s"
msgid "Editing"
msgstr "Editant"
msgid "Move up"
msgstr "Puja"
msgid "Move down"
msgstr "Baixa"
msgid "Add recommended page"
msgstr "Afegeix una pàgina recomanada"
msgid "Search Terms"
msgstr "Termini de cerca"
msgid "Search term(s)"
msgstr "Cerca paraula(es)"
msgid "Views (past week)"
msgstr "Vistes(la setmana pasada)"
msgid "Edit this pick"
msgstr "Edita aquesta selecció"
msgid "None"
msgstr "Cap"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
"Hi ha una coincidència"
msgstr[1] ""
"\n"
"Hi han %(counter)s coincidències"
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Selecció de l'editor per a '{0}' creada."
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Selecció de l'editor per '{0}' actualitzada."
msgid "Editor's picks deleted."
msgstr "Selecció de l'editor esborrada."

View file

@ -0,0 +1,169 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# M0rph 3u5 <transifex@m0rph3u5.net>, 2014
# pcraston <patrick@craston.com>, 2014
# Tammo van Lessen <tvanlessen@gmail.com>, 2015
# Wasilis Mandratzis-Walz, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: German (http://www.transifex.com/torchbox/wagtail/language/"
"de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr "Bitte geben Sie mindestens einen Vorschlag für diesen Suchbegriff an."
msgid "Page"
msgstr "Seite"
msgid "Description"
msgstr "Beschreibung"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
" <p>Hervorgehobene Suchergebnisse sind eine Möglichkeit, bestimmte "
"Seiten zu empfehlen die von sich aus nicht sehr weit oben in den "
"Suchergebnissen auftauchen würden. So könnte zum Beispiel ihre Spendenseite "
"auftauchen wenn nach dem Suchbegriff \"<em>unterstützen</em>\" gesucht wird."
"</p>\n"
" "
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
" <p>Im Eingabefeld \"Suchbegriffe/Phrasen\" müssen sie den "
"vollständigen und genauen Suchbegriff, inklusive eventueller "
"Rechtschreibfehler, eingeben, für den sie Seiten empfehlen möchten. Zur "
"Unterstützung können sie aus häufig verwendeten Suchbegriffen wählen.</p>\n"
" "
msgid "Save"
msgstr "Speichern"
#, python-format
msgid "Delete %(query)s"
msgstr "%(query)s löschen"
msgid "Delete"
msgstr "Löschen"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Sind Sie sicher, dass Sie alle hervorgehobenen Suchergebnisse für diesen "
"Suchbegriff löschen wollen?"
msgid "Yes, delete"
msgstr "Ja, löschen"
#, python-format
msgid "Editing %(query)s"
msgstr "%(query)s bearbeiten"
msgid "Editing"
msgstr "Bearbeiten"
msgid "Move up"
msgstr "Nach oben"
msgid "Move down"
msgstr "Nach unten"
msgid "Promoted search result"
msgstr "Hervorgehobenes Suchergebnis"
msgid "Add recommended page"
msgstr "Empfohlene Seite hinzufügen"
msgid "Search Terms"
msgstr "Suchbegriffe"
msgid "Promoted search results"
msgstr "Hervorgehobene Suchergebnisse"
msgid "Add new promoted result"
msgstr "Neues hervorgehobenes Suchergebnis hinzufügen"
msgid "Search term(s)"
msgstr "Suchbegriff/e"
msgid "Promoted results"
msgstr "Hervorgehobene Suchergebnisse"
msgid "Views (past week)"
msgstr "Aufrufe (letze Woche)"
msgid "Edit this pick"
msgstr "Diese Empfehlung bearbeiten"
msgid "None"
msgstr "Keine"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" Es gibt ein Ergebnis\n"
" "
msgstr[1] ""
"\n"
" Es gibt %(counter)s Ergebnisse\n"
" "
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Leider gibt es keine hervorgehobenen Suchergebnisse, die zu \"<em>"
"%(query_string)s</em>\" passen."
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Redaktionsempfehlungen für '{0}' erstellt."
msgid "Edit"
msgstr "Bearbeiten"
msgid "Recommendations have not been created due to errors"
msgstr "Empfehlungen konnten wegen eines Fehlers nicht erstellt werden"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Redaktionsempfehlungen für '{0}' geändert."
msgid "Recommendations have not been saved due to errors"
msgstr "Empfehlungen wurden wegen eines Fehlers nicht gespeichert"
msgid "Editor's picks deleted."
msgstr "Redaktionsempfehlungen gelöscht."

View file

@ -0,0 +1,164 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# dotoree <vdotoree@yahoo.gr>, 2015
# serafeim <serafeim@torchbox.com>, 2014
# Wasilis Mandratzis-Walz, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Greek (http://www.transifex.com/torchbox/wagtail/language/"
"el/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: el\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr ""
"Παρακαλείστε να διευκρινίσετε τουλάχιστον μία σύσταση για αυτόν τον όρο "
"αναζήτησης."
msgid "Page"
msgstr "Σελίδα"
msgid "Description"
msgstr "Περιγραφή"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
"<p>Οι επιλογές συντακτών είναι ένας τρόπος πρότασης συγκεκριμένων σελίδων οι "
"οποίες κανονικά δε θα βρίσκονται ψηλά στα αποτελέσματα της αναζήτησης. </p>"
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
"\n"
"<p>Το πεδίο \"όρος(οι)/φράσεις\" παρακάτω πρέπει να περιέχει το πλήρες και "
"ακριβές κείμενο για το οποίο θέλετε να παρέχετε προτεινόμενα αποτελέσματα, "
"<em>συμπεριλαμβανομένων</em> τυχόν ορθογραφικών λαθών. Προς βοήθεια, "
"μπορείτε να επιλέξετε όρους αναζήτησης που ήταν δημοφιλείς στους χρήστες.</p>"
msgid "Save"
msgstr "Αποθήκευση"
#, python-format
msgid "Delete %(query)s"
msgstr "Διαγραφή %(query)s"
msgid "Delete"
msgstr "Διαγραφή"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Είστε σίγουρος ότι θέλετε να διαγράψετε όλες τις επιλογές συντακτών για τον "
"εν λόγω όρο αναζήτησης;"
msgid "Yes, delete"
msgstr "Ναι, να διαγραφεί"
#, python-format
msgid "Editing %(query)s"
msgstr "Επεξεργασία %(query)s"
msgid "Editing"
msgstr "Διόρθωση"
msgid "Move up"
msgstr "Πάνω"
msgid "Move down"
msgstr "Κάτω"
msgid "Promoted search result"
msgstr "Προωθείται το αποτέλεσμα αναζήτησης"
msgid "Add recommended page"
msgstr "Προσθήκη προτεινόμενης σελίδας"
msgid "Search Terms"
msgstr "Όροι αναζήτησης"
msgid "Promoted search results"
msgstr "Προωθουνται τα αποτέλεσματα αναζήτησης"
msgid "Add new promoted result"
msgstr "Προσθήκη νέου προωθείμενου αποτελέσματος"
msgid "Search term(s)"
msgstr "Όροι αναζήτησης"
msgid "Promoted results"
msgstr "Προωθημενα αποτελέσματα"
msgid "Views (past week)"
msgstr "Εμφανίσεις (την περασμένη εβδομάδα)"
msgid "Edit this pick"
msgstr "Διόρθωση"
msgid "None"
msgstr "Καμία"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
"Βρέθηκε ένα αποτέλεσμα"
msgstr[1] ""
"\n"
"Βρέθηκαν %(counter)s αποτελέσματα"
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Λυπούμαστε, καμία ανακατεύθυνση δε ταιριάζει με το \"<em>%(query_string)s</"
"em>\""
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Επιτυχής δημιουργία επιλογή συντακτών για το '{0}'."
msgid "Edit"
msgstr "Επεξεργασία"
msgid "Recommendations have not been created due to errors"
msgstr "Οι συστάσεις δεν έχουν δημιουργηθεί λόγω σφαλμάτων"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Επιτυχής διόθρωση επιλογής συντακτών για το '{0}'."
msgid "Recommendations have not been saved due to errors"
msgstr "Οι συστάσεις δεν έχουν αποθηκευτεί λόγω σφαλμάτων"
msgid "Editor's picks deleted."
msgstr "Επιτυχής διαγραφή επιλογής συντακτών."

View file

@ -0,0 +1,196 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:31
msgid "Please specify at least one recommendation for this search term."
msgstr ""
#: models.py:9
msgid "Page"
msgstr ""
#: models.py:11
msgid "Description"
msgstr ""
#: models.py:18
msgid "Search promotion"
msgstr ""
#: templates/wagtailsearchpromotions/add.html:3
#: templates/wagtailsearchpromotions/add.html:5
msgid "Add search pick"
msgstr ""
#: templates/wagtailsearchpromotions/add.html:10
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
#: templates/wagtailsearchpromotions/add.html:14
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
#: templates/wagtailsearchpromotions/add.html:28
#: templates/wagtailsearchpromotions/edit.html:19
msgid "Save"
msgstr ""
#: templates/wagtailsearchpromotions/confirm_delete.html:3
#, python-format
msgid "Delete %(query)s"
msgstr ""
#: templates/wagtailsearchpromotions/confirm_delete.html:5
#: templates/wagtailsearchpromotions/edit.html:20
#: templates/wagtailsearchpromotions/includes/searchpromotion_form.html:6
msgid "Delete"
msgstr ""
#: templates/wagtailsearchpromotions/confirm_delete.html:9
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
#: templates/wagtailsearchpromotions/confirm_delete.html:12
msgid "Yes, delete"
msgstr ""
#: templates/wagtailsearchpromotions/edit.html:3
#, python-format
msgid "Editing %(query)s"
msgstr ""
#: templates/wagtailsearchpromotions/edit.html:5
msgid "Editing"
msgstr ""
#: templates/wagtailsearchpromotions/includes/searchpromotion_form.html:4
msgid "Move up"
msgstr ""
#: templates/wagtailsearchpromotions/includes/searchpromotion_form.html:5
msgid "Move down"
msgstr ""
#: templates/wagtailsearchpromotions/includes/searchpromotion_form.html:10
msgid "Promoted search result"
msgstr ""
#: templates/wagtailsearchpromotions/includes/searchpromotions_formset.html:16
msgid "Add recommended page"
msgstr ""
#: templates/wagtailsearchpromotions/index.html:3
msgid "Search Terms"
msgstr ""
#: templates/wagtailsearchpromotions/index.html:16 wagtail_hooks.py:30
msgid "Promoted search results"
msgstr ""
#: templates/wagtailsearchpromotions/index.html:17
msgid "Add new promoted result"
msgstr ""
#: templates/wagtailsearchpromotions/list.html:8
msgid "Search term(s)"
msgstr ""
#: templates/wagtailsearchpromotions/list.html:9
msgid "Promoted results"
msgstr ""
#: templates/wagtailsearchpromotions/list.html:10
msgid "Views (past week)"
msgstr ""
#: templates/wagtailsearchpromotions/list.html:17
msgid "Edit this pick"
msgstr ""
#: templates/wagtailsearchpromotions/list.html:23
msgid "None"
msgstr ""
#: templates/wagtailsearchpromotions/results.html:5
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
msgstr[1] ""
#: templates/wagtailsearchpromotions/results.html:18
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
#: templates/wagtailsearchpromotions/results.html:21
#, python-format
msgid ""
"No promoted results have been created. Why not <a href="
"\"%(wagtailsearchpromotions_add_url)s\">add one</a>?"
msgstr ""
#: views.py:51
msgid "Search promoted results"
msgstr ""
#: views.py:87
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr ""
#: views.py:88 views.py:124
msgid "Edit"
msgstr ""
#: views.py:95
msgid "Recommendations have not been created due to errors"
msgstr ""
#: views.py:123
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr ""
#: views.py:131
msgid "Recommendations have not been saved due to errors"
msgstr ""
#: views.py:150
msgid "Editor's picks deleted."
msgstr ""

View file

@ -0,0 +1,186 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# fooflare <amos.oviedo@gmail.com>, 2014
# Joaquín Tita <carpincho@gmail.com>, 2014
# José Alaguna <alagunajs@gmail.com>, 2015
# Mauricio Baeza <web@mauriciobaeza.net>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-27 01:32+0000\n"
"Last-Translator: José Alaguna <alagunajs@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/torchbox/wagtail/language/"
"es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr ""
"Por favor, especifique al menos una recomendación para este término de "
"búsqueda."
msgid "Page"
msgstr "Página"
msgid "Description"
msgstr "Descripción"
msgid "Search promotion"
msgstr "Promover búsqueda"
msgid "Add search pick"
msgstr "Añadir selección de búsqueda"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
"<p>Resultados promovidos son medios para recomendar páginas específicas que "
"pueden no aparecer en los primeros puestos de los resultados de búsqueda. "
"Por ejemplo: recomendar un sitio de donaciones utilizando términos menos "
"frecuentes como \"<em>donar</em>\".</p>"
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
"<p>El campo de \"término(s) de búsqueda/frase\", debe contener la búsqueda "
"completa y exacta para que se proporcionen los resultados recomendados, "
"<em>incluyendo</em> cualquier error de ortografía o error accidental del "
"usuario. Para ayudarte, puedes elegir entre los términos de búsqueda que han "
"sido más populares entre los usuarios de su sitio.</p>"
msgid "Save"
msgstr "Guardar"
#, python-format
msgid "Delete %(query)s"
msgstr "Eliminar %(query)s"
msgid "Delete"
msgstr "Eliminar"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"¿Esta seguro de querer borrar todos los resultados promocionados para este "
"termino de busqueda?"
msgid "Yes, delete"
msgstr "Sí, eliminar"
#, python-format
msgid "Editing %(query)s"
msgstr "Editando %(query)s"
msgid "Editing"
msgstr "Editando"
msgid "Move up"
msgstr "Subir"
msgid "Move down"
msgstr "Bajar"
msgid "Promoted search result"
msgstr "Resultados de busqueda promocionados"
msgid "Add recommended page"
msgstr "Añadir página recomendada"
msgid "Search Terms"
msgstr "Términos de búsqueda"
msgid "Promoted search results"
msgstr "Resultados de busqueda promocionados"
msgid "Add new promoted result"
msgstr "Agregar nuevo resultado promocionado"
msgid "Search term(s)"
msgstr "Término(s) de búsqueda"
msgid "Promoted results"
msgstr "Resultados promocionados"
msgid "Views (past week)"
msgstr "Vistas (semana pasada)"
msgid "Edit this pick"
msgstr "Editar esta selección"
msgid "None"
msgstr "Ninguna"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" Hay una coincidencia\n"
" "
msgstr[1] ""
"\n"
" Hay %(counter)s coincidencias\n"
" "
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Lo sentimos, resultados promovidos no encontrados \"<em>%(query_string)s</em>"
"\""
#, python-format
msgid ""
"No promoted results have been created. Why not <a href="
"\"%(wagtailsearchpromotions_add_url)s\">add one</a>?"
msgstr ""
"Resultados promovidos no han sido creados. ¿Por que no <a href="
"\"%(wagtailsearchpromotions_add_url)s\">agregar uno</a>?"
msgid "Search promoted results"
msgstr "Buscar resultados promovidos"
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Selecciones del editor para '{0}' creadas."
msgid "Edit"
msgstr "Editar"
msgid "Recommendations have not been created due to errors"
msgstr "Las recomendaciones no han sido creadas debido a errores "
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Selecciones del editor para '{0}' actualizadas."
msgid "Recommendations have not been saved due to errors"
msgstr "Las recomendaciones no han sido guardadas debido a errores"
msgid "Editor's picks deleted."
msgstr "Selecciones del editor para '{0}' eliminadas."

View file

@ -0,0 +1,169 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Adrien <laadrien@gmail.com>, 2014
# Bertrand Bordage <bordage.bertrand@gmail.com>, 2015
# nahuel, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: French (http://www.transifex.com/torchbox/wagtail/language/"
"fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr ""
"Veuillez spécifier au moins une recommandation pour ce terme de recherche."
msgid "Page"
msgstr "Page"
msgid "Description"
msgstr "Description"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
" <p>Les résultats améliorés sont un moyen de recommander des "
"pages spécifiques qui ne seraient pas arrivées naturellement en haut des "
"résultats de recherche. Ex: associer votre page de \"soutient\" à une "
"recherche utilisateur avec un terme moins explicite comme \"<em>donner</em>"
"\".</p>\n"
" "
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
" <p>Le champ \"Terme(s)/phrase de recherche\" ci-dessous doit "
"contenir la recherche complète et exacte pour laquelle vous souhaitez "
"fournir des résultats recommandés, <em>ce qui comprend</em> n'importe quelle "
"faute de frappe/erreur de l'utilisateur. Pour vous aider, vous pouvez "
"choisir parmi les termes de recherche populaires des utilisateurs de votre "
"site.</p>\n"
" "
msgid "Save"
msgstr "Enregistrer"
#, python-format
msgid "Delete %(query)s"
msgstr "Supprimée %(query)s"
msgid "Delete"
msgstr "Supprimer"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Êtes-vous sûr de vouloir supprimer tous les résultats améliorés pour ce "
"terme de recherche"
msgid "Yes, delete"
msgstr "Oui, supprimer"
#, python-format
msgid "Editing %(query)s"
msgstr "Modification de %(query)s"
msgid "Editing"
msgstr "Modification"
msgid "Move up"
msgstr "Monter"
msgid "Move down"
msgstr "Descendre"
msgid "Promoted search result"
msgstr "Résultat de recherche amélioré"
msgid "Add recommended page"
msgstr "Ajouter une page recommandée"
msgid "Search Terms"
msgstr "Termes de recherche"
msgid "Promoted search results"
msgstr "Résultats de recherche améliorés"
msgid "Add new promoted result"
msgstr "Ajouter un nouveau résultat amélioré"
msgid "Search term(s)"
msgstr "Terme(s) de recherche"
msgid "Promoted results"
msgstr "Résultats améliorés"
msgid "Views (past week)"
msgstr "Vues (semaine dernière)"
msgid "Edit this pick"
msgstr "Éditer ce choix"
msgid "None"
msgstr "Aucun"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" 1 correspondance "
msgstr[1] ""
"\n"
" %(counter)s correspondances "
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Désolé, aucun résultat amélioré correspondant pour \"<em>%(query_string)s</"
"em>\""
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Résultat amélioré pour '{0}' créé."
msgid "Edit"
msgstr "Modifier"
msgid "Recommendations have not been created due to errors"
msgstr "Les recommandations n'ont pas été créées en raison d'erreurs"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Résultat amélioré pour '{0}' mis à jour."
msgid "Recommendations have not been saved due to errors"
msgstr "Les recommandations n'ont pas été sauvegardées en raison d'erreurs"
msgid "Editor's picks deleted."
msgstr "Résultat amélioré supprimé."

View file

@ -0,0 +1,93 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# fooflare <amos.oviedo@gmail.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Galician (http://www.transifex.com/torchbox/wagtail/language/"
"gl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: gl\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Save"
msgstr "Gardar"
#, python-format
msgid "Delete %(query)s"
msgstr "Eliminar %(query)s"
msgid "Delete"
msgstr "Eliminar"
msgid "Yes, delete"
msgstr "Sí, eliminar"
#, python-format
msgid "Editing %(query)s"
msgstr "Editando %(query)s"
msgid "Editing"
msgstr "Editando"
msgid "Move up"
msgstr "Subir"
msgid "Move down"
msgstr "Baixar"
msgid "Add recommended page"
msgstr "Engadir páxina recomendada"
msgid "Search Terms"
msgstr "Termos de busca"
msgid "Search term(s)"
msgstr "Termos(s) de busca"
msgid "Views (past week)"
msgstr "Vistas (semana pasada)"
msgid "Edit this pick"
msgstr "Editar esta selección"
msgid "None"
msgstr "Ningunha"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" Hai unha coincidencia\n"
" "
msgstr[1] ""
"\n"
" Hai %(counter)s coincidencias\n"
" "
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Seleccións do editor para '{0}' creadas."
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Seleccións do editor para '{0}' actualizadas."
msgid "Editor's picks deleted."
msgstr "Seleccións do editor para '{0}' eliminadas."

View file

@ -0,0 +1,101 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# bjesus <bjesus@gmail.com>, 2015
# lior abazon <abazon@v15.org.il>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Hebrew (Israel) (http://www.transifex.com/torchbox/wagtail/"
"language/he_IL/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: he_IL\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr "אנא ציין לפחות המלצה אחת למונח חיפוש זה"
msgid "Page"
msgstr "עמוד"
msgid "Description"
msgstr "תיאור"
msgid "Save"
msgstr "שמור"
msgid "Delete"
msgstr "מחיקה"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"האם אתם בטוחים כי ברצונכם למחוק את כל התוצאות המקודמות עבור מונח חיפוש זה?"
msgid "Yes, delete"
msgstr "כן, מחק"
#, python-format
msgid "Editing %(query)s"
msgstr "עריכת %(query)s"
msgid "Editing"
msgstr "עריכה"
msgid "Move up"
msgstr "העבר מעלה"
msgid "Move down"
msgstr "העבר מטה"
msgid "Promoted search result"
msgstr "קדם תוצאת חיפוש"
msgid "Add recommended page"
msgstr "הוסף עמוד מומלץ"
msgid "Search Terms"
msgstr "מושגי חיפוש"
msgid "Promoted search results"
msgstr "תוצאות חיפוש מקודמות "
msgid "Add new promoted result"
msgstr "הוסף תוצאה מקודמת חדשה"
msgid "Promoted results"
msgstr "תוצאות מקודמות "
msgid "Edit this pick"
msgstr "ערוך בחירה זו"
msgid "None"
msgstr "אף אחת"
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "בחירת העורך עבור '{0}' נוצרה"
msgid "Edit"
msgstr "ערוך"
msgid "Recommendations have not been created due to errors"
msgstr "המלצות לא נשמרו בעקבות שגיאה"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "בחירת העורך עבור '{0}' עודכנה"
msgid "Recommendations have not been saved due to errors"
msgstr "ההמלצות לא נשמרו עקב שגיאות"
msgid "Editor's picks deleted."
msgstr "בחירת העורך נמחקה"

View file

@ -0,0 +1,170 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Claudio Bantaloukas <rockdreamer@gmail.com>, 2015
# Giacomo Ghizzani <giacomo.ghz@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Italian (http://www.transifex.com/torchbox/wagtail/language/"
"it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr ""
"Si prega di specificare almeno una raccomandazione per questo termine di "
"ricerca."
msgid "Page"
msgstr "Pagina"
msgid "Description"
msgstr "Descrizione"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
" <p>I risultati di ricerca sponsorizzati sono un mezzo di "
"raccomandare pagine specifiche che potrebbero non salire organicamente in "
"alto nei risultati dei motori di ricerca. Ad esempio, raccomanda la tua "
"pagina primaria donazione a un utente che fa una ricerca con il termine "
"comune \"<em>dare</em>\".</p>\n"
" "
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
" <p>Il campo \"Termine(i)/frase\" qui sotto deve contenere la "
"ricerca intera e esatta per cui vuoi sponsorizzare un risultato, "
"<em>incluso</em> anche ogni errore di battitura dell'utente. Puoi aiutarti "
"scegliendo fra i termini di ricerca più popolari degli utenti del tuo sito.</"
"p>\n"
" "
msgid "Save"
msgstr "Salva"
#, python-format
msgid "Delete %(query)s"
msgstr "Elimina %(query)s"
msgid "Delete"
msgstr "Elimina"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Sei sicuro di voler eliminare tutti i risultati di ricerca sponsorizzati per "
"questo termine di ricerca?"
msgid "Yes, delete"
msgstr "Si, elimina"
#, python-format
msgid "Editing %(query)s"
msgstr "Modifica %(query)s"
msgid "Editing"
msgstr "Modifica"
msgid "Move up"
msgstr "Vai su"
msgid "Move down"
msgstr "Vai giù"
msgid "Promoted search result"
msgstr "Risultati di ricerca sponsorizzati"
msgid "Add recommended page"
msgstr "Aggiungi pagina raccomandata"
msgid "Search Terms"
msgstr "Termini di ricerca"
msgid "Promoted search results"
msgstr "Risultati di ricerca promozionati"
msgid "Add new promoted result"
msgstr "Aggiungi nuovo risultato sponsorizzato"
msgid "Search term(s)"
msgstr "Termine(i) di ricerca"
msgid "Promoted results"
msgstr "Risultati promozionati"
msgid "Views (past week)"
msgstr "Viste (scorsa settimana)"
msgid "Edit this pick"
msgstr "Modifica questa scelta"
msgid "None"
msgstr "Nessuno"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" C'è una corrispondenza\n"
" "
msgstr[1] ""
"\n"
" Ci sono %(counter)s corrispondenze\n"
" "
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Spiacente, nessun risultato promozionato corrispondente a \"<em>"
"%(query_string)s</em>\""
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Scelta dalla redazione per '{0}' creata."
msgid "Edit"
msgstr "Modifica"
msgid "Recommendations have not been created due to errors"
msgstr "Raccomandazione non creata a causa di errori"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Scelta dalla redazione per '{0}' aggiornata."
msgid "Recommendations have not been saved due to errors"
msgstr "Raccomandazione non salvata a causa di errori"
msgid "Editor's picks deleted."
msgstr "Scelta dalla redazione eliminata."

View file

@ -0,0 +1,153 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Ji Han Chung <jihanchung20@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Korean (http://www.transifex.com/torchbox/wagtail/language/"
"ko/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ko\n"
"Plural-Forms: nplurals=1; plural=0;\n"
msgid "Please specify at least one recommendation for this search term."
msgstr "이 검색어를 위해 최소 한개의 추천을 지정하여 주시기 바랍니다."
msgid "Page"
msgstr "페이지"
msgid "Description"
msgstr "설명"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
"<p>프로모션 검색 결과는 일반적인 검색 결과에서 먼저 나오지 않는 추천을 위한 "
"특정 페이지들입니다. 예를 들어, 일반적이지 않은 \"<em>기부</em>\"같은 단어"
"를 검색한 사용자에게, 후원 페이지를 추천하는 형태입니다.</p>"
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
"<p>아래의 \"검색어/문장\" 필드는 틀린 철자/사용자 에러를 <em>포함한</em> 내용"
"에 대한 추천 결과를 제공하기 위해 정확한 검색어를 넣어야 합니다. 지원을 위"
"해 당신은 사이트의 유명한 검색어 중 선택할 수 있습니다. </p>"
msgid "Save"
msgstr "저장"
#, python-format
msgid "Delete %(query)s"
msgstr "%(query)s 삭제"
msgid "Delete"
msgstr "삭제"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr "이 검색어와 관련된 모든 프로모션 결과들을 정말 삭제할까요?"
msgid "Yes, delete"
msgstr "네, 지우겠습니다."
#, python-format
msgid "Editing %(query)s"
msgstr "%(query)s 수정"
msgid "Editing"
msgstr "수정중"
msgid "Move up"
msgstr "위로 이동"
msgid "Move down"
msgstr "아래로 이동"
msgid "Promoted search result"
msgstr "프로모션 검색 결과"
msgid "Add recommended page"
msgstr "추천 페이지 추가"
msgid "Search Terms"
msgstr "검색어"
msgid "Promoted search results"
msgstr "프로모션 검색 결과"
msgid "Add new promoted result"
msgstr "새로운 프로모션 결과 추가"
msgid "Search term(s)"
msgstr "검색어"
msgid "Promoted results"
msgstr "프로모션 결과"
msgid "Views (past week)"
msgstr "본 횟수(지난 주)"
msgid "Edit this pick"
msgstr "선택 수정"
msgid "None"
msgstr "없음"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
"%(counter)s 개의 연관된 결과가 있습니다"
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"죄송합니다, \"<em>%(query_string)s</em>\" 와 연관된 프로모션 결과가 없습니다."
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "'{0}' 를 위한 에디터의 선택이 추가 되었습니다."
msgid "Edit"
msgstr "수정"
msgid "Recommendations have not been created due to errors"
msgstr "에러로 인해 추천결과를 생성할 수 없습니다"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "'{0}' 를 위한 에디터의 선택이 업데이트 되었습니다."
msgid "Recommendations have not been saved due to errors"
msgstr "에러로 인해 추천결과를 저장할 수 없습니다"
msgid "Editor's picks deleted."
msgstr "에디터의 선택이 삭제 되었습니다."

View file

@ -0,0 +1,182 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Eirik Krogstad <eirikkr@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-09-02 14:43+0000\n"
"Last-Translator: Eirik Krogstad <eirikkr@gmail.com>\n"
"Language-Team: Norwegian Bokmål (http://www.transifex.com/torchbox/wagtail/"
"language/nb/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: nb\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr "Vennligst spesifiser minst en anbefaling for dette søkeordet."
msgid "Page"
msgstr "Side"
msgid "Description"
msgstr "Beskrivelse"
msgid "Search promotion"
msgstr "Søkepromotering"
msgid "Add search pick"
msgstr "Legg til søkevalg"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
"<p>Forfremmede søkeresultater er en måte å anbefale spesifikke sider som "
"ikke nødvendigvis kommer høyt opp i søkeresultater. Feks. kan man anbefale "
"kontaktsiden for en bruker som søker etter ordet <em>\"tilbakemelding\"</em>."
"</p>\n"
" "
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
"<p>Feltet \"Søkeord/-frase\" under må inneholde den fullstendige og eksakte "
"søkestrengen som du ønsker å gi anbefalinger for, <em>inkludert</em> vanlige "
"feilstavinger eller andre brukerfeil. Det kan være nyttig å se på hvilke "
"søkeord som har vært mye brukt på nettstedet.</p>\n"
" "
msgid "Save"
msgstr "Lagre"
#, python-format
msgid "Delete %(query)s"
msgstr "Slett %(query)s"
msgid "Delete"
msgstr "Slett"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Er du sikker på at du vil slette alle forfremmede resultater for dette "
"søkeordet?"
msgid "Yes, delete"
msgstr "Ja, slett"
#, python-format
msgid "Editing %(query)s"
msgstr "Endrer %(query)s"
msgid "Editing"
msgstr "Endrer"
msgid "Move up"
msgstr "Flytt opp"
msgid "Move down"
msgstr "Flytt ned"
msgid "Promoted search result"
msgstr "Forfremmet søkeresultat"
msgid "Add recommended page"
msgstr "Legg til anbefalt side"
msgid "Search Terms"
msgstr "Søkeord"
msgid "Promoted search results"
msgstr "Forfremmede søkeresultater"
msgid "Add new promoted result"
msgstr "Legg til nytt forfremmet resultat"
msgid "Search term(s)"
msgstr "Søkeord"
msgid "Promoted results"
msgstr "Forfremmede resultater"
msgid "Views (past week)"
msgstr "Visninger (siste uke)"
msgid "Edit this pick"
msgstr "Endre dette resultatet"
msgid "None"
msgstr "Ingen"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
"Det er ett treff\n"
" "
msgstr[1] ""
"\n"
"Det er %(counter)s treff\n"
" "
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Beklager, ingen forfremmede resultater samsvarer med \"<em>%(query_string)s</"
"em>\""
#, python-format
msgid ""
"No promoted results have been created. Why not <a href="
"\"%(wagtailsearchpromotions_add_url)s\">add one</a>?"
msgstr ""
"Ingen forfremmede resultater har blitt opprettet. Hvorfor ikke <a href="
"\"%(wagtailsearchpromotions_add_url)s\">legge til et</a>?"
msgid "Search promoted results"
msgstr "Søk i forfremmede resultater"
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Redaktørvalg for \"{0}\" er opprettet."
msgid "Edit"
msgstr "Endre"
msgid "Recommendations have not been created due to errors"
msgstr "Anbefalinger kunne ikke opprettes grunnet feil"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Redaktørvalg for \"{0}\" oppdatert."
msgid "Recommendations have not been saved due to errors"
msgstr "Anbefalinger kunne ikke lagres grunnet feil"
msgid "Editor's picks deleted."
msgstr "Redaktørvalg slettet."

View file

@ -0,0 +1,98 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# utek <mail@utek.pl>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Polish (http://www.transifex.com/torchbox/wagtail/language/"
"pl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pl\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
msgid "Save"
msgstr "Zapisz"
#, python-format
msgid "Delete %(query)s"
msgstr "Usuń %(query)s"
msgid "Delete"
msgstr "Usuń"
msgid "Yes, delete"
msgstr "Tak, usuń"
#, python-format
msgid "Editing %(query)s"
msgstr "Edycja %(query)s"
msgid "Editing"
msgstr "Edytujesz"
msgid "Move up"
msgstr "Przesuń w górę"
msgid "Move down"
msgstr "Przesuń w dół"
msgid "Add recommended page"
msgstr "Dodaj polecaną stronę"
msgid "Search Terms"
msgstr "Frazy wyszukiwania"
msgid "Search term(s)"
msgstr "Frazy wyszukiwania"
msgid "Views (past week)"
msgstr "Odsłony (poprzedni tydzień)"
msgid "Edit this pick"
msgstr "Edytuj ten wybór"
msgid "None"
msgstr "Brak"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" Jedno dopasowanie\n"
" "
msgstr[1] ""
"\n"
" Są %(counter)s dopasowania\n"
" "
msgstr[2] ""
"\n"
" Jest %(counter)s dopasowań\n"
" "
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Stworzono wybór redakcji dla '{0}'"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Zaktualizowano wybór redakcji dla '{0}'."
msgid "Editor's picks deleted."
msgstr "Usunięto wybór redakcji."

View file

@ -0,0 +1,163 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Claudemiro Alves Feitosa Neto <dimiro1@gmail.com>, 2015
# Gladson <gladsonbrito@gmail.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/torchbox/"
"wagtail/language/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pt_BR\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr "Especifique pelo menos uma recomendação para este termo de busca."
msgid "Page"
msgstr "Página"
msgid "Description"
msgstr "Descrição"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
"<p>Resultados de busca promovidos são meios de recomendar páginas "
"específicas que pode não aparecer organicamente nos resultados. Ex. "
"recomendar sua página de doação principal para um usuário pesquisando com um "
"termo menos comum \"<em>doando</em>\".</p>"
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
"<p>O \"Termo(s)/frase da busca\" abaixo devem conter a busca exata e "
"completa para a qual você deseja provê resultados recomendados, "
"<em>incluíndo</em> qualquer erro de digitação ou do usuário. Para ajudar, "
"você pode escolher a partir de termos que são populares entre os usuários de "
"seu site</p>"
msgid "Save"
msgstr "Salvar"
#, python-format
msgid "Delete %(query)s"
msgstr "Excluir %(query)s"
msgid "Delete"
msgstr "Excluir"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Você tem certeza que você quer excluir todos os resultados promovidos para "
"este termo?"
msgid "Yes, delete"
msgstr "Sim, apague"
#, python-format
msgid "Editing %(query)s"
msgstr "Editando %(query)s"
msgid "Editing"
msgstr "Editando"
msgid "Move up"
msgstr "Mover para cima"
msgid "Move down"
msgstr "Mover para baixo"
msgid "Promoted search result"
msgstr "Resultado promovido"
msgid "Add recommended page"
msgstr "Adicionar recomendação para página"
msgid "Search Terms"
msgstr "Procurar Termos"
msgid "Promoted search results"
msgstr "Resultados promovidos"
msgid "Add new promoted result"
msgstr "Adicionar um novo resultado promovido"
msgid "Search term(s)"
msgstr "Procurar termo(s)"
msgid "Promoted results"
msgstr "Resultados promovidos"
msgid "Views (past week)"
msgstr "Visualizações (última semana)"
msgid "Edit this pick"
msgstr "Editar sugestão do editor"
msgid "None"
msgstr "Nenhum"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
" Há um resultado\n"
" "
msgstr[1] ""
"\n"
" Há %(counter)s resultados\n"
" "
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr "Desculpe, nenhum resultado promovido com \"<em>%(query_string)s</em>\""
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Sugestões dos editores para '{0}' criados."
msgid "Edit"
msgstr "Editar"
msgid "Recommendations have not been created due to errors"
msgstr "As recomendações não poderiam ser criadas devido a erros"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Sugestões do editor para '{0}' atualizado."
msgid "Recommendations have not been saved due to errors"
msgstr "As recomendações não puderam ser salvas devido a erros"
msgid "Editor's picks deleted."
msgstr "Sugestões do editor deletado."

View file

@ -0,0 +1,168 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Gladson <gladsonbrito@gmail.com>, 2014
# Tiago Henriques <trinosauro@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Portuguese (Portugal) (http://www.transifex.com/torchbox/"
"wagtail/language/pt_PT/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pt_PT\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Please specify at least one recommendation for this search term."
msgstr ""
"Por favor especifique pelo menos uma recomendação para este termo de "
"pesquisa."
msgid "Page"
msgstr "Página"
msgid "Description"
msgstr "Descrição"
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
"<p>Os resultados de pesquisa promovidos servem para recomendar páginas "
"específicas que podem não aparecer bem posicionadas nos resultados de "
"pesquisa. Por exemplo, recomendar a sua página principal de donativos a um "
"utilizador que pesquisa um termo menos comum como \"<em>dar</em>\".</p>\n"
" "
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
"<p>O campo \"Pesquisar termo(s)/frase\" abaixo tem de conter a pesquisa "
"completa e exata para a qual pretende obter resultados recomendados, "
"<em>incluindo</em> quaisquer erros de ortografia/utilizador. Para facilitar, "
"pode escolher de entre os termos de pesquisa que são frequentemente usados "
"pelos utilizadores do seu site.</p>\n"
" "
msgid "Save"
msgstr "Guardar"
#, python-format
msgid "Delete %(query)s"
msgstr "Apagar %(query)s"
msgid "Delete"
msgstr "Apagar"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Tem a certeza que quer apagar todos os resultados promovidos para este termo "
"de pesquisa?"
msgid "Yes, delete"
msgstr "Sim, apagar"
#, python-format
msgid "Editing %(query)s"
msgstr "A editar %(query)s"
msgid "Editing"
msgstr "A editar"
msgid "Move up"
msgstr "Mover para cima"
msgid "Move down"
msgstr "Mover para baixo"
msgid "Promoted search result"
msgstr "Resultado de pesquisa promovido"
msgid "Add recommended page"
msgstr "Adicionar uma página recomendada"
msgid "Search Terms"
msgstr "Pesquisar Termos"
msgid "Promoted search results"
msgstr "Resultados de pesquisa promovidos"
msgid "Add new promoted result"
msgstr "Adicionar novo resultado promovido"
msgid "Search term(s)"
msgstr "Pesquisar termo(s)"
msgid "Promoted results"
msgstr "Resultados promovidos"
msgid "Views (past week)"
msgstr "Visualizações (última semana)"
msgid "Edit this pick"
msgstr "Editar esta escolha"
msgid "None"
msgstr "Nenhuma"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
"Encontrado um resultado\n"
" "
msgstr[1] ""
"\n"
"Encontrados %(counter)s resultados\n"
" "
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Desculpe, nenhuma resultado promovido contém \"<em>%(query_string)s</em>\""
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Escolhas do editor para '{0}' criadas."
msgid "Edit"
msgstr "Editar"
msgid "Recommendations have not been created due to errors"
msgstr "As recomendações não foram criadas devido a erros."
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Escolhas do editor para '{0}' atualizadas."
msgid "Recommendations have not been saved due to errors"
msgstr "As recomendações não foram guardadas devido a erros."
msgid "Editor's picks deleted."
msgstr "Escolhas do editor apagadas."

View file

@ -0,0 +1,157 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Dan Braghis, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Romanian (http://www.transifex.com/torchbox/wagtail/language/"
"ro/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ro\n"
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?"
"2:1));\n"
msgid "Please specify at least one recommendation for this search term."
msgstr "Introduceți cel puțin o recomandare pentru acest termen de căutare."
msgid ""
"\n"
" <p>Promoted search results are a means of recommending "
"specific pages that might not organically come high up in search results. E."
"g recommending your primary donation page to a user searching with the less "
"common term \"<em>giving</em>\".</p>\n"
" "
msgstr ""
"\n"
"<p>Rezultatele de căutare promovate reprezintă o modalitate de recomandare a "
"paginilor care pot să nu apară în topul rezultatelor de căutare în mod "
"organic. De exemplu, recomandărea paginii principale de donații unui "
"utilizator care caută termenul mai puțin frecvent \"<em>dare</em>\".</p>\n"
" "
msgid ""
"\n"
" <p>The \"Search term(s)/phrase\" field below must contain "
"the full and exact search for which you wish to provide recommended results, "
"<em>including</em> any misspellings/user error. To help, you can choose from "
"search terms that have been popular with users of your site.</p>\n"
" "
msgstr ""
"\n"
"<p>Câmpul \"Termeni/frază de căutare\" de mai jos trebuie să conțină șirul "
"exact pentru care doriți să furnizați rezultate recomandate. <em>Includeți</"
"em> greșeli ortografice și alte greșeli. Puteți să alegeți din termenii de "
"căutare populari printre utilizatorii sitului dvs.</p>"
msgid "Save"
msgstr "Salvează"
#, python-format
msgid "Delete %(query)s"
msgstr "Șterge %(query)s"
msgid "Delete"
msgstr "Șterge"
msgid ""
"Are you sure you want to delete all promoted results for this search term?"
msgstr ""
"Sigur doriți să ștergeți toate rezultatele promovate pentru acest termen de "
"căutare?"
msgid "Yes, delete"
msgstr "Da, șterge"
#, python-format
msgid "Editing %(query)s"
msgstr "Editare %(query)s"
msgid "Editing"
msgstr "Editare"
msgid "Move up"
msgstr "Deplasează în sus"
msgid "Move down"
msgstr "Deplasează în jos"
msgid "Promoted search result"
msgstr "Rezultat de căutare promovat"
msgid "Add recommended page"
msgstr "Adaugă pagină recomandată"
msgid "Search Terms"
msgstr "Termeni de căutare"
msgid "Promoted search results"
msgstr "Rezultate de căutare promovate"
msgid "Add new promoted result"
msgstr "Adaugă rezultat promovat"
msgid "Search term(s)"
msgstr "Termen de căutare"
msgid "Promoted results"
msgstr "Rezultate promovate"
msgid "Views (past week)"
msgstr "Vizualizări (ultima săptămână)"
msgid "Edit this pick"
msgstr "Editează selecția"
msgid "None"
msgstr "Nici una"
#, python-format
msgid ""
"\n"
" There is one match\n"
" "
msgid_plural ""
"\n"
" There are %(counter)s matches\n"
" "
msgstr[0] ""
"\n"
"Există o potrivire"
msgstr[1] ""
"\n"
"Sunt %(counter)s potriviri"
msgstr[2] ""
"\n"
"Sunt %(counter)s potriviri"
#, python-format
msgid "Sorry, no promoted results match \"<em>%(query_string)s</em>\""
msgstr ""
"Ne pare rău, \"<em>%(query_string)s</em>\" nu se potrivește cu nici un "
"rezultat promovat"
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "Selecțiile editoriale pentru '{0}' au fost create."
msgid "Recommendations have not been created due to errors"
msgstr "Recomandările nu au fost create din cauza erorilor."
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "Selecțiile editoriale pentru '{0}' au fost actualizate."
msgid "Recommendations have not been saved due to errors"
msgstr "Recomandările nu au fost salvate din cauza erorilor."
msgid "Editor's picks deleted."
msgstr "Selecțiile editoriale au fost șterse"

View file

@ -0,0 +1,74 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Chinese (http://www.transifex.com/torchbox/wagtail/language/"
"zh/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh\n"
"Plural-Forms: nplurals=1; plural=0;\n"
msgid "Save"
msgstr "保存"
#, python-format
msgid "Delete %(query)s"
msgstr "删除Delete %(query)s"
msgid "Delete"
msgstr "删除"
msgid "Yes, delete"
msgstr "是的,删除"
#, python-format
msgid "Editing %(query)s"
msgstr "编辑%(query)s"
msgid "Editing"
msgstr "编辑"
msgid "Move up"
msgstr "向上移动"
msgid "Move down"
msgstr "向下移动"
msgid "Add recommended page"
msgstr "添加推荐页"
msgid "Search Terms"
msgstr "搜索关键词"
msgid "Search term(s)"
msgstr "搜索关键词"
msgid "Views (past week)"
msgstr "查看 (上周)"
msgid "Edit this pick"
msgstr "编辑这个精选"
msgid "None"
msgstr "没有"
#, python-brace-format
msgid "Editor's picks for '{0}' created."
msgstr "编辑精选'{0}'已创建。"
#, python-brace-format
msgid "Editor's picks for '{0}' updated."
msgstr "编辑精选'{0}'已更新。"
msgid "Editor's picks deleted."
msgstr "编辑精选已删除"

View file

@ -0,0 +1,58 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# hanfeng <appweb.cn@gmail.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:46+0100\n"
"PO-Revision-Date: 2015-08-26 14:14+0000\n"
"Last-Translator: Karl Hobley <karl@torchbox.com>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/torchbox/wagtail/"
"language/zh_CN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0;\n"
msgid "Page"
msgstr "页面"
msgid "Description"
msgstr "描述"
msgid "Save"
msgstr "保存"
#, python-format
msgid "Delete %(query)s"
msgstr "删除%(query)s"
msgid "Delete"
msgstr "删除"
msgid "Yes, delete"
msgstr "是,删除"
#, python-format
msgid "Editing %(query)s"
msgstr "编辑%(query)s"
msgid "Editing"
msgstr "编辑"
msgid "Move up"
msgstr "上移"
msgid "Move down"
msgstr "下移"
msgid "Search Terms"
msgstr "检索词"
msgid "Edit"
msgstr "编辑"

View file

@ -1,6 +1,7 @@
from django import template
from wagtail.wagtailsearch.models import Query
from wagtail.contrib.wagtailsearchpromotions.models import SearchPromotion
register = template.Library()
@ -8,4 +9,7 @@ register = template.Library()
@register.assignment_tag()
def get_search_promotions(search_query):
return Query.get(search_query).editors_picks.all()
if search_query:
return Query.get(search_query).editors_picks.all()
else:
return SearchPromotion.objects.none()

View file

@ -71,6 +71,10 @@ class TestGetSearchPromotionsTemplateTag(TestCase):
search_picks = list(get_search_promotions("root page"))
self.assertEqual(search_picks, [pick])
def test_get_search_promotions_with_none_query_string(self):
search_picks = list(get_search_promotions(None))
self.assertEqual(search_picks, [])
class TestSearchPromotionsIndexView(TestCase, WagtailTestUtils):
def setUp(self):

View file

@ -9,10 +9,12 @@ from wagtail.wagtailsearch import forms as search_forms
from wagtail.wagtailsearch.models import Query
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailadmin import messages
from wagtail.wagtailadmin.utils import permission_required, any_permission_required
from wagtail.contrib.wagtailsearchpromotions import forms
@any_permission_required('wagtailsearchpromotions.add_searchpromotion', 'wagtailsearchpromotions.change_searchpromotion', 'wagtailsearchpromotions.delete_searchpromotion')
@vary_on_headers('X-Requested-With')
def index(request):
is_searching = False
@ -71,6 +73,7 @@ def save_searchpicks(query, new_query, searchpicks_formset):
return False
@permission_required('wagtailsearchpromotions.add_searchpromotion')
def add(request):
if request.POST:
# Get query
@ -102,6 +105,7 @@ def add(request):
})
@permission_required('wagtailsearchpromotions.change_searchpromotion')
def edit(request, query_id):
query = get_object_or_404(Query, id=query_id)
@ -137,6 +141,7 @@ def edit(request, query_id):
})
@permission_required('wagtailsearchpromotions.delete_searchpromotion')
def delete(request, query_id):
query = get_object_or_404(Query, id=query_id)

View file

@ -1,6 +1,7 @@
from django.core import urlresolvers
from django.conf.urls import include, url
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import Permission
from wagtail.wagtailcore import hooks
from wagtail.contrib.wagtailsearchpromotions import admin_urls
@ -17,10 +18,19 @@ def register_admin_urls():
class SearchPicksMenuItem(MenuItem):
def is_shown(self, request):
# TEMPORARY: Only show if the user is a superuser
return request.user.is_superuser
return (
request.user.has_perm('wagtailsearchpromotions.add_searchpromotion')
or request.user.has_perm('wagtailsearchpromotions.change_searchpromotion')
or request.user.has_perm('wagtailsearchpromotions.delete_searchpromotion')
)
@hooks.register('register_settings_menu_item')
def register_search_picks_menu_item():
return SearchPicksMenuItem(_('Promoted search results'), urlresolvers.reverse('wagtailsearchpromotions:index'), classnames='icon icon-pick', order=900)
@hooks.register('register_permissions')
def register_permissions():
return Permission.objects.filter(content_type__app_label='wagtailsearchpromotions',
codename__in=['add_searchpromotion', 'change_searchpromotion', 'delete_searchpromotion'])

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-03-06 12:05+0000\n"
"POT-Creation-Date: 2015-08-26 14:28+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -30,26 +30,26 @@ msgstr ""
msgid "Delete image"
msgstr ""
#: views.py:45
#: views.py:42
msgid "Search something"
msgstr ""
#: views.py:49
#: views.py:46
msgid "Success message"
msgstr ""
#: views.py:50 views.py:54 views.py:58
#: views.py:47 views.py:51 views.py:55
msgid "View live"
msgstr ""
#: views.py:51 views.py:55 views.py:59
#: views.py:48 views.py:52 views.py:56
msgid "Edit"
msgstr ""
#: views.py:53
#: views.py:50
msgid "Warning message"
msgstr ""
#: views.py:57
#: views.py:54
msgid "Error message"
msgstr ""

View file

@ -0,0 +1,47 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# José Alaguna <alagunajs@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:28+0100\n"
"PO-Revision-Date: 2015-08-27 01:40+0000\n"
"Last-Translator: José Alaguna <alagunajs@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/torchbox/wagtail/language/"
"es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Styleguide"
msgstr "Guía de estilo"
msgid "Save"
msgstr "Guardar"
msgid "Delete image"
msgstr "Eliminar imagen"
msgid "Search something"
msgstr "Buscar algo"
msgid "Success message"
msgstr "Mensaje de éxito"
msgid "View live"
msgstr "Ver en vivo"
msgid "Edit"
msgstr "Editar"
msgid "Warning message"
msgstr "Mensaje de advertencia"
msgid "Error message"
msgstr "Mensaje de error"

View file

@ -0,0 +1,47 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Arnar Tumi Þorsteinsson <arnartumi@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:28+0100\n"
"PO-Revision-Date: 2015-08-31 20:31+0000\n"
"Last-Translator: Arnar Tumi Þorsteinsson <arnartumi@gmail.com>\n"
"Language-Team: Icelandic (Iceland) (http://www.transifex.com/torchbox/"
"wagtail/language/is_IS/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: is_IS\n"
"Plural-Forms: nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);\n"
msgid "Styleguide"
msgstr "Stílblað"
msgid "Save"
msgstr "Vista"
msgid "Delete image"
msgstr "Eyða mynd"
msgid "Search something"
msgstr "Leita"
msgid "Success message"
msgstr "Jákvæð skilaboð"
msgid "View live"
msgstr "Skoða lifandi"
msgid "Edit"
msgstr "Breyta"
msgid "Warning message"
msgstr "Viðvörunar skilaboð"
msgid "Error message"
msgstr "Villu skilaboð"

View file

@ -0,0 +1,47 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Eirik Krogstad <eirikkr@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:28+0100\n"
"PO-Revision-Date: 2015-09-01 22:14+0000\n"
"Last-Translator: Eirik Krogstad <eirikkr@gmail.com>\n"
"Language-Team: Norwegian Bokmål (http://www.transifex.com/torchbox/wagtail/"
"language/nb/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: nb\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Styleguide"
msgstr "Stilguide"
msgid "Save"
msgstr "Lagre"
msgid "Delete image"
msgstr "Slett bilde"
msgid "Search something"
msgstr "Søk etter noe"
msgid "Success message"
msgstr "Positiv tilbakemeldning"
msgid "View live"
msgstr "Se publisert"
msgid "Edit"
msgstr "Rediger"
msgid "Warning message"
msgstr "Advarsel"
msgid "Error message"
msgstr "Feilmelding"

View file

@ -0,0 +1,48 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Dan Braghis, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:28+0100\n"
"PO-Revision-Date: 2015-09-02 21:38+0000\n"
"Last-Translator: Dan Braghis\n"
"Language-Team: Romanian (http://www.transifex.com/torchbox/wagtail/language/"
"ro/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ro\n"
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?"
"2:1));\n"
msgid "Styleguide"
msgstr "Ghid de stil"
msgid "Save"
msgstr "Salveză"
msgid "Delete image"
msgstr "Șterge imagine"
msgid "Search something"
msgstr "Caută ceva"
msgid "Success message"
msgstr "Mesaj de success"
msgid "View live"
msgstr "Vezi în direct"
msgid "Edit"
msgstr "Editează"
msgid "Warning message"
msgstr "Mesaj de avertizare"
msgid "Error message"
msgstr "Mesaj de eroare"

View file

@ -0,0 +1,49 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Eugene MechanisM <contact@mechanism.name>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Wagtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-26 14:28+0100\n"
"PO-Revision-Date: 2015-08-26 21:47+0000\n"
"Last-Translator: Eugene MechanisM <contact@mechanism.name>\n"
"Language-Team: Russian (http://www.transifex.com/torchbox/wagtail/language/"
"ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
msgid "Styleguide"
msgstr "Гид по стилям"
msgid "Save"
msgstr "Сохранить"
msgid "Delete image"
msgstr "Удалить изображение"
msgid "Search something"
msgstr "Искать что-нибудь"
msgid "Success message"
msgstr "Сообщение об успехе"
msgid "View live"
msgstr "Смотреть на сайте"
msgid "Edit"
msgstr "Правка"
msgid "Warning message"
msgstr "Сообщение с предупреждением"
msgid "Error message"
msgstr "Сообщение с ошибкой"

View file

@ -301,6 +301,22 @@
</section>
<section id="button-groups">
<h2>Button groups</h2>
<p>Adds rounding to first and last items only</p>
<div class="button-group">
<button>button element</button>
<button>button element</button>
<button>button element</button>
</div>
<br />
<div class="button-group">
<button class="icon text-replace yes icon-tick">A proper button</button>
<a href="#" class="button icon text-replace white icon-cog">A link button</a>
<span class="button icon text-replace no icon-bin">A non-link button</span>
</div>
</section>
<section id="dropdowns">
<h2>Dropdown buttons</h2>
@ -374,7 +390,7 @@
{% include "wagtailadmin/shared/header.html" with title=title_trans %}
{% include "wagtailadmin/shared/header.html" with title=title_trans add_link="wagtailimages_add_image" icon="image" add_text="button" search_url="wagtailimages:index" %}
{% include "wagtailadmin/shared/header.html" with title=title_trans add_link="wagtailimages:add" icon="image" add_text="button" search_url="wagtailimages:index" %}
</section>
<section id="forms">

View file

@ -2,13 +2,13 @@ from django import forms
from django.shortcuts import render
from django.utils.translation import ugettext as _
from wagtail.wagtailadmin import messages
from django.contrib.auth.decorators import permission_required
from wagtail.wagtailadmin.forms import SearchForm
from wagtail.wagtailadmin.widgets import AdminPageChooser, AdminDateInput, AdminTimeInput, AdminDateTimeInput
from wagtail.wagtailimages.widgets import AdminImageChooser
from wagtail.wagtaildocs.widgets import AdminDocumentChooser
class ExampleForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ExampleForm, self).__init__(*args, **kwargs)
@ -37,8 +37,6 @@ class ExampleForm(forms.Form):
document_chooser = forms.BooleanField(required=True)
@permission_required('wagtailadmin.access_admin')
def index(request):
form = SearchForm(placeholder=_("Search something"))

View file

@ -1,2 +1,2 @@
Django>=1.8,<1.9
wagtail==1.0
wagtail==1.1rc1

View file

@ -0,0 +1,72 @@
# This file contains a file storage backend that imitates behaviours of
# common external storage backends (S3 boto, libcloud, etc).
# The following behaviours have been added to this backend:
# - Calling .path on the storage or image file raises NotImplementedError
# - File.open() after the file has been closed raises an error
from django.core.files.storage import Storage, FileSystemStorage
from django.core.files.base import File
from django.utils.deconstruct import deconstructible
@deconstructible
class DummyExternalStorage(Storage):
def __init__(self, *args, **kwargs):
self.wrapped = FileSystemStorage(*args, **kwargs)
def path(self, name):
# Overridden to give it the behaviour of the base Storage class
# This is what an external storage backend would have
raise NotImplementedError("This backend doesn't support absolute paths.")
def _open(self, name, mode='rb'):
# Overridden to return a DummyExternalStorageFile instead of a normal
# File object
return DummyExternalStorageFile(open(self.wrapped.path(name), mode))
# Wrap all other functions
def _save(self, name, content):
return self.wrapped._save(name, content)
def delete(self, name):
self.wrapped.delete(name)
def exists(self, name):
return self.wrapped.exists(name)
def listdir(self, path):
return self.wrapped.listdir(path)
def size(self, name):
return self.wrapped.size(name)
def url(self, name):
return self.wrapped.url(name)
def accessed_time(self, name):
return self.wrapped.accessed_time(name)
def created_time(self, name):
return self.wrapped.created_time(name)
def modified_time(self, name):
return self.wrapped.modified_time(name)
class DummyExternalStorageFile(File):
def open(self, mode=None):
# Based on: https://github.com/django/django/blob/2c39f282b8389f47fee4b24e785a58567c6c3629/django/core/files/base.py#L135-L141
# I've commented out two lines of this function which stops it checking
# the filesystem for the file. Making it behave as if it is using an
# external file storage.
if not self.closed:
self.seek(0)
# elif self.name and os.path.exists(self.name):
# self.file = open(self.name, mode or self.mode)
else:
raise ValueError("The file cannot be reopened.")

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import wagtail.wagtailsearch.index
class Migration(migrations.Migration):
dependencies = [
('snippetstests', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SearchableSnippet',
fields=[
('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')),
('text', models.CharField(max_length=255)),
],
bases=(models.Model, wagtail.wagtailsearch.index.Indexed),
),
]

View file

@ -1,6 +1,8 @@
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from wagtail.wagtailsearch import index
from wagtail.wagtailsnippets.models import register_snippet
@ -36,3 +38,17 @@ register_snippet(RegisterFunction)
@register_snippet
class RegisterDecorator(models.Model):
pass
# A snippet model that inherits from index.Indexed can be searched on
@register_snippet
class SearchableSnippet(models.Model, index.Indexed):
text = models.CharField(max_length=255)
search_fields = (
index.SearchField('text'),
)
def __str__(self):
return self.text

View file

@ -39,7 +39,7 @@
"model": "wagtailcore.page",
"fields": {
"title": "Events",
"numchild": 4,
"numchild": 5,
"show_in_menus": true,
"live": true,
"depth": 3,
@ -86,6 +86,41 @@
}
},
{
"pk": 13,
"model": "wagtailcore.page",
"fields": {
"title": "Saint Patrick",
"numchild": 0,
"show_in_menus": true,
"live": true,
"depth": 4,
"content_type": ["tests", "singleeventpage"],
"path": "0001000100010005",
"url_path": "/home/events/saint-patrick/",
"slug": "saint-patrick",
"owner": 2
}
},
{
"pk": 13,
"model": "tests.eventpage",
"fields": {
"date_from": "2014-12-25",
"audience": "private",
"location": "Wellington",
"body": "<p>The day when nothing makes sense.</p>",
"cost": "Semi-free"
}
},
{
"pk": 13,
"model": "tests.singleeventpage",
"fields": {
"excerpt": "A little tiny excerpt for Saint Patrick."
}
},
{
"pk": 1,
"model": "tests.eventpagespeaker",

View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('tests', '0006_image_file_size'),
]
operations = [
migrations.AlterField(
model_name='customimagewithadminformfields',
name='created_at',
field=models.DateTimeField(db_index=True, verbose_name='Created at', auto_now_add=True),
),
migrations.AlterField(
model_name='customimagewithoutadminformfields',
name='created_at',
field=models.DateTimeField(db_index=True, verbose_name='Created at', auto_now_add=True),
),
]

View file

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('tests', '0006_image_file_size'),
]
operations = [
migrations.CreateModel(
name='SingleEventPage',
fields=[
('eventpage_ptr', models.OneToOneField(auto_created=True, to='tests.EventPage', serialize=False, parent_link=True, primary_key=True)),
('excerpt', models.TextField(help_text='Short text to describe what is this action about', max_length=255, null=True, blank=True)),
],
bases=('tests.eventpage',),
),
]

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('tests', '0007_auto_20150819_0614'),
('tests', '0007_singleeventpage'),
]
operations = [
]

Some files were not shown because too many files have changed in this diff Show more