diff --git a/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsInterface.php b/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsInterface.php
index 8eb3bce418..d75644c623 100644
--- a/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsInterface.php
+++ b/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsInterface.php
@@ -8,18 +8,18 @@
interface EntityBundleWithPluralLabelsInterface {
/**
- * Gets the singular label of the bundle.
+ * Returns the singular label of the bundle.
*
* @return string|null
- * The singular label or NULL if it hasn't been set.
+ * The singular label or NULL if it cannot be computed.
*/
public function getSingularLabel();
/**
- * Gets the plural label of the bundle.
+ * Returns the plural label of the bundle.
*
* @return string|null
- * The plural label or NULL if it hasn't been set.
+ * The singular label or NULL if it cannot be computed.
*/
public function getPluralLabel();
@@ -36,8 +36,8 @@ public function getPluralLabel();
* context if there's only one version of the definite singular/plural count
* label. Defaults to NULL.
*
- * @return string
- * The count label.
+ * @return string|null
+ * The count label or NULL if it cannot be computed.
*/
public function getCountLabel($count, $context = NULL);
diff --git a/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsTrait.php b/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsTrait.php
index aff03d6365..4f2e1d93bd 100644
--- a/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsTrait.php
+++ b/core/lib/Drupal/Core/Config/Entity/EntityBundleWithPluralLabelsTrait.php
@@ -85,6 +85,7 @@ public function getPluralLabel() {
* {@inheritdoc}
*/
public function getCountLabel($count, $context = NULL) {
+ $result = NULL;
$label_count_versions = (array) $this->label_count;
// If the context was not passed, pickup the first version of count label.
@@ -98,13 +99,13 @@ public function getCountLabel($count, $context = NULL) {
$label_count = empty($label_count_versions[$context]) ? [] : explode(PluralTranslatableMarkup::DELIMITER, $label_count_versions[$context]);
if (!empty($label_count[$index])) {
- return new FormattableMarkup($label_count[$index], ['@count' => $count]);
+ $result = new FormattableMarkup($label_count[$index], ['@count' => $count]);
}
- $arguments = [
- '@singular' => $this->getSingularLabel(),
- '@plural' => $this->getPluralLabel(),
- ];
- return new PluralTranslatableMarkup($count, '1 @singular', '@count @plural', $arguments);
+ elseif (($singular = $this->getSingularLabel()) && ($plural = $this->getPluralLabel())) {
+ $arguments = ['@singular' => $singular, '@plural' => $plural];
+ $result = new PluralTranslatableMarkup($count, '1 @singular', '@count @plural', $arguments);
+ }
+ return $result;
}
/**
diff --git a/core/modules/node/src/NodeTypeForm.php b/core/modules/node/src/NodeTypeForm.php
index 3544cd9026..9eec40c700 100644
--- a/core/modules/node/src/NodeTypeForm.php
+++ b/core/modules/node/src/NodeTypeForm.php
@@ -6,7 +6,6 @@
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\language\Entity\ContentLanguageSettings;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -185,39 +184,6 @@ public function form(array $form, FormStateInterface $form_state) {
'#default_value' => $type->displaySubmitted(),
'#description' => t('Author username and publish date will be displayed.'),
];
- $form['display']['plural'] = [
- '#type' => 'fieldset',
- '#title' => $this->t('Singular and plural labels'),
- '#description' => $this->t('These are lowercase alternatives to the node type label for singular and plural cases.'),
- ];
- $form['display']['plural']['label_singular'] = [
- '#type' => 'textfield',
- '#title' => $this->t('Singular label'),
- '#description' => $this->t("Enter a lowercase label for the singular case. Examples: 'article', 'page'."),
- '#default_value' => $type->getSingularLabel(),
- ];
- $form['display']['plural']['label_plural'] = [
- '#type' => 'textfield',
- '#title' => $this->t('Plural label'),
- '#description' => $this->t("Enter a lowercase label for the plural case. Examples: 'articles', 'pages'."),
- '#default_value' => $type->getPluralLabel(),
- ];
- $arguments = ['@plural' => $type->getPluralLabel() ?: $this->t('items')];
- $form['display']['label_count'] = [
- '#type' => 'fieldset',
- '#title' => $this->t('Count labels'),
- '#description' => $this->t('Count labels are used to build a text representation of a certain number of @plural. The @count
placeholder is available and will be replaced with the number of @plural.', $arguments),
- '#tree' => TRUE,
- ];
- $plurals = $this->getNumberOfPlurals($type->language()->getId());
- for ($i = 0; $i < $plurals; $i++) {
- $form['display']['label_count'][0][$i] = [
- '#type' => 'textfield',
- '#title' => $this->getPluralVariantLabel($plurals, $i),
- '#description' => $this->t('Text to use for this variant, @count will be replaced with the number of @plural.', $arguments),
- '#default_value' => $this->getPluralVariantDefaultValue($i),
- ];
- }
return $this->protectBundleIdElement($form);
}
@@ -243,13 +209,6 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
if ($id == '0') {
$form_state->setErrorByName('type', $this->t("Invalid machine-readable name. Enter a name other than %invalid.", ['%invalid' => $id]));
}
-
- // Pack the label_count values as a plural_label.
- $label_count = [];
- foreach ($form_state->getValue('label_count') as $plural_variants) {
- $label_count[] = implode(PluralTranslatableMarkup::DELIMITER, $plural_variants);
- }
- $form_state->setValue('label_count', $label_count);
}
/**
@@ -297,63 +256,4 @@ public function save(array $form, FormStateInterface $form_state) {
$form_state->setRedirectUrl($type->urlInfo('collection'));
}
- /**
- * Returns a plural variant label given the variant delta and variants count.
- *
- * @param int $plurals
- * The total number of plural variants.
- * @param int $delta
- * The plural variant delta.
- *
- * @return \Drupal\Component\Render\MarkupInterface
- * The variant label.
- */
- protected function getPluralVariantLabel($plurals, $delta) {
- if ($delta == 0) {
- return $this->t('Singular form');
- }
- elseif ($plurals == 2 && $delta == 1) {
- return $this->t('Plural form');
- }
- return $this->formatPlural($delta, 'First plural form', '@count. plural form');
- }
-
- /**
- * Retrieves a plural variant from the backend or assures a decent fallback.
- *
- * @param int $delta
- * The plural variant delta.
- *
- * @return \Drupal\Component\Render\MarkupInterface|string
- * The plural variant default value.
- */
- protected function getPluralVariantDefaultValue($delta) {
- static $label_count;
-
- /** @var \Drupal\node\NodeTypeInterface $type */
- $type = $this->getEntity();
-
- if (!isset($label_count)) {
- $label_count = isset($type->get('label_count')[0]) ? explode(PluralTranslatableMarkup::DELIMITER, $type->get('label_count')[0]) : [];
- }
-
- if (isset($label_count[$delta])) {
- // A value was stored in the backend.
- return $label_count[$delta];
- }
-
- $singular = $type->getSingularLabel();
- $plural = $type->getPluralLabel();
-
- if ($type->isNew() || ($delta == 0 && empty($singular) || ($delta > 0 && empty($plural)))) {
- // Either the node type is not yet saved (we don't even know the entity
- // label) or we cannot assure a decent fallback.
- return '';
- }
-
- // Provide a fallback default value.
- $arguments = ['@singular' => $singular, '@plural' => $plural];
- return $delta == 0 ? $this->t('1 @singular', $arguments) : $this->t('@count @plural', $arguments);
- }
-
}
diff --git a/core/modules/node/src/Tests/NodeTypeTest.php b/core/modules/node/src/Tests/NodeTypeTest.php
index e501eabd8c..70d3ac40b5 100644
--- a/core/modules/node/src/Tests/NodeTypeTest.php
+++ b/core/modules/node/src/Tests/NodeTypeTest.php
@@ -256,42 +256,4 @@ public function testNodeTypeNoContentType() {
$this->assertEqual(0, count($bundle_info->getBundleInfo('node')), 'The bundle information service has 0 bundles for the Node entity type.');
}
- /**
- * Tests singular/plural labels.
- */
- public function testPluralLabels() {
- $account = $this->drupalCreateUser(['administer content types', 'administer node fields']);
- $this->drupalLogin($account);
-
- $edit = [
- 'name' => 'Mouse',
- 'type' => 'mouse',
- ];
- $this->drupalPostForm('admin/structure/types/add', $edit, 'Save and manage fields');
-
- $type = NodeType::load('mouse');
-
- // Test fallback values.
- $this->assertEqual($type->getSingularLabel(), 'mouse');
- $this->assertEqual($type->getPluralLabel(), 'mouse items');
- $this->assertEqual($type->getCountLabel(1), '1 mouse');
- $this->assertEqual($type->getCountLabel(5), '5 mouse items');
-
- $edit = [
- 'label_singular' => 'mouse',
- 'label_plural' => 'mice',
- 'label_count[0][0]' => '1 mouse',
- 'label_count[0][1]' => '@count mice',
- ];
- $this->drupalPostForm('admin/structure/types/manage/mouse', $edit, 'Save content type');
-
- $type = NodeType::load('mouse');
-
- // Test user entered values.
- $this->assertEqual($type->getSingularLabel(), 'mouse');
- $this->assertEqual($type->getPluralLabel(), 'mice');
- $this->assertEqual($type->getCountLabel(1), '1 mouse');
- $this->assertEqual($type->getCountLabel(5), '5 mice');
- }
-
}
diff --git a/core/modules/node/tests/src/Functional/NodeTypePluralLabelsTranslationTest.php b/core/modules/node/tests/src/Functional/NodeTypePluralLabelsTranslationTest.php
deleted file mode 100644
index 56258e44ac..0000000000
--- a/core/modules/node/tests/src/Functional/NodeTypePluralLabelsTranslationTest.php
+++ /dev/null
@@ -1,136 +0,0 @@
-save();
-
- // Create and log in user.
- $account = $this->drupalCreateUser([
- 'administer content types',
- 'administer node fields',
- 'translate configuration',
- ]);
- $this->drupalLogin($account);
-
- /** @var \Drupal\locale\PluralFormulaInterface $plural_formula */
- $plural_formula = $this->container->get('locale.plural.formula');
-
- // Workaround to register the Romanian and English language formulae in
- // state. Without this, the number of plurals is not correctly parsed.
- $po_header = new PoHeader('ro');
- $plural = $po_header->parsePluralForms('nplurals=3; plural=((n==1)?(0):(((n==0)||(((n%100)>0)&&((n%100)<20)))?(1):2));\n');
- $plural_formula->setPluralFormula('ro', $plural[0], $plural[1]);
- $plural = $po_header->parsePluralForms('nplurals=2; plural=(n > 1);\n');
- $plural_formula->setPluralFormula('en', $plural[0], $plural[1]);
- }
-
- /**
- * {@inheritdoc}
- */
- protected function installParameters() {
- $parameters = parent::installParameters();
- // Install the site in Romanian language.
- $parameters['parameters']['langcode'] = 'ro';
- return $parameters;
- }
-
- /**
- * Tests the node type translation.
- */
- public function testNodeTypeTranslation() {
- /** @var \Drupal\Core\Language\LanguageManagerInterface $language_manager */
- $language_manager = $this->container->get('language_manager');
-
- $this->drupalGet('admin/structure/types/add');
-
- // Check that 3 plural variants are exposed for the Romanian language.
- $this->assertSession()->fieldExists('label_count[0][0]');
- $this->assertSession()->fieldExists('label_count[0][1]');
- $this->assertSession()->fieldExists('label_count[0][2]');
- $this->assertSession()->fieldNotExists('label_count[0][3]');
-
- $edit = [
- 'name' => 'Copil',
- 'type' => 'child',
- 'label_singular' => 'copil',
- 'label_plural' => 'copii',
- 'label_count[0][0]' => '1 copil',
- 'label_count[0][1]' => '@count copii',
- 'label_count[0][2]' => '@count de copii',
- ];
- $this->drupalPostForm(NULL, $edit, 'Save and manage fields');
-
- $edit = [
- 'translation[config_names][node.type.child][name]' => 'Child',
- 'translation[config_names][node.type.child][label_singular]' => 'child',
- 'translation[config_names][node.type.child][label_plural]' => 'children',
- 'translation[config_names][node.type.child][label_count][0][0]' => '1 child',
- 'translation[config_names][node.type.child][label_count][0][1]' => '@count children',
- ];
- $this->drupalPostForm('admin/structure/types/manage/child/translate/en/add', $edit, 'Save translation');
-
- /** @var \Drupal\node\NodeTypeInterface $node_type */
- $node_type = NodeType::load('child');
-
- // Check that the default language (Romanian) original labels were stored.
- self::assertEquals($node_type->label(), 'Copil');
- self::assertEquals($node_type->getSingularLabel(), 'copil');
- self::assertEquals($node_type->getPluralLabel(), 'copii');
- self::assertEquals($node_type->getCountLabel(1), '1 copil');
- self::assertEquals($node_type->getCountLabel(5), '5 copii');
- self::assertEquals($node_type->getCountLabel(20), '20 de copii');
-
- // Load the English version of the 'child' node-type.
- $original_language = $language_manager->getConfigOverrideLanguage();
- $language_manager->setConfigOverrideLanguage(ConfigurableLanguage::load('en'));
- /** @var \Drupal\node\NodeTypeInterface $node_type */
- $node_type = NodeType::load('child');
- $language_manager->setConfigOverrideLanguage($original_language);
-
- // Check that the English translated labels were stored.
- self::assertEquals($node_type->label(), 'Child');
- self::assertEquals($node_type->getSingularLabel(), 'child');
- self::assertEquals($node_type->getPluralLabel(), 'children');
- self::assertEquals($node_type->getCountLabel(1), '1 child');
- self::assertEquals($node_type->getCountLabel(5), '5 children');
- self::assertEquals($node_type->getCountLabel(20), '20 children');
-
- // Clear the count label second variant to test variant delta preserving.
- $edit = ['label_count[0][1]' => ''];
- $this->drupalPostForm($node_type->toUrl('edit-form'), $edit, 'Save content type');
-
- $node_type = NodeType::load('child');
-
- // Check that the variants delta has been preserved.
- $variants = explode(PluralTranslatableMarkup::DELIMITER, $node_type->get('label_count')[0]);
- self::assertEquals($variants[0], '1 copil');
- self::assertEquals($variants[1], '');
- self::assertEquals($variants[2], '@count de copii');
- }
-
-}
diff --git a/core/modules/node/tests/src/Unit/NodeTypePluralLabelTest.php b/core/modules/node/tests/src/Unit/NodeTypePluralLabelTest.php
new file mode 100644
index 0000000000..0ca811fede
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/NodeTypePluralLabelTest.php
@@ -0,0 +1,238 @@
+set('string_translation', $this->getStringTranslationStub());
+ \Drupal::setContainer($container);
+
+ $this->language = $this->getMockBuilder(LanguageInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock()
+ ->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue('en'));
+ }
+
+ /**
+ * @covers ::getSingularLabel
+ * @covers ::getPluralLabel
+ * @dataProvider providerForTestGetSingularAndPLuralLabel
+ *
+ * @param string|null $entity_label
+ * The entity label.
+ * @param string|null $singular_label
+ * The singular label.
+ * @param string|null $expected_singular
+ * The expected singular label.
+ * @param string|null $plural_label
+ * The plural label.
+ * @param string|null $expected_plural
+ * The expected plural label.
+ */
+ public function testGetSingularAndPLuralLabel($entity_label, $singular_label, $expected_singular, $plural_label, $expected_plural) {
+ $bundle_entity_mock = new TestingBundleMock($entity_label, $singular_label, $plural_label, NULL);
+ $this->assertEquals($expected_singular, $bundle_entity_mock->getSingularLabel());
+ $this->assertEquals($expected_plural, $bundle_entity_mock->getPluralLabel());
+ }
+
+ /**
+ * Provides test cases for self::testGetSingularAndPLuralLabel().
+ *
+ * @return array
+ * Test cases.
+ */
+ public function providerForTestGetSingularAndPLuralLabel() {
+ return [
+ // No singular/plural labels and a fallback cannot be build.
+ 'no labels' => [NULL, NULL, NULL, NULL, NULL],
+ // No singular/plural labels but a fallback label could be build.
+ 'entity label only' => ['Eye', NULL, 'eye', NULL, 'eye items'],
+ // No singular label but a fallback singular label could be build.
+ 'no singular label' => ['Eye', NULL, 'eye', 'eyes', 'eyes'],
+ // No plural label but a fallback plural label could be build.
+ 'no plural label' => ['Eye', 'eye', 'eye', NULL, 'eye items'],
+ // Singular and plural labels were provided.
+ 'singular/plural labels' => ['Eye', 'eye', 'eye', 'eyes', 'eyes'],
+ ];
+ }
+
+ /**
+ * @covers ::getCountLabel
+ * @dataProvider providerForTestGetCountLabel
+ *
+ * @param string[]|null $count_labels
+ * The count label array.
+ * @param string|null $entity_label
+ * The entity label.
+ * @param string|null $singular_label
+ * The singular label.
+ * @param string|null $plural_label
+ * The plural label.
+ * @param array $expectation
+ * An associative array keyed where each value is the expected result given
+ * a count integer which is the item key.
+ */
+ public function testGetCountLabel(array $count_labels = NULL, $entity_label, $singular_label, $plural_label, array $expectation) {
+ $count_labels = $count_labels ?: [NULL];
+ $bundle_entity_mock = new TestingBundleMock($entity_label, $singular_label, $plural_label, $count_labels);
+ foreach ($count_labels as $context => $count_label) {
+ foreach ($expectation[$context] as $count => $expected) {
+ // Count label doesn't have a context.
+ if (!$context) {
+ $this->assertEquals($expected, $bundle_entity_mock->getCountLabel($count));
+ }
+ // Multiple contextualised count labels.
+ else {
+ $this->assertEquals($expected, $bundle_entity_mock->getCountLabel($count, $context));
+ }
+ }
+ }
+ }
+
+ /**
+ * Provides test cases for self::testGetCountLabel().
+ *
+ * @return array
+ * Test cases.
+ */
+ public function providerForTestGetCountLabel() {
+ return [
+ // No singular/plural labels and a fallback cannot be build.
+ 'no labels' => [NULL, NULL, NULL, NULL, [[1 => NULL, 2 => NULL]]],
+ // The entity label is used to create fallback singular & plural labels
+ // and these are used to create the count label fallback.
+ 'entity label only' => [
+ NULL,
+ 'Eye',
+ NULL,
+ NULL,
+ [[1 => '1 eye', 2 => '2 eye items']],
+ ],
+ // In there's no count label set and one of singular or plural is missed,
+ // it's not possible to create a count fallback label.
+ 'singular label only' => [
+ NULL,
+ NULL,
+ 'eye',
+ NULL,
+ [[1 => NULL, 2 => NULL]],
+ ],
+ 'only singular/plural labels' => [
+ NULL,
+ NULL,
+ 'blue eye',
+ 'blue eyes',
+ [[1 => '1 blue eye', 2 => '2 blue eyes']],
+ ],
+ 'count label' => [
+ [
+ "1 blue eye\x3@count blue eyes",
+ ],
+ NULL,
+ NULL,
+ NULL,
+ [[1 => '1 blue eye', 2 => '2 blue eyes']],
+ ],
+ // This count label lacks the singular variant.
+ 'broken count label, no singular variant' => [
+ [
+ "\x3@count blue eyes",
+ ],
+ NULL,
+ NULL,
+ NULL,
+ [[1 => NULL, 2 => '2 blue eyes']],
+ ],
+ // This count label lacks the plural variant but is able to compute a
+ // fallback from the entity label.
+ 'broken count label, no plural variant but with entity label' => [
+ [
+ "1 blue eye",
+ ],
+ 'Eye',
+ NULL,
+ NULL,
+ [[1 => '1 blue eye', 2 => '2 eye items']],
+ ],
+ // This count label lacks the plural variant but is able to compute a
+ // fallback from the singular label.
+ 'broken count label, no plural variant but with singular label' => [
+ [
+ "1 blue eye",
+ ],
+ 'Eye',
+ 'blue eye',
+ 'blue eyes',
+ [[1 => '1 blue eye', 2 => '2 blue eyes']],
+ ],
+ // Multiple count labels.
+ 'contextualized count labels' => [
+ [
+ 'default' => "1 blue eye\x3@count blue eyes",
+ 'no count' => "blue eye\x3" . 'blue eyes',
+ 'with markup' => "1 blue eye\x3@count blue eyes",
+ 'with parenthesis' => "blue eye\x3" . 'blue eyes (@count)',
+ ],
+ NULL,
+ NULL,
+ NULL,
+ [
+ 'default' => [1 => '1 blue eye', 2 => '2 blue eyes'],
+ 'no count' => [1 => 'blue eye', 2 => 'blue eyes'],
+ 'with markup' => [1 => '1 blue eye', 2 => '2 blue eyes'],
+ 'with parenthesis' => [1 => 'blue eye', 2 => 'blue eyes (2)'],
+ ],
+ ],
+ ];
+ }
+
+}
+
+// @codingStandardsIgnoreStart
+
+/**
+ * Mocks a bundle config entity class that uses the tested trait.
+ */
+class TestingBundleMock implements EntityBundleWithPluralLabelsInterface {
+
+ use EntityBundleWithPluralLabelsTrait;
+
+ protected $label;
+
+ public function __construct($entity_label, $singular_label, $plural_label, $count_label) {
+ $this->label = $entity_label;
+ $this->label_singular = $singular_label;
+ $this->label_plural = $plural_label;
+ $this->label_count = $count_label;
+ }
+
+ public function label() { return $this->label; }
+ public function language() { return new Language(); }
+}
+
+// @codingStandardsIgnoreEnd