Commit 517efbde authored by effulgentsia's avatar effulgentsia

Issue #1850080 by amateescu, dawehner, Xano, bojanz, martin107, Pancho,...

Issue #1850080 by amateescu, dawehner, Xano, bojanz, martin107, Pancho, alexpott, tim.plunkett, icseh., stefank, Gábor Hojtsy, jhodgdon, tstoeckler: Entity type labels lack plurality, cannot generate UI text based on label if plural is needed
parent f3f3800f
<?php
/**
* @file
* Contains \Drupal\Core\Annotation\PluralTranslation.
*/
namespace Drupal\Core\Annotation;
use Drupal\Component\Annotation\AnnotationBase;
/**
* Defines an annotation object for strings that require plural forms.
*
* Note that the return values for both 'singular' and 'plural' keys needs to be
* passed to
* \Drupal\Core\StringTranslation\TranslationInterface::formatPlural().
*
* For example, the annotation can look like this:
* @code
* label_count = @ PluralTranslation(
* singular = "@count item",
* plural = "@count items",
* context = "cart_items",
* ),
* @endcode
* Remove spaces after @ in your actual plugin - these are put into this sample
* code so that it is not recognized as annotation.
*
* Code samples that make use of this annotation class and the definition sample
* above:
* @code
* // Returns: 1 item
* $entity_type->getCountLabel(1);
*
* // Returns: 5 items
* $entity_type->getCountLabel(5);
* @endcode
*
* @see \Drupal\Core\Entity\EntityType::getSingularLabel()
* @see \Drupal\Core\Entity\EntityType::getPluralLabel()
* @see \Drupal\Core\Entity\EntityType::getCountLabel()
*
* @ingroup plugin_translatable
*
* @Annotation
*/
class PluralTranslation extends AnnotationBase {
/**
* The string for the singular case.
*
* @var string
*/
protected $singular;
/**
* The string for the plural case.
*
* @var string
*/
protected $plural;
/**
* The context the source strings belong to.
*
* @var string
*/
protected $context;
/**
* Constructs a new class instance.
*
* @param array $values
* An associative array with the following keys:
* - singular: The string for the singular case.
* - plural: The string for the plural case.
* - context: The context the source strings belong to.
*
* @throws \InvalidArgumentException
* Thrown when the keys 'singular' or 'plural' are missing from the $values
* array.
*/
public function __construct(array $values) {
if (!isset($values['singular'])) {
throw new \InvalidArgumentException('Missing "singular" value in the PluralTranslation annotation');
}
if (!isset($values['plural'])) {
throw new \InvalidArgumentException('Missing "plural" value in the PluralTranslation annotation');
}
$this->singular = $values['singular'];
$this->plural = $values['plural'];
if (isset($values['context'])) {
$this->context = $values['context'];
}
}
/**
* {@inheritdoc}
*/
public function get() {
return [
'singular' => $this->singular,
'plural' => $this->plural,
'context' => $this->context,
];
}
}
......@@ -10,6 +10,7 @@
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\Exception\EntityTypeIdLengthException;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Provides an implementation of an entity type and its metadata.
......@@ -185,6 +186,29 @@ class EntityType implements EntityTypeInterface {
*/
protected $label = '';
/**
* The indefinite singular name of the type.
*
* @var string
*/
protected $label_singular = '';
/**
* The indefinite plural name of the type.
*
* @var string
*/
protected $label_plural = '';
/**
* A definite singular/plural name of the type.
*
* Needed keys: "singular" and "plural".
*
* @var string[]
*/
protected $label_count = [];
/**
* A callable that can be used to provide the entity URI.
*
......@@ -290,7 +314,6 @@ public function __construct($definition) {
if (empty($this->list_cache_tags)) {
$this->list_cache_tags = [$definition['id'] . '_list'];
}
}
/**
......@@ -720,6 +743,39 @@ public function getLowercaseLabel() {
return Unicode::strtolower($this->getLabel());
}
/**
* {@inheritdoc}
*/
public function getSingularLabel() {
if (empty($this->label_singular)) {
$lowercase_label = $this->getLowercaseLabel();
$this->label_singular = $lowercase_label;
}
return $this->label_singular;
}
/**
* {@inheritdoc}
*/
public function getPluralLabel() {
if (empty($this->label_plural)) {
$lowercase_label = $this->getLowercaseLabel();
$this->label_plural = new TranslatableMarkup('@label entities', ['@label' => $lowercase_label], [], $this->getStringTranslation());
}
return $this->label_plural;
}
/**
* {@inheritdoc}
*/
public function getCountLabel($count) {
if (empty($this->label_count)) {
return $this->formatPlural($count, '@count @label', '@count @label entities', ['@label' => $this->getLowercaseLabel()], ['context' => 'Entity type label']);
}
$context = isset($this->label_count['context']) ? $this->label_count['context'] : 'Entity type label';
return $this->formatPlural($count, $this->label_count['singular'], $this->label_count['plural'], ['context' => $context]);
}
/**
* {@inheritdoc}
*/
......
......@@ -630,6 +630,33 @@ public function getLabel();
*/
public function getLowercaseLabel();
/**
* Gets the singular label of the entity type.
*
* @return string
* The singular label.
*/
public function getSingularLabel();
/**
* Gets the plural label of the entity type.
*
* @return string
* The plural label.
*/
public function getPluralLabel();
/**
* Gets the count label of the entity type
*
* @param int $count
* The item count to display if the plural form was requested.
*
* @return string
* The count label.
*/
public function getCountLabel($count);
/**
* Gets a callable that can be used to provide the entity URI.
*
......
......@@ -22,6 +22,12 @@
* @ContentEntityType(
* id = "node",
* label = @Translation("Content"),
* label_singular = @Translation("content item"),
* label_plural = @Translation("content items"),
* label_count = @PluralTranslation(
* singular = "@count content item",
* plural = "@count content items"
* ),
* bundle_label = @Translation("Content type"),
* handlers = {
* "storage" = "Drupal\node\NodeStorage",
......
......@@ -32,6 +32,11 @@ protected function setUp() {
'color' => 'yellow',
'uses' => array(
'bread' => t('Banana bread'),
'loaf' => array(
'singular' => '@count loaf',
'plural' => '@count loaves',
'context' => NULL,
),
),
'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Banana',
'provider' => 'plugin_test',
......
......@@ -46,6 +46,11 @@ protected function setUp() {
'color' => 'yellow',
'uses' => array(
'bread' => t('Banana bread'),
'loaf' => array(
'singular' => '@count loaf',
'plural' => '@count loaves',
'context' => NULL,
),
),
'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Banana',
'provider' => 'plugin_test',
......
......@@ -13,7 +13,11 @@
* label = "Banana",
* color = "yellow",
* uses = {
* "bread" = @Translation("Banana bread")
* "bread" = @Translation("Banana bread"),
* "loaf" = @PluralTranslation(
* singular = "@count loaf",
* plural = "@count loaves"
* )
* }
* )
*/
......
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Annotation\PluralTranslationTest.
*/
namespace Drupal\Tests\Core\Annotation;
use Drupal\Core\Annotation\PluralTranslation;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Annotation\PluralTranslation
* @group Annotation
*/
class PluralTranslationTest extends UnitTestCase {
/**
* @covers ::get
*
* @dataProvider providerTestGet
*/
public function testGet(array $values) {
$annotation = new PluralTranslation($values);
$default_values = [
'context' => NULL,
];
$this->assertEquals($values + $default_values, $annotation->get());
}
/**
* Provides data to self::testGet().
*/
public function providerTestGet() {
$data = [];
$data[] = [
[
'singular' => $this->randomMachineName(),
'plural' => $this->randomMachineName(),
'context' => $this->randomMachineName(),
],
];
$data[] = [
[
'singular' => $this->randomMachineName(),
'plural' => $this->randomMachineName(),
],
];
return $data;
}
/**
* @dataProvider providerTestMissingData
*/
public function testMissingData($data) {
$this->setExpectedException(\InvalidArgumentException::class);
new PluralTranslation($data);
}
public function providerTestMissingData() {
$data = [];
$data['all-missing'] = [[]];
$data['singular-missing'] = [['plural' => 'muh']];
$data['plural-missing'] = [['singular' => 'muh']];
return $data;
}
}
......@@ -314,6 +314,66 @@ public function testGetGroupLabel() {
$this->assertSame($default_label, $entity_type->getGroupLabel());
}
/**
* @covers ::getSingularLabel
*/
public function testGetSingularLabel() {
$translatable_label = new TranslatableMarkup('entity test singular', [], [], $this->getStringTranslationStub());
$entity_type = $this->setUpEntityType(['label_singular' => $translatable_label]);
$entity_type->setStringTranslation($this->getStringTranslationStub());
$this->assertEquals('entity test singular', $entity_type->getSingularLabel());
}
/**
* @covers ::getSingularLabel
*/
public function testGetSingularLabelDefault() {
$entity_type = $this->setUpEntityType(['label' => 'Entity test Singular']);
$entity_type->setStringTranslation($this->getStringTranslationStub());
$this->assertEquals('entity test singular', $entity_type->getSingularLabel());
}
/**
* @covers ::getPluralLabel
*/
public function testGetPluralLabel() {
$translatable_label = new TranslatableMarkup('entity test plural', [], [], $this->getStringTranslationStub());
$entity_type = $this->setUpEntityType(['label_plural' => $translatable_label]);
$entity_type->setStringTranslation($this->getStringTranslationStub());
$this->assertEquals('entity test plural', $entity_type->getPluralLabel());
}
/**
* @covers ::getPluralLabel
*/
public function testGetPluralLabelDefault() {
$entity_type = $this->setUpEntityType(['label' => 'Entity test Plural']);
$entity_type->setStringTranslation($this->getStringTranslationStub());
$this->assertEquals('entity test plural entities', $entity_type->getPluralLabel());
}
/**
* @covers ::getCountLabel
*/
public function testGetCountLabel() {
$entity_type = $this->setUpEntityType(['label_count' => ['singular' => 'one entity test', 'plural' => '@count entity test']]);
$entity_type->setStringTranslation($this->getStringTranslationStub());
$this->assertEquals('one entity test', $entity_type->getCountLabel(1));
$this->assertEquals('2 entity test', $entity_type->getCountLabel(2));
$this->assertEquals('200 entity test', $entity_type->getCountLabel(200));
}
/**
* @covers ::getCountLabel
*/
public function testGetCountLabelDefault() {
$entity_type = $this->setUpEntityType(['label' => 'Entity test Plural']);
$entity_type->setStringTranslation($this->getStringTranslationStub());
$this->assertEquals('1 entity test plural', $entity_type->getCountLabel(1));
$this->assertEquals('2 entity test plural entities', $entity_type->getCountLabel(2));
$this->assertEquals('200 entity test plural entities', $entity_type->getCountLabel(200));
}
/**
* Gets a mock controller class name.
*
......
......@@ -49,6 +49,10 @@ protected function setUp() {
'color' => 'yellow',
'uses' => array(
'bread' => 'Banana bread',
'loaf' => array(
'singular' => '@count loaf',
'plural' => '@count loaves',
),
),
'class' => 'Drupal\plugin_test\Plugin\plugin_test\fruit\Banana',
),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment