module Rakka.Page
( PageName
, Page(..)
+ , LanguageTag
+ , LanguageName
+
, encodePageName
, decodePageName
, mkPageURI
import qualified Data.ByteString.Char8 as C8
import Data.Encoding
import Data.Encoding.UTF8
+import Data.Map (Map)
import Network.HTTP.Lucu
import Network.URI
import Subversion.Types
type PageName = String
+type LanguageTag = String -- See RFC 3066: http://www.ietf.org/rfc/rfc3066.txt
+type LanguageName = String -- i.e. "日本語"
+
data Page
= Redirection {
| Entity {
pageName :: !PageName
, pageType :: !MIMEType
+ , pageLanguage :: !(Maybe LanguageTag)
, pageIsTheme :: !Bool -- text/css 以外では無意味
, pageIsFeed :: !Bool -- text/x-rakka 以外では無意味
, pageIsLocked :: !Bool
, pageRevision :: !(Maybe RevNum)
, pageLastMod :: !CalendarTime
, pageSummary :: !(Maybe String)
- , pageOtherLang :: ![(String, PageName)]
+ , pageOtherLang :: !(Map LanguageTag PageName)
, pageContent :: !LazyByteString
}
Just redir@(Redirection _ _ _ _)
-> handleRedirect env redir
- Just entity@(Entity _ _ _ _ _ _ _ _ _ _ _ _)
+ Just entity@(Entity _ _ _ _ _ _ _ _ _ _ _ _ _)
-> handleGetEntity env entity
import Control.Arrow
import Control.Arrow.ArrowIO
+import Control.Arrow.ArrowIf
import Control.Arrow.ArrowList
import Data.Char
+import qualified Data.Map as M
import Network.HTTP.Lucu
import Network.HTTP.Lucu.Utils
import Network.URI
Just redir@(Redirection _ _ _ _)
-> handleRedirect env -< redir
- Just entity@(Entity _ _ _ _ _ _ _ _ _ _ _ _)
+ Just entity@(Entity _ _ _ _ _ _ _ _ _ _ _ _ _)
-> handleGetEntity env -< entity
{-
styleSheet="http://example.org/object/StyleSheet/Default"
name="Foo/Bar"
type="text/x-rakka"
+ lang="ja" -- 存在しない場合もある
isTheme="no" -- text/css の場合のみ存在
isFeed="no" -- text/x-rakka の場合のみ存在
isLocked="no"
+= sattr "styleSheet" (uriToString id (mkObjectURI baseURI cssName) "")
+= sattr "name" (pageName page)
+= sattr "type" (show $ pageType page)
+ += ( case pageLanguage page of
+ Just x -> sattr "lang" x
+ _ -> none
+ )
+= ( case pageType page of
MIMEType "text" "css" _
-> sattr "isTheme" (yesOrNo $ pageIsTheme page)
Just s -> eelem "summary" += txt s
)
- += ( case pageOtherLang page of
- [] -> none
- xs -> selem "otherLang"
- [ eelem "link"
- += sattr "lang" lang
- += sattr "page" page
- | (lang, page) <- xs ]
+ += ( if M.null (pageOtherLang page) then
+ none
+ else
+ selem "otherLang"
+ [ eelem "link"
+ += sattr "lang" lang
+ += sattr "page" page
+ | (lang, page) <- M.toList (pageOtherLang page) ]
)
+= ( eelem "pageTitle"
+= ( (constA (pageName page) &&& constA (Just page) &&& constA pageTitle)
= eelem "/"
+= ( eelem "html"
+= sattr "xmlns" "http://www.w3.org/1999/xhtml"
+ += ( getXPathTreesInDoc "/page/@lang"
+ `guards`
+ qattr (QN "xml" "lang" "")
+ ( getXPathTreesInDoc "/page/@lang/text()" )
+ )
+= ( eelem "head"
+= ( eelem "title"
+= getXPathTreesInDoc "/page/@site/text()"
import qualified Data.ByteString.Lazy as L
import Data.Encoding
import Data.Encoding.UTF8
+import qualified Data.Map as M
import Paths_Rakka -- Cabal が用意する。
import Rakka.Page
import Rakka.Utils
-> do mimeType <- (getXPathTreesInDoc "/page/@type/text()" >>> getText
>>> arr read) -< tree
+ lang <- maybeA (getXPathTreesInDoc "/page/@lang/text()" >>> getText) -< tree
+
isTheme <- (withDefault (getXPathTreesInDoc "/page/@isTheme/text()" >>> getText) "no"
>>> parseYesOrNo) -< tree
isFeed <- (withDefault (getXPathTreesInDoc "/page/@isFeed/text()" >>> getText) "no"
returnA -< Entity {
pageName = name
, pageType = mimeType
+ , pageLanguage = lang
, pageIsTheme = isTheme
, pageIsFeed = isFeed
, pageIsLocked = isLocked
, pageRevision = Nothing
, pageLastMod = lastMod
, pageSummary = summary
- , pageOtherLang = otherLang
+ , pageOtherLang = M.fromList otherLang
, pageContent = content
}
\ No newline at end of file
import GHC.Conc (unsafeIOToSTM)
import Network
import qualified Network.HTTP.Lucu.Config as LC
+import Network.HTTP.Lucu.Utils
import Network.URI
+import Rakka.Page
import Rakka.Utils
import Subversion.FileSystem
import Subversion.FileSystem.Revision
| BaseURI URI
| DefaultPage String
| StyleSheet String
+ | Languages (Map LanguageTag LanguageName)
deriving (Eq, Show)
fromConfPath = combine "/config"
+marshalStringPairs :: [(String, String)] -> String
+marshalStringPairs = joinWith "\n" . map marshalPair'
+ where
+ marshalPair' :: (String, String) -> String
+ marshalPair' (a, b) = a ++ " " ++ b
+
+
+unmarshalStringPairs :: String -> [(String, String)]
+unmarshalStringPairs = catMaybes . map unmarshalPair' . lines
+ where
+ unmarshalPair' :: String -> Maybe (String, String)
+ unmarshalPair' s = case break (/= ' ') s of
+ (a, ' ':b) -> Just (a, b)
+ _ -> Nothing
+
+
{- paths -}
sysConfPath :: SysConfValue -> FilePath
sysConfPath (SiteName _) = "siteName"
sysConfPath (BaseURI _) = "baseURI"
sysConfPath (DefaultPage _) = "defaultPage"
sysConfPath (StyleSheet _) = "styleSheet"
+sysConfPath (Languages _) = "languages"
{- marshalling -}
marshalSysConf :: SysConfValue -> String
-marshalSysConf (SiteName name) = name
-marshalSysConf (BaseURI uri ) = uriToString id uri ""
-marshalSysConf (DefaultPage name) = name
-marshalSysConf (StyleSheet name) = name
+marshalSysConf (SiteName name ) = name
+marshalSysConf (BaseURI uri ) = uriToString id uri ""
+marshalSysConf (DefaultPage name ) = name
+marshalSysConf (StyleSheet name ) = name
+marshalSysConf (Languages langs) = marshalStringPairs (M.toList langs)
{- unmarshalling -}
unmarshalSysConf :: SysConfValue -> String -> SysConfValue
-unmarshalSysConf (SiteName _) name = SiteName name
-unmarshalSysConf (BaseURI _) uri = BaseURI $ fromJust $ parseURI uri
-unmarshalSysConf (DefaultPage _) name = DefaultPage name
-unmarshalSysConf (StyleSheet _) name = StyleSheet name
+unmarshalSysConf (SiteName _) name = SiteName name
+unmarshalSysConf (BaseURI _) uri = BaseURI $ fromJust $ parseURI uri
+unmarshalSysConf (DefaultPage _) name = DefaultPage name
+unmarshalSysConf (StyleSheet _) name = StyleSheet name
+unmarshalSysConf (Languages _) langs = Languages $ M.fromList $ unmarshalStringPairs langs
{- getting default value -}
sysConfDefault _ (StyleSheet _)
= return $ StyleSheet "StyleSheet/Default"
+
+sysConfDefault _ (Languages _)
+ = return
+ $ Languages
+ $ M.fromList [ ("en", "English" )
+ , ("es", "Español" )
+ , ("de", "Deutsch" )
+ , ("fi", "Suomi" )
+ , ("fr", "Français" )
+ , ("ga", "Gaeilge" )
+ , ("gd", "Gàidhlig" )
+ , ("ja", "日本語" )
+ , ("pt", "Português")
+ , ("sv", "Svenska" )
+ ]
+
= proc page
-> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< ()
wiki <- wikifyPage env -< page
- xs <- interpretCommandsA env -< (pageName page, (Just wiki, wiki))
+ xs <- interpretCommandsA env -< (pageName page, (Just (page, wiki), wiki))
formatWikiBlocks -< (baseURI, xs)
mainWiki <- case mainPage of
Just page
-> do wiki <- wikifyPage env -< page
- returnA -< Just wiki
+ returnA -< Just (page, wiki)
Nothing
-> returnA -< Nothing
subWiki <- wikifyPage env -< subPage
interpretCommandsA :: ArrowIO a =>
Environment
- -> a (PageName, (Maybe WikiPage, WikiPage)) WikiPage
+ -> a (PageName, (Maybe (Page, WikiPage), WikiPage)) WikiPage
interpretCommandsA = arrIO3 . interpretCommands
-interpretCommands :: Environment -> PageName -> Maybe WikiPage -> WikiPage -> IO WikiPage
+interpretCommands :: Environment -> PageName -> Maybe (Page, WikiPage) -> WikiPage -> IO WikiPage
interpretCommands _ _ _ [] = return []
-interpretCommands env name mainTree targetTree
+interpretCommands env name mainPageAndTree targetTree
= everywhereM' (mkM interpBlockCmd) targetTree
>>=
everywhereM' (mkM interpInlineCmd)
ctx :: InterpreterContext
ctx = InterpreterContext {
ctxPageName = name
- , ctxMainTree = mainTree
+ , ctxMainPage = fmap fst mainPageAndTree
+ , ctxMainTree = fmap snd mainPageAndTree
, ctxTargetTree = targetTree
, ctxStorage = envStorage env
, ctxSysConf = envSysConf env
data InterpreterContext
= InterpreterContext {
ctxPageName :: !PageName
+ , ctxMainPage :: !(Maybe Page)
, ctxMainTree :: !(Maybe WikiPage)
, ctxTargetTree :: !WikiPage
, ctxStorage :: !Storage
)
where
+import Data.Map (Map)
+import qualified Data.Map as M
+import Rakka.Page
+import Rakka.SystemConfig
import Rakka.Wiki
import Rakka.Wiki.Interpreter
, spanInterp
, divInterp
, pageNameInterp
+-- , otherLangsInterp
]
, iciInterpret
= \ ctx _ -> return $ Text (ctxPageName ctx)
}
+
+{-
+otherLangsInterp :: Interpreter
+otherLangsInterp
+ = BlockCommandInterpreter {
+ bciName = "inOtherLanguages"
+ , bciInterpret
+ = \ ctx _ ->
+ case fmap pageOtherLang (ctxMainPage ctx) of
+ Nothing
+ -> return EmptyBlock
+
+ Just linkTable
+ -> do Languages langTable <- getSysConf (ctxSysConf ctx) (Languages undefined)
+ let merged = mergeTables langTable (M.toList linkTable)
+ -- FIXME
+ }
+ where
+ mergeTables :: Map LanguageTag LanguageName
+ -> [(LanguageTag, PageName)]
+ -> [(LanguageName, PageName)]
+ mergeTables _ [] = []
+ mergeTables m (x:xs) = fromMaybe x (M.lookup x m) : mergeTables m xs
+-}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns="http://cielonegro.org/schema/Rakka/Page/1.0"
type="text/x-rakka"
- isBoring="yes">
+ isBoring="yes"
+ lang="en">
<textData><![CDATA[= Syntax Help =
== Heading ==
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns="http://cielonegro.org/schema/Rakka/Page/1.0"
type="text/x-rakka"
- isBoring="yes">
+ isBoring="yes"
+ lang="en">
+
+ <otherLang>
+ <link lang="ja" page="メインページ" />
+ </otherLang>
+
<textData><![CDATA[
= Main Page =
This is the main page.
= RSS feeds =
= In other languages =
+<inOtherLanguages />
= Recent updates =
<text />
</attribute>
+ <optional>
+ <attribute name="lang">
+ <text />
+ </attribute>
+ </optional>
+
<optional>
<!-- text/css でなければ無視される -->
<attribute name="isTheme">