diff --git a/CHANGES.rst b/CHANGES.rst
index 23eb3d8..852fad2 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,15 @@
+Version 2.0.2
+-------------
+
+Released 2021-11-10
+
+-   Detect if Sphinx dirhtml builder is generating canonical URLs with
+    ".html" and replace with the correct dir URL. :issue:`47`
+-   ``canonical_url`` config is deprecated. Use Sphinx's built-in
+    ``html_baseurl`` config instead. :pr:`53`
+-   Address deprecations in Jinja 2.0. :pr:`54`
+
+
 Version 2.0.1
 -------------
 
diff --git a/PKG-INFO b/PKG-INFO
index 8caabce..8c66894 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: Pallets-Sphinx-Themes
-Version: 2.0.1
+Version: 2.0.2
 Summary: Sphinx themes for Pallets and related projects.
 Home-page: https://github.com/pallets/pallets-sphinx-themes/
 Author: Pallets
@@ -11,36 +11,6 @@ Project-URL: Source Code, https://github.com/pallets/pallets-sphinx-themes/
 Project-URL: Issue Tracker, https://github.com/pallets/pallets-sphinx-themes/issues/
 Project-URL: Twitter, https://twitter.com/PalletsTeam
 Project-URL: Chat, https://discord.gg/pallets
-Description: Pallets Sphinx Themes
-        =====================
-        
-        Themes for the Pallets projects. If you're writing an extension, use the
-        appropriate theme to make your documentation look consistent.
-        
-        Available themes:
-        
-        -   flask
-        -   jinja
-        -   werkzeug
-        -   click
-        
-        Install this package:
-        
-        .. code-block:: text
-        
-            pip install Pallets-Sphinx-Themes
-        
-        Enable the extension and choose the theme in ``docs/conf.py``:
-        
-        .. code-block:: python
-        
-            extensions = [
-                "pallets_sphinx_themes",
-                ...
-            ]
-        
-            html_theme = "flask"
-        
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Framework :: Sphinx
@@ -54,3 +24,36 @@ Classifier: Topic :: Documentation :: Sphinx
 Classifier: Topic :: Software Development :: Documentation
 Requires-Python: >=3.6
 Description-Content-Type: text/x-rst
+License-File: LICENSE.rst
+
+Pallets Sphinx Themes
+=====================
+
+Themes for the Pallets projects. If you're writing an extension, use the
+appropriate theme to make your documentation look consistent.
+
+Available themes:
+
+-   flask
+-   jinja
+-   werkzeug
+-   click
+
+Install this package:
+
+.. code-block:: text
+
+    pip install Pallets-Sphinx-Themes
+
+Enable the extension and choose the theme in ``docs/conf.py``:
+
+.. code-block:: python
+
+    extensions = [
+        "pallets_sphinx_themes",
+        ...
+    ]
+
+    html_theme = "flask"
+
+
diff --git a/debian/changelog b/debian/changelog
index d23e525..3418201 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-pallets-sphinx-themes (2.0.2-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 16 May 2022 12:25:03 -0000
+
 python-pallets-sphinx-themes (2.0.1-1) unstable; urgency=medium
 
   [ Ondřej Nový ]
diff --git a/debian/patches/0001-Prevent-privacy-breach.patch b/debian/patches/0001-Prevent-privacy-breach.patch
index 221ba93..b70a2b3 100644
--- a/debian/patches/0001-Prevent-privacy-breach.patch
+++ b/debian/patches/0001-Prevent-privacy-breach.patch
@@ -9,16 +9,20 @@ Subject: Prevent privacy breach
  src/pallets_sphinx_themes/themes/platter/static/platter.css | 1 -
  4 files changed, 6 deletions(-)
 
---- a/src/pallets_sphinx_themes/themes/babel/static/babel.css
-+++ b/src/pallets_sphinx_themes/themes/babel/static/babel.css
+Index: python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/babel/static/babel.css
+===================================================================
+--- python-pallets-sphinx-themes.orig/src/pallets_sphinx_themes/themes/babel/static/babel.css
++++ python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/babel/static/babel.css
 @@ -1,5 +1,4 @@
  @import url(pocoo.css);
 -@import url(http://fonts.googleapis.com/css?family=Bree+Serif);
  
  body {
    font-family: "Verdana", "Garamond", "Georgia", serif;
---- a/src/pallets_sphinx_themes/themes/click/static/click.css
-+++ b/src/pallets_sphinx_themes/themes/click/static/click.css
+Index: python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/click/static/click.css
+===================================================================
+--- python-pallets-sphinx-themes.orig/src/pallets_sphinx_themes/themes/click/static/click.css
++++ python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/click/static/click.css
 @@ -1,6 +1,4 @@
  @import url("pocoo.css");
 -@import url("https://fonts.googleapis.com/css?family=Ubuntu+Mono");
@@ -26,16 +30,20 @@ Subject: Prevent privacy breach
  
  body, pre, code {
    font-family: "Ubuntu Mono", "Consolas", "Menlo", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace;
---- a/src/pallets_sphinx_themes/themes/jinja/static/jinja.css
-+++ b/src/pallets_sphinx_themes/themes/jinja/static/jinja.css
+Index: python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/jinja/static/jinja.css
+===================================================================
+--- python-pallets-sphinx-themes.orig/src/pallets_sphinx_themes/themes/jinja/static/jinja.css
++++ python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/jinja/static/jinja.css
 @@ -1,5 +1,4 @@
  @import url("pocoo.css");
 -@import url("https://fonts.googleapis.com/css?family=Crimson+Text");
  
  h1, h2, h3, h4, h5, h6, p.admonition-title, div.sphinxsidebar input {
    font-family: "Crimson Text", "Garamond", "Georgia", serif;
---- a/src/pallets_sphinx_themes/themes/platter/static/platter.css
-+++ b/src/pallets_sphinx_themes/themes/platter/static/platter.css
+Index: python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/platter/static/platter.css
+===================================================================
+--- python-pallets-sphinx-themes.orig/src/pallets_sphinx_themes/themes/platter/static/platter.css
++++ python-pallets-sphinx-themes/src/pallets_sphinx_themes/themes/platter/static/platter.css
 @@ -1,5 +1,4 @@
  @import url(pocoo.css);
 -@import url(https://fonts.googleapis.com/css?family=Fira+Mono:400,700|Bitter:400,400italic,700);
diff --git a/setup.cfg b/setup.cfg
index d238b76..f7ae1b4 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = Pallets-Sphinx-Themes
-version = 2.0.1
+version = 2.0.2
 url = https://github.com/pallets/pallets-sphinx-themes/
 project_urls = 
 	Donate = https://palletsprojects.com/donate
diff --git a/src/Pallets_Sphinx_Themes.egg-info/PKG-INFO b/src/Pallets_Sphinx_Themes.egg-info/PKG-INFO
index 8caabce..8c66894 100644
--- a/src/Pallets_Sphinx_Themes.egg-info/PKG-INFO
+++ b/src/Pallets_Sphinx_Themes.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: Pallets-Sphinx-Themes
-Version: 2.0.1
+Version: 2.0.2
 Summary: Sphinx themes for Pallets and related projects.
 Home-page: https://github.com/pallets/pallets-sphinx-themes/
 Author: Pallets
@@ -11,36 +11,6 @@ Project-URL: Source Code, https://github.com/pallets/pallets-sphinx-themes/
 Project-URL: Issue Tracker, https://github.com/pallets/pallets-sphinx-themes/issues/
 Project-URL: Twitter, https://twitter.com/PalletsTeam
 Project-URL: Chat, https://discord.gg/pallets
-Description: Pallets Sphinx Themes
-        =====================
-        
-        Themes for the Pallets projects. If you're writing an extension, use the
-        appropriate theme to make your documentation look consistent.
-        
-        Available themes:
-        
-        -   flask
-        -   jinja
-        -   werkzeug
-        -   click
-        
-        Install this package:
-        
-        .. code-block:: text
-        
-            pip install Pallets-Sphinx-Themes
-        
-        Enable the extension and choose the theme in ``docs/conf.py``:
-        
-        .. code-block:: python
-        
-            extensions = [
-                "pallets_sphinx_themes",
-                ...
-            ]
-        
-            html_theme = "flask"
-        
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Framework :: Sphinx
@@ -54,3 +24,36 @@ Classifier: Topic :: Documentation :: Sphinx
 Classifier: Topic :: Software Development :: Documentation
 Requires-Python: >=3.6
 Description-Content-Type: text/x-rst
+License-File: LICENSE.rst
+
+Pallets Sphinx Themes
+=====================
+
+Themes for the Pallets projects. If you're writing an extension, use the
+appropriate theme to make your documentation look consistent.
+
+Available themes:
+
+-   flask
+-   jinja
+-   werkzeug
+-   click
+
+Install this package:
+
+.. code-block:: text
+
+    pip install Pallets-Sphinx-Themes
+
+Enable the extension and choose the theme in ``docs/conf.py``:
+
+.. code-block:: python
+
+    extensions = [
+        "pallets_sphinx_themes",
+        ...
+    ]
+
+    html_theme = "flask"
+
+
diff --git a/src/pallets_sphinx_themes/__init__.py b/src/pallets_sphinx_themes/__init__.py
index 788d4e4..f8ed768 100644
--- a/src/pallets_sphinx_themes/__init__.py
+++ b/src/pallets_sphinx_themes/__init__.py
@@ -5,7 +5,9 @@ import sys
 import textwrap
 from collections import namedtuple
 
+from sphinx.application import Sphinx
 from sphinx.builders._epub_base import EpubBuilder
+from sphinx.builders.dirhtml import DirectoryHTMLBuilder
 from sphinx.builders.singlehtml import SingleFileHTMLBuilder
 from sphinx.errors import ExtensionError
 
@@ -72,19 +74,40 @@ def add_404_page(app):
 
 
 @only_pallets_theme()
-def canonical_url(app, pagename, templatename, context, doctree):
-    """Build the canonical URL for a page. Appends the path for the
-    page to the base URL specified by the
-    ``html_context["canonical_url"]`` config and stores it in
-    ``html_context["page_canonical_url"]``.
+def canonical_url(app: Sphinx, pagename, templatename, context, doctree):
+    """Sphinx 1.8 builds a canonical URL if ``html_baseurl`` config is
+    set. However, it builds a URL ending with ".html" when using the
+    dirhtml builder, which is incorrect. Detect this and generate the
+    correct URL for each page.
+
+    Also accepts the custom, deprecated ``canonical_url`` config as the
+    base URL. This will be removed in version 2.1.
     """
-    base = context.get("canonical_url")
+    base = app.config.html_baseurl
 
-    if not base:
+    if not base and context.get("canonical_url"):
+        import warnings
+
+        warnings.warn(
+            "'canonical_url' config is deprecated and will be removed"
+            " in Pallets-Sphinx-Themes 2.1. Set Sphinx's 'html_baseurl'"
+            " config instead.",
+            DeprecationWarning,
+        )
+        base = context["canonical_url"]
+
+    if (
+        not base
+        or not isinstance(app.builder, DirectoryHTMLBuilder)
+        or not context["pageurl"]
+        or not context["pageurl"].endswith(".html")
+    ):
         return
 
+    # Fix pageurl for dirhtml builder if this version of Sphinx still
+    # generates .html URLs.
     target = app.builder.get_target_uri(pagename)
-    context["page_canonical_url"] = base + target
+    context["pageurl"] = base + target
 
 
 @only_pallets_theme()
@@ -157,7 +180,7 @@ def get_version(name, version_length=2, placeholder="x"):
     version = ".".join(release.split(".", version_length)[:version_length])
 
     if placeholder:
-        version = "{}.{}".format(version, placeholder)
+        version = f"{version}.{placeholder}"
 
     return release, version
 
diff --git a/src/pallets_sphinx_themes/themes/pocoo/layout.html b/src/pallets_sphinx_themes/themes/pocoo/layout.html
index 81756c0..3745303 100644
--- a/src/pallets_sphinx_themes/themes/pocoo/layout.html
+++ b/src/pallets_sphinx_themes/themes/pocoo/layout.html
@@ -5,13 +5,6 @@
   <meta name="viewport" content="width=device-width, initial-scale=1">
 {%- endset %}
 
-{% block extrahead %}
-  {%- if page_canonical_url %}
-    <link rel="canonical" href="{{ page_canonical_url }}">
-  {%- endif %}
-  {{ super() }}
-{%- endblock %}
-
 {% block sidebarlogo %}
   {% if pagename != "index" or theme_index_sidebar_logo %}
     {{ super() }}
diff --git a/src/pallets_sphinx_themes/versions.py b/src/pallets_sphinx_themes/versions.py
index e95256b..95a4811 100644
--- a/src/pallets_sphinx_themes/versions.py
+++ b/src/pallets_sphinx_themes/versions.py
@@ -1,9 +1,8 @@
-import io
 import json
 import os
 from collections import namedtuple
 
-from jinja2 import contextfunction
+from jinja2 import pass_context
 from packaging import version as pv
 
 from .theme_check import only_pallets_theme
@@ -27,7 +26,7 @@ def local_versions(app):
 
     if isinstance(config_versions, str):
         if os.path.isfile(config_versions):
-            with io.open(config_versions, "rt", encoding="utf8") as f:
+            with open(config_versions, encoding="utf8") as f:
                 config_versions = json.load(f)
         else:
             config_versions = json.loads(config_versions)
@@ -97,7 +96,7 @@ def readthedocs_versions(app):
 
 
 def _is_version(value, placeholder="x"):
-    if value.endswith(".{}".format(placeholder)):
+    if value.endswith(f".{placeholder}"):
         value = value[: -(len(placeholder) + 1)]
 
     try:
@@ -119,11 +118,9 @@ class DocVersion(
         if _is_version(slug):
             name = "Version " + name
 
-        return super(DocVersion, cls).__new__(
-            cls, name, slug, version, latest, dev, current
-        )
+        return super().__new__(cls, name, slug, version, latest, dev, current)
 
-    @contextfunction
+    @pass_context
     def href(self, context):
         pathto = context["pathto"]
         master_doc = context["master_doc"]
@@ -134,7 +131,7 @@ class DocVersion(
         path = builder.get_target_uri(pagename)
         return "/".join((master, "..", self.slug, path))
 
-    @contextfunction
+    @pass_context
     def banner(self, context):
         if self.latest:
             return