Copies vs. Connections: Modeling Content Areas for Multilingual Success
Starting With the Simple Question
Most multilingual content modeling conversations start with a deceptively simple question from a client:
"If we set this image once in English, will it show up automatically in French?"
It sounds like a yes-or-no question. In Optimizely SaaS CMS, the honest answer is: it depends entirely on how that image was modeled.
Before diving into anything complex, here are three quick sanity checks worth running on your own project. If you can answer all three confidently, you are probably in good shape:
-
Open a translated page in your CMS. Change something in the master language. Does the translated version follow, or stay as it was?
-
Look at a Content Area in the editor. Can you tell, at a glance, what each item inside it actually is?
-
Ask a translator to open a page. Do they immediately know which field maps to which part of the design?
If any of those made you pause, this post is written for you. Nothing here is exotic or advanced. It is simply about understanding what the platform stores where, and choosing shapes that match what your editors and translators actually need.
This is an area where reasonable teams land on different answers, so treat what follows as a starting point for your own discussion rather than a fixed rule set.
Designing for Both the Code and the Editor
One of the genuine strengths of Optimizely SaaS CMS is its code-first, headless approach. Developers define content types directly in TypeScript and push them straight to the CMS, keeping the model in version control alongside the front-end application.
But a content model is not only a database schema or a GraphQL query shape. It is also the daily interface for your editorial team.
When we model content, we are designing the workspace that authors, content managers, and translators will live in. Model purely for developer convenience and it is easy to hand editors something that is awkward to navigate, fragile across languages, and difficult to translate cleanly.
This post focuses on one specific area of that decision space: Content Areas, and how the items inside them behave once you introduce a second language.
The Core Building Blocks
There are three primary ways to structure content within a page or experience in Optimizely SaaS CMS.
Flat properties are scalar fields defined directly on the content type, such as a string, a contentReference, or a boolean. They are simple, predictable, and the easiest to reason about across languages.
Embedded components are nested data structures stored inside the parent page's data as a cohesive group. Their lifecycle is bound to the parent, so publishing the page publishes the component with it.
Content arrays are the headless equivalent of a Content Area. They hold a collection of content items, and those items can be one of two kinds:
-
Shared blocks are reusable items that live in the Assets panel with their own publishing workflow and their own locale branches.
-
Inline blocks are created on the fly inside the Content Area. They have no independent identity and their lifecycle is tied entirely to the parent page.
Each of these is a good fit for something. The interesting question is which one fits the requirement in front of you.
The SHARED Label: A Signal Worth Teaching
One of the most useful affordances in the CMS editing interface is a small label: SHARED.
When an author opens a Content Area, each item inside it is visually marked:
-
Shared blocks show a SHARED badge next to their name.
-
Inline blocks show no badge at all.
This is not decoration. It is a live signal about editorial reach:
If you see SHARED, this block is a connected item. Editing it affects every page that references it, and for non-localizable properties it updates all language versions at once.
An inline block, by contrast, is a private copy owned by that one page. On screen the two look almost identical. The consequences of editing them are quite different.
This is worth five minutes in editor onboarding. It is one of the simplest ways to prevent a well-meaning edit from rippling further than anyone intended.
Naming Habits: Small Effort, Large Payoff
When an author creates an inline block inside a Content Area, the CMS offers a Name field. It is optional. Leave it blank and the CMS fills it with the content type name.
The code compiles and the API returns everything correctly. But let's look at what actually happens in the editor's workspace on a multilingual site when we don't establish a naming standard.
Imagine an editor builds a Modular Landing Page using a Content Area, where they can add a flexible sequence of blocks: a hero banner, three promotional cards, and a call-to-action button. Because a landing page is highly dynamic, a flexible Content Area is exactly the right tool.
However, if they leave the optional Name fields blank during block creation, the CMS defaults each name to the block's content type (such as PromoCard or HeroBanner).
Here is what the English and French editors see side-by-side in their page editor:
THE UNNAMED PAIN POINT (What the translator sees)
English Page French Page (Copied)
Landing Page Landing Page
|- HeroBanner |- HeroBanner
|- PromoCard |- PromoCard
|- PromoCard |- PromoCard
|- PromoCard |- PromoCard
|- CTABlock |- CTABlock
The Problem: The list is completely anonymous. If the French translator wants to translate the text for the "Free Shipping" card vs. the "20% Discount" card, they have no idea which PromoCard is which. They have to click and open every single inline block on both sides of the screen to match them up. This turns a straightforward translation task into a tedious guessing game.
A Convention That Solves It
Now look at the difference when we introduce a simple, structured naming convention. If we instruct authors to prefix their inline blocks with a simple numeric order and a functional marketing label, the translation workspace transforms:
THE NAMED BEST PRACTICE (Effortless translation)
English Page French Page (Copied)
Landing Page Landing Page
|- 1. Hero - Summer Promo |- 1. Hero - Summer Promo
|- 2. Card - Free Shipping |- 2. Card - Free Shipping
|- 3. Card - 20% Discount |- 3. Card - 20% Discount
|- 4. Card - New Arrivals |- 4. Card - New Arrivals
|- 5. CTA - Sign Up |- 5. CTA - Sign Up
The Benefit: Because the names are cloned during the copy-to-language flow, the French translator immediately knows the context of each block. They click exactly the card they want, translate the English text to French, and can optionally update the block names if they choose. The page layout remains perfectly clear, organized, and predictable.
For shared blocks, a meaningful name is even more critical because that name appears in the global Assets panel where every editor on the project finds, filters, and manages them:
Assets panel
|- Global Blocks
|- Homepage Hero Banner (SHARED)
|- Q3 Promo CTA (SHARED)
Agreeing this convention before the first content entry session is a small investment that keeps paying off as the site grows.
The Multilingual Flow: Copies and Connections
Optimizely SaaS CMS makes creating a language variant straightforward. When you add a French version of an English page, the CMS offers to copy content from English, duplicating the structure and cloning the inline block data so translators start from a complete page rather than a blank one.
What happens after that copy depends on whether the items are inline or shared.
Inline Blocks: A Snapshot in Time
Inline blocks have no independent key, so they belong entirely to the language version of the page that owns them. Once the copy is made, the two sets of blocks are separate. Update the image in the English block and the French page keeps the one it already had. Fix a typo in English and the French text stays as it was. Add or reorder blocks in English and the French arrangement is unaffected.
This is reasonable behaviour, and for some teams it is exactly what they want. It gives regional editors complete freedom to shape their own market's content without a central team overwriting their work. The trade-off is that any master-language change needs to be applied again in each translated version.
Where this catches teams out is when the expectation was the opposite. If a client believes they are setting a value once for all markets, this is the moment to talk it through.
Shared Blocks: A Genuine Connection
Shared blocks are content items in their own right, with their own key and their own locale branches. When both the English and French pages reference the same shared block, they are pointing at the same item.
For properties marked as non-localizable, the value is held once and served to every language version of that block. Change it in the master language and all languages reflect it. In the editor, those fields appear as read-only when working in a non-master language, with an indicator showing where the value comes from.
For properties marked as localizable, each locale branch keeps its own value, exactly as you would expect for translatable text.
The Localizable Setting
The SDK exposes a localizable flag on property definitions. Setting it to false means one shared value across languages; setting it to true means a unique value per language version.
export const ImageWithAltCT = contentType({
key: 'ImageWithAlt',
baseType: '_component',
properties: {
image: {
type: 'contentReference',
allowedTypes: ['_image'],
displayName: 'Image',
localizable: false,
},
altText: {
type: 'string',
displayName: 'Alt text',
localizable: true,
},
},
});
The CLI maps this to the Unique value per language setting on the property when types are pushed to the CMS.
Where the Setting Creates a Connection
This is the part most worth internalising, because the same setting behaves differently depending on where the property lives.
|
Where the property lives |
Effect of setting localizable to false |
|
Flat property on a page |
One value shared by every language version of that page. Change it in the master language and all locales reflect it. |
|
Property on a shared block |
One value shared across all locale branches of that block. Both the English and French pages referencing it see the update. |
|
Property inside an inline block |
The setting still governs whether the field is translatable, but there are two separate anonymous copies. A change in the English copy does not reach the French copy. |
The underlying principle is straightforward once you see it: a shared value needs something stable to attach to. Flat properties and shared blocks both have a stable identity. Inline blocks do not, so there is nothing for the two language versions to share.
Pairing Shared Blocks With Localizable Settings
When you need grouped content, such as an image with its alt text, and that group needs to behave sensibly across languages, combining a shared block with selective localizable settings is a clean approach worth considering.
Using the definition above as a shared block, referenced from both the English and French pages, gives you this behaviour:
|
Action |
Result |
|
English editor selects a different image |
French page shows the new image, since the property is non-localizable on a shared item |
|
French translator updates the French alt text |
English alt text is unaffected |
|
English editor updates the English alt text |
French alt text is unaffected |
The result is the split many multilingual projects are reaching for: shared structural assets, independently translated text, enforced by the platform rather than by editorial vigilance.
Worth noting honestly: this pattern also means the shared block is genuinely shared. Editing it affects every page referencing it. That is the intent, but it should be a deliberate choice rather than a side effect, and the SHARED badge is what makes it visible to authors.
Choosing Between Flat Properties and Shared Blocks
Both approaches keep languages aligned. The question that usually separates them is whether the content is genuinely reused.
|
Scenario |
Approach worth considering |
|
Image and alt text in one fixed slot on one page |
Flat contentReference set to non-localizable, plus a flat string set to localizable |
|
The same grouped structure appearing on many pages |
A shared block with the image non-localizable and the alt text localizable |
|
Analytics identifiers or configuration values |
A flat string set to non-localizable on the parent type |
|
A centrally managed promo banner or CTA |
A shared block, structural fields non-localizable, headline localizable |
A reasonable rule of thumb: if nobody can name two pages today where the same instance genuinely needs to update together, starting with flat properties keeps things simple. Moving to a shared block later is a one-time migration. Unwinding a shared block that turned out not to be shared is usually more work.
A Practical Example: Analytics Container IDs
Consider a tracking container ID that needs to be present across the site.
Placed inside an inline block within a Content Area, it gets copied into each language version when the variant is created. If that ID ever changes, someone needs to open every language version of every page holding it and update the field individually. On a site with ten languages and fifty pages, that is a lot of repetitive edits for a single value.
Modeled as a flat property on the parent type with localizable set to false, the same change is made once in the master language and every language version reflects it.
The useful distinction here is that a tracking ID is not translatable content at all. It is configuration. Recognising which of your fields are configuration rather than content often makes the modeling choice obvious.
What Happens If an Author Deletes a Block
This question comes up on most projects, and the answer is more reassuring than teams often expect.
Inline blocks do not appear in the global Trash, because they are not standalone items. Deleting one is closer to clearing a property value on the parent page. However, the parent page's version history does cover them.
Every save and publish creates a revision in the Versions gadget, and rolling back to an earlier revision restores the Content Area as it was, including the inline blocks it contained. For everyday accidental deletions, this works well.
There are limits worth knowing. The Versions gadget holds a 20-version history, so if a deletion goes unnoticed across many subsequent publishes, the revision containing the block can age out. The documentation is also explicit that content versions are not covered by trash management, meaning a version deleted directly from the gadget is permanently gone.
Shared blocks behave differently here in a way that favours them: because they are standalone items, they do go to the Trash and can be restored independently of the pages referencing them.
A Decision Matrix to Discuss With Your Team
This is offered as a conversation starter rather than a prescription. Your team's editorial workflow may well justify different choices.
|
Requirement |
Approach worth considering |
Reasoning |
|
A fixed slot unique to one page |
Flat contentReference and string properties |
Structure stays locked, image can be shared across languages, alt text stays per language |
|
The same grouped structure on many pages |
A shared block with mixed localizable settings |
One instance referenced everywhere, with the SHARED badge making the reach visible |
|
Configuration values identical everywhere |
A flat string set to non-localizable |
One edit updates all languages |
|
Centrally managed reusable content |
A Content Area holding shared blocks |
Managed from the Assets panel, changes propagate to all referencing pages |
|
Genuinely flexible author-composed layouts |
A Content Area holding inline blocks |
Full composition freedom, with the naming convention and language copy flow documented for the team |
Questions Worth Asking Before You Model
Running through these with your technical and editorial teams tends to surface the right answer quickly.
Is the item count fixed by the design? If the layout always calls for exactly three slots, flat properties express that more directly than an array.
Should any field update everywhere when the master language changes? If so, a flat property or a shared block will give you that. An inline block will not.
Is this content genuinely reused across pages today? If no one can name two specific pages, starting simple is usually the safer bet.
Are we planning to use an external translation service? Stable named properties are generally easier for translation tooling to map reliably than nested arrays of anonymous items. This is worth validating with your specific vendor before committing.
Have editors been shown what the SHARED badge means? A short walkthrough prevents a lot of surprises.
Have we agreed a naming convention? Documenting it before the first content session is far easier than retrofitting it later.
Wrapping Up
Optimizely SaaS CMS gives teams a genuinely flexible toolkit here. Flat properties, embedded components, inline blocks, and shared blocks each serve a real purpose, and the localizable setting gives you fine-grained control over which values travel with translations and which stay anchored to one source of truth.
If there is one idea worth carrying into your next modeling conversation, it is this:
A shared value needs a stable identity to attach to. Flat properties and shared blocks have one. Inline blocks, by design, do not.
Everything else tends to follow from that. Decide deliberately, write the decisions down, walk your editors through the SHARED badge, and test the language copy flow on a real page before go-live rather than after.
I would genuinely like to hear how other teams are approaching this. Multilingual modeling is one of those areas where the best answer often depends on how a specific editorial team works day to day, and there is a lot to learn from comparing notes.
How is your team handling Content Areas across languages?
If you enjoyed this technical breakdown, you’ll like my monthly newsletter, Pragmatic Judgement. I write about where technical decisions meet real operational constraints for tech and delivery leaders.
Comments