1 {-# LANGUAGE DuplicateRecordFields #-}
2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE FlexibleContexts #-}
4 {-# LANGUAGE MultiParamTypeClasses #-}
5 {-# LANGUAGE OverloadedStrings #-}
6 {-# LANGUAGE ScopedTypeVariables #-}
7 {-# LANGUAGE TypeApplications #-}
8 {-# OPTIONS_GHC -fno-warn-orphans #-}
9 module Language.DTC.Write.HTML5 where
11 import Control.Applicative (Applicative(..))
12 import Control.Category as Cat
15 import Data.Char (Char)
16 import Data.Default.Class (Default(..))
17 import Data.Foldable (Foldable(..), concat)
18 import Data.Function (($), const, flip, on)
19 import Data.Functor (Functor(..), (<$>))
20 import Data.Functor.Compose (Compose(..))
22 import Data.Map.Strict (Map)
23 import Data.Maybe (Maybe(..), maybe, mapMaybe, fromJust, maybeToList)
24 import Data.Monoid (Monoid(..))
25 import Data.Ord (Ord(..))
26 import Data.Semigroup (Semigroup(..))
27 import Data.String (String, IsString(..))
28 import Data.Text (Text)
29 import Data.Traversable (Traversable(..))
30 import Data.TreeSeq.Strict (Tree(..), tree0)
31 import Data.Tuple (snd)
32 import Prelude (undefined)
33 import System.FilePath (FilePath)
34 import Text.Blaze ((!))
35 import Text.Blaze.Html (Html)
36 import Text.Show (Show(..))
37 import qualified Control.Monad.Trans.State as S
38 import qualified Data.Char as Char
39 import qualified Data.List as List
40 import qualified Data.Map.Strict as Map
41 import qualified Data.Sequence as Seq
42 import qualified Data.Strict.Maybe as Strict
43 import qualified Data.Text as Text
44 import qualified Data.Text.Lazy as TL
45 import qualified Data.TreeMap.Strict as TreeMap
46 import qualified Data.TreeSeq.Strict.Zipper as Tree
47 import qualified Text.Blaze.Html5 as H
48 import qualified Text.Blaze.Html5.Attributes as HA
49 import qualified Text.Blaze.Internal as H
51 import Text.Blaze.Utils
52 import Data.Locale hiding (Index)
53 import qualified Data.Locale as Locale
55 import Language.DTC.Document as DTC
56 import Language.DTC.Utils
57 import Language.DTC.Write.Plain (Plainify(..))
58 import Language.DTC.Write.XML ()
59 import qualified Language.DTC.Anchor as Anchor
60 import qualified Language.DTC.Write.Plain as Plain
63 Localize locales Plain.Plain Plain.L10n =>
64 Localize locales Html5 L10n =>
66 LocaleIn locales -> DTC.Document -> Html
67 document locale DTC.Document{..} = do
68 let titles = DTC.titles $ DTC.about (head :: Head)
69 let Keys{..} = keys body `S.execState` def
70 let (body',state_rrefs,state_notes,state_indexs) =
71 let irefs = foldMap Anchor.irefsOfTerms keys_index in
72 let (body0, Anchor.State{state_irefs, state_rrefs=rrefs, state_notes=notes}) =
73 Anchor.anchorify body `S.runState`
74 def{Anchor.state_irefs=irefs} in
75 (body0,rrefs,notes,) $
76 (<$> keys_index) $ \terms ->
78 TreeMap.intersection const state_irefs $
79 Anchor.irefsOfTerms terms
80 let state_plainify = def
81 { Plain.state_localize = Locale.localize locale }
82 let (html5Body, State{state_styles,state_scripts}) =
87 , state_figures = keys_figure
88 , state_references = keys_reference
90 , state_localize = Locale.localize locale
93 unless (null titles) $
94 H.div ! HA.class_ "title" $$ do
95 forM_ titles $ \title ->
96 H.h1 $$ html5ify title
100 H.html ! HA.lang (attrify $ countryCode locale) $ do
102 H.meta ! HA.httpEquiv "Content-Type"
103 ! HA.content "text/html; charset=UTF-8"
104 unless (null titles) $ do
106 H.toMarkup $ Plain.text state_plainify $ List.head titles
107 forM_ (DTC.links $ DTC.about (head :: Head)) $ \Link{rel, href} ->
108 H.link ! HA.rel (attrify rel)
109 ! HA.href (attrify href)
110 H.meta ! HA.name "generator"
111 ! HA.content "https://hackage.haskell.org/package/hdoc"
113 (`mapMaybe` toList body) $ \case
114 Tree k@BodySection{} _ -> Just k
116 forM_ chapters $ \case
118 H.link ! HA.rel "Chapter"
119 ! HA.title (attrify $ plainify title)
120 ! HA.href ("#"<>attrify pos)
122 H.link ! HA.rel "stylesheet"
123 ! HA.type_ "text/css"
124 ! HA.href "style/dtc-html5.css"
125 forM_ state_styles $ \style ->
126 H.style ! HA.type_ "text/css" $
128 forM_ state_scripts $ \script ->
129 H.script ! HA.type_ "application/javascript" $
134 html5Head :: Head -> Html5
135 html5Head Head{DTC.about=About{..}} = do
136 H.div ! HA.class_ "document-head" $$
140 H.td ! HA.class_ "left" $$ docHeaders
141 H.td ! HA.class_ "right" $$ docAuthors
145 H.td ! HA.class_ "full" $$
146 html5ify $ tree0 $ PlainEref{href}
149 H.table ! HA.class_ "document-headers" $$
151 forM_ series $ \s@Serie{id=id_, name} ->
155 headerName $ html5ify name
156 headerValue $ html5ify id_
158 headerName $ html5ify name
160 H.a ! HA.href (attrify href) $$
162 forM_ version $ \v ->
164 headerName $ html5ify L10n_Header_Version
165 headerValue $ html5ify v
168 headerName $ html5ify L10n_Header_Date
169 headerValue $ html5ify d
170 forM_ links $ \Link{..} ->
172 headerName $ html5ify name
174 H.a ! HA.href (attrify href) $$
177 H.table ! HA.class_ "document-authors" $$
179 forM_ authors $ \a ->
181 H.td ! HA.class_ "author" $$
183 header :: Html5 -> Html5
184 header h = H.tr ! HA.class_ "header" $$ h
185 headerName :: Html5 -> Html5
187 H.td ! HA.class_ "header-name" $$ do
189 html5ify Plain.L10n_Colon
190 headerValue :: Html5 -> Html5
192 H.td ! HA.class_ "header-value" $$ do
198 , authors :: [Entity]
199 , editor :: Maybe Entity
202 , keywords :: [TL.Text]
205 , includes :: [Include]
208 (<&>) :: Functor f => f a -> (a -> b) -> f b
213 type Html5 = StateMarkup State ()
214 instance IsString Html5 where
215 fromString = html5ify
220 { state_styles :: Map FilePath CSS
221 , state_scripts :: Map FilePath Script
222 , state_indexs :: Map DTC.Pos (Terms, Anchor.Irefs)
223 , state_rrefs :: Anchor.Rrefs
224 , state_figures :: Map TL.Text (Map DTC.Pos (Maybe Title))
225 , state_references :: Map Ident About
226 , state_notes :: Anchor.Notes
227 , state_plainify :: Plain.State
228 , state_localize :: L10n -> Html5
230 instance Default State where
233 , state_scripts = def
236 , state_figures = def
237 , state_references = def
239 , state_plainify = def
240 , state_localize = html5ify . show
248 { keys_index :: Map DTC.Pos Terms
249 , keys_figure :: Map TL.Text (Map DTC.Pos (Maybe Title))
250 , keys_reference :: Map Ident About
252 instance Default Keys where
253 def = Keys mempty mempty mempty
257 keys :: a -> S.State Keys ()
258 instance KeysOf Body where
260 instance KeysOf (Tree BodyNode) where
263 BodySection{..} -> keys ts
264 BodyBlock b -> keys b
265 instance KeysOf DTC.Block where
267 BlockPara{} -> return ()
268 BlockToC{} -> return ()
269 BlockToF{} -> return ()
271 S.modify $ \s -> s{keys_index=
272 Map.insert pos terms $ keys_index s}
274 S.modify $ \s -> s{keys_figure=
276 type_ (Map.singleton pos mayTitle) $
278 BlockReferences{..} ->
279 S.modify $ \s -> s{keys_reference=
282 (DTC.id (r::DTC.Reference))
283 (DTC.about (r::DTC.Reference)))
287 -- * Class 'Html5ify'
288 class Html5ify a where
289 html5ify :: a -> Html5
290 instance Html5ify H.Markup where
291 html5ify = Compose . return
292 instance Html5ify Char where
293 html5ify = html5ify . H.toMarkup
294 instance Html5ify Text where
295 html5ify = html5ify . H.toMarkup
296 instance Html5ify TL.Text where
297 html5ify = html5ify . H.toMarkup
298 instance Html5ify String where
299 html5ify = html5ify . H.toMarkup
300 instance Html5ify Title where
301 html5ify (Title t) = html5ify t
302 instance Html5ify Ident where
303 html5ify (Ident i) = html5ify i
304 instance Html5ify Int where
305 html5ify = html5ify . show
306 instance Html5ify Nat where
307 html5ify (Nat n) = html5ify n
308 instance Html5ify Nat1 where
309 html5ify (Nat1 n) = html5ify n
310 instance Html5ify a => Html5ify (Maybe a) where
311 html5ify = foldMap html5ify
313 -- * Type 'BodyCursor'
314 -- | Cursor to navigate within a 'Body' according to many axis (like in XSLT).
315 type BodyCursor = Tree.Zipper BodyNode
316 instance Html5ify Body where
318 forM_ (Tree.zippers body) $ \z ->
319 forM_ (Tree.axis_repeat Tree.axis_following_sibling_nearest `Tree.runAxis` z) $
321 instance Html5ify BodyCursor
323 let Tree n _ts = Tree.current z in
325 BodyBlock BlockToC{..} -> do
326 H.nav ! HA.class_ "toc"
327 ! HA.id (attrify pos) $$ do
328 H.span ! HA.class_ "toc-name" $$
329 H.a ! HA.href (attrify pos) $$
330 html5ify Plain.L10n_Table_of_Contents
332 forM_ (Tree.axis_following_sibling `Tree.runAxis` z) $
334 BodyBlock b -> html5ify b
335 BodySection{..} -> do
337 notes <- liftStateMarkup $ S.gets state_notes
339 p <- posParent $ posAncestors pos
340 let (ns, as) = Map.updateLookupWithKey (\_ _ -> Nothing) p notes
344 Just (secNotes, state_notes) -> do
345 liftStateMarkup $ S.modify' $ \s -> s{state_notes}
347 H.section ! HA.class_ "section"
348 ! HA.id (attrify pos) $$ do
349 forM_ aliases html5ify
350 html5CommonAttrs attrs{classes="section-header":classes attrs} $
354 H.td ! HA.class_ "section-number" $$ do
355 html5SectionNumber $ DTC.posAncestors pos
356 H.td ! HA.class_ "section-title" $$ do
357 (case List.length $ DTC.posAncestors pos of
366 forM_ (Tree.axis_child `Tree.runAxis` z) $
368 notes <- liftStateMarkup $ S.gets state_notes
369 html5ify $ Map.lookup (posAncestors pos) notes
370 instance Html5ify [Anchor.Note] where
372 H.aside ! HA.class_ "notes" $$ do
376 forM_ (List.reverse notes) $ \Anchor.Note{..} ->
378 H.td ! HA.class_ "note-ref" $$ do
379 H.a ! HA.class_ "note-number"
380 ! HA.id ("note."<>attrify note_number)
381 ! HA.href ("#note."<>attrify note_number) $$ do
384 H.a ! HA.href ("#note-ref."<>attrify note_number) $$ do
387 html5ify note_content
388 instance Html5ify Block where
390 BlockPara para -> html5ify para
391 BlockToC{..} -> mempty -- NOTE: done in Html5ify BodyCursor
393 H.nav ! HA.class_ "tof"
394 ! HA.id (attrify pos) $$
395 H.table ! HA.class_ "tof" $$
399 html5CommonAttrs attrs
400 { classes = "figure":("figure-"<>type_):classes attrs
401 , DTC.id = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
404 H.table ! HA.class_ "figure-caption" $$
408 then H.a ! HA.href ("#"<>attrify pos) $$ mempty
410 H.td ! HA.class_ "figure-number" $$ do
411 H.a ! HA.href ("#"<>attrify pos) $$ do
413 html5ify $ DTC.posAncestors pos
414 forM_ mayTitle $ \title ->
415 H.td ! HA.class_ "figure-title" $$ do
416 unless (TL.null type_) $
417 html5ify $ Plain.L10n_Colon
419 H.div ! HA.class_ "figure-content" $$ do
421 BlockIndex{pos} -> do
422 (allTerms,refsByTerm) <- liftStateMarkup $ S.gets $ (Map.! pos) . state_indexs
423 let chars = Anchor.termsByChar allTerms
424 H.div ! HA.class_ "index"
425 ! HA.id (attrify pos) $$ do
426 H.nav ! HA.class_ "index-nav" $$ do
427 forM_ (Map.keys chars) $ \char ->
428 H.a ! HA.href ("#"<>(attrify pos <> "." <> attrify char)) $$
430 H.dl ! HA.class_ "index-chars" $$
431 forM_ (Map.toList chars) $ \(char,terms) -> do
433 let i = attrify pos <> "." <> attrify char in
435 ! HA.href ("#"<>i) $$
438 H.dl ! HA.class_ "index-term" $$ do
439 forM_ terms $ \aliases -> do
441 H.ul ! HA.class_ "index-aliases" $$
442 forM_ (List.take 1 aliases) $ \term ->
443 H.li ! HA.id (attrifyIref term) $$
447 List.sortBy (compare `on` DTC.section . snd) $
448 (`foldMap` aliases) $ \words ->
450 path <- Anchor.pathFromWords words
451 Strict.maybe Nothing (Just . ((words,) <$>) . List.reverse) $
452 TreeMap.lookup path refsByTerm in
454 (<$> anchs) $ \(term,DTC.Anchor{..}) ->
455 H.a ! HA.class_ "index-iref"
456 ! HA.href ("#"<>attrifyIrefCount term count) $$
457 html5ify $ DTC.posAncestors section
458 BlockReferences{..} ->
459 html5CommonAttrs attrs
460 { classes = "references":classes attrs
461 , DTC.id = Just $ Ident $ Plain.text def $ DTC.posAncestors pos
467 html5ifyToC :: Maybe DTC.Nat -> BodyCursor -> Html5
468 html5ifyToC depth z =
469 let Tree n _ts = Tree.current z in
471 BodySection{..} -> do
473 H.table ! HA.class_ "toc-entry" $$
476 H.td ! HA.class_ "section-number" $$
477 html5SectionRef $ DTC.posAncestors pos
478 H.td ! HA.class_ "section-title" $$
479 html5ify $ cleanPlain $ unTitle title
480 when (maybe True (> Nat 1) depth && not (null sections)) $
483 html5ifyToC (depth >>= predNat)
489 `Tree.axis_filter_current` \case
490 Tree BodySection{} _ -> True
493 html5ifyToF :: [TL.Text] -> Html5
494 html5ifyToF types = do
495 figsByType <- liftStateMarkup $ S.gets state_figures
497 Map.foldMapWithKey (\ty -> ((ty,) <$>)) $
501 Map.intersection figsByType $
502 Map.fromList [(ty,()) | ty <- types]
503 forM_ (Map.toList figs) $ \(pos, (type_, title)) ->
505 H.td ! HA.class_ "figure-number" $$
506 H.a ! HA.href ("#"<>attrify pos) $$ do
508 html5ify $ DTC.posAncestors pos
510 H.td ! HA.class_ "figure-title" $$
511 html5ify $ cleanPlain $ unTitle ti
513 cleanPlain :: Plain -> Plain
516 Tree PlainIref{} ls -> cleanPlain ls
517 Tree PlainNote{} _ -> mempty
518 Tree n ts -> pure $ Tree n $ cleanPlain ts
520 instance Html5ify Para where
524 { classes="para":cls item
528 html5CommonAttrs attrs
529 { classes = "para":classes attrs
533 forM_ items $ \item ->
534 html5AttrClass (cls item) $
537 id_ = Just . Ident . Plain.text def . DTC.posAncestors
540 ParaArtwork{..} -> ["artwork", "artwork-"<>type_]
541 ParaQuote{..} -> ["quote", "quote-"<>type_]
545 instance Html5ify ParaItem where
547 ParaPlain p -> H.p $$ html5ify p
548 ParaArtwork{..} -> H.pre $$ do html5ify text
549 ParaQuote{..} -> H.div $$ do html5ify paras
550 ParaComment t -> html5ify $ H.Comment (H.String $ TL.unpack t) ()
554 forM_ items $ \ListItem{..} -> do
556 H.td ! HA.class_ "name" $$ do
559 H.td ! HA.class_ "value" $$
563 forM_ items $ \item -> do
565 H.dd $$ html5ify item
566 instance Html5ify [Para] where
567 html5ify = mapM_ html5ify
569 instance Html5ify Plain where
575 -- NOTE: gather adjacent PlainNotes
577 | (notes, rest) <- Seq.spanl (\case {Tree PlainNote{} _ -> True; _ -> False}) next -> do
578 H.sup ! HA.class_ "note-numbers" $$ do
580 forM_ notes $ \note -> do
589 instance Html5ify (Tree PlainNode)
590 where html5ify (Tree n ls) =
592 PlainBR -> html5ify H.br
593 PlainText t -> html5ify t
594 PlainGroup -> html5ify ls
595 PlainB -> H.strong $$ html5ify ls
596 PlainCode -> H.code $$ html5ify ls
597 PlainDel -> H.del $$ html5ify ls
599 i <- liftStateMarkup $ do
600 i <- S.gets $ Plain.state_italic . state_plainify
603 (state_plainify s){Plain.state_italic=
606 H.em ! HA.class_ (if i then "even" else "odd") $$
611 (state_plainify s){Plain.state_italic=i}}
612 PlainSub -> H.sub $$ html5ify ls
613 PlainSup -> H.sup $$ html5ify ls
614 PlainSC -> H.span ! HA.class_ "smallcaps" $$ html5ify ls
615 PlainU -> H.span ! HA.class_ "underline" $$ html5ify ls
620 H.a ! HA.class_ "note-ref"
621 ! HA.id ("note-ref."<>attrify num)
622 ! HA.href ("#note."<>attrify num) $$
625 depth <- liftStateMarkup $ do
626 depth <- S.gets $ Plain.state_quote . state_plainify
627 S.modify $ \s -> s{state_plainify=
628 (state_plainify s){Plain.state_quote=
631 H.span ! HA.class_ "q" $$ do
632 html5ify $ Plain.L10n_QuoteOpen depth
633 html5ify $ Tree PlainI ls
634 html5ify $ Plain.L10n_QuoteClose depth
638 (state_plainify s){Plain.state_quote = depth}}
640 H.a ! HA.class_ "eref"
641 ! HA.href (attrify href) $$
643 then html5ify $ unURL href
647 Nothing -> html5ify ls
649 H.span ! HA.class_ "iref"
650 ! HA.id (attrifyIrefCount term count) $$
653 H.a ! HA.class_ "ref"
654 ! HA.href ("#"<>attrify to) $$
659 refs <- liftStateMarkup $ S.gets state_references
660 case Map.lookup to refs of
663 H.span ! HA.class_ "rref-broken" $$
668 forM_ (List.take 1 titles) $ \(Title title) -> do
669 html5ify $ Tree PlainQ $
672 Just u -> pure $ Tree (PlainEref u) title
675 H.a ! HA.class_ "rref"
676 ! HA.href ("#rref."<>attrify to)
677 ! HA.id ("rref."<>attrify to<>maybe "" (\Anchor{..} -> "."<>attrify count) anchor) $$
681 instance Html5ify [Title] where
683 html5ify . fold . List.intersperse sep . toList
684 where sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
685 instance Html5ify About where
687 html5CommasDot $ concat $
689 , html5ify <$> authors
690 , html5ify <$> maybeToList date
691 , html5ify <$> maybeToList editor
692 , html5ify <$> series
695 html5Titles :: [Title] -> [Html5]
696 html5Titles ts | null ts = []
697 html5Titles ts = [html5Title $ joinTitles ts]
699 joinTitles = fold . List.intersperse sep . toList
700 sep = Title $ Seq.singleton $ tree0 $ PlainText " — "
701 html5Title (Title title) =
702 html5ify $ Tree PlainQ $
705 Just u -> pure $ Tree (PlainEref u) title
706 instance Html5ify Serie where
707 html5ify s@Serie{id=id_, name} = do
711 html5ify Plain.L10n_Colon
714 sp <- liftStateMarkup $ S.gets state_plainify
716 Tree PlainEref{href} $
718 [ tree0 $ PlainText $ name
719 , tree0 $ PlainText $ Plain.text sp Plain.L10n_Colon
720 , tree0 $ PlainText id_
722 instance Html5ify Entity where
723 html5ify Entity{..} = do
726 _ | not (TL.null email) ->
727 Tree (PlainEref $ URL $ "mailto:"<>email) $
728 pure $ tree0 $ PlainText name
731 pure $ tree0 $ PlainText name
732 _ -> tree0 $ PlainText name
737 instance Html5ify Words where
738 html5ify = html5ify . Anchor.plainifyWords
739 instance Html5ify Alias where
740 html5ify Alias{id=id_, ..} = do
741 H.a ! HA.class_ "alias"
742 ! HA.id (attrify id_) $$
744 instance Html5ify URL where
746 H.a ! HA.class_ "eref"
747 ! HA.href (attrify url) $$
749 instance Html5ify Date where
750 html5ify = html5ify . Plain.L10n_Date
751 instance Html5ify Reference where
752 html5ify Reference{id=id_, ..} =
754 H.td ! HA.class_ "reference-key" $$
755 html5ify $ Tree PlainRref{anchor=Nothing, to=id_} Seq.empty
756 H.td ! HA.class_ "reference-content" $$ do
758 rrefs <- liftStateMarkup $ S.gets state_rrefs
759 case Map.lookup id_ rrefs of
762 H.span ! HA.class_ "reference-rrefs" $$
764 (<$> List.reverse anchs) $ \Anchor{..} ->
765 H.a ! HA.class_ "reference-rref"
766 ! HA.href ("#rref."<>attrify id_<>"."<>attrify count) $$
767 html5ify $ DTC.posAncestors section
768 instance Html5ify PosPath where
776 Text.intercalate "." $
777 Text.pack . show . snd <$> as
778 instance Html5ify Plain.Plain where
780 sp <- liftStateMarkup $ S.gets state_plainify
781 let (t,sp') = Plain.runPlain p sp
783 liftStateMarkup $ S.modify $ \s -> s{state_plainify=sp'}
785 html5CommasDot :: [Html5] -> Html5
786 html5CommasDot [] = pure ()
787 html5CommasDot hs = do
788 sequence_ $ List.intersperse ", " hs
791 html5AttrClass :: [TL.Text] -> Html5 -> Html5
792 html5AttrClass = \case
796 (H.AddCustomAttribute "class"
797 (H.String $ TL.unpack $ TL.unwords cls) <$>) .
800 html5AttrId :: Ident -> Html5 -> Html5
801 html5AttrId (Ident id_) =
803 (H.AddCustomAttribute "id"
804 (H.String $ TL.unpack id_) <$>) .
807 html5CommonAttrs :: CommonAttrs -> Html5 -> Html5
808 html5CommonAttrs CommonAttrs{id=id_, ..} =
809 html5AttrClass classes .
810 maybe Cat.id html5AttrId id_
812 html5SectionNumber :: PosPath -> Html5
813 html5SectionNumber = go mempty
815 go :: PosPath -> PosPath -> Html5
817 case Seq.viewl next of
818 Seq.EmptyL -> pure ()
819 a@(_n,rank) Seq.:< as -> do
820 H.a ! HA.href ("#"<>attrify (prev Seq.|>a)) $$
822 when (not (null as) || null prev) $ do
826 html5SectionRef :: PosPath -> Html5
828 H.a ! HA.href ("#"<>attrify as) $$
832 instance Attrify Anchor where
833 attrify Anchor{..} = attrify section <> "." <> attrify count
834 instance Attrify Plain.Plain where
835 attrify p = attrify t
836 where (t,_) = Plain.runPlain p def
837 instance Attrify PosPath where
838 attrify = attrify . plainify
839 instance Attrify DTC.Pos where
840 attrify = attrify . DTC.posAncestors
842 attrifyIref :: Words -> H.AttributeValue
844 "iref" <> "." <> attrify (Anchor.plainifyWords term)
845 attrifyIrefCount :: Words -> Nat1 -> H.AttributeValue
846 attrifyIrefCount term count =
848 <> "." <> attrify (Anchor.plainifyWords term)
849 <> "." <> attrify count
854 | L10n_Header_Version
856 instance Html5ify L10n where
858 loc <- liftStateMarkup $ S.gets state_localize
860 instance LocalizeIn EN Html5 L10n where
862 L10n_Header_Date -> "Date"
863 L10n_Header_Version -> "Version"
864 instance LocalizeIn FR Html5 L10n where
866 L10n_Header_Date -> "Date"
867 L10n_Header_Version -> "Version"
869 instance Html5ify Plain.L10n where
870 html5ify = html5ify . plainify
871 instance Localize ls Plain.Plain Plain.L10n => Localize ls Html5 Plain.L10n where
872 localize loc a = html5ify (Locale.localize loc a::Plain.Plain)
873 instance LocalizeIn FR Html5 Plain.L10n where
874 localizeIn loc = html5ify @Plain.Plain . localizeIn loc
875 instance LocalizeIn EN Html5 Plain.L10n where
876 localizeIn loc = html5ify @Plain.Plain . localizeIn loc