@transglot/react-intl
v0.1.0
Published
A react-intl / FormatJS interop loader over @transglot/runtime: loadMessages() fetches a published bundle from transglot's OTA/CDN (ETag/304, cdnKey) and maps it into the { id: message } shape react-intl's IntlProvider expects, so existing <FormattedMessa
Maintainers
Readme
@transglot/react-intl
A react-intl / FormatJS interop loader
over @transglot/runtime. loadMessages() fetches a project's
PUBLISHED bundle from transglot's OTA/CDN (ETag/304, cdnKey) and maps it into the
{ id: message } shape react-intl's <IntlProvider> expects, so a team already on
react-intl keeps its <FormattedMessage>/formatMessage() call-sites and only
changes where the catalog comes from.
This is a LOADER, not a provider. It produces a plain messages map that you hand to react-intl's own
<IntlProvider>/createIntl. FormatJS does all the ICU formatting at render time.
Install
npm install @transglot/react-intl @transglot/runtime react-intlreact-intl is an optional peer (the consumer you pair this with).
Quickstart
import { IntlProvider } from 'react-intl';
import { loadMessages } from '@transglot/react-intl';
// Server component / getServerSideProps / SvelteKit load / the browser: anywhere
// with fetch.
const { locale, messages } = await loadMessages({
baseUrl: 'https://app.example.com',
project: 42,
cdnKey: 'taicdn_…',
locale: 'fr',
});
export function Root() {
return (
<IntlProvider locale={locale} messages={messages}>
<App />
</IntlProvider>
);
}Your existing call-sites keep working unchanged:
import { FormattedMessage, useIntl } from 'react-intl';
function Header() {
const intl = useIntl();
return (
<header>
<h1>{intl.formatMessage({ id: 'home.title' })}</h1>
<FormattedMessage id="cart" values={{ count: 3 }} />
</header>
);
}How the mapping works
transglot's stored strings ARE ICU MessageFormat: simple placeholders are
single-brace {name} and plurals are {count, plural, one {…} other {…}}, the same
syntax FormatJS parses. So messages pass through VERBATIM and only the container is
reshaped:
- nested objects (
json_nested) are flattened to dotted ids (home.title); - already-flat dotted keys (
json_flat,laravel_json) are kept as-is; - Flutter ARB globals (
@@locale) and per-key metadata (@key) are dropped.
Because the loader reuses the runtime client for the wire, a network/HTTP failure
surfaces as the runtime's typed RuntimeError (map to a fallback or rethrow).
API
loadMessages(options)returnsPromise<ReactIntlBundle>:{ locale, messages, format?, version?, etag? }. Spreadlocale+messagesonto<IntlProvider>. Options:baseUrl,project,cdnKey,locale,version?,authIn?(headerdefault orquery),fetchImpl?,dev?.bundleToMessages(rawBody)the pure mapping from a raw bundle body to the{ id: message }map. Handy if you already have the bytes (e.g. from an SSR snapshot) and just want the react-intl shape.
ICU parity
react-intl gives you the FULL ICU feature set here (plural, select, selectordinal, number/date skeletons, rich-text tags): FormatJS parses everything at render time. The nuance matters only if you ALSO read the same catalog through a transglot runtime SDK (which supports a subset) or through i18next (which is not ICU). See ICU-PARITY.md for the full matrix.
