houdini/app/javascript/components/intl/HoudiniIntl.tsx

57 lines
No EOL
2 KiB
TypeScript

// License: LGPL-3.0-or-later
import * as React from "react";
import { useIntl as useIntlParent,
IntlShape as IntlShapeParent,
IntlProvider as IntlProviderParent,
createIntl as createIntlParent} from "react-intl";
import { Money } from "../../common/money";
import { IntlContext } from "../../hooks/useIntl";
import type {IntlShape, FormatMoneyOptions} from '../../hooks/useIntl';
function rawFormatMoney(intl:IntlShapeParent, amount:Money, opts?:FormatMoneyOptions) : string {
const formatter = intl.formatters.getNumberFormat(intl.locale, {...opts,
style: 'currency',
currency: amount.currency.toUpperCase(),
});
const adjustedAmount = amount.amount / Math.pow(10, formatter.resolvedOptions().maximumFractionDigits);
return formatter.format(adjustedAmount);
}
/**
* Use this to scope a context to a tree of components.
* Works like [IntlProvider}(https://formatjs.io/docs/react-intl/components#intlprovider)
* But includes support for formatting money based on the current locale.
*
* @export
* @param {ConstructorParameters<typeof IntlProviderParent>[0]} props
* @returns {JSX.Element}
*/
export default function IntlProvider(props:ConstructorParameters<typeof IntlProviderParent>[0]) : JSX.Element {
return <IntlProviderParent {...props}>
<InnerProvider>
{props.children}
</InnerProvider>
</IntlProviderParent>;
}
function InnerProvider({children}:{children:React.ReactNode}) : JSX.Element {
const intl = useIntlParent();
const formatMoney = React.useCallback((amount:Money, opts?:FormatMoneyOptions) => {
return rawFormatMoney(intl, amount, opts);
}, [intl]);
const houdiniIntl = { ...intl, formatMoney};
return <IntlContext.Provider value={houdiniIntl}>
{children}
</IntlContext.Provider>;
}
export function createIntl(...props:Parameters<typeof createIntlParent>) : IntlShape {
const intl = createIntlParent(...props);
const formatMoney = (amount:Money, opts?:FormatMoneyOptions) => rawFormatMoney(intl, amount, opts);
return {...intl, formatMoney};
}