How to Manage Content Consistency in AEM When Only Languages Exist | Community
Skip to main content
arifhoque
Level 1
January 21, 2026
Question

How to Manage Content Consistency in AEM When Only Languages Exist

  • January 21, 2026
  • 2 replies
  • 60 views

We are working on an AEM project where the site structure is language-only, for example:

/content/site/global/en
/content/site/global/de
/content/site/global/fr
/content/site/global/es

There is no country structure

For translation management, we are using Phrase/Microsoft translation, and technically the translation flow is working as expected. However, over time we are facing serious content inconsistency issues across languages. Because there is no Master + Live Copy (MSM) setup

Phrase only handles translation when content is explicitly sent, but:

  • It does not enforce that all languages are updated
  • It does not guarantee structural/content parity across languages

After some time, each language version of the same page looks different:

  • Missing components/pages
  • Different layouts
  • Outdated text in some languages

We are trying to find a scalable and maintainable approach to ensure:

  • Content consistency across all languages
  • A clear “source of truth”
  • Less manual rollout effort
  • Better control over what is translated and what is missing

2 replies

giuseppebaglio
Level 10
January 22, 2026

hi ​@arifhoque,

Designate English as the master where all authoring occurs, keeping other languages as language copies (reference). This setup let yous leverages AEM's out-of-the-box translation workflow, which detects missing pages/components during project creation and treats them as initial translations or updates via launches. 
AEM translation projects centralize content from a master language (e.g., English) for systematic translation into language copies like French, automatically handling missing pages by creating them and outdated ones via launches for review.

Language copies inherit structure from the English master, ensuring identical page hierarchies and component layouts across de/fr/es. Translation projects automatically detect and resolve drift—missing pages get created, outdated content routes through launches for safe updates, eliminating the structural inconsistencies (reference)
 

PGURUKRISHNA
Level 4
January 23, 2026

Hi ​@arifhoque 

Implement MSM with Language Masters 

Recommended Approach: Introduce MSM even without a country structure by designating one language as the master.

Structure:

/content/site/global/en (Master)
/content/site/global/de (Live Copy)
/content/site/global/fr (Live Copy)
/content/site/global/es (Live Copy)

 

Key Benefits:

  • Structural consistency enforced automatically

  • Rollout ensures all languages get updates

  • Clear source of truth (English as master)

  • Phrase handles only text translation, MSM handles structure

Implementation Steps:

  1. Create Live Copies from English master:

    • Use AEM's Create Live Copy wizard

    • Set rollout configs to 

      Standard rollout config
       or custom
  2. Configure Rollout Config (

    /apps/[project]/rolloutconfigs/custom
    ):
    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0"
    xmlns:jcr="http://www.jcp.org/jcr/1.0"
    jcr:primaryType="cq:RolloutConfig"
    jcr:title="Translation Rollout Config"
    cq:trigger="rollout">
    <contentUpdate jcr:primaryType="cq:LiveSyncAction"
    cq:action="contentUpdate"/>
    <contentDelete jcr:primaryType="cq:LiveSyncAction"
    cq:action="contentDelete"/>
    </jcr:root>

     

     

  3. Create Translation-Aware Action Filter (

    /apps/[project]/msm/TranslationActionFilter.java
    ):
    @Component(service = LiveActionFactory.class)
    public class TranslationActionFilter implements LiveActionFactory<LiveAction> {

    @Override
    public LiveAction createAction(Resource config) {
    return (resource, liveRelationship, actionConfig, autoSave) -> {
    // Skip translatable properties during rollout
    ValueMap props = resource.getValueMap();
    ModifiableValueMap targetProps = resource.adaptTo(ModifiableValueMap.class);

    String[] excludeProps = {"jcr:title", "jcr:description", "text", "title"};

    for (String key : props.keySet()) {
    if (!Arrays.asList(excludeProps).contains(key)) {
    targetProps.put(key, props.get(key));
    }
    }
    };
    }
    }

     

    CopyInsert at cursorjava

  4. Workflow:

    • Author creates/updates content in 

      /en
    • Rollout to all language copies (structure + non-translatable content)

    • Send only text properties to Phrase

    • Phrase updates translated properties only

arifhoque
arifhoqueAuthor
Level 1
January 23, 2026

@PGURUKRISHNA We tried a similar approach. In that approach what we did is created live copy from master after that we ran Phrase translation project. But it broke the inheritance from the parent content. 

PGURUKRISHNA
Level 4
January 23, 2026

 ​@arifhoque  Ah, that's a common issue! When translation updates properties, it breaks MSM inheritance. Here's the solution:1. OSGi Configuration - Exclude Translation Properties

Path: 

/apps/wknd/config.author/com.day.cq.wcm.msm.impl.actions.ContentUpdateActionFactory-translation.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
cq.wcm.msm.action.excludedprops="[jcr:title,jcr:description,text,title,alt,description,actionText,linkText,pretitle]"
cq.wcm.msm.action.excludednodetypes="[cq:Page]"
cq.wcm.msm.action.excludedparagraphitems="[]"/>

 

2. Custom Rollout Configuration

Path: 

/apps/wknd/rolloutconfigs/translationRollout/.content.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:RolloutConfig"
jcr:title="Translation Rollout"
jcr:description="Rollout structure only, exclude translatable properties"
cq:trigger="rollout">
<contentUpdate
jcr:primaryType="cq:LiveSyncAction"
cq:action="contentUpdate"/>
<contentDelete
jcr:primaryType="cq:LiveSyncAction"
cq:action="contentDelete"/>
<referencesUpdate
jcr:primaryType="cq:LiveSyncAction"
cq:action="referencesUpdate"/>
</jcr:root>

 

 

3. Translation Configuration

Path: 

/apps/wknd/config/com.adobe.granite.translation.core.impl.TranslationManagerImpl.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
translate.attachWorkflow="false"
translate.inheritanceBreak="false"/>

 

Setup Steps

Step 1: Deploy Configuration

mvn clean install -PautoInstallPackage

 

Step 2: Create Live Copies (One-Time)

  1. Go to Sites → 

    /content/site/global/en
  2. Select root page → Create → Live Copy

  3. Title: 

    German
    , Path: 
    /content/site/global/de
  4. Rollout Config: Translation Rollout

  5. Click Create

  6. Repeat for 

    fr
    es

Step 3: Workflow

1. Author content in /en
2. Rollout → Select all languages → Rollout
(Copies structure, NOT text)
3. Create Translation Project → Select Phrase
4. Phrase translates text properties
5. Translation updates live copies (inheritance NOT broken)