fluent-effectful-1.0.0: src/Effectful/Fluent/Single.hs
{-# OPTIONS_GHC -Wno-orphans #-}
-- |
-- Module : Effectful.Fluent.Single
-- Copyright : (c) 2026 Institute for Digital Autonomy
-- License : EUPL-1.2
-- Maintainer : IDA
--
-- <https://projectfluent.org Project Fluent> translation support for the
-- <https://hackage.haskell.org/package/effectful Effectful> ecosystem, for applications
-- targeting a single language.
--
-- This module provides the 'Fluent' effect and 'runFluent' interpreter to translate
-- messages against a collection of 'Bundle's selected by locale code.
--
-- This library does not provide any concrete instances of 'Locale'.
-- Pair it with a locale provider such as <https://hackage.haskell.org/package/fluent-icu fluent-icu>.
--
-- = Quickstart
--
-- == 1. Parsing resources
--
-- Embed Fluent resources at compile time using the 'fluent' quasi-quoter:
--
-- > let resource =
-- > [fluent|
-- > greeting = Hello!
-- > welcome = Welcome, { $name }
-- > |]
--
-- Or parse Fluent source at runtime with 'parseResource':
--
-- > resource <- either fail pure . parseResource =<< Text.readFile "en-GB.ftl"
--
-- == 2. Building bundles
--
-- Combine 'Resource's and 'Locale's into a 'Bundle' using 'bundle':
--
-- > let english = bundle @LocaleName (pure "en-GB") [resource]
--
-- == 3. Running the effect
--
-- Pass the 'Bundle' to 'runFluent' and translate messages with 'translate':
--
-- > main :: IO ()
-- > main = runEff . runFluent english $ do
-- > translate "greeting" >>= liftIO . print
-- > -- Right "Hello!"
-- > translate "welcome" ("name", value @Text "Ann") >>= liftIO . print
-- > -- Right "Welcome, Ann"
module Effectful.Fluent.Single
( -- * Effect
Fluent
, runFluent
-- * Re-exports
, module Language.Fluent
)
where
import Data.Text (Text)
import Effectful
import Effectful.Dispatch.Static (SideEffects (..), StaticRep, evalStaticRep, getStaticRep)
import Language.Fluent
import Prelude
-- | Translates from a single t'Bundle'.
data Fluent :: Effect
type instance DispatchOf Fluent = 'Static 'NoSideEffects
data instance StaticRep Fluent where
Fluent :: (Locale locale) => Bundle locale -> StaticRep Fluent
-- | Translate with the given t'Bundle' in the effectful computation.
runFluent :: (Locale locale) => Bundle locale -> Eff (Fluent ': es) a -> Eff es a
runFluent = evalStaticRep . Fluent
instance (Fluent :> es, r ~ Either String Text) => Translate (Eff es r) where
translate ref = (\(Fluent bundle) -> translate ref bundle) <$> getStaticRep @Fluent