Exporting UTF-8 Smart Quotes from Org Mode
10 Apr 2024 Charles Choi
Count me as one who really likes using smart quotes when exporting from Org. To enable this requires that you set the variable org-export-with-smart-quotes
to t
. So far, so good yes? Not quite. Apparently by default when exporting to HTML or Markdown, Org will use the HTML character entity representation of a smart quote which I see as overly conservative in 2024. As most contemporary software now can handle UTF-8, it seems to me more sensible to use smart quote characters that are likewise UTF-8. For English these are:
- left and right double quote
- left and right single quote
- apostrophe (right single quote)
Apparently Org has an alist variable that captures the different representations of the above for different languages and for different export targets. This variable is called org-export-smart-quotes-alist
and sure enough it captures the UTF-8 set of characters for each language. Empowered with this knowledge, here’s some Elisp code to reconfigure org-export-smart-quotes-alist
so that exporting to HTML or Markdown uses the UTF-8 representation for English (en).
(defun cc/reconfig-org-smart-quotes-lang (lang)
"Reconfigure Org smart quotes to use utf-8 per LANG."
(let* ((db-entry (assoc-string lang org-export-smart-quotes-alist))
(utf8-primary-opening (plist-get (assoc-default 'primary-opening db-entry) :utf-8))
(utf8-primary-closing (plist-get (assoc-default 'primary-closing db-entry) :utf-8))
(utf8-secondary-opening (plist-get (assoc-default 'secondary-opening db-entry) :utf-8))
(utf8-secondary-closing (plist-get (assoc-default 'secondary-closing db-entry) :utf-8))
(utf8-apostrophe (plist-get (assoc-default 'apostrophe db-entry) :utf-8))
)
(setf (plist-get
(assoc-default 'primary-opening
(assoc-string lang org-export-smart-quotes-alist))
:html)
utf8-primary-opening)
(setf (plist-get
(assoc-default 'primary-closing
(assoc-string lang org-export-smart-quotes-alist))
:html)
utf8-primary-closing)
(setf (plist-get
(assoc-default 'secondary-opening
(assoc-string lang org-export-smart-quotes-alist))
:html)
utf8-secondary-opening)
(setf (plist-get
(assoc-default 'secondary-closing
(assoc-string lang org-export-smart-quotes-alist))
:html)
utf8-secondary-closing)
(setf (plist-get
(assoc-default 'apostrophe
(assoc-string lang org-export-smart-quotes-alist))
:html)
utf8-apostrophe)))
(add-hook 'org-mode-hook (lambda ()
(cc/reconfig-org-smart-quotes-lang "en")))
The above code is tested on Emacs 29.1, Org 9.6.25.
If you export to different languages, be sure to run cc/reconfig-org-smart-quotes-lang
with your language of choice.
I leave it as an exercise to motivated readers more experienced in Elisp to write a cleaner version of this code. As it stands, this works well enough to achieve my desired goal.