Skip to content

Commit

Permalink
Added support for hreflang
Browse files Browse the repository at this point in the history
  • Loading branch information
Nyholm committed Dec 5, 2015
1 parent 1c73115 commit 7f7044a
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 6 deletions.
41 changes: 41 additions & 0 deletions DependencyInjection/Compiler/SetRequestPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/*
* Copyright 2012 Johannes M. Schmitt <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace JMS\I18nRoutingBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;

/**
* Make sure the Twig extension could get a request object
*
* @author Tobias Nyholm <[email protected]>
*/
class SetRequestPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$twigExtDev = $container->getDefinition('jms_i18n_routing.twig_extension');
// If SF=>2.4
if (null !== $container->hasDefinition('request_stack')) {
$twigExtDev->addMethodCall('setRequestStack', [$container->getDefinition('request_stack')]);
} else {
$twigExtDev->addMethodCall('setContainer', [$container->getDefinition('service_container')]);
}
}
}
2 changes: 2 additions & 0 deletions JMSI18nRoutingBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

namespace JMS\I18nRoutingBundle;

use JMS\I18nRoutingBundle\DependencyInjection\Compiler\SetRequestPass;
use JMS\I18nRoutingBundle\DependencyInjection\JMSI18nRoutingExtension;
use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass;
use JMS\I18nRoutingBundle\DependencyInjection\Compiler\SetRouterPass;
Expand All @@ -34,6 +35,7 @@ class JMSI18nRoutingBundle extends Bundle
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new SetRouterPass());
$container->addCompilerPass(new SetRequestPass());
}

public function getContainerExtension()
Expand Down
6 changes: 6 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<parameter key="jms_i18n_routing.cookie_setting_listener.class">JMS\I18nRoutingBundle\EventListener\CookieSettingListener</parameter>

<parameter key="jms_i18n_routing.route_translation_extractor.class">JMS\I18nRoutingBundle\Translation\RouteTranslationExtractor</parameter>
<parameter key="jms_i18n_routing.twig_extension.class">JMS\I18nRoutingBundle\Twig\I18nRoutingExtension</parameter>
</parameters>

<services>
Expand Down Expand Up @@ -69,5 +70,10 @@
<argument type="service" id="jms_i18n_routing.route_exclusion_strategy" />
<tag name="jms_translation.extractor" alias="jms_i18n_routing" />
</service>

<service id="jms_i18n_routing.twig_extension" class="%jms_i18n_routing.twig_extension.class%" public="false">
<argument>%jms_i18n_routing.locales%</argument>
<tag name="twig.extension" />
</service>
</services>
</container>
5 changes: 5 additions & 0 deletions Resources/views/hreflang.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

{% for locale in locales %}
{% set arr = routeParams|merge({'_locale':locale}) %}
<link rel="alternate" hreflang="{{ locale }}" href="{{ url(route, arr) }}" />
{% endfor %}
2 changes: 2 additions & 0 deletions Router/I18nLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ public function load(RouteCollection $collection)
$catchMultipleRoute = clone $route;
$catchMultipleRoute->setPath($pattern);
$catchMultipleRoute->setDefault('_locales', $locales);
$catchMultipleRoute->setDefault('localized', true);
$i18nCollection->add(implode('_', $locales).I18nLoader::ROUTING_PREFIX.$name, $catchMultipleRoute);
}

foreach ($locales as $locale) {
$localeRoute = clone $route;
$localeRoute->setPath($pattern);
$localeRoute->setDefault('_locale', $locale);
$localeRoute->setDefault('localized', true);
$i18nCollection->add($locale.I18nLoader::ROUTING_PREFIX.$name, $localeRoute);
}
}
Expand Down
12 changes: 6 additions & 6 deletions Tests/Router/I18nRouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public function testMatch()
$context->setParameter('_locale', 'en');
$router->setContext($context);

$this->assertEquals(array('_controller' => 'foo', '_locale' => 'en', '_route' => 'welcome'), $router->match('/welcome-on-our-website'));
$this->assertEquals(array('_controller' => 'foo', '_locale' => 'en', '_route' => 'welcome', 'localized' => true), $router->match('/welcome-on-our-website'));

$this->assertEquals(array(
'_controller' => 'JMS\I18nRoutingBundle\Controller\RedirectController::redirectAction',
Expand All @@ -146,19 +146,19 @@ public function testRouteNotFoundForActiveLocale()
$router->setContext($context);

// The route should be available for both en_UK and en_US
$this->assertEquals(array('_route' => 'news_overview', '_locale' => 'en_US'), $router->match('/news'));
$this->assertEquals(array('_route' => 'news_overview', '_locale' => 'en_US', 'localized' => true), $router->match('/news'));

$context->setParameter('_locale', 'en_UK');
$context->setHost('uk.test');
$router->setContext($context);

// The route should be available for both en_UK and en_US
$this->assertEquals(array('_route' => 'news_overview', '_locale' => 'en_UK'), $router->match('/news'));
$this->assertEquals(array('_route' => 'news_overview', '_locale' => 'en_UK', 'localized' => true), $router->match('/news'));

// Tests whether generating a route to a different locale works
$this->assertEquals('http://nl.test/nieuws', $router->generate('news_overview', array('_locale' => 'nl_NL')));

$this->assertEquals(array('_route' => 'english_only', '_locale' => 'en_UK'), $router->match('/english-only'));
$this->assertEquals(array('_route' => 'english_only', '_locale' => 'en_UK', 'localized' => true), $router->match('/english-only'));
}

/**
Expand All @@ -174,12 +174,12 @@ public function testSubLocaleTranslation()
$router->setContext($context);

// Test overwrite
$this->assertEquals(array('_route' => 'sub_locale', '_locale' => 'en_US'), $router->match('/american'));
$this->assertEquals(array('_route' => 'sub_locale', '_locale' => 'en_US', 'localized' => true), $router->match('/american'));

$context->setParameter('_locale', 'en_UK');
$context->setHost('uk.test');
$router->setContext($context);
$this->assertEquals(array('_route' => 'enUK_only', '_locale' => 'en_UK'), $router->match('/enUK-only'));
$this->assertEquals(array('_route' => 'enUK_only', '_locale' => 'en_UK', 'localized' => true), $router->match('/enUK-only'));
}

/**
Expand Down
136 changes: 136 additions & 0 deletions Twig/I18nRoutingExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

/*
* Copyright 2012 Johannes M. Schmitt <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace JMS\I18nRoutingBundle\Twig;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* @author Tobias Nyholm <[email protected]>
*/
class I18nRoutingExtension extends \Twig_Extension
{
/**
* @var RequestStack requestStack
*/
private $requestStack;

/**
* @var ContainerInterface container
* This is only used in symfony 2.3
*/
private $container;

/**
* @var array locales
*/
private $locales;

/**
* @param array $locales
*/
public function __construct($locales)
{
$this->locales = $locales;
}

public function getFunctions()
{
return array(
new \Twig_SimpleFunction('hreflang', array($this, 'getHreflang'), array(
'needs_environment' => true,
'is_safe' => array('html'),
)),
);
}

/**
* Return HTML with hreflang attributes.
*
* @param \Twig_Environment $env
*/
public function getHreflang(\Twig_Environment $env)
{
if (null === $request = $this->getRequest()) {
return;
}

if (null === $routeParams = $request->attributes->get('_route_params')) {
return;
}

if (!isset($routeParams['localized']) || !$routeParams['localized']) {
return;
}

return $env->render('JMSI18nRoutingBundle::hreflang.html.twig', array(
'locales' => $this->locales,
'route' => $request->attributes->get('_route'),
'routeParams' => $routeParams,
));
}

/**
* @param ContainerInterface $container
*
* @return I18nRoutingExtension
*/
public function setContainer(ContainerInterface $container)
{
$this->container = $container;

return $this;
}

/**
* @param RequestStack $requestStack
*
* @return I18nRoutingExtension
*/
public function setRequestStack(RequestStack $requestStack)
{
$this->requestStack = $requestStack;

return $this;
}

/**
* @return null|\Symfony\Component\HttpFoundation\Request
*/
private function getRequest()
{
if ($this->requestStack !== null) {
return $this->requestStack->getMasterRequest();
}

if ($this->container !== null) {
$this->container->get('request');
}
}

/**
* {@inheritdoc}
*
* @return string
*/
public function getName()
{
return 'i18n_routing_extension';
}
}

0 comments on commit 7f7044a

Please sign in to comment.