emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[O] [RFC] Changing internal representation of back-ends to defstructs


From: Nicolas Goaziou
Subject: [O] [RFC] Changing internal representation of back-ends to defstructs
Date: Wed, 03 Jul 2013 22:57:58 +0200

Hello,

Currently, a back-end is a symbol which may point to an entry in
`org-export-registered-backends' variable. Therefore a back-end must be
registered (with a unique name) before one can call it. Or, to put it
differently, it is impossible to use an anonymous and temporary
back-end.

This is not satisfying for developers, as there are situations when you
need to use a one-shot back-end but don't want to clutter registered
back-ends list. You can of course let-bind
`org-export-registered-backends' to something else, but it leads to
clunky code. The process should be abstracted a bit more.

The following (long) patches address this by defining back-ends as
structures (see `defstruct'), possibly anonymous and by separating
creation from registration process. It allows to quickly create and use
temporary back-ends. In the example below, we quickly export a string
using a temporary back-end:

  (org-export-string-as
   "* H1\n** H2\nSome string"
   (org-export-create-backend
    :transcoders
    '((headline . (lambda (h contents i)
                    (let ((m (make-string (org-export-get-relative-level h i) 
?=)))
                      (concat m " " (org-element-property :raw-value h) " " m 
"\n"
                              contents))))
      ;; Contents only.
      (section . (lambda (e c i) c))
      (paragraph . (lambda (e c i) c)))))

It is also possible to create a temporary derived back-end. The
following export will use registered `latex' back-end, excepted for
`bold' type objects.

  (org-export-string-as
     "Some *bold* /string/"
     (org-export-create-backend
      :parent 'latex
      :transcoders '((italic . (lambda (o c i) (format "\\texit{%s}" c)))))
     'body-only)

Besides `org-export-create-backend', tools provided are:
 - `org-export-get-backend'
 - `org-export-register-backend'
 - `org-export-get-all-transcoders' (handles inheritance)
 - `org-export-get-all-options' (handles inheritance)
 - `org-export-get-all-filters' (handles inheritance)

At a higher level, `org-export-define-backend' and
`org-export-define-derived-backend' do not change (they are equivalent
to create and register in a row). So this change only matters for
back-end developers who used advanced features like
`org-export-with-translations' (which should now be
`org-export-with-backend' coupled with an anonymous back-end).

Also, it leads to a cleaner implementation as it removes the confusion
between a back-end and its name.

The next step after applying this patch will be to make
orgtbl-to-BACKEND functions use anonymous functions in order to
support :splice property, which is tedious with the new export
framework.

Feedback welcome.


Regards,

-- 
Nicolas Goaziou
>From 35bf951a1cd4c455f01863e128a899d36e76a76c Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <address@hidden>
Date: Mon, 24 Jun 2013 20:52:10 +0200
Subject: [PATCH 1/2] ox: Change back-ends internal representation to
 structures

* lisp/ox.el (org-export--registered-backends): Renamed from
  `org-export-registered-backends'.
(org-export-invisible-backends): Removed variable.
(org-export-get-backend, org-export-get-all-transcoders
org-export-get-all-options, org-export-get-all-filters): New
functions.  It replaces `org-export-backend-translate-table'.
(org-export-barf-if-invalid-backend, org-export-derived-backend-p,
org-export-define-backend, org-export-define-derived-backend):
Rewrite functions using new representation.
(org-export-backend-translate-table): Remove function.
(org-export-get-environment): Use new function.
(org-export--get-subtree-options, org-export--parse-option-keyword,
org-export--get-inbuffer-options, org-export--get-global-options,
org-export-to-buffer org-export-to-file, org-export-string-as
org-export-replace-region-by): Update docstring.
(org-export-data-with-translations): Remove function.  Use
`org-export-data-with-backend' with a temporary back-end instead.
(org-export-data-with-backend, org-export-as): Reflect new definition
for back-ends.
(org-export--dispatch-action, org-export--dispatch-ui): Reflect new
definition for back-ends and variable removal.  Refactoring.
(org-export-filter-apply-functions): Call functions with
current back-end's name, not full back-end.
* lisp/org.el (org-export-backends, org-create-formula--latex-header):
Use new structure and variables.
* testing/lisp/test-ox.el: Update tests.

This patch separates back-end definition from its registration.  Thus,
it allows to use anonymous or unregistered back-ends.
---
 lisp/org.el             |  58 ++--
 lisp/ox.el              | 527 +++++++++++++++++---------------
 testing/lisp/test-ox.el | 781 +++++++++++++++++++++++++++---------------------
 3 files changed, 764 insertions(+), 602 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index 6233972..89cc328 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -436,8 +436,9 @@ For export specific modules, see also 
`org-export-backends'."
        (const :tag "C  wl:                Links to Wanderlust 
folders/messages" org-wl)
        (repeat :tag "External packages" :inline t (symbol :tag "Package"))))
 
-(defvar org-export-registered-backends)        ; From ox.el
+(defvar org-export--registered-backends) ; From ox.el.
 (declare-function org-export-derived-backend-p "ox" (backend &rest backends))
+(declare-function org-export-backend-name "ox" (backend))
 (defcustom org-export-backends '(ascii html icalendar latex)
   "List of export back-ends that should be always available.
 
@@ -451,30 +452,29 @@ needed.
 
 This variable needs to be set before org.el is loaded.  If you
 need to make a change while Emacs is running, use the customize
-interface or run the following code, where VALUE stands for the
-new value of the variable, after updating it:
+interface or run the following code, where VAL stands for the new
+value of the variable, after updating it:
 
   \(progn
-    \(setq org-export-registered-backends
+    \(setq org-export--registered-backends
           \(org-remove-if-not
            \(lambda (backend)
-             \(or (memq backend val)
-                 \(catch 'parentp
-                   \(mapc
-                    \(lambda (b)
-                      \(and (org-export-derived-backend-p b (car backend))
-                           \(throw 'parentp t)))
-                    val)
-                   nil)))
-           org-export-registered-backends))
-    \(let ((new-list (mapcar 'car org-export-registered-backends)))
+             \(let ((name (org-export-backend-name backend)))
+               \(or (memq name val)
+                   \(catch 'parentp
+                     \(dolist (b val)
+                       \(and (org-export-derived-backend-p b name)
+                            \(throw 'parentp t)))))))
+           org-export--registered-backends))
+    \(let ((new-list (mapcar 'org-export-backend-name
+                            org-export--registered-backends)))
       \(dolist (backend val)
         \(cond
          \((not (load (format \"ox-%s\" backend) t t))
           \(message \"Problems while trying to load export back-end `%s'\"
                    backend))
          \((not (memq backend new-list)) (push backend new-list))))
-      \(set-default var new-list)))
+      \(set-default 'org-export-backends new-list)))
 
 Adding a back-end to this list will also pull the back-end it
 depends on, if any."
@@ -488,21 +488,20 @@ depends on, if any."
           ;; Any back-end not required anymore (not present in VAL and not
           ;; a parent of any back-end in the new value) is removed from the
           ;; list of registered back-ends.
-          (setq org-export-registered-backends
+          (setq org-export--registered-backends
                 (org-remove-if-not
                  (lambda (backend)
-                   (or (memq backend val)
-                       (catch 'parentp
-                         (mapc
-                          (lambda (b)
-                            (and (org-export-derived-backend-p b (car backend))
-                                 (throw 'parentp t)))
-                          val)
-                         nil)))
-                 org-export-registered-backends))
+                   (let ((name (org-export-backend-name backend)))
+                     (or (memq name val)
+                         (catch 'parentp
+                           (dolist (b val)
+                             (and (org-export-derived-backend-p b name)
+                                  (throw 'parentp t)))))))
+                 org-export--registered-backends))
           ;; Now build NEW-LIST of both new back-ends and required
           ;; parents.
-          (let ((new-list (mapcar 'car org-export-registered-backends)))
+          (let ((new-list (mapcar 'org-export-backend-name
+                                  org-export--registered-backends)))
             (dolist (backend val)
               (cond
                ((not (load (format "ox-%s" backend) t t))
@@ -18494,14 +18493,17 @@ share a good deal of logic."
          "Invalid value of `org-latex-create-formula-image-program'")))
    string tofile options buffer))
 
+(declare-function org-export-get-backend "ox" (name))
 (declare-function org-export--get-global-options "ox" (&optional backend))
 (declare-function org-export--get-inbuffer-options "ox" (&optional backend))
 (declare-function org-latex-guess-inputenc "ox-latex" (header))
 (declare-function org-latex-guess-babel-language "ox-latex" (header info))
 (defun org-create-formula--latex-header ()
   "Return LaTeX header appropriate for previewing a LaTeX snippet."
-  (let ((info (org-combine-plists (org-export--get-global-options 'latex)
-                                 (org-export--get-inbuffer-options 'latex))))
+  (let ((info (org-combine-plists (org-export--get-global-options
+                                  (org-export-get-backend 'latex))
+                                 (org-export--get-inbuffer-options
+                                  (org-export-get-backend 'latex)))))
     (org-latex-guess-babel-language
      (org-latex-guess-inputenc
       (org-splice-latex-header
diff --git a/lisp/ox.el b/lisp/ox.el
index 92ad356..71435b7 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -47,15 +47,10 @@
 ;; The core function is `org-export-as'.  It returns the transcoded
 ;; buffer as a string.
 ;;
-;; An export back-end is defined with `org-export-define-backend',
-;; which defines one mandatory information: his translation table.
-;; Its value is an alist whose keys are elements and objects types and
-;; values translator functions.  See function's docstring for more
-;; information about translators.
-;;
-;; Optionally, `org-export-define-backend' can also support specific
-;; buffer keywords, OPTION keyword's items and filters.  Also refer to
-;; function documentation for more information.
+;; An export back-end is defined with `org-export-define-backend'.
+;; This function can also support specific buffer keywords, OPTION
+;; keyword's items and filters.  Refer to function's documentation for
+;; more information.
 ;;
 ;; If the new back-end shares most properties with another one,
 ;; `org-export-define-derived-backend' can be used to simplify the
@@ -280,14 +275,8 @@ containing the back-end used, as a symbol, and either a 
process
 or the time at which it finished.  It is used to build the menu
 from `org-export-stack'.")
 
-(defvar org-export-registered-backends nil
+(defvar org-export--registered-backends nil
   "List of backends currently available in the exporter.
-
-A backend is stored as a list where CAR is its name, as a symbol,
-and CDR is a plist with the following properties:
-`:filters-alist', `:menu-entry', `:options-alist' and
-`:translate-alist'.
-
 This variable is set with `org-export-define-backend' and
 `org-export-define-derived-backend' functions.")
 
@@ -830,20 +819,6 @@ process faster and the export more portable."
   :package-version '(Org . "8.0")
   :type '(file :must-match t))
 
-(defcustom org-export-invisible-backends nil
-  "List of back-ends that shouldn't appear in the dispatcher.
-
-Any back-end belonging to this list or derived from a back-end
-belonging to it will not appear in the dispatcher menu.
-
-Indeed, Org may require some export back-ends without notice.  If
-these modules are never to be used interactively, adding them
-here will avoid cluttering the dispatcher menu."
-  :group 'org-export-general
-  :version "24.4"
-  :package-version '(Org . "8.0")
-  :type '(repeat (symbol :tag "Back-End")))
-
 (defcustom org-export-dispatch-use-expert-ui nil
   "Non-nil means using a non-intrusive `org-export-dispatch'.
 In that case, no help buffer is displayed.  Though, an indicator
@@ -863,25 +838,147 @@ mode."
 
 ;;; Defining Back-ends
 ;;
-;; `org-export-define-backend' is the standard way to define an export
-;; back-end.  It allows to specify translators, filters, buffer
-;; options and a menu entry.  If the new back-end shares translators
-;; with another back-end, `org-export-define-derived-backend' may be
-;; used instead.
+;; An export back-end is a structure with `org-export-backend' type
+;; and `name', `parent', `transcoders', `options', `filters', `blocks'
+;; and `menu' slots.
+;;
+;; At the lowest level, a back-end is created with
+;; `org-export-create-backend' function.
+;;
+;; A named back-end can be registered with
+;; `org-export-register-backend' function.  A registered back-end can
+;; later be referred to by its name, with `org-export-get-backend'
+;; function.  Also, such a back-end can become the parent of a derived
+;; back-end from which slot values will be inherited by default.
+;; `org-export-derived-backend-p' can check if a given back-end is
+;; derived from a list of back-end names.
+;;
+;; `org-export-get-all-transcoders', `org-export-get-all-options' and
+;; `org-export-get-all-filters' return the full alist of transcoders,
+;; options and filters, including those inherited from ancestors.
 ;;
-;; Internally, a back-end is stored as a list, of which CAR is the
-;; name of the back-end, as a symbol, and CDR a plist.  Accessors to
-;; properties of a given back-end are: `org-export-backend-filters',
-;; `org-export-backend-menu', `org-export-backend-options' and
-;; `org-export-backend-translate-table'.
+;; At a higher level, `org-export-define-backend' is the standard way
+;; to define an export back-end.  If the new back-end is similar to
+;; a registered back-end, `org-export-define-derived-backend' may be
+;; used instead.
 ;;
 ;; Eventually `org-export-barf-if-invalid-backend' returns an error
 ;; when a given back-end hasn't been registered yet.
 
-(defun org-export-define-backend (backend translators &rest body)
+(defstruct (org-export-backend (:constructor org-export-create-backend)
+                              (:copier nil))
+  name parent transcoders options filters blocks menu)
+
+(defun org-export-get-backend (name)
+  "Return export back-end named after NAME.
+NAME is a symbol.  Return nil if no such back-end is found."
+  (catch 'found
+    (dolist (b org-export--registered-backends)
+      (when (eq (org-export-backend-name b) name)
+       (throw 'found b)))))
+
+(defun org-export-register-backend (backend)
+  "Register BACKEND as a known export back-end.
+BACKEND is a structure with `org-export-backend' type."
+  ;; Refuse to register an unnamed back-end.
+  (unless (org-export-backend-name backend)
+    (error "Cannot register a unnamed export back-end"))
+  ;; Refuse to register a back-end with an unknown parent.
+  (let ((parent (org-export-backend-parent backend)))
+    (when (and parent (not (org-export-get-backend parent)))
+      (error "Cannot use unknown \"%s\" back-end as a parent" parent)))
+  ;; Register dedicated export blocks in the parser.
+  (dolist (name (org-export-backend-blocks backend))
+    (add-to-list 'org-element-block-name-alist
+                (cons name 'org-element-export-block-parser)))
+  ;; If a back-end with the same name as BACKEND is already
+  ;; registered, replace it with BACKEND.  Otherwise, simply add
+  ;; BACKEND to the list of registered back-ends.
+  (let ((old (org-export-get-backend (org-export-backend-name backend))))
+    (if old (setcar (memq old org-export--registered-backends) backend)
+      (push backend org-export--registered-backends))))
+
+(defun org-export-barf-if-invalid-backend (backend)
+  "Signal an error if BACKEND isn't defined."
+  (unless (org-export-backend-p backend)
+    (error "Unknown \"%s\" back-end: Aborting export" backend)))
+
+(defun org-export-derived-backend-p (backend &rest backends)
+  "Non-nil if BACKEND is derived from one of BACKENDS.
+BACKEND is an export back-end, as returned by, e.g.,
+`org-export-create-backend', or a symbol referring to
+a registered back-end.  BACKENDS is constituted of symbols."
+  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
+  (when backend
+    (catch 'exit
+      (while (org-export-backend-parent backend)
+       (when (memq (org-export-backend-name backend) backends)
+         (throw 'exit t))
+       (setq backend
+             (org-export-get-backend (org-export-backend-parent backend))))
+      (memq (org-export-backend-name backend) backends))))
+
+(defun org-export-get-all-transcoders (backend)
+  "Return full translation table for BACKEND.
+
+BACKEND is an export back-end, as return by, e.g,,
+`org-export-create-backend'.  Return value is an alist where
+keys are element or object types, as symbols, and values are
+transcoders.
+
+Unlike to `org-export-backend-transcoders', this function
+also returns transcoders inherited from parent back-ends,
+if any."
+  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
+  (when backend
+    (let ((transcoders (org-export-backend-transcoders backend))
+         parent)
+      (while (setq parent (org-export-backend-parent backend))
+       (setq backend (org-export-get-backend parent))
+       (setq transcoders
+             (append transcoders (org-export-backend-transcoders backend))))
+      transcoders)))
+
+(defun org-export-get-all-options (backend)
+  "Return export options for BACKEND.
+
+BACKEND is an export back-end, as return by, e.g,,
+`org-export-create-backend'.  See `org-export-options-alist'
+for the shape of the return value.
+
+Unlike to `org-export-backend-options', this function also
+returns options inherited from parent back-ends, if any."
+  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
+  (when backend
+    (let ((options (org-export-backend-options backend))
+         parent)
+      (while (setq parent (org-export-backend-parent backend))
+       (setq backend (org-export-get-backend parent))
+       (setq options (append options (org-export-backend-options backend))))
+      options)))
+
+(defun org-export-get-all-filters (backend)
+  "Return complete list of filters for BACKEND.
+
+BACKEND is an export back-end, as return by, e.g,,
+`org-export-create-backend'.  Return value is an alist where
+keys are symbols and values lists of functions.
+
+Unlike to `org-export-backend-filters', this function also
+returns filters inherited from parent back-ends, if any."
+  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
+  (when backend
+    (let ((filters (org-export-backend-filters backend))
+         parent)
+      (while (setq parent (org-export-backend-parent backend))
+       (setq backend (org-export-get-backend parent))
+       (setq filters (append filters (org-export-backend-filters backend))))
+      filters)))
+
+(defun org-export-define-backend (backend transcoders &rest body)
   "Define a new back-end BACKEND.
 
-TRANSLATORS is an alist between object or element types and
+TRANSCODERS is an alist between object or element types and
 functions handling them.
 
 These functions should return a string without any trailing
@@ -997,32 +1094,23 @@ keywords are understood:
     `org-export-options-alist' for more information about
     structure of the values."
   (declare (indent 1))
-  (let (export-block filters menu-entry options contents)
+  (let (blocks filters menu-entry options contents)
     (while (keywordp (car body))
       (case (pop body)
         (:export-block (let ((names (pop body)))
-                        (setq export-block
-                              (if (consp names) (mapcar 'upcase names)
-                                (list (upcase names))))))
+                        (setq blocks (if (consp names) (mapcar 'upcase names)
+                                       (list (upcase names))))))
        (:filters-alist (setq filters (pop body)))
        (:menu-entry (setq menu-entry (pop body)))
         (:options-alist (setq options (pop body)))
         (t (pop body))))
-    (setq contents (append (list :translate-alist translators)
-                          (and filters (list :filters-alist filters))
-                          (and options (list :options-alist options))
-                          (and menu-entry (list :menu-entry menu-entry))))
-    ;; Register back-end.
-    (let ((registeredp (assq backend org-export-registered-backends)))
-      (if registeredp (setcdr registeredp contents)
-       (push (cons backend contents) org-export-registered-backends)))
-    ;; Tell parser to not parse EXPORT-BLOCK blocks.
-    (when export-block
-      (mapc
-       (lambda (name)
-        (add-to-list 'org-element-block-name-alist
-                     `(,name . org-element-export-block-parser)))
-       export-block))))
+    (org-export-register-backend
+     (org-export-create-backend :name backend
+                               :transcoders transcoders
+                               :options options
+                               :filters filters
+                               :blocks blocks
+                               :menu menu-entry))))
 
 (defun org-export-define-derived-backend (child parent &rest body)
   "Create a new back-end as a variant of an existing one.
@@ -1077,75 +1165,25 @@ The back-end could then be called with, for example:
 
   \(org-export-to-buffer 'my-latex \"*Test my-latex*\")"
   (declare (indent 2))
-  (let (export-block filters menu-entry options translators contents)
+  (let (blocks filters menu-entry options transcoders contents)
     (while (keywordp (car body))
       (case (pop body)
        (:export-block (let ((names (pop body)))
-                        (setq export-block
-                              (if (consp names) (mapcar 'upcase names)
-                                (list (upcase names))))))
+                        (setq blocks (if (consp names) (mapcar 'upcase names)
+                                       (list (upcase names))))))
         (:filters-alist (setq filters (pop body)))
        (:menu-entry (setq menu-entry (pop body)))
         (:options-alist (setq options (pop body)))
-        (:translate-alist (setq translators (pop body)))
+        (:translate-alist (setq transcoders (pop body)))
         (t (pop body))))
-    (setq contents (append
-                   (list :parent parent)
-                   (let ((p-table (org-export-backend-translate-table parent)))
-                     (list :translate-alist (append translators p-table)))
-                   (let ((p-filters (org-export-backend-filters parent)))
-                     (list :filters-alist (append filters p-filters)))
-                   (let ((p-options (org-export-backend-options parent)))
-                     (list :options-alist (append options p-options)))
-                   (and menu-entry (list :menu-entry menu-entry))))
-    (org-export-barf-if-invalid-backend parent)
-    ;; Register back-end.
-    (let ((registeredp (assq child org-export-registered-backends)))
-      (if registeredp (setcdr registeredp contents)
-       (push (cons child contents) org-export-registered-backends)))
-    ;; Tell parser to not parse EXPORT-BLOCK blocks.
-    (when export-block
-      (mapc
-       (lambda (name)
-        (add-to-list 'org-element-block-name-alist
-                     `(,name . org-element-export-block-parser)))
-       export-block))))
-
-(defun org-export-backend-parent (backend)
-  "Return back-end from which BACKEND is derived, or nil."
-  (plist-get (cdr (assq backend org-export-registered-backends)) :parent))
-
-(defun org-export-backend-filters (backend)
-  "Return filters for BACKEND."
-  (plist-get (cdr (assq backend org-export-registered-backends))
-            :filters-alist))
-
-(defun org-export-backend-menu (backend)
-  "Return menu entry for BACKEND."
-  (plist-get (cdr (assq backend org-export-registered-backends))
-            :menu-entry))
-
-(defun org-export-backend-options (backend)
-  "Return export options for BACKEND."
-  (plist-get (cdr (assq backend org-export-registered-backends))
-            :options-alist))
-
-(defun org-export-backend-translate-table (backend)
-  "Return translate table for BACKEND."
-  (plist-get (cdr (assq backend org-export-registered-backends))
-            :translate-alist))
-
-(defun org-export-barf-if-invalid-backend (backend)
-  "Signal an error if BACKEND isn't defined."
-  (unless (org-export-backend-translate-table backend)
-    (error "Unknown \"%s\" back-end: Aborting export" backend)))
-
-(defun org-export-derived-backend-p (backend &rest backends)
-  "Non-nil if BACKEND is derived from one of BACKENDS."
-  (let ((parent backend))
-    (while (and (not (memq parent backends))
-               (setq parent (org-export-backend-parent parent))))
-    parent))
+    (org-export-register-backend
+     (org-export-create-backend :name child
+                               :parent parent
+                               :transcoders transcoders
+                               :options options
+                               :filters filters
+                               :blocks blocks
+                               :menu menu-entry))))
 
 
 
@@ -1448,14 +1486,15 @@ The back-end could then be called with, for example:
 ;;  `org-export--get-subtree-options' and
 ;;  `org-export--get-inbuffer-options'
 ;;
-;; Also, `org-export--install-letbind-maybe' takes care of the part
-;; relative to "#+BIND:" keywords.
+;; Also, `org-export--list-bound-variables' collects bound variables
+;; along with their value in order to set them as buffer local
+;; variables later in the process.
 
 (defun org-export-get-environment (&optional backend subtreep ext-plist)
   "Collect export options from the current buffer.
 
-Optional argument BACKEND is a symbol specifying which back-end
-specific options to read, if any.
+Optional argument BACKEND is an export back-end, as returned by
+`org-export-create-backend'.
 
 When optional argument SUBTREEP is non-nil, assume the export is
 done against the current sub-tree.
@@ -1481,8 +1520,7 @@ inferior to file-local settings."
    (list
     :back-end
     backend
-    :translate-alist
-    (org-export-backend-translate-table backend)
+    :translate-alist (org-export-get-all-transcoders backend)
     :footnote-definition-alist
     ;; Footnotes definitions must be collected in the original
     ;; buffer, as there's no insurance that they will still be in
@@ -1518,11 +1556,12 @@ inferior to file-local settings."
 
 (defun org-export--parse-option-keyword (options &optional backend)
   "Parse an OPTIONS line and return values as a plist.
-Optional argument BACKEND is a symbol specifying which back-end
+Optional argument BACKEND is an export back-end, as returned by,
+e.g., `org-export-create-backend'.  It specifies which back-end
 specific items to read, if any."
   (let* ((all
          ;; Priority is given to back-end specific options.
-         (append (and backend (org-export-backend-options backend))
+         (append (and backend (org-export-get-all-options backend))
                  org-export-options-alist))
         plist)
     (dolist (option all)
@@ -1542,7 +1581,8 @@ specific items to read, if any."
 
 (defun org-export--get-subtree-options (&optional backend)
   "Get export options in subtree at point.
-Optional argument BACKEND is a symbol specifying back-end used
+Optional argument BACKEND is an export back-end, as returned by,
+e.g., `org-export-create-backend'.  It specifies back-end used
 for export.  Return options as a plist."
   ;; For each buffer keyword, create a headline property setting the
   ;; same property in communication channel. The name for the property
@@ -1594,7 +1634,7 @@ for export.  Return options as a plist."
                          (t value)))))))))
        ;; Look for both general keywords and back-end specific
        ;; options, with priority given to the latter.
-       (append (and backend (org-export-backend-options backend))
+       (append (and backend (org-export-get-all-options backend))
                org-export-options-alist)))
      ;; Return value.
      plist)))
@@ -1602,7 +1642,8 @@ for export.  Return options as a plist."
 (defun org-export--get-inbuffer-options (&optional backend)
   "Return current buffer export options, as a plist.
 
-Optional argument BACKEND, when non-nil, is a symbol specifying
+Optional argument BACKEND, when non-nil, is an export back-end,
+as returned by, e.g., `org-export-create-backend'.  It specifies
 which back-end specific options should also be read in the
 process.
 
@@ -1612,7 +1653,7 @@ Assume buffer is in Org mode.  Narrowing, if any, is 
ignored."
         (case-fold-search t)
         (options (append
                   ;; Priority is given to back-end specific options.
-                  (and backend (org-export-backend-options backend))
+                  (and backend (org-export-get-all-options backend))
                   org-export-options-alist))
         (regexp (format "^[ \t]*#\\+%s:"
                         (regexp-opt (nconc (delq nil (mapcar 'cadr options))
@@ -1725,12 +1766,13 @@ name."
 
 (defun org-export--get-global-options (&optional backend)
   "Return global export options as a plist.
-Optional argument BACKEND, if non-nil, is a symbol specifying
+Optional argument BACKEND, if non-nil, is an export back-end, as
+returned by, e.g., `org-export-create-backend'.  It specifies
 which back-end specific export options should also be read in the
 process."
   (let (plist
        ;; Priority is given to back-end specific options.
-       (all (append (and backend (org-export-backend-options backend))
+       (all (append (and backend (org-export-get-all-options backend))
                     org-export-options-alist)))
     (dolist (cell all plist)
       (let ((prop (car cell)))
@@ -2058,11 +2100,10 @@ a tree with a select tag."
 ;; back-end output.  It takes care of filtering out elements or
 ;; objects according to export options and organizing the output blank
 ;; lines and white space are preserved.  The function memoizes its
-;; results, so it is cheap to call it within translators.
+;; results, so it is cheap to call it within transcoders.
 ;;
 ;; It is possible to modify locally the back-end used by
 ;; `org-export-data' or even use a temporary back-end by using
-;; `org-export-data-with-translations' and
 ;; `org-export-data-with-backend'.
 ;;
 ;; Internally, three functions handle the filtering of objects and
@@ -2190,24 +2231,6 @@ Return transcoded string."
             results)))
         (plist-get info :exported-data))))))
 
-(defun org-export-data-with-translations (data translations info)
-  "Convert DATA into another format using a given translation table.
-DATA is an element, an object, a secondary string or a string.
-TRANSLATIONS is an alist between element or object types and
-a functions handling them.  See `org-export-define-backend' for
-more information.  INFO is a plist used as a communication
-channel."
-  (org-export-data
-   data
-   ;; Set-up a new communication channel with TRANSLATIONS as the
-   ;; translate table and a new hash table for memoization.
-   (org-combine-plists
-    info
-    (list :translate-alist translations
-         ;; Size of the hash table is reduced since this function
-         ;; will probably be used on short trees.
-         :exported-data (make-hash-table :test 'eq :size 401)))))
-
 (defun org-export-data-with-backend (data backend info)
   "Convert DATA into BACKEND format.
 
@@ -2217,9 +2240,18 @@ channel.
 
 Unlike to `org-export-with-backend', this function will
 recursively convert DATA using BACKEND translation table."
-  (org-export-barf-if-invalid-backend backend)
-  (org-export-data-with-translations
-   data (org-export-backend-translate-table backend) info))
+  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
+  (org-export-data
+   data
+   ;; Set-up a new communication channel with translations defined in
+   ;; BACKEND as the translate table and a new hash table for
+   ;; memoization.
+   (org-combine-plists
+    info
+    (list :translate-alist (org-export-get-all-transcoders backend)
+         ;; Size of the hash table is reduced since this function
+         ;; will probably be used on short trees.
+         :exported-data (make-hash-table :test 'eq :size 401)))))
 
 (defun org-export--interpret-p (blob info)
   "Non-nil if element or object BLOB should be interpreted during export.
@@ -2713,18 +2745,19 @@ channel, as a plist.  It must return a string or nil.")
   "Call every function in FILTERS.
 
 Functions are called with arguments VALUE, current export
-back-end and INFO.  A function returning a nil value will be
-skipped.  If it returns the empty string, the process ends and
+back-end's name and INFO.  A function returning a nil value will
+be skipped.  If it returns the empty string, the process ends and
 VALUE is ignored.
 
 Call is done in a LIFO fashion, to be sure that developer
 specified filters, if any, are called first."
   (catch 'exit
-    (dolist (filter filters value)
-      (let ((result (funcall filter value (plist-get info :back-end) info)))
-       (cond ((not result) value)
-             ((equal value "") (throw 'exit nil))
-             (t (setq value result)))))))
+    (let ((backend-name (plist-get info :back-end)))
+      (dolist (filter filters value)
+       (let ((result (funcall filter value backend-name info)))
+         (cond ((not result) value)
+               ((equal value "") (throw 'exit nil))
+               (t (setq value result))))))))
 
 (defun org-export-install-filters (info)
   "Install filters properties in communication channel.
@@ -2755,7 +2788,7 @@ Return the updated communication channel."
                       plist key
                       (if (atom value) (cons value (plist-get plist key))
                         (append value (plist-get plist key))))))))
-         (org-export-backend-filters (plist-get info :back-end)))
+         (org-export-get-all-filters (plist-get info :back-end)))
     ;; Return new communication channel.
     (org-combine-plists info plist)))
 
@@ -2891,6 +2924,10 @@ The function assumes BUFFER's major mode is `org-mode'."
   (backend &optional subtreep visible-only body-only ext-plist)
   "Transcode current Org buffer into BACKEND code.
 
+BACKEND is either an export back-end, as returned by, e.g.,
+`org-export-create-backend', or a symbol referring to
+a registered back-end.
+
 If narrowing is active in the current buffer, only transcode its
 narrowed part.
 
@@ -2911,6 +2948,7 @@ with external parameters overriding Org default settings, 
but
 still inferior to file-local settings.
 
 Return code as a string."
+  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
   (org-export-barf-if-invalid-backend backend)
   (save-excursion
     (save-restriction
@@ -2943,8 +2981,9 @@ Return code as a string."
        ;; created, where include keywords, macros are expanded and
        ;; code blocks are evaluated.
        (org-export-with-buffer-copy
-        ;; Run first hook with current back-end as argument.
-        (run-hook-with-args 'org-export-before-processing-hook backend)
+        ;; Run first hook with current back-end's name as argument.
+        (run-hook-with-args 'org-export-before-processing-hook
+                            (org-export-backend-name backend))
         (org-export-expand-include-keyword)
         ;; Update macro templates since #+INCLUDE keywords might have
         ;; added some new ones.
@@ -2954,10 +2993,11 @@ Return code as a string."
         ;; Update radio targets since keyword inclusion might have
         ;; added some more.
         (org-update-radio-target-regexp)
-        ;; Run last hook with current back-end as argument.
+        ;; Run last hook with current back-end's name as argument.
         (goto-char (point-min))
         (save-excursion
-          (run-hook-with-args 'org-export-before-parsing-hook backend))
+          (run-hook-with-args 'org-export-before-parsing-hook
+                              (org-export-backend-name backend)))
         ;; Update communication channel with environment.  Also
         ;; install user's and developer's filters.
         (setq info
@@ -2980,9 +3020,10 @@ Return code as a string."
         ;; Call options filters and update export options.  We do not
         ;; use `org-export-filter-apply-functions' here since the
         ;; arity of such filters is different.
-        (dolist (filter (plist-get info :filter-options))
-          (let ((result (funcall filter info backend)))
-            (when result (setq info result))))
+        (let ((backend-name (org-export-backend-name backend)))
+          (dolist (filter (plist-get info :filter-options))
+            (let ((result (funcall filter info backend-name)))
+              (when result (setq info result)))))
         ;; Parse buffer and call parse-tree filter on it.
         (setq tree
               (org-export-filter-apply-functions
@@ -3018,7 +3059,9 @@ Return code as a string."
   (backend buffer &optional subtreep visible-only body-only ext-plist)
   "Call `org-export-as' with output to a specified buffer.
 
-BACKEND is the back-end used for transcoding, as a symbol.
+BACKEND is either an export back-end, as returned by, e.g.,
+`org-export-create-backend', or a symbol referring to
+a registered back-end.
 
 BUFFER is the output buffer.  If it already exists, it will be
 erased first, otherwise, it will be created.
@@ -3046,8 +3089,10 @@ to kill ring.  Return buffer."
   (backend file &optional subtreep visible-only body-only ext-plist)
   "Call `org-export-as' with output to a specified file.
 
-BACKEND is the back-end used for transcoding, as a symbol.  FILE
-is the name of the output file, as a string.
+BACKEND is either an export back-end, as returned by, e.g.,
+`org-export-create-backend', or a symbol referring to
+a registered back-end.  FILE is the name of the output file, as
+a string.
 
 Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY and
 EXT-PLIST are similar to those used in `org-export-as', which
@@ -3074,6 +3119,10 @@ to kill ring.  Return output file's name."
 (defun org-export-string-as (string backend &optional body-only ext-plist)
   "Transcode STRING into BACKEND code.
 
+BACKEND is either an export back-end, as returned by, e.g.,
+`org-export-create-backend', or a symbol referring to
+a registered back-end.
+
 When optional argument BODY-ONLY is non-nil, only return body
 code, without preamble nor postamble.
 
@@ -3089,7 +3138,10 @@ Return code as a string."
 
 ;;;###autoload
 (defun org-export-replace-region-by (backend)
-  "Replace the active region by its export to BACKEND."
+  "Replace the active region by its export to BACKEND.
+BACKEND is either an export back-end, as returned by, e.g.,
+`org-export-create-backend', or a symbol referring to
+a registered back-end."
   (if (not (org-region-active-p))
       (user-error "No active region to replace")
     (let* ((beg (region-beginning))
@@ -3103,10 +3155,10 @@ Return code as a string."
 (defun org-export-insert-default-template (&optional backend subtreep)
   "Insert all export keywords with default values at beginning of line.
 
-BACKEND is a symbol representing the export back-end for which
-specific export options should be added to the template, or
-`default' for default template.  When it is nil, the user will be
-prompted for a category.
+BACKEND is a symbol referring to the name of a registered export
+back-end, for which specific export options should be added to
+the template, or `default' for default template.  When it is nil,
+the user will be prompted for a category.
 
 If SUBTREEP is non-nil, export configuration will be set up
 locally for the subtree through node properties."
@@ -3115,17 +3167,22 @@ locally for the subtree through node properties."
   (when (and subtreep (org-before-first-heading-p))
     (user-error "No subtree to set export options for"))
   (let ((node (and subtreep (save-excursion (org-back-to-heading t) (point))))
-       (backend (or backend
-                     (intern
-                      (org-completing-read
-                       "Options category: "
-                       (cons "default"
-                             (mapcar (lambda (b) (symbol-name (car b)))
-                                     org-export-registered-backends))))))
+       (backend
+        (or backend
+            (intern
+             (org-completing-read
+              "Options category: "
+              (cons "default"
+                    (mapcar (lambda (b)
+                              (symbol-name (org-export-backend-name b)))
+                            org-export--registered-backends))))))
        options keywords)
     ;; Populate OPTIONS and KEYWORDS.
-    (dolist (entry (if (eq backend 'default) org-export-options-alist
-                    (org-export-backend-options backend)))
+    (dolist (entry (cond ((eq backend 'default) org-export-options-alist)
+                        ((org-export-backend-p backend)
+                         (org-export-get-all-options backend))
+                        (t (org-export-get-all-options
+                            (org-export-backend-name backend)))))
       (let ((keyword (nth 1 entry))
             (option (nth 2 entry)))
         (cond
@@ -3502,16 +3559,20 @@ Caption lines are separated by a white space."
 ;; back-end, it may be used as a fall-back function once all specific
 ;; cases have been treated.
 
-(defun org-export-with-backend (back-end data &optional contents info)
-  "Call a transcoder from BACK-END on DATA.
-CONTENTS, when non-nil, is the transcoded contents of DATA
-element, as a string.  INFO, when non-nil, is the communication
-channel used for export, as a plist.."
-  (org-export-barf-if-invalid-backend back-end)
+(defun org-export-with-backend (backend data &optional contents info)
+  "Call a transcoder from BACKEND on DATA.
+BACKEND is an export back-end, as returned by, e.g.,
+`org-export-create-backend', or a symbol referring to
+a registered back-end.  DATA is an Org element, object, secondary
+string or string.  CONTENTS, when non-nil, is the transcoded
+contents of DATA element, as a string.  INFO, when non-nil, is
+the communication channel used for export, as a plist."
+  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
+  (org-export-barf-if-invalid-backend backend)
   (let ((type (org-element-type data)))
     (if (memq type '(nil org-data)) (error "No foreign transcoder available")
       (let ((transcoder
-            (cdr (assq type (org-export-backend-translate-table back-end)))))
+            (cdr (assq type (org-export-get-all-transcoders backend)))))
        (if (functionp transcoder) (funcall transcoder data contents info)
          (error "No foreign transcoder available"))))))
 
@@ -5849,43 +5910,31 @@ back to standard interface."
          (lambda (value)
            ;; Fontify VALUE string.
            (org-propertize value 'face 'font-lock-variable-name-face)))
-        ;; Prepare menu entries by extracting them from
-        ;; `org-export-registered-backends', and sorting them by
-        ;; access key and by ordinal, if any.
-        (backends
-         (sort
-          (sort
-           (delq nil
-                 (mapcar
-                  (lambda (b)
-                    (let ((name (car b)))
-                      (catch 'ignored
-                        ;; Ignore any back-end belonging to
-                        ;; `org-export-invisible-backends' or derived
-                        ;; from one of them.
-                        (dolist (ignored org-export-invisible-backends)
-                          (when (org-export-derived-backend-p name ignored)
-                            (throw 'ignored nil)))
-                        (org-export-backend-menu name))))
-                  org-export-registered-backends))
-           (lambda (a b)
-             (let ((key-a (nth 1 a))
-                   (key-b (nth 1 b)))
-               (cond ((and (numberp key-a) (numberp key-b))
-                      (< key-a key-b))
-                     ((numberp key-b) t)))))
-          (lambda (a b) (< (car a) (car b)))))
+        ;; Prepare menu entries by extracting them from registered
+        ;; back-ends and sorting them by access key and by ordinal,
+        ;; if any.
+        (entries
+         (sort (sort (delq nil
+                           (mapcar 'org-export-backend-menu
+                                   org-export--registered-backends))
+                     (lambda (a b)
+                       (let ((key-a (nth 1 a))
+                             (key-b (nth 1 b)))
+                         (cond ((and (numberp key-a) (numberp key-b))
+                                (< key-a key-b))
+                               ((numberp key-b) t)))))
+               'car-less-than-car))
         ;; Compute a list of allowed keys based on the first key
         ;; pressed, if any.  Some keys
         ;; (?^B, ?^V, ?^S, ?^F, ?^A, ?&, ?# and ?q) are always
         ;; available.
         (allowed-keys
          (nconc (list 2 22 19 6 1)
-                (if (not first-key) (org-uniquify (mapcar 'car backends))
+                (if (not first-key) (org-uniquify (mapcar 'car entries))
                   (let (sub-menu)
-                    (dolist (backend backends (sort (mapcar 'car sub-menu) '<))
-                      (when (eq (car backend) first-key)
-                        (setq sub-menu (append (nth 2 backend) sub-menu))))))
+                    (dolist (entry entries (sort (mapcar 'car sub-menu) '<))
+                      (when (eq (car entry) first-key)
+                        (setq sub-menu (append (nth 2 entry) sub-menu))))))
                 (cond ((eq first-key ?P) (list ?f ?p ?x ?a))
                       ((not first-key) (list ?P)))
                 (list ?& ?#)
@@ -5944,7 +5993,7 @@ back to standard interface."
                                (nth 1 sub-entry)))
                             sub-menu "")
                            (when (zerop (mod index 2)) "\n"))))))))
-               backends ""))
+               entries ""))
             ;; Publishing menu is hard-coded.
             (format "\n[%s] Publish
     [%s] Current file              [%s] Current project
@@ -5979,7 +6028,7 @@ back to standard interface."
     ;; UI, display an intrusive help buffer.
     (if expertp
        (org-export--dispatch-action
-        expert-prompt allowed-keys backends options first-key expertp)
+        expert-prompt allowed-keys entries options first-key expertp)
       ;; At first call, create frame layout in order to display menu.
       (unless (get-buffer "*Org Export Dispatcher*")
        (delete-other-windows)
@@ -6002,15 +6051,15 @@ back to standard interface."
          (set-window-start nil pos)))
       (org-fit-window-to-buffer)
       (org-export--dispatch-action
-       standard-prompt allowed-keys backends options first-key expertp))))
+       standard-prompt allowed-keys entries options first-key expertp))))
 
 (defun org-export--dispatch-action
-  (prompt allowed-keys backends options first-key expertp)
+  (prompt allowed-keys entries options first-key expertp)
   "Read a character from command input and act accordingly.
 
 PROMPT is the displayed prompt, as a string.  ALLOWED-KEYS is
 a list of characters available at a given step in the process.
-BACKENDS is a list of menu entries.  OPTIONS, FIRST-KEY and
+ENTRIES is a list of menu entries.  OPTIONS, FIRST-KEY and
 EXPERTP are the same as defined in `org-export--dispatch-ui',
 which see.
 
@@ -6067,9 +6116,9 @@ options as CDR."
        first-key expertp))
      ;; Action selected: Send key and options back to
      ;; `org-export-dispatch'.
-     ((or first-key (functionp (nth 2 (assq key backends))))
+     ((or first-key (functionp (nth 2 (assq key entries))))
       (cons (cond
-            ((not first-key) (nth 2 (assq key backends)))
+            ((not first-key) (nth 2 (assq key entries)))
             ;; Publishing actions are hard-coded.  Send a special
             ;; signal to `org-export-dispatch'.
             ((eq first-key ?P)
@@ -6082,10 +6131,10 @@ options as CDR."
             ;; path. Indeed, derived backends can share the same
             ;; FIRST-KEY.
             (t (catch 'found
-                 (mapc (lambda (backend)
-                         (let ((match (assq key (nth 2 backend))))
+                 (mapc (lambda (entry)
+                         (let ((match (assq key (nth 2 entry))))
                            (when match (throw 'found (nth 2 match)))))
-                       (member (assq first-key backends) backends)))))
+                       (member (assq first-key entries) entries)))))
            options))
      ;; Otherwise, enter sub-menu.
      (t (org-export--dispatch-ui options key expertp)))))
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index cbae08a..0ba20f2 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -24,30 +24,22 @@
 (unless (featurep 'ox)
   (signal 'missing-test-dependency "org-export"))
 
-(defmacro org-test-with-backend (backend &rest body)
-  "Execute body with an export back-end defined.
-
-BACKEND is the name of the back-end.  BODY is the body to
-execute.  The defined back-end simply returns parsed data as Org
-syntax."
-  (declare (debug (form body)) (indent 1))
-  `(let ((org-export-registered-backends
-         ',(list
-            (list backend
-                  :translate-alist
-                  (let (transcode-table)
-                    (dolist (type (append org-element-all-elements
-                                          org-element-all-objects)
-                                  transcode-table)
-                      (push
-                       (cons type
-                             (lambda (obj contents info)
-                               (funcall
-                                (intern (format "org-element-%s-interpreter"
-                                                type))
-                                obj contents)))
-                       transcode-table)))))))
-     (progn ,@body)))
+(defun org-test-default-backend ()
+  "Return a default export back-end.
+This back-end simply returns parsed data as Org syntax."
+  (org-export-create-backend
+   :transcoders (let (transcode-table)
+                 (dolist (type (append org-element-all-elements
+                                       org-element-all-objects)
+                               transcode-table)
+                   (push
+                    (cons type
+                          (lambda (obj contents info)
+                            (funcall
+                             (intern (format "org-element-%s-interpreter"
+                                             type))
+                             obj contents)))
+                    transcode-table)))))
 
 (defmacro org-test-with-parsed-data (data &rest body)
   "Execute body with parsed data available.
@@ -108,12 +100,12 @@ already filled in `info'."
   (should
    (equal "Yes\n"
          (org-test-with-temp-text "#+BIND: test-ox-var value"
-           (let ((org-export-allow-bind-keywords t)
-                 org-export-registered-backends)
-             (org-export-define-backend 'check
+           (let ((org-export-allow-bind-keywords t))
+             (org-export-as
+              (org-export-create-backend
+               :transcoders
                '((section . (lambda (s c i)
-                              (if (eq test-ox-var 'value) "Yes" "No")))))
-             (org-export-as 'check))))))
+                              (if (eq test-ox-var 'value) "Yes" "No")))))))))))
 
 (ert-deftest test-org-export/parse-option-keyword ()
   "Test reading all standard #+OPTIONS: items."
@@ -276,14 +268,14 @@ Paragraph"
     'equal
     (org-test-with-temp-text-in-file "Test"
       (org-mode)
-      (let (org-export-registered-backends)
-       (org-export-define-backend 'test
-         '((template . (lambda (text info)
-                         (org-element-interpret-data
-                          (plist-get info :title) info)))))
-       (list (org-export-as 'test)
-             (file-name-nondirectory
-              (file-name-sans-extension (buffer-file-name))))))))
+      (list (org-export-as
+            (org-export-create-backend
+             :transcoders
+             '((template . (lambda (text info)
+                             (org-element-interpret-data
+                              (plist-get info :title) info))))))
+           (file-name-nondirectory
+            (file-name-sans-extension (buffer-file-name)))))))
   ;; If no title is specified, and no file is associated to the
   ;; buffer, use buffer's name.
   (should
@@ -291,36 +283,37 @@ Paragraph"
     'equal
     (org-test-with-temp-text "Test"
       (org-mode)
-      (let (org-export-registered-backends)
-       (org-export-define-backend 'test
-         '((template . (lambda (text info)
-                         (org-element-interpret-data
-                          (plist-get info :title) info)))))
-       (list (org-export-as 'test) (buffer-name))))))
+      (list (org-export-as
+            (org-export-create-backend
+             :transcoders
+             '((template . (lambda (text info)
+                             (org-element-interpret-data
+                              (plist-get info :title) info))))))
+           (buffer-name)))))
   ;; If a title is specified, use it.
   (should
    (equal
     "Title"
     (org-test-with-temp-text-in-file "#+TITLE: Title\nTest"
       (org-mode)
-      (let (org-export-registered-backends)
-       (org-export-define-backend 'test
-         '((template . (lambda (text info)
-                         (org-element-interpret-data
-                          (plist-get info :title) info)))))
-       (org-export-as 'test)))))
+      (org-export-as
+       (org-export-create-backend
+       :transcoders
+       '((template . (lambda (text info)
+                       (org-element-interpret-data
+                        (plist-get info :title) info)))))))))
   ;; If an empty title is specified, do not set it.
   (should
    (equal
     ""
     (org-test-with-temp-text-in-file "#+TITLE:\nTest"
       (org-mode)
-      (let (org-export-registered-backends)
-       (org-export-define-backend 'test
-         '((template . (lambda (text info)
-                         (org-element-interpret-data
-                          (plist-get info :title) info)))))
-       (org-export-as 'test))))))
+      (org-export-as
+       (org-export-create-backend
+       :transcoders
+       '((template . (lambda (text info)
+                       (org-element-interpret-data
+                        (plist-get info :title) info))))))))))
 
 (ert-deftest test-org-export/handle-options ()
   "Test if export options have an impact on output."
@@ -328,142 +321,148 @@ Paragraph"
   (should
    (equal ""
          (org-test-with-temp-text "* Head1 :noexp:"
-           (org-test-with-backend test
-             (org-export-as 'test nil nil nil '(:exclude-tags ("noexp")))))))
+           (org-export-as (org-test-default-backend)
+                          nil nil nil '(:exclude-tags ("noexp"))))))
   ;; Test include tags for headlines and inlinetasks.
   (should
    (equal "* H2\n** Sub :exp:\n*** Sub Sub\n"
          (org-test-with-temp-text "* H1\n* H2\n** Sub :exp:\n*** Sub Sub\n* H3"
            (let ((org-tags-column 0))
-             (org-test-with-backend test
-               (org-export-as 'test nil nil nil '(:select-tags ("exp"))))))))
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:select-tags ("exp")))))))
   ;; Test mixing include tags and exclude tags.
-  (org-test-with-temp-text "
+  (should
+   (string-match
+    "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
+    (org-test-with-temp-text "
 * Head1 :export:
 ** Sub-Head1 :noexport:
 ** Sub-Head2
 * Head2 :noexport:
 ** Sub-Head1 :export:"
-    (org-test-with-backend test
-      (should
-       (string-match
-       "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
-       (org-export-as
-        'test nil nil nil
-        '(:select-tags ("export") :exclude-tags ("noexport")))))))
+      (org-export-as (org-test-default-backend) nil nil nil
+                    '(:select-tags ("export") :exclude-tags ("noexport"))))))
   ;; Ignore tasks.
   (should
    (equal ""
          (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
            (org-test-with-temp-text "* TODO Head1"
-             (org-test-with-backend test
-               (org-export-as 'test nil nil nil '(:with-tasks nil)))))))
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-tasks nil))))))
   (should
    (equal "* TODO Head1\n"
          (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
            (org-test-with-temp-text "* TODO Head1"
-             (org-test-with-backend test
-               (org-export-as 'test nil nil nil '(:with-tasks t)))))))
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-tasks t))))))
   ;; Archived tree.
-  (org-test-with-temp-text "* Head1 :archive:"
-    (let ((org-archive-tag "archive"))
-      (org-test-with-backend test
-       (should
-        (equal (org-export-as 'test nil nil nil '(:with-archived-trees nil))
-               "")))))
-  (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
-    (let ((org-archive-tag "archive"))
-      (org-test-with-backend test
-       (should
-        (string-match
-         "\\* Head1[ \t]+:archive:"
-         (org-export-as 'test nil nil nil
-                        '(:with-archived-trees headline)))))))
-  (org-test-with-temp-text "* Head1 :archive:"
-    (let ((org-archive-tag "archive"))
-      (org-test-with-backend test
-       (should
-        (string-match
-         "\\`\\* Head1[ \t]+:archive:\n\\'"
-         (org-export-as 'test nil nil nil '(:with-archived-trees t)))))))
+  (should
+   (equal ""
+         (org-test-with-temp-text "* Head1 :archive:"
+           (let ((org-archive-tag "archive"))
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-archived-trees nil))))))
+  (should
+   (string-match
+    "\\* Head1[ \t]+:archive:"
+    (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
+      (let ((org-archive-tag "archive"))
+       (org-export-as (org-test-default-backend) nil nil nil
+                      '(:with-archived-trees headline))))))
+  (should
+   (string-match
+    "\\`\\* Head1[ \t]+:archive:\n\\'"
+    (org-test-with-temp-text "* Head1 :archive:"
+      (let ((org-archive-tag "archive"))
+       (org-export-as (org-test-default-backend)
+                      nil nil nil '(:with-archived-trees t))))))
   ;; Clocks.
-  (let ((org-clock-string "CLOCK:"))
-    (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
-      (org-test-with-backend test
-       (should
-        (equal (org-export-as 'test nil nil nil '(:with-clocks t))
-               "CLOCK: [2012-04-29 sun. 10:45]\n"))
-       (should
-        (equal (org-export-as 'test nil nil nil '(:with-clocks nil)) "")))))
+  (should
+   (equal "CLOCK: [2012-04-29 sun. 10:45]\n"
+         (let ((org-clock-string "CLOCK:"))
+           (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-clocks t))))))
+  (should
+   (equal ""
+         (let ((org-clock-string "CLOCK:"))
+           (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-clocks nil))))))
   ;; Drawers.
-  (let ((org-drawers '("TEST")))
-    (org-test-with-temp-text ":TEST:\ncontents\n:END:"
-      (org-test-with-backend test
-       (should (equal (org-export-as 'test nil nil nil '(:with-drawers nil))
-                      ""))
-       (should (equal (org-export-as 'test nil nil nil '(:with-drawers t))
-                      ":TEST:\ncontents\n:END:\n")))))
-  (let ((org-drawers '("FOO" "BAR")))
-    (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
-      (org-test-with-backend test
-       (should
-        (equal (org-export-as 'test nil nil nil '(:with-drawers ("FOO")))
-               ":FOO:\nkeep\n:END:\n")))))
-  (let ((org-drawers '("FOO" "BAR")))
-    (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
-      (org-test-with-backend test
-       (should
-        (equal (org-export-as 'test nil nil nil '(:with-drawers (not "BAR")))
-               ":FOO:\nkeep\n:END:\n")))))
+  (should
+   (equal ""
+         (let ((org-drawers '("TEST")))
+           (org-test-with-temp-text ":TEST:\ncontents\n:END:"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-drawers nil))))))
+  (should
+   (equal ":TEST:\ncontents\n:END:\n"
+         (let ((org-drawers '("TEST")))
+           (org-test-with-temp-text ":TEST:\ncontents\n:END:"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-drawers t))))))
+  (should
+   (equal ":FOO:\nkeep\n:END:\n"
+         (let ((org-drawers '("FOO" "BAR")))
+           (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-drawers ("FOO")))))))
+  (should
+   (equal ":FOO:\nkeep\n:END:\n"
+         (let ((org-drawers '("FOO" "BAR")))
+           (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-drawers (not "BAR")))))))
   ;; Footnotes.
   (should
    (equal "Footnote?"
          (let ((org-footnote-section nil))
            (org-test-with-temp-text "Footnote?[fn:1]\n\n[fn:1] Def"
-             (org-test-with-backend test
-               (org-trim
-                (org-export-as 'test nil nil nil '(:with-footnotes nil))))))))
+             (org-trim (org-export-as (org-test-default-backend)
+                                      nil nil nil '(:with-footnotes nil)))))))
   (should
    (equal "Footnote?[fn:1]\n\n[fn:1] Def"
          (let ((org-footnote-section nil))
            (org-test-with-temp-text "Footnote?[fn:1]\n\n[fn:1] Def"
-             (org-test-with-backend test
-               (org-trim
-                (org-export-as 'test nil nil nil '(:with-footnotes t))))))))
+             (org-trim (org-export-as (org-test-default-backend)
+                                      nil nil nil '(:with-footnotes t)))))))
   ;; Inlinetasks.
   (when (featurep 'org-inlinetask)
     (should
      (equal
+      ""
       (let ((org-inlinetask-min-level 15))
        (org-test-with-temp-text "*************** Task"
-         (org-test-with-backend test
-           (org-export-as 'test nil nil nil '(:with-inlinetasks nil)))))
-      ""))
+         (org-export-as (org-test-default-backend)
+                        nil nil nil '(:with-inlinetasks nil))))))
     (should
      (equal
+      ""
       (let ((org-inlinetask-min-level 15))
        (org-test-with-temp-text
            "*************** Task\nContents\n*************** END"
-         (org-test-with-backend test
-           (org-export-as 'test nil nil nil '(:with-inlinetasks nil)))))
-      "")))
+         (org-export-as (org-test-default-backend)
+                        nil nil nil '(:with-inlinetasks nil)))))))
   ;; Plannings.
-  (let ((org-closed-string "CLOSED:"))
-    (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
-      (org-test-with-backend test
-       (should
-        (equal (org-export-as 'test nil nil nil '(:with-planning t))
-               "CLOSED: [2012-04-29 sun. 10:45]\n"))
-       (should
-        (equal (org-export-as 'test nil nil nil '(:with-planning nil))
-               "")))))
+  (should
+   (equal "CLOSED: [2012-04-29 sun. 10:45]\n"
+         (let ((org-closed-string "CLOSED:"))
+           (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-planning t))))))
+  (should
+   (equal ""
+         (let ((org-closed-string "CLOSED:"))
+           (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
+             (org-export-as (org-test-default-backend)
+                            nil nil nil '(:with-planning nil))))))
   ;; Statistics cookies.
   (should
    (equal ""
          (org-test-with-temp-text "[0/0]"
-           (org-test-with-backend test
-             (org-export-as
-              'test nil nil nil '(:with-statistics-cookies nil)))))))
+           (org-export-as (org-test-default-backend)
+                          nil nil nil '(:with-statistics-cookies nil))))))
 
 (ert-deftest test-org-export/with-timestamps ()
   "Test `org-export-with-timestamps' specifications."
@@ -472,15 +471,15 @@ Paragraph"
    (equal
     "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>\n"
     (org-test-with-temp-text "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>"
-      (org-test-with-backend test
-       (org-export-as 'test nil nil nil '(:with-timestamps t))))))
+      (org-export-as (org-test-default-backend)
+                    nil nil nil '(:with-timestamps t)))))
   ;; nil value.
   (should
    (equal
     ""
     (org-test-with-temp-text "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>"
-      (org-test-with-backend test
-       (org-export-as 'test nil nil nil '(:with-timestamps nil))))))
+      (org-export-as (org-test-default-backend)
+                    nil nil nil '(:with-timestamps nil)))))
   ;; `active' value.
   (should
    (equal
@@ -489,9 +488,8 @@ Paragraph"
        "<2012-03-29 Thu>[2012-03-29 Thu]
 
 Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
-      (org-test-with-backend test
-       (org-trim
-        (org-export-as 'test nil nil nil '(:with-timestamps active)))))))
+      (org-trim (org-export-as (org-test-default-backend)
+                              nil nil nil '(:with-timestamps active))))))
   ;; `inactive' value.
   (should
    (equal
@@ -500,16 +498,16 @@ Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
        "<2012-03-29 Thu>[2012-03-29 Thu]
 
 Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
-      (org-test-with-backend test
-       (org-trim
-        (org-export-as 'test nil nil nil '(:with-timestamps inactive))))))))
+      (org-trim (org-export-as (org-test-default-backend)
+                              nil nil nil '(:with-timestamps inactive)))))))
 
 (ert-deftest test-org-export/comment-tree ()
   "Test if export process ignores commented trees."
-  (let ((org-comment-string "COMMENT"))
-    (org-test-with-temp-text "* COMMENT Head1"
-      (org-test-with-backend test
-       (should (equal (org-export-as 'test) ""))))))
+  (should
+   (equal ""
+         (let ((org-comment-string "COMMENT"))
+           (org-test-with-temp-text "* COMMENT Head1"
+             (org-export-as (org-test-default-backend)))))))
 
 (ert-deftest test-org-export/export-scope ()
   "Test all export scopes."
@@ -518,22 +516,23 @@ Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
 ** Head2
 text
 *** Head3"
-    (org-test-with-backend test
-      ;; Subtree.
-      (forward-line 3)
-      (should (equal (org-export-as 'test 'subtree) "text\n*** Head3\n"))
-      ;; Visible.
-      (goto-char (point-min))
-      (forward-line)
-      (org-cycle)
-      (should (equal (org-export-as 'test nil 'visible) "* Head1\n"))
-      ;; Region.
-      (goto-char (point-min))
-      (forward-line 3)
-      (transient-mark-mode 1)
-      (push-mark (point) t t)
-      (goto-char (point-at-eol))
-      (should (equal (org-export-as 'test) "text\n"))))
+    ;; Subtree.
+    (forward-line 3)
+    (should (equal (org-export-as (org-test-default-backend) 'subtree)
+                  "text\n*** Head3\n"))
+    ;; Visible.
+    (goto-char (point-min))
+    (forward-line)
+    (org-cycle)
+    (should (equal (org-export-as (org-test-default-backend) nil 'visible)
+                  "* Head1\n"))
+    ;; Region.
+    (goto-char (point-min))
+    (forward-line 3)
+    (transient-mark-mode 1)
+    (push-mark (point) t t)
+    (goto-char (point-at-eol))
+    (should (equal (org-export-as (org-test-default-backend)) "text\n")))
   ;; Subtree with a code block calling another block outside.
   (should
    (equal ": 3\n"
@@ -547,19 +546,18 @@ text
 #+BEGIN_SRC emacs-lisp
 \(+ 1 2)
 #+END_SRC"
-           (org-test-with-backend test
-             (forward-line 1)
-             (org-export-as 'test 'subtree)))))
+           (forward-line 1)
+           (org-export-as (org-test-default-backend) 'subtree))))
   ;; Body only.
-  (org-test-with-temp-text "Text"
-    (org-test-with-backend test
-      (plist-put
-       (cdr (assq 'test org-export-registered-backends))
-       :translate-alist
-       (cons (cons 'template (lambda (body info) (format "BEGIN\n%sEND" body)))
-            (org-export-backend-translate-table 'test)))
-      (should (equal (org-export-as 'test nil nil 'body-only) "Text\n"))
-      (should (equal (org-export-as 'test) "BEGIN\nText\nEND")))))
+  (let ((backend (org-test-default-backend)))
+    (setf (org-export-backend-transcoders backend)
+         (cons '(template . (lambda (body i)
+                              (format "BEGIN\n%sEND" body)))
+               (org-export-backend-transcoders backend)))
+    (org-test-with-temp-text "Text"
+      (should (equal (org-export-as backend nil nil 'body-only)
+                    "Text\n"))
+      (should (equal (org-export-as backend) "BEGIN\nText\nEND")))))
 
 (ert-deftest test-org-export/output-file-name ()
   "Test `org-export-output-file-name' specifications."
@@ -667,7 +665,7 @@ body\n")))
   (should
    (equal "#+MACRO: macro1 value\nvalue\n"
          (org-test-with-temp-text "#+MACRO: macro1 value\n{{{macro1}}}"
-           (org-test-with-backend test (org-export-as 'test)))))
+           (org-export-as (org-test-default-backend)))))
   ;; Expand specific macros.
   (should
    (equal "me 2012-03-29 address@hidden Title\n"
@@ -678,7 +676,7 @@ body\n")))
 #+AUTHOR: me
 #+EMAIL: address@hidden
 {{{author}}} {{{date}}} {{{email}}} {{{title}}}"
-           (let ((output (org-test-with-backend test (org-export-as 'test))))
+           (let ((output (org-export-as (org-test-default-backend))))
              (substring output (string-match ".*\n\\'" output))))))
   ;; Expand specific macros when property contained a regular macro
   ;; already.
@@ -688,7 +686,7 @@ body\n")))
 #+MACRO: macro1 value
 #+TITLE: {{{macro1}}}
 {{{title}}}"
-           (let ((output (org-test-with-backend test (org-export-as 'test))))
+           (let ((output (org-export-as (org-test-default-backend))))
              (substring output (string-match ".*\n\\'" output))))))
   ;; Expand macros with templates in included files.
   (should
@@ -696,57 +694,65 @@ body\n")))
          (org-test-with-temp-text
              (format "#+INCLUDE: \"%s/examples/macro-templates.org\"
 {{{included-macro}}}" org-test-dir)
-           (let ((output (org-test-with-backend test (org-export-as 'test))))
+           (let ((output (org-export-as (org-test-default-backend))))
              (substring output (string-match ".*\n\\'" output)))))))
 
 (ert-deftest test-org-export/user-ignore-list ()
   "Test if `:ignore-list' accepts user input."
-  (org-test-with-backend test
-    (flet ((skip-note-head
-           (data backend info)
-           ;; Ignore headlines with the word "note" in their title.
-           (org-element-map data 'headline
-             (lambda (headline)
-               (when (string-match "\\<note\\>"
-                                   (org-element-property :raw-value headline))
-                 (org-export-ignore-element headline info)))
-             info)
-           data))
-      ;; Install function in parse tree filters.
-      (let ((org-export-filter-parse-tree-functions '(skip-note-head)))
-       (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
-         (should (equal (org-export-as 'test) "* Head1\n")))))))
+  (let ((backend (org-test-default-backend)))
+    (setf (org-export-backend-transcoders backend)
+         (cons '(template . (lambda (body i)
+                              (format "BEGIN\n%sEND" body)))
+               (org-export-backend-transcoders backend)))
+    (org-test-with-temp-text "Text"
+      (should (equal (org-export-as backend nil nil 'body-only)
+                    "Text\n"))
+      (should (equal (org-export-as backend) "BEGIN\nText\nEND"))))
+  (should
+   (equal
+    "* Head1\n"
+    (let ((org-export-filter-parse-tree-functions
+          '((lambda (data backend info)
+              ;; Ignore headlines with the word "note" in their title.
+              (org-element-map data 'headline
+                (lambda (headline)
+                  (when (string-match "\\<note\\>"
+                                      (org-element-property :raw-value
+                                                            headline))
+                    (org-export-ignore-element headline info)))
+                info)
+              data))))
+      (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
+       (org-export-as (org-test-default-backend)))))))
 
 (ert-deftest test-org-export/before-processing-hook ()
   "Test `org-export-before-processing-hook'."
   (should
    (equal
     "#+MACRO: mac val\nTest\n"
-    (org-test-with-backend test
-      (org-test-with-temp-text "#+MACRO: mac val\n{{{mac}}} Test"
-       (let ((org-export-before-processing-hook
-              '((lambda (backend)
-                  (while (re-search-forward "{{{" nil t)
-                    (let ((object (org-element-context)))
-                      (when (eq (org-element-type object) 'macro)
-                        (delete-region
-                         (org-element-property :begin object)
-                         (org-element-property :end object)))))))))
-         (org-export-as 'test)))))))
+    (org-test-with-temp-text "#+MACRO: mac val\n{{{mac}}} Test"
+      (let ((org-export-before-processing-hook
+            '((lambda (backend)
+                (while (re-search-forward "{{{" nil t)
+                  (let ((object (org-element-context)))
+                    (when (eq (org-element-type object) 'macro)
+                      (delete-region
+                       (org-element-property :begin object)
+                       (org-element-property :end object)))))))))
+       (org-export-as (org-test-default-backend)))))))
 
 (ert-deftest test-org-export/before-parsing-hook ()
   "Test `org-export-before-parsing-hook'."
   (should
    (equal "Body 1\nBody 2\n"
-         (org-test-with-backend test
-           (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 
2"
-             (let ((org-export-before-parsing-hook
-                    '((lambda (backend)
-                        (goto-char (point-min))
-                        (while (re-search-forward org-outline-regexp-bol nil t)
-                          (delete-region
-                           (point-at-bol) (progn (forward-line) (point))))))))
-               (org-export-as 'test)))))))
+         (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 2"
+           (let ((org-export-before-parsing-hook
+                  '((lambda (backend)
+                      (goto-char (point-min))
+                      (while (re-search-forward org-outline-regexp-bol nil t)
+                        (delete-region
+                         (point-at-bol) (progn (forward-line) (point))))))))
+             (org-export-as (org-test-default-backend)))))))
 
 
 
@@ -833,37 +839,37 @@ body\n")))
   ;; Translate table.
   (should
    (equal '((headline . my-headline-test))
-         (let (org-export-registered-backends)
+         (let (org-export--registered-backends)
            (org-export-define-backend 'test '((headline . my-headline-test)))
-           (org-export-backend-translate-table 'test))))
+           (org-export-get-all-transcoders 'test))))
   ;; Filters.
   (should
    (equal '((:filter-headline . my-filter))
-         (let (org-export-registered-backends)
+         (let (org-export--registered-backends)
            (org-export-define-backend 'test
              '((headline . my-headline-test))
              :filters-alist '((:filter-headline . my-filter)))
-           (org-export-backend-filters 'test))))
+           (org-export-backend-filters (org-export-get-backend 'test)))))
   ;; Options.
   (should
    (equal '((:prop value))
-         (let (org-export-registered-backends)
+         (let (org-export--registered-backends)
            (org-export-define-backend 'test
              '((headline . my-headline-test))
              :options-alist '((:prop value)))
-           (org-export-backend-options 'test))))
+           (org-export-backend-options (org-export-get-backend 'test)))))
   ;; Menu.
   (should
    (equal '(?k "Test Export" test)
-         (let (org-export-registered-backends)
+         (let (org-export--registered-backends)
            (org-export-define-backend 'test
              '((headline . my-headline-test))
              :menu-entry '(?k "Test Export" test))
-           (org-export-backend-menu 'test))))
+           (org-export-backend-menu (org-export-get-backend 'test)))))
   ;; Export Blocks.
   (should
    (equal '(("TEST" . org-element-export-block-parser))
-         (let (org-export-registered-backends org-element-block-name-alist)
+         (let (org-export--registered-backends org-element-block-name-alist)
            (org-export-define-backend 'test
              '((headline . my-headline-test))
              :export-block '("test"))
@@ -873,115 +879,218 @@ body\n")))
   "Test `org-export-define-derived-backend' specifications."
   ;; Error when parent back-end is not defined.
   (should-error
-   (let (org-export-registered-backends)
+   (let (org-export--registered-backends)
      (org-export-define-derived-backend 'test 'parent)))
   ;; Append translation table to parent's.
   (should
    (equal '((:headline . test) (:headline . parent))
-         (let (org-export-registered-backends)
+         (let (org-export--registered-backends)
            (org-export-define-backend 'parent '((:headline . parent)))
            (org-export-define-derived-backend 'test 'parent
              :translate-alist '((:headline . test)))
-           (org-export-backend-translate-table 'test))))
+           (org-export-get-all-transcoders 'test))))
   ;; Options defined in the new back have priority over those defined
   ;; in parent.
   (should
    (eq 'test
-       (let (org-export-registered-backends)
+       (let (org-export--registered-backends)
         (org-export-define-backend 'parent
           '((:headline . parent))
           :options-alist '((:a nil nil 'parent)))
         (org-export-define-derived-backend 'test 'parent
           :options-alist '((:a nil nil 'test)))
-        (plist-get (org-export--get-global-options 'test) :a)))))
+        (plist-get (org-export--get-global-options
+                    (org-export-get-backend 'test))
+                   :a)))))
 
 (ert-deftest test-org-export/derived-backend-p ()
   "Test `org-export-derived-backend-p' specifications."
   ;; Non-nil with direct match.
   (should
-   (let (org-export-registered-backends)
+   (let (org-export--registered-backends)
      (org-export-define-backend 'test '((headline . test)))
      (org-export-derived-backend-p 'test 'test)))
   (should
-   (let (org-export-registered-backends)
+   (let (org-export--registered-backends)
      (org-export-define-backend 'test '((headline . test)))
      (org-export-define-derived-backend 'test2 'test)
      (org-export-derived-backend-p 'test2 'test2)))
   ;; Non-nil with a direct parent.
   (should
-   (let (org-export-registered-backends)
+   (let (org-export--registered-backends)
      (org-export-define-backend 'test '((headline . test)))
      (org-export-define-derived-backend 'test2 'test)
      (org-export-derived-backend-p 'test2 'test)))
   ;; Non-nil with an indirect parent.
   (should
-   (let (org-export-registered-backends)
+   (let (org-export--registered-backends)
      (org-export-define-backend 'test '((headline . test)))
      (org-export-define-derived-backend 'test2 'test)
      (org-export-define-derived-backend 'test3 'test2)
      (org-export-derived-backend-p 'test3 'test)))
   ;; Nil otherwise.
   (should-not
-   (let (org-export-registered-backends)
+   (let (org-export--registered-backends)
      (org-export-define-backend 'test '((headline . test)))
      (org-export-define-backend 'test2 '((headline . test2)))
      (org-export-derived-backend-p 'test2 'test)))
   (should-not
-   (let (org-export-registered-backends)
+   (let (org-export--registered-backends)
      (org-export-define-backend 'test '((headline . test)))
      (org-export-define-backend 'test2 '((headline . test2)))
      (org-export-define-derived-backend 'test3 'test2)
      (org-export-derived-backend-p 'test3 'test))))
 
+(ert-deftest test-org-export/get-all-transcoders ()
+  "Test `org-export-get-all-transcoders' specifications."
+  ;; Return nil when back-end cannot be found.
+  (should-not (org-export-get-all-transcoders nil))
+  ;; Same as `org-export-transcoders' if no parent.
+  (should
+   (equal '((headline . ignore))
+         (org-export-get-all-transcoders
+          (org-export-create-backend
+           :transcoders '((headline . ignore))))))
+  ;; But inherit from all ancestors whenever possible.
+  (should
+   (equal '((section . ignore) (headline . ignore))
+         (let (org-export--registered-backends)
+           (org-export-define-backend 'b1 '((headline . ignore)))
+           (org-export-get-all-transcoders
+            (org-export-create-backend
+             :parent 'b1 :transcoders '((section . ignore)))))))
+  (should
+   (equal '((paragraph . ignore) (section . ignore) (headline . ignore))
+         (let (org-export--registered-backends)
+           (org-export-define-backend 'b1 '((headline . ignore)))
+           (org-export-define-derived-backend 'b2 'b1
+             :translate-alist '((section . ignore)))
+           (org-export-get-all-transcoders
+            (org-export-create-backend
+             :parent 'b2 :transcoders '((paragraph . ignore)))))))
+  ;; Back-end transcoders overrule inherited ones.
+  (should
+   (eq 'b
+       (let (org-export--registered-backends)
+        (org-export-define-backend 'b1 '((headline . a)))
+        (cdr (assq 'headline
+                   (org-export-get-all-transcoders
+                    (org-export-create-backend
+                     :parent 'b1 :transcoders '((headline . b))))))))))
+
+(ert-deftest test-org-export/get-all-options ()
+  "Test `org-export-get-all-options' specifications."
+  ;; Return nil when back-end cannot be found.
+  (should-not (org-export-get-all-options nil))
+  ;; Same as `org-export-options' if no parent.
+  (should
+   (equal '((headline . ignore))
+         (org-export-get-all-options
+          (org-export-create-backend
+           :options '((headline . ignore))))))
+  ;; But inherit from all ancestors whenever possible.
+  (should
+   (equal '((:key2 value2) (:key1 value1))
+         (let (org-export--registered-backends)
+           (org-export-define-backend 'b1 nil :options-alist '((:key1 value1)))
+           (org-export-get-all-options
+            (org-export-create-backend
+             :parent 'b1 :options '((:key2 value2)))))))
+  (should
+   (equal '((:key3 value3) (:key2 value2) (:key1 value1))
+         (let (org-export--registered-backends)
+           (org-export-define-backend 'b1 nil :options-alist '((:key1 value1)))
+           (org-export-define-derived-backend 'b2 'b1
+             :options-alist '((:key2 value2)))
+           (org-export-get-all-options
+            (org-export-create-backend
+             :parent 'b2 :options '((:key3 value3)))))))
+  ;; Back-end options overrule inherited ones.
+  (should
+   (eq 'b
+       (let (org-export--registered-backends)
+        (org-export-define-backend 'b1 nil :options-alist '((:key1 . a)))
+        (cdr (assq :key1
+                   (org-export-get-all-options
+                    (org-export-create-backend
+                     :parent 'b1 :options '((:key1 . b))))))))))
+
+(ert-deftest test-org-export/get-all-filters ()
+  "Test `org-export-get-all-filters' specifications."
+  ;; Return nil when back-end cannot be found.
+  (should-not (org-export-get-all-filters nil))
+  ;; Same as `org-export-filters' if no parent.
+  (should
+   (equal '((:filter-headline . ignore))
+         (org-export-get-all-filters
+          (org-export-create-backend
+           :filters '((:filter-headline . ignore))))))
+  ;; But inherit from all ancestors whenever possible.
+  (should
+   (equal '((:filter-section . ignore) (:filter-headline . ignore))
+         (let (org-export--registered-backends)
+           (org-export-define-backend 'b1
+             nil :filters-alist '((:filter-headline . ignore)))
+           (org-export-get-all-filters
+            (org-export-create-backend
+             :parent 'b1 :filters '((:filter-section . ignore)))))))
+  (should
+   (equal '((:filter-paragraph . ignore)
+           (:filter-section . ignore)
+           (:filter-headline . ignore))
+         (let (org-export--registered-backends)
+           (org-export-define-backend 'b1
+             nil :filters-alist '((:filter-headline . ignore)))
+           (org-export-define-derived-backend 'b2 'b1
+             :filters-alist '((:filter-section . ignore)))
+           (org-export-get-all-filters
+            (org-export-create-backend
+             :parent 'b2 :filters '((:filter-paragraph . ignore)))))))
+  ;; Back-end filters overrule inherited ones.
+  (should
+   (eq 'b
+       (let (org-export--registered-backends)
+        (org-export-define-backend 'b1 '((:filter-headline . a)))
+        (cdr (assq :filter-headline
+                   (org-export-get-all-filters
+                    (org-export-create-backend
+                     :parent 'b1 :filters '((:filter-headline . b))))))))))
+
 (ert-deftest test-org-export/with-backend ()
   "Test `org-export-with-backend' definition."
   ;; Error when calling an undefined back-end
-  (should-error
-   (let (org-export-registered-backends)
-     (org-export-with-backend 'test "Test")))
+  (should-error (org-export-with-backend nil "Test"))
   ;; Error when called back-end doesn't have an appropriate
   ;; transcoder.
   (should-error
-   (let (org-export-registered-backends)
-     (org-export-define-backend 'test ((headline . ignore)))
-     (org-export-with-backend 'test "Test")))
+   (org-export-with-backend
+    (org-export-create-backend :transcoders '((headline . ignore)))
+    "Test"))
   ;; Otherwise, export using correct transcoder
   (should
    (equal "Success"
-         (let (org-export-registered-backends)
+         (let (org-export--registered-backends)
            (org-export-define-backend 'test
              '((plain-text . (lambda (text contents info) "Failure"))))
            (org-export-define-backend 'test2
              '((plain-text . (lambda (text contents info) "Success"))))
            (org-export-with-backend 'test2 "Test")))))
 
-(ert-deftest test-org-export/data-with-translations ()
-  "Test `org-export-data-with-translations' specifications."
-  (should
-   (equal
-    "Success!"
-    (org-export-data-with-translations
-     '(bold nil "Test")
-     '((plain-text . (lambda (text info) "Success"))
-       (bold . (lambda (bold contents info) (concat contents "!"))))
-     '(:with-emphasize t)))))
-
 (ert-deftest test-org-export/data-with-backend ()
   "Test `org-export-data-with-backend' specifications."
   ;; Error when calling an undefined back-end.
-  (should-error
-   (let (org-export-registered-backends)
-     (org-export-data-with-backend 'test "Test" nil)))
+  (should-error (org-export-data-with-backend nil "nil" nil))
   ;; Otherwise, export data recursively, using correct back-end.
   (should
    (equal
     "Success!"
-    (let (org-export-registered-backends)
-      (org-export-define-backend 'test
-       '((plain-text . (lambda (text info) "Success"))
-         (bold . (lambda (bold contents info) (concat contents "!")))))
-      (org-export-data-with-backend
-       '(bold nil "Test") 'test '(:with-emphasize t))))))
+    (org-export-data-with-backend
+     '(bold nil "Test")
+     (org-export-create-backend
+      :transcoders
+      '((plain-text . (lambda (text info) "Success"))
+       (bold . (lambda (bold contents info) (concat contents "!")))))
+     '(:with-emphasize t)))))
 
 
 
@@ -989,28 +1098,30 @@ body\n")))
 
 (ert-deftest test-org-export/export-snippet ()
   "Test export snippets transcoding."
+  ;; Standard test.
   (org-test-with-temp-text "@@test:A@@@@t:B@@"
-    (org-test-with-backend test
-      (plist-put
-       (cdr (assq 'test org-export-registered-backends))
-       :translate-alist
-       (cons (cons 'export-snippet
-                  (lambda (snippet contents info)
-                    (when (eq (org-export-snippet-backend snippet) 'test)
-                      (org-element-property :value snippet))))
-            (org-export-backend-translate-table 'test)))
+    (let ((backend (org-test-default-backend)))
+      (setf (org-export-backend-name backend) 'test)
+      (setf (org-export-backend-transcoders backend)
+           (cons (cons 'export-snippet
+                       (lambda (snippet contents info)
+                         (when (eq (org-export-snippet-backend snippet) 'test)
+                           (org-element-property :value snippet))))
+                 (org-export-backend-transcoders backend)))
       (let ((org-export-snippet-translation-alist nil))
-       (should (equal (org-export-as 'test) "A\n")))
+       (should (equal (org-export-as backend) "A\n")))
       (let ((org-export-snippet-translation-alist '(("t" . "test"))))
-       (should (equal (org-export-as 'test) "AB\n")))))
+       (should (equal (org-export-as backend) "AB\n")))))
   ;; Ignored export snippets do not remove any blank.
   (should
    (equal "begin  end\n"
          (org-test-with-parsed-data "begin @@test:A@@ end"
-           (org-export-data-with-translations
+           (org-export-data-with-backend
             tree
-            '((paragraph . (lambda (paragraph contents info) contents))
-              (section . (lambda (section contents info) contents)))
+            (org-export-create-backend
+             :transcoders
+             '((paragraph . (lambda (paragraph contents info) contents))
+               (section . (lambda (section contents info) contents))))
             info)))))
 
 
@@ -1036,11 +1147,11 @@ body\n")))
                            (car (org-element-contents def))))))))
          info))))
     ;; 2. Test nested footnotes order.
-    (org-test-with-parsed-data
-       "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
-      (should
-       (equal
-       '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
+    (should
+     (equal
+      '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
+      (org-test-with-parsed-data
+         "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
        (org-element-map tree 'footnote-reference
          (lambda (ref)
            (when (org-export-footnote-first-reference-p ref info)
@@ -1060,29 +1171,30 @@ body\n")))
        (should
         (= (length (org-export-collect-footnote-definitions tree info)) 2))))
     ;; 4. Test footnotes definitions collection.
-    (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
+    (should
+     (= 4
+       (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
 
 \[fn:2] B [fn:3] [fn::D].
 
 \[fn:3] C."
-      (should (= (length (org-export-collect-footnote-definitions tree info))
-                4)))
+         (length (org-export-collect-footnote-definitions tree info)))))
     ;; 5. Test export of footnotes defined outside parsing scope.
-    (org-test-with-temp-text "[fn:1] Out of scope
+    (should
+     (equal
+      "ParagraphOut of scope\n"
+      (org-test-with-temp-text "[fn:1] Out of scope
 * Title
 Paragraph[fn:1]"
-      (org-test-with-backend test
-       (plist-put
-        (cdr (assq 'test org-export-registered-backends))
-        :translate-alist
-        (cons (cons 'footnote-reference
-                    (lambda (fn contents info)
-                      (org-element-interpret-data
-                       (org-export-get-footnote-definition fn info))))
-              (org-export-backend-translate-table 'test)))
-       (forward-line)
-       (should (equal "ParagraphOut of scope\n"
-                      (org-export-as 'test 'subtree)))))
+       (let ((backend (org-test-default-backend)))
+         (setf (org-export-backend-transcoders backend)
+               (cons (cons 'footnote-reference
+                           (lambda (fn contents info)
+                             (org-element-interpret-data
+                              (org-export-get-footnote-definition fn info))))
+                     (org-export-backend-transcoders backend)))
+         (forward-line)
+         (org-export-as backend 'subtree)))))
     ;; 6. Footnotes without a definition should be provided a fallback
     ;;    definition.
     (should
@@ -1378,8 +1490,8 @@ Paragraph[fn:1]"
       ""
       (let ((org-inlinetask-min-level 3))
        (org-test-with-temp-text "*** Inlinetask :noexp:\nContents\n*** end"
-         (org-test-with-backend test
-           (org-export-as 'test nil nil nil '(:exclude-tags ("noexp"))))))))
+         (org-export-as (org-test-default-backend)
+                        nil nil nil '(:exclude-tags ("noexp")))))))
     ;; Inlinetask with an include tag.
     (should
      (equal
@@ -1387,16 +1499,16 @@ Paragraph[fn:1]"
       (let ((org-inlinetask-min-level 3)
            (org-tags-column 0))
        (org-test-with-temp-text "* H1\n* H2\n*** Inline :exp:"
-         (org-test-with-backend test
-           (org-export-as 'test nil nil nil '(:select-tags ("exp"))))))))
+         (org-export-as (org-test-default-backend)
+                        nil nil nil '(:select-tags ("exp")))))))
     ;; Ignore inlinetask with a TODO keyword and tasks excluded.
     (should
      (equal ""
            (let ((org-todo-keywords '((sequence "TODO" "DONE")))
                  (org-inlinetask-min-level 3))
              (org-test-with-temp-text "*** TODO Inline"
-               (org-test-with-backend test
-                 (org-export-as 'test nil nil nil '(:with-tasks nil)))))))))
+               (org-export-as (org-test-default-backend)
+                              nil nil nil '(:with-tasks nil))))))))
 
 
 
@@ -2492,41 +2604,40 @@ Another text. (ref:text)
   "Test `inner-template' translator specifications."
   (should
    (equal "Success!"
-         (let (org-export-registered-backends)
-           (org-export-define-backend 'test
+         (org-test-with-temp-text "* Headline"
+           (org-export-as
+            (org-export-create-backend
+             :transcoders
              '((inner-template . (lambda (contents info) "Success!"))
-               (headline . (lambda (h c i) "Headline"))))
-           (org-test-with-temp-text "* Headline"
-             (org-export-as 'test)))))
+               (headline . (lambda (h c i) "Headline"))))))))
   ;; Inner template is applied even in a "body-only" export.
   (should
    (equal "Success!"
-         (let (org-export-registered-backends)
-           (org-export-define-backend 'test
-             '((inner-template . (lambda (contents info) "Success!"))
-               (headline . (lambda (h c i) "Headline"))))
-           (org-test-with-temp-text "* Headline"
-             (org-export-as 'test nil nil 'body-only))))))
+         (org-test-with-temp-text "* Headline"
+           (org-export-as
+            (org-export-create-backend
+             :transcoders '((inner-template . (lambda (c i) "Success!"))
+                            (headline . (lambda (h c i) "Headline"))))
+            nil nil 'body-only)))))
 
 (ert-deftest test-org-export/template ()
   "Test `template' translator specifications."
   (should
    (equal "Success!"
-         (let (org-export-registered-backends)
-           (org-export-define-backend 'test
-             '((template . (lambda (contents info) "Success!"))
-               (headline . (lambda (h c i) "Headline"))))
-           (org-test-with-temp-text "* Headline"
-             (org-export-as 'test)))))
+         (org-test-with-temp-text "* Headline"
+           (org-export-as
+            (org-export-create-backend
+             :transcoders '((template . (lambda (contents info) "Success!"))
+                            (headline . (lambda (h c i) "Headline"))))))))
   ;; Template is not applied in a "body-only" export.
   (should-not
    (equal "Success!"
-         (let (org-export-registered-backends)
-           (org-export-define-backend 'test
-             '((template . (lambda (contents info) "Success!"))
-               (headline . (lambda (h c i) "Headline"))))
-           (org-test-with-temp-text "* Headline"
-             (org-export-as 'test nil nil 'body-only))))))
+         (org-test-with-temp-text "* Headline"
+           (org-export-as
+            (org-export-create-backend
+             :transcoders '((template . (lambda (contents info) "Success!"))
+                            (headline . (lambda (h c i) "Headline"))))
+            nil nil 'body-only)))))
 
 
 
-- 
1.8.3.2

>From 5c3b1765d219fc55edac393460128b9cd8d0d013 Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <address@hidden>
Date: Mon, 24 Jun 2013 20:55:24 +0200
Subject: [PATCH 2/2] Export back-ends: Apply changes to back-end structure

* lisp/ox-html.el (org-html--format-toc-headline): Make use of
  anonymous back-ends.
* lisp/ox-odt.el (org-odt-footnote-reference): Make use of anonymous
  back-ends.
(org-odt-format-label, org-odt-toc, org-odt-format-headline--wrap):
  Use `org-export-with-backend' instead of
  `org-export-with-translations'.
* contrib/lisp/ox-freemind.el (org-freemind--build-node-contents): Use
  `org-export-with-backend' instead of `org-export-with-translations'.
---
 contrib/lisp/ox-freemind.el | 11 +++---
 lisp/ox-html.el             | 19 ++++++-----
 lisp/ox-odt.el              | 83 +++++++++++++++++++++++----------------------
 3 files changed, 57 insertions(+), 56 deletions(-)

diff --git a/contrib/lisp/ox-freemind.el b/contrib/lisp/ox-freemind.el
index 4e90eff..d31c65f 100644
--- a/contrib/lisp/ox-freemind.el
+++ b/contrib/lisp/ox-freemind.el
@@ -316,12 +316,11 @@ will result in following node:
         (element-contents (org-element-contents element))
         (section (assoc 'section element-contents))
         (section-contents
-         (let* ((translations
-                 (nconc (list (cons 'section
-                                    (lambda (section contents info)
-                                      contents)))
-                        (plist-get info :translate-alist))))
-           (org-export-data-with-translations section translations info)))
+         (let ((backend (org-export-create-backend
+                         :parent (org-export-backend-name
+                                  (plist-get info :back-end))
+                         :translations '(section . (lambda (e c i) c)))))
+           (org-export-data-with-backend section backend info)))
         (itemized-contents-p (let ((first-child-headline
                                     (org-element-map element-contents
                                         'headline 'identity info t)))
diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index 9ce73c4..0c997b4 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -1983,16 +1983,17 @@ INFO is a plist used as a communication channel."
                                           headline-number "-"))))
            ;; Body.
            (concat section-number
-                   (org-export-data-with-translations
+                   (org-export-data-with-backend
                     (org-export-get-alt-title headline info)
-                    ;; Ignore any footnote-reference, link,
-                    ;; radio-target and target in table of contents.
-                    (append
-                     '((footnote-reference . ignore)
-                       (link . (lambda (link desc i) desc))
-                       (radio-target . (lambda (radio desc i) desc))
-                       (target . ignore))
-                     (org-export-backend-translate-table 'html))
+                    ;; Create an anonymous back-end that will ignore
+                    ;; any footnote-reference, link, radio-target and
+                    ;; target in table of contents.
+                    (org-export-create-backend
+                     :parent 'html
+                     :transcoders '((footnote-reference . ignore)
+                                    (link . (lambda (object c i) c))
+                                    (radio-target . (lambda (object c i) c))
+                                    (target . ignore)))
                     info)
                    (and tags "&#xa0;&#xa0;&#xa0;") (org-html--tags tags)))))
 
diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
index 1cccdc6..abf88cd 100644
--- a/lisp/ox-odt.el
+++ b/lisp/ox-odt.el
@@ -1152,20 +1152,19 @@ See `org-odt--build-date-styles' for implementation 
details."
   (let* ((title (org-export-translate "Table of Contents" :utf-8 info))
         (headlines (org-export-collect-headlines
                     info (and (wholenump depth) depth)))
-        (translations (nconc (mapcar
-                              (lambda (type)
-                                (cons type (lambda (data contents info)
-                                             contents)))
-                              (list 'radio-target))
-                             (plist-get info :translate-alist))))
+        (backend (org-export-create-backend
+                  :parent (org-export-backend-name
+                           (plist-get info :back-end))
+                  :transcoders (mapcar
+                                (lambda (type) (cons type (lambda (d c i) c)))
+                                (list 'radio-target)))))
     (when headlines
       (concat
        (org-odt-begin-toc title depth)
        (mapconcat
        (lambda (headline)
          (let* ((entry (org-odt-format-headline--wrap
-                        headline translations info
-                        'org-odt-format-toc-headline))
+                        headline backend info 'org-odt-format-toc-headline))
                 (level (org-export-get-relative-level headline info))
                 (style (format "Contents_20_%d" level)))
            (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
@@ -1731,18 +1730,22 @@ CONTENTS is nil.  INFO is a plist holding contextual 
information."
        (t
         (let* ((raw (org-export-get-footnote-definition
                      footnote-reference info))
-               (translations
-                (cons (cons 'paragraph
-                            (lambda (p c i)
-                              (org-odt--format-paragraph
-                               p c "Footnote" "OrgFootnoteCenter"
-                               "OrgFootnoteQuotations")))
-                      (org-export-backend-translate-table 'odt)))
-               (def (let ((def (org-trim (org-export-data-with-translations
-                                          raw translations info))))
-                      (if (eq (org-element-type raw) 'org-data) def
-                        (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
-                                "Footnote" def)))))
+               (def
+                (let ((def (org-trim
+                            (org-export-data-with-backend
+                             raw
+                             (org-export-create-backend
+                              :parent 'odt
+                              :transcoders
+                              '((paragraph . (lambda (p c i)
+                                               (org-odt--format-paragraph
+                                                p c "Footnote"
+                                                "OrgFootnoteCenter"
+                                                "OrgFootnoteQuotations")))))
+                             info))))
+                  (if (eq (org-element-type raw) 'org-data) def
+                    (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
+                            "Footnote" def)))))
           (funcall --format-footnote-definition n def))))))))
 
 
@@ -1775,13 +1778,12 @@ CONTENTS is nil.  INFO is a plist holding contextual 
information."
                            "<text:span text:style-name=\"%s\">%s</text:span>"
                            "OrgTag" tag)) tags " : "))))))
 
-(defun org-odt-format-headline--wrap (headline translations info
-                                                &optional format-function
-                                                &rest extra-keys)
-  "Transcode a HEADLINE element from Org to ODT.
-CONTENTS holds the contents of the headline.  INFO is a plist
-holding contextual information."
-  (setq translations (or translations (plist-get info :translate-alist)))
+(defun org-odt-format-headline--wrap (headline backend info
+                                              &optional format-function
+                                              &rest extra-keys)
+  "Transcode a HEADLINE element using BACKEND.
+INFO is a plist holding contextual information."
+  (setq backend (or backend (plist-get info :back-end)))
   (let* ((level (+ (org-export-get-relative-level headline info)))
         (headline-number (org-export-get-headline-number headline info))
         (section-number (and (org-export-numbered-headline-p headline info)
@@ -1789,13 +1791,13 @@ holding contextual information."
                                         headline-number ".")))
         (todo (and (plist-get info :with-todo-keywords)
                    (let ((todo (org-element-property :todo-keyword headline)))
-                     (and todo (org-export-data-with-translations
-                                todo translations info)))))
+                     (and todo
+                          (org-export-data-with-backend todo backend info)))))
         (todo-type (and todo (org-element-property :todo-type headline)))
         (priority (and (plist-get info :with-priority)
                        (org-element-property :priority headline)))
-        (text (org-export-data-with-translations
-               (org-element-property :title headline) translations info))
+        (text (org-export-data-with-backend
+               (org-element-property :title headline) backend info))
         (tags (and (plist-get info :with-tags)
                    (org-export-get-tags headline info)))
         (headline-label (concat "sec-" (mapconcat 'number-to-string
@@ -1805,7 +1807,7 @@ holding contextual information."
                           ((functionp org-odt-format-headline-function)
                            (function*
                             (lambda (todo todo-type priority text tags
-                                          &allow-other-keys)
+                                     &allow-other-keys)
                               (funcall org-odt-format-headline-function
                                        todo todo-type priority text tags))))
                           (t 'org-odt-format-headline))))
@@ -1934,7 +1936,7 @@ holding contextual information."
     (let ((format-function
           (function*
            (lambda (todo todo-type priority text tags
-                         &key contents &allow-other-keys)
+                    &key contents &allow-other-keys)
              (funcall org-odt-format-inlinetask-function
                       todo todo-type priority text tags contents)))))
       (org-odt-format-headline--wrap
@@ -2149,15 +2151,14 @@ SHORT-CAPTION are strings."
         ;; will do.
         (short-caption
          (let ((short-caption (or short-caption caption))
-               (translations (nconc (mapcar
-                                     (lambda (type)
-                                       (cons type (lambda (data contents info)
-                                                    contents)))
-                                     org-element-all-objects)
-                                    (plist-get info :translate-alist))))
+               (backend (org-export-create-backend
+                         :parent (org-export-backend-name
+                                  (plist-get info :back-end))
+                         :transcoders
+                         (mapcar (lambda (type) (cons type (lambda (o c i) c)))
+                                 org-element-all-objects))))
            (when short-caption
-             (org-export-data-with-translations short-caption
-                                                translations info)))))
+             (org-export-data-with-backend short-caption backend info)))))
     (when (or label caption)
       (let* ((default-category
               (case (org-element-type element)
-- 
1.8.3.2


reply via email to

[Prev in Thread] Current Thread [Next in Thread]