lingui / js-lingui

🌍 📖 A readable, automated, and optimized (3 kb) internationalization for JavaScript
https://lingui.dev
MIT License
4.6k stars 382 forks source link

Configurable formatters #512

Closed tricoder42 closed 4 years ago

tricoder42 commented 5 years ago

Is your feature request related to a problem? Please describe.

  1. I don't want to use built-in formatters (e.g. I would like to format dates using date-fns instead of Intl.DateTimeFormat)
  2. I want to use custom formatters, e.g. relative time format.

Describe the solution you'd like

Provide configuration with formatters. date and number are standard formats in ICU MessageFormat, but we can override them.

i18n.formats({
  // 1. Override built-in formatter
  date: locale => (value, format =  'MM/DD/YYYY') => format(value, format),

  // 2. Provide a custom formatter
  relativeTime: locale => value => distanceInWordsToNow(value, { locale })

  // `plural`, `select` and `selectOrdinal` isn't possible to override
  // plural: locale => value => ...  // this would throw an Error
})

Then I could simply call i18n.formats.date or i18n.formats.relativeTime to format value based on current locale:

i18n.formats.relativeTime(new Date(2019, 4, 2)) 
 === distanceInWordsToNow(new Date(2019, 4, 2), { locale: i18n.locale })

Describe alternatives you've considered

Don't use date and number formats in ICU. Each value is simply replaced by placeholder:

i18n._(t`Today is ${i18n.format.date(now)}`)

// Originally, the message above would be transformed into message:
// "Today is {now, date}"

// Instead, we would treat it as any other variable:
// "Today is {0}"

That way we don't need to provide default parsers for date and number.

On the other hand, having a global config allows us to bind formatters to locale and memoize formating function (see #472)

Additional context

In the process I would like to deprecate NumberFormat and DateFormat components in @lingui/react (maybe it already is in next branch). There's really no benefit over using plain functions:

// Before
<Trans>Today is <DateFormat value={now} /></Trans>

// After
<Trans>Today is {i18n.format.date(now)}</Trans>

Related issues:

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.