neos / neos-development-collection

The unified repository containing the Neos core packages, used for Neos development.
https://www.neos.io/
GNU General Public License v3.0
260 stars 221 forks source link

FusionExceptionView does not set current locale correctly #3190

Open kdambekalns opened 3 years ago

kdambekalns commented 3 years ago

Description

With "native 404 handling" the FusionExceptionView was added.

When using native 404 handling with content dimensions, some things need to be tweaked, see this post.

Now, when the document rendered through this contains something translated via XLIFF files, the languages do not match.

Steps to Reproduce

  1. have a website with two languages, e.g. en and de
  2. configure as per the post linked above
  3. add the Flowpack.SearchPlugin search form on the 404 page
  4. call a non-existing page in de
  5. the 404 page is rendered as expected, but the form elements show up in en

Expected behavior

Language matches the shown document.

Actual behavior

German 404 content, but english labels on the search form.

Affected Versions

Neos: 4.3.0 and up

kdambekalns commented 3 years ago

The FusionExceptionView basically does the same thing as the FusionView: https://github.com/neos/neos-development-collection/blob/4.3/Neos.Neos/Classes/View/FusionExceptionView.php#L131-L136

But there is no "current node" to fetch the dimensions from, so it's always whatever (default) dimensions are there.

As of 5.3 that has been extracted into FusionViewI18nTrait - but the logic has not changed, the problem persists.

kdambekalns commented 3 years ago

Seems "impossible" to fix at that point, so I created this:

<?php
declare(strict_types=1);

namespace Acme\Com\Eel;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Eel\ProtectedContextAwareInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\I18n\Locale;
use Neos\Flow\I18n\Service;

/**
 * The LocaleHelper deals with i18n-related things.
 */
class LocaleHelper implements ProtectedContextAwareInterface
{
    /**
     * @Flow\Inject
     * @var Service
     */
    protected $i18nService;

    /**
     * Given a node this tries to set the current locale for the Flow i18n service
     * from the content dimension "language", if possible.
     *
     * The input node is returned as is for chaining, to make sure the operation is
     * actually evaluated.
     *
     * @param NodeInterface $node
     * @return NodeInterface
     * @throws \Neos\Flow\I18n\Exception\InvalidLocaleIdentifierException
     */
    public function setCurrentFromNode(NodeInterface $node): NodeInterface
    {
        $dimensions = $node->getContext()->getDimensions();
        if (array_key_exists('language', $dimensions) && $dimensions['language'] !== []) {
            $currentLocale = new Locale($dimensions['language'][0]);
            $this->i18nService->getConfiguration()->setCurrentLocale($currentLocale);
            $this->i18nService->getConfiguration()->setFallbackRule(['strict' => false, 'order' => array_reverse($dimensions['language'])]);
        }

        return $node;
    }

    /**
     * All methods are considered safe
     *
     * @param string $methodName
     * @return boolean
     */
    public function allowsCallOfMethod($methodName)
    {
        return true;
    }
}

which can be used like this:

error {
    dimensions = Acme.Com:ExtractLanguageDimension
    adjustedSite = ${q(site).context({'dimensions': this.dimensions.dimensions, 'targetDimensions': this.dimensions.targetDimensions}).get(0)}
    // route node through LocaleHelper, to set "current locale" for Flow
    @context.notFoundDocumentNode = ${Locale.setCurrentFromNode(q(this.adjustedSite).children('[instanceof Acme.Com:ErrorPage]').get(0))}

    4xx {
        @position = 'start'
        condition = ${statusCode >= 400 && statusCode < 500 && notFoundDocumentNode}
        renderer = Neos.Fusion:Renderer {
            @context {
                site = ${notFoundDocumentNode.context.currentSiteNode}
                node = ${notFoundDocumentNode}
                documentNode = ${notFoundDocumentNode}
            }
            renderPath = '/root'
        }
    }
}

Works for me(tm). 😎


Any solution we could put in the core would be preferred, obviously. 🤔

mhsdesign commented 1 year ago

With Neos 9.0 we now have to do really odd things to keep this "wrong" behavior. It should be almost easier to do it right ^^

see

https://github.com/neos/neos-development-collection/blob/96e4257c0161186d13eca78f0b2588aa6f4c3af3/Neos.Neos/Classes/View/FusionExceptionView.php#L115

and

https://github.com/neos/neos-development-collection/blob/96e4257c0161186d13eca78f0b2588aa6f4c3af3/Neos.Neos/Classes/View/FusionExceptionViewInternals.php#L21-L43

and

https://github.com/neos/neos-development-collection/blob/96e4257c0161186d13eca78f0b2588aa6f4c3af3/Neos.Neos/Classes/View/FusionExceptionViewInternalsFactory.php#L20-L32

mhsdesign commented 1 year ago

@nezaniel do you know how we could find out the correct locale?