Translation Manager – Exclude Blockgrid Module from Translation / Override Mapper

Hi everyone

I’m trying to configure the Translation Manager so that it ignores a specific module with the alias ModuleHTML during translation.

Background:
I’m using the Umbraco Blockgrid, and within it I have a module called ModuleHTML. This module contains custom HTML code for a third-party form.
Each language has a slightly different version of this form, meaning the HTML code varies per language.

The problem:
When I run a translation, the ModuleHTML module is copied into the target language as-is, meaning the HTML code from the source language is carried over 1:1.
I’d like to prevent that, since it makes sense for the target language to contain different HTML in this case.

What I’ve tried so far:

  1. Ignore Doctypes:
    I tried using the setting under
    Settings > Translation Manager > Sets > My Set > "Ignore Doctypes"
    to exclude the ModuleHTML module.
    However, this didn’t work – I suspect it’s because the module lives inside a Blockgrid.

    Question 1:
    Is there any way to make Translation Manager ignore specific content within a Blockgrid?

  2. Custom ValueMapper:
    Since the module uses a custom property, I thought about writing a Custom ValueMapper that just returns the original value unchanged.
    Unfortunately, that didn’t work as expected.
    Here’s my current code attempt:
    :backhand_index_pointing_right: https://gist.github.com/NicoM77/40f4b94fe68501531de5def4636566cb#file-codeeditormapper-cs-L58

    Ideally (if ignoring isn’t an option), I would like to override the mapper for the Umbraco.TextArea property and apply custom logic:

    • If the property is not inside ModuleHTML → use default behavior
    • If it is inside ModuleHTML → skip translation and return the existing value

    I haven’t been able to override or extend the SimpleStringMapper to make this work.

    Question 2:
    Has anyone done something similar or knows how to implement this kind of logic?

I’m open to suggestions or alternative approaches. Maybe someone has already solved a similar scenario?

Thanks in advance!

ps: I’m using Umbraco V13

1 Like

You can probably do this by using the regex version of the properties exclusion.

so all items in the block list that are translated will get a path - when you send them you can see this on the block.

e.g in the clean starter kit an image looks like this .

the path is contentRows/contentData/caption

you can then use this to exclude this from translation - an example might be.

-/*/caption

(note the ‘-’ at the start, which would exclude the ‘caption’ block whenever it appears

or

-contentRows/*/caption

which would exclude it when used in on a content row property.

fully this might then look like this .

this is all done with RegEx so standard regex things apply, test it makesure it matches only the things you want it to match ect, don’t expect to understand regex in 6 months :slight_smile:

but if your htmlBlock has a consistent name for the property this should work for you. :crossed_fingers:

Hi @KevinJump

Thank you for your response!

Unfortunately, the regex doesn’t seem to work as expected on my end.
I’ve attached a screenshot showing the property without the regex applied – this is the one I’d like to have ignored.

I tried the following regex:
*,-/*/contentData/html

This does remove the property from the Translation tab, which is good.
However, the value (in my case from German to English) is still being copied.
What I actually want is for the property to be completely ignored – not shown, not copied, not modified. The English value should remain unchanged.

This does remove the property from the Translation tab, which is good.
However, the value (in my case from German to English) is still being copied.
What I actually want is for the property to be completely ignored – not shown, not copied, not modified. The English value should remain unchanged.

So my question is:
Is this a bug in the “Ignore Property” behavior, or am I missing something?
From my understanding, “ignore” should mean the property is fully excluded from processing.

Thanks a lot for your help, and best regards

Nico

Yeah :frowning: that’s sort of the default behavior.

Translations happen at the property level, so when you translate a text string for example the property value moves from source to target, this is true if you translate say an URL picker, the link title say is translated but the actual value (i.e the link) will be copied as part of the property.

blocks/grids are a complex beast, but they behave the same way, the property (e.g. the whole ~blocklist~/grid) is copied from the source to the target and then the translated values are put in it. this preserves all the layout, images, links everything else that might be in the property.

So things that are not translated are copied, which would include the html you have there.

I did just write a whole bit about how we have some beta code to merge things for blockgrid and then realised you are using grid :disappointed_face: also to say when/if you go to v16+ of umbraco and use blocks the block level variance starts to solve this problem too - but i probably wouldn’t recommend that just to solve this problem.


I am not 100% sure what is the best way forward here, some of it implementation will be based.

It might not be practical (depending on setup) but I might be inclined to write a custom grid element that lets the user pick something that then generated the html to be inserted into the page. rather than having it directly in there.

If for example you are getting them to pick a different form for each language, i would suggest they are directed to pick another content node and that content node contains the details of the form in each language and that gets translated/updated separately from the grid.


To change translation manager behavior is possible - but would require - probably quite a bit of - code to achieve

Translation manager has the concept of Value Mergers (implementing a IContentValueMerger interface). The merger happens before the translation, and it takes the source and target property values and allows you to merge them pre -translation.

this is something we have written for blockgrid/lists for someone, but it can/does get complicated when you consider the possibilities that the source and target items may not match have different Layous etc (often they don’t but they might).

As you are using the grid you would have to traverse the grid JSON properties and merge the targets and the source properties at the relevant locations so that translation manager then had a version of the grid property it could put translations into.

if you trust the source and target grid properties will always contain the same layout/ordering and number of items this can be not to bad, but if they don’t or they might not it gets a little more sticky.


Hi @KevinJump,

Thanks a lot for your detailed reply, and sorry for getting back to you so late – I was quite busy.

Your explanation really helped me to understand the issue better. I was able to solve the problem as you suggested, by using a Node Picker outside. It worked perfectly – a bit cumbersome when filling in, but absolutely sufficient.

Now I have another question regarding the default data type Umbraco.MultiUrlPicker.
Here I have the problem that an anchor link is copied 1:1 as well. Is there a way to ignore the anchor? If that’s not easily possible, it would also be fine if the anchor link could be adapted/translated during the process.

I already tried writing a custom mapper to handle the anchor link, but unfortunately without much success.
Could you maybe give me some guidance here?

Thanks a lot for your help, and best regards
Nico

Hi,

the anchor value forms part of the URL so generally isn’t touched - and if it’s pointing to somewhere else in your content then that will also be an id on an element ? (e.g <h1 id=”sub-topic”> ) and that Id shouldn’t be getting sent to translation either (so it should be the same each language?

I would worry if you did something global to all link anchors it might have side effects ? but if you really need to. its also worth noting the anchor value is a Anchor/query string parameter in umbraco so you would want to be really sure it was something you wanted to drop.

If you want to remove them i think the best thing to do would be to have something that ran code when the TranslationJobPartialApprovalNotification notification is fired by Translation manager.

this happens when someone approves a job, (well at least one item in a job, hence partial).

for example (code isn’t tested, but is probably what you need)

public void Handle(TranslationJobPartialApprovalNotification notification)
{
    if (notification.Job == null) return;

    foreach(var node in notification.Nodes)
    {
        var targetItem = _contentService.GetById(node.TargetNodeId);
        foreach(var property in targetItem.Properties)
        {
            var alias = property.PropertyType.PropertyEditorAlias;
            if (property.PropertyType.PropertyEditorAlias != Constants.PropertyEditors.Aliases.MultiUrlPicker) continue;

            // assuming here you are not using variants .
            // if you are you need to get by culture.
            var value = property.GetValue();
            var picker = JsonConvert.DeserializeObject<MultiUrlPickerValueEditor.LinkDto[]>(value.ToString());
            foreach(var link in picker)
            {
                if (link.QueryString.StartsWith('#'))
                    link.QueryString = "";
            }

            property.SetValue(picker);
        }

        if (targetItem.IsDirty())
            _contentService.Save(targetItem, userId: notification.UserId);
    }
}

Hi Kevin

My main goal is to have a clean and consistent URL – for example my-domain.ch/Contact#Form – and ideally keep it that way across all languages. But yes, having a language-specific anchor could also be an option.

Thanks a lot for your quick reply, I’ll give it a try.

Wishing you a great day.
Best regards