uSync-Legacy icon indicating copy to clipboard operation
uSync-Legacy copied to clipboard

Prevent update of Dictionary entries

Open dgg opened this issue 8 years ago • 6 comments

Hi we are using Dictionary to localize labels in our application and uSync to push entries between environments.

Our workflow workflow is as follows:

  1. developers create entries for the labels needed for the feature in hand
  2. developers populate the default language
  3. entries get to the production environment eventually
  4. content editors translate those labels to all languages

Those translated dictionary entries never "get back" to the development environment, meaning that the source of dictionary entries is an incomplete (missing translations) dataset of the live data.

With this approach we have a problem with the out-of-the-box feature of uSync of updating the dictionary entry, as when new features are pushed to production, translations done by business users are overwritten and, thus, lost.

Is there a way to enable only creation (and eventually deletions) of dictionary entries, without updating them? I would not mind using a customized handler based on the existing one if I knew how to "register" it so that the customized version is run instead of the out-of-the-box handler.

Thanks for such an awesome and useful product.

dgg avatar Feb 12 '16 13:02 dgg

Hi,

yeah - making handlers a little more nuanced is on my wish list :)

If you want to write a custom version of the handler, then you just need to have something implement ISyncHandler.

uSync should pick up anything that implements that at runtime. All handlers are on by default (the entry in the uSyncBackOffice.config isn't needed - unless you want to turn the handler off)

If you took a copy of the DictionaryHandler then you only need change the name property and the Import function to do some does it already exist checking.

At the moment the core doesn't return anything to tell you if its a new or existing update, so you would have to do the actually looking inside umbraco from the handler.

KevinJump avatar Feb 12 '16 13:02 KevinJump

Hi Kevin,

Your approach was totally spot on and so easy to implement. I wrapped the existing DictionaryHandler into a CreateOnlyDictionaryHandler and disabled the out-of-the-box one in configuration. Is this a good approach? Or should inheritance be preferred?

<?xml version="1.0" encoding="utf-8"?>
<uSyncBackOfficeSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <!-- ... rest of configuration ... -->
    <Handlers>
        <HandlerConfig Name="uSync: DataTypeHandler" Enabled="true" />
        <HandlerConfig Name="uSync: TemplateHandler" Enabled="true" />
        <HandlerConfig Name="uSync: ContentTypeHanlder" Enabled="true" />
        <HandlerConfig Name="uSync: MediaTypeHandler" Enabled="true" />
        <HandlerConfig Name="uSync: LanguageHandler" Enabled="true" />
        <HandlerConfig Name="uSync: DictionaryHandler" Enabled="false" />
        <HandlerConfig Name="uSync: MacroHandler" Enabled="true" />
        <HandlerConfig Name="uSync: DataTypeMappingHandler" Enabled="true" />
        <HandlerConfig Name="uSync: MemberTypeHandler" Enabled="false" />
        <HandlerConfig Name="uSync: CreateOnlyDictionaryHandler" Enabled="true" />
    </Handlers>
</uSyncBackOfficeSettings>

And the class that only creates new dictionary entries:

public class CreateOnlyDictionaryHandler : uSyncBaseHandler<IDictionaryItem>, ISyncHandler
{
    private readonly DictionaryHandler _inner;
    private readonly ILocalizationService _localization;

    public CreateOnlyDictionaryHandler()
    {
        _inner = new DictionaryHandler();
        _localization = ApplicationContext.Current.Services.LocalizationService;
    }

    #region delegating members: DeleteItem, ExportAll, ExportToDisk, RegisterEvents, SyncFolder
    // ...
    #endregion

    public int Priority => 1061;

    public string Name => "uSync: CreateOnlyDictionaryHandler";

    public override uSyncAction ReportItem(string file)
    {
        string dictionaryKey;
        var action = keyAlreadyExists(file, out dictionaryKey) ?
            uSyncActionHelper<IDictionaryItem>.ReportAction(false, dictionaryKey, "Dictionary Items often get their order mixed up") :
            _inner.ReportItem(file);
        return action;
    }

    public override SyncAttempt<IDictionaryItem> Import(string filePath, bool force = false)
    {
        string dictionaryKey;
        SyncAttempt<IDictionaryItem> attempt = keyAlreadyExists(filePath, out dictionaryKey) ?
            SyncAttempt<IDictionaryItem>.Succeed(dictionaryKey, ChangeType.NoChange) :
        _inner.Import(filePath, force);

        return attempt;
    }

    private bool keyAlreadyExists(string filePath, out string dictionaryKey)
    {
        XElement node = XElement.Load(filePath);
        dictionaryKey = node.NameFromNode();

        bool exists = _localization.DictionaryItemExists(dictionaryKey);
        return exists;
    }
}

Feel free to use this code in whichever manner you see fit.

Thanks a bunch

dgg avatar Feb 16 '16 07:02 dgg

yeah that looks cool, I wouldn't do inheritance, because you don't know what random stuff might get added in the future :)

long term (i'm writing all this here so i don't forget!) I am probably going to add IsNew to the core serializers - that will be very similar to the keyAlreadyExists - & I am going to sit down and work out all the possible options for the handlers and put some form of ISyncHandler2 interface together to let you turn creation, deletion, etc off or on in the config and per import

KevinJump avatar Feb 16 '16 08:02 KevinJump

Hi gents, I've also had this issue and I found @dgg's code as a very useful starting point. Please see the following modifications to have the code work with nested items too as I found the other code is just for top level items.

The TryImportItem && TryImportChildren are there to capture if an item or a child item are updated. With my current setup (running uSync 3.0.2, uSynce.Core 3.0.0 on Umbraco 7.3.1) only the top level items are reported so nested dictionary items aren't reported.

Anyways, here's the gist of my code. I hope it helps. It's configured & used in exactly the same way as @dgg's.

Thanks, Jamie

jamiepollock avatar Mar 04 '16 10:03 jamiepollock

@KevinJump I'm looking to use uSync Content in v8 to sync dictionary items as described in this ticket - creating dictionary items but not updating.

Are you still planning to add the IsNew option? Is there a OOTB uSync8 way to do this, or would porting the gist above be the best way in v8?

michaelchart avatar Jan 02 '20 16:01 michaelchart

Hi, see uSync8 doc : https://jumoo.co.uk/usync/docs/v8/contentEdition/dictionaryHandler/

AlexandreLocas avatar Jan 28 '20 16:01 AlexandreLocas