Deliver the right entry for each language#
Languages belong to a website. Content entries are also scoped to a website and language, so an English Article and a French Article are separate records that use the same content type.
Article content type (tenant schema)
├─ Marketing website / en / hello-contoprix
└─ Marketing website / fr / hello-contoprixThis makes language selection explicit in the CMS and in the frontend.
1. Add website languages#
In the website language settings, create the languages your site will deliver.
| Name | Code | Default? |
|---|---|---|
| English | en | Yes |
| French | fr | No |
Contoprix stores language codes in lowercase and allows exactly one default language per website. Pick the default before editors create most content, because non-localized content types can only create entries in that default language.
2. Enable localization on the type#
Open the content type and enable Supports localization when editors need entries outside the default language.
| Type setting | Result |
|---|---|
| Localization off | An entry can only be created in the website's default language. |
| Localization on | An entry can be created for any configured website language. |
Choose this before creating a large content collection. It makes the intended editorial workflow obvious and prevents a non-default entry from being created by mistake.
3. Create language-specific entries#
Contoprix currently represents localized content as separate entries, not as a hidden field-by-field translation layer or a linked content-translation group. To add French for an English Article, create another Article entry for the same website and select French as its language.
Example:
| Property | English entry | French entry |
|---|---|---|
| Content type | article | article |
| Website | Marketing site | Marketing site |
| Language | en | fr |
| Title | Welcome to Contoprix | Bienvenue sur Contoprix |
| Slug | welcome | welcome or bienvenue |
The same slug can be used in different languages because slug uniqueness is scoped to website, content type, and language. Whether URLs share the slug or use translated slugs is a product decision your routing layer must make.
Important
Publishing English does not publish French. Each language-specific entry has its own draft, version history, review, and publication state.
4. Request the visitor's language#
Pass the language code on the SDK call. It overrides the shared client's default language.
import { client } from "./client";
export function getArticle(slug: string, languageCode: "en" | "fr") {
return client.content.getBySlug("article", slug, { languageCode });
}In a locale route, derive the language from the route segment:
import { getArticle } from "@/lib/contoprix/articles";
export default async function ArticlePage({
params,
}: {
params: Promise<{ locale: "en" | "fr"; slug: string }>;
}) {
const { locale, slug } = await params;
const entry = await getArticle(slug, locale);
const data = entry.data as { title?: string };
return <h1>{data.title ?? "Untitled article"}</h1>;
}Use the same language code in the route, SDK call, and website language configuration.
No automatic delivery fallback#
The delivery API looks for an entry in the exact requested language. It does not silently return English when French is missing. Decide the desired product behavior in your data layer:
| Situation | Possible product rule |
|---|---|
| French route has no French entry | Return not found |
| Marketing content may fall back | Try the default language deliberately, then show a language notice |
| Legal or regulated content | Do not fall back; require the exact language |
An explicit fallback makes caching, SEO, and visitor expectations easier to reason about. Never mix individual fields from two language entries without an intentional rule.
Localize more than body copy#
Review each language entry for:
- title, summary, and body;
- slug and canonical URL behavior;
- media selection and alt text;
- calls to action and destination links;
- selected related entries;
- metadata components or page blocks;
- publish timing and workflow approval.
For example, a French Article should usually relate to the French Author or Category entry if those records are localized too. A relation to an English-only target can be valid only when the UI is deliberately designed for it.
Page language versus content language#
Pages and content entries both accept a language code in delivery requests, but they are separate systems. A French page does not automatically choose French content unless the page block, relation, or frontend request is configured to do so. Test both the page route and the content request for every supported locale.
Localization checklist#
- One enabled default language exists for the website.
- The content type has localization enabled before non-default entries are created.
- Each required locale has its own entry, review, and publication.
- The frontend passes the visitor's locale to the SDK.
- Missing translation behavior is explicit and tested.
- Locale-specific routes and caches are revalidated after publication.
Read Content Entries for language-specific publishing and Routing for connecting locale routes to delivered pages.