-
Notifications
You must be signed in to change notification settings - Fork 77
React Overlays
Translations in Fluent can include simple HTML markup. @fluent/react
will match them with props to <Localized>
. If the prop is a React element, its content will be replaced by the localizable content found in the markup the translation.
<Localized
id="create-account"
elems={{
confirm: <button onClick={createAccount}></button>,
cancel: <Link to="/"></Link>
}}
>
<p>{'<confirm>Create account</confirm> or <cancel>go back</cancel>.'}</p>
</Localized>
The overlaid result will include the source elements passed as props interpolated into the translation:
<p>
<button onClick={createAccount}>Create account</button> or <Link to="/">go back</Link>.
</p>
When @fluent/react
sees markup in the translation it parses the translation string using a <template>
element. This creates a safe inert DocumentFragment
with a hierarchy of text nodes and HTML elements. Any unknown elements (e.g. cancel
in the example above) are parsed as HTMLUnknownElements. @fluent/react
then tries to match all elements found in the translation with props passed to the <Localized>
component. If a match is found, the element passed as a prop is cloned with the translated content taken from the DocumentFragment
used as children
.
Sometimes the <template>
element isn't available for parsing the markup from the translation. This may be the case in projects which perform server-side rendering (SSR) or apps written in React Native. In these situations a custom parseMarkup
can be passed as the second argument to ReactLocalization. It will be used by all <Localized>
components connect to it via the <LocalizationProvider>
.
By using the custom markup parser, you can work around the lack of the <template>
elements in environments where document
is not defined. You can use jsdom
or cheerio
, or any other available DOM implementation or an XML/HTML parser. Or, you can choose to ignore the fact that translations may include HTML. If you do, please make sure your localizers know about this limitation.
The parseMarkup
function must have the following signature:
parseMarkup(str: string): Array<Node>
It takes a string and must return an array of objects partially implementing the DOM Node interface. Only the following 2 properties are strictly required:
nodeName
textContent
// This custom markup parser doesn't actually parse anything,
// but it pretends to have parsed a single Node. This node
// contains the entire contents of the string passed into
// the parser, converted to upper case.
function parseMarkup(str) {
return [
{
nodeName: "#text",
textContent: str.toUpperCase()
}
];
}
let l10n = new ReactLocalization(bundles, parseMarkup);
<LocalizationProvider l10n={l10n}>
<App />
</LocalizationProvider>