Type definitions and low-level bindings for the Intl object.
spago install js-intl
Module documentation is published on Pursuit.
See also: the ECMA-402 specification published here, MDN documentation for Intl here.
Assuming these imports
module Example where
import Prelude
import Data.Array as Array
import Data.Interval as Interval
import Data.JSDate as JSDate
import Data.Maybe (Maybe(..))
import Data.Maybe as Maybe
import Effect (Effect)
import Effect.Class.Console as Console
import JS.Intl.Collator as Collator
import JS.Intl.DateTimeFormat as DateTimeFormat
import JS.Intl.Locale as Locale
import JS.Intl.NumberFormat as NumberFormat
import JS.Intl.Options.Notation as Notation
import JS.Intl.Options.NumberFormatStyle as NumberFormatStyle
import JS.Intl.Options.PluralCategory (PluralCategory(..))
import JS.Intl.Options.UnitDisplay as UnitDisplay
import JS.Intl.PluralRules as PluralRules
import JS.Intl.Segmenter as Segmenter
import Partial.Unsafe as Unsafe
Use the new constructor (or new_ if you don't care to pass LocaleOptions)
to create a Locale
main :: Effect Unit
main = do
en_US <- Locale.new_ "en-US"This Locale is then passed as an argument to the various Intl service
constructors.
let
unsafeParseDateTime string = Unsafe.unsafePartial do
Maybe.fromJust <<< JSDate.toDateTime <$> JSDate.parse string
sep22 <- unsafeParseDateTime "2023-09-22T14:30-04:00"
dateTimeFormat <-
DateTimeFormat.new [ en_US ]
{ weekday: "long"
, hour: "numeric"
, minute: "numeric"
, timeZone: "America/New_York"
}
let
formattedDate =
DateTimeFormat.format dateTimeFormat sep22
Console.log formattedDate -- Friday 2:30 PM sep30 <- unsafeParseDateTime "2023-09-30"
dateTimeRangeFormat <-
DateTimeFormat.new [ en_US ]
{ dateStyle: "medium"
, timeZone: "UTC"
}
let
formattedDateRange =
DateTimeFormat.formatRange dateTimeRangeFormat sep22 sep30
Console.log formattedDateRange -- Sep 22 – 30, 2023 collator <- Collator.new [ en_US ] { numeric: true }
let
sortedStrings =
Array.sortBy (Collator.compare collator) [ "Chapter 1", "Chapter 11", "Chapter 2" ]
Console.logShow sortedStrings -- ["Chapter 1","Chapter 2","Chapter 11"] usdCurrencyFormat <-
NumberFormat.new [ en_US ]
{ style: "currency"
, currency: "USD"
}
let
formattedUSD = NumberFormat.format usdCurrencyFormat 123456.789
Console.log formattedUSD -- $123,456.79 mbNumberFormat <-
NumberFormat.new [ en_US ]
{ style: "unit"
, unit: "megabyte"
, maximumFractionDigits: 0
}
let
formattedMB = NumberFormat.format mbNumberFormat 123456.789
Console.log formattedMB -- 123,457 MB segmenter <- Segmenter.new [ en_US ] { granularity: "word" }
let
sentence = "Hey! How are ya, Jim?"
words = Segmenter.segment segmenter sentence
# Array.mapMaybe \{ isWordLike, segment } ->
if isWordLike then
Just segment
else Nothing
Console.logShow words -- ["Hey","How","are","ya","Jim"] let
ordinalSuffix :: PluralCategory -> String
ordinalSuffix = case _ of
Zero -> "th"
One -> "st"
Two -> "nd"
Few -> "rd"
Many -> "th"
Other -> "th"
pluralRules <- PluralRules.new [ en_US ] { type: "ordinal" }
let
numbers = [ 1, 2, 3, 8, 21 ]
formattedOrdinals = numbers <#> \number -> do
let
suffix = ordinalSuffix (PluralRules.select pluralRules number)
show number <> suffix
Console.logShow formattedOrdinals -- ["1st","2nd","3rd","8th","21st"]In the examples above we mostly passed string values as options to the
service constructors. Many String-typed options only have a few valid
strings that can be passed in. For example, the style option for
NumberFormat only accepts the values "currency", "decimal",
"percent", and "unit". Passing in any other value will throw a
RangeError from JavaScript.
> new Intl.NumberFormat("en-US", { style: "oops" })
Uncaught:
RangeError: Value oops out of range for Intl.NumberFormat options property style
at new NumberFormat (<anonymous>)
This library doesn't prevent you from passing invalid strings, and it
generally won't catch any errors for you. However, for ease of
discoverability of valid options, there are enums in the JS.Intl.Options
modules for most of the option types, and the service constructors are
overloaded to accept these values as well.
secondsNumberFormat <-
NumberFormat.new [ en_US ]
{ style: NumberFormatStyle.Unit
, unit: Interval.Second
, unitDisplay: UnitDisplay.Short
, notation: Notation.Compact
, maximumFractionDigits: 1
}
let
formattedSeconds = NumberFormat.format secondsNumberFormat 123456.789
Console.log formattedSeconds -- 123.5K secSee the ConvertOption type class instances in each of the service
constructor modules to see what options are available as typed enums. Note
that even when using the typed enums there are still some invalid
combinations of options that will throw an error, like specifying timeStyle
and fractionalSecondDigits in the DateTimeFormat options. Reference
the official specification for details on valid
combinations.
More examples are in the Test.Main module.