packages feed

fluent-icu 1.0.0 → 1.1.0

raw patch · 10 files changed

+87/−66 lines, 10 filesdep ~fluentsetup-changedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: fluent

API changes (from Hackage documentation)

+ Language.Fluent.ICU: Bundle :: NonEmpty locale -> [Resource] -> HashMap Identifier ([Pattern] -> HashMap Identifier Value -> Either String Pattern) -> Bool -> Bundle locale
+ Language.Fluent.ICU: Cardinal :: Form
+ Language.Fluent.ICU: Code :: CurrencyDisplay
+ Language.Fluent.ICU: Currency :: Text -> Style
+ Language.Fluent.ICU: Decimal :: Style
+ Language.Fluent.ICU: Few :: Category
+ Language.Fluent.ICU: Isolated :: Pattern -> PatternElement
+ Language.Fluent.ICU: Long :: Width
+ Language.Fluent.ICU: Many :: Category
+ Language.Fluent.ICU: Name :: CurrencyDisplay
+ Language.Fluent.ICU: Narrow :: Width
+ Language.Fluent.ICU: NumberOptions :: Form -> Style -> CurrencyDisplay -> Width -> Bool -> Int -> Int -> Maybe Int -> Maybe Int -> Maybe Int -> NumberOptions
+ Language.Fluent.ICU: Numeric :: Digits
+ Language.Fluent.ICU: One :: Category
+ Language.Fluent.ICU: Ordinal :: Form
+ Language.Fluent.ICU: Other :: Category
+ Language.Fluent.ICU: Pattern :: NonEmpty PatternElement -> Pattern
+ Language.Fluent.ICU: Percent :: Style
+ Language.Fluent.ICU: Reference :: Either String Identifier -> Maybe AttributeAccessor -> HashMap Text Value -> [Override] -> Reference
+ Language.Fluent.ICU: Short :: Width
+ Language.Fluent.ICU: Symbol :: CurrencyDisplay
+ Language.Fluent.ICU: TimeOptions :: Text -> Maybe Bool -> Maybe Width -> Maybe Width -> Maybe Digits -> Maybe (Either Digits Width) -> Maybe Digits -> Maybe Digits -> Maybe Digits -> Maybe Digits -> Maybe Width -> TimeOptions
+ Language.Fluent.ICU: Two :: Category
+ Language.Fluent.ICU: TwoDigit :: Digits
+ Language.Fluent.ICU: Unit :: Text -> Style
+ Language.Fluent.ICU: UseIsolating :: Bool -> Override
+ Language.Fluent.ICU: Value :: Value -> PatternElement
+ Language.Fluent.ICU: WithFunction :: Identifier -> ([Pattern] -> HashMap Identifier Value -> Either String Pattern) -> Override
+ Language.Fluent.ICU: Zero :: Category
+ Language.Fluent.ICU: [arguments] :: Reference -> HashMap Text Value
+ Language.Fluent.ICU: [attribute] :: Reference -> Maybe AttributeAccessor
+ Language.Fluent.ICU: [currencyDisplay] :: NumberOptions -> CurrencyDisplay
+ Language.Fluent.ICU: [day] :: TimeOptions -> Maybe Digits
+ Language.Fluent.ICU: [era] :: TimeOptions -> Maybe Width
+ Language.Fluent.ICU: [form] :: NumberOptions -> Form
+ Language.Fluent.ICU: [functions] :: Bundle locale -> HashMap Identifier ([Pattern] -> HashMap Identifier Value -> Either String Pattern)
+ Language.Fluent.ICU: [hour12] :: TimeOptions -> Maybe Bool
+ Language.Fluent.ICU: [hour] :: TimeOptions -> Maybe Digits
+ Language.Fluent.ICU: [locales] :: Bundle locale -> NonEmpty locale
+ Language.Fluent.ICU: [maximumFractionDigits] :: NumberOptions -> Maybe Int
+ Language.Fluent.ICU: [maximumSignificantDigits] :: NumberOptions -> Maybe Int
+ Language.Fluent.ICU: [minimumFractionDigits] :: NumberOptions -> Int
+ Language.Fluent.ICU: [minimumIntegerDigits] :: NumberOptions -> Int
+ Language.Fluent.ICU: [minimumSignificantDigits] :: NumberOptions -> Maybe Int
+ Language.Fluent.ICU: [minute] :: TimeOptions -> Maybe Digits
+ Language.Fluent.ICU: [month] :: TimeOptions -> Maybe (Either Digits Width)
+ Language.Fluent.ICU: [name] :: Reference -> Either String Identifier
+ Language.Fluent.ICU: [overrides] :: Reference -> [Override]
+ Language.Fluent.ICU: [resources] :: Bundle locale -> [Resource]
+ Language.Fluent.ICU: [second] :: TimeOptions -> Maybe Digits
+ Language.Fluent.ICU: [style] :: NumberOptions -> Style
+ Language.Fluent.ICU: [timeZoneName] :: TimeOptions -> Maybe Width
+ Language.Fluent.ICU: [timeZone] :: TimeOptions -> Text
+ Language.Fluent.ICU: [unitDisplay] :: NumberOptions -> Width
+ Language.Fluent.ICU: [useGrouping] :: NumberOptions -> Bool
+ Language.Fluent.ICU: [useIsolating] :: Bundle locale -> Bool
+ Language.Fluent.ICU: [weekday] :: TimeOptions -> Maybe Width
+ Language.Fluent.ICU: [year] :: TimeOptions -> Maybe Digits
+ Language.Fluent.ICU: bundle :: NonEmpty locale -> [Resource] -> Bundle locale
+ Language.Fluent.ICU: capitalise :: Locale l => l -> Text -> Text
+ Language.Fluent.ICU: class Locale l
+ Language.Fluent.ICU: class ToValue v
+ Language.Fluent.ICU: class Translate r
+ Language.Fluent.ICU: data Bundle locale
+ Language.Fluent.ICU: data Category
+ Language.Fluent.ICU: data CurrencyDisplay
+ Language.Fluent.ICU: data Digits
+ Language.Fluent.ICU: data Form
+ Language.Fluent.ICU: data Identifier
+ Language.Fluent.ICU: data NumberOptions
+ Language.Fluent.ICU: data Override
+ Language.Fluent.ICU: data PatternElement
+ Language.Fluent.ICU: data Reference
+ Language.Fluent.ICU: data Resource
+ Language.Fluent.ICU: data Style
+ Language.Fluent.ICU: data TimeOptions
+ Language.Fluent.ICU: data Value
+ Language.Fluent.ICU: data Width
+ Language.Fluent.ICU: displayLanguage :: Locale l => l -> l -> Maybe Text
+ Language.Fluent.ICU: fluent :: QuasiQuoter
+ Language.Fluent.ICU: formatNumber :: Locale l => NonEmpty l -> Scientific -> NumberOptions -> Either String Text
+ Language.Fluent.ICU: formatTime :: Locale l => NonEmpty l -> UTCTime -> TimeOptions -> Either String Text
+ Language.Fluent.ICU: fromCode :: Locale l => Text -> Maybe l
+ Language.Fluent.ICU: localDisplayLanguage :: Locale l => l -> Maybe Text
+ Language.Fluent.ICU: messageIdentifiers :: FilePath -> DecsQ
+ Language.Fluent.ICU: newtype Pattern
+ Language.Fluent.ICU: numberOptions :: NumberOptions
+ Language.Fluent.ICU: parseResource :: Text -> Either String Resource
+ Language.Fluent.ICU: parseResourceLenient :: Text -> Resource
+ Language.Fluent.ICU: pluralCategory :: Locale l => l -> Scientific -> NumberOptions -> Category
+ Language.Fluent.ICU: timeOptions :: TimeOptions
+ Language.Fluent.ICU: toCode :: Locale l => l -> Text
+ Language.Fluent.ICU: toValue :: ToValue v => v -> Value
+ Language.Fluent.ICU: translate :: Translate r => Reference -> r

Files

CHANGELOG.md view
@@ -5,6 +5,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## [1.1.0] - 2026-10-20++### Changed++- **Breaking:** `fluent` 1.1.0 breaking changes:+  - `SomeValue` is now `Value`.+  - The `Value` class is now `ToValue`.+  - Constructors are used qualified: `Value.String`, `Value.Number`, `Value.Time`.+  - `CustomValue` and `ToValue.format` are replaced by `Value.Formatted`.+  - The `fluent` quasi-quoter and `messageIdentifiers` fail to compile on a syntax error.+  - `parseResource` fails on a syntax error. `parseResourceLenient` returns a `JunkEntry` instead.++### Fixed++- Huge digit options, such as `minimumIntegerDigits: 1000000000`, are capped to the ranges of `Intl.NumberFormat`.+ ## [1.0.0] - 2026-10-01  ### Added
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
fluent-icu.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: fluent-icu-version: 1.0.0+version: 1.1.0 synopsis: ICU backend for fluent description: ICU backend for <https://hackage.haskell.org/package/fluent fluent>. license: EUPL-1.2@@ -45,7 +45,7 @@    build-depends:     base >=4.11 && <5,-    fluent >=1.0 && <1.1,+    fluent >=1.1 && <1.2,     text >=2.0 && <2.2,  library@@ -69,7 +69,7 @@   import: common   type: exitcode-stdio-1.0   hs-source-dirs: test-  main-is: Spec.hs+  main-is: Main.hs   other-modules:     BuiltinSpec     LocaleSpec
src/Language/Fluent/ICU.hs view
@@ -9,7 +9,7 @@ -- -- <https://projectfluent.org Project Fluent> localisation backed by -- <https://unicode-org.github.io/icu/ ICU> using the--- <https://hackage.package.org/package/text-icu text-icu> library.+-- <https://hackage.haskell.org/package/text-icu text-icu> library. -- -- This module re-exports everything needed to translate Fluent messages. --@@ -39,6 +39,8 @@ -- -- > resource <- either fail pure . parseResource =<< Text.readFile "resource.ftl" --+-- A syntax error fails the whole file. 'parseResourceLenient' returns a 'JunkEntry' instead.+-- -- == 2. Building bundles -- -- Combine 'Resource's and 'Locale's into a 'Bundle' using 'bundle':@@ -55,38 +57,39 @@ -- -- Pass parameters as name-value tuples: ----- >>> translate "unread-emails" ("count", value @Int 1) english :: Either String Text+-- >>> translate "unread-emails" ("count", 1) english :: Either String Text -- Right "You have one unread email."--- >>> translate "unread-emails" ("count", value @Int 5) english :: Either String Text+-- >>> translate "unread-emails" ("count", 5) english :: Either String Text -- Right "You have several unread emails." -- -- You can chain multiple arguments and configure Unicode isolation marks using 'UseIsolating': ----- >>> translate "greeting" ("name", value @Text "Ann") ("count", value @Int 3) (UseIsolating False) english :: Either String Text+-- >>> translate "greeting" ("name", "Ann") ("count", 3) (UseIsolating False) english :: Either String Text -- Right "Hello, Ann! You have 3 new messages." -- -- == 4. Formatting numbers, currencies, and units -- -- Number formatting adapts to the target locale: ----- >>> translate "amount" ("amount", value @Int 1234567) english :: Either String Text+-- >>> translate "amount" ("amount", 1234567 :: Int) english :: Either String Text -- Right "1,234,567"--- >>> translate "amount" ("amount", value @Int 1234567) german :: Either String Text+-- >>> translate "amount" ("amount", 1234567 :: Int) german :: Either String Text -- Right "1'234'567"--- >>> translate "price" ("amount", value @Double 1234.5) english :: Either String Text+-- >>> translate "price" ("amount", 1234.5 :: Double) english :: Either String Text -- Right "1,234.50 euros"--- >>> translate "price" ("amount", value @Double 1234.5) german :: Either String Text+-- >>> translate "price" ("amount", 1234.5 :: Double) german :: Either String Text -- Right "1'234.50 Euro"--- >>> translate "temperature" ("degrees", value @Int 21) english :: Either String Text+-- >>> translate "temperature" ("degrees", 21 :: Int) english :: Either String Text -- Right "21 degrees Celsius"--- >>> translate "temperature" ("degrees", value @Int 21) german :: Either String Text+-- >>> translate "temperature" ("degrees", 21 :: Int) german :: Either String Text -- Right "21 Grad Celsius" -- -- You can pass formatting options directly via structured values: ----- >>> translate "amount" ("amount", NumberValue 1234.5 numberOptions{style = Currency "EUR", currencyDisplay = Name}) english :: Either String Text+-- >>> import Language.Fluent.Value qualified as Value+-- >>> translate "amount" ("amount", Value.Number 1234.5 numberOptions{style = Currency "EUR", currencyDisplay = Name}) english :: Either String Text -- Right "1,234.50 euros"--- >>> translate "amount" ("amount", NumberValue 21 numberOptions{style = Unit "metre-per-second", unitDisplay = Short}) english :: Either String Text+-- >>> translate "amount" ("amount", Value.Number 21 numberOptions{style = Unit "metre-per-second", unitDisplay = Short}) english :: Either String Text -- Right "21 m/s" module Language.Fluent.ICU     ( -- * Re-exports@@ -139,7 +142,7 @@         withLocaleName a \source ->             withLocaleName b \target ->                 allocaBytes capacity \name -> do-                    written <- fluentGetDisplayLanguage source target name (fromIntegral capacity)+                    written <- fluentGetDisplayLanguage source target name $ fromIntegral capacity                     if written < 0                         then pure Nothing                         else Just . Text.decodeUtf8 <$> ByteString.packCStringLen (name, fromIntegral written)@@ -151,7 +154,7 @@             ByteString.useAsCStringLen utf8 \(source, sourceLength) ->                 allocaBytes capacity \out -> do                     written <--                        fluentFormatTitlecase locale source (fromIntegral sourceLength) out (fromIntegral capacity)+                        fluentFormatTitlecase locale source (fromIntegral sourceLength) out $ fromIntegral capacity                     if written < 0                         then pure text                         else Text.decodeUtf8 <$> ByteString.packCStringLen (out, fromIntegral written)@@ -172,7 +175,7 @@                                 decimal                                 (fromIntegral decimalLength)                                 keyword-                                (fromIntegral capacity)+                                $ fromIntegral capacity                         if written < 0                             then pure Plural.Other                             else fromMaybe Plural.Other . readMaybe <$> peekCStringLen (keyword, fromIntegral written)@@ -195,7 +198,7 @@                                     decimal                                     (fromIntegral decimalLength)                                     out-                                    (fromIntegral capacity)+                                    $ fromIntegral capacity                             if written < 0                                 then Left . ("NUMBER: " <>) <$> icuErrorMessage written                                 else Right . Text.decodeUtf8 <$> ByteString.packCStringLen (out, fromIntegral written)@@ -209,7 +212,7 @@                 withLocaleName locale \name ->                     withUtf8Text skeleton \wanted ->                         allocaBytes capacity \ptr -> do-                            written <- fluentResolveDatePattern name wanted ptr (fromIntegral capacity)+                            written <- fluentResolveDatePattern name wanted ptr $ fromIntegral capacity                             if written < 0                                 then pure skeleton                                 else Text.decodeUtf8 <$> ByteString.packCStringLen (ptr, fromIntegral written)@@ -223,7 +226,7 @@         skeleton = Time.skeleton options          millisecondsSinceEpoch :: UTCTime -> Double-        millisecondsSinceEpoch = (* 1000) . realToFrac . utcTimeToPOSIXSeconds+        millisecondsSinceEpoch = (1000 *) . realToFrac . utcTimeToPOSIXSeconds          setMillis :: Calendar -> Double -> IO ()         setMillis calendar ms = do@@ -251,7 +254,7 @@     withMany withLocaleName (NonEmpty.toList preferences) \accept ->         withArrayLen accept \count array ->             allocaBytes capacity \out -> do-                written <- fluentNegotiateSupportedLocale array (fromIntegral count) out (fromIntegral capacity)+                written <- fluentNegotiateSupportedLocale array (fromIntegral count) out $ fromIntegral capacity                 if written < 0                     then pure Nothing                     else Just . ICU.Locale <$> peekCStringLen (out, fromIntegral written)
test/BuiltinSpec.hs view
@@ -13,7 +13,7 @@         it "omits the grouping separators when turned off" $             translate                 "foo"-                [("arg", number 1234567)]+                [("arg", 1234567 :: Int)]                 [fluent|foo = { NUMBER($arg, useGrouping: "false") }|]                 `shouldBe` Right "1234567"         it "selects by the plural category of the number" $@@ -66,10 +66,10 @@                 `shouldBe` Left "DATETIME: the positional argument is not a time"  written :: Resource -> Either String Text-written = translate "foo" [("arg", number 3)]+written = translate "foo" [("arg", 3 :: Int)]  when' :: Resource -> Either String Text-when' = translate "foo" [("arg", value afternoon)]+when' = translate "foo" [("arg", afternoon)]  -- | 2026-08-10, a Monday, 12:34:56 UTC. afternoon :: UTCTime
+ test/Main.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
test/NumberSpec.hs view
@@ -1,94 +1,95 @@ module NumberSpec (spec) where +import Language.Fluent.Value qualified as Value import Prelude  spec :: Spec spec = do     it "groups the digits the way the locale groups them" $-        translate "foo" ("arg", NumberValue 1234567 numberOptions) resource `shouldBe` Right "1,234,567"+        translate "foo" ("arg", Value.Number 1234567 numberOptions) resource `shouldBe` Right "1,234,567"     it "leaves the grouping out when it is turned off" $-        translate "foo" ("arg", NumberValue 1234567 numberOptions{useGrouping = False}) resource+        translate "foo" ("arg", Value.Number 1234567 numberOptions{useGrouping = False}) resource             `shouldBe` Right "1234567"     it "pads the integer part to the given width" $-        translate "foo" ("arg", NumberValue 5 numberOptions{minimumIntegerDigits = 3}) resource+        translate "foo" ("arg", Value.Number 5 numberOptions{minimumIntegerDigits = 3}) resource             `shouldBe` Right "005"     it "limits the fraction digits to the maximum given" $-        translate "foo" ("arg", NumberValue 1.5 numberOptions{maximumFractionDigits = Just 0}) resource+        translate "foo" ("arg", Value.Number 1.5 numberOptions{maximumFractionDigits = Just 0}) resource             `shouldBe` Right "2"     it "limits the significant digits it is given" $         translate             "foo"-            ("arg", NumberValue 1234 numberOptions{maximumSignificantDigits = Just 2})+            ("arg", Value.Number 1234 numberOptions{maximumSignificantDigits = Just 2})             resource             `shouldBe` Right "1,200"     it "is shown as a percentage" $-        translate "foo" ("arg", NumberValue 0.25 numberOptions{style = Percent}) resource+        translate "foo" ("arg", Value.Number 0.25 numberOptions{style = Percent}) resource             `shouldBe` Right "25%"     it "is an amount of a currency" $-        translate "foo" ("arg", NumberValue 12.5 numberOptions{style = Currency "EUR"}) resource+        translate "foo" ("arg", Value.Number 12.5 numberOptions{style = Currency "EUR"}) resource             `shouldBe` Right "€12.50"     it "spells the currency's name out, not its symbol" $         translate             "foo"-            ("arg", NumberValue 12.5 numberOptions{style = Currency "EUR", currencyDisplay = Name})+            ("arg", Value.Number 12.5 numberOptions{style = Currency "EUR", currencyDisplay = Name})             resource             `shouldBe` Right "12.50 euros"     it "is an amount of a unit" $-        translate "foo" ("arg", NumberValue 5 numberOptions{style = Unit "kilometre-per-hour"}) resource+        translate "foo" ("arg", Value.Number 5 numberOptions{style = Unit "kilometre-per-hour"}) resource             `shouldBe` Right "5 km/h"     it "is an amount of a unit of one thing per another" $-        translate "foo" ("arg", NumberValue 5 numberOptions{style = Unit "litre-per-kilometre"}) resource+        translate "foo" ("arg", Value.Number 5 numberOptions{style = Unit "litre-per-kilometre"}) resource             `shouldBe` Right "5 l/km"     it "shows the unit's symbol when narrow, its name when long" $ do         translate             "foo"-            ("arg", NumberValue 5 numberOptions{style = Unit "litre", unitDisplay = Narrow})+            ("arg", Value.Number 5 numberOptions{style = Unit "litre", unitDisplay = Narrow})             resource             `shouldBe` Right "5l"         translate             "foo"-            ("arg", NumberValue 5 numberOptions{style = Unit "litre", unitDisplay = Long})+            ("arg", Value.Number 5 numberOptions{style = Unit "litre", unitDisplay = Long})             resource             `shouldBe` Right "5 litres"     it "accepts a unit identifier written in British spelling" $ do-        translate "foo" ("arg", NumberValue 5 numberOptions{style = Unit "litre"}) resource+        translate "foo" ("arg", Value.Number 5 numberOptions{style = Unit "litre"}) resource             `shouldBe` Right "5 l"-        translate "foo" ("arg", NumberValue 5 numberOptions{style = Unit "millilitre"}) resource+        translate "foo" ("arg", Value.Number 5 numberOptions{style = Unit "millilitre"}) resource             `shouldBe` Right "5 ml"-        translate "foo" ("arg", NumberValue 5 numberOptions{style = Unit "square-kilometre"}) resource+        translate "foo" ("arg", Value.Number 5 numberOptions{style = Unit "square-kilometre"}) resource             `shouldBe` Right "5 km²"     it "keeps the fraction digits a unit is given" $         translate             "foo"-            ("arg", NumberValue 5 numberOptions{style = Unit "megabyte", minimumFractionDigits = 1})+            ("arg", Value.Number 5 numberOptions{style = Unit "megabyte", minimumFractionDigits = 1})             resource             `shouldBe` Right "5.0 MB"     it "spells the unit the way the locale spells it, whatever it is called" $ do         translate             "foo"-            ("arg", NumberValue 5 numberOptions{style = Unit "kilometre", unitDisplay = Long})+            ("arg", Value.Number 5 numberOptions{style = Unit "kilometre", unitDisplay = Long})             resource             `shouldBe` Right "5 kilometres"         translate             "foo"-            ("arg", NumberValue 5 numberOptions{style = Unit "litre", unitDisplay = Long})+            ("arg", Value.Number 5 numberOptions{style = Unit "litre", unitDisplay = Long})             deCH             resource             `shouldBe` Right "5 Liter"     it "rejects a unit it does not know" $-        translate "foo" ("arg", NumberValue 5 numberOptions{style = Unit "banana"}) resource+        translate "foo" ("arg", Value.Number 5 numberOptions{style = Unit "banana"}) resource             `shouldBe` Left "NUMBER: U_NUMBER_SKELETON_SYNTAX_ERROR"     it "uses the first known locale in the chain" $ do-        translate "foo" ("arg", NumberValue 1234.5 numberOptions) [deCH, enGB] resource+        translate "foo" ("arg", Value.Number 1234.5 numberOptions) [deCH, enGB] resource             `shouldBe` Right "1'234.5"-        translate "foo" ("arg", NumberValue 1234.5 numberOptions) [enGB, deCH] resource+        translate "foo" ("arg", Value.Number 1234.5 numberOptions) [enGB, deCH] resource             `shouldBe` Right "1,234.5"-        translate "foo" ("arg", NumberValue 1234.5 numberOptions) [unknown, deCH] resource+        translate "foo" ("arg", Value.Number 1234.5 numberOptions) [unknown, deCH] resource             `shouldBe` Right "1'234.5"     it "falls back to an ancestor locale when the exact one is unknown" $ do-        translate "foo" ("arg", NumberValue 1234.5 numberOptions) deSince1996 resource+        translate "foo" ("arg", Value.Number 1234.5 numberOptions) deSince1996 resource             `shouldBe` Right "1'234.5"-        translate "foo" ("arg", NumberValue 1234.5 numberOptions) deInAnUnknownScript resource+        translate "foo" ("arg", Value.Number 1234.5 numberOptions) deInAnUnknownScript resource             `shouldBe` Right "1.234,5"  resource :: Resource
test/Prelude.hs view
@@ -21,6 +21,7 @@ import Language.Fluent.Bundle qualified as Bundle import Language.Fluent.ICU import Language.Fluent.Locale qualified as Locale+import Language.Fluent.Value qualified as Value import Test.Hspec import "base" Prelude @@ -40,12 +41,12 @@ instance (r ~ Either String Text) => Translate (Resource -> r) where     translate arguments = translate arguments $ Locale.fromCode @LocaleName "en-GB" -number :: Scientific -> SomeValue+number :: Scientific -> Value number = numberWith Cardinal 0 -ordinal :: Scientific -> SomeValue+ordinal :: Scientific -> Value ordinal = numberWith Ordinal 0 -numberWith :: Form -> Int -> Scientific -> SomeValue+numberWith :: Form -> Int -> Scientific -> Value numberWith form minimumFractionDigits amount =-    NumberValue amount numberOptions{form, minimumFractionDigits}+    Value.Number amount numberOptions{form, minimumFractionDigits}
− test/Spec.hs
@@ -1,1 +0,0 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
test/TimeSpec.hs view
@@ -1,43 +1,45 @@ module TimeSpec (spec) where  import Data.Time+import Language.Fluent.Value qualified as Value import Prelude  spec :: Spec spec = do     it "is a date of numbers when given nothing" $-        translate "foo" ("when", TimeValue afternoon timeOptions) resource `shouldBe` Right "10/08/2026"+        translate "foo" ("when", Value.Time afternoon timeOptions) resource `shouldBe` Right "10/08/2026"     it "formats the date to match the locale's convention" $-        translate "foo" ("when", TimeValue afternoon timeOptions) deCH resource `shouldBe` Right "10.8.2026"+        translate "foo" ("when", Value.Time afternoon timeOptions) deCH resource+            `shouldBe` Right "10.8.2026"     it "spells the month out at the width it is given" $         translate             "foo"-            ("when", TimeValue afternoon dated{month = Just (Right Long)})+            ("when", Value.Time afternoon dated{month = Just $ Right Long})             resource             `shouldBe` Right "10 August 2026"     it "formats only the field it is given" $-        translate "foo" ("when", TimeValue afternoon timeOptions{month = Just (Right Long)}) resource+        translate "foo" ("when", Value.Time afternoon timeOptions{month = Just $ Right Long}) resource             `shouldBe` Right "August"     it "spells the weekday out" $-        translate "foo" ("when", TimeValue afternoon timeOptions{weekday = Just Long}) resource+        translate "foo" ("when", Value.Time afternoon timeOptions{weekday = Just Long}) resource             `shouldBe` Right "Monday"     it "shows the time of day it is given" $-        translate "foo" ("when", TimeValue afternoon clock) resource `shouldBe` Right "12:34"+        translate "foo" ("when", Value.Time afternoon clock) resource `shouldBe` Right "12:34"     it "formats the month in digits or in words, beside a year of digits" $ do         translate             "foo"-            ("when", TimeValue afternoon timeOptions{year = Just Numeric, month = Just (Right Narrow)})+            ("when", Value.Time afternoon timeOptions{year = Just Numeric, month = Just $ Right Narrow})             resource             `shouldBe` Right "A 2026"         translate             "foo"-            ("when", TimeValue afternoon timeOptions{year = Just Numeric, month = Just (Left TwoDigit)})+            ("when", Value.Time afternoon timeOptions{year = Just Numeric, month = Just $ Left TwoDigit})             resource             `shouldBe` Right "08/2026"     it "reads the time in the zone it is given" $-        translate "foo" ("when", TimeValue afternoon berlin) resource `shouldBe` Right "14:34"+        translate "foo" ("when", Value.Time afternoon berlin) resource `shouldBe` Right "14:34"     it "keeps the hour the zone keeps at that time of year" $-        translate "foo" ("when", TimeValue midwinter berlin) resource `shouldBe` Right "13:34"+        translate "foo" ("when", Value.Time midwinter berlin) resource `shouldBe` Right "13:34"  resource :: Resource resource = [fluent|foo = { $when }|]