summaryrefslogtreecommitdiffstats
path: root/doc/usage/advanced
diff options
context:
space:
mode:
Diffstat (limited to 'doc/usage/advanced')
-rw-r--r--doc/usage/advanced/intl.rst372
-rw-r--r--doc/usage/advanced/websupport/api.rst80
-rw-r--r--doc/usage/advanced/websupport/index.rst16
-rw-r--r--doc/usage/advanced/websupport/quickstart.rst255
-rw-r--r--doc/usage/advanced/websupport/searchadapters.rst49
-rw-r--r--doc/usage/advanced/websupport/storagebackends.rst49
6 files changed, 821 insertions, 0 deletions
diff --git a/doc/usage/advanced/intl.rst b/doc/usage/advanced/intl.rst
new file mode 100644
index 0000000..ae6e7dc
--- /dev/null
+++ b/doc/usage/advanced/intl.rst
@@ -0,0 +1,372 @@
+.. _intl:
+
+Internationalization
+====================
+
+.. versionadded:: 1.1
+
+Complementary to translations provided for Sphinx-generated messages such as
+navigation bars, Sphinx provides mechanisms facilitating the translation of
+*documents*. See the :ref:`intl-options` for details on configuration.
+
+.. figure:: /_static/translation.*
+ :width: 100%
+
+ Workflow visualization of translations in Sphinx. (The figure is created by
+ `plantuml <https://plantuml.com>`_.)
+
+.. contents::
+ :local:
+
+Sphinx internationalization details
+-----------------------------------
+
+**gettext** [1]_ is an established standard for internationalization and
+localization. It naively maps messages in a program to a translated string.
+Sphinx uses these facilities to translate whole documents.
+
+Initially project maintainers have to collect all translatable strings (also
+referred to as *messages*) to make them known to translators. Sphinx extracts
+these through invocation of ``sphinx-build -b gettext``.
+
+Every single element in the doctree will end up in a single message which
+results in lists being equally split into different chunks while large
+paragraphs will remain as coarsely-grained as they were in the original
+document. This grants seamless document updates while still providing a little
+bit of context for translators in free-text passages. It is the maintainer's
+task to split up paragraphs which are too large as there is no sane automated
+way to do that.
+
+After Sphinx successfully ran the
+:class:`~sphinx.builders.gettext.MessageCatalogBuilder` you will find a
+collection of ``.pot`` files in your output directory. These are **catalog
+templates** and contain messages in your original language *only*.
+
+They can be delivered to translators which will transform them to ``.po`` files
+--- so called **message catalogs** --- containing a mapping from the original
+messages to foreign-language strings.
+
+*gettext* compiles them into a binary format known as **binary catalogs**
+through :program:`msgfmt` for efficiency reasons. If you make these files
+discoverable with :confval:`locale_dirs` for your :confval:`language`, Sphinx
+will pick them up automatically.
+
+An example: you have a document ``usage.rst`` in your Sphinx project. The
+*gettext* builder will put its messages into ``usage.pot``. Imagine you have
+Spanish translations [2]_ stored in ``usage.po`` --- for your builds to
+be translated you need to follow these instructions:
+
+* Compile your message catalog to a locale directory, say ``locale``, so it
+ ends up in ``./locale/es/LC_MESSAGES/usage.mo`` in your source directory
+ (where ``es`` is the language code for Spanish.) ::
+
+ msgfmt "usage.po" -o "locale/es/LC_MESSAGES/usage.mo"
+
+* Set :confval:`locale_dirs` to ``["locale/"]``.
+* Set :confval:`language` to ``es`` (also possible via
+ :option:`-D <sphinx-build -D>`).
+* Run your desired build.
+
+
+In order to protect against mistakes, a warning is emitted if
+cross-references in the translated paragraph do not match those from the
+original. This can be turned off globally using the
+:confval:`suppress_warnings` configuration variable. Alternatively, to
+turn it off for one message only, end the message with ``#noqa`` like
+this::
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
+ risus tortor, luctus id ultrices at. #noqa
+
+(Write ``\#noqa`` in case you want to have "#noqa" literally in the
+text. This does not apply to code blocks, where ``#noqa`` is ignored
+because code blocks do not contain references anyway.)
+
+.. versionadded:: 4.5
+ The ``#noqa`` mechanism.
+
+
+Translating with sphinx-intl
+----------------------------
+
+Quick guide
+~~~~~~~~~~~
+
+`sphinx-intl`_ is a useful tool to work with Sphinx translation flow. This
+section describe an easy way to translate with *sphinx-intl*.
+
+#. Install `sphinx-intl`_.
+
+ .. code-block:: console
+
+ $ pip install sphinx-intl
+
+#. Add configurations to ``conf.py``.
+
+ ::
+
+ locale_dirs = ['locale/'] # path is example but recommended.
+ gettext_compact = False # optional.
+
+ This case-study assumes that BUILDDIR is set to ``_build``,
+ :confval:`locale_dirs` is set to ``locale/`` and :confval:`gettext_compact`
+ is set to ``False`` (the Sphinx document is already configured as such).
+
+#. Extract translatable messages into pot files.
+
+ .. code-block:: console
+
+ $ make gettext
+
+ The generated pot files will be placed in the ``_build/gettext`` directory.
+
+#. Generate po files.
+
+ We'll use the pot files generated in the above step.
+
+ .. code-block:: console
+
+ $ sphinx-intl update -p _build/gettext -l de -l ja
+
+ Once completed, the generated po files will be placed in the below
+ directories:
+
+ * ``./locale/de/LC_MESSAGES/``
+ * ``./locale/ja/LC_MESSAGES/``
+
+#. Translate po files.
+
+ As noted above, these are located in the ``./locale/<lang>/LC_MESSAGES``
+ directory. An example of one such file, from Sphinx, ``builders.po``, is
+ given below.
+
+ .. code-block:: po
+
+ # a5600c3d2e3d48fc8c261ea0284db79b
+ #: ../../builders.rst:4
+ msgid "Available builders"
+ msgstr "<FILL HERE BY TARGET LANGUAGE>"
+
+ Another case, msgid is multi-line text and contains reStructuredText syntax:
+
+ .. code-block:: po
+
+ # 302558364e1d41c69b3277277e34b184
+ #: ../../builders.rst:9
+ msgid ""
+ "These are the built-in Sphinx builders. More builders can be added by "
+ ":ref:`extensions <extensions>`."
+ msgstr ""
+ "FILL HERE BY TARGET LANGUAGE FILL HERE BY TARGET LANGUAGE FILL HERE "
+ "BY TARGET LANGUAGE :ref:`EXTENSIONS <extensions>` FILL HERE."
+
+ Please be careful not to break reST notation. Most po-editors will help you
+ with that.
+
+#. Build translated document.
+
+ You need a :confval:`language` parameter in ``conf.py`` or you may also
+ specify the parameter on the command line.
+
+ For BSD/GNU make, run:
+
+ .. code-block:: console
+
+ $ make -e SPHINXOPTS="-D language='de'" html
+
+ For Windows :command:`cmd.exe`, run:
+
+ .. code-block:: console
+
+ > set SPHINXOPTS=-D language=de
+ > .\make.bat html
+
+ For PowerShell, run:
+
+ .. code-block:: console
+
+ > Set-Item env:SPHINXOPTS "-D language=de"
+ > .\make.bat html
+
+Congratulations! You got the translated documentation in the ``_build/html``
+directory.
+
+.. versionadded:: 1.3
+
+ :program:`sphinx-build` that is invoked by make command will build po files
+ into mo files.
+
+ If you are using 1.2.x or earlier, please invoke :command:`sphinx-intl build`
+ command before :command:`make` command.
+
+Translating
+~~~~~~~~~~~
+
+Update your po files by new pot files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If a document is updated, it is necessary to generate updated pot files and to
+apply differences to translated po files. In order to apply the updates from a
+pot file to the po file, use the :command:`sphinx-intl update` command.
+
+.. code-block:: console
+
+ $ sphinx-intl update -p _build/gettext
+
+
+Using Transifex service for team translation
+--------------------------------------------
+
+Transifex_ is one of several services that allow collaborative translation via a
+web interface. It has a nifty Python-based command line client that makes it
+easy to fetch and push translations.
+
+.. TODO: why use transifex?
+
+
+#. Install `transifex-client`_.
+
+ You need :command:`tx` command to upload resources (pot files).
+
+ .. code-block:: console
+
+ $ pip install transifex-client
+
+ .. seealso:: `Transifex Client documentation`_
+
+#. Create your Transifex_ account and create new project for your document.
+
+ Currently, Transifex does not allow for a translation project to have more
+ than one version of the document, so you'd better include a version number in
+ your project name.
+
+ For example:
+
+ :Project ID: ``sphinx-document-test_1_0``
+ :Project URL: ``https://www.transifex.com/projects/p/sphinx-document-test_1_0/``
+
+#. Create config files for :command:`tx` command.
+
+ This process will create ``.tx/config`` in the current directory, as well as
+ a ``~/.transifexrc`` file that includes auth information.
+
+ .. code-block:: console
+
+ $ tx init
+ Creating .tx folder...
+ Transifex instance [https://www.transifex.com]:
+ ...
+ Please enter your transifex username: <transifex-username>
+ Password: <transifex-password>
+ ...
+ Done.
+
+#. Upload pot files to Transifex service.
+
+ Register pot files to ``.tx/config`` file:
+
+ .. code-block:: console
+
+ $ cd /your/document/root
+ $ sphinx-intl update-txconfig-resources --pot-dir _build/locale \
+ --transifex-project-name sphinx-document-test_1_0
+
+ and upload pot files:
+
+ .. code-block:: console
+
+ $ tx push -s
+ Pushing translations for resource sphinx-document-test_1_0.builders:
+ Pushing source file (locale/pot/builders.pot)
+ Resource does not exist. Creating...
+ ...
+ Done.
+
+#. Forward the translation on Transifex.
+
+ .. TODO: write this section
+
+#. Pull translated po files and make translated HTML.
+
+ Get translated catalogs and build mo files. For example, to build mo files
+ for German (de):
+
+ .. code-block:: console
+
+ $ cd /your/document/root
+ $ tx pull -l de
+ Pulling translations for resource sphinx-document-test_1_0.builders (...)
+ -> de: locale/de/LC_MESSAGES/builders.po
+ ...
+ Done.
+
+ Invoke :command:`make html` (for BSD/GNU make):
+
+ .. code-block:: console
+
+ $ make -e SPHINXOPTS="-D language='de'" html
+
+That's all!
+
+.. tip:: Translating locally and on Transifex
+
+ If you want to push all language's po files, you can be done by using
+ :command:`tx push -t` command. Watch out! This operation overwrites
+ translations in Transifex.
+
+ In other words, if you have updated each in the service and local po files,
+ it would take much time and effort to integrate them.
+
+
+Using Weblate service for team translation
+------------------------------------------
+
+Read more in `Weblate's documentation`_.
+
+
+Contributing to Sphinx reference translation
+--------------------------------------------
+
+The recommended way for new contributors to translate Sphinx reference is to
+join the translation team on Transifex.
+
+There is a `sphinx translation page`_ for Sphinx (master) documentation.
+
+1. Login to Transifex_ service.
+2. Go to `sphinx translation page`_.
+3. Click ``Request language`` and fill form.
+4. Wait acceptance by Transifex sphinx translation maintainers.
+5. (After acceptance) Translate on Transifex.
+
+Detail is here: https://docs.transifex.com/getting-started-1/translators
+
+
+Translation progress and statistics
+-----------------------------------
+
+.. versionadded:: 7.1.0
+
+During the rendering process,
+Sphinx marks each translatable node with a ``translated`` attribute,
+indicating if a translation was found for the text in that node.
+
+The :confval:`translation_progress_classes` configuration value
+can be used to add a class to each element,
+depending on the value of the ``translated`` attribute.
+
+The ``|translation progress|`` substitution can be used to display the
+percentage of nodes that have been translated on a per-document basis.
+
+.. rubric:: Footnotes
+
+.. [1] See the `GNU gettext utilities
+ <https://www.gnu.org/software/gettext/manual/gettext.html#Introduction>`_
+ for details on that software suite.
+.. [2] Because nobody expects the Spanish Inquisition!
+
+.. _`transifex-client`: https://pypi.org/project/transifex-client/
+.. _`sphinx-intl`: https://pypi.org/project/sphinx-intl/
+.. _Transifex: https://www.transifex.com/
+.. _Weblate's documentation: https://docs.weblate.org/en/latest/devel/sphinx.html
+.. _`sphinx translation page`: https://www.transifex.com/sphinx-doc/sphinx-doc/
+.. _`Transifex Client documentation`: https://docs.transifex.com/client/introduction/
diff --git a/doc/usage/advanced/websupport/api.rst b/doc/usage/advanced/websupport/api.rst
new file mode 100644
index 0000000..79b51ee
--- /dev/null
+++ b/doc/usage/advanced/websupport/api.rst
@@ -0,0 +1,80 @@
+.. _websupportapi:
+
+.. currentmodule:: sphinxcontrib.websupport
+
+The WebSupport Class
+====================
+
+.. class:: WebSupport
+
+ The main API class for the web support package. All interactions with the
+ web support package should occur through this class.
+
+ The class takes the following keyword arguments:
+
+ srcdir
+ The directory containing reStructuredText source files.
+
+ builddir
+ The directory that build data and static files should be placed in. This
+ should be used when creating a :class:`WebSupport` object that will be
+ used to build data.
+
+ datadir
+ The directory that the web support data is in. This should be used when
+ creating a :class:`WebSupport` object that will be used to retrieve data.
+
+ search
+ This may contain either a string (e.g. 'xapian') referencing a built-in
+ search adapter to use, or an instance of a subclass of
+ :class:`~.search.BaseSearch`.
+
+ storage
+ This may contain either a string representing a database uri, or an
+ instance of a subclass of :class:`~.storage.StorageBackend`. If this is
+ not provided, a new sqlite database will be created.
+
+ moderation_callback
+ A callable to be called when a new comment is added that is not
+ displayed. It must accept one argument: a dictionary representing the
+ comment that was added.
+
+ staticdir
+ If the static files should be created in a different location
+ **and not in** ``'/static'``, this should be a string with the name of
+ that location (e.g. ``builddir + '/static_files'``).
+
+ .. note::
+ If you specify ``staticdir``, you will typically want to adjust
+ ``staticroot`` accordingly.
+
+ staticroot
+ If the static files are not served from ``'/static'``, this should be a
+ string with the name of that location (e.g. ``'/static_files'``).
+
+ docroot
+ If the documentation is not served from the base path of a URL, this
+ should be a string specifying that path (e.g. ``'docs'``).
+
+
+.. versionchanged:: 1.6
+
+ WebSupport class is moved to sphinxcontrib.websupport from sphinx.websupport.
+ Please add ``sphinxcontrib-websupport`` package in your dependency and use
+ moved class instead.
+
+
+Methods
+-------
+
+.. automethod:: sphinxcontrib.websupport.WebSupport.build
+
+.. automethod:: sphinxcontrib.websupport.WebSupport.get_document
+
+.. automethod:: sphinxcontrib.websupport.WebSupport.get_data
+
+.. automethod:: sphinxcontrib.websupport.WebSupport.add_comment
+
+.. automethod:: sphinxcontrib.websupport.WebSupport.process_vote
+
+.. automethod:: sphinxcontrib.websupport.WebSupport.get_search_results
diff --git a/doc/usage/advanced/websupport/index.rst b/doc/usage/advanced/websupport/index.rst
new file mode 100644
index 0000000..0816640
--- /dev/null
+++ b/doc/usage/advanced/websupport/index.rst
@@ -0,0 +1,16 @@
+.. _websupport:
+
+Sphinx Web Support
+==================
+
+.. versionadded:: 1.1
+
+Sphinx provides a Python API to easily integrate Sphinx documentation into your
+web application. To learn more read the :ref:`websupportquickstart`.
+
+.. toctree::
+
+ quickstart
+ api
+ searchadapters
+ storagebackends
diff --git a/doc/usage/advanced/websupport/quickstart.rst b/doc/usage/advanced/websupport/quickstart.rst
new file mode 100644
index 0000000..1cdd23f
--- /dev/null
+++ b/doc/usage/advanced/websupport/quickstart.rst
@@ -0,0 +1,255 @@
+.. _websupportquickstart:
+
+Web Support Quick Start
+=======================
+
+Building Documentation Data
+----------------------------
+
+To make use of the web support package in your application you'll need to build
+the data it uses. This data includes pickle files representing documents,
+search indices, and node data that is used to track where comments and other
+things are in a document. To do this you will need to create an instance of the
+:class:`~.WebSupport` class and call its :meth:`~.WebSupport.build` method::
+
+ from sphinxcontrib.websupport import WebSupport
+
+ support = WebSupport(srcdir='/path/to/rst/sources/',
+ builddir='/path/to/build/outdir',
+ search='xapian')
+
+ support.build()
+
+This will read reStructuredText sources from ``srcdir`` and place the necessary
+data in ``builddir``. The ``builddir`` will contain two sub-directories: one
+named "data" that contains all the data needed to display documents, search
+through documents, and add comments to documents. The other directory will be
+called "static" and contains static files that should be served from "/static".
+
+.. note::
+
+ If you wish to serve static files from a path other than "/static", you can
+ do so by providing the *staticdir* keyword argument when creating the
+ :class:`~.WebSupport` object.
+
+
+Integrating Sphinx Documents Into Your Webapp
+----------------------------------------------
+
+Now that the data is built, it's time to do something useful with it. Start off
+by creating a :class:`~.WebSupport` object for your application::
+
+ from sphinxcontrib.websupport import WebSupport
+
+ support = WebSupport(datadir='/path/to/the/data',
+ search='xapian')
+
+You'll only need one of these for each set of documentation you will be working
+with. You can then call its :meth:`~.WebSupport.get_document` method to access
+individual documents::
+
+ contents = support.get_document('contents')
+
+This will return a dictionary containing the following items:
+
+* **body**: The main body of the document as HTML
+* **sidebar**: The sidebar of the document as HTML
+* **relbar**: A div containing links to related documents
+* **title**: The title of the document
+* **css**: Links to CSS files used by Sphinx
+* **script**: JavaScript containing comment options
+
+This dict can then be used as context for templates. The goal is to be easy to
+integrate with your existing templating system. An example using `Jinja2
+<https://jinja.palletsprojects.com/>`_ is:
+
+.. code-block:: html+jinja
+
+ {%- extends "layout.html" %}
+
+ {%- block title %}
+ {{ document.title }}
+ {%- endblock %}
+
+ {% block css %}
+ {{ super() }}
+ {{ document.css|safe }}
+ <link rel="stylesheet" href="/static/websupport-custom.css" type="text/css">
+ {% endblock %}
+
+ {%- block script %}
+ {{ super() }}
+ {{ document.script|safe }}
+ {%- endblock %}
+
+ {%- block relbar %}
+ {{ document.relbar|safe }}
+ {%- endblock %}
+
+ {%- block body %}
+ {{ document.body|safe }}
+ {%- endblock %}
+
+ {%- block sidebar %}
+ {{ document.sidebar|safe }}
+ {%- endblock %}
+
+
+Authentication
+~~~~~~~~~~~~~~
+
+To use certain features such as voting, it must be possible to authenticate
+users. The details of the authentication are left to your application. Once a
+user has been authenticated you can pass the user's details to certain
+:class:`~.WebSupport` methods using the *username* and *moderator* keyword
+arguments. The web support package will store the username with comments and
+votes. The only caveat is that if you allow users to change their username you
+must update the websupport package's data::
+
+ support.update_username(old_username, new_username)
+
+*username* should be a unique string which identifies a user, and *moderator*
+should be a boolean representing whether the user has moderation privileges.
+The default value for *moderator* is ``False``.
+
+An example `Flask <https://flask.palletsprojects.com/>`_ function that checks
+whether a user is logged in and then retrieves a document is::
+
+ from sphinxcontrib.websupport.errors import *
+
+ @app.route('/<path:docname>')
+ def doc(docname):
+ username = g.user.name if g.user else ''
+ moderator = g.user.moderator if g.user else False
+ try:
+ document = support.get_document(docname, username, moderator)
+ except DocumentNotFoundError:
+ abort(404)
+ return render_template('doc.html', document=document)
+
+The first thing to notice is that the *docname* is just the request path. This
+makes accessing the correct document easy from a single view. If the user is
+authenticated, then the username and moderation status are passed along with the
+docname to :meth:`~.WebSupport.get_document`. The web support package will then
+add this data to the ``COMMENT_OPTIONS`` that are used in the template.
+
+.. note::
+
+ This only works if your documentation is served from your
+ document root. If it is served from another directory, you will
+ need to prefix the url route with that directory, and give the `docroot`
+ keyword argument when creating the web support object::
+
+ support = WebSupport(..., docroot='docs')
+
+ @app.route('/docs/<path:docname>')
+
+
+Performing Searches
+-------------------
+
+To use the search form built-in to the Sphinx sidebar, create a function to
+handle requests to the URL 'search' relative to the documentation root. The
+user's search query will be in the GET parameters, with the key `q`. Then use
+the :meth:`~sphinxcontrib.websupport.WebSupport.get_search_results` method to
+retrieve search results. In `Flask <https://flask.palletsprojects.com/>`_ that
+would be like this::
+
+ @app.route('/search')
+ def search():
+ q = request.args.get('q')
+ document = support.get_search_results(q)
+ return render_template('doc.html', document=document)
+
+Note that we used the same template to render our search results as we did to
+render our documents. That's because :meth:`~.WebSupport.get_search_results`
+returns a context dict in the same format that :meth:`~.WebSupport.get_document`
+does.
+
+
+Comments & Proposals
+--------------------
+
+Now that this is done it's time to define the functions that handle the AJAX
+calls from the script. You will need three functions. The first function is
+used to add a new comment, and will call the web support method
+:meth:`~.WebSupport.add_comment`::
+
+ @app.route('/docs/add_comment', methods=['POST'])
+ def add_comment():
+ parent_id = request.form.get('parent', '')
+ node_id = request.form.get('node', '')
+ text = request.form.get('text', '')
+ proposal = request.form.get('proposal', '')
+ username = g.user.name if g.user is not None else 'Anonymous'
+ comment = support.add_comment(text, node_id='node_id',
+ parent_id='parent_id',
+ username=username, proposal=proposal)
+ return jsonify(comment=comment)
+
+You'll notice that both a ``parent_id`` and ``node_id`` are sent with the
+request. If the comment is being attached directly to a node, ``parent_id``
+will be empty. If the comment is a child of another comment, then ``node_id``
+will be empty. Then next function handles the retrieval of comments for a
+specific node, and is aptly named
+:meth:`~sphinxcontrib.websupport.WebSupport.get_data`::
+
+ @app.route('/docs/get_comments')
+ def get_comments():
+ username = g.user.name if g.user else None
+ moderator = g.user.moderator if g.user else False
+ node_id = request.args.get('node', '')
+ data = support.get_data(node_id, username, moderator)
+ return jsonify(**data)
+
+The final function that is needed will call :meth:`~.WebSupport.process_vote`,
+and will handle user votes on comments::
+
+ @app.route('/docs/process_vote', methods=['POST'])
+ def process_vote():
+ if g.user is None:
+ abort(401)
+ comment_id = request.form.get('comment_id')
+ value = request.form.get('value')
+ if value is None or comment_id is None:
+ abort(400)
+ support.process_vote(comment_id, g.user.id, value)
+ return "success"
+
+
+Comment Moderation
+------------------
+
+By default, all comments added through :meth:`~.WebSupport.add_comment` are
+automatically displayed. If you wish to have some form of moderation, you can
+pass the ``displayed`` keyword argument::
+
+ comment = support.add_comment(text, node_id='node_id',
+ parent_id='parent_id',
+ username=username, proposal=proposal,
+ displayed=False)
+
+You can then create a new view to handle the moderation of comments. It
+will be called when a moderator decides a comment should be accepted and
+displayed::
+
+ @app.route('/docs/accept_comment', methods=['POST'])
+ def accept_comment():
+ moderator = g.user.moderator if g.user else False
+ comment_id = request.form.get('id')
+ support.accept_comment(comment_id, moderator=moderator)
+ return 'OK'
+
+Rejecting comments happens via comment deletion.
+
+To perform a custom action (such as emailing a moderator) when a new comment is
+added but not displayed, you can pass callable to the :class:`~.WebSupport`
+class when instantiating your support object::
+
+ def moderation_callback(comment):
+ """Do something..."""
+
+ support = WebSupport(..., moderation_callback=moderation_callback)
+
+The moderation callback must take one argument, which will be the same comment
+dict that is returned by :meth:`.WebSupport.add_comment`.
diff --git a/doc/usage/advanced/websupport/searchadapters.rst b/doc/usage/advanced/websupport/searchadapters.rst
new file mode 100644
index 0000000..262d666
--- /dev/null
+++ b/doc/usage/advanced/websupport/searchadapters.rst
@@ -0,0 +1,49 @@
+.. _searchadapters:
+
+.. currentmodule:: sphinxcontrib.websupport.search
+
+Search Adapters
+===============
+
+To create a custom search adapter you will need to subclass the
+:class:`BaseSearch` class. Then create an instance of the new class and pass
+that as the `search` keyword argument when you create the :class:`~.WebSupport`
+object::
+
+ support = WebSupport(srcdir=srcdir,
+ builddir=builddir,
+ search=MySearch())
+
+For more information about creating a custom search adapter, please see the
+documentation of the :class:`BaseSearch` class below.
+
+.. class:: BaseSearch
+
+ Defines an interface for search adapters.
+
+.. versionchanged:: 1.6
+
+ BaseSearch class is moved to sphinxcontrib.websupport.search from
+ sphinx.websupport.search.
+
+Methods
+-------
+
+The following methods are defined in the BaseSearch class. Some methods do not
+need to be overridden, but some (:meth:`~BaseSearch.add_document` and
+:meth:`~BaseSearch.handle_query`) must be overridden in your subclass. For a
+working example, look at the built-in adapter for whoosh.
+
+.. automethod:: BaseSearch.init_indexing
+
+.. automethod:: BaseSearch.finish_indexing
+
+.. automethod:: BaseSearch.feed
+
+.. automethod:: BaseSearch.add_document
+
+.. automethod:: BaseSearch.query
+
+.. automethod:: BaseSearch.handle_query
+
+.. automethod:: BaseSearch.extract_context
diff --git a/doc/usage/advanced/websupport/storagebackends.rst b/doc/usage/advanced/websupport/storagebackends.rst
new file mode 100644
index 0000000..ccb00b6
--- /dev/null
+++ b/doc/usage/advanced/websupport/storagebackends.rst
@@ -0,0 +1,49 @@
+.. _storagebackends:
+
+.. currentmodule:: sphinxcontrib.websupport.storage
+
+Storage Backends
+================
+
+To create a custom storage backend you will need to subclass the
+:class:`StorageBackend` class. Then create an instance of the new class and
+pass that as the `storage` keyword argument when you create the
+:class:`~.WebSupport` object::
+
+ support = WebSupport(srcdir=srcdir,
+ builddir=builddir,
+ storage=MyStorage())
+
+For more information about creating a custom storage backend, please see the
+documentation of the :class:`StorageBackend` class below.
+
+.. class:: StorageBackend
+
+ Defines an interface for storage backends.
+
+.. versionchanged:: 1.6
+
+ StorageBackend class is moved to sphinxcontrib.websupport.storage from
+ sphinx.websupport.storage.
+
+
+Methods
+-------
+
+.. automethod:: StorageBackend.pre_build
+
+.. automethod:: StorageBackend.add_node
+
+.. automethod:: StorageBackend.post_build
+
+.. automethod:: StorageBackend.add_comment
+
+.. automethod:: StorageBackend.delete_comment
+
+.. automethod:: StorageBackend.get_data
+
+.. automethod:: StorageBackend.process_vote
+
+.. automethod:: StorageBackend.update_username
+
+.. automethod:: StorageBackend.accept_comment