A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Binh Nguyen Thi
Nov 15, 2025
  354
(0 votes)

Full implementation - Fallback languages with Optimizely Graph

Nowadays, many people choose a headless approach when developing Optimizely CMS/Commerce projects using Opti Graph.
One challenge we may face is implementing language fallback, as it is not supported by default. There are a few tips available, and today I want to share my complete implementation. I hope it will help others who need to achieve the same thing.


1. In back-end code, add more fallback language property for Graph model:

public class FallbackLanguageContentsApiModelProperty(
    ILanguageBranchRepository languageBranchRepository,
    ICustomUrlService customUrlService,
    IContentLanguageSettingsHandler contentLanguageSettingsHandler) : IContentApiModelProperty
{
    public object GetValue(ContentApiModel contentApiModel)
    {
        if (contentApiModel.ContentLink != null)
        {
            var enabledLanguages = languageBranchRepository.ListEnabled();
            var pagesThatFallBackContentToCurrentPage = new List<FallbackLanguageContent>();
            var cRef = contentApiModel.ContentLink.ToContentReference();

            foreach (var enabledLanguage in enabledLanguages)
            {
                var fallbackLanguages = contentLanguageSettingsHandler.GetFallbackLanguages(cRef, enabledLanguage.Culture.Name);
                if (fallbackLanguages != null && fallbackLanguages.Any() && fallbackLanguages.Contains(contentApiModel.Language.Name))
                {
                    var lang = enabledLanguage.Culture.Name;

                    pagesThatFallBackContentToCurrentPage.Add(new FallbackLanguageContent()
                    {
                        LanguageName = lang,
                        RelativePath = !ContentReference.IsNullOrEmpty(cRef) ? customUrlService.GetRelativeUrl(cRef, lang) : string.Empty
                    });
                }
            }

            return pagesThatFallBackContentToCurrentPage;
        }
        else
        {
            return new List<FallbackLanguageContent>();
        }
    }

    public string Name => "FallbackLanguageContents";
}

internal class FallbackLanguageContent
{
    public required string LanguageName { get; set; }
    public required string RelativePath { get; set; }
}

 

2. In the front-end code, we need to query content using a relative path and locale, including the fallback logic. Here is the query:

query getContentByPathWithinFallback($path: [String!]!, $locale: String, $siteId: String) {
  content: Content(
    where: {
      SiteId: { eq: $siteId }
      _or: [
        { _and: [{ Language: { Name: { eq: $locale, boost: 2 } } }, { RelativePath: { in: $path } }] }
        { _and: [{ FallbackLanguageContents: { LanguageName: { eq: $locale, boost: 1 } } }, { FallbackLanguageContents: { RelativePath: { in: $path } } }] }
      ]
    }
    locale: ALL
  ) {
    items: item {
      ...IContentData
      ...PageData
    }
  }
}
fragment PageData on IContent {
  ...IContentData
}
fragment IContentData on IContent {
  contentType: ContentType
  _metadata: ContentLink {
    id: Id
    version: WorkId
    key: GuidValue
  }
  locale: Language {
    name: Name
  }
  path: RelativePath
  _type: __typename
}

 

By using boost values in the query, we can indicate which conditions should have higher priority. As a result, the fallback content is returned only when no content exists for the exact locale.

If you are using Optimizely SaaS Starter for your headless solution, you can call your custom content query in src/app/[[...path]]/page.tsx by replacing the following section:


 

That's all. Hope this makes your multilingual setup a bit easier. Happy coding!

Nov 15, 2025

Comments

Please login to comment.
Latest blogs
Beginner's Guide for Optimizely Backend Developers

Developing with Optimizely (formerly Episerver) requires more than just technical know‑how. It’s about respecting the editor’s perspective, ensurin...

MilosR | Dec 10, 2025

Optimizely PaaS Administrator Certification : Free for Everyone

Optimizely has recently launched a free PaaS Administrator Certification. https://academy.optimizely.com/student/activity/2958208-paas-cms-administ...

Madhu | Dec 9, 2025 |

Fixing TinyMCE Initialization Failures in Optimizely CMS: A Hidden Pipeline Issue with .NET SDK Versions

Over the past few weeks, several Optimizely CMS projects began experiencing a puzzling failure: XHtmlString fields stopped initializing TinyMCE in...

Francisco Quintanilla | Dec 9, 2025 |

Jhoose Security Modules v2.6.0 — Added support for Permissions Policy and .NET 10

Version 2.6.0 adds Permissions Policy header support, updates to .NET 10, improved policy management, configurable security settings, and enhanced...

Andrew Markham | Dec 6, 2025 |