SaaS CMS has officially launched! Learn more now.

Issue with Language Manager

Vote:
 

Business Expectation:

For a not translated Welsh page, want to copy english content to all page properties and blocks used in page.

Current Implementation:

We have one ColumnBlock having two content reference properties, and we are using standard Pages by drag and drop in contentArea property. "Broadcast and OnDemand Bulletin" is a standard page and we refrenced it in below content area.

We enabled TranslateOrCopyContentAreaChildrenBlockForTypes  configuration for all templates  in Language Manager V 5.2.0 as below

 "LanguageManager": {
       "TranslateOrCopyContentAreaChildrenBlockForTypes": [
          ".*"
        ]
    },

Problem Statement:

When End user selects "Duplicate English Content" option, it will iterate all blocks including the Page references which are dragged in ContentRefrence property. Here, the plugin is picking up all the nested childres page refrence and updated all content, adn this operation updates 700+ pages in our secerio.

 

Please suggets on the possible solution to copy the cotntet at level one only, but including all blocks.

Also, tried 5.3.0, but both options "Add all children" and "Add related content(s)" are not working as per our business need.

#322146
May 16, 2024 10:34
Vote:
 

Hi Rajveer,

I think there are a couple of points to address here so brace yourself for a bit of a lengthy response.

First, to answer your question, if you're looking to control which content gets updated when you create a new language version of a page, you can do that by creating your own instance of IChildrenContentLoader and overriding the default implementation. To avoid having to implement all of the logic from scratch you can either inherit from the default implementation (DefaultChildrenContentLoader) or intercept the default implementation. Here's an example of how you might do that using interception...

First create your own implementation of IChildrenContentLoader

public class CustomChildrenContentLoader : IChildrenContentLoader
{
    private Injected<IContentLoader> _contentLoader;

    private IChildrenContentLoader _interceptedChildrenContentLoader;
    public CustomChildrenContentLoader(IChildrenContentLoader interceptedChildrenContentLoader)
    {
        _interceptedChildrenContentLoader = interceptedChildrenContentLoader;
    }
    public IEnumerable<ContentReference> GetChildrenContentsNeedToCopyOrTranslate(ContentReference root, string masterLangID, bool includeDescendents, bool includeRelatedContents)
    {
        //Call the method from the intercepted implementation to get the initial list of content
        var contentList = _interceptedChildrenContentLoader.GetChildrenContentsNeedToCopyOrTranslate(root, masterLangID, includeDescendents, includeRelatedContents);
        //Filter the list here to remove the content you don't want to create a new language version for
        return contentList.Where(x => _contentLoader.Service.Get<ContentData>(x) is not PageData);
    }
}

Then, in ConfigureServices, register the interception:

services.Intercept<IChildrenContentLoader>((a, b) => new CustomChildrenContentLoader(b));

However, I don't think that will necessarily resolve your issue. I'd say the bigger issue is that, if you have a bunch of translated content and you reference that translated content from a page you've yet to translate, when you click the "Duplicate English content" button and choose "add related contents", the content you've already translated will be overwritten with a copy of the English content. Really, what we want to do is to only duplicate the English content for the content items we haven't translated yet. Ideally, this should be an option in the language manager but unfortunately it's not. Also, you may notice that, in the example above, "GetChildrenContentsNeedToCopyOrTranslate" only has the source language as a parameter, not the destination so you can't filter the content in there. That means you'll have to dig a little deeper and override the CopyDataFromMasterBranch method of the ILanguageBranchManager which is the bit of code responsible for creating the new language version. You can use a similar technique to the one described above using interception by creating an implementation of ILanguageBranchManager which accepts the default implementation in its constructor then overriding the CopyDataFromMasterBranch method so that it skips anything where the target language branch has already been created. For the rest of the methods you can just pass-through to the default implementation. The custom language branch manager might look like this:

public class CustomLanguageBranchManager : ILanguageBranchManager
{
    private Injected<IContentLoader> _contentLoader;

    private ILanguageBranchManager _defaultLanguageBranchManager;

    public CustomLanguageBranchManager(ILanguageBranchManager defaultLanguageBranchManager)
    {
        _defaultLanguageBranchManager = defaultLanguageBranchManager;
    }

    public async Task<TranslationAsyncResult> CopyDataFromMasterBranch(ContentReference contentReference,
        string fromLanguageID,
        string toLanguageID,
        Func<object, Task<object>> transformOnCopyingValue,
        bool autoPublish = false)
    {
        //Get the content being translated
        var masterContent = _contentLoader.Service.Get<ContentData>(contentReference.ToReferenceWithoutVersion(), new LanguageSelector(fromLanguageID));
        var toLanguage = new CultureInfo(toLanguageID);
        //Check whether the content already has a version in the language we're looking to translate to
        if (masterContent is ILocalizable localizableContent && localizableContent.ExistingLanguages.Any(x => x.Equals(toLanguage)))
        {
            //The content already exists in the target language so don't recreate it
            //Pretend the creation's been a success so as to continue the process for other content
            return new TranslationAsyncResult { ContentLink = contentReference, Result = true };
        }

        return await _defaultLanguageBranchManager.CopyDataFromMasterBranch(contentReference, fromLanguageID, toLanguageID, transformOnCopyingValue, autoPublish);
    }

    //Everything below here just calls the matching method on the default implementation...
    public async Task<TranslationAsyncResult> TranslateAndCopyDataFromMasterBranch(
        ContentReference contentReference,
        string fromLanguageID,
        string fromTwoLetterLanguageName,
        string toLanguageID,
        string toTwoLetterLanguageName,
        bool autoPublish = false)
    {
        return await _defaultLanguageBranchManager.TranslateAndCopyDataFromMasterBranch(contentReference, fromLanguageID, fromTwoLetterLanguageName, toLanguageID, toTwoLetterLanguageName, autoPublish);
    }

    bool ILanguageBranchManager.CreateLanguageBranch(ContentReference contentLink, string languageID, out ContentReference createdContentLink)
    {
        return _defaultLanguageBranchManager.CreateLanguageBranch(contentLink, languageID, out createdContentLink);
    }

    bool ILanguageBranchManager.DeleteLanguageBranch(ContentReference contentLink, string languageID)
    {
        return _defaultLanguageBranchManager.DeleteLanguageBranch(contentLink, languageID);
    }

    bool ILanguageBranchManager.GetMasterLanguageName(ContentReference contentReference, out string languageID, out string twoLetterLanguageName)
    {
        return _defaultLanguageBranchManager.GetMasterLanguageName(contentReference, out languageID, out twoLetterLanguageName);
    }

    IContent ILanguageBranchManager.GetPublishedOrCommonDraftVersion(ContentReference contentReference, string languageID)
    {
        return _defaultLanguageBranchManager.GetPublishedOrCommonDraftVersion(contentReference, languageID);
    }

    IEnumerable<LanguageInfo> ILanguageBranchManager.GetSystemEnabledLanguages(ContentReference contentReference)
    {
        return _defaultLanguageBranchManager.GetSystemEnabledLanguages(contentReference);
    }

    bool ILanguageBranchManager.ToggleLanguageBranchActivation(ContentReference contentLink, string languageID)
    {
        return _defaultLanguageBranchManager.ToggleLanguageBranchActivation(contentLink, languageID);
    }

    Task<object> ILanguageBranchManager.TranslateStringList(object inputStringList, IMachineTranslatorProvider translator, string fromLanguageID, string toLanguageID)
    {
        return _defaultLanguageBranchManager.TranslateStringList(inputStringList, translator, fromLanguageID, toLanguageID);
    }
}

which you can register in ConfigureServices like this...

services.Intercept<ILanguageBranchManager>((a, b) => new CustomLanguageBranchManager(b));
#322279
May 17, 2024 17:10
Rajveer Singh - May 20, 2024 10:23
Thank you @paul and much appreciated..
* 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.