Take the community feedback survey now.

How fallback language logic works with Opti GraphQL

Vote:
 

Hi eveyone,

I am using Cms 12.33.1 and Optimizely.ContentGraph.Cms 3.19.2. I am using Opti GraphQL for my headless site and want to have multilinguale function.
But I am wondering if I can get content from fallback language if there is no existed content in target language via Opti GraphQL by default or not?
How can I do setup to make fallback logic work with Opti GraphQL?

Please let me know if you know it or have experienced with it.

Thanks a lot

#340094
Aug 25, 2025 12:18
Vote:
 

Try this to see if it works. If your query has locale parameter (something as below example), the graph client should have all the locales

query ArticlesContentAreaQuery(
    $locale: Locales = ALL
    ) {
  ArticlePage(
    locale: [$locale]){
    items {
      Name
      MainContentArea {
        ContentLink {
          Expanded {
            ... on ContactPage {
              Name
              Email
            }
          }
        }
      }
    }
  }
}

in the query, you can have        

var queryResponse = await _contentGraphClient.ArticlesContentAreaQuery.ExecuteAsync(currentPage.GetLocales()); 

Add an extension method GetLocales()

public static Locales GetLocales(this object content)
{
    if(content is ILocalizable localizableContent)
   {
      return localizableContent.Language.Name;
   }
 
  else
  {
     return Locales.All
  }
}
 

 

 
#340101
Aug 25, 2025 18:12
Vote:
 

Thanks for your help. I did something like that with adding more custom properties in Graph as well

#340128
Aug 29, 2025 2:55
Vote:
 

Actually I am using https://github.com/remkoj/optimizely-dxp-clients for my front-end site.

Here is my customization for fallback:

  • GraphQL query in FE
query getContentByPathWithinFallback($path: [String!]!, $locale: String, $siteId: String) {
  content: Content(
    where: {
      SiteId: { eq: $siteId }
      _or: [
        { _and: [{ FallbackLanguageContents: { LanguageName: { eq: $locale, boost: 1 } } }, { FallbackLanguageContents: { RelativePath: { in: $path } } }] }
        { _and: [{ Language: { Name: { eq: $locale, boost: 2 } } }, { 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
}

I use boost value here to make sure that always get content with matched language completely first then get fallback content.

  • Custom graph api model in BE
public class FallbackLanguageContentsApiModelProperty(
    ILanguageBranchRepository languageBranchRepository,
    IUrlResolver urlResolver,
    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.Any() && fallbackLanguages.Contains(contentApiModel.Language.Name))
                {
                    var lang = enabledLanguage.Culture.Name;
                    var url = urlResolver.GetUrl(cRef, lang);

                    pagesThatFallBackContentToCurrentPage.Add(new FallbackLanguageContent()
                    {
                        LanguageName = lang,
                        RelativePath = url != null ? customUrlService.GetRelativeUrl(url) : 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; }
}
#340132
Aug 29, 2025 3:48
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.