Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duplicated urls with different locales #94

Closed
davidrojo opened this issue Oct 11, 2016 · 2 comments
Closed

Duplicated urls with different locales #94

davidrojo opened this issue Oct 11, 2016 · 2 comments

Comments

@davidrojo
Copy link

Hello, I am using the dev-master version for use with symofony3.

I have prefixed the locale and when I load an url I can change the locale and the url still loads, although the path is different:

// app/config/config.yml
be_simple_i18n_routing:
    locales:
        supported: ['en', 'nl']
        filter: true
        strict: true
// app/config/routing.yml
my_app:
    resource: '@AppBundle/Resources/routing/routing.yml'
    type: be_simple_i18n
    prefix:   /{_locale}/
    requirements:
      _locale: 'en|es'
// AppBundle/Resources/routing/routing.yml
who_we_are:
    locales:
        en: '/who-we-are'
        es: '/quienes-somos'
    defaults:
        _controller: 'AppBundle:Default:whoWeAre'

mysite.com/en/who-we-are
mysite.com/es/who-whe-are

The two urls are loaded although the "es" shouldn't load.

@bartmcleod
Copy link

bartmcleod commented Oct 17, 2016

I tried to fix this, but the matching relies on a postfix of '.en' and '.nl' after the route name. If this matches the route matched by Symfony, then the matched route is replaced by the i18n route. If however the locale and the postfix do not match, the original Symfony route match is returned without modification. This will still lead to a controller and action, and therefore, the url will load.

Now the simple solution would be to detect that there is a postfix, such as .en and .nl and that it does not match the prefixed locale. However, since anyone might postfix their routes with a locale in that form (.nl, .es etc.), this solution might break their code.

This is a fix that works, but does break any other route postfixed with a dot and two characters:

    /**
     * {@inheritDoc}
     */
    public function match($pathinfo)
    {
        $match = $this->router->match($pathinfo);

        // if a _locale parameter isset remove the .locale suffix that is appended to each route in I18nRoute
        if ( ! empty($match['_locale'])) {
            if (preg_match('#^(.+)\.' . preg_quote($match['_locale'], '#') . '+$#', $match['_route'], $route)) {
                $match['_route'] = $route[1];

                // now also check if we want to translate parameters:
                if (null !== $this->translator && isset($match['_translate'])) {
                    foreach ((array) $match['_translate'] as $attribute) {
                        $match[$attribute] = $this->translator->translate(
                            $match['_route'], $match['_locale'], $attribute, $match[$attribute]
                        );
                    }
                }
            } else {
                // check if this is a route, configured as i18n route, if so, throw the exception
                if (preg_match("/^.*\.[a-z]{2}$/", $match['_route'])) {
                    throw new RouteNotFoundException('A route was matched, but the locale provided does not match the locale of the matched route.');
                }
            }
        }

        return $match;
    }

The corresponding test case would be:

    /**
     * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
     */
    public function testTheConfiguredLocaleIsTheSameAsThePrefixLocaleWhenMatched()
    {
        $parentRouter = $this->getMock('Symfony\Component\Routing\RouterInterface');

        $parentRouter->expects($this->once())
            ->method('match')
            ->with($this->equalTo('/en/testen'))
            ->will($this->returnValue(array('_route' => 'test.nl', '_locale' => 'en')));

        $router = new Router($parentRouter);

        $this->assertInstanceOf(Router::class, $router);

        $match = $router->match('/en/testen');
    }

I am now experimenting with a solution where we add more than just the locale to the route name, to make it possible to identify it as a route configured by the BeSimpleI18nRoutingBundle.

@boekkooi
Copy link
Collaborator

boekkooi commented Feb 18, 2017

The problem looks to be that you are trying to use a parameter where a prefix would be required.

Simply changing app/config/routing.yml to use prefix would solve the issue.

// app/config/routing.yml
my_app:
    resource: '@AppBundle/Resources/routing/routing.yml'
    type: be_simple_i18n
    prefix:
        en: /en
        es: /es

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants