Content & i18n
Content strings are localized key-value pairs for your site's UI. Use them for headings, labels, CTAs, and any text that needs to be editable or translated without redeploying.
How Content Strings Work
Content strings are organized as key-value pairs per locale. Use dot notation for namespacing: hero.title, hero.subtitle, footer.copyright.
Manage them in the CMS dashboard under the Content section. Each string can have a different value per locale (French, English, etc.).
Fetching Content
Fetch all content for a locale
const res = await fetch(
`${CMS_URL}/api/public/content?locale=fr`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const { content } = await res.json();
// content = { "hero.title": "Bienvenue", "hero.subtitle": "Sur notre site" }const res = await fetch(
`${CMS_URL}/api/public/content?locale=fr`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const { content } = await res.json();
// content = { "hero.title": "Bienvenue", "hero.subtitle": "Sur notre site" }Fetch specific keys
// Single key
const res = await fetch(
`${CMS_URL}/api/public/content?key=hero.title&locale=en`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const { value } = await res.json(); // "Welcome"
// Multiple keys
const res2 = await fetch(
`${CMS_URL}/api/public/content?keys=hero.title,hero.subtitle&locale=en`,
{ headers: { "x-api-key": CMS_API_KEY } }
);// Single key
const res = await fetch(
`${CMS_URL}/api/public/content?key=hero.title&locale=en`,
{ headers: { "x-api-key": CMS_API_KEY } }
);
const { value } = await res.json(); // "Welcome"
// Multiple keys
const res2 = await fetch(
`${CMS_URL}/api/public/content?keys=hero.title,hero.subtitle&locale=en`,
{ headers: { "x-api-key": CMS_API_KEY } }
);Using Content in Your Site
Example: content helper
// lib/content.ts
export async function getContent(locale: string) {
const res = await fetch(
`${process.env.CMS_URL}/api/public/content?locale=${locale}`,
{
headers: { "x-api-key": process.env.CMS_API_KEY! },
next: { revalidate: 60 },
}
);
const { content } = await res.json();
return (key: string) => content[key] ?? key;
}
// In a page
const t = await getContent("fr");
// t("hero.title") -> "Bienvenue"
// t("missing.key") -> "missing.key" (fallback)// lib/content.ts
export async function getContent(locale: string) {
const res = await fetch(
`${process.env.CMS_URL}/api/public/content?locale=${locale}`,
{
headers: { "x-api-key": process.env.CMS_API_KEY! },
next: { revalidate: 60 },
}
);
const { content } = await res.json();
return (key: string) => content[key] ?? key;
}
// In a page
const t = await getContent("fr");
// t("hero.title") -> "Bienvenue"
// t("missing.key") -> "missing.key" (fallback)Content Preview
Use the preview endpoint to test content changes before publishing. Pass overrides to see how they'd look:
Preview with overrides
const res = await fetch(`${CMS_URL}/api/public/content/preview`, {
method: "POST",
headers: {
"x-api-key": CMS_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
locale: "fr",
overrides: {
"hero.title": "New Title Being Tested",
},
}),
});
const { content, overridesApplied } = await res.json();const res = await fetch(`${CMS_URL}/api/public/content/preview`, {
method: "POST",
headers: {
"x-api-key": CMS_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
locale: "fr",
overrides: {
"hero.title": "New Title Being Tested",
},
}),
});
const { content, overridesApplied } = await res.json();