How to link to node in other content dimension

We all know there’s a TYPO3.Neos:DimensionsMenu TS object with which you can build a language menu.
But sometimes you need more flexibility and be able to create links to nodes in different content dimensions, e.g. in different language.

Here’s a trick to do it:

TYPO3.Neos:NodeUri {
    node = ${q(documentNode).context({targetDimensions: {language: 'en'}, dimensions: {language: ['en']}}).get(0)}
}

Here’s a slightly more advanced example. I use it to add links inside article body to inform user that this article exists in alternative language. We only have Russian and English versions, so these are hard coded in the example, but you get the point. If this exact article doesn’t exist in alternative language dimension nothing is shown.

languageMenu = TYPO3.TypoScript:Tag {
	    lang = ${Array.first(node.context.dimensions.language)}
	    @context.altLang = ${this.lang == 'ru' ? 'en' : 'ru'}
	    tagName = 'a'
            @context.altNode = ${q(documentNode).context({targetDimensions: {language: altLang}, dimensions: {language: [altLang]}})}
	    @if.nodeExists = ${altNode.count() > 0}
	    attributes.href = TYPO3.Neos:NodeUri {
	        node = ${altNode.get(0)}
	    }
	    content = ${altLang == 'en' ? 'Read this in English' : 'Читать по-русски'}
}
9 Likes

Hi @dimaip I’m struggling to obtain something like what you are describing here but with no success.

What I’m trying to acheive is a language menu based on a combination of dimensions (language + country) ; even a list of allowed combinations in each page that would link to other versions of the same page would be good (something like your last example, as far as I understand).

To give you an example: let’s say I have the 3 combinations it_ch, de_ch and fr_ch and on each page I would like to show Italian - German - French (3 links that would take me to /it_ch/one-page, /de_ch/one-page, /fr_ch/one-page accordingly).

How would you suggest me to proceed? What is the “best practice” here?
I played around a lot with the TYPO3.Neos:DimensionMenu in vain till now.

Thanks,
Nicola

Hi, Nicola! Let’s first start with defining what’s wrong with TYPO3.Neos:DimensionMenu for your use case? Do you only want links to show when the current page is available in those languages, right?

I can say so… I would like to allow users coming from multi-language countries to be able to surf the website in their languages/versions; i.e. it_ch, fr_ch, de_ch for Swiss… nl_be, fr_be for Belgium and so on (I already got a component to do the country<>version matching).

In real life it’s a little more complicated as I should consider the case where same version is used for different countries and activate the menu on a country base, but I think to understand is best to keep it at the basic.

Thanks,
Nicola

So technically you want to get a list of all dimension combinations, then test each dimension combination if a node exists in that dimension, and if it does create a link?
The point of this FAQ entry was to show how to link to node in the other dimension, so it should help you with the last task. I don’t know how to get the list of all available dimensions programmatically (read Settings perhaps?), but then it should be quite easy to iterate over it with TYPO3.TypoScript:Collection and create the links.

Hi again @dimaip,
first of all thank you, with your advices I could manage to resolve my issue in a very short time.
I still have some polishing to do and some obscure features that just work without having deep knowledge of it, but it works as i expected.

To give back some here is my solution (not polished yet :wink:):

prototype(Vendor:DimensionsMenu) < prototype(TYPO3.Neos:Menu) {
@class = 'Vendor\\TypoScript\\DimensionsMenuImplementation'

templatePath = 'resource://Vendor/Private/Templates/NodeTypes/DimensionsMenu.html'

#allowed dimensions combinations coming from Implementation class (@context still kinda obscure)
@context.combinations = ${this.items}

versions = TYPO3.TypoScript:Collection{
    collection = ${combinations}
    itemName = 'item'
    itemRenderer = TYPO3.TypoScript:Tag {
        tagName = 'a'
        @context.altNode = ${q(documentNode).context({targetDimensions : {language : item.language.uriSegment, country : item.country.uriSegment}, dimensions: {language: [item.language.uriSegment], country: [item.country.uriSegment]}})}
        @if.nodeExists = ${altNode.count()> 0}
        attributes.href = TYPO3.Neos:NodeUri {
            node = ${altNode.get(0)}
        }
        content = ${String.toUpperCase(item.language.identifier)}
    }
}

#quick-&-dirty: counting items to enable language menu only if more than 2 elements exist (wrapping reasons)
languages = ${Array.length(this.items)}

}

Thanks again,
Nicola

1 Like

In simple cases when you don’t have dimension constraints, reading presets from the settings would work just fine:

prototype(Your.Workspace:LanguageMenu) < prototype(TYPO3.TypoScript:Collection) {
	collection = ${Configuration.setting('TYPO3.TYPO3CR.contentDimensions.language.presets')}
	itemName = 'dimension'
	itemRenderer = TYPO3.TypoScript:Tag {
		tagName = 'a'
		@context.targetDimension = ${Array.first(dimension.values)}
		attributes.class = ${targetDimension == Array.first(node.context.dimensions.language) && 'active'}
		attributes.href = TYPO3.Neos:NodeUri {
			node = ${q(documentNode).context({targetDimensions: {language: targetDimension}, dimensions: {language: [targetDimension]}}).count() > 0 ?
				q(documentNode).context({targetDimensions: {language: targetDimension}, dimensions: {language: [targetDimension]}}).get(0) :
				q(site).context({targetDimensions: {language: targetDimension}, dimensions: {language: [targetDimension]}}).get(0)}
		}
		content = ${dimension.label}
	}
}
2 Likes

I used your code, but ran into caching issues.

I have two solutions:
Solution 1: Take altLang out of context and use local variable instead
``altLang = ${this.lang == ‘ru’ ? ‘en’ : ‘ru’}
@context.altNode = ${q(documentNode).context({targetDimensions: {language: this.altLang}, dimensions: {language: [this.altLang]}})}```

Solution 2: Uncache altLang

            @cache {
                mode = 'uncached'
                context {                           
                    1 = 'altLang'
                }
            }