Fix HeaderDotSlash rendering.
[doclang.git] / Language / DTC / Write / HTML5.hs
index 028ba26880cd09399589a8124c2580d5a7e3d4a9..eb87c8451a748ab21665db0051f84e85aa71a786 100644 (file)
@@ -5,39 +5,30 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TypeApplications #-}
-{-# LANGUAGE ViewPatterns #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Language.DTC.Write.HTML5 where
 
--- import Control.Monad.Trans.Class (MonadTrans(..))
--- import Data.Functor.Identity (Identity(..))
--- import Data.Sequence (Seq)
--- import Data.Set (Set)
--- import Data.Traversable (Traversable(..))
--- import qualified Data.Sequence as Seq
--- import qualified Data.TreeSeq.Strict as Tree
 import Control.Applicative (Applicative(..))
-import Control.Category
+import Control.Category as Cat
 import Control.Monad
 import Data.Bool
 import Data.Char (Char)
 import Data.Default.Class (Default(..))
 import Data.Eq (Eq(..))
-import Data.Foldable (Foldable(..))
+import Data.Foldable (Foldable(..), concat, any)
 import Data.Function (($), const, flip, on)
 import Data.Functor (Functor(..), (<$>))
 import Data.Functor.Compose (Compose(..))
 import Data.Int (Int)
 import Data.Map.Strict (Map)
-import Data.Maybe (Maybe(..), mapMaybe, fromJust)
+import Data.Maybe (Maybe(..), maybe, mapMaybe, fromJust, maybeToList)
 import Data.Monoid (Monoid(..))
 import Data.Ord (Ord(..))
 import Data.Semigroup (Semigroup(..))
-import Data.String (String)
+import Data.String (String, IsString(..))
 import Data.Text (Text)
-import Data.TreeSeq.Strict (Tree(..), Trees)
+import Data.TreeSeq.Strict (Tree(..), tree0)
 import Data.Tuple (snd)
-import Prelude (Num(..))
 import System.FilePath (FilePath)
 import Text.Blaze ((!))
 import Text.Blaze.Html (Html)
@@ -50,22 +41,160 @@ import qualified Data.Strict.Maybe as Strict
 import qualified Data.Text as Text
 import qualified Data.Text.Lazy as TL
 import qualified Data.TreeMap.Strict as TreeMap
-import qualified Data.TreeSeq.Strict as Tree
 import qualified Data.TreeSeq.Strict.Zipper as Tree
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes  as HA
 import qualified Text.Blaze.Internal as H
 
 import Text.Blaze.Utils
-import Data.Locale hiding (localize, Index)
+import Data.Locale hiding (Index)
 import qualified Data.Locale as Locale
 
-import Language.DTC.Document (Document)
+import Language.DTC.Document as DTC
+import Language.DTC.Write.Plain (Plainify(..))
 import Language.DTC.Write.XML ()
-import Language.XML (XmlName(..), XmlPos(..))
-import qualified Language.DTC.Document as DTC
-import qualified Language.DTC.Index as Index
--- import Debug.Trace (trace)
+import qualified Language.DTC.Anchor as Anchor
+import qualified Language.DTC.Write.Plain as Plain
+
+document ::
+ Localize locales Plain.Plain Plain.L10n =>
+ Localize locales Html5 L10n =>
+ Locales  locales =>
+ LocaleIn locales -> DTC.Document -> Html
+document locale DTC.Document{..} = do
+       let Keys{..} = keys body `S.execState` def
+       let (body',state_rrefs,state_notes,state_indexs) =
+               let irefs = foldMap Anchor.irefsOfTerms keys_index in
+               let (body0, Anchor.State{state_irefs, state_rrefs=rrefs, state_notes=notes}) =
+                       Anchor.anchorify body `S.runState`
+                       def{Anchor.state_irefs=irefs} in
+               (body0,rrefs,notes,) $
+               (<$> keys_index) $ \terms ->
+                       (terms,) $
+                       TreeMap.intersection const state_irefs $
+                       Anchor.irefsOfTerms terms
+       let state_plainify = def
+               { Plain.state_localize = Locale.localize locale }
+       let (html5Body, endState) =
+               runStateMarkup def
+                { state_indexs
+                , state_rrefs
+                , state_notes
+                , state_figures    = keys_figure
+                , state_references = keys_reference
+                , state_plainify
+                , state_localize = Locale.localize locale
+                } $ do
+                       html5DocumentHead head
+                       html5ify body'
+       H.docType
+       H.html ! HA.lang (attrify $ countryCode locale) $ do
+               html5Head endState head body
+               H.body $ html5Body
+
+html5Head :: State -> Head -> Body -> Html
+html5Head State{..} Head{DTC.about=About{..}} body = do
+       H.head $ do
+               H.meta ! HA.httpEquiv "Content-Type"
+                      ! HA.content "text/html; charset=UTF-8"
+               unless (null titles) $ do
+                       H.title $
+                               H.toMarkup $ Plain.text state_plainify $ List.head titles
+               forM_ links $ \Link{rel, href} ->
+                       H.link ! HA.rel (attrify rel)
+                              ! HA.href (attrify href)
+               forM_ url $ \href ->
+                       H.link ! HA.rel "self"
+                              ! HA.href (attrify href)
+               H.meta ! HA.name "generator"
+                      ! HA.content "https://hackage.haskell.org/package/hdoc"
+               unless (null tags) $
+                       H.meta ! HA.name "keywords"
+                              ! HA.content (attrify $ TL.intercalate ", " tags)
+               let chapters =
+                       (`mapMaybe` toList body) $ \case
+                        Tree k@BodySection{} _ -> Just k
+                        _ -> Nothing
+               forM_ chapters $ \case
+                BodySection{..} ->
+                       H.link ! HA.rel "Chapter"
+                              ! HA.title (attrify $ plainify title)
+                              ! HA.href ("#"<>attrify pos)
+                _ -> mempty
+               unless (any (\DTC.Link{rel} -> rel == "stylesheet") links) $ do
+                       H.link ! HA.rel "stylesheet"
+                              ! HA.type_ "text/css"
+                              ! HA.href "style/dtc-html5.css"
+                       forM_ state_styles $ \style ->
+                               H.style ! HA.type_ "text/css" $
+                                       H.toMarkup style
+               unless (any (\DTC.Link{rel} -> rel == "script") links) $ do
+                       forM_ state_scripts $ \script ->
+                               H.script ! HA.type_ "application/javascript" $
+                                       H.toMarkup script
+
+html5DocumentHead :: Head -> Html5
+html5DocumentHead Head{DTC.about=About{..}} = do
+       H.div ! HA.class_ "document-head" $$
+               H.table $$ do
+                       H.tbody $$ do
+                               H.tr $$ do
+                                       H.td ! HA.class_ "left"  $$ docHeaders
+                                       H.td ! HA.class_ "right" $$ docAuthors
+       unless (null titles) $
+               H.div ! HA.class_ "title" $$ do
+                       forM_ titles $ \title ->
+                               H.h1 $$ html5ify title
+       where
+       docHeaders =
+               H.table ! HA.class_ "document-headers" $$
+                       H.tbody $$ do
+                               forM_ series $ \s@Serie{id=id_, name} ->
+                                       header $
+                                               case urlSerie s of
+                                                Nothing -> do
+                                                       headerName  $ html5ify name
+                                                       headerValue $ html5ify id_
+                                                Just href -> do
+                                                       headerName  $ html5ify name
+                                                       headerValue $
+                                                               H.a ! HA.href (attrify href) $$
+                                                                       html5ify id_
+                               forM_ date $ \d ->
+                                       header $ do
+                                               headerName  $ html5ify L10n_Header_Date
+                                               headerValue $ html5ify d
+                               forM_ url $ \href ->
+                                       header $ do
+                                               headerName  $ html5ify L10n_Header_Address
+                                               headerValue $ html5ify $ tree0 $ PlainEref{href}
+                               forM_ links $ \Link{..} ->
+                                       unless (TL.null name) $
+                                               header $ do
+                                                       headerName  $ html5ify name
+                                                       headerValue $ html5ify $ Tree PlainEref{href} plain
+                               forM_ headers $ \Header{..} ->
+                                       header $ do
+                                               headerName  $ html5ify name
+                                               headerValue $ html5ify value
+       docAuthors =
+               H.table ! HA.class_ "document-authors" $$
+                       H.tbody $$ do
+                               forM_ authors $ \a ->
+                                       H.tr $$
+                                               H.td ! HA.class_ "author" $$
+                                                       html5ify a
+       header :: Html5 -> Html5
+       header h = H.tr ! HA.class_ "header" $$ h
+       headerName :: Html5 -> Html5
+       headerName h =
+               H.td ! HA.class_ "header-name" $$ do
+                       h
+                       html5ify Plain.L10n_Colon
+       headerValue :: Html5 -> Html5
+       headerValue h =
+               H.td ! HA.class_ "header-value" $$ do
+                       h
 
 (<&>) :: Functor f => f a -> (a -> b) -> f b
 (<&>) = flip (<$>)
@@ -73,141 +202,150 @@ infixl 4 <&>
 
 -- * Type 'Html5'
 type Html5 = StateMarkup State ()
+instance IsString Html5 where
+       fromString = html5ify
 
--- ** Type 'State'
+-- * Type 'State'
 data State
  =   State
- { styles   :: Map FilePath CSS
- , scripts  :: Map FilePath Script
- , localize :: MsgHtml5 -> Html5
- , indexs   :: Map XmlPos (DTC.Terms, Index.Refs)
- }
-state :: State
-state = State
- { styles   = mempty
- , scripts  = mempty
- , localize = html5ify . show
- , indexs   = mempty
+ {   state_styles     :: Map FilePath CSS
+ ,   state_scripts    :: Map FilePath Script
+ ,   state_indexs     :: Map DTC.Pos (Terms, Anchor.Irefs)
+ ,   state_rrefs      :: Anchor.Rrefs
+ ,   state_figures    :: Map TL.Text (Map DTC.Pos (Maybe Title))
+ ,   state_references :: Map Ident About
+ ,   state_notes      :: Anchor.Notes
+ ,   state_plainify   :: Plain.State
+ ,   state_localize   :: L10n -> Html5
  }
+instance Default State where
+       def = State
+        { state_styles     = def
+        , state_scripts    = def
+        , state_indexs     = def
+        , state_rrefs      = def
+        , state_figures    = def
+        , state_references = def
+        , state_notes      = def
+        , state_plainify   = def
+        , state_localize   = html5ify . show
+        }
 type CSS = Text
 type Script = Text
 
--- ** Type 'Keys'
+-- * Type 'Keys'
 data Keys
  = Keys
- { keys_index :: Map XmlPos DTC.Terms
+ { keys_index     :: Map DTC.Pos Terms
+ , keys_figure    :: Map TL.Text (Map DTC.Pos (Maybe Title))
+ , keys_reference :: Map Ident About
  } deriving (Show)
+instance Default Keys where
+       def = Keys mempty mempty mempty
 
-keys :: Trees DTC.BodyKey DTC.BodyValue -> Keys
-keys body = foldl' flt (Keys mempty) (Compose body)
-       where
-       flt acc = \case
-        DTC.Index{..} -> acc{keys_index =
-               Map.insert pos terms $ keys_index acc}
-        _ -> acc
+-- ** Class 'KeysOf'
+class KeysOf a where
+       keys :: a -> S.State Keys ()
+instance KeysOf Body where
+       keys = mapM_ keys
+instance KeysOf (Tree BodyNode) where
+       keys (Tree n ts) =
+               case n of
+                BodySection{..} -> keys ts
+                BodyBlock b -> keys b
+instance KeysOf DTC.Block where
+       keys = \case
+        BlockPara{} -> return ()
+        BlockToC{}  -> return ()
+        BlockToF{}  -> return ()
+        BlockIndex{..} ->
+               S.modify $ \s -> s{keys_index=
+                       Map.insert pos terms $ keys_index s}
+        BlockFigure{..} ->
+               S.modify $ \s -> s{keys_figure=
+                       Map.insertWith (<>)
+                        type_ (Map.singleton pos mayTitle) $
+                       keys_figure s}
+        BlockReferences{..} ->
+               S.modify $ \s -> s{keys_reference=
+                       foldr
+                        (\r -> Map.insert
+                                (DTC.id    (r::DTC.Reference))
+                                (DTC.about (r::DTC.Reference)))
+                        (keys_reference s)
+                        refs}
 
--- ** Class 'Html5ify'
+-- * Class 'Html5ify'
 class Html5ify a where
        html5ify :: a -> Html5
+instance Html5ify H.Markup where
+       html5ify = Compose . return
 instance Html5ify Char where
        html5ify = html5ify . H.toMarkup
 instance Html5ify Text where
        html5ify = html5ify . H.toMarkup
+instance Html5ify TL.Text where
+       html5ify = html5ify . H.toMarkup
 instance Html5ify String where
        html5ify = html5ify . H.toMarkup
-instance Html5ify H.Markup where
-       html5ify = Compose . return
-instance Html5ify DTC.Title where
-       html5ify (DTC.Title t) = html5ify t
-instance Html5ify DTC.Ident where
-       html5ify (DTC.Ident i) = html5ify i
-
-html5Document ::
- Localize ls Html5 MsgHtml5 =>
- Locales ls =>
- LocaleIn ls -> Document -> Html
-html5Document locale DTC.Document{..} = do
-       let Keys{..} = keys body
-       let (body',indexs) =
-               case foldMap Index.refsOfTerms keys_index of
-                refs | null refs -> (body, mempty)
-                     | otherwise ->
-                       (<$> S.runState
-                                (Index.indexify body)
-                                Index.state
-                                        { Index.state_refs = refs
-                                        }) $ \Index.State{state_refs} ->
-                               (<$> keys_index) $ \terms ->
-                                       (terms,) $
-                                       TreeMap.intersection const state_refs $
-                                       Index.refsOfTerms terms
-       let (html5Body, State{styles,scripts}) =
-               runStateMarkup state{indexs} $ do
-                       liftStateMarkup $ S.modify $ \s -> s{localize = Locale.localize locale}
-                       html5ify body'
-       
-       H.docType
-       H.html ! HA.lang (attrValue $ countryCode locale) $ do
-               H.head $ do
-                       H.meta ! HA.httpEquiv "Content-Type"
-                              ! HA.content "text/html; charset=UTF-8"
-                       whenSome (DTC.titles $ DTC.about (head :: DTC.Head)) $ \ts ->
-                               H.title $
-                                       H.toMarkup $ plainify $ List.head ts
-                       forM_ (DTC.links $ DTC.about (head :: DTC.Head)) $ \DTC.Link{rel, href} ->
-                               H.link ! HA.rel (attrValue rel)
-                                      ! HA.href (attrValue href)
-                       H.meta ! HA.name "generator"
-                              ! HA.content "tct"
-                       let chapters =
-                               (`mapMaybe` toList body) $ \case
-                                TreeN k@DTC.Section{} _ -> Just k
-                                _ -> Nothing
-                       forM_ chapters $ \DTC.Section{..} ->
-                               H.link ! HA.rel "Chapter"
-                                      ! HA.title (attrValue $ plainify title)
-                                      ! HA.href ("#"<>attrValue pos)
-                       H.link ! HA.rel "stylesheet"
-                              ! HA.type_ "text/css"
-                              ! HA.href "style/dtc-html5.css"
-                       forM_ styles $ \style ->
-                               H.style ! HA.type_ "text/css" $
-                                       H.toMarkup style
-                       forM_ scripts $ \script ->
-                               H.script ! HA.type_ "application/javascript" $
-                                       H.toMarkup script
-               H.body
-                       html5Body
+instance Html5ify Title where
+       html5ify (Title t) = html5ify t
+instance Html5ify Ident where
+       html5ify (Ident i) = html5ify i
+instance Html5ify Int where
+       html5ify = html5ify . show
+instance Html5ify Nat where
+       html5ify (Nat n) = html5ify n
+instance Html5ify Nat1 where
+       html5ify (Nat1 n) = html5ify n
+instance Html5ify a => Html5ify (Maybe a) where
+       html5ify = foldMap html5ify
 
 -- * Type 'BodyCursor'
--- | Cursor to navigate within a 'DTC.Body' according to many axis (like in XSLT).
-type BodyCursor = Tree.Zipper DTC.BodyKey DTC.BodyValue
-instance Html5ify DTC.Body where
+-- | Cursor to navigate within a 'Body' according to many axis (like in XSLT).
+type BodyCursor = Tree.Zipper BodyNode
+instance Html5ify Body where
        html5ify body =
                forM_ (Tree.zippers body) $ \z ->
                        forM_ (Tree.axis_repeat Tree.axis_following_sibling_nearest `Tree.runAxis` z) $
                                html5ify
-
-instance Html5ify BodyCursor where
-       html5ify z =
-               case Tree.current z of
-                TreeN k _ts -> html5BodyKey z k
-                Tree0 v     -> html5BodyValue z v
-
-html5BodyKey :: BodyCursor -> DTC.BodyKey -> Html5
-html5BodyKey z = \case
-        DTC.Section{..} ->
+instance Html5ify BodyCursor
+ where html5ify z =
+       let Tree n _ts = Tree.current z in
+       case n of
+        BodyBlock BlockToC{..} -> do
+               H.nav ! HA.class_ "toc"
+                     ! HA.id (attrify pos) $$ do
+                       H.span ! HA.class_ "toc-name" $$
+                               H.a ! HA.href (attrify pos) $$
+                                       html5ify Plain.L10n_Table_of_Contents
+                       H.ul $$
+                               forM_ (Tree.axis_following_sibling `Tree.runAxis` z) $
+                                       html5ifyToC depth
+        BodyBlock b -> html5ify b
+        BodySection{..} -> do
+               do
+                       notes <- liftStateMarkup $ S.gets state_notes
+                       let mayNotes = do
+                               p <- posParent $ posAncestors pos
+                               let (ns, as) = Map.updateLookupWithKey (\_ _ -> Nothing) p notes
+                               (,as) <$> ns
+                       case mayNotes of
+                        Nothing -> mempty
+                        Just (secNotes, state_notes) -> do
+                               liftStateMarkup $ S.modify' $ \s -> s{state_notes}
+                               html5ify secNotes
                H.section ! HA.class_ "section"
-                         ! HA.id (attrValue pos) $$ do
-                       html5CommonAttrs attrs $
-                               H.table ! HA.class_ "section-header" $$
+                         ! HA.id (attrify pos) $$ do
+                       forM_ aliases html5ify
+                       html5CommonAttrs attrs{classes="section-header":classes attrs} $
+                               H.table $$
                                        H.tbody $$
                                                H.tr $$ do
                                                        H.td ! HA.class_ "section-number" $$ do
-                                                               html5SectionNumber $
-                                                                       xmlPosAncestors pos
+                                                               html5SectionNumber $ DTC.posAncestors pos
                                                        H.td ! HA.class_ "section-title" $$ do
-                                                               (case List.length $ xmlPosAncestors pos of
+                                                               (case List.length $ DTC.posAncestors pos of
                                                                 0 -> H.h1
                                                                 1 -> H.h2
                                                                 2 -> H.h3
@@ -218,314 +356,521 @@ html5BodyKey z = \case
                                                                        html5ify title
                        forM_ (Tree.axis_child `Tree.runAxis` z) $
                                html5ify
-html5BodyValue :: BodyCursor -> DTC.BodyValue -> Html5
-html5BodyValue z = \case
-        DTC.Block b -> html5ify b
-        DTC.ToC{..} -> do
-               H.nav ! HA.class_ "toc"
-                     ! HA.id (attrValue pos) $$ do
-                       H.span ! HA.class_ "toc-name" $$
-                               H.a ! HA.href (attrValue pos) $$
-                                       html5ify MsgHTML5_Table_of_Contents
-                       H.ul $$
-                               forM_ (Tree.axis_following_sibling `Tree.runAxis` z) $
-                                       html5ToC d
-               where d = case depth of { Just (DTC.Nat n) -> n; _ -> 0 }
-        DTC.ToF{..} -> do
+                       notes <- liftStateMarkup $ S.gets state_notes
+                       html5ify $ Map.lookup (posAncestors pos) notes
+instance Html5ify [Anchor.Note] where
+       html5ify notes =
+               H.aside ! HA.class_ "notes" $$ do
+                       Compose $ pure H.hr
+                       H.table $$
+                               H.tbody $$
+                                       forM_ (List.reverse notes) $ \Anchor.Note{..} ->
+                                               H.tr $$ do
+                                                       H.td ! HA.class_ "note-ref" $$ do
+                                                               H.a ! HA.class_ "note-number"
+                                                                   ! HA.id   ("note."<>attrify note_number)
+                                                                   ! HA.href ("#note."<>attrify note_number) $$ do
+                                                                       html5ify note_number
+                                                               ". "::Html5
+                                                               H.a ! HA.href ("#note-ref."<>attrify note_number) $$ do
+                                                                       "↑"
+                                                       H.td $$
+                                                               html5ify note_content
+instance Html5ify Block where
+       html5ify = \case
+        BlockPara para -> html5ify para
+        BlockToC{..} -> mempty -- NOTE: done in Html5ify BodyCursor
+        BlockToF{..} -> do
                H.nav ! HA.class_ "tof"
-                     ! HA.id (attrValue pos) $$
+                     ! HA.id (attrify pos) $$
                        H.table ! HA.class_ "tof" $$
                                H.tbody $$
-                                       forM_ (Tree.axis_preceding `Tree.runAxis` z) $
-                                               html5ToF d
-               where d = case depth of { Just (DTC.Nat n) -> n; _ -> 0 }
-        DTC.Figure{..} ->
-               html5CommonAttrs attrs $
-               H.div ! HA.class_ (attrValue $ "figure-"<>type_)
-                     ! HA.id (attrValue pos) $$ do
+                                       html5ifyToF types
+        BlockFigure{..} ->
+               html5CommonAttrs attrs
+                { classes = "figure":("figure-"<>type_):classes attrs
+                , DTC.id  = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
+                } $
+               H.div $$ do
                        H.table ! HA.class_ "figure-caption" $$
                                H.tbody $$
                                        H.tr $$ do
-                                               H.td ! HA.class_ "figure-number" $$ do
-                                                       H.a ! HA.href ("#"<>attrValue pos) $$
-                                                               html5ify type_
-                                                       ": "
-                                               H.td ! HA.class_ "figure-name" $$
-                                                       html5ify title
+                                               if TL.null type_
+                                                then H.a ! HA.href ("#"<>attrify pos) $$ mempty
+                                                else
+                                                       H.td ! HA.class_ "figure-number" $$ do
+                                                               H.a ! HA.href ("#"<>attrify pos) $$ do
+                                                                       html5ify type_
+                                                                       html5ify $ DTC.posAncestors pos
+                                               forM_ mayTitle $ \title ->
+                                                       H.td ! HA.class_ "figure-title" $$ do
+                                                               unless (TL.null type_) $
+                                                                       html5ify $ Plain.L10n_Colon
+                                                               html5ify title
                        H.div ! HA.class_ "figure-content" $$ do
-                               html5ify blocks
-        DTC.Index{pos} -> do
-               (allTerms,refsByTerm) <- liftStateMarkup $ S.gets $ (Map.! pos) . indexs
-               let chars = Index.termsByChar allTerms
+                               html5ify paras
+        BlockIndex{pos} -> do
+               (allTerms,refsByTerm) <- liftStateMarkup $ S.gets $ (Map.! pos) . state_indexs
+               let chars = Anchor.termsByChar allTerms
                H.div ! HA.class_ "index"
-                     ! HA.id (attrValue pos) $$ do
-                       H.nav ! HA.class_ "index-nav-chars" $$ do
+                     ! HA.id (attrify pos) $$ do
+                       H.nav ! HA.class_ "index-nav" $$ do
                                forM_ (Map.keys chars) $ \char ->
-                                       H.a ! HA.href ("#"<>(attrValue pos <> "." <> attrValue char)) $$
+                                       H.a ! HA.href ("#"<>(attrify pos <> "." <> attrify char)) $$
                                                html5ify char
-                       H.dl $$
+                       H.dl ! HA.class_ "index-chars" $$
                                forM_ (Map.toList chars) $ \(char,terms) -> do
                                        H.dt $$
-                                               let i = attrValue pos <> "." <> attrValue char in
+                                               let i = attrify pos <> "." <> attrify char in
                                                H.a ! HA.id i
                                                    ! HA.href ("#"<>i) $$
                                                        html5ify char
                                        H.dd $$
-                                               H.dl ! HA.class_ "index-char-refs" $$ do
+                                               H.dl ! HA.class_ "index-term" $$ do
                                                forM_ terms $ \aliases -> do
                                                        H.dt $$
-                                                               forM_ aliases $ \term ->
-                                                                       H.ul $$
-                                                                               H.li ! HA.id (attrValue Index.Ref{term, count=0, section=def}) $$
+                                                               H.ul ! HA.class_ "index-aliases" $$
+                                                                       forM_ (List.take 1 aliases) $ \term ->
+                                                                               H.li ! HA.id (attrifyIref term) $$
                                                                                        html5ify term
-                                                       H.dd $$ do
-                                                               let refs =
-                                                                       List.sortBy
-                                                                        (compare `on` Index.section) $
-                                                                       (`foldMap` aliases) $ \words -> fromJust $ do
-                                                                               path <- Index.pathFromWords words
-                                                                               Strict.maybe Nothing Just $
-                                                                                       TreeMap.lookup path refsByTerm
-                                                               sequence_ $
-                                                                       List.intersperse ", " $
-                                                                       (<$> refs) $ \ref@Index.Ref{..} ->
-                                                                               H.a ! HA.href ("#"<>attrValue ref) $$
-                                                                                       html5ify $
-                                                                                               List.intercalate "." $
-                                                                                               List.reverse $
-                                                                                               (<$> xmlPosAncestors section) $ \(_n,c) -> show c
-
-instance Html5ify DTC.Words where
-       html5ify = html5ify . Index.plainifyWords
+                                                       H.dd $$
+                                                               let anchs =
+                                                                       List.sortBy (compare `on` DTC.section . snd) $
+                                                                       (`foldMap` aliases) $ \words ->
+                                                                               fromJust $ do
+                                                                                       path <- Anchor.pathFromWords words
+                                                                                       Strict.maybe Nothing (Just . ((words,) <$>) . List.reverse) $
+                                                                                               TreeMap.lookup path refsByTerm in
+                                                               html5CommasDot $
+                                                               (<$> anchs) $ \(term,DTC.Anchor{..}) ->
+                                                                       H.a ! HA.class_ "index-iref"
+                                                                           ! HA.href ("#"<>attrifyIrefCount term count) $$
+                                                                               html5ify $ DTC.posAncestors section
+        BlockReferences{..} ->
+               html5CommonAttrs attrs
+                { classes = "references":classes attrs
+                , DTC.id  = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
+                } $
+               H.div $$ do
+                       H.table $$
+                               forM_ refs html5ify
 
-html5ToC :: Int -> BodyCursor -> Html5
-html5ToC depth z =
-       case Tree.current z of
-        TreeN DTC.Section{..} _ts -> do
+html5ifyToC :: Maybe DTC.Nat -> BodyCursor -> Html5
+html5ifyToC depth z =
+       let Tree n _ts = Tree.current z in
+       case n of
+        BodySection{..} -> do
                H.li $$ do
                        H.table ! HA.class_ "toc-entry" $$
                                H.tbody $$
                                        H.tr $$ do
                                                H.td ! HA.class_ "section-number" $$
-                                                       html5SectionRef $ xmlPosAncestors pos
+                                                       html5SectionRef $ DTC.posAncestors pos
                                                H.td ! HA.class_ "section-title" $$
-                                                       html5ify $
-                                                               DTC.unTitle title >>= \ts -> Tree.bindTrees ts $ \case
-                                                                TreeN DTC.Iref{} ls -> ls
-                                                                TreeN DTC.Note{} _ -> mempty
-                                                                h -> pure h
-                       let sections =
-                               (`Tree.runAxis` z) $
-                               Tree.axis_child
-                               `Tree.axis_filter_current` \case
-                                TreeN DTC.Section{} _ -> True
-                                _ -> False
-                       when (depth > 0 && not (null sections)) $
+                                                       html5ify $ cleanPlain $ unTitle title
+                       when (maybe True (> Nat 1) depth && not (null sections)) $
                                H.ul $$
                                        forM_ sections $
-                                               html5ToC (depth - 1)
+                                               html5ifyToC (depth >>= predNat)
         _ -> pure ()
+       where
+       sections =
+               (`Tree.runAxis` z) $
+               Tree.axis_child
+               `Tree.axis_filter_current` \case
+                Tree BodySection{} _ -> True
+                _ -> False
 
-html5ToF :: Int -> BodyCursor -> Html5
-html5ToF depth z =
-       case Tree.current z of
-        Tree0 v ->
-               case v of
-                DTC.Figure{..} ->
-                       H.tr $$ do
-                               H.td ! HA.class_ "figure-number" $$
-                                       H.a ! HA.href ("#"<>attrValue pos) $$
-                                               html5ify type_
-                               H.td ! HA.class_ "figure-name" $$
-                                       html5ify title
-                _ -> pure ()
-        _ -> pure ()
+html5ifyToF :: [TL.Text] -> Html5
+html5ifyToF types = do
+       figsByType <- liftStateMarkup $ S.gets state_figures
+       let figs =
+               Map.foldMapWithKey (\ty -> ((ty,) <$>)) $
+               if null types
+               then figsByType
+               else
+                       Map.intersection figsByType $
+                       Map.fromList [(ty,()) | ty <- types]
+       forM_ (Map.toList figs) $ \(pos, (type_, title)) ->
+               H.tr $$ do
+                       H.td ! HA.class_ "figure-number" $$
+                               H.a ! HA.href ("#"<>attrify pos) $$ do
+                                       html5ify type_
+                                       html5ify $ DTC.posAncestors pos
+                       forM_ title $ \ti ->
+                               H.td ! HA.class_ "figure-title" $$
+                                       html5ify $ cleanPlain $ unTitle ti
 
-instance Html5ify [DTC.Block] where
-       html5ify = mapM_ html5ify
-instance Html5ify DTC.Block where
+cleanPlain :: Plain -> Plain
+cleanPlain ps =
+       ps >>= \case
+        Tree PlainIref{} ls -> cleanPlain ls
+        Tree PlainNote{} _  -> mempty
+        Tree n ts -> pure $ Tree n $ cleanPlain ts
+
+instance Html5ify Para where
        html5ify = \case
-        DTC.Para{..} ->
-               html5CommonAttrs attrs $
-               H.p ! HA.class_ "para"
-                   ! HA.id (attrValue pos) $$ do
-                       html5ify lines
-        DTC.OL{..} ->
-               html5CommonAttrs attrs $
-               H.ol ! HA.class_ "ol"
-                    ! HA.id (attrValue pos) $$ do
-                       forM_ items $ \item ->
-                               H.li $$ html5ify item
-        DTC.UL{..} ->
-               html5CommonAttrs attrs $
-               H.ul ! HA.class_ "ul"
-                    ! HA.id (attrValue pos) $$ do
+        ParaItem{..} ->
+               html5CommonAttrs def
+                { classes="para":cls item
+                } $
+                       html5ify item
+        ParaItems{..} ->
+               html5CommonAttrs attrs
+                { classes = "para":classes attrs
+                , DTC.id  = id_ pos
+                } $
+               H.div $$
                        forM_ items $ \item ->
-                               H.li $$ html5ify item
-        DTC.RL{..} ->
-               html5CommonAttrs attrs $
-               H.div ! HA.class_ "rl"
-                     ! HA.id (attrValue pos) $$ do
-                       H.table $$
-                               forM_ refs html5ify
-        DTC.Comment t ->
-               html5ify $ H.Comment (H.Text t) ()
-instance Html5ify DTC.Lines where
-       html5ify = mapM_ $ \case
-        Tree0 v ->
-               case v of
-                DTC.BR      -> html5ify H.br
-                DTC.Plain t -> html5ify t
-        TreeN k ls ->
-               case k of
-                DTC.B    -> H.strong $$ html5ify ls
-                DTC.Code -> H.code   $$ html5ify ls
-                DTC.Del  -> H.del    $$ html5ify ls
-                DTC.I    -> H.i      $$ html5ify ls
-                DTC.Sub  -> H.sub    $$ html5ify ls
-                DTC.Sup  -> H.sup    $$ html5ify ls
-                DTC.SC   -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
-                DTC.U    -> H.span ! HA.class_ "underline" $$ html5ify ls
-                DTC.Note -> ""
-                DTC.Q ->
-                       H.span ! HA.class_ "q" $$ do
-                               "« "::Html5
-                               H.i $$ html5ify ls
-                               " »"
-                DTC.Eref{..} ->
-                       H.a ! HA.class_ "eref"
-                           ! HA.href (attrValue href) $$
-                               html5ify ls
-                DTC.Iref{..} ->
-                       H.span ! HA.class_ "iref"
-                              ! HA.id (attrValue Index.Ref{term, count, section=def}) $$
-                               html5ify ls
-                DTC.Ref{..} ->
-                       H.a ! HA.class_ "ref"
-                           ! HA.href ("#"<>attrValue to) $$
+                               html5AttrClass (cls item) $
+                               html5ify item
+        where
+               id_ = Just . Ident . Plain.text def . DTC.posAncestors
+               cls = \case
+                ParaPlain{}     -> []
+                ParaArtwork{..} -> ["artwork", "artwork-"<>type_]
+                ParaQuote{..}   -> ["quote", "quote-"<>type_]
+                ParaComment{}   -> []
+                ParaOL{}        -> ["ol"]
+                ParaUL{}        -> ["ul"]
+instance Html5ify ParaItem where
+       html5ify = \case
+        ParaPlain p -> H.p $$ html5ify p
+        ParaArtwork{..} -> H.pre $$ do html5ify text
+        ParaQuote{..} -> H.div $$ do html5ify paras
+        ParaComment t -> html5ify $ H.Comment (H.String $ TL.unpack t) ()
+        ParaOL items ->
+               H.table $$ do
+                       H.tbody $$
+                               forM_ items $ \ListItem{..} -> do
+                                       H.tr $$ do
+                                               H.td ! HA.class_ "name" $$ do
+                                                       html5ify name
+                                                       "."::Html5
+                                               H.td ! HA.class_ "value" $$
+                                                       html5ify paras
+        ParaUL items ->
+               H.dl $$ do
+                       forM_ items $ \item -> do
+                               H.dt $$ "—"
+                               H.dd $$ html5ify item
+instance Html5ify [Para] where
+       html5ify = mapM_ html5ify
+
+instance Html5ify Plain where
+       html5ify ps =
+               case Seq.viewl ps of
+                Seq.EmptyL -> mempty
+                curr Seq.:< next ->
+                       case curr of
+                       -- NOTE: gather adjacent PlainNotes
+                        Tree PlainNote{} _
+                         | (notes, rest) <- Seq.spanl (\case {Tree PlainNote{} _ -> True; _ -> False}) next -> do
+                               H.sup ! HA.class_ "note-numbers" $$ do
+                                       html5ify curr
+                                       forM_ notes $ \note -> do
+                                               ", "::Html5
+                                               html5ify note
+                               " "::Html5
+                               html5ify rest
+                       --
+                        _ -> do
+                               html5ify curr
+                               html5ify next
+instance Html5ify (Tree PlainNode)
+ where html5ify (Tree n ls) =
+       case n of
+        PlainBR     -> html5ify H.br
+        PlainText t -> html5ify t
+        PlainGroup  -> html5ify ls
+        PlainB      -> H.strong $$ html5ify ls
+        PlainCode   -> H.code   $$ html5ify ls
+        PlainDel    -> H.del    $$ html5ify ls
+        PlainI -> do
+               i <- liftStateMarkup $ do
+                       i <- S.gets $ Plain.state_italic . state_plainify
+                       S.modify $ \s ->
+                               s{state_plainify=
+                                       (state_plainify s){Plain.state_italic=
+                                               not i}}
+                       return i
+               H.em ! HA.class_ (if i then "even" else "odd") $$
+                       html5ify ls
+               liftStateMarkup $
+                       S.modify $ \s ->
+                               s{state_plainify=
+                                       (state_plainify s){Plain.state_italic=i}}
+        PlainSub  -> H.sub    $$ html5ify ls
+        PlainSup  -> H.sup    $$ html5ify ls
+        PlainSC   -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
+        PlainU    -> H.span ! HA.class_ "underline" $$ html5ify ls
+        PlainNote{..} ->
+               case number of
+                Nothing -> mempty
+                Just num ->
+                       H.a ! HA.class_ "note-ref"
+                           ! HA.id ("note-ref."<>attrify num)
+                           ! HA.href ("#note."<>attrify num) $$
+                               html5ify num
+        PlainQ -> do
+               depth <- liftStateMarkup $ do
+                       depth <- S.gets $ Plain.state_quote . state_plainify
+                       S.modify $ \s -> s{state_plainify=
+                               (state_plainify s){Plain.state_quote=
+                                       succNat depth}}
+                       return depth
+               H.span ! HA.class_ "q" $$ do
+                       html5ify $ Plain.L10n_QuoteOpen depth
+                       html5ify $ Tree PlainI ls
+                       html5ify $ Plain.L10n_QuoteClose depth
+               liftStateMarkup $
+                       S.modify $ \s ->
+                               s{state_plainify=
+                                       (state_plainify s){Plain.state_quote = depth}}
+        PlainEref{..} ->
+               H.a ! HA.class_ "eref"
+                   ! HA.href (attrify href) $$
                        if null ls
-                       then html5ify to
+                       then html5ify $ unURL href
                        else html5ify ls
-                DTC.Rref{..} ->
-                       H.a ! HA.class_ "rref"
-                           ! HA.href (attrValue to) $$
+        PlainIref{..} ->
+               case anchor of
+                Nothing -> html5ify ls
+                Just Anchor{..} ->
+                       H.span ! HA.class_ "iref"
+                              ! HA.id (attrifyIrefCount term count) $$
                                html5ify ls
-instance AttrValue Index.Ref where
-       attrValue Index.Ref{..} =
-               "iref" <> "." <> attrValue (Index.plainifyWords term) <>
-               if count > 0
-               then "." <> attrValue count
-               else ""
-instance Html5ify DTC.About where
-       html5ify DTC.About{..} =
-               forM_ titles $ \(DTC.Title title) ->
-                       html5ify $ Seq.singleton $ TreeN DTC.Q title
-instance Html5ify DTC.Reference where
-       html5ify DTC.Reference{id=id_, ..} =
+        PlainRef{..} ->
+               H.a ! HA.class_ "ref"
+                   ! HA.href ("#"<>attrify to) $$
+               if null ls
+               then html5ify to
+               else html5ify ls
+        PlainRref{..} -> do
+               refs <- liftStateMarkup $ S.gets state_references
+               case Map.lookup to refs of
+                Nothing -> do
+                       "["::Html5
+                       H.span ! HA.class_ "rref-broken" $$
+                               html5ify to
+                       "]"
+                Just About{..} -> do
+                       unless (null ls) $
+                               forM_ (List.take 1 titles) $ \(Title title) -> do
+                                       html5ify $ Tree PlainQ $
+                                               case url of
+                                                Nothing -> title
+                                                Just u -> pure $ Tree (PlainEref u) title
+                                       " "::Html5
+                       "["::Html5
+                       H.a ! HA.class_ "rref"
+                           ! HA.href ("#rref."<>attrify to)
+                           ! HA.id ("rref."<>attrify to<>maybe "" (\Anchor{..} -> "."<>attrify count) anchor) $$
+                               html5ify to
+                       "]"
+
+instance Html5ify [Title] where
+       html5ify =
+               html5ify . fold . List.intersperse sep . toList
+               where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
+instance Html5ify About where
+       html5ify About{..} =
+               html5CommasDot $ concat $
+                [ html5Titles titles
+                , html5ify <$> authors
+                , html5ify <$> maybeToList date
+                , html5ify <$> maybeToList editor
+                , html5ify <$> series
+                ]
+               where
+               html5Titles :: [Title] -> [Html5]
+               html5Titles ts | null ts = []
+               html5Titles ts = [html5Title $ joinTitles ts]
+                       where
+                       joinTitles = fold . List.intersperse sep . toList
+                       sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
+               html5Title (Title title) =
+                       html5ify $ Tree PlainQ $
+                               case url of
+                                Nothing -> title
+                                Just u -> pure $ Tree (PlainEref u) title
+instance Html5ify Serie where
+       html5ify s@Serie{id=id_, name} = do
+               case urlSerie s of
+                Nothing -> do
+                       html5ify name
+                       html5ify Plain.L10n_Colon
+                       html5ify id_
+                Just href -> do
+                       sp <- liftStateMarkup $ S.gets state_plainify
+                       html5ify $
+                               Tree PlainEref{href} $
+                               Seq.fromList
+                                [ tree0 $ PlainText $ name
+                                , tree0 $ PlainText $ Plain.text sp Plain.L10n_Colon
+                                , tree0 $ PlainText id_
+                                ]
+instance Html5ify Entity where
+       html5ify Entity{..} = do
+               html5ify $
+                       case () of
+                        _ | not (TL.null email) ->
+                               Tree (PlainEref $ URL $ "mailto:"<>email) $
+                                       pure $ tree0 $ PlainText name
+                        _ | Just u <- url ->
+                               Tree (PlainEref u) $
+                                       pure $ tree0 $ PlainText name
+                        _ -> tree0 $ PlainText name
+               forM_ org $ \o -> do
+                       " ("::Html5
+                       html5ify o
+                       ")"::Html5
+instance Html5ify Words where
+       html5ify = html5ify . Anchor.plainifyWords
+instance Html5ify Alias where
+       html5ify Alias{id=id_, ..} = do
+               H.a ! HA.class_ "alias"
+                   ! HA.id (attrify id_) $$
+                       mempty
+instance Html5ify URL where
+       html5ify (URL url) =
+               H.a ! HA.class_ "eref"
+                   ! HA.href (attrify url) $$
+                       html5ify url
+instance Html5ify Date where
+       html5ify = html5ify . Plain.L10n_Date
+instance Html5ify Reference where
+       html5ify Reference{id=id_, ..} =
                H.tr $$ do
                        H.td ! HA.class_ "reference-key" $$
-                               html5ify id_
-                       H.td ! HA.class_ "reference-content" $$
+                               html5ify $ Tree PlainRref{anchor=Nothing, to=id_} Seq.empty
+                       H.td ! HA.class_ "reference-content" $$ do
                                html5ify about
-
-html5CommonAttrs :: DTC.CommonAttrs -> Html5 -> Html5
-html5CommonAttrs DTC.CommonAttrs{id=id_, ..} =
-       Compose . (addClass . addId <$>) . getCompose
-       where
-       addClass =
-               case classes of
-                [] -> \x -> x
-                _  -> H.AddCustomAttribute "class" (H.Text $ Text.unwords classes)
-       addId =
-               case id_ of
-                Nothing -> \x -> x
-                Just (DTC.Ident i) ->
-                       H.AddCustomAttribute "id" (H.Text i)
-
-html5SectionNumber :: [(XmlName,Int)] -> Html5
-html5SectionNumber = go [] . List.reverse
-       where
-       go :: [(XmlName,Int)] -> [(XmlName,Int)] -> Html5
-       go _rs [] = pure ()
-       go rs (a@(_n,cnt):as) = do
-               H.a ! HA.href (attrValue $ "#"<>textXmlPosAncestors (a:rs)) $$
-                       html5ify $ show cnt
-               html5ify '.'
-               go (a:rs) as
-
-html5SectionRef :: [(XmlName,Int)] -> Html5
-html5SectionRef as =
-       H.a ! HA.href (attrValue $ "#"<>textXmlPosAncestors as) $$
-               case as of
+                               rrefs <- liftStateMarkup $ S.gets state_rrefs
+                               case Map.lookup id_ rrefs of
+                                Nothing -> pure ()
+                                Just anchs ->
+                                       H.span ! HA.class_ "reference-rrefs" $$
+                                               html5CommasDot $
+                                               (<$> List.reverse anchs) $ \Anchor{..} ->
+                                                       H.a ! HA.class_ "reference-rref"
+                                                           ! HA.href ("#rref."<>attrify id_<>"."<>attrify count) $$
+                                                               html5ify $ DTC.posAncestors section
+instance Html5ify PosPath where
+       html5ify ancs =
+               case toList ancs of
                 [(_n,c)] -> do
                        html5ify $ show c
                        html5ify '.'
-                _ ->
+                as ->
                        html5ify $
                                Text.intercalate "." $
                                Text.pack . show . snd <$> as
+instance Html5ify Plain.Plain where
+       html5ify p = do
+               sp <- liftStateMarkup $ S.gets state_plainify
+               let (t,sp') = Plain.runPlain p sp
+               html5ify t
+               liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
+
+html5CommasDot :: [Html5] -> Html5
+html5CommasDot [] = pure ()
+html5CommasDot hs = do
+       sequence_ $ List.intersperse ", " hs
+       "."
+
+html5AttrClass :: [TL.Text] -> Html5 -> Html5
+html5AttrClass = \case
+ [] -> Cat.id
+ cls  ->
+       Compose .
+       (H.AddCustomAttribute "class"
+        (H.String $ TL.unpack $ TL.unwords cls) <$>) .
+       getCompose
+
+html5AttrId :: Ident -> Html5 -> Html5
+html5AttrId (Ident id_) =
+       Compose .
+       (H.AddCustomAttribute "id"
+        (H.String $ TL.unpack id_) <$>) .
+       getCompose
 
-textXmlPosAncestors :: [(XmlName,Int)] -> Text
-textXmlPosAncestors =
-       snd . foldr (\(n,c) (nParent,acc) ->
-               (n,
-                       (if Text.null acc
-                               then acc
-                               else acc <> ".") <>
-                       Text.pack
-                        (if n == nParent
-                               then show c
-                               else show n<>show c)
-               )
-        )
-        ("","")
+html5CommonAttrs :: CommonAttrs -> Html5 -> Html5
+html5CommonAttrs CommonAttrs{id=id_, ..} =
+       html5AttrClass classes .
+       maybe Cat.id html5AttrId id_
 
--- * Class 'Plainify'
-class Plainify a where
-       plainify :: a -> TL.Text
-instance Plainify TL.Text where
-       plainify = id
-instance Plainify Text where
-       plainify = TL.fromStrict
-instance Plainify DTC.Lines where
-       plainify = foldMap $ \case
-        Tree0 v ->
-               case v of
-                DTC.BR -> "\n"
-                DTC.Plain p -> plainify p
-        TreeN k ls ->
-               case k of
-                DTC.B        -> "*"<>plainify ls<>"*"
-                DTC.Code     -> "`"<>plainify ls<>"`"
-                DTC.Del      -> "-"<>plainify ls<>"-"
-                DTC.I        -> "/"<>plainify ls<>"/"
-                DTC.Note     -> ""
-                DTC.Q        -> "« "<>plainify ls<>" »"
-                DTC.SC       -> plainify ls
-                DTC.Sub      -> plainify ls
-                DTC.Sup      -> plainify ls
-                DTC.U        -> "_"<>plainify ls<>"_"
-                DTC.Eref{..} -> plainify ls
-                DTC.Iref{..} -> plainify ls
-                DTC.Ref{..}  -> plainify ls
-                DTC.Rref{..} -> plainify ls
-instance Plainify DTC.Title where
-       plainify (DTC.Title t) = plainify t
+html5SectionNumber :: PosPath -> Html5
+html5SectionNumber = go mempty
+       where
+       go :: PosPath -> PosPath -> Html5
+       go prev next =
+               case Seq.viewl next of
+                Seq.EmptyL -> pure ()
+                a@(_n,rank) Seq.:< as -> do
+                       H.a ! HA.href ("#"<>attrify (prev Seq.|>a)) $$
+                               html5ify $ show rank
+                       when (not (null as) || null prev) $ do
+                               html5ify '.'
+                               go (prev Seq.|>a) as
+
+html5SectionRef :: PosPath -> Html5
+html5SectionRef as =
+       H.a ! HA.href ("#"<>attrify as) $$
+               html5ify as
 
-instance AttrValue XmlPos where
-       attrValue = attrValue . textXmlPosAncestors . xmlPosAncestors
+-- * 'Attrify'
+instance Attrify Anchor where
+       attrify Anchor{..} = attrify section <> "." <> attrify count
+instance Attrify Plain.Plain where
+       attrify p = attrify t
+               where (t,_) = Plain.runPlain p def
+instance Attrify PosPath where
+       attrify = attrify . plainify
+instance Attrify DTC.Pos where
+       attrify = attrify . DTC.posAncestors
 
--- * Type 'MsgHtml5'
-data MsgHtml5
- =   MsgHTML5_Table_of_Contents
+attrifyIref :: Words -> H.AttributeValue
+attrifyIref term =
+       "iref" <> "." <> attrify (Anchor.plainifyWords term)
+attrifyIrefCount :: Words -> Nat1 -> H.AttributeValue
+attrifyIrefCount term count =
+       "iref"
+        <> "." <> attrify (Anchor.plainifyWords term)
+        <> "." <> attrify count
+
+-- * Type 'L10n'
+data L10n
+ =   L10n_Header_Address
+ |   L10n_Header_Date
+ |   L10n_Header_Version
+ |   L10n_Header_Origin
+ |   L10n_Header_Source
  deriving (Show)
-instance Html5ify MsgHtml5 where
+instance Html5ify L10n where
        html5ify msg = do
-               loc <- liftStateMarkup $ S.gets localize
+               loc <- liftStateMarkup $ S.gets state_localize
                loc msg
-instance LocalizeIn FR Html5 MsgHtml5 where
+instance LocalizeIn EN Html5 L10n where
        localizeIn _ = \case
-        MsgHTML5_Table_of_Contents -> "Sommaire"
-instance LocalizeIn EN Html5 MsgHtml5 where
+        L10n_Header_Address -> "Address"
+        L10n_Header_Date    -> "Date"
+        L10n_Header_Origin  -> "Origin"
+        L10n_Header_Source  -> "Source"
+        L10n_Header_Version -> "Version"
+instance LocalizeIn FR Html5 L10n where
        localizeIn _ = \case
-        MsgHTML5_Table_of_Contents -> "Summary"
+        L10n_Header_Address -> "Adresse"
+        L10n_Header_Date    -> "Date"
+        L10n_Header_Origin  -> "Origine"
+        L10n_Header_Source  -> "Source"
+        L10n_Header_Version -> "Version"
+
+instance Html5ify Plain.L10n where
+       html5ify = html5ify . plainify
+instance Localize ls Plain.Plain Plain.L10n => Localize ls Html5 Plain.L10n where
+       localize loc a = html5ify (Locale.localize loc a::Plain.Plain)
+instance LocalizeIn FR Html5 Plain.L10n where
+       localizeIn loc = html5ify @Plain.Plain . localizeIn loc
+instance LocalizeIn EN Html5 Plain.L10n where
+       localizeIn loc = html5ify @Plain.Plain . localizeIn loc