Render custom dimensions menu

Hey,

if i have a multisite setup with multi-language described here:

  • How to make sure that only the languages existing in the specific site will show up in the menu (right now all show up).
    ** props.item.state shows normal and current but not absent even if there is no Home site for the target language

  • how to render the link correctly with the uriSegment?
    ** props.item.uriSegment is giving me nothing
    ** also tried to add an attribut to the dimension items but its also giving me nothing

Fusion Menu

prototype(WG.BaseSite:CustomLanguageDimensionsMenu) < prototype(Neos.Fusion:Component) {
dimension = ‘language’
current = “current”

languageMenuItems = Neos.Neos:DimensionsMenuItems {
    dimension = 'language'
}

renderer = afx`
        <Neos.Fusion:Loop items={props.languageMenuItems} as="item">
            <WG.BaseSite:CustomLanguageDimensionsMenu.ItemRenderer item={item} />
        </Neos.Fusion:Loop>
`

}

prototype(WG.BaseSite:CustomLanguageDimensionsMenu.ItemRenderer) < prototype(Neos.Fusion:Component) {
item = ${null}

renderer = afx`

<Neos.Fusion:Match @subject={props.item.state} >
<Neos.Fusion:Case @path=“current”>

<li class=“uc” @if={props.item.state != ‘absent’}>

{props.item.shortLabel}


</Neos.Fusion:Case>
<Neos.Fusion:Case @path=“@default”>

  <li class="uc" @if={props.item.state != 'absent'}>
      <a  href={props.item.label} hreflang={props.item.label}>
          {props.item.shortLabel}
      </a>
  </li>
</Neos.Fusion:Case>

</Neos.Fusion:Match>
`

}

My Languages:

Languages

Neos:
Flow:
i18n:
defaultLocale: en
ContentRepository:
contentDimensions:
language:
label: Languages
icon: icon-language
default: en
defaultPreset: en
presets:
de:
label: German
values:
- de
uriSegment: “de”
fr:
label: French
values:
- fr
uriSegment: “fr”
fi:
label: Finnish
values:
- fi
uriSegment: “fi”
sw:
label: Swedish
values:
- sw
uriSegment: ‘sw’
pl:
label: Polish
values:
- pl
uriSegment: “fi”
gr:
label: Greek
values:
- gr
uriSegment: “gr”
en:
label: English
values:
- en
uriSegment: ‘en’
Neos:
userInterface:
defaultLanguage: en
translation:
autoInclude:
WG.BaseSite:
- Main
- “NodeTypes/*”

Hi,

you can access the node via item.node and use Neos.Neos:NodeLink with it.

Every language must have a homepage, Don’t think you can skip that, please check whether it really doesn’t exist.

Probably it’s best to have a custom configuration in your settings, which site should have which presets and filter those during rendering.

Every language must have a homepage, Don’t think you can skip that, please check whether it really doesn’t exist.

The problem is, i have a multi site setup but not every site has every language. Thats why i have to filter it somehow.

Probably it’s best to have a custom configuration in your settings, which site should have which presets and filter those during rendering.

But i cant do custom configurations in multi site setups, cause configs are global or am i wrong?

You can create a configuration in which the key at a certain point is the internal name of the site. This is a common practise for SEO or Tracking configs.

Thanks for your help!

This is my language config right now:

Neos:
  Flow:
    i18n:
      defaultLocale: en
  ContentRepository:
    contentDimensions:
      language:
        label: Languages
        icon: icon-language
        default: en
        defaultPreset: en
        presets:
          de:
            label: German
            values:
              - de
            uriSegment: "de"
          fr:
            label: French
            values:
              - fr
            uriSegment: "fr"
          fi:
            label: Finnish
            values:
              - fi
            uriSegment: "fi"
          sw:
           label: Swedish
           values:
             - sw
           uriSegment: 'sw'
          pl:
            label: Polish
            values:
              - pl
            uriSegment: "fi"
          gr:
            label: Greek
            values:
              - gr
            uriSegment: "gr"
          en:
           label: English
           values:
             - en
           uriSegment: 'en'
  Neos:
    userInterface:
      defaultLanguage: en
      translation:
        autoInclude:
          WG.BaseSite:
            - Main
            - "NodeTypes/*"

Lets say i want in the german site with the package key EQ.Germany just english and german.

How does the settings file for the german site looks like?

For example:

Vendor:
  Package:
    Dimensions:
      PresetsBySite:
        de: ['de', 'en']

And the you add a filter to your dimensions menu to filter out non matching presets.

Sorry for asking that mutch but we still learning the basics by doing.

I found this Documentation about the Menu (Fusion Reference — Neos CMS 8.3.x documentation), but how to set the filter based on the preset configuration?

I managed to create a fusion template that almost works like i want to:

my Settings looks like this:

WG:
  BaseSite:
    Dimensions:
      LanguagesBySite:
        eq-germany: ['de', 'en']
        eq-international: ['en', 'de']
        international: ['en', 'de']
        eq-france: ['fr', 'en']
        eq-finland: ['fi', 'en']
        eq-sweden: ['sw', 'en']
        eq-poland: ['pl', 'en']
        eq-greece: ['gr', 'en']
        eq-south-africa: ['en']

so i am using the node names to match the right config.

prototype(WG.BaseSite:CustomLanguageDimensionsMenu) < prototype(Neos.Fusion:Component) {
    dimension = 'language'
    rootInstanz = ${q(node).closest('[instanceof Neos.Neos:Document]').get(0)}
    path = ${this.rootInstanz.nodeData.path}

    # Funktion, um den Index des dritten Slashes zu finden
    thirdSlashIndex = ${String.indexOf(this.path, '/', String.indexOf(this.path, '/', 1) + 1)}

    # Kürzen des Pfads nach /sites/ und nach dem dritten Slash
    rootNode = ${this.thirdSlashIndex != -1 ? String.substring(this.path, 7, this.thirdSlashIndex) : String.substring(this.path, 7)}

    # Laden der Presets in einem sicheren Kontext mit @process
    presetsBySite = ${Configuration.setting('WG.BaseSite.Dimensions.LanguagesBySite')}

    # Filtern der verfügbaren Sprachdimensionen basierend auf der aktuellen Seite
    @context.availablePresets = ${this.presetsBySite[this.rootNode]}

    languageMenu = Neos.Neos:DimensionsMenu {
        dimension = 'language'
        presets = ${availablePresets}
    }

    renderer = afx`
    <nav class="flx">
      {props.languageMenu}
    </nav>
    `
}

I would like to have fallback links, looks like the DimensionsMenu is rendering a link only if there are matching dimensions found. Is there a way to set a fallback link to the home page of the other dimension if not?

I created a Eel helper to link the homepage of the language if no translation is available. I dont know its best practice but it works.

<?php

declare(strict_types=1);

namespace WG\BaseSite\Eel\Helper;

use Neos\Flow\Annotations as Flow;
use Neos\Eel\ProtectedContextAwareInterface;


class LanguageMenuHelper implements ProtectedContextAwareInterface
{
    public function allowsCallOfMethod($methodName)
    {
        return true;
    }

    /**
     * Funktion um fehlende Übersetzungen zu ermitteln und in dem Fall auf die Startseite zu verlinken
     * @param array $languageMenuItems
     * @return array
     */

    public function getMissingTranslations($languageMenuItems)
    {

        foreach ($languageMenuItems as $key => $value) {
            if ($value['state'] === 'absent') {
                // Zielsprache
                $targetLanguage = strtolower($value['label']);
                // Die Zielsprache in den Link einfügen
                $languageMenuItems[$key]['uri'] = '/' . $targetLanguage . '/';
            }
        }


        return $languageMenuItems;
    }
}

It works with this template.

prototype(WG.BaseSite:CustomLanguageDimensionsMenu) < prototype(Neos.Fusion:Component) {
    dimension = 'language'
    rootInstanz = ${q(node).closest('[instanceof Neos.Neos:Document]').get(0)}
    path = ${this.rootInstanz.nodeData.path}

    # Funktion, um den Index des dritten Slashes zu finden
    thirdSlashIndex = ${String.indexOf(this.path, '/', String.indexOf(this.path, '/', 1) + 1)}

    # Kürzen des Pfads nach /sites/ und nach dem dritten Slash
    rootNode = ${this.thirdSlashIndex != -1 ? String.substring(this.path, 7, this.thirdSlashIndex) : String.substring(this.path, 7)}

    # Laden der Presets in einem sicheren Kontext mit @process
    presetsBySite = ${Configuration.setting('WG.BaseSite.Dimensions.LanguagesBySite')}

    # Filtern der verfügbaren Sprachdimensionen basierend auf der aktuellen Seite
    @context.availablePresets = ${this.presetsBySite[this.rootNode]}

    # Verfügbare Übersetzungen
    availableTranslations = ${this.rootInstanz.dimensions}

    languageMenuItems = Neos.Neos:DimensionsMenuItems {
        dimension = 'language'
        presets = ${availablePresets}
    }

    # Menü items mit fehlenden Übersetzungen als Default
    menuItems = ${WG.BaseSite.LanguageMenuHelper.getMissingTranslations(this.languageMenuItems)}

    renderer = afx`
    <nav class="flx">

      <ul class="reset">
        <Neos.Fusion:Loop items={props.menuItems} itemName="item">
          <!-- Aktiver Eintrag -->
          <li @if={item.state == 'current'} class="uc current">
            <Neos.Neos:NodeLink node={item.node} content={item.label} />
          </li>
          <!-- Normale Einträge -->
          <li @if={item.state == 'normal'} class="uc">
            <Neos.Neos:NodeLink node={item.node} content={item.label} />
          </li>
          <!-- Einträge ohne direkte Übersetzung -->
          <li @if={item.state == 'absent'} class="uc">
            <a href={item.uri} >{item.label}</a>
          </li>
        </Neos.Fusion:Loop>
      </ul>
    </nav>
    `
}