Documentation

Custom property editors

Support site-specific editors with safe configuration mappings or a persisted-value adapter in code.

Choose the smallest safe extension

Omni extends support at the persisted-value boundary. Choose an approach based on what the editor actually stores—not how it renders in the backoffice.

Map simple values in configuration

Use PlainText only when the editor stores text directly. Use RichText only when it stores HTML compatible with Umbraco's rich-text parser.

{
  "DiploTranslatorOmni": {
    "ContentTranslation": {
      "PropertyEditorMappings": [
        { "EditorAlias": "Acme.Headline", "Adapter": "PlainText" },
        { "EditorAlias": "Acme.FormattedIntroduction", "Adapter": "RichText" }
      ]
    }
  }
}

Only PlainText and RichText are accepted. Unknown mappings, complex JSON and unsafe values remain unsupported.

Implement a code adapter for complex values

For structured persisted values, implement IContentTranslationPropertyEditorAdapter. An adapter identifies the editors it handles, extracts stable text-unit IDs, patches only those units into a cloned value and validates that protected structure remains unchanged.

public sealed class CalloutTranslationAdapter
    : IContentTranslationPropertyEditorAdapter
{
    public bool CanHandle(ContentTranslationEditorAdapterContext context)
        => context.EditorAlias == "Acme.Callout";

    public ContentTranslationEditorExtraction Extract(
        ContentTranslationEditorAdapterContext context,
        string sourceValue) { /* return stable text units */ }

    public ContentTranslationEditorPatch Patch(
        ContentTranslationEditorAdapterContext context,
        string sourceValue,
        IReadOnlyDictionary<string, string> translations,
        IReadOnlyCollection<ContentTranslationEditorUnit> units)
        { /* patch a clone of the persisted value */ }

    public ContentTranslationEditorValidation Validate(
        ContentTranslationEditorAdapterContext context,
        string originalValue,
        string patchedValue)
        { /* verify protected structure is unchanged */ }
}

The outline shows the contract; production implementations must parse defensively and return extraction, patch and validation failures rather than accepting uncertain output.

Register the adapter

Register the implementation from an Umbraco composer:

using Diplo.Translator.Omni;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;

public sealed class TranslationComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
        => builder.AddContentTranslationEditorAdapter<CalloutTranslationAdapter>();
}

Safety behaviour

  • Built-in editor aliases cannot be overridden.
  • Adapter exceptions and validation failures fail closed.
  • Duplicate or unknown unit IDs and null patch results are rejected.
  • Use stable unit IDs so Omni can track source changes reliably.

Diplo Translator Omni

Ready to translate your first draft?

Bring AI translation into the Umbraco backoffice — and keep the final say with your editors.