reflex-localize-dom (empty) → 1.0.0.0
raw patch · 8 files changed
+347/−0 lines, 8 filesdep +basedep +containersdep +raw-strings-qq
Dependencies added: base, containers, raw-strings-qq, reflex, reflex-dom, reflex-localize, reflex-localize-dom, text
Files
- CHANGELOG.md +3/−0
- LICENSE +7/−0
- README.md +81/−0
- example/App/Language.hs +21/−0
- example/App/Localization.hs +19/−0
- example/Main.hs +47/−0
- reflex-localize-dom.cabal +108/−0
- src/Reflex/Localize/Dom.hs +61/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+# 1.0.0.0++* Initial release
+ LICENSE view
@@ -0,0 +1,7 @@+Copyright 2019 ATUM SOLUTIONS AG++Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,81 @@+# reflex-localize-dom++Dom extensions for [reflex-localize](../reflex-localize/README.md). Library+provides helpers for dynamic strings that depends on current selected language.++# How to use++Build example with `cabal new-build -f examples`.++First, you should define which languages your app supports:+``` haskell+module App.Language(+ Language(..)+ , module Reflex.Localize+ ) where++import Reflex.Localize+import Reflex.Localize.Language++data instance Language+ = English+ | Russian+```++Second, define enumeration for strings ids.++``` haskell+module App.Localization(+ module App.Localization+ , module App.Language+ ) where++import App.Language++data AboutPageStrings =+ AboutTitle+ | AboutVersion+ | AboutLicence+ | AboutHomepage+ | AboutDevelopers++instance LocalizedPrint AboutPageStrings where+ localizedShow l v = case l of+ English -> case v of+ AboutTitle -> "About"+ AboutVersion -> "Version"+ AboutLicence -> "Licence"+ AboutHomepage -> "Homepage"+ AboutDevelopers -> "Developers"+ Russian -> case v of+ AboutTitle -> "О продукте"+ AboutVersion -> "Версия"+ AboutLicence -> "Лицензия"+ AboutHomepage -> "Сайт"+ AboutDevelopers -> "Разработчики"+```++You can either collect all strings to one data sum or split strings for each+widget.++And finally you should implement `MonadLocalized` type class in you application monad.+We suggest using monad transformer `LocalizeT` via `runLocalize` function:++``` haskell+runLocalize :: (Reflex t, TriggerEvent t m, MonadIO m) => Language -> LocalizeT t m a -> m a+```++Finally, you can define widgets with localization like following:+``` haskell+buttonClass :: (DomBuilder t m, PostBuild t m, MonadLocalized t m, LocalizedPrint lbl)+ => Dynamic t Text -> lbl -> m (Event t ())+buttonClass classValD lbl = mkButton "button" [("onclick", "return false;")] classValD . dynText =<< localized lbl++mkButton :: (DomBuilder t m, PostBuild t m) => Text -> Map Text Text -> Dynamic t Text -> m a -> m (Event t a)+mkButton eltp attrs classValD ma = do+ let classesD = do+ classVal <- classValD+ pure $ attrs <> [("class", classVal)]+ (e, a) <- elDynAttr' eltp classesD ma+ return $ a <$ domEvent Click e+```
+ example/App/Language.hs view
@@ -0,0 +1,21 @@+module App.Language(+ Language(..)+ , module Reflex.Localize+ ) where++import Reflex.Localize+import Reflex.Localize.Language++data instance Language+ = English+ | Russian+ deriving (Eq, Ord, Enum, Bounded)++instance LocalizedPrint Language where+ localizedShow l v = case l of+ English -> case v of+ English -> "English"+ Russian -> "Russian"+ Russian -> case v of+ English -> "Английский"+ Russian -> "Русский"
+ example/App/Localization.hs view
@@ -0,0 +1,19 @@+module App.Localization(+ module App.Localization+ , module App.Language+ ) where++import App.Language++data AppStrings =+ ButtonLabel+ | PressedLabel++instance LocalizedPrint AppStrings where+ localizedShow l v = case l of+ English -> case v of+ ButtonLabel -> "Button"+ PressedLabel -> "Button is pressed!"+ Russian -> case v of+ ButtonLabel -> "Кнопка"+ PressedLabel -> "Кнопка нажата!"
+ example/Main.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE QuasiQuotes #-}+module Main where++import App.Localization+import Data.Map.Strict (Map)+import Data.Text (Text)+import Reflex.Dom+import Reflex.Localize.Dom+import Text.RawString.QQ++main :: IO ()+main = mainWidgetWithCss css $ runLocalize English $ do+ languageDropdown+ pressE <- buttonClass "outline" ButtonLabel+ widgetHold_ (pure ()) $ localizedText PressedLabel <$ pressE+ where+ css = [r|+ select {+ background-color: white;+ color: black;+ font-size: 14pt;+ }+ .outline {+ border-width: 1px;+ border-radius: 10px;+ min-width: 100px;+ min-height: 50px;+ margin-right: 30px;+ color: black;+ background-color: white;+ border-color: black;+ font-size: 14pt;+ }+ |]++buttonClass :: (DomBuilder t m, PostBuild t m, MonadLocalized t m, LocalizedPrint lbl)+ => Dynamic t Text -> lbl -> m (Event t ())+buttonClass classValD lbl = mkButton "button" [("onclick", "return false;")] classValD . dynText =<< localized lbl++mkButton :: (DomBuilder t m, PostBuild t m) => Text -> Map Text Text -> Dynamic t Text -> m a -> m (Event t a)+mkButton eltp attrs classValD ma = do+ let classesD = do+ classVal <- classValD+ pure $ attrs <> [("class", classVal)]+ (e, a) <- elDynAttr' eltp classesD ma+ return $ a <$ domEvent Click e
+ reflex-localize-dom.cabal view
@@ -0,0 +1,108 @@+name: reflex-localize-dom+version: 1.0.0.0+synopsis: Helper widgets for reflex-localize+description: Library provides helpers for dynamic strings that depends on current selected language.+stability: Experimental+category: Reflex, FRP, Web, GUI, HTML, Javascript, Reactive, Reactivity, User Interfaces, User-interface+build-type: Simple+cabal-version: >=1.10+license: MIT+license-file: LICENSE+copyright: 2019 ATUM SOLUTIONS AG+author:+ - Anton Gushcha+ - Aminion+ - Vladimir Krutkin+ - Levon Oganyan+maintainer: - Anton Gushcha <ncrashed@gmail.com>+ - Aminion <>+ - Vladimir Krutkin <krutkinvs@gmail.com>+ - Levon Oganyan+bug-reports: https://github.com/hexresearch/ergvein/issues+homepage: https://github.com/hexresearch/ergvein+extra-source-files:+ README.md+ CHANGELOG.md++flag examples+ default: False+ manual: True++library+ hs-source-dirs: src+ exposed-modules:+ Reflex.Localize.Dom+ build-depends:+ base >= 4.5 && < 4.15+ , containers+ , reflex >= 0.4 && < 0.9+ , reflex-dom >= 0.6 && < 0.9+ , reflex-localize >= 1.0 && < 1.1+ , text+ default-language: Haskell2010+ default-extensions:+ DataKinds+ DeriveDataTypeable+ DeriveGeneric+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GeneralizedNewtypeDeriving+ LambdaCase+ MultiParamTypeClasses+ OverloadedStrings+ RankNTypes+ ScopedTypeVariables+ StandaloneDeriving+ TypeFamilies+ UndecidableInstances++executable reflex-localize-example+ hs-source-dirs: example+ if flag(examples)+ buildable: True+ else+ buildable: False+ main-is: Main.hs+ other-modules:+ App.Language+ App.Localization+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base+ , containers+ , raw-strings-qq+ , reflex+ , reflex-dom+ , reflex-localize+ , reflex-localize-dom+ , text++ default-language: Haskell2010+ default-extensions:+ BangPatterns+ ConstraintKinds+ DataKinds+ DeriveDataTypeable+ DeriveGeneric+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GADTs+ GeneralizedNewtypeDeriving+ LambdaCase+ OverloadedStrings+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ StandaloneDeriving+ TemplateHaskell+ TupleSections+ TypeApplications+ TypeFamilies+ TypeOperators++source-repository head+ type: git+ location: https://github.com/hexresearch/ergvein+ subdir: reflex-localize
+ src/Reflex/Localize/Dom.hs view
@@ -0,0 +1,61 @@+-- |+-- Module : Reflex.Localize.Dom+-- Copyright : (c) 2019-2020 ATUM SOLUTIONS AG+-- License : MIT+-- Maintainer : ncrashed@protonmail.com+-- Stability : unstable+-- Portability : non-portable+--+-- Dom helpers to show localized+--+module Reflex.Localize.Dom(+ localizedText+ , localizedTextWith+ , localizedTextLower+ , localizedTextUpper+ , languageDropdown+ , module Reflex.Localize+ ) where++import Control.Monad.Fix+import Data.Text (Text)+import Reflex.Dom+import Reflex.Localize+import Reflex.Localize.Language+import Reflex.Localize.Trans++import qualified Data.Text as T+import qualified Data.Map.Strict as M++-- | Simple dropdown that allows to select a language and set it for current context. The dropdown has `select-lang` CSS class.+languageDropdown :: (MonadLocalized t m, MonadFix m, PostBuild t m, MonadHold t m, DomBuilder t m, LocalizedPrint Language, Eq Language, Enum Language, Ord Language, Bounded Language) => m ()+languageDropdown = do+ langD <- getLanguage+ initKey <- sample . current $ langD+ let listLangsD = ffor langD $ \l -> M.fromList $ fmap (\v -> (v, localizedShow l v)) [minBound .. maxBound]+ ddnCfg = DropdownConfig {+ _dropdownConfig_setValue = updated langD+ , _dropdownConfig_attributes = constDyn ("class" =: "select-lang")+ }+ dp <- dropdown initKey listLangsD ddnCfg+ let selD = _dropdown_value dp+ selE <- fmap updated $ holdUniqDyn selD+ widgetHold_ (pure ()) $ setLanguage <$> selE++-- | Same as 'text', but changes when language is changed.+localizedText :: (MonadLocalized t m, LocalizedPrint a, PostBuild t m, DomBuilder t m) => a -> m ()+localizedText val = dynText =<< localized val++-- | Same as `localizedText` but transforms text before displaying.+localizedTextWith :: (MonadLocalized t m, LocalizedPrint a, PostBuild t m, DomBuilder t m) => (Text -> Text) -> a -> m ()+localizedTextWith f val = dynText =<< ((fmap . fmap) f $ localized val)++-- | Same as `localizedText` but transforms text to lower case.+localizedTextLower :: (MonadLocalized t m, LocalizedPrint a, PostBuild t m, DomBuilder t m) => a -> m ()+localizedTextLower = localizedTextWith T.toLower++-- | Same as `localizedText` but transforms text to upper case.+localizedTextUpper :: (MonadLocalized t m, LocalizedPrint a, PostBuild t m, DomBuilder t m) => a -> m ()+localizedTextUpper = localizedTextWith T.toUpper++deriving instance DomBuilder t m => DomBuilder t (LocalizeT t m)