Issue #2428103 by dawehner, amateescu, Berdir, AjitS: String formatter should link to its translation

8.0.x
Nathaniel Catchpole 2015-05-08 21:53:09 +01:00
parent b5f7cccde4
commit 74db053104
8 changed files with 186 additions and 42 deletions

View File

@ -204,8 +204,15 @@ abstract class Entity implements EntityInterface {
$uri
->setOption('entity_type', $this->getEntityTypeId())
->setOption('entity', $this);
// Display links by default based on the current language.
if ($rel !== 'collection') {
$options += ['language' => $this->language()];
}
$uri_options = $uri->getOptions();
$uri_options += $options;
return $uri->setOptions($uri_options);
}
@ -323,13 +330,16 @@ abstract class Entity implements EntityInterface {
* {@inheritdoc}
*/
public function language() {
$langcode = $this->{$this->getEntityType()->getKey('langcode')};
$language = $this->languageManager()->getLanguage($langcode);
if (!$language) {
// Make sure we return a proper language object.
$langcode = $this->langcode ?: LanguageInterface::LANGCODE_NOT_SPECIFIED;
$language = new Language(array('id' => $langcode));
if ($key = $this->getEntityType()->getKey('langcode')) {
$langcode = $this->$key;
$language = $this->languageManager()->getLanguage($langcode);
if ($language) {
return $language;
}
}
// Make sure we return a proper language object.
$langcode = !empty($this->langcode) ? $this->langcode : LanguageInterface::LANGCODE_NOT_SPECIFIED;
$language = new Language(array('id' => $langcode));
return $language;
}

View File

@ -0,0 +1,69 @@
<?php
/**
* @file
* Contains \Drupal\language\Tests\EntityUrlLanguageTest.
*/
namespace Drupal\language\Tests;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\simpletest\KernelTestBase;
/**
* Tests the language of entity URLs.
* @group language
*/
class EntityUrlLanguageTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['language', 'entity_test', 'user', 'system'];
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test');
$this->installEntitySchema('configurable_language');
$this->installSchema('system', 'router');
\Drupal::service('router.builder')->rebuild();
// In order to reflect the changes for a multilingual site in the container
// we have to rebuild it.
ConfigurableLanguage::create(['id' => 'es'])->save();
ConfigurableLanguage::create(['id' => 'fr'])->save();
$this->config('language.types')->setData([
'configurable' => ['language_interface'],
'negotiation' => ['language_interface' => ['enabled' => ['language-url' => 0]]],
])->save();
$this->config('language.negotiation')->setData([
'url' => [
'source' => 'path_prefix',
'prefixes' => ['en' => 'en', 'es' => 'es', 'fr' => 'fr']
],
])->save();
$this->kernel->rebuildContainer();
$this->container = $this->kernel->getContainer();
\Drupal::setContainer($this->container);
}
/**
* Ensures that entity URLs in a language have the right language prefix.
*/
public function testEntityUrlLanguage() {
$entity = EntityTest::create();
$entity->addTranslation('es', ['name' => 'name spanish']);
$entity->addTranslation('fr', ['name' => 'name french']);
$entity->save();
$this->assertTrue(strpos($entity->urlInfo()->toString(), '/en/entity_test/' . $entity->id()) !== FALSE);
$this->assertTrue(strpos($entity->getTranslation('es')->urlInfo()->toString(), '/es/entity_test/' . $entity->id()) !== FALSE);
$this->assertTrue(strpos($entity->getTranslation('fr')->urlInfo()->toString(), '/fr/entity_test/' . $entity->id()) !== FALSE);
}
}

View File

@ -49,7 +49,9 @@ class StatisticsReportsTest extends StatisticsTestBase {
$this->assertText('All time', 'Found the all time popular content.');
$this->assertText('Last viewed', 'Found the last viewed popular content.');
$this->assertRaw(\Drupal::l($node->label(), $node->urlInfo()), 'Found link to visited node.');
// statistics.module doesn't use node entities, prevent the node language
// from being added to the options.
$this->assertRaw(\Drupal::l($node->label(), $node->urlInfo('canonical', ['language' => NULL])), 'Found link to visited node.');
}
}

View File

@ -211,6 +211,8 @@ class TermIndexTest extends TaxonomyTestBase {
// Verify that the page breadcrumbs include a link to the parent term.
$this->drupalGet('taxonomy/term/' . $term1->id());
$this->assertRaw(\Drupal::l($term2->getName(), $term2->urlInfo()), 'Parent term link is displayed when viewing the node.');
// Breadcrumbs are not rendered with a language, prevent the term
// language from being added to the options.
$this->assertRaw(\Drupal::l($term2->getName(), $term2->urlInfo('canonical', ['language' => NULL])), 'Parent term link is displayed when viewing the node.');
}
}

View File

@ -122,10 +122,10 @@ class FieldEntityLinkTest extends ViewUnitTestBase {
if ($expected_result) {
$path = $entity->url($template);
$destination = $info[$template]['destination'] ? '?destination=/' : '';
$expected_link = '<a href="' . $path . $destination . '">' . $info[$template]['label'] . '</a>';
$expected_link = '<a href="' . $path . $destination . '" hreflang="en">' . $info[$template]['label'] . '</a>';
}
$link = $view->style_plugin->getField($index, $info[$template]['field_id']);
$this->assertEqual($link, $expected_link, SafeMarkup::format('@template entity link behaves as expected.', ['@template' => $template]));
$this->assertEqual($link, $expected_link);
}
$index++;
}

View File

@ -302,7 +302,8 @@ class FieldFieldTest extends ViewUnitTestBase {
for ($i = 0; $i < 5; $i++) {
$this->assertEqual($i + 1, $executable->getStyle()->getField($i, 'id'));
$this->assertEqual('test ' . $i, $executable->getStyle()->getField($i, 'name'));
$this->assertEqual('<a href="' . EntityTest::load($i + 1)->url() . '">test ' . $i . '</a>', $executable->getStyle()->getField($i, 'name_alias'));
$entity = EntityTest::load($i + 1);
$this->assertEqual('<a href="' . $entity->url() . '" hreflang="' . $entity->language()->getId() . '">test ' . $i . '</a>', $executable->getStyle()->getField($i, 'name_alias'));
}
}

View File

@ -8,6 +8,7 @@
namespace Drupal\Tests\Core\Entity;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Language\Language;
use Drupal\Core\Link;
use Drupal\Tests\UnitTestCase;
@ -31,6 +32,13 @@ class EntityLinkTest extends UnitTestCase {
*/
protected $linkGenerator;
/**
* The mocked language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $languageManager;
/**
* {@inheritdoc}
*/
@ -39,10 +47,12 @@ class EntityLinkTest extends UnitTestCase {
$this->entityManager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
$this->linkGenerator = $this->getMock('Drupal\Core\Utility\LinkGeneratorInterface');
$this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$container = new ContainerBuilder();
$container->set('entity.manager', $this->entityManager);
$container->set('link_generator', $this->linkGenerator);
$container->set('language_manager', $this->languageManager);
\Drupal::setContainer($container);
}
@ -52,6 +62,13 @@ class EntityLinkTest extends UnitTestCase {
* @dataProvider providerTestLink
*/
public function testLink($entity_label, $link_text, $expected_text, $link_rel = 'canonical', array $link_options = []) {
$language = new Language(['id' => 'es']);
$link_options += ['language' => $language];
$this->languageManager->expects($this->any())
->method('getLanguage')
->with('es')
->willReturn($language);
$route_name_map = [
'canonical' => 'entity.test_entity_type.canonical',
'edit-form' => 'entity.test_entity_type.edit_form',
@ -67,8 +84,10 @@ class EntityLinkTest extends UnitTestCase {
->willReturn($route_name_map);
$entity_type->expects($this->any())
->method('getKey')
->with('label')
->willReturn('label');
->willReturnMap([
['label', 'label'],
['langcode', 'langcode'],
]);
$this->entityManager
->expects($this->any())
@ -78,7 +97,7 @@ class EntityLinkTest extends UnitTestCase {
/** @var \Drupal\Core\Entity\Entity $entity */
$entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', [
['id' => $entity_id, 'label' => $entity_label],
['id' => $entity_id, 'label' => $entity_label, 'langcode' => 'es'],
$entity_type_id
]);

View File

@ -7,8 +7,11 @@
namespace Drupal\Tests\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\UnitTestCase;
/**
@ -51,13 +54,39 @@ class EntityUrlTest extends UnitTestCase {
*
* @dataProvider providerTestUrlInfo
*/
public function testUrlInfo($entity_class, $link_template, $expected) {
public function testUrlInfo($entity_class, $link_template, $expected, $langcode = NULL) {
/** @var $entity \Drupal\Core\Entity\EntityInterface */
$entity = $this->getMockForAbstractClass($entity_class, array(array('id' => 'test_entity_id'), 'test_entity_type'));
$uri = $this->getTestUrlInfo($entity, $link_template);
$uri = $this->getTestUrlInfo($entity, $link_template, [], $langcode);
$this->assertSame($expected, $uri->getRouteName());
$this->assertSame($entity, $uri->getOption('entity'));
if ($langcode) {
$this->assertEquals($langcode, $uri->getOption('language')->getId());
}
else {
// The expected langcode for a config entity is 'en', because it sets the
// value as default property.
$expected_langcode = $entity instanceof ConfigEntityInterface ? 'en' : LanguageInterface::LANGCODE_NOT_SPECIFIED;
$this->assertEquals($expected_langcode, $uri->getOption('language')->getId());
}
}
/**
* @covers ::urlInfo
*/
public function testUrlInfoWithSpecificLanguageInOptions() {
/** @var $entity \Drupal\Core\Entity\EntityInterface */
$entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array('id' => 'test_entity_id'), 'test_entity_type'));
// Ensure that a specified language overrides the current translation
// language.
$uri = $this->getTestUrlInfo($entity, 'edit-form', [], 'en');
$this->assertEquals('en', $uri->getOption('language')->getId());
$uri = $this->getTestUrlInfo($entity, 'edit-form', ['language' => new Language(['id' => 'fr'])], 'en');
$this->assertEquals('fr', $uri->getOption('language')->getId());
}
/**
@ -65,10 +94,13 @@ class EntityUrlTest extends UnitTestCase {
*/
public function providerTestUrlInfo() {
return array(
array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form'),
array('Drupal\Core\Config\Entity\ConfigEntityBase', 'edit-form', 'entity.test_entity_type.edit_form'),
array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form', NULL),
// Specify a langcode.
array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form', 'es'),
array('Drupal\Core\Entity\Entity', 'edit-form', 'entity.test_entity_type.edit_form', 'en'),
array('Drupal\Core\Config\Entity\ConfigEntityBase', 'edit-form', 'entity.test_entity_type.edit_form', NULL),
// Test that overriding the default $rel parameter works.
array('Drupal\Core\Config\Entity\ConfigEntityBase', FALSE, 'entity.test_entity_type.edit_form'),
array('Drupal\Core\Config\Entity\ConfigEntityBase', FALSE, 'entity.test_entity_type.edit_form', NULL),
);
}
@ -108,18 +140,24 @@ class EntityUrlTest extends UnitTestCase {
* The test entity.
* @param string $link_template
* The link template.
* @param string $langcode
* The langcode.
*
* @return \Drupal\Core\Url
* The URL for this entity's link template.
*/
protected function getTestUrlInfo(EntityInterface $entity, $link_template) {
protected function getTestUrlInfo(EntityInterface $entity, $link_template, array $options = [], $langcode = NULL) {
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$entity_type->expects($this->once())
$entity_type->expects($this->any())
->method('getLinkTemplates')
->will($this->returnValue(array(
'edit-form' => 'test_entity_type.edit',
)));
if ($langcode) {
$entity->langcode = $langcode;
}
$this->entityManager
->expects($this->any())
->method('getDefinition')
@ -128,10 +166,15 @@ class EntityUrlTest extends UnitTestCase {
// If no link template is given, call without a value to test the default.
if ($link_template) {
$uri = $entity->urlInfo($link_template);
$uri = $entity->urlInfo($link_template, $options);
}
else {
$uri = $entity->urlInfo();
if ($entity instanceof ConfigEntityInterface) {
$uri = $entity->urlInfo('edit-form', $options);
}
else {
$uri = $entity->urlInfo('canonical', $options);
}
}
return $uri;
@ -158,14 +201,14 @@ class EntityUrlTest extends UnitTestCase {
*/
public function testUrl() {
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$entity_type->expects($this->exactly(5))
$entity_type->expects($this->any())
->method('getLinkTemplates')
->will($this->returnValue(array(
'canonical' => 'test_entity_type.view',
)));
$this->entityManager
->expects($this->exactly(5))
->expects($this->any())
->method('getDefinition')
->with('test_entity_type')
->will($this->returnValue($entity_type));
@ -177,22 +220,20 @@ class EntityUrlTest extends UnitTestCase {
$this->assertSame('', $no_link_entity->url('banana'));
$valid_entity = $this->getMockForAbstractClass('Drupal\Core\Entity\Entity', array(array('id' => 'test_entity_id'), 'test_entity_type'));
$this->urlGenerator->expects($this->exactly(2))
$language = new Language(array('id' => LanguageInterface::LANGCODE_NOT_SPECIFIED));
$this->urlGenerator->expects($this->any())
->method('generateFromRoute')
->will($this->returnValueMap(array(
array(
'entity.test_entity_type.canonical',
array('test_entity_type' => 'test_entity_id'),
array('entity_type' => 'test_entity_type', 'entity' => $valid_entity),
'/entity/test_entity_type/test_entity_id',
),
array(
'entity.test_entity_type.canonical',
array('test_entity_type' => 'test_entity_id'),
array('absolute' => TRUE, 'entity_type' => 'test_entity_type', 'entity' => $valid_entity),
'http://drupal/entity/test_entity_type/test_entity_id',
),
)));
// Sadly returnValueMap() uses ===, see \PHPUnit_Framework_MockObject_Stub_ReturnValueMap::invoke
// so the $language object can't be compared directly.
->willReturnCallback(function ($route_name, $route_parameters, $options) use ($language) {
if ($route_name === 'entity.test_entity_type.canonical' && $route_parameters === array('test_entity_type' => 'test_entity_id') && array_keys($options) === ['entity_type', 'entity', 'language'] && $options['language'] == $language) {
return '/entity/test_entity_type/test_entity_id';
}
if ($route_name === 'entity.test_entity_type.canonical' && $route_parameters === array('test_entity_type' => 'test_entity_id') && array_keys($options) === ['absolute', 'entity_type', 'entity', 'language'] && $options['language'] == $language) {
return 'http://drupal/entity/test_entity_type/test_entity_id';
}
});
$this->assertSame('/entity/test_entity_type/test_entity_id', $valid_entity->url());
$this->assertSame('http://drupal/entity/test_entity_type/test_entity_id', $valid_entity->url('canonical', array('absolute' => TRUE)));
@ -205,14 +246,14 @@ class EntityUrlTest extends UnitTestCase {
*/
public function testGetSystemPath() {
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$entity_type->expects($this->exactly(3))
$entity_type->expects($this->any())
->method('getLinkTemplates')
->will($this->returnValue(array(
'canonical' => 'entity.test_entity_type.canonical',
)));
$this->entityManager
->expects($this->exactly(3))
->expects($this->any())
->method('getDefinition')
->with('test_entity_type')
->will($this->returnValue($entity_type));