Package

purescript-js-intl

Repository
pete-murphy/purescript-js-intl
License
MIT
Uploaded by
pacchettibotti
Published on
2023-09-23T02:32:33Z

Latest release Build status Pursuit

Type definitions and low-level bindings for the Intl object.

Installation

spago install js-intl

Documentation

Module documentation is published on Pursuit.

See also: the ECMA-402 specification published here, MDN documentation for Intl here.

How to use this library

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

Construct a Locale

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.

Format a date

  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

Format a date range

  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

Sort a collection of strings by natural sort order

  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"]

Format a number as currency

  usdCurrencyFormat <-
    NumberFormat.new [ en_US ]
      { style: "currency"
      , currency: "USD"
      }

  let
    formattedUSD = NumberFormat.format usdCurrencyFormat 123456.789

  Console.log formattedUSD -- $123,456.79

Format a number as megabytes (or whatever unit)

  mbNumberFormat <-
    NumberFormat.new [ en_US ]
      { style: "unit"
      , unit: "megabyte"
      , maximumFractionDigits: 0
      }

  let
    formattedMB = NumberFormat.format mbNumberFormat 123456.789

  Console.log formattedMB -- 123,457 MB

Get a list of words from a sentence

  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"]

Format numbers as ordinal (1st, 2nd, 3rd, etc.)

  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"]

Type safety and overloaded API

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 sec

See 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.

Modules
JS.Intl
JS.Intl.Collator
JS.Intl.DateTimeFormat
JS.Intl.DisplayNames
JS.Intl.ListFormat
JS.Intl.Locale
JS.Intl.NumberFormat
JS.Intl.Options.AvailableCanonical
JS.Intl.Options.CaseFirst
JS.Intl.Options.Collation
JS.Intl.Options.CompactDisplay
JS.Intl.Options.CurrencyDisplay
JS.Intl.Options.CurrencySign
JS.Intl.Options.DateStyle
JS.Intl.Options.Day
JS.Intl.Options.DayPeriod
JS.Intl.Options.DisplayNamesType
JS.Intl.Options.Era
JS.Intl.Options.Fallback
JS.Intl.Options.FormatMatcher
JS.Intl.Options.Granularity
JS.Intl.Options.Hour
JS.Intl.Options.HourCycle
JS.Intl.Options.Internal.Unsafe
JS.Intl.Options.LanguageDisplay
JS.Intl.Options.ListFormatType
JS.Intl.Options.LocaleMatcher
JS.Intl.Options.Minute
JS.Intl.Options.Month
JS.Intl.Options.Notation
JS.Intl.Options.NumberFormatStyle
JS.Intl.Options.Numeric
JS.Intl.Options.PluralCategory
JS.Intl.Options.PluralRulesType
JS.Intl.Options.RelativeTimeUnit
JS.Intl.Options.RoundingIncrement
JS.Intl.Options.RoundingMode
JS.Intl.Options.RoundingPriority
JS.Intl.Options.Second
JS.Intl.Options.Sensitivity
JS.Intl.Options.SignDisplay
JS.Intl.Options.Style
JS.Intl.Options.TimeStyle
JS.Intl.Options.TimeZoneName
JS.Intl.Options.TrailingZeroDisplay
JS.Intl.Options.UnitDisplay
JS.Intl.Options.Usage
JS.Intl.Options.UseGrouping
JS.Intl.Options.Weekday
JS.Intl.Options.Year
JS.Intl.PluralRules
JS.Intl.RelativeTimeFormat
JS.Intl.Segmenter
Dependencies