diff --git a/core/modules/views/config/schema/views.area.schema.yml b/core/modules/views/config/schema/views.area.schema.yml
index 51042e9587..a17668a349 100644
--- a/core/modules/views/config/schema/views.area.schema.yml
+++ b/core/modules/views/config/schema/views.area.schema.yml
@@ -51,6 +51,17 @@ views.area.result:
type: text
label: 'The shown text of the result summary area'
+views.area.result_plural:
+ type: views.area.result
+ label: 'Result plural'
+ mapping:
+ content_plural:
+ type: text
+ label: 'Text to use for the plural form'
+ plural_count_token:
+ type: text
+ label: 'Plural count token'
+
views.area.title:
type: views_area
label: 'Title'
diff --git a/core/modules/views/src/Plugin/views/area/Result.php b/core/modules/views/src/Plugin/views/area/Result.php
index 6405a9bf43..547fa405e7 100644
--- a/core/modules/views/src/Plugin/views/area/Result.php
+++ b/core/modules/views/src/Plugin/views/area/Result.php
@@ -3,6 +3,7 @@
namespace Drupal\views\Plugin\views\area;
use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\Xss;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\style\DefaultSummary;
@@ -15,6 +16,20 @@
*/
class Result extends AreaPluginBase {
+ /**
+ * Total number of results.
+ *
+ * @var int
+ */
+ protected $total;
+
+ /**
+ * The token replacements.
+ *
+ * @var array
+ */
+ protected $replacements = [];
+
/**
* {@inheritdoc}
*/
@@ -60,7 +75,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
* {@inheritdoc}
*/
public function query() {
- if (str_contains($this->options['content'], '@total')) {
+ if (strpos($this->options['content'], '@total') !== FALSE || strpos($this->options['content'], '@format_total') !== FALSE) {
$this->view->get_total_rows = TRUE;
}
}
@@ -74,53 +89,60 @@ public function render($empty = FALSE) {
return [];
}
$output = '';
+ $this->calculateTotalAndReplacements();
$format = $this->options['content'];
+ // Send the output.
+ if (!empty($this->total) || !empty($this->options['empty'])) {
+ $output .= Xss::filterAdmin(str_replace(array_keys($this->replacements), array_values($this->replacements), $format));
+ // Return as render array.
+ return [
+ '#markup' => $output,
+ ];
+ }
+
+ return [];
+ }
+
+ /**
+ * Calculate the replacement tokens.
+ */
+ protected function calculateTotalAndReplacements() {
// Calculate the page totals.
$current_page = (int) $this->view->getCurrentPage() + 1;
$per_page = (int) $this->view->getItemsPerPage();
// @TODO: Maybe use a possible is views empty functionality.
// Not every view has total_rows set, use view->result instead.
- $total = $this->view->total_rows ?? count($this->view->result);
+ $this->total = $this->view->total_rows ?? count($this->view->result);
$label = Html::escape($this->view->storage->label());
// If there is no result the "start" and "current_record_count" should be
// equal to 0. To have the same calculation logic, we use a "start offset"
// to handle all the cases.
- $start_offset = empty($total) ? 0 : 1;
+ $start_offset = empty($this->total) ? 0 : 1;
if ($per_page === 0) {
$page_count = 1;
$start = $start_offset;
- $end = $total;
+ $end = $this->total;
}
else {
- $page_count = (int) ceil($total / $per_page);
+ $page_count = (int) ceil($this->total / $per_page);
$total_count = $current_page * $per_page;
- if ($total_count > $total) {
- $total_count = $total;
+ if ($total_count > $this->total) {
+ $total_count = $this->total;
}
$start = ($current_page - 1) * $per_page + $start_offset;
$end = $total_count;
}
$current_record_count = ($end - $start) + $start_offset;
// Get the search information.
- $replacements = [];
- $replacements['@start'] = $start;
- $replacements['@end'] = $end;
- $replacements['@total'] = $total;
- $replacements['@label'] = $label;
- $replacements['@per_page'] = $per_page;
- $replacements['@current_page'] = $current_page;
- $replacements['@current_record_count'] = $current_record_count;
- $replacements['@page_count'] = $page_count;
- // Send the output.
- if (!empty($total) || !empty($this->options['empty'])) {
- $output .= str_replace(array_keys($replacements), array_values($replacements), $format);
- // Return as render array.
- return [
- '#markup' => $output,
- ];
- }
-
- return [];
+ $this->replacements['@start'] = $start;
+ $this->replacements['@end'] = $end;
+ $this->replacements['@total'] = $this->total;
+ $this->replacements['@format_total'] = number_format($this->total, 0, '.', ',');
+ $this->replacements['@label'] = $label;
+ $this->replacements['@per_page'] = $per_page;
+ $this->replacements['@current_page'] = $current_page;
+ $this->replacements['@current_record_count'] = $current_record_count;
+ $this->replacements['@page_count'] = $page_count;
}
}
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml
index 05f574e59d..0e7ca44cbe 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml
@@ -50,7 +50,7 @@ display:
group_type: group
admin_label: ''
empty: true
- content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
+ content: "start: @start | end: @end | total: @total | total formatted: @format_total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
plugin_id: result
display_plugin: default
display_title: Default
@@ -70,7 +70,7 @@ display:
group_type: group
admin_label: ''
empty: false
- content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
+ content: "start: @start | end: @end | total: @total | total formatted: @format_total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
plugin_id: result
display_plugin: page
display_title: 'Page 1'
diff --git a/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php b/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php
index a292e5c6a8..6aa2101faa 100644
--- a/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php
+++ b/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php
@@ -28,7 +28,7 @@ public function testResult() {
$output = $view->render();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->setRawContent($output);
- $this->assertText('start: 1 | end: 5 | total: 5 | label: test_area_result | per page: 0 | current page: 1 | current record count: 5 | page count: 1');
+ $this->assertText('start: 1 | end: 5 | total: 5 | total formatted: 5 | label: test_area_result | per page: 0 | current page: 1 | current record count: 5 | page count: 1');
// Make sure that potentially dangerous content was stripped.
$this->assertNoRaw('');
@@ -59,7 +59,7 @@ public function testResultEmpty() {
$output = $view->render();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->setRawContent($output);
- $this->assertText('start: 0 | end: 0 | total: 0 | label: test_area_result | per page: 0 | current page: 1 | current record count: 0 | page count: 1');
+ $this->assertText('start: 0 | end: 0 | total: 0 | total formatted: 0 | label: test_area_result | per page: 0 | current page: 1 | current record count: 0 | page count: 1');
$this->assertRaw('');
// Test that the area is not displayed if we have not checked the empty
@@ -70,7 +70,7 @@ public function testResultEmpty() {
$output = $view->render();
$output = \Drupal::service('renderer')->renderRoot($output);
$this->setRawContent($output);
- $this->assertNoText('start: 0 | end: 0 | total: 0 | label: test_area_result | per page: 0 | current page: 1 | current record count: 0 | page count: 1');
+ $this->assertNoText('start: 0 | end: 0 | total: 0 | total formatted: 0 | label: test_area_result | per page: 0 | current page: 1 | current record count: 0 | page count: 1');
// Make sure the empty header region isn't rendered.
$this->assertNoRaw('');
}
diff --git a/core/modules/views/views.views.inc b/core/modules/views/views.views.inc
index e24be15b90..4b8a32db4c 100644
--- a/core/modules/views/views.views.inc
+++ b/core/modules/views/views.views.inc
@@ -99,6 +99,14 @@ function views_views_data() {
],
];
+ $data['views']['result_plural'] = [
+ 'title' => t('Result summary (plural)'),
+ 'help' => t('Shows result summary, for example the items per page, with support for having singular and plural text depending on the number of results.'),
+ 'area' => [
+ 'id' => 'result_plural',
+ ],
+ ];
+
$data['views']['messages'] = [
'title' => t('Messages'),
'help' => t('Displays messages in an area.'),