typesafe-i18n icon indicating copy to clipboard operation
typesafe-i18n copied to clipboard

Argument with custom type is not passed to the formatter function

Open riolly opened this issue 1 year ago • 2 comments

Version

5.26.2

Describe the bug

Following this instruction failed to pass an argument of custom type to the formatter function.

Reproduction

// en/index.ts
dateRange: "{0: DateRange|formatDateRange}",

// custom-types.ts
export interface DateRange {
  from: Date;
  to: Date;
}

// formatters.ts
formatDateRange: (value) => {
  console.log(value) // correctly typed but undefined 
  // using date-fns
  return `${format(value.from, "MM/dd/yyyy", {
    locale: localeDate[locale],
  })} - ${format(value.to, "MM/dd/yyyy", {
    locale: localeDate[locale],
  })}`;
},
  
// app.js
LL.dateRange({ from: new Date(), to: new Date() })

Logs

Cannot read property 'from' of undefined

Value correctly typed but the value undefined

Config

{
   "baseLocale": "en",
   "adapter": "react",
   "$schema": "https://unpkg.com/[email protected]/schema/typesafe-i18n.json"
}

Additional information

No response

riolly avatar Nov 04 '23 06:11 riolly

I've stumbled upon this as well.

// en/component/index.ts
totalPrice: '{value:Currency|currency}',
// custom-types.ts
export type Currency = { value: number; currency: string }
// formatters.ts
currency: (value: Currency) =>
  number(locale, {
    style: 'currency',
    currency: value.currency,
    maximumFractionDigits: 2,
  })(value.value)

vladev avatar Feb 10 '24 10:02 vladev

I also got hit with this - and also with a currency formatter similar to @vladev.

// i18n/custom-types.ts
export type MonetaryAmount = {
  currency: string
  value: number
}

// i18n/en/index.ts
const en = {
  money: "{0:MonetaryAmount|currency}",
}

// i18n/formatters.ts
const formatters: Formatters = {
  currency: ({ value, currency }: MonetaryAmount): string => {
    const formatter = new Intl.NumberFormat(locale, {
    style: "currency",
    currency,
    minimumFractionDigits: 0,
  }

  return formatter.format(value)
}

// component.ts
function Money({value, valueCurrency}: {value: number, valueCurrency: string}) {
  const { LL } = useI18nContext()
  // below is correctly typed, but throws TypeError: Cannot read property 'value' of undefined
  return <Text>{LL.money({ value, currency: valueCurrency })}</Text>
}

Even though this was passing typescript, the call to LL was passing the argument as a "keyed argument". Passing the index through in an object works around the issue, but fails typescript: LL.money({ 0: { value, currency: valueCurrency }})

As a workaround, specifying an argument key in the translation passes typescript and works as expected at runtime:

// i18n/en/index.ts
const en = {
  money: "{money:MonetaryAmount|currency}",
}

// component.ts
function Money({value, valueCurrency}: {value: number, valueCurrency: string}) {
  const { LL } = useI18nContext()
  // now compiles in typescript and works as expected at runtime
  return <Text>{LL.money({ money: { value, currency: valueCurrency }})}</Text>
}

So this is only an issue if you use a single indexed argument in the translation.

jamespamplin avatar Feb 27 '24 16:02 jamespamplin