Localization Strategies: Field vs Entry Level in CMS Models
This guide, part of Content Modeling Best Practices, compares the two ways a headless CMS can store translations and shows how to choose per content type. It is the modeling side of localization; the frontend side, routing and fallbacks, is covered in the localization and SEO section.
Field-level localization keeps one entry per piece of content and stores a value per locale in each translatable field. The entry’s structure, its references and block order are shared across languages. Entry-level localization, also called document-level, stores one entry per locale, linked to its translations through a shared id or a translation metadata document. Each locale’s entry can have its own structure. Contentful and Hygraph default to field-level, Sanity supports both through its internationalization plugins, Storyblok offers field-level translation and folder-level or space-level separation, and Strapi’s i18n creates separate localized entries linked by a document id.
The Problem
A software company launched in five markets with field-level localization for everything. It worked for product documentation, which is the same everywhere. It failed for marketing pages: the German team wanted a customer story block that only applied to German customers, and the Japanese team wanted a different page structure with more detail up front. Because blocks were shared across locales, every structural change applied everywhere. Teams resorted to adding blocks with empty content in other languages and hiding them in code, which made the model confusing and the pages fragile.
How Each Strategy Works
Field-level is best when locales are translations of the same content. Structure, references, media and publishing state are shared, so editors add a block once and translators fill in its text. Fallbacks are natural: a field without a German value can fall back to English at the field level. The cost is rigidity; a locale cannot add or remove blocks, and most platforms publish all locales of an entry together, although some support per-locale publishing.
Entry-level is best when locales are adaptations. Each market has its own entry with its own blocks and publishing schedule. The cost is coordination: translation links must be maintained, shared changes such as a new product image must be applied to each entry, and fallbacks work at the page level, showing the English page when no German entry exists, rather than per field.
Many models mix both. Documentation, product data and legal texts are field-level; landing pages and campaign content are entry-level. The choice is per content type, not per project.
Implementation
The frontend should not care which strategy a content type uses. Put that knowledge in the fetch layer, which returns a localized object and a flag saying whether a fallback was used, so the page can set the correct lang attribute and hreflang tags.
// lib/cms/localized.ts
type Locale = "en" | "de" | "fr" | "ja";
const FALLBACK: Record<Locale, Locale[]> = { en: [], de: ["en"], fr: ["en"], ja: ["en"] };
// Field-level (Contentful-style): one request with locale and fallback handled by the CMS.
export async function getDocPage(slug: string, locale: Locale) {
const url = new URL(`${process.env.CMS_URL}/entries`);
url.searchParams.set("content_type", "docPage");
url.searchParams.set("fields.slug", slug);
url.searchParams.set("locale", locale); // CMS applies its configured fallback chain per field
const data = await (await fetch(url, { next: { tags: [`doc:${slug}`] } })).json();
return data.items[0] ? { page: data.items[0], contentLocale: locale } : null;
}
// Entry-level (Strapi-style): try the locale, then walk the fallback chain at page level.
export async function getLandingPage(slug: string, locale: Locale) {
for (const candidate of [locale, ...FALLBACK[locale]]) {
const url = `${process.env.CMS_URL}/api/landing-pages?filters[slug][$eq]=${encodeURIComponent(slug)}&locale=${candidate}&populate=*`;
const data = await (await fetch(url, { next: { tags: [`landing:${slug}`] } })).json();
if (data.data?.[0]) return { page: data.data[0], contentLocale: candidate };
}
return null;
}
When contentLocale differs from the requested locale, the page renders the fallback content with lang set to the content’s language, and should either omit a hreflang entry for the missing locale or point it to the fallback, as described in content fallback routing.
Mixing strategies with shared references
In a mixed model, entry-level pages often reference field-level content: a German landing page references products whose names and descriptions are localized per field. Resolve those references in the page’s locale, and keep a clear rule for which content type owns which text. When the same sentence exists in both places, it will eventually be translated differently.
Editorial workflow and translation status
The strategy also shapes how translators and market teams work day to day. With field-level localization, the unit of translation is the field: when the English headline changes, the German headline is out of date, and the CMS or a translation management system needs to show that. Some platforms track this natively; elsewhere, store a hash or the revision of the source value next to each translation and flag fields where they differ. With entry-level localization, the unit is the page: market teams own their entries and decide for themselves when to follow changes in the source page. That autonomy is the point, but it needs a report that lists pages whose source changed after their translation was last updated, or markets drift further apart than anyone intended.
Whichever strategy a type uses, expose translation status to the frontend only in preview. A small banner in draft mode saying “German text is 3 revisions behind English” helps reviewers, while production pages should simply render the best available content with the right lang attribute.
Configuration Reference
| Content type | Suggested strategy | Reason |
|---|---|---|
| Documentation, help articles | field-level | Same structure everywhere, translations only. |
| Product data | field-level | Shared media and attributes, localized text. |
| Legal pages | field-level or entry-level per jurisdiction | Entry-level when the law differs, not just the language. |
| Landing and campaign pages | entry-level | Markets need different structure and timing. |
| Navigation | entry-level per market | Different pages are relevant in each market. |
| Global settings | field-level | One structure, localized labels. |
Gotchas & Edge Cases
- Non-localized fields. In field-level models, decide field by field which fields are localized. Slugs are usually localized; images often are not, but images containing text must be.
- Required fields and new locales. Adding a locale to a field-level model can make every entry invalid if translatable fields are required in all locales. Make requirements apply to the default locale only, and rely on fallbacks elsewhere.
- Orphaned translations. In entry-level models, deleting the English entry leaves translations pointing at a missing group. Validate translation groups regularly.
- Switching strategies. Moving a content type from field-level to entry-level, or back, is a large migration. Prototype with real editors before committing to one for a content type.
Worked Example
The software company kept documentation and product data field-level and moved marketing landing pages to entry-level, linked by a translation group. A migration created one entry per locale from each field-level landing page, copying blocks and localized field values, and dropping the empty placeholder blocks. The German team added its customer story block to the German page only; the Japanese team restructured its pages without affecting others. The frontend changed in one place, the fetch layer, and components saw the same shape as before.
Rollout Checklist
- Classify each content type as translation or adaptation.
- Use field-level for translations and entry-level for adaptations.
- Put strategy-specific fetching and fallback logic in the fetch layer only.
- Return the content’s actual locale so pages set
langand hreflang correctly. - Require fields in the default locale only and rely on fallbacks elsewhere.
Frequently Asked Questions
Can one content type use both strategies?
Not cleanly. Pick one per content type. If a type needs both, split it into a field-level part for shared data and an entry-level part for market-specific structure.
Which strategy is better for SEO?
Neither inherently. What matters is correct lang, hreflang and canonical tags, and avoiding thin fallback pages that duplicate the default locale. Both strategies can produce correct output.
How do translation management systems fit in?
Most TMS connectors support field-level content directly and entry-level content through translation groups. Check which your connector expects before choosing, because it will shape the editorial workflow.
What about locales that are variants, such as en-GB and en-US?
Use fallbacks: en-GB falls back to en-US field by field, so only differing fields need values. That works best with field-level localization.
How many locales can field-level localization handle?
Technically dozens, but the editing interface becomes crowded when every field shows many languages at once. Use locale filtering in the editor, and move markets that need their own structure to entry-level types rather than stretching one model across all of them. Watch query payloads too: request only the locale you render, not every locale of every field.