Expand my Community achievements bar.

Submissions are now open for the 2026 Adobe Experience Maker Awards.

How to make experience fragment variations in page templates language-aware and site-aware (agnostic)?

Avatar

Level 1

Assume I have the following setup:

Two sites with both english and french content pages

 

/content/siteAAA/language-masters/en

/content/siteAAA/language-masters/fr

 

/content/siteBBB/language-masters/en

/content/siteBBB/language-masters/fr

 

Site AAA was created first and all my page templates are defined in its conf folder. E.g.
/conf/siteAAA/settings/wcm/templates/best-product

Now I also want to use the exact same page templates for Site BBB


First challenge: how to make the variation language-aware

 

In my "best-product"  page template, I have configured two experience fragments, one for the header and one for the footer. The path to include this from the page template is pointing to the english version

/content/experience-fragments/siteAAA/language_masters/en/site/header/master

Now, both english and french pages using this best-product page template show only the english header XF

/content/siteAAA/language-masters/en/buy-this

/content/siteAAA/language-masters/fr/buy-this
But maybe I want a different header on my french pages, so I want the page template and experience fragment to be language-context-aware, and use the FR sibling in the experience-fragments folder.
How can this be achieved? Obviously I do not want to create a copy of all page templates for every language, to point to their own hardcoded experience fragment path.


Second challenge: how to also make the variation site-aware
Now since I have another site also using the same page templates, I want the path to include the experience fragment variation to be site-aware as well as language aware

In other words, I only have ONE generic page template with only ONE header experience fragment configured, and

Page /content/siteAAA/language-masters/en/buy-this
Uses XF /content/experience-fragments/siteAAA/language_masters/en/site/header/master

 

Page /content/siteAAA/language-masters/fr/buy-this
Uses XF /content/experience-fragments/siteAAA/language_masters/fr/site/header/master

 

Page /content/siteBBB/language-masters/en/buy-this
Uses XF /content/experience-fragments/siteBBB/language_masters/en/site/header/master

 

Page /content/siteBBB/language-masters/fr/buy-this
Uses XF /content/experience-fragments/siteBBB/language_masters/fr/site/header/master

 

How can this be achieved?

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

3 Replies

Avatar

Level 10

hi @MeasurableBusinessResults,

One possible approach is to resolve the Experience Fragment path at render time by utilizing Sling Context-Aware Configuration (CAC) for site- and language-specific base paths. This can be combined with a simple Sling Model that determines the current page's site and language root, allowing it to dynamically build the correct XF variation path.

While using CAC is recommended, it is not mandatory. If you can establish a single pattern that you are confident will not change, you could also set this pattern as a field in an OSGI configuration.

 

Implementation steps:

  • Define a CAC model (e.g., com.example.site.header) with properties like headerXfRoot=/content/experience-fragments/{site}/language_masters/{language} and footerXfRoot similarly
  • Define a proxy Sling Model of Experience Fragment component where you override the method getLocalizedFragmentVariationPath
  • In the Sling Model bound to the header/footer component, you will resolve both site and language page (with getAbsoluteParent)  to derive their node names, finally you will replace the placeholders from above-mentioned pattern

  • Update your template to use the component resource type bound to the new Sling Model implementation

Do not forget to provide a robust fallback sequence: localized XF → site default XF → global default XF, so missing locales don’t break page rendering.

 

Avatar

Community Advisor

Hi @MeasurableBusinessResults,

I think, for your case you don’t really need to duplicate page templates - you can solve it in two main ways:

  • Use Context-Aware Config (CAC):
    Put a config at the site/language root that says where the header/footer XF should live. Then, when the page renders, the component looks up CAC and automatically pulls the right localized XF. This way, your French page will get the FR header without you hardcoding paths.

  • Or (IMO simpler if your folder structure is strict):
    Don’t even store configs. Just calculate the XF path dynamically based on the current page. From the page path you already know the site (siteAAA vs siteBBB) and the language (en vs fr). Your Sling Model can take those values and build the path pattern like:

    /content/experience-fragments/{site}/language_masters/{language}/site/header/master

    That way the same template works for all sites and languages.

In practice, I’d probably go with CAC if you expect flexibility (paths may change, not always consistent). If your sites follow a fixed pattern, then the runtime calculation is lighter and easier.

Either way you only keep one generic page template, and the header/footer XF will always resolve to the right variation.


Santosh Sai

AEM BlogsLinkedIn


Avatar

Level 2

Got it — you want to avoid duplicating your page templates per language/site and instead have them dynamically resolve the correct Experience Fragment (XF) based on the page context (site + language). This is a very common AEM multi-site / multi-language setup challenge.

Let’s break this down step by step.

🧩 Problem Summary

You have one template (/conf/siteAAA/.../best-product) used across multiple sites (siteAAA, siteBBB) and multiple languages (en, fr).

Template includes XFs for header/footer, currently hardcoded to /content/experience-fragments/siteAAA/language_masters/en/...

You want:

Language-aware resolution: French pages use FR XF, English pages use EN XF.

Site-aware resolution: SiteBBB pages use SiteBBB XF (not SiteAAA’s XF).

Single template maintenance: No duplicate templates per site or language.

Recommended Approach: Dynamic XF Path Resolution
1. Use Context-Aware Configuration or Dynamic Path Resolution in the Component

Instead of hardcoding /content/experience-fragments/siteAAA/... in your template, configure the relative path or a property that can be resolved dynamically at runtime.

You have two main strategies:

Option A: Context-Aware Config (Caconfig) + Sling Model

Store the XF root path in Caconfig

Define a context-aware configuration under /conf/siteAAA and /conf/siteBBB:

/conf/siteAAA/settings/cloudconfigs/xf-config
+ headerXFRoot = /content/experience-fragments/siteAAA/language_masters
+ footerXFRoot = /content/experience-fragments/siteAAA/language_masters

/conf/siteBBB/settings/cloudconfigs/xf-config
+ headerXFRoot = /content/experience-fragments/siteBBB/language_masters
+ footerXFRoot = /content/experience-fragments/siteBBB/language_masters


Resolve language dynamically

From the page’s cq:language or from the page path (between language-masters/ and next /), extract the language code (en / fr).

Construct full XF path:

String xfPath = headerXFRoot + "/" + currentLanguage + "/site/header/master";


Render XF dynamically

Use <cq:include path="${xfPath}" resourceType="cq/experience-fragments/components/xfpage" />

Or if using a custom Sling Model for your header/footer component, compute this path there and expose it as a model property.

This approach allows site-aware and language-aware resolution with one config per site, no template duplication.

Option B: Use Relative XF Paths

If you prefer no caconfig, you can:

Use a relative path pattern in the template like:

/content/experience-fragments/${siteName}/language_masters/${language}/site/header/master


Resolve siteName and language dynamically from the current page path in a Sling Model backing your component:

Resource page = currentPage.adaptTo(Resource.class);
String pagePath = page.getPath();

String siteName = pagePath.split("/")[2]; // siteAAA / siteBBB
String language = pagePath.split("/")[4]; // en / fr

String xfPath = "/content/experience-fragments/" + siteName + "/language_masters/" + language + "/site/header/master";


This keeps your template fully generic — just compute and include the right XF at runtime.

2. (Optional) Use XF Variations for Localization

If your header/footer only changes text but keeps the same structure, you can:

Create one XF master and translate it (AEM XF translation projects support i18n).

That way, you don’t need separate XF per language — but per your question, it sounds like you want separate XFs anyway.

3. Example Template Usage

Instead of this in your template:

<cq:include path="/content/experience-fragments/siteAAA/language_masters/en/site/header/master"
resourceType="cq/experience-fragments/components/xfpage"/>


Use something like:

<sly data-sly-use.header="com.myproject.core.models.DynamicXFModel"
data-sly-test="${header.xfPath}">
<cq:include path="${header.xfPath}" resourceType="cq/experience-fragments/components/xfpage"/>
</sly>


Where DynamicXFModel builds xfPath based on page context (site + language + configured root).

🏁 Benefits of This Setup

Single template for all sites/languages
Automatic resolution — no manual updates when you add a new language
Clean separation of concerns — template stays generic, logic lives in Sling Model or configuration
Reusability — easily extend to more sites or locales