patternjavascriptMajor
Interpolation and Rich Text in Translation Strings
Viewed 0 times
i18n rich textinline elements translationTrans componentFormattedMessage richinterpolation reacttranslation markup
Problem
Translation strings that contain inline HTML elements (bold text, links) cannot be stored as raw HTML without creating security vulnerabilities or losing markup on some locales.
Solution
Use the rich text support provided by your i18n library. Pass renderers as values instead of raw markup strings.
// react-intl rich text
// en.json: { "tos": "By signing up you agree to our <link>Terms of Service</link>" }
<FormattedMessage
id="tos"
values={{
link: (chunks) => <a href="/tos">{chunks}</a>,
}}
/>
// next-intl rich text
// en.json: { "tos": "By signing up you agree to our <link>Terms of Service</link>" }
const t = useTranslations('auth');
t.rich('tos', {
link: (chunks) => <a href="/tos">{chunks}</a>,
});
// react-i18next Trans component
// en.json: { "welcome": "Welcome <bold>{{name}}</bold>!" }
import { Trans } from 'react-i18next';
<Trans i18nKey="welcome" values={{ name: 'Alice' }}
components={{ bold: <strong /> }}
/>Why
Injecting raw HTML strings from translation files into the DOM is an XSS risk. Rich text APIs allow translators to use safe placeholder tags while the component layer controls what each tag renders.
Gotchas
- Never render translator-supplied strings as raw HTML markup in the DOM — translators could inadvertently introduce unsafe content.
- Ensure translators know what placeholder tags mean (e.g.,
<link>renders as a hyperlink) via context notes in your TMS. - The tags in translation strings must be consistent across locales — if a translator omits the
<link>tag, the link disappears in their locale. - Test all locales for correct wrapping — some languages reorder sentence structure, which can break inline elements.
Revisions (0)
No revisions yet.