Formatting Dictionary Items in Sitecore XM Cloud Headless with a Custom Dictionary Text Parser
Sitecore XM Cloud is powerful for multilingual and personalized experiences, but when it comes to formatting localized dictionary items, it falls short out of the box. In this post, you’ll learn how to use a custom React parser that adds support for <b>
tags, newline rendering, and dynamic placeholders. This approach is safe, scalable, and easily extendable for additional HTML or markdown-style formatting.
Why You Need This
Sitecore dictionary items are designed for simple text localization. However, modern UX often demands:
- Bold emphasis
- Multi-line messages
- Dynamic variables (like dates, names, values)
- Clean, safe React rendering without using
dangerouslySetInnerHTML
What We’ll Build
We’ll create a custom dictionary text parser designed to be reusable across Sitecore XM Cloud projects. It is intended to parse and render dictionary items that include:
A custom parser with:
<b>
tag parsing\n
newline rendering as<p>
or<span>
{placeholder}
replacements with dynamic values- Easily extendable pattern for supporting other tags (
<i>
,<u>
, etc.)
The Code: Custom Text Parser
The full code is now maintained in a single, easy-to-import file: dictionaryParser.tsx
Below is the complete code for quick reference or direct copy-paste into your project:
import React, { ReactNode } from "react";
/**
* Parses bold tags in a line of text
* @param line - The line to parse
* @returns Array of React elements with bold formatting
*/
const parseBoldTags = (line: string): ReactNode[] => {
return line.split(/(<b>.*?<\/b>)/).map((part, j) => {
if (part.startsWith("<b>") && part.endsWith("</b>")) {
const boldText = part.slice(3, -4);
return <b key={j}>{boldText}</b>;
}
return part;
});
};
/**
* Parses text containing newlines and bold tags into React elements
* @param text - The text to parse
* @param tag - The HTML tag to wrap each line in ('p' or 'span')
* @returns Array of React elements with proper formatting
*/
export const parseFormattedText = (
text: string,
tag: "p" | "span" = "p"
): ReactNode[] => {
const Tag = tag; // Capitalize for JSX
return text
.split("\n")
.map((line, i) => <Tag key={i}>{parseBoldTags(line)}</Tag>);
};
/**
* Replaces placeholders in text with provided values
* @param text - The text containing placeholders
* @param replacements - Object containing placeholder keys and their replacement values
* @returns Text with placeholders replaced
*/
export const replacePlaceholders = (
text: string,
replacements: Record<string, string>
): string => {
let result = text;
Object.entries(replacements).forEach(([key, value]) => {
result = result.replace(`{${key}}`, value);
});
return result;
};
This utility:
- Parses
<b>
tags into React<b>
elements - Handles newlines (
\n
) by wrapping each line in a specified tag (like<p>
) - Supports placeholder replacement using
{key}
syntax - Is written in TypeScript for full type safety
What Each Function Does
parseBoldTags
Takes a string and finds segments wrapped in <b>
and returns them as React <b>
elements, preserving other parts of the string as plain text.
parseFormattedText
Splits the input string by newlines \n
and wraps each resulting line in a tag (<p>
or <span>
), then passes each line through parseBoldTags
to format any <b>
tags.
replacePlaceholders
Searches for {placeholder}
keys in the string and replaces them with the corresponding values provided in a key-value object, allowing dynamic content like dates or names to be injected safely.
You can import everything from this one file in your project.
import {
parseFormattedText,
replacePlaceholders
} from '@/utils/dictionaryParser';
Example Usage in Sitecore XM Cloud
Dictionary item:
You’re outside your period <b>{startDate}</b> to <b>{endDate}</b>.
Component usage:
<div className="text-sm p-3">
{parseFormattedText(
replacePlaceholders(translations.outsidePeriod, {
startDate: now(),
endDate: addDays(now(), 2)
}),
'p'
)}
</div>
Extending This Parser
This parser is designed to be easily extendable. You can add support for additional tags beyond <b>
by expanding the tag parsing logic. Here's an example of how to support <i>
and <u>
tags using a more general parser function:
Support <i>
and <u>
Tags
const parseCustomTags = (line: string): ReactNode[] => {
return line.split(/(<\/?[a-z]+>.*?<\/[a-z]+>)/).map((part, i) => {
if (part.match(/^<b>.*<\/b>$/)) {
return <b key={i}>{part.slice(3, -4)}</b>;
}
if (part.match(/^<i>.*<\/i>$/)) {
return <i key={i}>{part.slice(3, -4)}</i>;
}
if (part.match(/^<u>.*<\/u>$/)) {
return <u key={i}>{part.slice(3, -4)}</u>;
}
return part;
});
};
Best Practices and Gotchas
Do | Don’t |
---|---|
Use consistent tag structure | Forget closing tags like </b> |
Always sanitize dynamic data | Use dangerouslySetInnerHTML |
Wrap each line with semantic tags | Hard-code HTML into dictionary values |
Integration with Sitecore Dictionary Hook
We retrieve and update dictionary values using a custom hook with useEffect
to support dynamic values in the client-rendered app, as described in this blog post.
const t = useDictionary();
const message = t.outsidePeriod;
const content = parseFormattedText(
replacePlaceholders(message, {
startDate: now(),
endDate: addDays(now(), 2),
})
);
Future Ideas
- Support markdown-like syntax (
*bold**
,_italic_
) - Create a reusable hook like
useParsedText(key, replacements)
- Add unit tests for parsing logic
- Build a visual formatter in Sitecore editing UI
How to Use This in Your Project
You can use the parser by copying just one file: dictionaryParser.tsx
from the official repository.
# Suggested folder structure
src/
utils/
dictionaryParser.tsx
Then import and use it directly in your components:
import {
parseFormattedText,
replacePlaceholders
} from '@/utils/dictionaryParser';
Final Thoughts on Sitecore Dictionary Parser
This parser is intentionally lightweight — the parsing logic is fast and has negligible impact on render performance, even when used frequently in client-rendered dictionary content. It does not rely on any heavy parsing libraries or runtime DOM manipulation.
This approach allows you to get the most out of Sitecore dictionary items while keeping your codebase clean and maintainable. By supporting rich formatting, dynamic placeholders, and extensibility in a single utility file, you can dramatically improve the flexibility and user experience of your localized content in Sitecore XM Cloud.
Whether you're building a small POC or a scalable enterprise app, this lightweight parser bridges the gap between Sitecore's backend content management and your React-based frontend rendering.
Have ideas to improve it or want to contribute? Fork the project or submit a pull request on GitHub!