typesafe-i18n
typesafe-i18n copied to clipboard
Argument with custom type is not passed to the formatter function
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
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)
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.